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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
42 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
43 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
45 static ALvoid InitSourceParams(ALsource *Source);
46 static ALint64 GetSourceSampleOffset(ALsource *Source);
47 static ALdouble GetSourceSecOffset(ALsource *Source);
48 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
49 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
51 typedef enum SourceProp {
54 srcMinGain = AL_MIN_GAIN,
55 srcMaxGain = AL_MAX_GAIN,
56 srcMaxDistance = AL_MAX_DISTANCE,
57 srcRolloffFactor = AL_ROLLOFF_FACTOR,
58 srcDopplerFactor = AL_DOPPLER_FACTOR,
59 srcConeOuterGain = AL_CONE_OUTER_GAIN,
60 srcSecOffset = AL_SEC_OFFSET,
61 srcSampleOffset = AL_SAMPLE_OFFSET,
62 srcByteOffset = AL_BYTE_OFFSET,
63 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
64 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
65 srcRefDistance = AL_REFERENCE_DISTANCE,
67 srcPosition = AL_POSITION,
68 srcVelocity = AL_VELOCITY,
69 srcDirection = AL_DIRECTION,
71 srcSourceRelative = AL_SOURCE_RELATIVE,
72 srcLooping = AL_LOOPING,
73 srcBuffer = AL_BUFFER,
74 srcSourceState = AL_SOURCE_STATE,
75 srcBuffersQueued = AL_BUFFERS_QUEUED,
76 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
77 srcSourceType = AL_SOURCE_TYPE,
80 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
81 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
82 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
83 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
84 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
85 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
86 srcDirectFilter = AL_DIRECT_FILTER,
87 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
89 /* AL_SOFT_direct_channels */
90 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
92 /* AL_EXT_source_distance_model */
93 srcDistanceModel = AL_DISTANCE_MODEL,
95 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
96 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
97 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
99 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100 srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
101 srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
103 /* AL_SOFT_source_latency */
104 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
105 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
108 srcOrientation = AL_ORIENTATION,
111 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
112 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
113 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
115 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
116 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
117 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
119 static ALint FloatValsByProp(ALenum prop)
121 if(prop != (ALenum)((SourceProp)prop))
123 switch((SourceProp)prop)
129 case AL_MAX_DISTANCE:
130 case AL_ROLLOFF_FACTOR:
131 case AL_DOPPLER_FACTOR:
132 case AL_CONE_OUTER_GAIN:
134 case AL_SAMPLE_OFFSET:
136 case AL_CONE_INNER_ANGLE:
137 case AL_CONE_OUTER_ANGLE:
138 case AL_REFERENCE_DISTANCE:
139 case AL_CONE_OUTER_GAINHF:
140 case AL_AIR_ABSORPTION_FACTOR:
141 case AL_ROOM_ROLLOFF_FACTOR:
142 case AL_DIRECT_FILTER_GAINHF_AUTO:
143 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
144 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
145 case AL_DIRECT_CHANNELS_SOFT:
146 case AL_DISTANCE_MODEL:
147 case AL_SOURCE_RELATIVE:
149 case AL_SOURCE_STATE:
150 case AL_BUFFERS_QUEUED:
151 case AL_BUFFERS_PROCESSED:
153 case AL_BYTE_LENGTH_SOFT:
154 case AL_SAMPLE_LENGTH_SOFT:
155 case AL_SEC_LENGTH_SOFT:
158 case AL_SAMPLE_RW_OFFSETS_SOFT:
159 case AL_BYTE_RW_OFFSETS_SOFT:
170 case AL_SEC_OFFSET_LATENCY_SOFT:
171 break; /* Double only */
174 case AL_DIRECT_FILTER:
175 case AL_AUXILIARY_SEND_FILTER:
176 break; /* i/i64 only */
177 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
178 break; /* i64 only */
182 static ALint DoubleValsByProp(ALenum prop)
184 if(prop != (ALenum)((SourceProp)prop))
186 switch((SourceProp)prop)
192 case AL_MAX_DISTANCE:
193 case AL_ROLLOFF_FACTOR:
194 case AL_DOPPLER_FACTOR:
195 case AL_CONE_OUTER_GAIN:
197 case AL_SAMPLE_OFFSET:
199 case AL_CONE_INNER_ANGLE:
200 case AL_CONE_OUTER_ANGLE:
201 case AL_REFERENCE_DISTANCE:
202 case AL_CONE_OUTER_GAINHF:
203 case AL_AIR_ABSORPTION_FACTOR:
204 case AL_ROOM_ROLLOFF_FACTOR:
205 case AL_DIRECT_FILTER_GAINHF_AUTO:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208 case AL_DIRECT_CHANNELS_SOFT:
209 case AL_DISTANCE_MODEL:
210 case AL_SOURCE_RELATIVE:
212 case AL_SOURCE_STATE:
213 case AL_BUFFERS_QUEUED:
214 case AL_BUFFERS_PROCESSED:
216 case AL_BYTE_LENGTH_SOFT:
217 case AL_SAMPLE_LENGTH_SOFT:
218 case AL_SEC_LENGTH_SOFT:
221 case AL_SAMPLE_RW_OFFSETS_SOFT:
222 case AL_BYTE_RW_OFFSETS_SOFT:
223 case AL_SEC_OFFSET_LATENCY_SOFT:
235 case AL_DIRECT_FILTER:
236 case AL_AUXILIARY_SEND_FILTER:
237 break; /* i/i64 only */
238 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
239 break; /* i64 only */
244 static ALint IntValsByProp(ALenum prop)
246 if(prop != (ALenum)((SourceProp)prop))
248 switch((SourceProp)prop)
254 case AL_MAX_DISTANCE:
255 case AL_ROLLOFF_FACTOR:
256 case AL_DOPPLER_FACTOR:
257 case AL_CONE_OUTER_GAIN:
259 case AL_SAMPLE_OFFSET:
261 case AL_CONE_INNER_ANGLE:
262 case AL_CONE_OUTER_ANGLE:
263 case AL_REFERENCE_DISTANCE:
264 case AL_CONE_OUTER_GAINHF:
265 case AL_AIR_ABSORPTION_FACTOR:
266 case AL_ROOM_ROLLOFF_FACTOR:
267 case AL_DIRECT_FILTER_GAINHF_AUTO:
268 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
269 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
270 case AL_DIRECT_CHANNELS_SOFT:
271 case AL_DISTANCE_MODEL:
272 case AL_SOURCE_RELATIVE:
278 case AL_SOURCE_STATE:
279 case AL_BUFFERS_QUEUED:
280 case AL_BUFFERS_PROCESSED:
282 case AL_DIRECT_FILTER:
283 case AL_BYTE_LENGTH_SOFT:
284 case AL_SAMPLE_LENGTH_SOFT:
285 case AL_SEC_LENGTH_SOFT:
288 case AL_SAMPLE_RW_OFFSETS_SOFT:
289 case AL_BYTE_RW_OFFSETS_SOFT:
295 case AL_AUXILIARY_SEND_FILTER:
301 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
302 break; /* i64 only */
303 case AL_SEC_OFFSET_LATENCY_SOFT:
304 break; /* Double only */
308 static ALint Int64ValsByProp(ALenum prop)
310 if(prop != (ALenum)((SourceProp)prop))
312 switch((SourceProp)prop)
318 case AL_MAX_DISTANCE:
319 case AL_ROLLOFF_FACTOR:
320 case AL_DOPPLER_FACTOR:
321 case AL_CONE_OUTER_GAIN:
323 case AL_SAMPLE_OFFSET:
325 case AL_CONE_INNER_ANGLE:
326 case AL_CONE_OUTER_ANGLE:
327 case AL_REFERENCE_DISTANCE:
328 case AL_CONE_OUTER_GAINHF:
329 case AL_AIR_ABSORPTION_FACTOR:
330 case AL_ROOM_ROLLOFF_FACTOR:
331 case AL_DIRECT_FILTER_GAINHF_AUTO:
332 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
333 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
334 case AL_DIRECT_CHANNELS_SOFT:
335 case AL_DISTANCE_MODEL:
336 case AL_SOURCE_RELATIVE:
339 case AL_SOURCE_STATE:
340 case AL_BUFFERS_QUEUED:
341 case AL_BUFFERS_PROCESSED:
343 case AL_DIRECT_FILTER:
344 case AL_BYTE_LENGTH_SOFT:
345 case AL_SAMPLE_LENGTH_SOFT:
346 case AL_SEC_LENGTH_SOFT:
349 case AL_SAMPLE_RW_OFFSETS_SOFT:
350 case AL_BYTE_RW_OFFSETS_SOFT:
351 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
357 case AL_AUXILIARY_SEND_FILTER:
363 case AL_SEC_OFFSET_LATENCY_SOFT:
364 break; /* Double only */
370 #define CHECKVAL(x) do { \
372 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
375 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
381 case AL_BYTE_RW_OFFSETS_SOFT:
382 case AL_SAMPLE_RW_OFFSETS_SOFT:
383 case AL_BYTE_LENGTH_SOFT:
384 case AL_SAMPLE_LENGTH_SOFT:
385 case AL_SEC_LENGTH_SOFT:
386 case AL_SEC_OFFSET_LATENCY_SOFT:
388 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
391 CHECKVAL(*values >= 0.0f);
393 Source->Pitch = *values;
394 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
397 case AL_CONE_INNER_ANGLE:
398 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
400 Source->InnerAngle = *values;
401 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
404 case AL_CONE_OUTER_ANGLE:
405 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
407 Source->OuterAngle = *values;
408 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
412 CHECKVAL(*values >= 0.0f);
414 Source->Gain = *values;
415 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
418 case AL_MAX_DISTANCE:
419 CHECKVAL(*values >= 0.0f);
421 Source->MaxDistance = *values;
422 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
425 case AL_ROLLOFF_FACTOR:
426 CHECKVAL(*values >= 0.0f);
428 Source->RollOffFactor = *values;
429 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
432 case AL_REFERENCE_DISTANCE:
433 CHECKVAL(*values >= 0.0f);
435 Source->RefDistance = *values;
436 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
440 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
442 Source->MinGain = *values;
443 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
447 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
449 Source->MaxGain = *values;
450 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
453 case AL_CONE_OUTER_GAIN:
454 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
456 Source->OuterGain = *values;
457 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
460 case AL_CONE_OUTER_GAINHF:
461 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
463 Source->OuterGainHF = *values;
464 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
467 case AL_AIR_ABSORPTION_FACTOR:
468 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
470 Source->AirAbsorptionFactor = *values;
471 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
474 case AL_ROOM_ROLLOFF_FACTOR:
475 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
477 Source->RoomRolloffFactor = *values;
478 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
481 case AL_DOPPLER_FACTOR:
482 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
484 Source->DopplerFactor = *values;
485 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
489 case AL_SAMPLE_OFFSET:
491 CHECKVAL(*values >= 0.0f);
493 LockContext(Context);
494 Source->OffsetType = prop;
495 Source->Offset = *values;
497 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
498 !Context->DeferUpdates)
500 WriteLock(&Source->queue_lock);
501 if(ApplyOffset(Source) == AL_FALSE)
503 WriteUnlock(&Source->queue_lock);
504 UnlockContext(Context);
505 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
507 WriteUnlock(&Source->queue_lock);
509 UnlockContext(Context);
514 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
516 LockContext(Context);
517 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
518 UnlockContext(Context);
519 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
523 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
525 LockContext(Context);
526 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
527 UnlockContext(Context);
528 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
532 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
534 LockContext(Context);
535 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
536 UnlockContext(Context);
537 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
541 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
542 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
544 LockContext(Context);
545 Source->Orientation[0][0] = values[0];
546 Source->Orientation[0][1] = values[1];
547 Source->Orientation[0][2] = values[2];
548 Source->Orientation[1][0] = values[3];
549 Source->Orientation[1][1] = values[4];
550 Source->Orientation[1][2] = values[5];
551 UnlockContext(Context);
552 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
556 case AL_SOURCE_RELATIVE:
558 case AL_SOURCE_STATE:
560 case AL_DISTANCE_MODEL:
561 case AL_DIRECT_FILTER_GAINHF_AUTO:
562 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
563 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
564 case AL_DIRECT_CHANNELS_SOFT:
565 ival = (ALint)values[0];
566 return SetSourceiv(Source, Context, prop, &ival);
568 case AL_BUFFERS_QUEUED:
569 case AL_BUFFERS_PROCESSED:
570 ival = (ALint)((ALuint)values[0]);
571 return SetSourceiv(Source, Context, prop, &ival);
574 case AL_DIRECT_FILTER:
575 case AL_AUXILIARY_SEND_FILTER:
576 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
580 ERR("Unexpected property: 0x%04x\n", prop);
581 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
584 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
586 ALCdevice *device = Context->Device;
587 ALbuffer *buffer = NULL;
588 ALfilter *filter = NULL;
589 ALeffectslot *slot = NULL;
590 ALbufferlistitem *oldlist;
591 ALbufferlistitem *newlist;
596 case AL_SOURCE_STATE:
598 case AL_BUFFERS_QUEUED:
599 case AL_BUFFERS_PROCESSED:
600 case AL_SAMPLE_RW_OFFSETS_SOFT:
601 case AL_BYTE_RW_OFFSETS_SOFT:
602 case AL_BYTE_LENGTH_SOFT:
603 case AL_SAMPLE_LENGTH_SOFT:
604 case AL_SEC_LENGTH_SOFT:
606 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
608 case AL_SOURCE_RELATIVE:
609 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
611 Source->HeadRelative = (ALboolean)*values;
612 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
616 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
618 Source->Looping = (ALboolean)*values;
624 ALuint uValue = (ALuint)(*values);
627 Source->LoopCount = uValue;
628 Source->Looping = AL_FALSE;
632 Source->LoopCount = uValue;
633 Source->Looping = AL_TRUE;
640 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
642 WriteLock(&Source->queue_lock);
643 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
645 WriteUnlock(&Source->queue_lock);
646 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
651 /* Add the selected buffer to a one-item queue */
652 newlist = malloc(sizeof(ALbufferlistitem));
653 newlist->buffer = buffer;
654 newlist->next = NULL;
655 newlist->prev = NULL;
656 IncrementRef(&buffer->ref);
658 /* Source is now Static */
659 Source->SourceType = AL_STATIC;
661 ReadLock(&buffer->lock);
662 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
663 Source->SampleSize = BytesFromFmt(buffer->FmtType);
664 ReadUnlock(&buffer->lock);
668 /* Source is now Undetermined */
669 Source->SourceType = AL_UNDETERMINED;
672 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
673 ATOMIC_STORE(&Source->current_buffer, newlist);
674 WriteUnlock(&Source->queue_lock);
676 /* Delete all elements in the previous queue */
677 while(oldlist != NULL)
679 ALbufferlistitem *temp = oldlist;
680 oldlist = temp->next;
683 DecrementRef(&temp->buffer->ref);
689 case AL_SAMPLE_OFFSET:
691 CHECKVAL(*values >= 0);
693 LockContext(Context);
694 Source->OffsetType = prop;
695 Source->Offset = *values;
697 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
698 !Context->DeferUpdates)
700 WriteLock(&Source->queue_lock);
701 if(ApplyOffset(Source) == AL_FALSE)
703 WriteUnlock(&Source->queue_lock);
704 UnlockContext(Context);
705 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
707 WriteUnlock(&Source->queue_lock);
709 UnlockContext(Context);
712 case AL_DIRECT_FILTER:
713 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
715 LockContext(Context);
718 Source->Direct.Gain = 1.0f;
719 Source->Direct.GainHF = 1.0f;
720 Source->Direct.HFReference = LOWPASSFREQREF;
721 Source->Direct.GainLF = 1.0f;
722 Source->Direct.LFReference = HIGHPASSFREQREF;
726 Source->Direct.Gain = filter->Gain;
727 Source->Direct.GainHF = filter->GainHF;
728 Source->Direct.HFReference = filter->HFReference;
729 Source->Direct.GainLF = filter->GainLF;
730 Source->Direct.LFReference = filter->LFReference;
732 UnlockContext(Context);
733 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
736 case AL_DIRECT_FILTER_GAINHF_AUTO:
737 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
739 Source->DryGainHFAuto = *values;
740 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
743 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
744 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
746 Source->WetGainAuto = *values;
747 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
750 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
751 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
753 Source->WetGainHFAuto = *values;
754 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
757 case AL_DIRECT_CHANNELS_SOFT:
758 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
760 Source->DirectChannels = *values;
761 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
764 case AL_DISTANCE_MODEL:
765 CHECKVAL(*values == AL_NONE ||
766 *values == AL_INVERSE_DISTANCE ||
767 *values == AL_INVERSE_DISTANCE_CLAMPED ||
768 *values == AL_LINEAR_DISTANCE ||
769 *values == AL_LINEAR_DISTANCE_CLAMPED ||
770 *values == AL_EXPONENT_DISTANCE ||
771 *values == AL_EXPONENT_DISTANCE_CLAMPED);
773 Source->DistanceModel = *values;
774 if(Context->SourceDistanceModel)
775 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
779 case AL_AUXILIARY_SEND_FILTER:
780 LockContext(Context);
781 if(!((ALuint)values[1] < device->NumAuxSends &&
782 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
783 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
785 UnlockContext(Context);
786 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
789 /* Add refcount on the new slot, and release the previous slot */
790 if(slot) IncrementRef(&slot->ref);
791 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
792 if(slot) DecrementRef(&slot->ref);
797 Source->Send[values[1]].Gain = 1.0f;
798 Source->Send[values[1]].GainHF = 1.0f;
799 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
800 Source->Send[values[1]].GainLF = 1.0f;
801 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
805 Source->Send[values[1]].Gain = filter->Gain;
806 Source->Send[values[1]].GainHF = filter->GainHF;
807 Source->Send[values[1]].HFReference = filter->HFReference;
808 Source->Send[values[1]].GainLF = filter->GainLF;
809 Source->Send[values[1]].LFReference = filter->LFReference;
811 UnlockContext(Context);
812 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
817 case AL_CONE_INNER_ANGLE:
818 case AL_CONE_OUTER_ANGLE:
823 case AL_REFERENCE_DISTANCE:
824 case AL_ROLLOFF_FACTOR:
825 case AL_CONE_OUTER_GAIN:
826 case AL_MAX_DISTANCE:
827 case AL_DOPPLER_FACTOR:
828 case AL_CONE_OUTER_GAINHF:
829 case AL_AIR_ABSORPTION_FACTOR:
830 case AL_ROOM_ROLLOFF_FACTOR:
831 fvals[0] = (ALfloat)*values;
832 return SetSourcefv(Source, Context, (int)prop, fvals);
838 fvals[0] = (ALfloat)values[0];
839 fvals[1] = (ALfloat)values[1];
840 fvals[2] = (ALfloat)values[2];
841 return SetSourcefv(Source, Context, (int)prop, fvals);
845 fvals[0] = (ALfloat)values[0];
846 fvals[1] = (ALfloat)values[1];
847 fvals[2] = (ALfloat)values[2];
848 fvals[3] = (ALfloat)values[3];
849 fvals[4] = (ALfloat)values[4];
850 fvals[5] = (ALfloat)values[5];
851 return SetSourcefv(Source, Context, (int)prop, fvals);
853 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
854 case AL_SEC_OFFSET_LATENCY_SOFT:
858 ERR("Unexpected property: 0x%04x\n", prop);
859 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
862 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
870 case AL_BUFFERS_QUEUED:
871 case AL_BUFFERS_PROCESSED:
872 case AL_SOURCE_STATE:
873 case AL_SAMPLE_RW_OFFSETS_SOFT:
874 case AL_BYTE_RW_OFFSETS_SOFT:
875 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
876 case AL_BYTE_LENGTH_SOFT:
877 case AL_SAMPLE_LENGTH_SOFT:
878 case AL_SEC_LENGTH_SOFT:
880 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
884 case AL_SOURCE_RELATIVE:
887 case AL_SAMPLE_OFFSET:
889 case AL_DIRECT_FILTER_GAINHF_AUTO:
890 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
891 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
892 case AL_DIRECT_CHANNELS_SOFT:
893 case AL_DISTANCE_MODEL:
894 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
896 ivals[0] = (ALint)*values;
897 return SetSourceiv(Source, Context, (int)prop, ivals);
901 case AL_DIRECT_FILTER:
902 CHECKVAL(*values <= UINT_MAX && *values >= 0);
904 ivals[0] = (ALuint)*values;
905 return SetSourceiv(Source, Context, (int)prop, ivals);
908 case AL_AUXILIARY_SEND_FILTER:
909 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
910 values[1] <= UINT_MAX && values[1] >= 0 &&
911 values[2] <= UINT_MAX && values[2] >= 0);
913 ivals[0] = (ALuint)values[0];
914 ivals[1] = (ALuint)values[1];
915 ivals[2] = (ALuint)values[2];
916 return SetSourceiv(Source, Context, (int)prop, ivals);
919 case AL_CONE_INNER_ANGLE:
920 case AL_CONE_OUTER_ANGLE:
925 case AL_REFERENCE_DISTANCE:
926 case AL_ROLLOFF_FACTOR:
927 case AL_CONE_OUTER_GAIN:
928 case AL_MAX_DISTANCE:
929 case AL_DOPPLER_FACTOR:
930 case AL_CONE_OUTER_GAINHF:
931 case AL_AIR_ABSORPTION_FACTOR:
932 case AL_ROOM_ROLLOFF_FACTOR:
933 fvals[0] = (ALfloat)*values;
934 return SetSourcefv(Source, Context, (int)prop, fvals);
940 fvals[0] = (ALfloat)values[0];
941 fvals[1] = (ALfloat)values[1];
942 fvals[2] = (ALfloat)values[2];
943 return SetSourcefv(Source, Context, (int)prop, fvals);
947 fvals[0] = (ALfloat)values[0];
948 fvals[1] = (ALfloat)values[1];
949 fvals[2] = (ALfloat)values[2];
950 fvals[3] = (ALfloat)values[3];
951 fvals[4] = (ALfloat)values[4];
952 fvals[5] = (ALfloat)values[5];
953 return SetSourcefv(Source, Context, (int)prop, fvals);
955 case AL_SEC_OFFSET_LATENCY_SOFT:
959 ERR("Unexpected property: 0x%04x\n", prop);
960 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
966 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
968 ALCdevice *device = Context->Device;
969 ALbufferlistitem *BufferList;
978 *values = Source->Gain;
982 *values = Source->Pitch;
985 case AL_MAX_DISTANCE:
986 *values = Source->MaxDistance;
989 case AL_ROLLOFF_FACTOR:
990 *values = Source->RollOffFactor;
993 case AL_REFERENCE_DISTANCE:
994 *values = Source->RefDistance;
997 case AL_CONE_INNER_ANGLE:
998 *values = Source->InnerAngle;
1001 case AL_CONE_OUTER_ANGLE:
1002 *values = Source->OuterAngle;
1006 *values = Source->MinGain;
1010 *values = Source->MaxGain;
1013 case AL_CONE_OUTER_GAIN:
1014 *values = Source->OuterGain;
1018 case AL_SAMPLE_OFFSET:
1019 case AL_BYTE_OFFSET:
1020 LockContext(Context);
1021 GetSourceOffsets(Source, prop, offsets, 0.0);
1022 UnlockContext(Context);
1023 *values = offsets[0];
1026 case AL_CONE_OUTER_GAINHF:
1027 *values = Source->OuterGainHF;
1030 case AL_AIR_ABSORPTION_FACTOR:
1031 *values = Source->AirAbsorptionFactor;
1034 case AL_ROOM_ROLLOFF_FACTOR:
1035 *values = Source->RoomRolloffFactor;
1038 case AL_DOPPLER_FACTOR:
1039 *values = Source->DopplerFactor;
1042 case AL_SEC_LENGTH_SOFT:
1043 ReadLock(&Source->queue_lock);
1044 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1051 ALbuffer *buffer = BufferList->buffer;
1052 if(buffer && buffer->SampleLen > 0)
1054 freq = buffer->Frequency;
1055 length += buffer->SampleLen;
1057 } while((BufferList=BufferList->next) != NULL);
1058 *values = (ALdouble)length / (ALdouble)freq;
1060 ReadUnlock(&Source->queue_lock);
1063 case AL_SAMPLE_RW_OFFSETS_SOFT:
1064 case AL_BYTE_RW_OFFSETS_SOFT:
1065 LockContext(Context);
1066 updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1067 GetSourceOffsets(Source, prop, values, updateLen);
1068 UnlockContext(Context);
1071 case AL_SEC_OFFSET_LATENCY_SOFT:
1072 LockContext(Context);
1073 values[0] = GetSourceSecOffset(Source);
1074 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1076 UnlockContext(Context);
1080 LockContext(Context);
1081 values[0] = Source->Position.v[0];
1082 values[1] = Source->Position.v[1];
1083 values[2] = Source->Position.v[2];
1084 UnlockContext(Context);
1088 LockContext(Context);
1089 values[0] = Source->Velocity.v[0];
1090 values[1] = Source->Velocity.v[1];
1091 values[2] = Source->Velocity.v[2];
1092 UnlockContext(Context);
1096 LockContext(Context);
1097 values[0] = Source->Direction.v[0];
1098 values[1] = Source->Direction.v[1];
1099 values[2] = Source->Direction.v[2];
1100 UnlockContext(Context);
1103 case AL_ORIENTATION:
1104 LockContext(Context);
1105 values[0] = Source->Orientation[0][0];
1106 values[1] = Source->Orientation[0][1];
1107 values[2] = Source->Orientation[0][2];
1108 values[3] = Source->Orientation[1][0];
1109 values[4] = Source->Orientation[1][1];
1110 values[5] = Source->Orientation[1][2];
1111 UnlockContext(Context);
1115 case AL_SOURCE_RELATIVE:
1117 case AL_SOURCE_STATE:
1118 case AL_BUFFERS_QUEUED:
1119 case AL_BUFFERS_PROCESSED:
1120 case AL_SOURCE_TYPE:
1121 case AL_DIRECT_FILTER_GAINHF_AUTO:
1122 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1123 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1124 case AL_DIRECT_CHANNELS_SOFT:
1125 case AL_BYTE_LENGTH_SOFT:
1126 case AL_SAMPLE_LENGTH_SOFT:
1127 case AL_DISTANCE_MODEL:
1128 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1129 *values = (ALdouble)ivals[0];
1133 case AL_DIRECT_FILTER:
1134 case AL_AUXILIARY_SEND_FILTER:
1135 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1139 ERR("Unexpected property: 0x%04x\n", prop);
1140 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1143 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1145 ALbufferlistitem *BufferList;
1151 case AL_SOURCE_RELATIVE:
1152 *values = Source->HeadRelative;
1156 *values = Source->Looping;
1160 ReadLock(&Source->queue_lock);
1161 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1162 ATOMIC_LOAD(&Source->current_buffer);
1163 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1164 ReadUnlock(&Source->queue_lock);
1167 case AL_SOURCE_STATE:
1168 *values = Source->state;
1171 case AL_BYTE_LENGTH_SOFT:
1172 ReadLock(&Source->queue_lock);
1173 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1179 ALbuffer *buffer = BufferList->buffer;
1180 if(buffer && buffer->SampleLen > 0)
1182 ALuint byte_align, sample_align;
1183 if(buffer->OriginalType == UserFmtIMA4)
1185 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1186 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1187 sample_align = buffer->OriginalAlign;
1189 else if(buffer->OriginalType == UserFmtMSADPCM)
1191 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1192 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1193 sample_align = buffer->OriginalAlign;
1197 ALsizei align = buffer->OriginalAlign;
1198 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1199 sample_align = buffer->OriginalAlign;
1202 length += buffer->SampleLen / sample_align * byte_align;
1204 } while((BufferList=BufferList->next) != NULL);
1207 ReadUnlock(&Source->queue_lock);
1210 case AL_SAMPLE_LENGTH_SOFT:
1211 ReadLock(&Source->queue_lock);
1212 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1218 ALbuffer *buffer = BufferList->buffer;
1219 if(buffer) length += buffer->SampleLen;
1220 } while((BufferList=BufferList->next) != NULL);
1223 ReadUnlock(&Source->queue_lock);
1226 case AL_BUFFERS_QUEUED:
1227 ReadLock(&Source->queue_lock);
1228 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1235 } while((BufferList=BufferList->next) != NULL);
1238 ReadUnlock(&Source->queue_lock);
1241 case AL_BUFFERS_PROCESSED:
1242 ReadLock(&Source->queue_lock);
1243 if(Source->Looping || Source->SourceType != AL_STREAMING)
1245 /* Buffers on a looping source are in a perpetual state of
1246 * PENDING, so don't report any as PROCESSED */
1251 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1252 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1254 while(BufferList && BufferList != Current)
1257 BufferList = BufferList->next;
1261 ReadUnlock(&Source->queue_lock);
1264 case AL_SOURCE_TYPE:
1265 *values = Source->SourceType;
1268 case AL_DIRECT_FILTER_GAINHF_AUTO:
1269 *values = Source->DryGainHFAuto;
1272 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1273 *values = Source->WetGainAuto;
1276 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1277 *values = Source->WetGainHFAuto;
1280 case AL_DIRECT_CHANNELS_SOFT:
1281 *values = Source->DirectChannels;
1284 case AL_DISTANCE_MODEL:
1285 *values = Source->DistanceModel;
1288 /* 1x float/double */
1289 case AL_CONE_INNER_ANGLE:
1290 case AL_CONE_OUTER_ANGLE:
1295 case AL_REFERENCE_DISTANCE:
1296 case AL_ROLLOFF_FACTOR:
1297 case AL_CONE_OUTER_GAIN:
1298 case AL_MAX_DISTANCE:
1300 case AL_SAMPLE_OFFSET:
1301 case AL_BYTE_OFFSET:
1302 case AL_DOPPLER_FACTOR:
1303 case AL_AIR_ABSORPTION_FACTOR:
1304 case AL_ROOM_ROLLOFF_FACTOR:
1305 case AL_CONE_OUTER_GAINHF:
1306 case AL_SEC_LENGTH_SOFT:
1307 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1308 *values = (ALint)dvals[0];
1311 /* 2x float/double */
1312 case AL_SAMPLE_RW_OFFSETS_SOFT:
1313 case AL_BYTE_RW_OFFSETS_SOFT:
1314 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1316 values[0] = (ALint)dvals[0];
1317 values[1] = (ALint)dvals[1];
1321 /* 3x float/double */
1325 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1327 values[0] = (ALint)dvals[0];
1328 values[1] = (ALint)dvals[1];
1329 values[2] = (ALint)dvals[2];
1333 /* 6x float/double */
1334 case AL_ORIENTATION:
1335 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1337 values[0] = (ALint)dvals[0];
1338 values[1] = (ALint)dvals[1];
1339 values[2] = (ALint)dvals[2];
1340 values[3] = (ALint)dvals[3];
1341 values[4] = (ALint)dvals[4];
1342 values[5] = (ALint)dvals[5];
1346 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1347 break; /* i64 only */
1348 case AL_SEC_OFFSET_LATENCY_SOFT:
1349 break; /* Double only */
1351 case AL_DIRECT_FILTER:
1352 case AL_AUXILIARY_SEND_FILTER:
1356 ERR("Unexpected property: 0x%04x\n", prop);
1357 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1360 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1362 ALCdevice *device = Context->Device;
1369 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1370 LockContext(Context);
1371 values[0] = GetSourceSampleOffset(Source);
1372 values[1] = V0(device->Backend,getLatency)();
1373 UnlockContext(Context);
1376 /* 1x float/double */
1377 case AL_CONE_INNER_ANGLE:
1378 case AL_CONE_OUTER_ANGLE:
1383 case AL_REFERENCE_DISTANCE:
1384 case AL_ROLLOFF_FACTOR:
1385 case AL_CONE_OUTER_GAIN:
1386 case AL_MAX_DISTANCE:
1388 case AL_SAMPLE_OFFSET:
1389 case AL_BYTE_OFFSET:
1390 case AL_DOPPLER_FACTOR:
1391 case AL_AIR_ABSORPTION_FACTOR:
1392 case AL_ROOM_ROLLOFF_FACTOR:
1393 case AL_CONE_OUTER_GAINHF:
1394 case AL_SEC_LENGTH_SOFT:
1395 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1396 *values = (ALint64)dvals[0];
1399 /* 2x float/double */
1400 case AL_SAMPLE_RW_OFFSETS_SOFT:
1401 case AL_BYTE_RW_OFFSETS_SOFT:
1402 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1404 values[0] = (ALint64)dvals[0];
1405 values[1] = (ALint64)dvals[1];
1409 /* 3x float/double */
1413 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1415 values[0] = (ALint64)dvals[0];
1416 values[1] = (ALint64)dvals[1];
1417 values[2] = (ALint64)dvals[2];
1421 /* 6x float/double */
1422 case AL_ORIENTATION:
1423 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1425 values[0] = (ALint64)dvals[0];
1426 values[1] = (ALint64)dvals[1];
1427 values[2] = (ALint64)dvals[2];
1428 values[3] = (ALint64)dvals[3];
1429 values[4] = (ALint64)dvals[4];
1430 values[5] = (ALint64)dvals[5];
1435 case AL_SOURCE_RELATIVE:
1437 case AL_SOURCE_STATE:
1438 case AL_BUFFERS_QUEUED:
1439 case AL_BUFFERS_PROCESSED:
1440 case AL_BYTE_LENGTH_SOFT:
1441 case AL_SAMPLE_LENGTH_SOFT:
1442 case AL_SOURCE_TYPE:
1443 case AL_DIRECT_FILTER_GAINHF_AUTO:
1444 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1445 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1446 case AL_DIRECT_CHANNELS_SOFT:
1447 case AL_DISTANCE_MODEL:
1448 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1454 case AL_DIRECT_FILTER:
1455 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1456 *values = (ALuint)ivals[0];
1460 case AL_AUXILIARY_SEND_FILTER:
1461 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1463 values[0] = (ALuint)ivals[0];
1464 values[1] = (ALuint)ivals[1];
1465 values[2] = (ALuint)ivals[2];
1469 case AL_SEC_OFFSET_LATENCY_SOFT:
1470 break; /* Double only */
1473 ERR("Unexpected property: 0x%04x\n", prop);
1474 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1478 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1480 ALCcontext *context;
1484 context = GetContextRef();
1485 if(!context) return;
1488 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1489 for(cur = 0;cur < n;cur++)
1491 ALsource *source = al_calloc(16, sizeof(ALsource));
1494 alDeleteSources(cur, sources);
1495 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1497 InitSourceParams(source);
1499 err = NewThunkEntry(&source->id);
1500 if(err == AL_NO_ERROR)
1501 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1502 if(err != AL_NO_ERROR)
1504 FreeThunkEntry(source->id);
1505 memset(source, 0, sizeof(ALsource));
1508 alDeleteSources(cur, sources);
1509 SET_ERROR_AND_GOTO(context, err, done);
1512 sources[cur] = source->id;
1516 ALCcontext_DecRef(context);
1520 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1522 ALCcontext *context;
1523 ALbufferlistitem *BufferList;
1527 context = GetContextRef();
1528 if(!context) return;
1531 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1533 /* Check that all Sources are valid */
1534 for(i = 0;i < n;i++)
1536 if(LookupSource(context, sources[i]) == NULL)
1537 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1539 for(i = 0;i < n;i++)
1541 ALvoice *voice, *voice_end;
1543 if((Source=RemoveSource(context, sources[i])) == NULL)
1545 FreeThunkEntry(Source->id);
1547 LockContext(context);
1548 voice = context->Voices;
1549 voice_end = voice + context->VoiceCount;
1550 while(voice != voice_end)
1552 ALsource *old = Source;
1553 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1557 UnlockContext(context);
1559 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1560 while(BufferList != NULL)
1562 ALbufferlistitem *next = BufferList->next;
1563 if(BufferList->buffer != NULL)
1564 DecrementRef(&BufferList->buffer->ref);
1569 for(j = 0;j < MAX_SENDS;++j)
1571 if(Source->Send[j].Slot)
1572 DecrementRef(&Source->Send[j].Slot->ref);
1573 Source->Send[j].Slot = NULL;
1576 memset(Source, 0, sizeof(*Source));
1581 ALCcontext_DecRef(context);
1585 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1587 ALCcontext *context;
1590 context = GetContextRef();
1591 if(!context) return AL_FALSE;
1593 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1595 ALCcontext_DecRef(context);
1601 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1603 ALCcontext *Context;
1606 Context = GetContextRef();
1607 if(!Context) return;
1609 if((Source=LookupSource(Context, source)) == NULL)
1610 alSetError(Context, AL_INVALID_NAME);
1611 else if(!(FloatValsByProp(param) == 1))
1612 alSetError(Context, AL_INVALID_ENUM);
1614 SetSourcefv(Source, Context, param, &value);
1616 ALCcontext_DecRef(Context);
1619 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1621 ALCcontext *Context;
1624 Context = GetContextRef();
1625 if(!Context) return;
1627 if((Source=LookupSource(Context, source)) == NULL)
1628 alSetError(Context, AL_INVALID_NAME);
1629 else if(!(FloatValsByProp(param) == 3))
1630 alSetError(Context, AL_INVALID_ENUM);
1633 ALfloat fvals[3] = { value1, value2, value3 };
1634 SetSourcefv(Source, Context, param, fvals);
1637 ALCcontext_DecRef(Context);
1640 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1642 ALCcontext *Context;
1645 Context = GetContextRef();
1646 if(!Context) return;
1648 if((Source=LookupSource(Context, source)) == NULL)
1649 alSetError(Context, AL_INVALID_NAME);
1651 alSetError(Context, AL_INVALID_VALUE);
1652 else if(!(FloatValsByProp(param) > 0))
1653 alSetError(Context, AL_INVALID_ENUM);
1655 SetSourcefv(Source, Context, param, values);
1657 ALCcontext_DecRef(Context);
1661 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1663 ALCcontext *Context;
1666 Context = GetContextRef();
1667 if(!Context) return;
1669 if((Source=LookupSource(Context, source)) == NULL)
1670 alSetError(Context, AL_INVALID_NAME);
1671 else if(!(DoubleValsByProp(param) == 1))
1672 alSetError(Context, AL_INVALID_ENUM);
1675 ALfloat fval = (ALfloat)value;
1676 SetSourcefv(Source, Context, param, &fval);
1679 ALCcontext_DecRef(Context);
1682 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1684 ALCcontext *Context;
1687 Context = GetContextRef();
1688 if(!Context) return;
1690 if((Source=LookupSource(Context, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 else if(!(DoubleValsByProp(param) == 3))
1693 alSetError(Context, AL_INVALID_ENUM);
1696 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1697 SetSourcefv(Source, Context, param, fvals);
1700 ALCcontext_DecRef(Context);
1703 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1705 ALCcontext *Context;
1709 Context = GetContextRef();
1710 if(!Context) return;
1712 if((Source=LookupSource(Context, source)) == NULL)
1713 alSetError(Context, AL_INVALID_NAME);
1715 alSetError(Context, AL_INVALID_VALUE);
1716 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1717 alSetError(Context, AL_INVALID_ENUM);
1723 for(i = 0;i < count;i++)
1724 fvals[i] = (ALfloat)values[i];
1725 SetSourcefv(Source, Context, param, fvals);
1728 ALCcontext_DecRef(Context);
1731 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1733 ALCcontext *Context;
1736 Context = GetContextRef();
1737 if(!Context) return;
1739 if((Source=LookupSource(Context, source)) == NULL)
1740 alSetError(Context, AL_INVALID_NAME);
1741 else if(!(IntValsByProp(param) == 1))
1742 alSetError(Context, AL_INVALID_ENUM);
1744 SetSourceiv(Source, Context, param, &value);
1746 ALCcontext_DecRef(Context);
1749 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1751 ALCcontext *Context;
1754 Context = GetContextRef();
1755 if(!Context) return;
1757 if((Source=LookupSource(Context, source)) == NULL)
1758 alSetError(Context, AL_INVALID_NAME);
1759 else if(!(IntValsByProp(param) == 3))
1760 alSetError(Context, AL_INVALID_ENUM);
1763 ALint ivals[3] = { value1, value2, value3 };
1764 SetSourceiv(Source, Context, param, ivals);
1767 ALCcontext_DecRef(Context);
1770 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1772 ALCcontext *Context;
1775 Context = GetContextRef();
1776 if(!Context) return;
1778 if((Source=LookupSource(Context, source)) == NULL)
1779 alSetError(Context, AL_INVALID_NAME);
1781 alSetError(Context, AL_INVALID_VALUE);
1782 else if(!(IntValsByProp(param) > 0))
1783 alSetError(Context, AL_INVALID_ENUM);
1785 SetSourceiv(Source, Context, param, values);
1787 ALCcontext_DecRef(Context);
1791 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1793 ALCcontext *Context;
1796 Context = GetContextRef();
1797 if(!Context) return;
1799 if((Source=LookupSource(Context, source)) == NULL)
1800 alSetError(Context, AL_INVALID_NAME);
1801 else if(!(Int64ValsByProp(param) == 1))
1802 alSetError(Context, AL_INVALID_ENUM);
1804 SetSourcei64v(Source, Context, param, &value);
1806 ALCcontext_DecRef(Context);
1809 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1811 ALCcontext *Context;
1814 Context = GetContextRef();
1815 if(!Context) return;
1817 if((Source=LookupSource(Context, source)) == NULL)
1818 alSetError(Context, AL_INVALID_NAME);
1819 else if(!(Int64ValsByProp(param) == 3))
1820 alSetError(Context, AL_INVALID_ENUM);
1823 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1824 SetSourcei64v(Source, Context, param, i64vals);
1827 ALCcontext_DecRef(Context);
1830 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1832 ALCcontext *Context;
1835 Context = GetContextRef();
1836 if(!Context) return;
1838 if((Source=LookupSource(Context, source)) == NULL)
1839 alSetError(Context, AL_INVALID_NAME);
1841 alSetError(Context, AL_INVALID_VALUE);
1842 else if(!(Int64ValsByProp(param) > 0))
1843 alSetError(Context, AL_INVALID_ENUM);
1845 SetSourcei64v(Source, Context, param, values);
1847 ALCcontext_DecRef(Context);
1851 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1853 ALCcontext *Context;
1856 Context = GetContextRef();
1857 if(!Context) return;
1859 if((Source=LookupSource(Context, source)) == NULL)
1860 alSetError(Context, AL_INVALID_NAME);
1862 alSetError(Context, AL_INVALID_VALUE);
1863 else if(!(FloatValsByProp(param) == 1))
1864 alSetError(Context, AL_INVALID_ENUM);
1868 if(GetSourcedv(Source, Context, param, &dval))
1869 *value = (ALfloat)dval;
1872 ALCcontext_DecRef(Context);
1876 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1878 ALCcontext *Context;
1881 Context = GetContextRef();
1882 if(!Context) return;
1884 if((Source=LookupSource(Context, source)) == NULL)
1885 alSetError(Context, AL_INVALID_NAME);
1886 else if(!(value1 && value2 && value3))
1887 alSetError(Context, AL_INVALID_VALUE);
1888 else if(!(FloatValsByProp(param) == 3))
1889 alSetError(Context, AL_INVALID_ENUM);
1893 if(GetSourcedv(Source, Context, param, dvals))
1895 *value1 = (ALfloat)dvals[0];
1896 *value2 = (ALfloat)dvals[1];
1897 *value3 = (ALfloat)dvals[2];
1901 ALCcontext_DecRef(Context);
1905 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1907 ALCcontext *Context;
1911 Context = GetContextRef();
1912 if(!Context) return;
1914 if((Source=LookupSource(Context, source)) == NULL)
1915 alSetError(Context, AL_INVALID_NAME);
1917 alSetError(Context, AL_INVALID_VALUE);
1918 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1919 alSetError(Context, AL_INVALID_ENUM);
1923 if(GetSourcedv(Source, Context, param, dvals))
1926 for(i = 0;i < count;i++)
1927 values[i] = (ALfloat)dvals[i];
1931 ALCcontext_DecRef(Context);
1935 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1937 ALCcontext *Context;
1940 Context = GetContextRef();
1941 if(!Context) return;
1943 if((Source=LookupSource(Context, source)) == NULL)
1944 alSetError(Context, AL_INVALID_NAME);
1946 alSetError(Context, AL_INVALID_VALUE);
1947 else if(!(DoubleValsByProp(param) == 1))
1948 alSetError(Context, AL_INVALID_ENUM);
1950 GetSourcedv(Source, Context, param, value);
1952 ALCcontext_DecRef(Context);
1955 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1957 ALCcontext *Context;
1960 Context = GetContextRef();
1961 if(!Context) return;
1963 if((Source=LookupSource(Context, source)) == NULL)
1964 alSetError(Context, AL_INVALID_NAME);
1965 else if(!(value1 && value2 && value3))
1966 alSetError(Context, AL_INVALID_VALUE);
1967 else if(!(DoubleValsByProp(param) == 3))
1968 alSetError(Context, AL_INVALID_ENUM);
1972 if(GetSourcedv(Source, Context, param, dvals))
1980 ALCcontext_DecRef(Context);
1983 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1985 ALCcontext *Context;
1988 Context = GetContextRef();
1989 if(!Context) return;
1991 if((Source=LookupSource(Context, source)) == NULL)
1992 alSetError(Context, AL_INVALID_NAME);
1994 alSetError(Context, AL_INVALID_VALUE);
1995 else if(!(DoubleValsByProp(param) > 0))
1996 alSetError(Context, AL_INVALID_ENUM);
1998 GetSourcedv(Source, Context, param, values);
2000 ALCcontext_DecRef(Context);
2004 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2006 ALCcontext *Context;
2009 Context = GetContextRef();
2010 if(!Context) return;
2012 if((Source=LookupSource(Context, source)) == NULL)
2013 alSetError(Context, AL_INVALID_NAME);
2015 alSetError(Context, AL_INVALID_VALUE);
2016 else if(!(IntValsByProp(param) == 1))
2017 alSetError(Context, AL_INVALID_ENUM);
2019 GetSourceiv(Source, Context, param, value);
2021 ALCcontext_DecRef(Context);
2025 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2027 ALCcontext *Context;
2030 Context = GetContextRef();
2031 if(!Context) return;
2033 if((Source=LookupSource(Context, source)) == NULL)
2034 alSetError(Context, AL_INVALID_NAME);
2035 else if(!(value1 && value2 && value3))
2036 alSetError(Context, AL_INVALID_VALUE);
2037 else if(!(IntValsByProp(param) == 3))
2038 alSetError(Context, AL_INVALID_ENUM);
2042 if(GetSourceiv(Source, Context, param, ivals))
2050 ALCcontext_DecRef(Context);
2054 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2056 ALCcontext *Context;
2059 Context = GetContextRef();
2060 if(!Context) return;
2062 if((Source=LookupSource(Context, source)) == NULL)
2063 alSetError(Context, AL_INVALID_NAME);
2065 alSetError(Context, AL_INVALID_VALUE);
2066 else if(!(IntValsByProp(param) > 0))
2067 alSetError(Context, AL_INVALID_ENUM);
2069 GetSourceiv(Source, Context, param, values);
2071 ALCcontext_DecRef(Context);
2075 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2077 ALCcontext *Context;
2080 Context = GetContextRef();
2081 if(!Context) return;
2083 if((Source=LookupSource(Context, source)) == NULL)
2084 alSetError(Context, AL_INVALID_NAME);
2086 alSetError(Context, AL_INVALID_VALUE);
2087 else if(!(Int64ValsByProp(param) == 1))
2088 alSetError(Context, AL_INVALID_ENUM);
2090 GetSourcei64v(Source, Context, param, value);
2092 ALCcontext_DecRef(Context);
2095 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2097 ALCcontext *Context;
2100 Context = GetContextRef();
2101 if(!Context) return;
2103 if((Source=LookupSource(Context, source)) == NULL)
2104 alSetError(Context, AL_INVALID_NAME);
2105 else if(!(value1 && value2 && value3))
2106 alSetError(Context, AL_INVALID_VALUE);
2107 else if(!(Int64ValsByProp(param) == 3))
2108 alSetError(Context, AL_INVALID_ENUM);
2112 if(GetSourcei64v(Source, Context, param, i64vals))
2114 *value1 = i64vals[0];
2115 *value2 = i64vals[1];
2116 *value3 = i64vals[2];
2120 ALCcontext_DecRef(Context);
2123 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2125 ALCcontext *Context;
2128 Context = GetContextRef();
2129 if(!Context) return;
2131 if((Source=LookupSource(Context, source)) == NULL)
2132 alSetError(Context, AL_INVALID_NAME);
2134 alSetError(Context, AL_INVALID_VALUE);
2135 else if(!(Int64ValsByProp(param) > 0))
2136 alSetError(Context, AL_INVALID_ENUM);
2138 GetSourcei64v(Source, Context, param, values);
2140 ALCcontext_DecRef(Context);
2144 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2146 alSourcePlayv(1, &source);
2148 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2150 ALCcontext *context;
2154 context = GetContextRef();
2155 if(!context) return;
2158 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2159 for(i = 0;i < n;i++)
2161 if(!LookupSource(context, sources[i]))
2162 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2165 LockContext(context);
2166 while(n > context->MaxVoices-context->VoiceCount)
2168 ALvoice *temp = NULL;
2171 newcount = context->MaxVoices << 1;
2173 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2176 UnlockContext(context);
2177 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2179 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2181 context->Voices = temp;
2182 context->MaxVoices = newcount;
2185 for(i = 0;i < n;i++)
2187 source = LookupSource(context, sources[i]);
2188 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2189 else SetSourceState(source, context, AL_PLAYING);
2193 /* Resume device if device is paused by alcDevicePauseSOFT() in alSourcePausev() */
2194 alcDeviceResumeSOFT(context->Device);
2197 UnlockContext(context);
2200 ALCcontext_DecRef(context);
2204 static ALboolean _alPlayingSourcesExists(ALCcontext *context)
2206 ALsource *source = NULL;
2209 if (context == NULL)
2211 /* As this is error case, I think device would be safe to keep active */
2215 for(i = 0; i < context->SourceMap.size; i++)
2217 source = (ALsource *)context->SourceMap.array[i].value;
2218 TRACE("[total:%d, index:%d, key:%d, state:%d]\n",
2219 context->SourceMap.size, i, source->id, source->state);
2220 if(source->state == AL_PLAYING)
2222 TRACE(" - source[%d] is still playing....\n", source->id);
2231 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2233 alSourcePausev(1, &source);
2235 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2237 ALCcontext *context;
2241 context = GetContextRef();
2242 if(!context) return;
2245 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2246 for(i = 0;i < n;i++)
2248 if(!LookupSource(context, sources[i]))
2249 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2252 LockContext(context);
2253 for(i = 0;i < n;i++)
2255 source = LookupSource(context, sources[i]);
2256 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2257 else SetSourceState(source, context, AL_PAUSED);
2259 UnlockContext(context);
2262 /* if there are no playing sources, pause DEVICE to let backend device can suspend
2263 device will be resumed when one of source is going to be played by alSourcePlay */
2264 if(!_alPlayingSourcesExists(context))
2266 TRACE("No playing source in this context, do alcDevicePauseSOFT()!");
2267 alcDevicePauseSOFT(context->Device);
2272 ALCcontext_DecRef(context);
2275 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2277 alSourceStopv(1, &source);
2279 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2281 ALCcontext *context;
2285 context = GetContextRef();
2286 if(!context) return;
2289 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2290 for(i = 0;i < n;i++)
2292 if(!LookupSource(context, sources[i]))
2293 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2296 LockContext(context);
2297 for(i = 0;i < n;i++)
2299 source = LookupSource(context, sources[i]);
2300 source->new_state = AL_NONE;
2301 SetSourceState(source, context, AL_STOPPED);
2303 UnlockContext(context);
2306 ALCcontext_DecRef(context);
2309 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2311 alSourceRewindv(1, &source);
2313 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2315 ALCcontext *context;
2319 context = GetContextRef();
2320 if(!context) return;
2323 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2324 for(i = 0;i < n;i++)
2326 if(!LookupSource(context, sources[i]))
2327 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2330 LockContext(context);
2331 for(i = 0;i < n;i++)
2333 source = LookupSource(context, sources[i]);
2334 source->new_state = AL_NONE;
2335 SetSourceState(source, context, AL_INITIAL);
2337 UnlockContext(context);
2340 ALCcontext_DecRef(context);
2344 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2347 ALCcontext *context;
2350 ALbufferlistitem *BufferListStart;
2351 ALbufferlistitem *BufferList;
2352 ALbuffer *BufferFmt = NULL;
2357 context = GetContextRef();
2358 if(!context) return;
2360 device = context->Device;
2363 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2364 if((source=LookupSource(context, src)) == NULL)
2365 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2367 WriteLock(&source->queue_lock);
2368 if(source->SourceType == AL_STATIC)
2370 WriteUnlock(&source->queue_lock);
2371 /* Can't queue on a Static Source */
2372 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2375 /* Check for a valid Buffer, for its frequency and format */
2376 BufferList = ATOMIC_LOAD(&source->queue);
2379 if(BufferList->buffer)
2381 BufferFmt = BufferList->buffer;
2384 BufferList = BufferList->next;
2387 BufferListStart = NULL;
2389 for(i = 0;i < nb;i++)
2391 ALbuffer *buffer = NULL;
2392 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2394 WriteUnlock(&source->queue_lock);
2395 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2398 if(!BufferListStart)
2400 BufferListStart = malloc(sizeof(ALbufferlistitem));
2401 BufferListStart->buffer = buffer;
2402 BufferListStart->next = NULL;
2403 BufferListStart->prev = NULL;
2404 BufferList = BufferListStart;
2408 BufferList->next = malloc(sizeof(ALbufferlistitem));
2409 BufferList->next->buffer = buffer;
2410 BufferList->next->next = NULL;
2411 BufferList->next->prev = BufferList;
2412 BufferList = BufferList->next;
2414 if(!buffer) continue;
2416 /* Hold a read lock on each buffer being queued while checking all
2417 * provided buffers. This is done so other threads don't see an extra
2418 * reference on some buffers if this operation ends up failing. */
2419 ReadLock(&buffer->lock);
2420 IncrementRef(&buffer->ref);
2422 if(BufferFmt == NULL)
2426 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2427 source->SampleSize = BytesFromFmt(buffer->FmtType);
2429 else if(BufferFmt->Frequency != buffer->Frequency ||
2430 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2431 BufferFmt->OriginalType != buffer->OriginalType)
2433 WriteUnlock(&source->queue_lock);
2434 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2437 /* A buffer failed (invalid ID or format), so unlock and release
2438 * each buffer we had. */
2439 while(BufferList != NULL)
2441 ALbufferlistitem *prev = BufferList->prev;
2442 if((buffer=BufferList->buffer) != NULL)
2444 DecrementRef(&buffer->ref);
2445 ReadUnlock(&buffer->lock);
2453 /* All buffers good, unlock them now. */
2454 while(BufferList != NULL)
2456 ALbuffer *buffer = BufferList->buffer;
2457 if(buffer) ReadUnlock(&buffer->lock);
2458 BufferList = BufferList->prev;
2461 /* Source is now streaming */
2462 source->SourceType = AL_STREAMING;
2465 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2467 /* Queue head is not NULL, append to the end of the queue */
2468 while(BufferList->next != NULL)
2469 BufferList = BufferList->next;
2471 BufferListStart->prev = BufferList;
2472 BufferList->next = BufferListStart;
2475 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2476 WriteUnlock(&source->queue_lock);
2479 ALCcontext_DecRef(context);
2482 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2484 ALCcontext *context;
2486 ALbufferlistitem *NewHead;
2487 ALbufferlistitem *OldHead;
2488 ALbufferlistitem *Current;
2494 context = GetContextRef();
2495 if(!context) return;
2498 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2500 if((source=LookupSource(context, src)) == NULL)
2501 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2503 WriteLock(&source->queue_lock);
2504 /* Find the new buffer queue head */
2505 NewHead = ATOMIC_LOAD(&source->queue);
2506 Current = ATOMIC_LOAD(&source->current_buffer);
2507 for(i = 0;i < nb && NewHead;i++)
2509 if(NewHead == Current)
2511 NewHead = NewHead->next;
2513 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2515 WriteUnlock(&source->queue_lock);
2516 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2517 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2520 /* Swap it, and cut the new head from the old. */
2521 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2524 ALCdevice *device = context->Device;
2525 ALbufferlistitem *OldTail = NewHead->prev;
2528 /* Cut the new head's link back to the old body. The mixer is robust
2529 * enough to handle the link back going away. Once the active mix (if
2530 * any) is complete, it's safe to finish cutting the old tail from the
2532 NewHead->prev = NULL;
2533 if(((count=ReadRef(&device->MixCount))&1) != 0)
2535 while(count == ReadRef(&device->MixCount))
2538 OldTail->next = NULL;
2540 WriteUnlock(&source->queue_lock);
2542 while(OldHead != NULL)
2544 ALbufferlistitem *next = OldHead->next;
2545 ALbuffer *buffer = OldHead->buffer;
2551 *(buffers++) = buffer->id;
2552 DecrementRef(&buffer->ref);
2560 ALCcontext_DecRef(context);
2564 static ALvoid InitSourceParams(ALsource *Source)
2568 RWLockInit(&Source->queue_lock);
2570 Source->InnerAngle = 360.0f;
2571 Source->OuterAngle = 360.0f;
2572 Source->Pitch = 1.0f;
2573 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2574 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2575 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2576 Source->Orientation[0][0] = 0.0f;
2577 Source->Orientation[0][1] = 0.0f;
2578 Source->Orientation[0][2] = -1.0f;
2579 Source->Orientation[1][0] = 0.0f;
2580 Source->Orientation[1][1] = 1.0f;
2581 Source->Orientation[1][2] = 0.0f;
2582 Source->RefDistance = 1.0f;
2583 Source->MaxDistance = FLT_MAX;
2584 Source->RollOffFactor = 1.0f;
2585 Source->Looping = AL_FALSE;
2587 Source->LoopCount = 1;
2589 Source->Gain = 1.0f;
2590 Source->MinGain = 0.0f;
2591 Source->MaxGain = 1.0f;
2592 Source->OuterGain = 0.0f;
2593 Source->OuterGainHF = 1.0f;
2595 Source->DryGainHFAuto = AL_TRUE;
2596 Source->WetGainAuto = AL_TRUE;
2597 Source->WetGainHFAuto = AL_TRUE;
2598 Source->AirAbsorptionFactor = 0.0f;
2599 Source->RoomRolloffFactor = 0.0f;
2600 Source->DopplerFactor = 1.0f;
2601 Source->DirectChannels = AL_FALSE;
2603 Source->Radius = 0.0f;
2605 Source->DistanceModel = DefaultDistanceModel;
2607 Source->state = AL_INITIAL;
2608 Source->new_state = AL_NONE;
2609 Source->SourceType = AL_UNDETERMINED;
2610 Source->Offset = -1.0;
2612 ATOMIC_INIT(&Source->queue, NULL);
2613 ATOMIC_INIT(&Source->current_buffer, NULL);
2615 Source->Direct.Gain = 1.0f;
2616 Source->Direct.GainHF = 1.0f;
2617 Source->Direct.HFReference = LOWPASSFREQREF;
2618 Source->Direct.GainLF = 1.0f;
2619 Source->Direct.LFReference = HIGHPASSFREQREF;
2620 for(i = 0;i < MAX_SENDS;i++)
2622 Source->Send[i].Gain = 1.0f;
2623 Source->Send[i].GainHF = 1.0f;
2624 Source->Send[i].HFReference = LOWPASSFREQREF;
2625 Source->Send[i].GainLF = 1.0f;
2626 Source->Send[i].LFReference = HIGHPASSFREQREF;
2629 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2635 * Sets the source's new play state given its current state.
2637 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2639 WriteLock(&Source->queue_lock);
2640 if(state == AL_PLAYING)
2642 ALCdevice *device = Context->Device;
2643 ALbufferlistitem *BufferList;
2644 ALboolean discontinuity;
2645 ALvoice *voice = NULL;
2648 /* Check that there is a queue containing at least one valid, non zero
2650 BufferList = ATOMIC_LOAD(&Source->queue);
2654 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2656 BufferList = BufferList->next;
2659 if(Source->state != AL_PAUSED)
2661 Source->state = AL_PLAYING;
2662 Source->position = 0;
2663 Source->position_fraction = 0;
2664 ATOMIC_STORE(&Source->current_buffer, BufferList);
2665 discontinuity = AL_TRUE;
2669 Source->state = AL_PLAYING;
2670 discontinuity = AL_FALSE;
2673 // Check if an Offset has been set
2674 if(Source->Offset >= 0.0)
2676 ApplyOffset(Source);
2677 /* discontinuity = AL_TRUE;??? */
2680 /* If there's nothing to play, or device is disconnected, go right to
2682 if(!BufferList || !device->Connected)
2685 /* Make sure this source isn't already active, while looking for an
2686 * unused active source slot to put it in. */
2687 for(i = 0;i < Context->VoiceCount;i++)
2689 ALsource *old = Source;
2690 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2694 voice = &Context->Voices[i];
2695 voice->Source = Source;
2700 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2701 voice = &Context->Voices[i];
2705 voice = &Context->Voices[Context->VoiceCount++];
2706 voice->Source = Source;
2709 /* Clear previous samples if playback is discontinuous. */
2711 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2713 voice->Direct.Moving = AL_FALSE;
2714 voice->Direct.Counter = 0;
2715 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2718 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2719 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2720 for(j = 0;j < HRIR_LENGTH;j++)
2722 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2723 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2726 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2728 voice->Send[i].Moving = AL_FALSE;
2729 voice->Send[i].Counter = 0;
2732 if(BufferList->buffer->FmtChannels == FmtMono)
2733 voice->Update = CalcSourceParams;
2735 voice->Update = CalcNonAttnSourceParams;
2737 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2739 else if(state == AL_PAUSED)
2741 if(Source->state == AL_PLAYING)
2742 Source->state = AL_PAUSED;
2744 else if(state == AL_STOPPED)
2747 if(Source->state != AL_INITIAL)
2749 Source->state = AL_STOPPED;
2750 ATOMIC_STORE(&Source->current_buffer, NULL);
2752 Source->Offset = -1.0;
2754 else if(state == AL_INITIAL)
2756 if(Source->state != AL_INITIAL)
2758 Source->state = AL_INITIAL;
2759 Source->position = 0;
2760 Source->position_fraction = 0;
2761 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2763 Source->Offset = -1.0;
2765 WriteUnlock(&Source->queue_lock);
2768 /* GetSourceSampleOffset
2770 * Gets the current read offset for the given Source, in 32.32 fixed-point
2771 * samples. The offset is relative to the start of the queue (not the start of
2772 * the current buffer).
2774 ALint64 GetSourceSampleOffset(ALsource *Source)
2776 const ALbufferlistitem *BufferList;
2777 const ALbufferlistitem *Current;
2780 ReadLock(&Source->queue_lock);
2781 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2783 ReadUnlock(&Source->queue_lock);
2787 /* NOTE: This is the offset into the *current* buffer, so add the length of
2788 * any played buffers */
2789 readPos = (ALuint64)Source->position << 32;
2790 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2791 BufferList = ATOMIC_LOAD(&Source->queue);
2792 Current = ATOMIC_LOAD(&Source->current_buffer);
2793 while(BufferList && BufferList != Current)
2795 if(BufferList->buffer)
2796 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2797 BufferList = BufferList->next;
2800 ReadUnlock(&Source->queue_lock);
2801 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2804 /* GetSourceSecOffset
2806 * Gets the current read offset for the given Source, in seconds. The offset is
2807 * relative to the start of the queue (not the start of the current buffer).
2809 static ALdouble GetSourceSecOffset(ALsource *Source)
2811 const ALbufferlistitem *BufferList;
2812 const ALbufferlistitem *Current;
2813 const ALbuffer *Buffer = NULL;
2816 ReadLock(&Source->queue_lock);
2817 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2819 ReadUnlock(&Source->queue_lock);
2823 /* NOTE: This is the offset into the *current* buffer, so add the length of
2824 * any played buffers */
2825 readPos = (ALuint64)Source->position << FRACTIONBITS;
2826 readPos |= (ALuint64)Source->position_fraction;
2827 BufferList = ATOMIC_LOAD(&Source->queue);
2828 Current = ATOMIC_LOAD(&Source->current_buffer);
2829 while(BufferList && BufferList != Current)
2831 const ALbuffer *buffer = BufferList->buffer;
2834 if(!Buffer) Buffer = buffer;
2835 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2837 BufferList = BufferList->next;
2840 while(BufferList && !Buffer)
2842 Buffer = BufferList->buffer;
2843 BufferList = BufferList->next;
2845 assert(Buffer != NULL);
2847 ReadUnlock(&Source->queue_lock);
2848 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2853 * Gets the current read and write offsets for the given Source, in the
2854 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2855 * the start of the queue (not the start of the current buffer).
2857 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2859 const ALbufferlistitem *BufferList;
2860 const ALbufferlistitem *Current;
2861 const ALbuffer *Buffer = NULL;
2862 ALboolean readFin = AL_FALSE;
2863 ALuint readPos, readPosFrac, writePos;
2864 ALuint totalBufferLen;
2866 ReadLock(&Source->queue_lock);
2867 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2871 ReadUnlock(&Source->queue_lock);
2875 if(updateLen > 0.0 && updateLen < 0.015)
2878 /* NOTE: This is the offset into the *current* buffer, so add the length of
2879 * any played buffers */
2881 readPos = Source->position;
2882 readPosFrac = Source->position_fraction;
2883 BufferList = ATOMIC_LOAD(&Source->queue);
2884 Current = ATOMIC_LOAD(&Source->current_buffer);
2885 while(BufferList != NULL)
2887 const ALbuffer *buffer;
2888 readFin = readFin || (BufferList == Current);
2889 if((buffer=BufferList->buffer) != NULL)
2891 if(!Buffer) Buffer = buffer;
2892 totalBufferLen += buffer->SampleLen;
2893 if(!readFin) readPos += buffer->SampleLen;
2895 BufferList = BufferList->next;
2897 assert(Buffer != NULL);
2899 if(Source->state == AL_PLAYING)
2900 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2906 readPos %= totalBufferLen;
2907 writePos %= totalBufferLen;
2911 /* Wrap positions back to 0 */
2912 if(readPos >= totalBufferLen)
2913 readPos = readPosFrac = 0;
2914 if(writePos >= totalBufferLen)
2921 offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2922 offset[1] = (ALdouble)writePos/Buffer->Frequency;
2925 case AL_SAMPLE_OFFSET:
2926 case AL_SAMPLE_RW_OFFSETS_SOFT:
2927 offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2928 offset[1] = (ALdouble)writePos;
2931 case AL_BYTE_OFFSET:
2932 case AL_BYTE_RW_OFFSETS_SOFT:
2933 if(Buffer->OriginalType == UserFmtIMA4)
2935 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2936 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2937 ALuint FrameBlockSize = Buffer->OriginalAlign;
2939 /* Round down to nearest ADPCM block */
2940 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2941 if(Source->state != AL_PLAYING)
2942 offset[1] = offset[0];
2945 /* Round up to nearest ADPCM block */
2946 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2947 FrameBlockSize * BlockSize);
2950 else if(Buffer->OriginalType == UserFmtMSADPCM)
2952 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2953 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2954 ALuint FrameBlockSize = Buffer->OriginalAlign;
2956 /* Round down to nearest ADPCM block */
2957 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2958 if(Source->state != AL_PLAYING)
2959 offset[1] = offset[0];
2962 /* Round up to nearest ADPCM block */
2963 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2964 FrameBlockSize * BlockSize);
2969 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2970 offset[0] = (ALdouble)(readPos * FrameSize);
2971 offset[1] = (ALdouble)(writePos * FrameSize);
2976 ReadUnlock(&Source->queue_lock);
2982 * Apply the stored playback offset to the Source. This function will update
2983 * the number of buffers "played" given the stored offset.
2985 ALboolean ApplyOffset(ALsource *Source)
2987 ALbufferlistitem *BufferList;
2988 const ALbuffer *Buffer;
2989 ALuint bufferLen, totalBufferLen;
2990 ALuint offset=0, frac=0;
2992 /* Get sample frame offset */
2993 if(!GetSampleOffset(Source, &offset, &frac))
2997 BufferList = ATOMIC_LOAD(&Source->queue);
2998 while(BufferList && totalBufferLen <= offset)
3000 Buffer = BufferList->buffer;
3001 bufferLen = Buffer ? Buffer->SampleLen : 0;
3003 if(bufferLen > offset-totalBufferLen)
3005 /* Offset is in this buffer */
3006 ATOMIC_STORE(&Source->current_buffer, BufferList);
3008 Source->position = offset - totalBufferLen;
3009 Source->position_fraction = frac;
3013 totalBufferLen += bufferLen;
3015 BufferList = BufferList->next;
3018 /* Offset is out of range of the queue */
3025 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3026 * or Second offset supplied by the application). This takes into account the
3027 * fact that the buffer format may have been modifed since.
3029 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3031 const ALbuffer *Buffer = NULL;
3032 const ALbufferlistitem *BufferList;
3033 ALdouble dbloff, dblfrac;
3035 /* Find the first valid Buffer in the Queue */
3036 BufferList = ATOMIC_LOAD(&Source->queue);
3039 if(BufferList->buffer)
3041 Buffer = BufferList->buffer;
3044 BufferList = BufferList->next;
3048 Source->Offset = -1.0;
3052 switch(Source->OffsetType)
3054 case AL_BYTE_OFFSET:
3055 /* Determine the ByteOffset (and ensure it is block aligned) */
3056 *offset = (ALuint)Source->Offset;
3057 if(Buffer->OriginalType == UserFmtIMA4)
3059 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3060 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3061 *offset *= Buffer->OriginalAlign;
3063 else if(Buffer->OriginalType == UserFmtMSADPCM)
3065 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3066 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3067 *offset *= Buffer->OriginalAlign;
3070 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3074 case AL_SAMPLE_OFFSET:
3075 dblfrac = modf(Source->Offset, &dbloff);
3076 *offset = (ALuint)mind(dbloff, UINT_MAX);
3077 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3081 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3082 *offset = (ALuint)mind(dbloff, UINT_MAX);
3083 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3086 Source->Offset = -1.0;
3094 * Destroys all sources in the source map.
3096 ALvoid ReleaseALSources(ALCcontext *Context)
3098 ALbufferlistitem *item;
3101 for(pos = 0;pos < Context->SourceMap.size;pos++)
3103 ALsource *temp = Context->SourceMap.array[pos].value;
3104 Context->SourceMap.array[pos].value = NULL;
3106 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3109 ALbufferlistitem *next = item->next;
3110 if(item->buffer != NULL)
3111 DecrementRef(&item->buffer->ref);
3116 for(j = 0;j < MAX_SENDS;++j)
3118 if(temp->Send[j].Slot)
3119 DecrementRef(&temp->Send[j].Slot->ref);
3120 temp->Send[j].Slot = NULL;
3123 FreeThunkEntry(temp->id);
3124 memset(temp, 0, sizeof(*temp));