SetSourceiv should never get AL_SAMPLE_OFFSET_LATENCY_SOFT
[openal-soft.git] / OpenAL32 / alSource.c
blob480e77fef0ae3941a21764dc3dc8533abdb00065
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
37 enum Resampler DefaultResampler = LinearResampler;
38 const ALsizei ResamplerPadding[ResamplerMax] = {
39 0, /* Point */
40 1, /* Linear */
41 2, /* Cubic */
43 const ALsizei ResamplerPrePadding[ResamplerMax] = {
44 0, /* Point */
45 0, /* Linear */
46 1, /* Cubic */
50 static ALvoid InitSourceParams(ALsource *Source);
51 static ALint64 GetSourceOffset(const ALsource *Source);
52 static ALdouble GetSourceSecOffset(const ALsource *Source);
53 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
54 static ALint GetSampleOffset(ALsource *Source);
56 typedef enum SrcFloatProp {
57 sfPitch = AL_PITCH,
58 sfGain = AL_GAIN,
59 sfMinGain = AL_MIN_GAIN,
60 sfMaxGain = AL_MAX_GAIN,
61 sfMaxDistance = AL_MAX_DISTANCE,
62 sfRolloffFactor = AL_ROLLOFF_FACTOR,
63 sfDopplerFactor = AL_DOPPLER_FACTOR,
64 sfConeOuterGain = AL_CONE_OUTER_GAIN,
65 sfSecOffset = AL_SEC_OFFSET,
66 sfSampleOffset = AL_SAMPLE_OFFSET,
67 sfByteOffset = AL_BYTE_OFFSET,
68 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
69 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
70 sfRefDistance = AL_REFERENCE_DISTANCE,
72 sfPosition = AL_POSITION,
73 sfVelocity = AL_VELOCITY,
74 sfDirection = AL_DIRECTION,
76 sfSourceRelative = AL_SOURCE_RELATIVE,
77 sfLooping = AL_LOOPING,
78 sfBuffer = AL_BUFFER,
79 sfSourceState = AL_SOURCE_STATE,
80 sfBuffersQueued = AL_BUFFERS_QUEUED,
81 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
82 sfSourceType = AL_SOURCE_TYPE,
84 /* ALC_EXT_EFX */
85 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
86 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
87 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
88 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
89 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
90 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
92 /* AL_SOFT_direct_channels */
93 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
95 /* AL_EXT_source_distance_model */
96 sfDistanceModel = AL_DISTANCE_MODEL,
98 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
99 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
100 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102 /* AL_SOFT_source_latency */
103 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
104 } SrcFloatProp;
106 typedef enum SrcIntProp {
107 siMaxDistance = AL_MAX_DISTANCE,
108 siRolloffFactor = AL_ROLLOFF_FACTOR,
109 siRefDistance = AL_REFERENCE_DISTANCE,
110 siSourceRelative = AL_SOURCE_RELATIVE,
111 siConeInnerAngle = AL_CONE_INNER_ANGLE,
112 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
113 siLooping = AL_LOOPING,
114 siBuffer = AL_BUFFER,
115 siSourceState = AL_SOURCE_STATE,
116 siBuffersQueued = AL_BUFFERS_QUEUED,
117 siBuffersProcessed = AL_BUFFERS_PROCESSED,
118 siSourceType = AL_SOURCE_TYPE,
119 siSecOffset = AL_SEC_OFFSET,
120 siSampleOffset = AL_SAMPLE_OFFSET,
121 siByteOffset = AL_BYTE_OFFSET,
122 siDopplerFactor = AL_DOPPLER_FACTOR,
123 siPosition = AL_POSITION,
124 siVelocity = AL_VELOCITY,
125 siDirection = AL_DIRECTION,
127 /* ALC_EXT_EFX */
128 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
129 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
130 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
131 siDirectFilter = AL_DIRECT_FILTER,
132 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
134 /* AL_SOFT_direct_channels */
135 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
137 /* AL_EXT_source_distance_model */
138 siDistanceModel = AL_DISTANCE_MODEL,
140 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
141 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
142 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
144 /* AL_SOFT_source_latency */
145 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
146 } SrcIntProp;
148 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
149 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
150 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
152 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
153 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
154 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
156 static ALint FloatValsByProp(ALenum prop)
158 if(prop != (ALenum)((SrcFloatProp)prop))
159 return 0;
160 switch((SrcFloatProp)prop)
162 case sfPitch:
163 case sfGain:
164 case sfMinGain:
165 case sfMaxGain:
166 case sfMaxDistance:
167 case sfRolloffFactor:
168 case sfDopplerFactor:
169 case sfConeOuterGain:
170 case sfSecOffset:
171 case sfSampleOffset:
172 case sfByteOffset:
173 case sfConeInnerAngle:
174 case sfConeOuterAngle:
175 case sfRefDistance:
176 case sfConeOuterGainHF:
177 case sfAirAbsorptionFactor:
178 case sfRoomRolloffFactor:
179 case sfDirectFilterGainHFAuto:
180 case sfAuxSendFilterGainAuto:
181 case sfAuxSendFilterGainHFAuto:
182 case sfDirectChannelsSOFT:
183 case sfDistanceModel:
184 case sfSourceRelative:
185 case sfLooping:
186 case sfBuffer:
187 case sfSourceState:
188 case sfBuffersQueued:
189 case sfBuffersProcessed:
190 case sfSourceType:
191 return 1;
193 case sfSampleRWOffsetsSOFT:
194 case sfByteRWOffsetsSOFT:
195 return 2;
197 case sfPosition:
198 case sfVelocity:
199 case sfDirection:
200 return 3;
202 case sfSecOffsetLatencySOFT:
203 break; /* Double only */
205 return 0;
207 static ALint DoubleValsByProp(ALenum prop)
209 if(prop != (ALenum)((SrcFloatProp)prop))
210 return 0;
211 switch((SrcFloatProp)prop)
213 case sfPitch:
214 case sfGain:
215 case sfMinGain:
216 case sfMaxGain:
217 case sfMaxDistance:
218 case sfRolloffFactor:
219 case sfDopplerFactor:
220 case sfConeOuterGain:
221 case sfSecOffset:
222 case sfSampleOffset:
223 case sfByteOffset:
224 case sfConeInnerAngle:
225 case sfConeOuterAngle:
226 case sfRefDistance:
227 case sfConeOuterGainHF:
228 case sfAirAbsorptionFactor:
229 case sfRoomRolloffFactor:
230 case sfDirectFilterGainHFAuto:
231 case sfAuxSendFilterGainAuto:
232 case sfAuxSendFilterGainHFAuto:
233 case sfDirectChannelsSOFT:
234 case sfDistanceModel:
235 case sfSourceRelative:
236 case sfLooping:
237 case sfBuffer:
238 case sfSourceState:
239 case sfBuffersQueued:
240 case sfBuffersProcessed:
241 case sfSourceType:
242 return 1;
244 case sfSampleRWOffsetsSOFT:
245 case sfByteRWOffsetsSOFT:
246 case sfSecOffsetLatencySOFT:
247 return 2;
249 case sfPosition:
250 case sfVelocity:
251 case sfDirection:
252 return 3;
254 return 0;
257 static ALint IntValsByProp(ALenum prop)
259 if(prop != (ALenum)((SrcIntProp)prop))
260 return 0;
261 switch((SrcIntProp)prop)
263 case siMaxDistance:
264 case siRolloffFactor:
265 case siRefDistance:
266 case siSourceRelative:
267 case siConeInnerAngle:
268 case siConeOuterAngle:
269 case siLooping:
270 case siBuffer:
271 case siSourceState:
272 case siBuffersQueued:
273 case siBuffersProcessed:
274 case siSourceType:
275 case siSecOffset:
276 case siSampleOffset:
277 case siByteOffset:
278 case siDopplerFactor:
279 case siDirectFilterGainHFAuto:
280 case siAuxSendFilterGainAutio:
281 case siAuxSendFilterGainHFAuto:
282 case siDirectFilter:
283 case siDirectChannelsSOFT:
284 case siDistanceModel:
285 return 1;
287 case siSampleRWOffsetsSOFT:
288 case siByteRWOffsetsSOFT:
289 return 2;
291 case siPosition:
292 case siVelocity:
293 case siDirection:
294 case siAuxSendFilter:
295 return 3;
297 case siSampleOffsetLatencySOFT:
298 break; /* i64 only */
300 return 0;
302 static ALint Int64ValsByProp(ALenum prop)
304 if(prop != (ALenum)((SrcIntProp)prop))
305 return 0;
306 switch((SrcIntProp)prop)
308 case siMaxDistance:
309 case siRolloffFactor:
310 case siRefDistance:
311 case siSourceRelative:
312 case siConeInnerAngle:
313 case siConeOuterAngle:
314 case siLooping:
315 case siBuffer:
316 case siSourceState:
317 case siBuffersQueued:
318 case siBuffersProcessed:
319 case siSourceType:
320 case siSecOffset:
321 case siSampleOffset:
322 case siByteOffset:
323 case siDopplerFactor:
324 case siDirectFilterGainHFAuto:
325 case siAuxSendFilterGainAutio:
326 case siAuxSendFilterGainHFAuto:
327 case siDirectFilter:
328 case siDirectChannelsSOFT:
329 case siDistanceModel:
330 return 1;
332 case siSampleRWOffsetsSOFT:
333 case siByteRWOffsetsSOFT:
334 case siSampleOffsetLatencySOFT:
335 return 2;
337 case siPosition:
338 case siVelocity:
339 case siDirection:
340 case siAuxSendFilter:
341 return 3;
343 return 0;
347 #define RETERR(x) do { \
348 alSetError(Context, (x)); \
349 return (x); \
350 } while(0)
352 #define CHECKVAL(x) do { \
353 if(!(x)) \
354 RETERR(AL_INVALID_VALUE); \
355 } while(0)
357 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
359 ALint ival;
361 switch(prop)
363 case AL_PITCH:
364 CHECKVAL(*values >= 0.0f);
366 Source->Pitch = *values;
367 Source->NeedsUpdate = AL_TRUE;
368 return AL_NO_ERROR;
370 case AL_CONE_INNER_ANGLE:
371 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
373 Source->InnerAngle = *values;
374 Source->NeedsUpdate = AL_TRUE;
375 return AL_NO_ERROR;
377 case AL_CONE_OUTER_ANGLE:
378 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
380 Source->OuterAngle = *values;
381 Source->NeedsUpdate = AL_TRUE;
382 return AL_NO_ERROR;
384 case AL_GAIN:
385 CHECKVAL(*values >= 0.0f);
387 Source->Gain = *values;
388 Source->NeedsUpdate = AL_TRUE;
389 return AL_NO_ERROR;
391 case AL_MAX_DISTANCE:
392 CHECKVAL(*values >= 0.0f);
394 Source->MaxDistance = *values;
395 Source->NeedsUpdate = AL_TRUE;
396 return AL_NO_ERROR;
398 case AL_ROLLOFF_FACTOR:
399 CHECKVAL(*values >= 0.0f);
401 Source->RollOffFactor = *values;
402 Source->NeedsUpdate = AL_TRUE;
403 return AL_NO_ERROR;
405 case AL_REFERENCE_DISTANCE:
406 CHECKVAL(*values >= 0.0f);
408 Source->RefDistance = *values;
409 Source->NeedsUpdate = AL_TRUE;
410 return AL_NO_ERROR;
412 case AL_MIN_GAIN:
413 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
415 Source->MinGain = *values;
416 Source->NeedsUpdate = AL_TRUE;
417 return AL_NO_ERROR;
419 case AL_MAX_GAIN:
420 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
422 Source->MaxGain = *values;
423 Source->NeedsUpdate = AL_TRUE;
424 return AL_NO_ERROR;
426 case AL_CONE_OUTER_GAIN:
427 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
429 Source->OuterGain = *values;
430 Source->NeedsUpdate = AL_TRUE;
431 return AL_NO_ERROR;
433 case AL_CONE_OUTER_GAINHF:
434 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
436 Source->OuterGainHF = *values;
437 Source->NeedsUpdate = AL_TRUE;
438 return AL_NO_ERROR;
440 case AL_AIR_ABSORPTION_FACTOR:
441 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
443 Source->AirAbsorptionFactor = *values;
444 Source->NeedsUpdate = AL_TRUE;
445 return AL_NO_ERROR;
447 case AL_ROOM_ROLLOFF_FACTOR:
448 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
450 Source->RoomRolloffFactor = *values;
451 Source->NeedsUpdate = AL_TRUE;
452 return AL_NO_ERROR;
454 case AL_DOPPLER_FACTOR:
455 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
457 Source->DopplerFactor = *values;
458 Source->NeedsUpdate = AL_TRUE;
459 return AL_NO_ERROR;
461 case AL_SEC_OFFSET:
462 case AL_SAMPLE_OFFSET:
463 case AL_BYTE_OFFSET:
464 CHECKVAL(*values >= 0.0f);
466 LockContext(Context);
467 Source->OffsetType = prop;
468 Source->Offset = *values;
470 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
471 !Context->DeferUpdates)
473 if(ApplyOffset(Source) == AL_FALSE)
475 UnlockContext(Context);
476 RETERR(AL_INVALID_VALUE);
479 UnlockContext(Context);
480 return AL_NO_ERROR;
483 case AL_SEC_OFFSET_LATENCY_SOFT:
484 /* Query only */
485 RETERR(AL_INVALID_OPERATION);
488 case AL_POSITION:
489 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
491 LockContext(Context);
492 Source->Position[0] = values[0];
493 Source->Position[1] = values[1];
494 Source->Position[2] = values[2];
495 UnlockContext(Context);
496 Source->NeedsUpdate = AL_TRUE;
497 return AL_NO_ERROR;
499 case AL_VELOCITY:
500 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
502 LockContext(Context);
503 Source->Velocity[0] = values[0];
504 Source->Velocity[1] = values[1];
505 Source->Velocity[2] = values[2];
506 UnlockContext(Context);
507 Source->NeedsUpdate = AL_TRUE;
508 return AL_NO_ERROR;
510 case AL_DIRECTION:
511 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
513 LockContext(Context);
514 Source->Orientation[0] = values[0];
515 Source->Orientation[1] = values[1];
516 Source->Orientation[2] = values[2];
517 UnlockContext(Context);
518 Source->NeedsUpdate = AL_TRUE;
519 return AL_NO_ERROR;
522 case sfSampleRWOffsetsSOFT:
523 case sfByteRWOffsetsSOFT:
524 RETERR(AL_INVALID_OPERATION);
527 case sfSourceRelative:
528 case sfLooping:
529 case sfSourceState:
530 case sfSourceType:
531 case sfDistanceModel:
532 case sfDirectFilterGainHFAuto:
533 case sfAuxSendFilterGainAuto:
534 case sfAuxSendFilterGainHFAuto:
535 case sfDirectChannelsSOFT:
536 ival = (ALint)values[0];
537 return SetSourceiv(Source, Context, prop, &ival);
539 case sfBuffer:
540 case sfBuffersQueued:
541 case sfBuffersProcessed:
542 ival = (ALint)((ALuint)values[0]);
543 return SetSourceiv(Source, Context, prop, &ival);
546 ERR("Unexpected property: 0x%04x\n", prop);
547 RETERR(AL_INVALID_ENUM);
550 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
552 ALCdevice *device = Context->Device;
553 ALbuffer *buffer = NULL;
554 ALfilter *filter = NULL;
555 ALeffectslot *slot = NULL;
556 ALbufferlistitem *oldlist;
557 ALfloat fvals[3];
559 switch(prop)
561 case AL_SOURCE_RELATIVE:
562 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
564 Source->HeadRelative = (ALboolean)*values;
565 Source->NeedsUpdate = AL_TRUE;
566 return AL_NO_ERROR;
568 case AL_LOOPING:
569 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
571 Source->Looping = (ALboolean)*values;
572 return AL_NO_ERROR;
574 case AL_BUFFER:
575 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
577 LockContext(Context);
578 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
580 UnlockContext(Context);
581 RETERR(AL_INVALID_OPERATION);
584 Source->BuffersInQueue = 0;
585 Source->BuffersPlayed = 0;
587 if(buffer != NULL)
589 ALbufferlistitem *BufferListItem;
591 /* Source is now Static */
592 Source->SourceType = AL_STATIC;
594 /* Add the selected buffer to a one-item queue */
595 BufferListItem = malloc(sizeof(ALbufferlistitem));
596 BufferListItem->buffer = buffer;
597 BufferListItem->next = NULL;
598 BufferListItem->prev = NULL;
599 IncrementRef(&buffer->ref);
601 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
602 Source->BuffersInQueue = 1;
604 ReadLock(&buffer->lock);
605 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
606 Source->SampleSize = BytesFromFmt(buffer->FmtType);
607 ReadUnlock(&buffer->lock);
608 if(buffer->FmtChannels == FmtMono)
609 Source->Update = CalcSourceParams;
610 else
611 Source->Update = CalcNonAttnSourceParams;
612 Source->NeedsUpdate = AL_TRUE;
614 else
616 /* Source is now Undetermined */
617 Source->SourceType = AL_UNDETERMINED;
618 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
621 /* Delete all elements in the previous queue */
622 while(oldlist != NULL)
624 ALbufferlistitem *temp = oldlist;
625 oldlist = temp->next;
627 if(temp->buffer)
628 DecrementRef(&temp->buffer->ref);
629 free(temp);
631 UnlockContext(Context);
632 return AL_NO_ERROR;
634 case siSourceState:
635 case siSourceType:
636 case siBuffersQueued:
637 case siBuffersProcessed:
638 /* Query only */
639 RETERR(AL_INVALID_OPERATION);
641 case AL_SEC_OFFSET:
642 case AL_SAMPLE_OFFSET:
643 case AL_BYTE_OFFSET:
644 CHECKVAL(*values >= 0);
646 LockContext(Context);
647 Source->OffsetType = prop;
648 Source->Offset = *values;
650 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
651 !Context->DeferUpdates)
653 if(ApplyOffset(Source) == AL_FALSE)
655 UnlockContext(Context);
656 RETERR(AL_INVALID_VALUE);
659 UnlockContext(Context);
660 return AL_NO_ERROR;
663 case siSampleRWOffsetsSOFT:
664 case siByteRWOffsetsSOFT:
665 /* Query only */
666 RETERR(AL_INVALID_OPERATION);
669 case AL_DIRECT_FILTER:
670 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
672 LockContext(Context);
673 if(!filter)
675 Source->DirectGain = 1.0f;
676 Source->DirectGainHF = 1.0f;
678 else
680 Source->DirectGain = filter->Gain;
681 Source->DirectGainHF = filter->GainHF;
683 UnlockContext(Context);
684 Source->NeedsUpdate = AL_TRUE;
685 return AL_NO_ERROR;
687 case AL_DIRECT_FILTER_GAINHF_AUTO:
688 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
690 Source->DryGainHFAuto = *values;
691 Source->NeedsUpdate = AL_TRUE;
692 return AL_NO_ERROR;
694 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
695 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
697 Source->WetGainAuto = *values;
698 Source->NeedsUpdate = AL_TRUE;
699 return AL_NO_ERROR;
701 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
702 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
704 Source->WetGainHFAuto = *values;
705 Source->NeedsUpdate = AL_TRUE;
706 return AL_NO_ERROR;
708 case AL_DIRECT_CHANNELS_SOFT:
709 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
711 Source->DirectChannels = *values;
712 Source->NeedsUpdate = AL_TRUE;
713 return AL_NO_ERROR;
715 case AL_DISTANCE_MODEL:
716 CHECKVAL(*values == AL_NONE ||
717 *values == AL_INVERSE_DISTANCE ||
718 *values == AL_INVERSE_DISTANCE_CLAMPED ||
719 *values == AL_LINEAR_DISTANCE ||
720 *values == AL_LINEAR_DISTANCE_CLAMPED ||
721 *values == AL_EXPONENT_DISTANCE ||
722 *values == AL_EXPONENT_DISTANCE_CLAMPED);
724 Source->DistanceModel = *values;
725 if(Context->SourceDistanceModel)
726 Source->NeedsUpdate = AL_TRUE;
727 return AL_NO_ERROR;
730 case AL_AUXILIARY_SEND_FILTER:
731 LockContext(Context);
732 if(!((ALuint)values[1] < device->NumAuxSends &&
733 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
734 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
736 UnlockContext(Context);
737 RETERR(AL_INVALID_VALUE);
740 /* Add refcount on the new slot, and release the previous slot */
741 if(slot) IncrementRef(&slot->ref);
742 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
743 if(slot) DecrementRef(&slot->ref);
745 if(!filter)
747 /* Disable filter */
748 Source->Send[values[1]].Gain = 1.0f;
749 Source->Send[values[1]].GainHF = 1.0f;
751 else
753 Source->Send[values[1]].Gain = filter->Gain;
754 Source->Send[values[1]].GainHF = filter->GainHF;
756 Source->NeedsUpdate = AL_TRUE;
757 UnlockContext(Context);
758 return AL_NO_ERROR;
761 case AL_MAX_DISTANCE:
762 case AL_ROLLOFF_FACTOR:
763 case AL_CONE_INNER_ANGLE:
764 case AL_CONE_OUTER_ANGLE:
765 case AL_REFERENCE_DISTANCE:
766 case siDopplerFactor:
767 fvals[0] = (ALfloat)*values;
768 return SetSourcefv(Source, Context, (int)prop, fvals);
770 case AL_POSITION:
771 case AL_VELOCITY:
772 case AL_DIRECTION:
773 fvals[0] = (ALfloat)values[0];
774 fvals[1] = (ALfloat)values[1];
775 fvals[2] = (ALfloat)values[2];
776 return SetSourcefv(Source, Context, (int)prop, fvals);
778 case siSampleOffsetLatencySOFT:
779 /* i64 only */
780 break;
783 ERR("Unexpected property: 0x%04x\n", prop);
784 RETERR(AL_INVALID_ENUM);
787 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
789 ALfloat fvals[3];
790 ALint ivals[3];
792 switch(prop)
794 case siSampleRWOffsetsSOFT:
795 case siByteRWOffsetsSOFT:
796 case siSampleOffsetLatencySOFT:
797 /* Query only */
798 RETERR(AL_INVALID_OPERATION);
801 /* 1x int */
802 case AL_SOURCE_RELATIVE:
803 case AL_LOOPING:
804 case AL_SOURCE_STATE:
805 case AL_BYTE_OFFSET:
806 case AL_SAMPLE_OFFSET:
807 case siSourceType:
808 case siBuffersQueued:
809 case siBuffersProcessed:
810 case AL_DIRECT_FILTER_GAINHF_AUTO:
811 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
812 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
813 case AL_DIRECT_CHANNELS_SOFT:
814 case AL_DISTANCE_MODEL:
815 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
817 ivals[0] = (ALint)*values;
818 return SetSourceiv(Source, Context, (int)prop, ivals);
820 /* 1x uint */
821 case AL_BUFFER:
822 case AL_DIRECT_FILTER:
823 CHECKVAL(*values <= UINT_MAX && *values >= 0);
825 ivals[0] = (ALuint)*values;
826 return SetSourceiv(Source, Context, (int)prop, ivals);
828 /* 3x uint */
829 case AL_AUXILIARY_SEND_FILTER:
830 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
831 values[1] <= UINT_MAX && values[1] >= 0 &&
832 values[2] <= UINT_MAX && values[2] >= 0);
834 ivals[0] = (ALuint)values[0];
835 ivals[1] = (ALuint)values[1];
836 ivals[2] = (ALuint)values[2];
837 return SetSourceiv(Source, Context, (int)prop, ivals);
839 /* 1x float */
840 case AL_MAX_DISTANCE:
841 case AL_ROLLOFF_FACTOR:
842 case AL_CONE_INNER_ANGLE:
843 case AL_CONE_OUTER_ANGLE:
844 case AL_REFERENCE_DISTANCE:
845 case AL_SEC_OFFSET:
846 case siDopplerFactor:
847 fvals[0] = (ALfloat)*values;
848 return SetSourcefv(Source, Context, (int)prop, fvals);
850 /* 3x float */
851 case AL_POSITION:
852 case AL_VELOCITY:
853 case AL_DIRECTION:
854 fvals[0] = (ALfloat)values[0];
855 fvals[1] = (ALfloat)values[1];
856 fvals[2] = (ALfloat)values[2];
857 return SetSourcefv(Source, Context, (int)prop, fvals);
860 ERR("Unexpected property: 0x%04x\n", prop);
861 RETERR(AL_INVALID_ENUM);
864 #undef CHECKVAL
867 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
869 ALdouble offsets[2];
870 ALdouble updateLen;
871 ALint ivals[3];
872 ALenum err;
874 switch(prop)
876 case AL_GAIN:
877 *values = Source->Gain;
878 return AL_NO_ERROR;
880 case AL_PITCH:
881 *values = Source->Pitch;
882 return AL_NO_ERROR;
884 case AL_MAX_DISTANCE:
885 *values = Source->MaxDistance;
886 return AL_NO_ERROR;
888 case AL_ROLLOFF_FACTOR:
889 *values = Source->RollOffFactor;
890 return AL_NO_ERROR;
892 case AL_REFERENCE_DISTANCE:
893 *values = Source->RefDistance;
894 return AL_NO_ERROR;
896 case AL_CONE_INNER_ANGLE:
897 *values = Source->InnerAngle;
898 return AL_NO_ERROR;
900 case AL_CONE_OUTER_ANGLE:
901 *values = Source->OuterAngle;
902 return AL_NO_ERROR;
904 case AL_MIN_GAIN:
905 *values = Source->MinGain;
906 return AL_NO_ERROR;
908 case AL_MAX_GAIN:
909 *values = Source->MaxGain;
910 return AL_NO_ERROR;
912 case AL_CONE_OUTER_GAIN:
913 *values = Source->OuterGain;
914 return AL_NO_ERROR;
916 case AL_SEC_OFFSET:
917 case AL_SAMPLE_OFFSET:
918 case AL_BYTE_OFFSET:
919 LockContext(Context);
920 updateLen = (ALdouble)Context->Device->UpdateSize /
921 Context->Device->Frequency;
922 GetSourceOffsets(Source, prop, offsets, updateLen);
923 UnlockContext(Context);
924 *values = offsets[0];
925 return AL_NO_ERROR;
927 case AL_CONE_OUTER_GAINHF:
928 *values = Source->OuterGainHF;
929 return AL_NO_ERROR;
931 case AL_AIR_ABSORPTION_FACTOR:
932 *values = Source->AirAbsorptionFactor;
933 return AL_NO_ERROR;
935 case AL_ROOM_ROLLOFF_FACTOR:
936 *values = Source->RoomRolloffFactor;
937 return AL_NO_ERROR;
939 case AL_DOPPLER_FACTOR:
940 *values = Source->DopplerFactor;
941 return AL_NO_ERROR;
943 case AL_SAMPLE_RW_OFFSETS_SOFT:
944 case AL_BYTE_RW_OFFSETS_SOFT:
945 LockContext(Context);
946 updateLen = (ALdouble)Context->Device->UpdateSize /
947 Context->Device->Frequency;
948 GetSourceOffsets(Source, prop, values, updateLen);
949 UnlockContext(Context);
950 return AL_NO_ERROR;
952 case AL_SEC_OFFSET_LATENCY_SOFT:
953 LockContext(Context);
954 values[0] = GetSourceSecOffset(Source);
955 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
956 1000000000.0;
957 UnlockContext(Context);
958 return AL_NO_ERROR;
960 case AL_POSITION:
961 LockContext(Context);
962 values[0] = Source->Position[0];
963 values[1] = Source->Position[1];
964 values[2] = Source->Position[2];
965 UnlockContext(Context);
966 return AL_NO_ERROR;
968 case AL_VELOCITY:
969 LockContext(Context);
970 values[0] = Source->Velocity[0];
971 values[1] = Source->Velocity[1];
972 values[2] = Source->Velocity[2];
973 UnlockContext(Context);
974 return AL_NO_ERROR;
976 case AL_DIRECTION:
977 LockContext(Context);
978 values[0] = Source->Orientation[0];
979 values[1] = Source->Orientation[1];
980 values[2] = Source->Orientation[2];
981 UnlockContext(Context);
982 return AL_NO_ERROR;
984 case AL_SOURCE_RELATIVE:
985 case AL_LOOPING:
986 case AL_BUFFER:
987 case AL_SOURCE_STATE:
988 case AL_BUFFERS_QUEUED:
989 case AL_BUFFERS_PROCESSED:
990 case AL_SOURCE_TYPE:
991 case AL_DIRECT_FILTER_GAINHF_AUTO:
992 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
993 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
994 case AL_DIRECT_CHANNELS_SOFT:
995 case AL_DISTANCE_MODEL:
996 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
997 *values = (ALdouble)ivals[0];
998 return err;
1001 ERR("Unexpected property: 0x%04x\n", prop);
1002 RETERR(AL_INVALID_ENUM);
1005 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1007 ALbufferlistitem *BufferList;
1008 ALdouble dvals[3];
1009 ALenum err;
1011 switch(prop)
1013 case AL_SOURCE_RELATIVE:
1014 *values = Source->HeadRelative;
1015 return AL_NO_ERROR;
1017 case AL_LOOPING:
1018 *values = Source->Looping;
1019 return AL_NO_ERROR;
1021 case AL_BUFFER:
1022 LockContext(Context);
1023 BufferList = Source->queue;
1024 if(Source->SourceType != AL_STATIC)
1026 ALuint i = Source->BuffersPlayed;
1027 while(i > 0)
1029 BufferList = BufferList->next;
1030 i--;
1033 *values = ((BufferList && BufferList->buffer) ?
1034 BufferList->buffer->id : 0);
1035 UnlockContext(Context);
1036 return AL_NO_ERROR;
1038 case AL_SOURCE_STATE:
1039 *values = Source->state;
1040 return AL_NO_ERROR;
1042 case AL_BUFFERS_QUEUED:
1043 *values = Source->BuffersInQueue;
1044 return AL_NO_ERROR;
1046 case AL_BUFFERS_PROCESSED:
1047 LockContext(Context);
1048 if(Source->Looping || Source->SourceType != AL_STREAMING)
1050 /* Buffers on a looping source are in a perpetual state of
1051 * PENDING, so don't report any as PROCESSED */
1052 *values = 0;
1054 else
1055 *values = Source->BuffersPlayed;
1056 UnlockContext(Context);
1057 return AL_NO_ERROR;
1059 case AL_SOURCE_TYPE:
1060 *values = Source->SourceType;
1061 return AL_NO_ERROR;
1063 case AL_DIRECT_FILTER_GAINHF_AUTO:
1064 *values = Source->DryGainHFAuto;
1065 return AL_NO_ERROR;
1067 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1068 *values = Source->WetGainAuto;
1069 return AL_NO_ERROR;
1071 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1072 *values = Source->WetGainHFAuto;
1073 return AL_NO_ERROR;
1075 case AL_DIRECT_CHANNELS_SOFT:
1076 *values = Source->DirectChannels;
1077 return AL_NO_ERROR;
1079 case AL_DISTANCE_MODEL:
1080 *values = Source->DistanceModel;
1081 return AL_NO_ERROR;
1083 case AL_MAX_DISTANCE:
1084 case AL_ROLLOFF_FACTOR:
1085 case AL_REFERENCE_DISTANCE:
1086 case AL_CONE_INNER_ANGLE:
1087 case AL_CONE_OUTER_ANGLE:
1088 case AL_SEC_OFFSET:
1089 case AL_SAMPLE_OFFSET:
1090 case AL_BYTE_OFFSET:
1091 case AL_DOPPLER_FACTOR:
1092 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1093 *values = (ALint)dvals[0];
1094 return err;
1096 case AL_SAMPLE_RW_OFFSETS_SOFT:
1097 case AL_BYTE_RW_OFFSETS_SOFT:
1098 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1100 values[0] = (ALint)dvals[0];
1101 values[1] = (ALint)dvals[1];
1103 return err;
1105 case AL_POSITION:
1106 case AL_VELOCITY:
1107 case AL_DIRECTION:
1108 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1110 values[0] = (ALint)dvals[0];
1111 values[1] = (ALint)dvals[1];
1112 values[2] = (ALint)dvals[2];
1114 return err;
1116 case siSampleOffsetLatencySOFT:
1117 /* i64 only */
1118 break;
1120 case siDirectFilter:
1121 case siAuxSendFilter:
1122 /* ??? */
1123 break;
1126 ERR("Unexpected property: 0x%04x\n", prop);
1127 RETERR(AL_INVALID_ENUM);
1130 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1132 ALdouble dvals[3];
1133 ALint ivals[3];
1134 ALenum err;
1136 switch(prop)
1138 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1139 LockContext(Context);
1140 values[0] = GetSourceOffset(Source);
1141 values[1] = ALCdevice_GetLatency(Context->Device);
1142 UnlockContext(Context);
1143 return AL_NO_ERROR;
1145 case AL_MAX_DISTANCE:
1146 case AL_ROLLOFF_FACTOR:
1147 case AL_REFERENCE_DISTANCE:
1148 case AL_CONE_INNER_ANGLE:
1149 case AL_CONE_OUTER_ANGLE:
1150 case AL_SEC_OFFSET:
1151 case AL_SAMPLE_OFFSET:
1152 case AL_BYTE_OFFSET:
1153 case AL_DOPPLER_FACTOR:
1154 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1155 *values = (ALint64)dvals[0];
1156 return err;
1158 case AL_SAMPLE_RW_OFFSETS_SOFT:
1159 case AL_BYTE_RW_OFFSETS_SOFT:
1160 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1162 values[0] = (ALint64)dvals[0];
1163 values[1] = (ALint64)dvals[1];
1165 return err;
1167 case AL_POSITION:
1168 case AL_VELOCITY:
1169 case AL_DIRECTION:
1170 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1172 values[0] = (ALint64)dvals[0];
1173 values[1] = (ALint64)dvals[1];
1174 values[2] = (ALint64)dvals[2];
1176 return err;
1178 case AL_SOURCE_RELATIVE:
1179 case AL_LOOPING:
1180 case AL_BUFFER:
1181 case AL_SOURCE_STATE:
1182 case AL_BUFFERS_QUEUED:
1183 case AL_BUFFERS_PROCESSED:
1184 case AL_SOURCE_TYPE:
1185 case AL_DIRECT_FILTER_GAINHF_AUTO:
1186 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1187 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1188 case AL_DIRECT_CHANNELS_SOFT:
1189 case AL_DISTANCE_MODEL:
1190 case siDirectFilter:
1191 case siAuxSendFilter:
1192 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
1193 *values = ivals[0];
1194 return err;
1197 ERR("Unexpected property: 0x%04x\n", prop);
1198 RETERR(AL_INVALID_ENUM);
1201 #undef RETERR
1204 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1206 ALCcontext *Context;
1207 ALsizei cur = 0;
1209 Context = GetContextRef();
1210 if(!Context) return;
1212 al_try
1214 ALenum err;
1216 CHECK_VALUE(Context, n >= 0);
1217 for(cur = 0;cur < n;cur++)
1219 ALsource *source = al_calloc(16, sizeof(ALsource));
1220 if(!source)
1221 al_throwerr(Context, AL_OUT_OF_MEMORY);
1222 InitSourceParams(source);
1224 err = NewThunkEntry(&source->id);
1225 if(err == AL_NO_ERROR)
1226 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
1227 if(err != AL_NO_ERROR)
1229 FreeThunkEntry(source->id);
1230 memset(source, 0, sizeof(ALsource));
1231 al_free(source);
1233 al_throwerr(Context, err);
1236 sources[cur] = source->id;
1239 al_catchany()
1241 if(cur > 0)
1242 alDeleteSources(cur, sources);
1244 al_endtry;
1246 ALCcontext_DecRef(Context);
1250 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1252 ALCcontext *Context;
1254 Context = GetContextRef();
1255 if(!Context) return;
1257 al_try
1259 ALbufferlistitem *BufferList;
1260 ALsource *Source;
1261 ALsizei i, j;
1263 CHECK_VALUE(Context, n >= 0);
1265 /* Check that all Sources are valid */
1266 for(i = 0;i < n;i++)
1268 if(LookupSource(Context, sources[i]) == NULL)
1269 al_throwerr(Context, AL_INVALID_NAME);
1272 for(i = 0;i < n;i++)
1274 ALsource **srclist, **srclistend;
1276 if((Source=RemoveSource(Context, sources[i])) == NULL)
1277 continue;
1278 FreeThunkEntry(Source->id);
1280 LockContext(Context);
1281 srclist = Context->ActiveSources;
1282 srclistend = srclist + Context->ActiveSourceCount;
1283 while(srclist != srclistend)
1285 if(*srclist == Source)
1287 Context->ActiveSourceCount--;
1288 *srclist = *(--srclistend);
1289 break;
1291 srclist++;
1293 UnlockContext(Context);
1295 while(Source->queue != NULL)
1297 BufferList = Source->queue;
1298 Source->queue = BufferList->next;
1300 if(BufferList->buffer != NULL)
1301 DecrementRef(&BufferList->buffer->ref);
1302 free(BufferList);
1305 for(j = 0;j < MAX_SENDS;++j)
1307 if(Source->Send[j].Slot)
1308 DecrementRef(&Source->Send[j].Slot->ref);
1309 Source->Send[j].Slot = NULL;
1312 memset(Source, 0, sizeof(*Source));
1313 al_free(Source);
1316 al_endtry;
1318 ALCcontext_DecRef(Context);
1322 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1324 ALCcontext *Context;
1325 ALboolean result;
1327 Context = GetContextRef();
1328 if(!Context) return AL_FALSE;
1330 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
1332 ALCcontext_DecRef(Context);
1334 return result;
1338 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1340 ALCcontext *Context;
1341 ALsource *Source;
1343 Context = GetContextRef();
1344 if(!Context) return;
1346 if((Source=LookupSource(Context, source)) == NULL)
1347 alSetError(Context, AL_INVALID_NAME);
1348 else if(!(FloatValsByProp(param) == 1))
1349 alSetError(Context, AL_INVALID_ENUM);
1350 else
1351 SetSourcefv(Source, Context, param, &value);
1353 ALCcontext_DecRef(Context);
1356 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1358 ALCcontext *Context;
1359 ALsource *Source;
1361 Context = GetContextRef();
1362 if(!Context) return;
1364 if((Source=LookupSource(Context, source)) == NULL)
1365 alSetError(Context, AL_INVALID_NAME);
1366 else if(!(FloatValsByProp(param) == 3))
1367 alSetError(Context, AL_INVALID_ENUM);
1368 else
1370 ALfloat fvals[3] = { value1, value2, value3 };
1371 SetSourcefv(Source, Context, param, fvals);
1374 ALCcontext_DecRef(Context);
1377 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1379 ALCcontext *Context;
1380 ALsource *Source;
1382 Context = GetContextRef();
1383 if(!Context) return;
1385 if((Source=LookupSource(Context, source)) == NULL)
1386 alSetError(Context, AL_INVALID_NAME);
1387 else if(!values)
1388 alSetError(Context, AL_INVALID_VALUE);
1389 else if(!(FloatValsByProp(param) > 0))
1390 alSetError(Context, AL_INVALID_ENUM);
1391 else
1392 SetSourcefv(Source, Context, param, values);
1394 ALCcontext_DecRef(Context);
1398 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1400 ALCcontext *Context;
1401 ALsource *Source;
1403 Context = GetContextRef();
1404 if(!Context) return;
1406 if((Source=LookupSource(Context, source)) == NULL)
1407 alSetError(Context, AL_INVALID_NAME);
1408 else if(!(DoubleValsByProp(param) == 1))
1409 alSetError(Context, AL_INVALID_ENUM);
1410 else
1412 ALfloat fval = (ALfloat)value;
1413 SetSourcefv(Source, Context, param, &fval);
1416 ALCcontext_DecRef(Context);
1419 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1421 ALCcontext *Context;
1422 ALsource *Source;
1424 Context = GetContextRef();
1425 if(!Context) return;
1427 if((Source=LookupSource(Context, source)) == NULL)
1428 alSetError(Context, AL_INVALID_NAME);
1429 else if(!(DoubleValsByProp(param) == 3))
1430 alSetError(Context, AL_INVALID_ENUM);
1431 else
1433 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1434 SetSourcefv(Source, Context, param, fvals);
1437 ALCcontext_DecRef(Context);
1440 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1442 ALCcontext *Context;
1443 ALsource *Source;
1444 ALint count;
1446 Context = GetContextRef();
1447 if(!Context) return;
1449 if((Source=LookupSource(Context, source)) == NULL)
1450 alSetError(Context, AL_INVALID_NAME);
1451 else if(!values)
1452 alSetError(Context, AL_INVALID_VALUE);
1453 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1454 alSetError(Context, AL_INVALID_ENUM);
1455 else
1457 ALfloat fvals[3];
1458 ALint i;
1460 for(i = 0;i < count;i++)
1461 fvals[i] = (ALfloat)values[i];
1462 SetSourcefv(Source, Context, param, fvals);
1465 ALCcontext_DecRef(Context);
1469 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1471 ALCcontext *Context;
1472 ALsource *Source;
1474 Context = GetContextRef();
1475 if(!Context) return;
1477 if((Source=LookupSource(Context, source)) == NULL)
1478 alSetError(Context, AL_INVALID_NAME);
1479 else if(!(IntValsByProp(param) == 1))
1480 alSetError(Context, AL_INVALID_ENUM);
1481 else
1482 SetSourceiv(Source, Context, param, &value);
1484 ALCcontext_DecRef(Context);
1487 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1489 ALCcontext *Context;
1490 ALsource *Source;
1492 Context = GetContextRef();
1493 if(!Context) return;
1495 if((Source=LookupSource(Context, source)) == NULL)
1496 alSetError(Context, AL_INVALID_NAME);
1497 else if(!(IntValsByProp(param) == 3))
1498 alSetError(Context, AL_INVALID_ENUM);
1499 else
1501 ALint ivals[3] = { value1, value2, value3 };
1502 SetSourceiv(Source, Context, param, ivals);
1505 ALCcontext_DecRef(Context);
1508 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1510 ALCcontext *Context;
1511 ALsource *Source;
1513 Context = GetContextRef();
1514 if(!Context) return;
1516 if((Source=LookupSource(Context, source)) == NULL)
1517 alSetError(Context, AL_INVALID_NAME);
1518 else if(!values)
1519 alSetError(Context, AL_INVALID_VALUE);
1520 else if(!(IntValsByProp(param) > 0))
1521 alSetError(Context, AL_INVALID_ENUM);
1522 else
1523 SetSourceiv(Source, Context, param, values);
1525 ALCcontext_DecRef(Context);
1529 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1531 ALCcontext *Context;
1532 ALsource *Source;
1534 Context = GetContextRef();
1535 if(!Context) return;
1537 if((Source=LookupSource(Context, source)) == NULL)
1538 alSetError(Context, AL_INVALID_NAME);
1539 else if(!(Int64ValsByProp(param) == 1))
1540 alSetError(Context, AL_INVALID_ENUM);
1541 else
1542 SetSourcei64v(Source, Context, param, &value);
1544 ALCcontext_DecRef(Context);
1547 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1549 ALCcontext *Context;
1550 ALsource *Source;
1552 Context = GetContextRef();
1553 if(!Context) return;
1555 if((Source=LookupSource(Context, source)) == NULL)
1556 alSetError(Context, AL_INVALID_NAME);
1557 else if(!(Int64ValsByProp(param) == 3))
1558 alSetError(Context, AL_INVALID_ENUM);
1559 else
1561 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1562 SetSourcei64v(Source, Context, param, i64vals);
1565 ALCcontext_DecRef(Context);
1568 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1570 ALCcontext *Context;
1571 ALsource *Source;
1573 Context = GetContextRef();
1574 if(!Context) return;
1576 if((Source=LookupSource(Context, source)) == NULL)
1577 alSetError(Context, AL_INVALID_NAME);
1578 else if(!values)
1579 alSetError(Context, AL_INVALID_VALUE);
1580 else if(!(Int64ValsByProp(param) > 0))
1581 alSetError(Context, AL_INVALID_ENUM);
1582 else
1583 SetSourcei64v(Source, Context, param, values);
1585 ALCcontext_DecRef(Context);
1589 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1591 ALCcontext *Context;
1592 ALsource *Source;
1594 Context = GetContextRef();
1595 if(!Context) return;
1597 if((Source=LookupSource(Context, source)) == NULL)
1598 alSetError(Context, AL_INVALID_NAME);
1599 else if(!value)
1600 alSetError(Context, AL_INVALID_VALUE);
1601 else if(!(FloatValsByProp(param) == 1))
1602 alSetError(Context, AL_INVALID_ENUM);
1603 else
1605 ALdouble dval;
1606 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1607 *value = (ALfloat)dval;
1610 ALCcontext_DecRef(Context);
1614 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1616 ALCcontext *Context;
1617 ALsource *Source;
1619 Context = GetContextRef();
1620 if(!Context) return;
1622 if((Source=LookupSource(Context, source)) == NULL)
1623 alSetError(Context, AL_INVALID_NAME);
1624 else if(!(value1 && value2 && value3))
1625 alSetError(Context, AL_INVALID_VALUE);
1626 else if(!(FloatValsByProp(param) == 3))
1627 alSetError(Context, AL_INVALID_ENUM);
1628 else
1630 ALdouble dvals[3];
1631 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1633 *value1 = (ALfloat)dvals[0];
1634 *value2 = (ALfloat)dvals[1];
1635 *value3 = (ALfloat)dvals[2];
1639 ALCcontext_DecRef(Context);
1643 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1645 ALCcontext *Context;
1646 ALsource *Source;
1647 ALint count;
1649 Context = GetContextRef();
1650 if(!Context) return;
1652 if((Source=LookupSource(Context, source)) == NULL)
1653 alSetError(Context, AL_INVALID_NAME);
1654 else if(!values)
1655 alSetError(Context, AL_INVALID_VALUE);
1656 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1657 alSetError(Context, AL_INVALID_ENUM);
1658 else
1660 ALdouble dvals[3];
1661 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1663 ALint i;
1664 for(i = 0;i < count;i++)
1665 values[i] = (ALfloat)dvals[i];
1669 ALCcontext_DecRef(Context);
1673 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1675 ALCcontext *Context;
1676 ALsource *Source;
1678 Context = GetContextRef();
1679 if(!Context) return;
1681 if((Source=LookupSource(Context, source)) == NULL)
1682 alSetError(Context, AL_INVALID_NAME);
1683 else if(!value)
1684 alSetError(Context, AL_INVALID_VALUE);
1685 else if(!(DoubleValsByProp(param) == 1))
1686 alSetError(Context, AL_INVALID_ENUM);
1687 else
1688 GetSourcedv(Source, Context, param, value);
1690 ALCcontext_DecRef(Context);
1693 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1695 ALCcontext *Context;
1696 ALsource *Source;
1698 Context = GetContextRef();
1699 if(!Context) return;
1701 if((Source=LookupSource(Context, source)) == NULL)
1702 alSetError(Context, AL_INVALID_NAME);
1703 else if(!(value1 && value2 && value3))
1704 alSetError(Context, AL_INVALID_VALUE);
1705 else if(!(DoubleValsByProp(param) == 3))
1706 alSetError(Context, AL_INVALID_ENUM);
1707 else
1709 ALdouble dvals[3];
1710 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1712 *value1 = dvals[0];
1713 *value2 = dvals[1];
1714 *value3 = dvals[2];
1718 ALCcontext_DecRef(Context);
1721 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1723 ALCcontext *Context;
1724 ALsource *Source;
1726 Context = GetContextRef();
1727 if(!Context) return;
1729 if((Source=LookupSource(Context, source)) == NULL)
1730 alSetError(Context, AL_INVALID_NAME);
1731 else if(!values)
1732 alSetError(Context, AL_INVALID_VALUE);
1733 else if(!(DoubleValsByProp(param) > 0))
1734 alSetError(Context, AL_INVALID_ENUM);
1735 else
1736 GetSourcedv(Source, Context, param, values);
1738 ALCcontext_DecRef(Context);
1742 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1744 ALCcontext *Context;
1745 ALsource *Source;
1747 Context = GetContextRef();
1748 if(!Context) return;
1750 if((Source=LookupSource(Context, source)) == NULL)
1751 alSetError(Context, AL_INVALID_NAME);
1752 else if(!value)
1753 alSetError(Context, AL_INVALID_VALUE);
1754 else if(!(IntValsByProp(param) == 1))
1755 alSetError(Context, AL_INVALID_ENUM);
1756 else
1757 GetSourceiv(Source, Context, param, value);
1759 ALCcontext_DecRef(Context);
1763 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1765 ALCcontext *Context;
1766 ALsource *Source;
1768 Context = GetContextRef();
1769 if(!Context) return;
1771 if((Source=LookupSource(Context, source)) == NULL)
1772 alSetError(Context, AL_INVALID_NAME);
1773 else if(!(value1 && value2 && value3))
1774 alSetError(Context, AL_INVALID_VALUE);
1775 else if(!(IntValsByProp(param) == 3))
1776 alSetError(Context, AL_INVALID_ENUM);
1777 else
1779 ALint ivals[3];
1780 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1782 *value1 = ivals[0];
1783 *value2 = ivals[1];
1784 *value3 = ivals[2];
1788 ALCcontext_DecRef(Context);
1792 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1794 ALCcontext *Context;
1795 ALsource *Source;
1797 Context = GetContextRef();
1798 if(!Context) return;
1800 if((Source=LookupSource(Context, source)) == NULL)
1801 alSetError(Context, AL_INVALID_NAME);
1802 else if(!values)
1803 alSetError(Context, AL_INVALID_VALUE);
1804 else if(!(IntValsByProp(param) > 0))
1805 alSetError(Context, AL_INVALID_ENUM);
1806 else
1807 GetSourceiv(Source, Context, param, values);
1809 ALCcontext_DecRef(Context);
1813 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1815 ALCcontext *Context;
1816 ALsource *Source;
1818 Context = GetContextRef();
1819 if(!Context) return;
1821 if((Source=LookupSource(Context, source)) == NULL)
1822 alSetError(Context, AL_INVALID_NAME);
1823 else if(!value)
1824 alSetError(Context, AL_INVALID_VALUE);
1825 else if(!(Int64ValsByProp(param) == 1))
1826 alSetError(Context, AL_INVALID_ENUM);
1827 else
1828 GetSourcei64v(Source, Context, param, value);
1830 ALCcontext_DecRef(Context);
1833 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1835 ALCcontext *Context;
1836 ALsource *Source;
1838 Context = GetContextRef();
1839 if(!Context) return;
1841 if((Source=LookupSource(Context, source)) == NULL)
1842 alSetError(Context, AL_INVALID_NAME);
1843 else if(!(value1 && value2 && value3))
1844 alSetError(Context, AL_INVALID_VALUE);
1845 else if(!(Int64ValsByProp(param) == 3))
1846 alSetError(Context, AL_INVALID_ENUM);
1847 else
1849 ALint64 i64vals[3];
1850 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1852 *value1 = i64vals[0];
1853 *value2 = i64vals[1];
1854 *value3 = i64vals[2];
1858 ALCcontext_DecRef(Context);
1861 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1863 ALCcontext *Context;
1864 ALsource *Source;
1866 Context = GetContextRef();
1867 if(!Context) return;
1869 if((Source=LookupSource(Context, source)) == NULL)
1870 alSetError(Context, AL_INVALID_NAME);
1871 else if(!values)
1872 alSetError(Context, AL_INVALID_VALUE);
1873 else if(!(Int64ValsByProp(param) > 0))
1874 alSetError(Context, AL_INVALID_ENUM);
1875 else
1876 GetSourcei64v(Source, Context, param, values);
1878 ALCcontext_DecRef(Context);
1882 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1884 alSourcePlayv(1, &source);
1886 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1888 ALCcontext *Context;
1889 ALsource *Source;
1890 ALsizei i;
1892 Context = GetContextRef();
1893 if(!Context) return;
1895 al_try
1897 CHECK_VALUE(Context, n >= 0);
1898 for(i = 0;i < n;i++)
1900 if(!LookupSource(Context, sources[i]))
1901 al_throwerr(Context, AL_INVALID_NAME);
1904 LockContext(Context);
1905 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1907 void *temp = NULL;
1908 ALsizei newcount;
1910 newcount = Context->MaxActiveSources << 1;
1911 if(newcount > 0)
1912 temp = realloc(Context->ActiveSources,
1913 sizeof(*Context->ActiveSources) * newcount);
1914 if(!temp)
1916 UnlockContext(Context);
1917 al_throwerr(Context, AL_OUT_OF_MEMORY);
1920 Context->ActiveSources = temp;
1921 Context->MaxActiveSources = newcount;
1924 for(i = 0;i < n;i++)
1926 Source = LookupSource(Context, sources[i]);
1927 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1928 else SetSourceState(Source, Context, AL_PLAYING);
1930 UnlockContext(Context);
1932 al_endtry;
1934 ALCcontext_DecRef(Context);
1937 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1939 alSourcePausev(1, &source);
1941 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1943 ALCcontext *Context;
1944 ALsource *Source;
1945 ALsizei i;
1947 Context = GetContextRef();
1948 if(!Context) return;
1950 al_try
1952 CHECK_VALUE(Context, n >= 0);
1953 for(i = 0;i < n;i++)
1955 if(!LookupSource(Context, sources[i]))
1956 al_throwerr(Context, AL_INVALID_NAME);
1959 LockContext(Context);
1960 for(i = 0;i < n;i++)
1962 Source = LookupSource(Context, sources[i]);
1963 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1964 else SetSourceState(Source, Context, AL_PAUSED);
1966 UnlockContext(Context);
1968 al_endtry;
1970 ALCcontext_DecRef(Context);
1973 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1975 alSourceStopv(1, &source);
1977 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1979 ALCcontext *Context;
1980 ALsource *Source;
1981 ALsizei i;
1983 Context = GetContextRef();
1984 if(!Context) return;
1986 al_try
1988 CHECK_VALUE(Context, n >= 0);
1989 for(i = 0;i < n;i++)
1991 if(!LookupSource(Context, sources[i]))
1992 al_throwerr(Context, AL_INVALID_NAME);
1995 LockContext(Context);
1996 for(i = 0;i < n;i++)
1998 Source = LookupSource(Context, sources[i]);
1999 Source->new_state = AL_NONE;
2000 SetSourceState(Source, Context, AL_STOPPED);
2002 UnlockContext(Context);
2004 al_endtry;
2006 ALCcontext_DecRef(Context);
2009 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2011 alSourceRewindv(1, &source);
2013 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2015 ALCcontext *Context;
2016 ALsource *Source;
2017 ALsizei i;
2019 Context = GetContextRef();
2020 if(!Context) return;
2022 al_try
2024 CHECK_VALUE(Context, n >= 0);
2025 for(i = 0;i < n;i++)
2027 if(!LookupSource(Context, sources[i]))
2028 al_throwerr(Context, AL_INVALID_NAME);
2031 LockContext(Context);
2032 for(i = 0;i < n;i++)
2034 Source = LookupSource(Context, sources[i]);
2035 Source->new_state = AL_NONE;
2036 SetSourceState(Source, Context, AL_INITIAL);
2038 UnlockContext(Context);
2040 al_endtry;
2042 ALCcontext_DecRef(Context);
2046 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2048 ALCcontext *Context;
2049 ALsource *Source;
2050 ALsizei i;
2051 ALbufferlistitem *BufferListStart = NULL;
2052 ALbufferlistitem *BufferList;
2053 ALbuffer *BufferFmt;
2055 if(nb == 0)
2056 return;
2058 Context = GetContextRef();
2059 if(!Context) return;
2061 al_try
2063 ALCdevice *device = Context->Device;
2065 CHECK_VALUE(Context, nb >= 0);
2067 if((Source=LookupSource(Context, source)) == NULL)
2068 al_throwerr(Context, AL_INVALID_NAME);
2070 LockContext(Context);
2071 if(Source->SourceType == AL_STATIC)
2073 UnlockContext(Context);
2074 /* Can't queue on a Static Source */
2075 al_throwerr(Context, AL_INVALID_OPERATION);
2078 BufferFmt = NULL;
2080 /* Check for a valid Buffer, for its frequency and format */
2081 BufferList = Source->queue;
2082 while(BufferList)
2084 if(BufferList->buffer)
2086 BufferFmt = BufferList->buffer;
2087 break;
2089 BufferList = BufferList->next;
2092 for(i = 0;i < nb;i++)
2094 ALbuffer *buffer = NULL;
2095 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2097 UnlockContext(Context);
2098 al_throwerr(Context, AL_INVALID_NAME);
2101 if(!BufferListStart)
2103 BufferListStart = malloc(sizeof(ALbufferlistitem));
2104 BufferListStart->buffer = buffer;
2105 BufferListStart->next = NULL;
2106 BufferListStart->prev = NULL;
2107 BufferList = BufferListStart;
2109 else
2111 BufferList->next = malloc(sizeof(ALbufferlistitem));
2112 BufferList->next->buffer = buffer;
2113 BufferList->next->next = NULL;
2114 BufferList->next->prev = BufferList;
2115 BufferList = BufferList->next;
2117 if(!buffer) continue;
2118 IncrementRef(&buffer->ref);
2120 ReadLock(&buffer->lock);
2121 if(BufferFmt == NULL)
2123 BufferFmt = buffer;
2125 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2126 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2127 if(buffer->FmtChannels == FmtMono)
2128 Source->Update = CalcSourceParams;
2129 else
2130 Source->Update = CalcNonAttnSourceParams;
2132 Source->NeedsUpdate = AL_TRUE;
2134 else if(BufferFmt->Frequency != buffer->Frequency ||
2135 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2136 BufferFmt->OriginalType != buffer->OriginalType)
2138 ReadUnlock(&buffer->lock);
2139 UnlockContext(Context);
2140 al_throwerr(Context, AL_INVALID_OPERATION);
2142 ReadUnlock(&buffer->lock);
2145 /* Source is now streaming */
2146 Source->SourceType = AL_STREAMING;
2148 if(Source->queue == NULL)
2149 Source->queue = BufferListStart;
2150 else
2152 /* Append to the end of the queue */
2153 BufferList = Source->queue;
2154 while(BufferList->next != NULL)
2155 BufferList = BufferList->next;
2157 BufferListStart->prev = BufferList;
2158 BufferList->next = BufferListStart;
2161 Source->BuffersInQueue += nb;
2163 UnlockContext(Context);
2165 al_catchany()
2167 while(BufferListStart)
2169 BufferList = BufferListStart;
2170 BufferListStart = BufferList->next;
2172 if(BufferList->buffer)
2173 DecrementRef(&BufferList->buffer->ref);
2174 free(BufferList);
2177 al_endtry;
2179 ALCcontext_DecRef(Context);
2182 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2184 ALCcontext *Context;
2185 ALsource *Source;
2186 ALsizei i;
2187 ALbufferlistitem *BufferList;
2189 if(nb == 0)
2190 return;
2192 Context = GetContextRef();
2193 if(!Context) return;
2195 al_try
2197 CHECK_VALUE(Context, nb >= 0);
2199 if((Source=LookupSource(Context, source)) == NULL)
2200 al_throwerr(Context, AL_INVALID_NAME);
2202 LockContext(Context);
2203 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2204 (ALuint)nb > Source->BuffersPlayed)
2206 UnlockContext(Context);
2207 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2208 al_throwerr(Context, AL_INVALID_VALUE);
2211 for(i = 0;i < nb;i++)
2213 BufferList = Source->queue;
2214 Source->queue = BufferList->next;
2215 Source->BuffersInQueue--;
2216 Source->BuffersPlayed--;
2218 if(BufferList->buffer)
2220 buffers[i] = BufferList->buffer->id;
2221 DecrementRef(&BufferList->buffer->ref);
2223 else
2224 buffers[i] = 0;
2226 free(BufferList);
2228 if(Source->queue)
2229 Source->queue->prev = NULL;
2230 UnlockContext(Context);
2232 al_endtry;
2234 ALCcontext_DecRef(Context);
2238 static ALvoid InitSourceParams(ALsource *Source)
2240 ALuint i;
2242 Source->InnerAngle = 360.0f;
2243 Source->OuterAngle = 360.0f;
2244 Source->Pitch = 1.0f;
2245 Source->Position[0] = 0.0f;
2246 Source->Position[1] = 0.0f;
2247 Source->Position[2] = 0.0f;
2248 Source->Orientation[0] = 0.0f;
2249 Source->Orientation[1] = 0.0f;
2250 Source->Orientation[2] = 0.0f;
2251 Source->Velocity[0] = 0.0f;
2252 Source->Velocity[1] = 0.0f;
2253 Source->Velocity[2] = 0.0f;
2254 Source->RefDistance = 1.0f;
2255 Source->MaxDistance = FLT_MAX;
2256 Source->RollOffFactor = 1.0f;
2257 Source->Looping = AL_FALSE;
2258 Source->Gain = 1.0f;
2259 Source->MinGain = 0.0f;
2260 Source->MaxGain = 1.0f;
2261 Source->OuterGain = 0.0f;
2262 Source->OuterGainHF = 1.0f;
2264 Source->DryGainHFAuto = AL_TRUE;
2265 Source->WetGainAuto = AL_TRUE;
2266 Source->WetGainHFAuto = AL_TRUE;
2267 Source->AirAbsorptionFactor = 0.0f;
2268 Source->RoomRolloffFactor = 0.0f;
2269 Source->DopplerFactor = 1.0f;
2270 Source->DirectChannels = AL_FALSE;
2272 Source->DistanceModel = DefaultDistanceModel;
2274 Source->Resampler = DefaultResampler;
2276 Source->state = AL_INITIAL;
2277 Source->new_state = AL_NONE;
2278 Source->SourceType = AL_UNDETERMINED;
2279 Source->Offset = -1.0;
2281 Source->DirectGain = 1.0f;
2282 Source->DirectGainHF = 1.0f;
2283 for(i = 0;i < MAX_SENDS;i++)
2285 Source->Send[i].Gain = 1.0f;
2286 Source->Send[i].GainHF = 1.0f;
2289 Source->NeedsUpdate = AL_TRUE;
2291 Source->Hrtf.Moving = AL_FALSE;
2292 Source->Hrtf.Counter = 0;
2296 /* SetSourceState
2298 * Sets the source's new play state given its current state.
2300 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2302 if(state == AL_PLAYING)
2304 ALbufferlistitem *BufferList;
2305 ALsizei j, k;
2307 /* Check that there is a queue containing at least one valid, non zero
2308 * length Buffer. */
2309 BufferList = Source->queue;
2310 while(BufferList)
2312 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2313 break;
2314 BufferList = BufferList->next;
2317 if(Source->state != AL_PLAYING)
2319 for(j = 0;j < MaxChannels;j++)
2321 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2322 Source->Hrtf.History[j][k] = 0.0f;
2323 for(k = 0;k < HRIR_LENGTH;k++)
2325 Source->Hrtf.Values[j][k][0] = 0.0f;
2326 Source->Hrtf.Values[j][k][1] = 0.0f;
2331 if(Source->state != AL_PAUSED)
2333 Source->state = AL_PLAYING;
2334 Source->position = 0;
2335 Source->position_fraction = 0;
2336 Source->BuffersPlayed = 0;
2338 else
2339 Source->state = AL_PLAYING;
2341 // Check if an Offset has been set
2342 if(Source->Offset >= 0.0)
2343 ApplyOffset(Source);
2345 /* If there's nothing to play, or device is disconnected, go right to
2346 * stopped */
2347 if(!BufferList || !Context->Device->Connected)
2349 SetSourceState(Source, Context, AL_STOPPED);
2350 return;
2353 for(j = 0;j < Context->ActiveSourceCount;j++)
2355 if(Context->ActiveSources[j] == Source)
2356 break;
2358 if(j == Context->ActiveSourceCount)
2359 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2361 else if(state == AL_PAUSED)
2363 if(Source->state == AL_PLAYING)
2365 Source->state = AL_PAUSED;
2366 Source->Hrtf.Moving = AL_FALSE;
2367 Source->Hrtf.Counter = 0;
2370 else if(state == AL_STOPPED)
2372 if(Source->state != AL_INITIAL)
2374 Source->state = AL_STOPPED;
2375 Source->BuffersPlayed = Source->BuffersInQueue;
2376 Source->Hrtf.Moving = AL_FALSE;
2377 Source->Hrtf.Counter = 0;
2379 Source->Offset = -1.0;
2381 else if(state == AL_INITIAL)
2383 if(Source->state != AL_INITIAL)
2385 Source->state = AL_INITIAL;
2386 Source->position = 0;
2387 Source->position_fraction = 0;
2388 Source->BuffersPlayed = 0;
2389 Source->Hrtf.Moving = AL_FALSE;
2390 Source->Hrtf.Counter = 0;
2392 Source->Offset = -1.0;
2396 /* GetSourceOffset
2398 * Gets the current read offset for the given Source, in 32.32 fixed-point
2399 * samples. The offset is relative to the start of the queue (not the start of
2400 * the current buffer).
2402 static ALint64 GetSourceOffset(const ALsource *Source)
2404 const ALbufferlistitem *BufferList;
2405 ALuint64 readPos;
2406 ALuint i;
2408 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2409 return 0;
2411 /* NOTE: This is the offset into the *current* buffer, so add the length of
2412 * any played buffers */
2413 readPos = (ALuint64)Source->position << 32;
2414 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2415 BufferList = Source->queue;
2416 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2418 if(BufferList->buffer)
2419 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2420 BufferList = BufferList->next;
2423 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2426 /* GetSourceSecOffset
2428 * Gets the current read offset for the given Source, in seconds. The offset is
2429 * relative to the start of the queue (not the start of the current buffer).
2431 static ALdouble GetSourceSecOffset(const ALsource *Source)
2433 const ALbufferlistitem *BufferList;
2434 const ALbuffer *Buffer = NULL;
2435 ALuint64 readPos;
2436 ALuint i;
2438 BufferList = Source->queue;
2439 while(BufferList)
2441 if(BufferList->buffer)
2443 Buffer = BufferList->buffer;
2444 break;
2446 BufferList = BufferList->next;
2449 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2450 return 0.0;
2452 /* NOTE: This is the offset into the *current* buffer, so add the length of
2453 * any played buffers */
2454 readPos = (ALuint64)Source->position << FRACTIONBITS;
2455 readPos |= (ALuint64)Source->position_fraction;
2456 BufferList = Source->queue;
2457 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2459 if(BufferList->buffer)
2460 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2461 BufferList = BufferList->next;
2464 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2467 /* GetSourceOffsets
2469 * Gets the current read and write offsets for the given Source, in the
2470 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2471 * the start of the queue (not the start of the current buffer).
2473 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2475 const ALbufferlistitem *BufferList;
2476 const ALbuffer *Buffer = NULL;
2477 ALuint readPos, writePos;
2478 ALuint totalBufferLen;
2479 ALuint i;
2481 // Find the first valid Buffer in the Queue
2482 BufferList = Source->queue;
2483 while(BufferList)
2485 if(BufferList->buffer)
2487 Buffer = BufferList->buffer;
2488 break;
2490 BufferList = BufferList->next;
2493 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2495 offset[0] = 0.0;
2496 offset[1] = 0.0;
2497 return;
2500 if(updateLen > 0.0 && updateLen < 0.015)
2501 updateLen = 0.015;
2503 /* NOTE: This is the offset into the *current* buffer, so add the length of
2504 * any played buffers */
2505 readPos = Source->position;
2506 totalBufferLen = 0;
2507 BufferList = Source->queue;
2508 for(i = 0;BufferList;i++)
2510 if(BufferList->buffer)
2512 if(i < Source->BuffersPlayed)
2513 readPos += BufferList->buffer->SampleLen;
2514 totalBufferLen += BufferList->buffer->SampleLen;
2516 BufferList = BufferList->next;
2518 if(Source->state == AL_PLAYING)
2519 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2520 else
2521 writePos = readPos;
2523 if(Source->Looping)
2525 readPos %= totalBufferLen;
2526 writePos %= totalBufferLen;
2528 else
2530 /* Wrap positions back to 0 */
2531 if(readPos >= totalBufferLen)
2532 readPos = 0;
2533 if(writePos >= totalBufferLen)
2534 writePos = 0;
2537 switch(name)
2539 case AL_SEC_OFFSET:
2540 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2541 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2542 break;
2544 case AL_SAMPLE_OFFSET:
2545 case AL_SAMPLE_RW_OFFSETS_SOFT:
2546 offset[0] = (ALdouble)readPos;
2547 offset[1] = (ALdouble)writePos;
2548 break;
2550 case AL_BYTE_OFFSET:
2551 case AL_BYTE_RW_OFFSETS_SOFT:
2552 if(Buffer->OriginalType == UserFmtIMA4)
2554 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2555 ALuint FrameBlockSize = 65;
2557 /* Round down to nearest ADPCM block */
2558 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2559 if(Source->state != AL_PLAYING)
2560 offset[1] = offset[0];
2561 else
2563 /* Round up to nearest ADPCM block */
2564 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2565 FrameBlockSize * BlockSize);
2568 else
2570 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2571 offset[0] = (ALdouble)(readPos * FrameSize);
2572 offset[1] = (ALdouble)(writePos * FrameSize);
2574 break;
2579 /* ApplyOffset
2581 * Apply the stored playback offset to the Source. This function will update
2582 * the number of buffers "played" given the stored offset.
2584 ALboolean ApplyOffset(ALsource *Source)
2586 const ALbufferlistitem *BufferList;
2587 const ALbuffer *Buffer;
2588 ALint bufferLen, totalBufferLen;
2589 ALint buffersPlayed;
2590 ALint offset;
2592 /* Get sample frame offset */
2593 offset = GetSampleOffset(Source);
2594 if(offset == -1)
2595 return AL_FALSE;
2597 buffersPlayed = 0;
2598 totalBufferLen = 0;
2600 BufferList = Source->queue;
2601 while(BufferList)
2603 Buffer = BufferList->buffer;
2604 bufferLen = Buffer ? Buffer->SampleLen : 0;
2606 if(bufferLen <= offset-totalBufferLen)
2608 /* Offset is past this buffer so increment to the next buffer */
2609 buffersPlayed++;
2611 else if(totalBufferLen <= offset)
2613 /* Offset is in this buffer */
2614 Source->BuffersPlayed = buffersPlayed;
2616 Source->position = offset - totalBufferLen;
2617 Source->position_fraction = 0;
2618 return AL_TRUE;
2621 totalBufferLen += bufferLen;
2623 BufferList = BufferList->next;
2626 /* Offset is out of range of the queue */
2627 return AL_FALSE;
2631 /* GetSampleOffset
2633 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2634 * Second offset supplied by the application). This takes into account the fact
2635 * that the buffer format may have been modifed since.
2637 static ALint GetSampleOffset(ALsource *Source)
2639 const ALbuffer *Buffer = NULL;
2640 const ALbufferlistitem *BufferList;
2641 ALint Offset = -1;
2643 /* Find the first valid Buffer in the Queue */
2644 BufferList = Source->queue;
2645 while(BufferList)
2647 if(BufferList->buffer)
2649 Buffer = BufferList->buffer;
2650 break;
2652 BufferList = BufferList->next;
2655 if(!Buffer)
2657 Source->Offset = -1.0;
2658 return -1;
2661 switch(Source->OffsetType)
2663 case AL_BYTE_OFFSET:
2664 /* Determine the ByteOffset (and ensure it is block aligned) */
2665 Offset = (ALint)Source->Offset;
2666 if(Buffer->OriginalType == UserFmtIMA4)
2668 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2669 Offset *= 65;
2671 else
2672 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2673 break;
2675 case AL_SAMPLE_OFFSET:
2676 Offset = (ALint)Source->Offset;
2677 break;
2679 case AL_SEC_OFFSET:
2680 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2681 break;
2683 Source->Offset = -1.0;
2685 return Offset;
2689 /* ReleaseALSources
2691 * Destroys all sources in the source map.
2693 ALvoid ReleaseALSources(ALCcontext *Context)
2695 ALsizei pos;
2696 ALuint j;
2697 for(pos = 0;pos < Context->SourceMap.size;pos++)
2699 ALsource *temp = Context->SourceMap.array[pos].value;
2700 Context->SourceMap.array[pos].value = NULL;
2702 while(temp->queue != NULL)
2704 ALbufferlistitem *BufferList = temp->queue;
2705 temp->queue = BufferList->next;
2707 if(BufferList->buffer != NULL)
2708 DecrementRef(&BufferList->buffer->ref);
2709 free(BufferList);
2712 for(j = 0;j < MAX_SENDS;++j)
2714 if(temp->Send[j].Slot)
2715 DecrementRef(&temp->Send[j].Slot->ref);
2716 temp->Send[j].Slot = NULL;
2719 FreeThunkEntry(temp->id);
2720 memset(temp, 0, sizeof(*temp));
2721 al_free(temp);