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"
43 extern inline void LockSourcesRead(ALCcontext
*context
);
44 extern inline void UnlockSourcesRead(ALCcontext
*context
);
45 extern inline void LockSourcesWrite(ALCcontext
*context
);
46 extern inline void UnlockSourcesWrite(ALCcontext
*context
);
47 extern inline struct ALsource
*LookupSource(ALCcontext
*context
, ALuint id
);
48 extern inline struct ALsource
*RemoveSource(ALCcontext
*context
, ALuint id
);
49 extern inline ALboolean
IsPlayingOrPaused(const ALsource
*source
);
51 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
52 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
53 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
);
54 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
56 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
57 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
);
59 typedef enum SourceProp
{
62 srcMinGain
= AL_MIN_GAIN
,
63 srcMaxGain
= AL_MAX_GAIN
,
64 srcMaxDistance
= AL_MAX_DISTANCE
,
65 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
66 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
67 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
68 srcSecOffset
= AL_SEC_OFFSET
,
69 srcSampleOffset
= AL_SAMPLE_OFFSET
,
70 srcByteOffset
= AL_BYTE_OFFSET
,
71 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
72 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
73 srcRefDistance
= AL_REFERENCE_DISTANCE
,
75 srcPosition
= AL_POSITION
,
76 srcVelocity
= AL_VELOCITY
,
77 srcDirection
= AL_DIRECTION
,
79 srcSourceRelative
= AL_SOURCE_RELATIVE
,
80 srcLooping
= AL_LOOPING
,
81 srcBuffer
= AL_BUFFER
,
82 srcSourceState
= AL_SOURCE_STATE
,
83 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
84 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
85 srcSourceType
= AL_SOURCE_TYPE
,
88 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
89 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
90 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
91 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
92 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
93 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
94 srcDirectFilter
= AL_DIRECT_FILTER
,
95 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel
= AL_DISTANCE_MODEL
,
103 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
104 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
105 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
109 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles
= AL_STEREO_ANGLES
,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius
= AL_SOURCE_RADIUS
,
118 srcOrientation
= AL_ORIENTATION
,
121 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
122 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
123 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
125 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
126 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
127 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
129 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
131 ALvoice
**voice
= context
->Voices
;
132 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
133 while(voice
!= voice_end
)
135 if((*voice
)->Source
== source
)
142 static inline bool IsPlayingOrPausedSeq(const ALsource
*source
)
144 ALenum state
= ATOMIC_LOAD_SEQ(&source
->state
);
145 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
148 static inline bool SourceShouldUpdate(const ALsource
*source
, const ALCcontext
*context
)
150 return IsPlayingOrPausedSeq(source
) &&
151 !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
);
154 static ALint
FloatValsByProp(ALenum prop
)
156 if(prop
!= (ALenum
)((SourceProp
)prop
))
158 switch((SourceProp
)prop
)
164 case AL_MAX_DISTANCE
:
165 case AL_ROLLOFF_FACTOR
:
166 case AL_DOPPLER_FACTOR
:
167 case AL_CONE_OUTER_GAIN
:
169 case AL_SAMPLE_OFFSET
:
171 case AL_CONE_INNER_ANGLE
:
172 case AL_CONE_OUTER_ANGLE
:
173 case AL_REFERENCE_DISTANCE
:
174 case AL_CONE_OUTER_GAINHF
:
175 case AL_AIR_ABSORPTION_FACTOR
:
176 case AL_ROOM_ROLLOFF_FACTOR
:
177 case AL_DIRECT_FILTER_GAINHF_AUTO
:
178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
179 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
180 case AL_DIRECT_CHANNELS_SOFT
:
181 case AL_DISTANCE_MODEL
:
182 case AL_SOURCE_RELATIVE
:
184 case AL_SOURCE_STATE
:
185 case AL_BUFFERS_QUEUED
:
186 case AL_BUFFERS_PROCESSED
:
188 case AL_BYTE_LENGTH_SOFT
:
189 case AL_SAMPLE_LENGTH_SOFT
:
190 case AL_SEC_LENGTH_SOFT
:
191 case AL_SOURCE_RADIUS
:
194 case AL_STEREO_ANGLES
:
205 case AL_SEC_OFFSET_LATENCY_SOFT
:
206 break; /* Double only */
209 case AL_DIRECT_FILTER
:
210 case AL_AUXILIARY_SEND_FILTER
:
211 break; /* i/i64 only */
212 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
213 break; /* i64 only */
217 static ALint
DoubleValsByProp(ALenum prop
)
219 if(prop
!= (ALenum
)((SourceProp
)prop
))
221 switch((SourceProp
)prop
)
227 case AL_MAX_DISTANCE
:
228 case AL_ROLLOFF_FACTOR
:
229 case AL_DOPPLER_FACTOR
:
230 case AL_CONE_OUTER_GAIN
:
232 case AL_SAMPLE_OFFSET
:
234 case AL_CONE_INNER_ANGLE
:
235 case AL_CONE_OUTER_ANGLE
:
236 case AL_REFERENCE_DISTANCE
:
237 case AL_CONE_OUTER_GAINHF
:
238 case AL_AIR_ABSORPTION_FACTOR
:
239 case AL_ROOM_ROLLOFF_FACTOR
:
240 case AL_DIRECT_FILTER_GAINHF_AUTO
:
241 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
242 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
243 case AL_DIRECT_CHANNELS_SOFT
:
244 case AL_DISTANCE_MODEL
:
245 case AL_SOURCE_RELATIVE
:
247 case AL_SOURCE_STATE
:
248 case AL_BUFFERS_QUEUED
:
249 case AL_BUFFERS_PROCESSED
:
251 case AL_BYTE_LENGTH_SOFT
:
252 case AL_SAMPLE_LENGTH_SOFT
:
253 case AL_SEC_LENGTH_SOFT
:
254 case AL_SOURCE_RADIUS
:
257 case AL_SEC_OFFSET_LATENCY_SOFT
:
258 case AL_STEREO_ANGLES
:
270 case AL_DIRECT_FILTER
:
271 case AL_AUXILIARY_SEND_FILTER
:
272 break; /* i/i64 only */
273 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
274 break; /* i64 only */
279 static ALint
IntValsByProp(ALenum prop
)
281 if(prop
!= (ALenum
)((SourceProp
)prop
))
283 switch((SourceProp
)prop
)
289 case AL_MAX_DISTANCE
:
290 case AL_ROLLOFF_FACTOR
:
291 case AL_DOPPLER_FACTOR
:
292 case AL_CONE_OUTER_GAIN
:
294 case AL_SAMPLE_OFFSET
:
296 case AL_CONE_INNER_ANGLE
:
297 case AL_CONE_OUTER_ANGLE
:
298 case AL_REFERENCE_DISTANCE
:
299 case AL_CONE_OUTER_GAINHF
:
300 case AL_AIR_ABSORPTION_FACTOR
:
301 case AL_ROOM_ROLLOFF_FACTOR
:
302 case AL_DIRECT_FILTER_GAINHF_AUTO
:
303 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
304 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
305 case AL_DIRECT_CHANNELS_SOFT
:
306 case AL_DISTANCE_MODEL
:
307 case AL_SOURCE_RELATIVE
:
310 case AL_SOURCE_STATE
:
311 case AL_BUFFERS_QUEUED
:
312 case AL_BUFFERS_PROCESSED
:
314 case AL_DIRECT_FILTER
:
315 case AL_BYTE_LENGTH_SOFT
:
316 case AL_SAMPLE_LENGTH_SOFT
:
317 case AL_SEC_LENGTH_SOFT
:
318 case AL_SOURCE_RADIUS
:
324 case AL_AUXILIARY_SEND_FILTER
:
330 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
331 break; /* i64 only */
332 case AL_SEC_OFFSET_LATENCY_SOFT
:
333 break; /* Double only */
334 case AL_STEREO_ANGLES
:
335 break; /* Float/double only */
339 static ALint
Int64ValsByProp(ALenum prop
)
341 if(prop
!= (ALenum
)((SourceProp
)prop
))
343 switch((SourceProp
)prop
)
349 case AL_MAX_DISTANCE
:
350 case AL_ROLLOFF_FACTOR
:
351 case AL_DOPPLER_FACTOR
:
352 case AL_CONE_OUTER_GAIN
:
354 case AL_SAMPLE_OFFSET
:
356 case AL_CONE_INNER_ANGLE
:
357 case AL_CONE_OUTER_ANGLE
:
358 case AL_REFERENCE_DISTANCE
:
359 case AL_CONE_OUTER_GAINHF
:
360 case AL_AIR_ABSORPTION_FACTOR
:
361 case AL_ROOM_ROLLOFF_FACTOR
:
362 case AL_DIRECT_FILTER_GAINHF_AUTO
:
363 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
364 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
365 case AL_DIRECT_CHANNELS_SOFT
:
366 case AL_DISTANCE_MODEL
:
367 case AL_SOURCE_RELATIVE
:
370 case AL_SOURCE_STATE
:
371 case AL_BUFFERS_QUEUED
:
372 case AL_BUFFERS_PROCESSED
:
374 case AL_DIRECT_FILTER
:
375 case AL_BYTE_LENGTH_SOFT
:
376 case AL_SAMPLE_LENGTH_SOFT
:
377 case AL_SEC_LENGTH_SOFT
:
378 case AL_SOURCE_RADIUS
:
381 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
387 case AL_AUXILIARY_SEND_FILTER
:
393 case AL_SEC_OFFSET_LATENCY_SOFT
:
394 break; /* Double only */
395 case AL_STEREO_ANGLES
:
396 break; /* Float/double only */
402 #define CHECKVAL(x) do { \
404 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
407 #define DO_UPDATEPROPS() do { \
408 if(SourceShouldUpdate(Source, Context)) \
409 UpdateSourceProps(Source, device->NumAuxSends); \
411 Source->NeedsUpdate = AL_TRUE; \
414 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
416 ALCdevice
*device
= Context
->Device
;
421 case AL_BYTE_LENGTH_SOFT
:
422 case AL_SAMPLE_LENGTH_SOFT
:
423 case AL_SEC_LENGTH_SOFT
:
424 case AL_SEC_OFFSET_LATENCY_SOFT
:
426 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
429 CHECKVAL(*values
>= 0.0f
);
431 Source
->Pitch
= *values
;
435 case AL_CONE_INNER_ANGLE
:
436 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
438 Source
->InnerAngle
= *values
;
442 case AL_CONE_OUTER_ANGLE
:
443 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
445 Source
->OuterAngle
= *values
;
450 CHECKVAL(*values
>= 0.0f
);
452 Source
->Gain
= *values
;
456 case AL_MAX_DISTANCE
:
457 CHECKVAL(*values
>= 0.0f
);
459 Source
->MaxDistance
= *values
;
463 case AL_ROLLOFF_FACTOR
:
464 CHECKVAL(*values
>= 0.0f
);
466 Source
->RollOffFactor
= *values
;
470 case AL_REFERENCE_DISTANCE
:
471 CHECKVAL(*values
>= 0.0f
);
473 Source
->RefDistance
= *values
;
478 CHECKVAL(*values
>= 0.0f
);
480 Source
->MinGain
= *values
;
485 CHECKVAL(*values
>= 0.0f
);
487 Source
->MaxGain
= *values
;
491 case AL_CONE_OUTER_GAIN
:
492 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
494 Source
->OuterGain
= *values
;
498 case AL_CONE_OUTER_GAINHF
:
499 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
501 Source
->OuterGainHF
= *values
;
505 case AL_AIR_ABSORPTION_FACTOR
:
506 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
508 Source
->AirAbsorptionFactor
= *values
;
512 case AL_ROOM_ROLLOFF_FACTOR
:
513 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
515 Source
->RoomRolloffFactor
= *values
;
519 case AL_DOPPLER_FACTOR
:
520 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
522 Source
->DopplerFactor
= *values
;
527 case AL_SAMPLE_OFFSET
:
529 CHECKVAL(*values
>= 0.0f
);
531 Source
->OffsetType
= prop
;
532 Source
->Offset
= *values
;
534 if(!ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
) &&
535 IsPlayingOrPausedSeq(Source
))
539 ALCdevice_Lock(Context
->Device
);
540 /* Double-check that the source is still playing while we have
543 voice
= GetSourceVoice(Source
, Context
);
546 WriteLock(&Source
->queue_lock
);
547 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
549 WriteUnlock(&Source
->queue_lock
);
550 ALCdevice_Unlock(Context
->Device
);
551 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
553 WriteUnlock(&Source
->queue_lock
);
555 ALCdevice_Unlock(Context
->Device
);
559 case AL_SOURCE_RADIUS
:
560 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
562 Source
->Radius
= *values
;
566 case AL_STEREO_ANGLES
:
567 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
569 Source
->StereoPan
[0] = values
[0];
570 Source
->StereoPan
[1] = values
[1];
576 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
578 Source
->Position
[0] = values
[0];
579 Source
->Position
[1] = values
[1];
580 Source
->Position
[2] = values
[2];
585 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
587 Source
->Velocity
[0] = values
[0];
588 Source
->Velocity
[1] = values
[1];
589 Source
->Velocity
[2] = values
[2];
594 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
596 Source
->Direction
[0] = values
[0];
597 Source
->Direction
[1] = values
[1];
598 Source
->Direction
[2] = values
[2];
603 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
604 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
606 Source
->Orientation
[0][0] = values
[0];
607 Source
->Orientation
[0][1] = values
[1];
608 Source
->Orientation
[0][2] = values
[2];
609 Source
->Orientation
[1][0] = values
[3];
610 Source
->Orientation
[1][1] = values
[4];
611 Source
->Orientation
[1][2] = values
[5];
616 case AL_SOURCE_RELATIVE
:
618 case AL_SOURCE_STATE
:
620 case AL_DISTANCE_MODEL
:
621 case AL_DIRECT_FILTER_GAINHF_AUTO
:
622 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
623 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
624 case AL_DIRECT_CHANNELS_SOFT
:
625 ival
= (ALint
)values
[0];
626 return SetSourceiv(Source
, Context
, prop
, &ival
);
628 case AL_BUFFERS_QUEUED
:
629 case AL_BUFFERS_PROCESSED
:
630 ival
= (ALint
)((ALuint
)values
[0]);
631 return SetSourceiv(Source
, Context
, prop
, &ival
);
634 case AL_DIRECT_FILTER
:
635 case AL_AUXILIARY_SEND_FILTER
:
636 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
640 ERR("Unexpected property: 0x%04x\n", prop
);
641 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
644 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
646 ALCdevice
*device
= Context
->Device
;
647 ALbuffer
*buffer
= NULL
;
648 ALfilter
*filter
= NULL
;
649 ALeffectslot
*slot
= NULL
;
650 ALbufferlistitem
*oldlist
;
651 ALbufferlistitem
*newlist
;
656 case AL_SOURCE_STATE
:
658 case AL_BUFFERS_QUEUED
:
659 case AL_BUFFERS_PROCESSED
:
660 case AL_BYTE_LENGTH_SOFT
:
661 case AL_SAMPLE_LENGTH_SOFT
:
662 case AL_SEC_LENGTH_SOFT
:
664 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
666 case AL_SOURCE_RELATIVE
:
667 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
669 Source
->HeadRelative
= (ALboolean
)*values
;
674 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
676 WriteLock(&Source
->queue_lock
);
677 ATOMIC_STORE_SEQ(&Source
->looping
, *values
);
678 WriteUnlock(&Source
->queue_lock
);
682 LockBuffersRead(device
);
683 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
685 UnlockBuffersRead(device
);
686 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
689 WriteLock(&Source
->queue_lock
);
690 if(IsPlayingOrPausedSeq(Source
))
692 WriteUnlock(&Source
->queue_lock
);
693 UnlockBuffersRead(device
);
694 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
699 /* Add the selected buffer to a one-item queue */
700 newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
701 newlist
->buffer
= buffer
;
702 newlist
->next
= NULL
;
703 IncrementRef(&buffer
->ref
);
705 /* Source is now Static */
706 Source
->SourceType
= AL_STATIC
;
708 ReadLock(&buffer
->lock
);
709 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
710 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
711 ReadUnlock(&buffer
->lock
);
715 /* Source is now Undetermined */
716 Source
->SourceType
= AL_UNDETERMINED
;
719 oldlist
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &Source
->queue
, newlist
);
720 WriteUnlock(&Source
->queue_lock
);
721 UnlockBuffersRead(device
);
723 /* Delete all elements in the previous queue */
724 while(oldlist
!= NULL
)
726 ALbufferlistitem
*temp
= oldlist
;
727 oldlist
= temp
->next
;
730 DecrementRef(&temp
->buffer
->ref
);
736 case AL_SAMPLE_OFFSET
:
738 CHECKVAL(*values
>= 0);
740 Source
->OffsetType
= prop
;
741 Source
->Offset
= *values
;
743 if(!ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
) &&
744 IsPlayingOrPausedSeq(Source
))
748 ALCdevice_Lock(Context
->Device
);
749 voice
= GetSourceVoice(Source
, Context
);
752 WriteLock(&Source
->queue_lock
);
753 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
755 WriteUnlock(&Source
->queue_lock
);
756 ALCdevice_Unlock(Context
->Device
);
757 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
759 WriteUnlock(&Source
->queue_lock
);
761 ALCdevice_Unlock(Context
->Device
);
765 case AL_DIRECT_FILTER
:
766 LockFiltersRead(device
);
767 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
769 UnlockFiltersRead(device
);
770 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
775 Source
->Direct
.Gain
= 1.0f
;
776 Source
->Direct
.GainHF
= 1.0f
;
777 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
778 Source
->Direct
.GainLF
= 1.0f
;
779 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
783 Source
->Direct
.Gain
= filter
->Gain
;
784 Source
->Direct
.GainHF
= filter
->GainHF
;
785 Source
->Direct
.HFReference
= filter
->HFReference
;
786 Source
->Direct
.GainLF
= filter
->GainLF
;
787 Source
->Direct
.LFReference
= filter
->LFReference
;
789 UnlockFiltersRead(device
);
793 case AL_DIRECT_FILTER_GAINHF_AUTO
:
794 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
796 Source
->DryGainHFAuto
= *values
;
800 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
801 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
803 Source
->WetGainAuto
= *values
;
807 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
808 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
810 Source
->WetGainHFAuto
= *values
;
814 case AL_DIRECT_CHANNELS_SOFT
:
815 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
817 Source
->DirectChannels
= *values
;
821 case AL_DISTANCE_MODEL
:
822 CHECKVAL(*values
== AL_NONE
||
823 *values
== AL_INVERSE_DISTANCE
||
824 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
825 *values
== AL_LINEAR_DISTANCE
||
826 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
827 *values
== AL_EXPONENT_DISTANCE
||
828 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
830 Source
->DistanceModel
= *values
;
831 if(Context
->SourceDistanceModel
)
836 case AL_AUXILIARY_SEND_FILTER
:
837 LockEffectSlotsRead(Context
);
838 LockFiltersRead(device
);
839 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
840 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
841 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
843 UnlockFiltersRead(device
);
844 UnlockEffectSlotsRead(Context
);
845 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
851 Source
->Send
[values
[1]].Gain
= 1.0f
;
852 Source
->Send
[values
[1]].GainHF
= 1.0f
;
853 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
854 Source
->Send
[values
[1]].GainLF
= 1.0f
;
855 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
859 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
860 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
861 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
862 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
863 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
865 UnlockFiltersRead(device
);
867 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPausedSeq(Source
))
869 /* Add refcount on the new slot, and release the previous slot */
870 if(slot
) IncrementRef(&slot
->ref
);
871 if(Source
->Send
[values
[1]].Slot
)
872 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
873 Source
->Send
[values
[1]].Slot
= slot
;
875 /* We must force an update if the auxiliary slot changed on a
876 * playing source, in case the slot is about to be deleted.
878 UpdateSourceProps(Source
, device
->NumAuxSends
);
882 if(slot
) IncrementRef(&slot
->ref
);
883 if(Source
->Send
[values
[1]].Slot
)
884 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
885 Source
->Send
[values
[1]].Slot
= slot
;
888 UnlockEffectSlotsRead(Context
);
894 case AL_CONE_INNER_ANGLE
:
895 case AL_CONE_OUTER_ANGLE
:
900 case AL_REFERENCE_DISTANCE
:
901 case AL_ROLLOFF_FACTOR
:
902 case AL_CONE_OUTER_GAIN
:
903 case AL_MAX_DISTANCE
:
904 case AL_DOPPLER_FACTOR
:
905 case AL_CONE_OUTER_GAINHF
:
906 case AL_AIR_ABSORPTION_FACTOR
:
907 case AL_ROOM_ROLLOFF_FACTOR
:
908 case AL_SOURCE_RADIUS
:
909 fvals
[0] = (ALfloat
)*values
;
910 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
916 fvals
[0] = (ALfloat
)values
[0];
917 fvals
[1] = (ALfloat
)values
[1];
918 fvals
[2] = (ALfloat
)values
[2];
919 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
923 fvals
[0] = (ALfloat
)values
[0];
924 fvals
[1] = (ALfloat
)values
[1];
925 fvals
[2] = (ALfloat
)values
[2];
926 fvals
[3] = (ALfloat
)values
[3];
927 fvals
[4] = (ALfloat
)values
[4];
928 fvals
[5] = (ALfloat
)values
[5];
929 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
931 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
932 case AL_SEC_OFFSET_LATENCY_SOFT
:
933 case AL_STEREO_ANGLES
:
937 ERR("Unexpected property: 0x%04x\n", prop
);
938 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
941 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
949 case AL_BUFFERS_QUEUED
:
950 case AL_BUFFERS_PROCESSED
:
951 case AL_SOURCE_STATE
:
952 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
953 case AL_BYTE_LENGTH_SOFT
:
954 case AL_SAMPLE_LENGTH_SOFT
:
955 case AL_SEC_LENGTH_SOFT
:
957 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
961 case AL_SOURCE_RELATIVE
:
964 case AL_SAMPLE_OFFSET
:
966 case AL_DIRECT_FILTER_GAINHF_AUTO
:
967 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
968 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
969 case AL_DIRECT_CHANNELS_SOFT
:
970 case AL_DISTANCE_MODEL
:
971 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
973 ivals
[0] = (ALint
)*values
;
974 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
978 case AL_DIRECT_FILTER
:
979 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
981 ivals
[0] = (ALuint
)*values
;
982 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
985 case AL_AUXILIARY_SEND_FILTER
:
986 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
987 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
988 values
[2] <= UINT_MAX
&& values
[2] >= 0);
990 ivals
[0] = (ALuint
)values
[0];
991 ivals
[1] = (ALuint
)values
[1];
992 ivals
[2] = (ALuint
)values
[2];
993 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
996 case AL_CONE_INNER_ANGLE
:
997 case AL_CONE_OUTER_ANGLE
:
1002 case AL_REFERENCE_DISTANCE
:
1003 case AL_ROLLOFF_FACTOR
:
1004 case AL_CONE_OUTER_GAIN
:
1005 case AL_MAX_DISTANCE
:
1006 case AL_DOPPLER_FACTOR
:
1007 case AL_CONE_OUTER_GAINHF
:
1008 case AL_AIR_ABSORPTION_FACTOR
:
1009 case AL_ROOM_ROLLOFF_FACTOR
:
1010 case AL_SOURCE_RADIUS
:
1011 fvals
[0] = (ALfloat
)*values
;
1012 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1018 fvals
[0] = (ALfloat
)values
[0];
1019 fvals
[1] = (ALfloat
)values
[1];
1020 fvals
[2] = (ALfloat
)values
[2];
1021 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1024 case AL_ORIENTATION
:
1025 fvals
[0] = (ALfloat
)values
[0];
1026 fvals
[1] = (ALfloat
)values
[1];
1027 fvals
[2] = (ALfloat
)values
[2];
1028 fvals
[3] = (ALfloat
)values
[3];
1029 fvals
[4] = (ALfloat
)values
[4];
1030 fvals
[5] = (ALfloat
)values
[5];
1031 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1033 case AL_SEC_OFFSET_LATENCY_SOFT
:
1034 case AL_STEREO_ANGLES
:
1038 ERR("Unexpected property: 0x%04x\n", prop
);
1039 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1045 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1047 ALCdevice
*device
= Context
->Device
;
1048 ALbufferlistitem
*BufferList
;
1049 ClockLatency clocktime
;
1057 *values
= Source
->Gain
;
1061 *values
= Source
->Pitch
;
1064 case AL_MAX_DISTANCE
:
1065 *values
= Source
->MaxDistance
;
1068 case AL_ROLLOFF_FACTOR
:
1069 *values
= Source
->RollOffFactor
;
1072 case AL_REFERENCE_DISTANCE
:
1073 *values
= Source
->RefDistance
;
1076 case AL_CONE_INNER_ANGLE
:
1077 *values
= Source
->InnerAngle
;
1080 case AL_CONE_OUTER_ANGLE
:
1081 *values
= Source
->OuterAngle
;
1085 *values
= Source
->MinGain
;
1089 *values
= Source
->MaxGain
;
1092 case AL_CONE_OUTER_GAIN
:
1093 *values
= Source
->OuterGain
;
1097 case AL_SAMPLE_OFFSET
:
1098 case AL_BYTE_OFFSET
:
1099 *values
= GetSourceOffset(Source
, prop
, Context
);
1102 case AL_CONE_OUTER_GAINHF
:
1103 *values
= Source
->OuterGainHF
;
1106 case AL_AIR_ABSORPTION_FACTOR
:
1107 *values
= Source
->AirAbsorptionFactor
;
1110 case AL_ROOM_ROLLOFF_FACTOR
:
1111 *values
= Source
->RoomRolloffFactor
;
1114 case AL_DOPPLER_FACTOR
:
1115 *values
= Source
->DopplerFactor
;
1118 case AL_SEC_LENGTH_SOFT
:
1119 ReadLock(&Source
->queue_lock
);
1120 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1127 ALbuffer
*buffer
= BufferList
->buffer
;
1128 if(buffer
&& buffer
->SampleLen
> 0)
1130 freq
= buffer
->Frequency
;
1131 length
+= buffer
->SampleLen
;
1133 } while((BufferList
=BufferList
->next
) != NULL
);
1134 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1136 ReadUnlock(&Source
->queue_lock
);
1139 case AL_SOURCE_RADIUS
:
1140 *values
= Source
->Radius
;
1143 case AL_STEREO_ANGLES
:
1144 values
[0] = Source
->StereoPan
[0];
1145 values
[1] = Source
->StereoPan
[1];
1148 case AL_SEC_OFFSET_LATENCY_SOFT
:
1149 /* Get the source offset with the clock time first. Then get the
1150 * clock time with the device latency. Order is important.
1152 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1153 clocktime
= V0(device
->Backend
,getClockLatency
)();
1154 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1155 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1158 /* If the clock time incremented, reduce the latency by that
1159 * much since it's that much closer to the source offset it got
1162 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1163 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1169 values
[0] = Source
->Position
[0];
1170 values
[1] = Source
->Position
[1];
1171 values
[2] = Source
->Position
[2];
1175 values
[0] = Source
->Velocity
[0];
1176 values
[1] = Source
->Velocity
[1];
1177 values
[2] = Source
->Velocity
[2];
1181 values
[0] = Source
->Direction
[0];
1182 values
[1] = Source
->Direction
[1];
1183 values
[2] = Source
->Direction
[2];
1186 case AL_ORIENTATION
:
1187 values
[0] = Source
->Orientation
[0][0];
1188 values
[1] = Source
->Orientation
[0][1];
1189 values
[2] = Source
->Orientation
[0][2];
1190 values
[3] = Source
->Orientation
[1][0];
1191 values
[4] = Source
->Orientation
[1][1];
1192 values
[5] = Source
->Orientation
[1][2];
1196 case AL_SOURCE_RELATIVE
:
1198 case AL_SOURCE_STATE
:
1199 case AL_BUFFERS_QUEUED
:
1200 case AL_BUFFERS_PROCESSED
:
1201 case AL_SOURCE_TYPE
:
1202 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1205 case AL_DIRECT_CHANNELS_SOFT
:
1206 case AL_BYTE_LENGTH_SOFT
:
1207 case AL_SAMPLE_LENGTH_SOFT
:
1208 case AL_DISTANCE_MODEL
:
1209 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1210 *values
= (ALdouble
)ivals
[0];
1214 case AL_DIRECT_FILTER
:
1215 case AL_AUXILIARY_SEND_FILTER
:
1216 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1220 ERR("Unexpected property: 0x%04x\n", prop
);
1221 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1224 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1226 ALbufferlistitem
*BufferList
;
1232 case AL_SOURCE_RELATIVE
:
1233 *values
= Source
->HeadRelative
;
1237 *values
= ATOMIC_LOAD_SEQ(&Source
->looping
);
1241 ReadLock(&Source
->queue_lock
);
1242 BufferList
= (Source
->SourceType
== AL_STATIC
) ?
1243 ATOMIC_LOAD_SEQ(&Source
->queue
) : NULL
;
1244 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1245 ReadUnlock(&Source
->queue_lock
);
1248 case AL_SOURCE_STATE
:
1249 *values
= ATOMIC_LOAD_SEQ(&Source
->state
);
1252 case AL_BYTE_LENGTH_SOFT
:
1253 ReadLock(&Source
->queue_lock
);
1254 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1260 ALbuffer
*buffer
= BufferList
->buffer
;
1261 if(buffer
&& buffer
->SampleLen
> 0)
1263 ALuint byte_align
, sample_align
;
1264 if(buffer
->OriginalType
== UserFmtIMA4
)
1266 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1267 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1268 sample_align
= buffer
->OriginalAlign
;
1270 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1272 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1273 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1274 sample_align
= buffer
->OriginalAlign
;
1278 ALsizei align
= buffer
->OriginalAlign
;
1279 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1280 sample_align
= buffer
->OriginalAlign
;
1283 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1285 } while((BufferList
=BufferList
->next
) != NULL
);
1288 ReadUnlock(&Source
->queue_lock
);
1291 case AL_SAMPLE_LENGTH_SOFT
:
1292 ReadLock(&Source
->queue_lock
);
1293 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1299 ALbuffer
*buffer
= BufferList
->buffer
;
1300 if(buffer
) length
+= buffer
->SampleLen
;
1301 } while((BufferList
=BufferList
->next
) != NULL
);
1304 ReadUnlock(&Source
->queue_lock
);
1307 case AL_BUFFERS_QUEUED
:
1308 ReadLock(&Source
->queue_lock
);
1309 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1316 } while((BufferList
=BufferList
->next
) != NULL
);
1319 ReadUnlock(&Source
->queue_lock
);
1322 case AL_BUFFERS_PROCESSED
:
1323 ReadLock(&Source
->queue_lock
);
1324 if(ATOMIC_LOAD_SEQ(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1326 /* Buffers on a looping source are in a perpetual state of
1327 * PENDING, so don't report any as PROCESSED */
1332 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
1333 const ALbufferlistitem
*Current
= NULL
;
1337 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1338 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1339 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1340 Current
= BufferList
;
1342 while(BufferList
&& BufferList
!= Current
)
1345 BufferList
= BufferList
->next
;
1349 ReadUnlock(&Source
->queue_lock
);
1352 case AL_SOURCE_TYPE
:
1353 *values
= Source
->SourceType
;
1356 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1357 *values
= Source
->DryGainHFAuto
;
1360 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1361 *values
= Source
->WetGainAuto
;
1364 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1365 *values
= Source
->WetGainHFAuto
;
1368 case AL_DIRECT_CHANNELS_SOFT
:
1369 *values
= Source
->DirectChannels
;
1372 case AL_DISTANCE_MODEL
:
1373 *values
= Source
->DistanceModel
;
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 case AL_SOURCE_RADIUS
:
1396 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1397 *values
= (ALint
)dvals
[0];
1400 /* 3x float/double */
1404 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1406 values
[0] = (ALint
)dvals
[0];
1407 values
[1] = (ALint
)dvals
[1];
1408 values
[2] = (ALint
)dvals
[2];
1412 /* 6x float/double */
1413 case AL_ORIENTATION
:
1414 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1416 values
[0] = (ALint
)dvals
[0];
1417 values
[1] = (ALint
)dvals
[1];
1418 values
[2] = (ALint
)dvals
[2];
1419 values
[3] = (ALint
)dvals
[3];
1420 values
[4] = (ALint
)dvals
[4];
1421 values
[5] = (ALint
)dvals
[5];
1425 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1426 break; /* i64 only */
1427 case AL_SEC_OFFSET_LATENCY_SOFT
:
1428 break; /* Double only */
1429 case AL_STEREO_ANGLES
:
1430 break; /* Float/double only */
1432 case AL_DIRECT_FILTER
:
1433 case AL_AUXILIARY_SEND_FILTER
:
1437 ERR("Unexpected property: 0x%04x\n", prop
);
1438 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1441 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1443 ALCdevice
*device
= Context
->Device
;
1444 ClockLatency clocktime
;
1452 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1453 /* Get the source offset with the clock time first. Then get the
1454 * clock time with the device latency. Order is important.
1456 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1457 clocktime
= V0(device
->Backend
,getClockLatency
)();
1458 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1459 values
[1] = clocktime
.Latency
;
1462 /* If the clock time incremented, reduce the latency by that
1463 * much since it's that much closer to the source offset it got
1466 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1467 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1471 /* 1x float/double */
1472 case AL_CONE_INNER_ANGLE
:
1473 case AL_CONE_OUTER_ANGLE
:
1478 case AL_REFERENCE_DISTANCE
:
1479 case AL_ROLLOFF_FACTOR
:
1480 case AL_CONE_OUTER_GAIN
:
1481 case AL_MAX_DISTANCE
:
1483 case AL_SAMPLE_OFFSET
:
1484 case AL_BYTE_OFFSET
:
1485 case AL_DOPPLER_FACTOR
:
1486 case AL_AIR_ABSORPTION_FACTOR
:
1487 case AL_ROOM_ROLLOFF_FACTOR
:
1488 case AL_CONE_OUTER_GAINHF
:
1489 case AL_SEC_LENGTH_SOFT
:
1490 case AL_SOURCE_RADIUS
:
1491 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1492 *values
= (ALint64
)dvals
[0];
1495 /* 3x float/double */
1499 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1501 values
[0] = (ALint64
)dvals
[0];
1502 values
[1] = (ALint64
)dvals
[1];
1503 values
[2] = (ALint64
)dvals
[2];
1507 /* 6x float/double */
1508 case AL_ORIENTATION
:
1509 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1511 values
[0] = (ALint64
)dvals
[0];
1512 values
[1] = (ALint64
)dvals
[1];
1513 values
[2] = (ALint64
)dvals
[2];
1514 values
[3] = (ALint64
)dvals
[3];
1515 values
[4] = (ALint64
)dvals
[4];
1516 values
[5] = (ALint64
)dvals
[5];
1521 case AL_SOURCE_RELATIVE
:
1523 case AL_SOURCE_STATE
:
1524 case AL_BUFFERS_QUEUED
:
1525 case AL_BUFFERS_PROCESSED
:
1526 case AL_BYTE_LENGTH_SOFT
:
1527 case AL_SAMPLE_LENGTH_SOFT
:
1528 case AL_SOURCE_TYPE
:
1529 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1530 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1531 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1532 case AL_DIRECT_CHANNELS_SOFT
:
1533 case AL_DISTANCE_MODEL
:
1534 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1540 case AL_DIRECT_FILTER
:
1541 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1542 *values
= (ALuint
)ivals
[0];
1546 case AL_AUXILIARY_SEND_FILTER
:
1547 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1549 values
[0] = (ALuint
)ivals
[0];
1550 values
[1] = (ALuint
)ivals
[1];
1551 values
[2] = (ALuint
)ivals
[2];
1555 case AL_SEC_OFFSET_LATENCY_SOFT
:
1556 break; /* Double only */
1557 case AL_STEREO_ANGLES
:
1558 break; /* Float/double only */
1561 ERR("Unexpected property: 0x%04x\n", prop
);
1562 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1566 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1569 ALCcontext
*context
;
1573 context
= GetContextRef();
1574 if(!context
) return;
1577 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1578 device
= context
->Device
;
1579 for(cur
= 0;cur
< n
;cur
++)
1581 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1584 alDeleteSources(cur
, sources
);
1585 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1587 InitSourceParams(source
, device
->NumAuxSends
);
1589 err
= NewThunkEntry(&source
->id
);
1590 if(err
== AL_NO_ERROR
)
1591 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1592 if(err
!= AL_NO_ERROR
)
1594 FreeThunkEntry(source
->id
);
1595 memset(source
, 0, sizeof(ALsource
));
1598 alDeleteSources(cur
, sources
);
1599 SET_ERROR_AND_GOTO(context
, err
, done
);
1602 sources
[cur
] = source
->id
;
1606 ALCcontext_DecRef(context
);
1610 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1613 ALCcontext
*context
;
1617 context
= GetContextRef();
1618 if(!context
) return;
1620 LockSourcesWrite(context
);
1622 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1624 /* Check that all Sources are valid */
1625 for(i
= 0;i
< n
;i
++)
1627 if(LookupSource(context
, sources
[i
]) == NULL
)
1628 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1630 device
= context
->Device
;
1631 for(i
= 0;i
< n
;i
++)
1635 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1637 FreeThunkEntry(Source
->id
);
1639 ALCdevice_Lock(device
);
1640 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1642 voice
->Source
= NULL
;
1643 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1645 ALCdevice_Unlock(device
);
1647 DeinitSource(Source
, device
->NumAuxSends
);
1649 memset(Source
, 0, sizeof(*Source
));
1654 UnlockSourcesWrite(context
);
1655 ALCcontext_DecRef(context
);
1659 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1661 ALCcontext
*context
;
1664 context
= GetContextRef();
1665 if(!context
) return AL_FALSE
;
1667 LockSourcesRead(context
);
1668 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1669 UnlockSourcesRead(context
);
1671 ALCcontext_DecRef(context
);
1677 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1679 ALCcontext
*Context
;
1682 Context
= GetContextRef();
1683 if(!Context
) return;
1685 WriteLock(&Context
->PropLock
);
1686 LockSourcesRead(Context
);
1687 if((Source
=LookupSource(Context
, source
)) == NULL
)
1688 alSetError(Context
, AL_INVALID_NAME
);
1689 else if(!(FloatValsByProp(param
) == 1))
1690 alSetError(Context
, AL_INVALID_ENUM
);
1692 SetSourcefv(Source
, Context
, param
, &value
);
1693 UnlockSourcesRead(Context
);
1694 WriteUnlock(&Context
->PropLock
);
1696 ALCcontext_DecRef(Context
);
1699 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1701 ALCcontext
*Context
;
1704 Context
= GetContextRef();
1705 if(!Context
) return;
1707 WriteLock(&Context
->PropLock
);
1708 LockSourcesRead(Context
);
1709 if((Source
=LookupSource(Context
, source
)) == NULL
)
1710 alSetError(Context
, AL_INVALID_NAME
);
1711 else if(!(FloatValsByProp(param
) == 3))
1712 alSetError(Context
, AL_INVALID_ENUM
);
1715 ALfloat fvals
[3] = { value1
, value2
, value3
};
1716 SetSourcefv(Source
, Context
, param
, fvals
);
1718 UnlockSourcesRead(Context
);
1719 WriteUnlock(&Context
->PropLock
);
1721 ALCcontext_DecRef(Context
);
1724 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1726 ALCcontext
*Context
;
1729 Context
= GetContextRef();
1730 if(!Context
) return;
1732 WriteLock(&Context
->PropLock
);
1733 LockSourcesRead(Context
);
1734 if((Source
=LookupSource(Context
, source
)) == NULL
)
1735 alSetError(Context
, AL_INVALID_NAME
);
1737 alSetError(Context
, AL_INVALID_VALUE
);
1738 else if(!(FloatValsByProp(param
) > 0))
1739 alSetError(Context
, AL_INVALID_ENUM
);
1741 SetSourcefv(Source
, Context
, param
, values
);
1742 UnlockSourcesRead(Context
);
1743 WriteUnlock(&Context
->PropLock
);
1745 ALCcontext_DecRef(Context
);
1749 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1751 ALCcontext
*Context
;
1754 Context
= GetContextRef();
1755 if(!Context
) return;
1757 WriteLock(&Context
->PropLock
);
1758 LockSourcesRead(Context
);
1759 if((Source
=LookupSource(Context
, source
)) == NULL
)
1760 alSetError(Context
, AL_INVALID_NAME
);
1761 else if(!(DoubleValsByProp(param
) == 1))
1762 alSetError(Context
, AL_INVALID_ENUM
);
1765 ALfloat fval
= (ALfloat
)value
;
1766 SetSourcefv(Source
, Context
, param
, &fval
);
1768 UnlockSourcesRead(Context
);
1769 WriteUnlock(&Context
->PropLock
);
1771 ALCcontext_DecRef(Context
);
1774 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1776 ALCcontext
*Context
;
1779 Context
= GetContextRef();
1780 if(!Context
) return;
1782 WriteLock(&Context
->PropLock
);
1783 LockSourcesRead(Context
);
1784 if((Source
=LookupSource(Context
, source
)) == NULL
)
1785 alSetError(Context
, AL_INVALID_NAME
);
1786 else if(!(DoubleValsByProp(param
) == 3))
1787 alSetError(Context
, AL_INVALID_ENUM
);
1790 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1791 SetSourcefv(Source
, Context
, param
, fvals
);
1793 UnlockSourcesRead(Context
);
1794 WriteUnlock(&Context
->PropLock
);
1796 ALCcontext_DecRef(Context
);
1799 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1801 ALCcontext
*Context
;
1805 Context
= GetContextRef();
1806 if(!Context
) return;
1808 WriteLock(&Context
->PropLock
);
1809 LockSourcesRead(Context
);
1810 if((Source
=LookupSource(Context
, source
)) == NULL
)
1811 alSetError(Context
, AL_INVALID_NAME
);
1813 alSetError(Context
, AL_INVALID_VALUE
);
1814 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1815 alSetError(Context
, AL_INVALID_ENUM
);
1821 for(i
= 0;i
< count
;i
++)
1822 fvals
[i
] = (ALfloat
)values
[i
];
1823 SetSourcefv(Source
, Context
, param
, fvals
);
1825 UnlockSourcesRead(Context
);
1826 WriteUnlock(&Context
->PropLock
);
1828 ALCcontext_DecRef(Context
);
1832 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1834 ALCcontext
*Context
;
1837 Context
= GetContextRef();
1838 if(!Context
) return;
1840 WriteLock(&Context
->PropLock
);
1841 LockSourcesRead(Context
);
1842 if((Source
=LookupSource(Context
, source
)) == NULL
)
1843 alSetError(Context
, AL_INVALID_NAME
);
1844 else if(!(IntValsByProp(param
) == 1))
1845 alSetError(Context
, AL_INVALID_ENUM
);
1847 SetSourceiv(Source
, Context
, param
, &value
);
1848 UnlockSourcesRead(Context
);
1849 WriteUnlock(&Context
->PropLock
);
1851 ALCcontext_DecRef(Context
);
1854 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1856 ALCcontext
*Context
;
1859 Context
= GetContextRef();
1860 if(!Context
) return;
1862 WriteLock(&Context
->PropLock
);
1863 LockSourcesRead(Context
);
1864 if((Source
=LookupSource(Context
, source
)) == NULL
)
1865 alSetError(Context
, AL_INVALID_NAME
);
1866 else if(!(IntValsByProp(param
) == 3))
1867 alSetError(Context
, AL_INVALID_ENUM
);
1870 ALint ivals
[3] = { value1
, value2
, value3
};
1871 SetSourceiv(Source
, Context
, param
, ivals
);
1873 UnlockSourcesRead(Context
);
1874 WriteUnlock(&Context
->PropLock
);
1876 ALCcontext_DecRef(Context
);
1879 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1881 ALCcontext
*Context
;
1884 Context
= GetContextRef();
1885 if(!Context
) return;
1887 WriteLock(&Context
->PropLock
);
1888 LockSourcesRead(Context
);
1889 if((Source
=LookupSource(Context
, source
)) == NULL
)
1890 alSetError(Context
, AL_INVALID_NAME
);
1892 alSetError(Context
, AL_INVALID_VALUE
);
1893 else if(!(IntValsByProp(param
) > 0))
1894 alSetError(Context
, AL_INVALID_ENUM
);
1896 SetSourceiv(Source
, Context
, param
, values
);
1897 UnlockSourcesRead(Context
);
1898 WriteUnlock(&Context
->PropLock
);
1900 ALCcontext_DecRef(Context
);
1904 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1906 ALCcontext
*Context
;
1909 Context
= GetContextRef();
1910 if(!Context
) return;
1912 WriteLock(&Context
->PropLock
);
1913 LockSourcesRead(Context
);
1914 if((Source
=LookupSource(Context
, source
)) == NULL
)
1915 alSetError(Context
, AL_INVALID_NAME
);
1916 else if(!(Int64ValsByProp(param
) == 1))
1917 alSetError(Context
, AL_INVALID_ENUM
);
1919 SetSourcei64v(Source
, Context
, param
, &value
);
1920 UnlockSourcesRead(Context
);
1921 WriteUnlock(&Context
->PropLock
);
1923 ALCcontext_DecRef(Context
);
1926 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1928 ALCcontext
*Context
;
1931 Context
= GetContextRef();
1932 if(!Context
) return;
1934 WriteLock(&Context
->PropLock
);
1935 LockSourcesRead(Context
);
1936 if((Source
=LookupSource(Context
, source
)) == NULL
)
1937 alSetError(Context
, AL_INVALID_NAME
);
1938 else if(!(Int64ValsByProp(param
) == 3))
1939 alSetError(Context
, AL_INVALID_ENUM
);
1942 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1943 SetSourcei64v(Source
, Context
, param
, i64vals
);
1945 UnlockSourcesRead(Context
);
1946 WriteUnlock(&Context
->PropLock
);
1948 ALCcontext_DecRef(Context
);
1951 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1953 ALCcontext
*Context
;
1956 Context
= GetContextRef();
1957 if(!Context
) return;
1959 WriteLock(&Context
->PropLock
);
1960 LockSourcesRead(Context
);
1961 if((Source
=LookupSource(Context
, source
)) == NULL
)
1962 alSetError(Context
, AL_INVALID_NAME
);
1964 alSetError(Context
, AL_INVALID_VALUE
);
1965 else if(!(Int64ValsByProp(param
) > 0))
1966 alSetError(Context
, AL_INVALID_ENUM
);
1968 SetSourcei64v(Source
, Context
, param
, values
);
1969 UnlockSourcesRead(Context
);
1970 WriteUnlock(&Context
->PropLock
);
1972 ALCcontext_DecRef(Context
);
1976 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1978 ALCcontext
*Context
;
1981 Context
= GetContextRef();
1982 if(!Context
) return;
1984 ReadLock(&Context
->PropLock
);
1985 LockSourcesRead(Context
);
1986 if((Source
=LookupSource(Context
, source
)) == NULL
)
1987 alSetError(Context
, AL_INVALID_NAME
);
1989 alSetError(Context
, AL_INVALID_VALUE
);
1990 else if(!(FloatValsByProp(param
) == 1))
1991 alSetError(Context
, AL_INVALID_ENUM
);
1995 if(GetSourcedv(Source
, Context
, param
, &dval
))
1996 *value
= (ALfloat
)dval
;
1998 UnlockSourcesRead(Context
);
1999 ReadUnlock(&Context
->PropLock
);
2001 ALCcontext_DecRef(Context
);
2005 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2007 ALCcontext
*Context
;
2010 Context
= GetContextRef();
2011 if(!Context
) return;
2013 ReadLock(&Context
->PropLock
);
2014 LockSourcesRead(Context
);
2015 if((Source
=LookupSource(Context
, source
)) == NULL
)
2016 alSetError(Context
, AL_INVALID_NAME
);
2017 else if(!(value1
&& value2
&& value3
))
2018 alSetError(Context
, AL_INVALID_VALUE
);
2019 else if(!(FloatValsByProp(param
) == 3))
2020 alSetError(Context
, AL_INVALID_ENUM
);
2024 if(GetSourcedv(Source
, Context
, param
, dvals
))
2026 *value1
= (ALfloat
)dvals
[0];
2027 *value2
= (ALfloat
)dvals
[1];
2028 *value3
= (ALfloat
)dvals
[2];
2031 UnlockSourcesRead(Context
);
2032 ReadUnlock(&Context
->PropLock
);
2034 ALCcontext_DecRef(Context
);
2038 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2040 ALCcontext
*Context
;
2044 Context
= GetContextRef();
2045 if(!Context
) return;
2047 ReadLock(&Context
->PropLock
);
2048 LockSourcesRead(Context
);
2049 if((Source
=LookupSource(Context
, source
)) == NULL
)
2050 alSetError(Context
, AL_INVALID_NAME
);
2052 alSetError(Context
, AL_INVALID_VALUE
);
2053 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2054 alSetError(Context
, AL_INVALID_ENUM
);
2058 if(GetSourcedv(Source
, Context
, param
, dvals
))
2061 for(i
= 0;i
< count
;i
++)
2062 values
[i
] = (ALfloat
)dvals
[i
];
2065 UnlockSourcesRead(Context
);
2066 ReadUnlock(&Context
->PropLock
);
2068 ALCcontext_DecRef(Context
);
2072 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2074 ALCcontext
*Context
;
2077 Context
= GetContextRef();
2078 if(!Context
) return;
2080 ReadLock(&Context
->PropLock
);
2081 LockSourcesRead(Context
);
2082 if((Source
=LookupSource(Context
, source
)) == NULL
)
2083 alSetError(Context
, AL_INVALID_NAME
);
2085 alSetError(Context
, AL_INVALID_VALUE
);
2086 else if(!(DoubleValsByProp(param
) == 1))
2087 alSetError(Context
, AL_INVALID_ENUM
);
2089 GetSourcedv(Source
, Context
, param
, value
);
2090 UnlockSourcesRead(Context
);
2091 ReadUnlock(&Context
->PropLock
);
2093 ALCcontext_DecRef(Context
);
2096 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2098 ALCcontext
*Context
;
2101 Context
= GetContextRef();
2102 if(!Context
) return;
2104 ReadLock(&Context
->PropLock
);
2105 LockSourcesRead(Context
);
2106 if((Source
=LookupSource(Context
, source
)) == NULL
)
2107 alSetError(Context
, AL_INVALID_NAME
);
2108 else if(!(value1
&& value2
&& value3
))
2109 alSetError(Context
, AL_INVALID_VALUE
);
2110 else if(!(DoubleValsByProp(param
) == 3))
2111 alSetError(Context
, AL_INVALID_ENUM
);
2115 if(GetSourcedv(Source
, Context
, param
, dvals
))
2122 UnlockSourcesRead(Context
);
2123 ReadUnlock(&Context
->PropLock
);
2125 ALCcontext_DecRef(Context
);
2128 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2130 ALCcontext
*Context
;
2133 Context
= GetContextRef();
2134 if(!Context
) return;
2136 ReadLock(&Context
->PropLock
);
2137 LockSourcesRead(Context
);
2138 if((Source
=LookupSource(Context
, source
)) == NULL
)
2139 alSetError(Context
, AL_INVALID_NAME
);
2141 alSetError(Context
, AL_INVALID_VALUE
);
2142 else if(!(DoubleValsByProp(param
) > 0))
2143 alSetError(Context
, AL_INVALID_ENUM
);
2145 GetSourcedv(Source
, Context
, param
, values
);
2146 UnlockSourcesRead(Context
);
2147 ReadUnlock(&Context
->PropLock
);
2149 ALCcontext_DecRef(Context
);
2153 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2155 ALCcontext
*Context
;
2158 Context
= GetContextRef();
2159 if(!Context
) return;
2161 ReadLock(&Context
->PropLock
);
2162 LockSourcesRead(Context
);
2163 if((Source
=LookupSource(Context
, source
)) == NULL
)
2164 alSetError(Context
, AL_INVALID_NAME
);
2166 alSetError(Context
, AL_INVALID_VALUE
);
2167 else if(!(IntValsByProp(param
) == 1))
2168 alSetError(Context
, AL_INVALID_ENUM
);
2170 GetSourceiv(Source
, Context
, param
, value
);
2171 UnlockSourcesRead(Context
);
2172 ReadUnlock(&Context
->PropLock
);
2174 ALCcontext_DecRef(Context
);
2178 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2180 ALCcontext
*Context
;
2183 Context
= GetContextRef();
2184 if(!Context
) return;
2186 ReadLock(&Context
->PropLock
);
2187 LockSourcesRead(Context
);
2188 if((Source
=LookupSource(Context
, source
)) == NULL
)
2189 alSetError(Context
, AL_INVALID_NAME
);
2190 else if(!(value1
&& value2
&& value3
))
2191 alSetError(Context
, AL_INVALID_VALUE
);
2192 else if(!(IntValsByProp(param
) == 3))
2193 alSetError(Context
, AL_INVALID_ENUM
);
2197 if(GetSourceiv(Source
, Context
, param
, ivals
))
2204 UnlockSourcesRead(Context
);
2205 ReadUnlock(&Context
->PropLock
);
2207 ALCcontext_DecRef(Context
);
2211 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2213 ALCcontext
*Context
;
2216 Context
= GetContextRef();
2217 if(!Context
) return;
2219 ReadLock(&Context
->PropLock
);
2220 LockSourcesRead(Context
);
2221 if((Source
=LookupSource(Context
, source
)) == NULL
)
2222 alSetError(Context
, AL_INVALID_NAME
);
2224 alSetError(Context
, AL_INVALID_VALUE
);
2225 else if(!(IntValsByProp(param
) > 0))
2226 alSetError(Context
, AL_INVALID_ENUM
);
2228 GetSourceiv(Source
, Context
, param
, values
);
2229 UnlockSourcesRead(Context
);
2230 ReadUnlock(&Context
->PropLock
);
2232 ALCcontext_DecRef(Context
);
2236 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2238 ALCcontext
*Context
;
2241 Context
= GetContextRef();
2242 if(!Context
) return;
2244 ReadLock(&Context
->PropLock
);
2245 LockSourcesRead(Context
);
2246 if((Source
=LookupSource(Context
, source
)) == NULL
)
2247 alSetError(Context
, AL_INVALID_NAME
);
2249 alSetError(Context
, AL_INVALID_VALUE
);
2250 else if(!(Int64ValsByProp(param
) == 1))
2251 alSetError(Context
, AL_INVALID_ENUM
);
2253 GetSourcei64v(Source
, Context
, param
, value
);
2254 UnlockSourcesRead(Context
);
2255 ReadUnlock(&Context
->PropLock
);
2257 ALCcontext_DecRef(Context
);
2260 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2262 ALCcontext
*Context
;
2265 Context
= GetContextRef();
2266 if(!Context
) return;
2268 ReadLock(&Context
->PropLock
);
2269 LockSourcesRead(Context
);
2270 if((Source
=LookupSource(Context
, source
)) == NULL
)
2271 alSetError(Context
, AL_INVALID_NAME
);
2272 else if(!(value1
&& value2
&& value3
))
2273 alSetError(Context
, AL_INVALID_VALUE
);
2274 else if(!(Int64ValsByProp(param
) == 3))
2275 alSetError(Context
, AL_INVALID_ENUM
);
2279 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2281 *value1
= i64vals
[0];
2282 *value2
= i64vals
[1];
2283 *value3
= i64vals
[2];
2286 UnlockSourcesRead(Context
);
2287 ReadUnlock(&Context
->PropLock
);
2289 ALCcontext_DecRef(Context
);
2292 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2294 ALCcontext
*Context
;
2297 Context
= GetContextRef();
2298 if(!Context
) return;
2300 ReadLock(&Context
->PropLock
);
2301 LockSourcesRead(Context
);
2302 if((Source
=LookupSource(Context
, source
)) == NULL
)
2303 alSetError(Context
, AL_INVALID_NAME
);
2305 alSetError(Context
, AL_INVALID_VALUE
);
2306 else if(!(Int64ValsByProp(param
) > 0))
2307 alSetError(Context
, AL_INVALID_ENUM
);
2309 GetSourcei64v(Source
, Context
, param
, values
);
2310 UnlockSourcesRead(Context
);
2311 ReadUnlock(&Context
->PropLock
);
2313 ALCcontext_DecRef(Context
);
2317 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2319 alSourcePlayv(1, &source
);
2321 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2323 ALCcontext
*context
;
2327 context
= GetContextRef();
2328 if(!context
) return;
2330 LockSourcesRead(context
);
2332 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2333 for(i
= 0;i
< n
;i
++)
2335 if(!LookupSource(context
, sources
[i
]))
2336 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2339 ALCdevice_Lock(context
->Device
);
2340 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2342 ALsizei newcount
= context
->MaxVoices
<< 1;
2343 if(context
->MaxVoices
>= newcount
)
2345 ALCdevice_Unlock(context
->Device
);
2346 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2348 AllocateVoices(context
, newcount
, context
->Device
->NumAuxSends
);
2351 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) == DeferAll
)
2353 for(i
= 0;i
< n
;i
++)
2355 source
= LookupSource(context
, sources
[i
]);
2356 source
->new_state
= AL_PLAYING
;
2361 for(i
= 0;i
< n
;i
++)
2363 source
= LookupSource(context
, sources
[i
]);
2364 SetSourceState(source
, context
, AL_PLAYING
);
2367 ALCdevice_Unlock(context
->Device
);
2370 UnlockSourcesRead(context
);
2371 ALCcontext_DecRef(context
);
2374 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2376 alSourcePausev(1, &source
);
2378 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2380 ALCcontext
*context
;
2384 context
= GetContextRef();
2385 if(!context
) return;
2387 LockSourcesRead(context
);
2389 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2390 for(i
= 0;i
< n
;i
++)
2392 if(!LookupSource(context
, sources
[i
]))
2393 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2396 ALCdevice_Lock(context
->Device
);
2397 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2399 for(i
= 0;i
< n
;i
++)
2401 source
= LookupSource(context
, sources
[i
]);
2402 source
->new_state
= AL_PAUSED
;
2407 for(i
= 0;i
< n
;i
++)
2409 source
= LookupSource(context
, sources
[i
]);
2410 SetSourceState(source
, context
, AL_PAUSED
);
2413 ALCdevice_Unlock(context
->Device
);
2416 UnlockSourcesRead(context
);
2417 ALCcontext_DecRef(context
);
2420 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2422 alSourceStopv(1, &source
);
2424 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2426 ALCcontext
*context
;
2430 context
= GetContextRef();
2431 if(!context
) return;
2433 LockSourcesRead(context
);
2435 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2436 for(i
= 0;i
< n
;i
++)
2438 if(!LookupSource(context
, sources
[i
]))
2439 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2442 ALCdevice_Lock(context
->Device
);
2443 for(i
= 0;i
< n
;i
++)
2445 source
= LookupSource(context
, sources
[i
]);
2446 source
->new_state
= AL_NONE
;
2447 SetSourceState(source
, context
, AL_STOPPED
);
2449 ALCdevice_Unlock(context
->Device
);
2452 UnlockSourcesRead(context
);
2453 ALCcontext_DecRef(context
);
2456 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2458 alSourceRewindv(1, &source
);
2460 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2462 ALCcontext
*context
;
2466 context
= GetContextRef();
2467 if(!context
) return;
2469 LockSourcesRead(context
);
2471 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2472 for(i
= 0;i
< n
;i
++)
2474 if(!LookupSource(context
, sources
[i
]))
2475 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2478 ALCdevice_Lock(context
->Device
);
2479 for(i
= 0;i
< n
;i
++)
2481 source
= LookupSource(context
, sources
[i
]);
2482 source
->new_state
= AL_NONE
;
2483 SetSourceState(source
, context
, AL_INITIAL
);
2485 ALCdevice_Unlock(context
->Device
);
2488 UnlockSourcesRead(context
);
2489 ALCcontext_DecRef(context
);
2493 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2496 ALCcontext
*context
;
2499 ALbufferlistitem
*BufferListStart
;
2500 ALbufferlistitem
*BufferList
;
2501 ALbuffer
*BufferFmt
= NULL
;
2506 context
= GetContextRef();
2507 if(!context
) return;
2509 device
= context
->Device
;
2511 LockSourcesRead(context
);
2513 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2514 if((source
=LookupSource(context
, src
)) == NULL
)
2515 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2517 WriteLock(&source
->queue_lock
);
2518 if(source
->SourceType
== AL_STATIC
)
2520 WriteUnlock(&source
->queue_lock
);
2521 /* Can't queue on a Static Source */
2522 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2525 /* Check for a valid Buffer, for its frequency and format */
2526 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2529 if(BufferList
->buffer
)
2531 BufferFmt
= BufferList
->buffer
;
2534 BufferList
= BufferList
->next
;
2537 LockBuffersRead(device
);
2538 BufferListStart
= NULL
;
2540 for(i
= 0;i
< nb
;i
++)
2542 ALbuffer
*buffer
= NULL
;
2543 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2545 WriteUnlock(&source
->queue_lock
);
2546 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2549 if(!BufferListStart
)
2551 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2552 BufferList
= BufferListStart
;
2556 BufferList
->next
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2557 BufferList
= BufferList
->next
;
2559 BufferList
->buffer
= buffer
;
2560 BufferList
->next
= NULL
;
2561 if(!buffer
) continue;
2563 /* Hold a read lock on each buffer being queued while checking all
2564 * provided buffers. This is done so other threads don't see an extra
2565 * reference on some buffers if this operation ends up failing. */
2566 ReadLock(&buffer
->lock
);
2567 IncrementRef(&buffer
->ref
);
2569 if(BufferFmt
== NULL
)
2573 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2574 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2576 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2577 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2578 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2580 WriteUnlock(&source
->queue_lock
);
2581 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2584 /* A buffer failed (invalid ID or format), so unlock and release
2585 * each buffer we had. */
2586 while(BufferListStart
)
2588 ALbufferlistitem
*next
= BufferListStart
->next
;
2589 if((buffer
=BufferListStart
->buffer
) != NULL
)
2591 DecrementRef(&buffer
->ref
);
2592 ReadUnlock(&buffer
->lock
);
2594 al_free(BufferListStart
);
2595 BufferListStart
= next
;
2597 UnlockBuffersRead(device
);
2601 /* All buffers good, unlock them now. */
2602 BufferList
= BufferListStart
;
2603 while(BufferList
!= NULL
)
2605 ALbuffer
*buffer
= BufferList
->buffer
;
2606 if(buffer
) ReadUnlock(&buffer
->lock
);
2607 BufferList
= BufferList
->next
;
2609 UnlockBuffersRead(device
);
2611 /* Source is now streaming */
2612 source
->SourceType
= AL_STREAMING
;
2615 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->queue
,
2616 &BufferList
, BufferListStart
))
2618 /* Queue head is not NULL, append to the end of the queue */
2619 while(BufferList
->next
!= NULL
)
2620 BufferList
= BufferList
->next
;
2621 BufferList
->next
= BufferListStart
;
2623 WriteUnlock(&source
->queue_lock
);
2626 UnlockSourcesRead(context
);
2627 ALCcontext_DecRef(context
);
2630 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2632 ALCcontext
*context
;
2634 ALbufferlistitem
*OldHead
;
2635 ALbufferlistitem
*OldTail
;
2636 ALbufferlistitem
*Current
;
2640 context
= GetContextRef();
2641 if(!context
) return;
2643 LockSourcesRead(context
);
2645 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2647 if((source
=LookupSource(context
, src
)) == NULL
)
2648 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2650 /* Nothing to unqueue. */
2651 if(nb
== 0) goto done
;
2653 WriteLock(&source
->queue_lock
);
2654 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2656 WriteUnlock(&source
->queue_lock
);
2657 /* Trying to unqueue buffers on a looping or non-streaming source. */
2658 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2661 /* Find the new buffer queue head */
2662 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2664 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2665 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2666 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2668 if(OldTail
!= Current
)
2670 for(i
= 1;i
< nb
;i
++)
2672 ALbufferlistitem
*next
= OldTail
->next
;
2673 if(!next
|| next
== Current
) break;
2679 WriteUnlock(&source
->queue_lock
);
2680 /* Trying to unqueue pending buffers. */
2681 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2684 /* Swap it, and cut the new head from the old. */
2685 OldHead
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2688 ALCdevice
*device
= context
->Device
;
2691 /* Once the active mix (if any) is done, it's safe to cut the old tail
2692 * from the new head.
2694 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2696 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2699 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2700 OldTail
->next
= NULL
;
2702 WriteUnlock(&source
->queue_lock
);
2704 while(OldHead
!= NULL
)
2706 ALbufferlistitem
*next
= OldHead
->next
;
2707 ALbuffer
*buffer
= OldHead
->buffer
;
2713 *(buffers
++) = buffer
->id
;
2714 DecrementRef(&buffer
->ref
);
2722 UnlockSourcesRead(context
);
2723 ALCcontext_DecRef(context
);
2727 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2731 RWLockInit(&Source
->queue_lock
);
2733 Source
->InnerAngle
= 360.0f
;
2734 Source
->OuterAngle
= 360.0f
;
2735 Source
->Pitch
= 1.0f
;
2736 Source
->Position
[0] = 0.0f
;
2737 Source
->Position
[1] = 0.0f
;
2738 Source
->Position
[2] = 0.0f
;
2739 Source
->Velocity
[0] = 0.0f
;
2740 Source
->Velocity
[1] = 0.0f
;
2741 Source
->Velocity
[2] = 0.0f
;
2742 Source
->Direction
[0] = 0.0f
;
2743 Source
->Direction
[1] = 0.0f
;
2744 Source
->Direction
[2] = 0.0f
;
2745 Source
->Orientation
[0][0] = 0.0f
;
2746 Source
->Orientation
[0][1] = 0.0f
;
2747 Source
->Orientation
[0][2] = -1.0f
;
2748 Source
->Orientation
[1][0] = 0.0f
;
2749 Source
->Orientation
[1][1] = 1.0f
;
2750 Source
->Orientation
[1][2] = 0.0f
;
2751 Source
->RefDistance
= 1.0f
;
2752 Source
->MaxDistance
= FLT_MAX
;
2753 Source
->RollOffFactor
= 1.0f
;
2754 Source
->Gain
= 1.0f
;
2755 Source
->MinGain
= 0.0f
;
2756 Source
->MaxGain
= 1.0f
;
2757 Source
->OuterGain
= 0.0f
;
2758 Source
->OuterGainHF
= 1.0f
;
2760 Source
->DryGainHFAuto
= AL_TRUE
;
2761 Source
->WetGainAuto
= AL_TRUE
;
2762 Source
->WetGainHFAuto
= AL_TRUE
;
2763 Source
->AirAbsorptionFactor
= 0.0f
;
2764 Source
->RoomRolloffFactor
= 0.0f
;
2765 Source
->DopplerFactor
= 1.0f
;
2766 Source
->DirectChannels
= AL_FALSE
;
2768 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2769 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2771 Source
->Radius
= 0.0f
;
2773 Source
->DistanceModel
= DefaultDistanceModel
;
2775 Source
->Direct
.Gain
= 1.0f
;
2776 Source
->Direct
.GainHF
= 1.0f
;
2777 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2778 Source
->Direct
.GainLF
= 1.0f
;
2779 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2780 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2781 for(i
= 0;i
< num_sends
;i
++)
2783 Source
->Send
[i
].Slot
= NULL
;
2784 Source
->Send
[i
].Gain
= 1.0f
;
2785 Source
->Send
[i
].GainHF
= 1.0f
;
2786 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2787 Source
->Send
[i
].GainLF
= 1.0f
;
2788 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2791 Source
->Offset
= 0.0;
2792 Source
->OffsetType
= AL_NONE
;
2793 Source
->SourceType
= AL_UNDETERMINED
;
2794 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2795 Source
->new_state
= AL_NONE
;
2797 ATOMIC_INIT(&Source
->queue
, NULL
);
2799 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2801 Source
->NeedsUpdate
= AL_TRUE
;
2803 ATOMIC_INIT(&Source
->Update
, NULL
);
2804 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2807 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2809 ALbufferlistitem
*BufferList
;
2810 struct ALsourceProps
*props
;
2814 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2815 if(props
) al_free(props
);
2817 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2820 struct ALsourceProps
*next
;
2821 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2826 /* This is excessively spammy if it traces every source destruction, so
2827 * just warn if it was unexpectedly large.
2830 WARN("Freed "SZFMT
" Source property objects\n", count
);
2832 BufferList
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, NULL
);
2833 while(BufferList
!= NULL
)
2835 ALbufferlistitem
*next
= BufferList
->next
;
2836 if(BufferList
->buffer
!= NULL
)
2837 DecrementRef(&BufferList
->buffer
->ref
);
2838 al_free(BufferList
);
2844 for(i
= 0;i
< num_sends
;i
++)
2846 if(source
->Send
[i
].Slot
)
2847 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2848 source
->Send
[i
].Slot
= NULL
;
2850 al_free(source
->Send
);
2851 source
->Send
= NULL
;
2855 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
)
2857 struct ALsourceProps
*props
;
2860 /* Get an unused property container, or allocate a new one as needed. */
2861 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2863 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
2866 struct ALsourceProps
*next
;
2868 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2869 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2870 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
2871 almemory_order_acquire
) == 0);
2874 /* Copy in current property values. */
2875 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2876 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2877 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2878 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2879 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2880 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2881 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2882 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2883 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2884 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2885 for(i
= 0;i
< 3;i
++)
2886 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2887 for(i
= 0;i
< 3;i
++)
2888 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2889 for(i
= 0;i
< 3;i
++)
2890 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2891 for(i
= 0;i
< 2;i
++)
2894 for(j
= 0;j
< 3;j
++)
2895 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2896 almemory_order_relaxed
);
2898 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2899 ATOMIC_STORE(&props
->DistanceModel
, source
->DistanceModel
, almemory_order_relaxed
);
2900 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2902 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2903 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2904 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2905 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2907 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2908 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2909 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2911 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2912 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2914 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2916 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2917 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2918 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2919 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2920 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2922 for(i
= 0;i
< num_sends
;i
++)
2924 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2925 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2926 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2927 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2928 almemory_order_relaxed
);
2929 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2930 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2931 almemory_order_relaxed
);
2934 /* Set the new container for updating internal parameters. */
2935 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2938 /* If there was an unused update container, put it back in the
2941 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
2945 void UpdateAllSourceProps(ALCcontext
*context
)
2947 ALsizei num_sends
= context
->Device
->NumAuxSends
;
2950 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
2952 ALvoice
*voice
= context
->Voices
[pos
];
2953 ALsource
*source
= voice
->Source
;
2954 if(source
!= NULL
&& source
->NeedsUpdate
&& IsPlayingOrPausedSeq(source
))
2956 source
->NeedsUpdate
= AL_FALSE
;
2957 UpdateSourceProps(source
, num_sends
);
2965 * Sets the source's new play state given its current state.
2967 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2969 ALCdevice
*device
= Context
->Device
;
2973 WriteLock(&Source
->queue_lock
);
2974 if(state
== AL_PLAYING
)
2976 ALCdevice
*device
= Context
->Device
;
2977 ALbufferlistitem
*BufferList
;
2980 /* Check that there is a queue containing at least one valid, non zero
2982 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
2986 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2988 BufferList
= BufferList
->next
;
2991 /* If there's nothing to play, or the device is disconnected, go right
2994 if(!BufferList
|| !device
->Connected
)
2997 voice
= GetSourceVoice(Source
, Context
);
2998 switch(ATOMIC_EXCHANGE(ALenum
, &Source
->state
, AL_PLAYING
, almemory_order_acq_rel
))
3001 assert(voice
!= NULL
);
3002 /* A source that's already playing is restarted from the beginning. */
3003 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
3004 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
3005 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
3009 assert(voice
!= NULL
);
3010 /* A source that's paused simply resumes. Make sure it uses the
3011 * volume last specified; there's no reason to fade from where
3014 voice
->Moving
= AL_FALSE
;
3015 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
3022 Source
->NeedsUpdate
= AL_FALSE
;
3023 UpdateSourceProps(Source
, device
->NumAuxSends
);
3025 /* Make sure this source isn't already active, and if not, look for an
3026 * unused voice to put it in.
3028 assert(voice
== NULL
);
3029 for(i
= 0;i
< Context
->VoiceCount
;i
++)
3031 if(Context
->Voices
[i
]->Source
== NULL
)
3033 voice
= Context
->Voices
[i
];
3038 voice
= Context
->Voices
[Context
->VoiceCount
++];
3039 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3040 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3042 /* A source that's not playing or paused has any offset applied when it
3045 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
3046 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
3047 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
3048 if(Source
->OffsetType
!= AL_NONE
)
3049 ApplyOffset(Source
, voice
);
3051 /* Clear previous samples. */
3052 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
3054 /* Clear the stepping value so the mixer knows not to mix this until
3055 * the update gets applied.
3059 voice
->Moving
= AL_FALSE
;
3060 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
3063 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
3064 voice
->Direct
.Params
[i
].Hrtf
.State
.History
[j
] = 0.0f
;
3065 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3067 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][0] = 0.0f
;
3068 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][1] = 0.0f
;
3072 voice
->Source
= Source
;
3073 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
3075 else if(state
== AL_PAUSED
)
3077 ALenum playing
= AL_PLAYING
;
3078 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
3080 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3081 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3084 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum
, &Source
->state
, &playing
, AL_PAUSED
);
3086 else if(state
== AL_STOPPED
)
3089 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
3091 voice
->Source
= NULL
;
3092 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3093 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3096 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3097 ATOMIC_STORE(&Source
->state
, AL_STOPPED
, almemory_order_relaxed
);
3098 Source
->OffsetType
= AL_NONE
;
3099 Source
->Offset
= 0.0;
3101 else if(state
== AL_INITIAL
)
3103 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
3105 voice
->Source
= NULL
;
3106 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3107 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3110 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3111 ATOMIC_STORE(&Source
->state
, AL_INITIAL
, almemory_order_relaxed
);
3112 Source
->OffsetType
= AL_NONE
;
3113 Source
->Offset
= 0.0;
3116 WriteUnlock(&Source
->queue_lock
);
3119 /* GetSourceSampleOffset
3121 * Gets the current read offset for the given Source, in 32.32 fixed-point
3122 * samples. The offset is relative to the start of the queue (not the start of
3123 * the current buffer).
3125 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3127 ALCdevice
*device
= context
->Device
;
3128 const ALbufferlistitem
*BufferList
;
3129 const ALbufferlistitem
*Current
;
3134 ReadLock(&Source
->queue_lock
);
3135 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3139 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3141 *clocktime
= GetDeviceClockTime(device
);
3143 voice
= GetSourceVoice(Source
, context
);
3146 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3148 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3149 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3152 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3153 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3157 while(BufferList
&& BufferList
!= Current
)
3159 if(BufferList
->buffer
)
3160 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3161 BufferList
= BufferList
->next
;
3163 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3166 ReadUnlock(&Source
->queue_lock
);
3167 return (ALint64
)readPos
;
3170 /* GetSourceSecOffset
3172 * Gets the current read offset for the given Source, in seconds. The offset is
3173 * relative to the start of the queue (not the start of the current buffer).
3175 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3177 ALCdevice
*device
= context
->Device
;
3178 const ALbufferlistitem
*BufferList
;
3179 const ALbufferlistitem
*Current
;
3185 ReadLock(&Source
->queue_lock
);
3186 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3190 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3192 *clocktime
= GetDeviceClockTime(device
);
3194 voice
= GetSourceVoice(Source
, context
);
3197 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3199 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3201 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3203 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3204 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3209 const ALbuffer
*Buffer
= NULL
;
3210 while(BufferList
&& BufferList
!= Current
)
3212 const ALbuffer
*buffer
= BufferList
->buffer
;
3215 if(!Buffer
) Buffer
= buffer
;
3216 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3218 BufferList
= BufferList
->next
;
3221 while(BufferList
&& !Buffer
)
3223 Buffer
= BufferList
->buffer
;
3224 BufferList
= BufferList
->next
;
3226 assert(Buffer
!= NULL
);
3228 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3229 (ALdouble
)Buffer
->Frequency
;
3232 ReadUnlock(&Source
->queue_lock
);
3238 * Gets the current read offset for the given Source, in the appropriate format
3239 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3240 * queue (not the start of the current buffer).
3242 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3244 ALCdevice
*device
= context
->Device
;
3245 const ALbufferlistitem
*BufferList
;
3246 const ALbufferlistitem
*Current
;
3247 const ALbuffer
*Buffer
= NULL
;
3248 ALboolean readFin
= AL_FALSE
;
3249 ALuint readPos
, readPosFrac
;
3250 ALuint totalBufferLen
;
3256 ReadLock(&Source
->queue_lock
);
3257 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3258 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3260 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3262 voice
= GetSourceVoice(Source
, context
);
3265 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3267 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3268 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3270 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3271 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3275 ReadUnlock(&Source
->queue_lock
);
3280 while(BufferList
!= NULL
)
3282 const ALbuffer
*buffer
;
3283 readFin
= readFin
|| (BufferList
== Current
);
3284 if((buffer
=BufferList
->buffer
) != NULL
)
3286 if(!Buffer
) Buffer
= buffer
;
3287 totalBufferLen
+= buffer
->SampleLen
;
3288 if(!readFin
) readPos
+= buffer
->SampleLen
;
3290 BufferList
= BufferList
->next
;
3292 assert(Buffer
!= NULL
);
3295 readPos
%= totalBufferLen
;
3298 /* Wrap back to 0 */
3299 if(readPos
>= totalBufferLen
)
3300 readPos
= readPosFrac
= 0;
3307 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3310 case AL_SAMPLE_OFFSET
:
3311 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3314 case AL_BYTE_OFFSET
:
3315 if(Buffer
->OriginalType
== UserFmtIMA4
)
3317 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3318 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3319 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3321 /* Round down to nearest ADPCM block */
3322 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3324 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3326 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3327 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3328 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3330 /* Round down to nearest ADPCM block */
3331 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3335 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3336 offset
= (ALdouble
)(readPos
* FrameSize
);
3341 ReadUnlock(&Source
->queue_lock
);
3348 * Apply the stored playback offset to the Source. This function will update
3349 * the number of buffers "played" given the stored offset.
3351 ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3353 ALbufferlistitem
*BufferList
;
3354 const ALbuffer
*Buffer
;
3355 ALuint bufferLen
, totalBufferLen
;
3356 ALuint offset
=0, frac
=0;
3358 /* Get sample frame offset */
3359 if(!GetSampleOffset(Source
, &offset
, &frac
))
3363 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3364 while(BufferList
&& totalBufferLen
<= offset
)
3366 Buffer
= BufferList
->buffer
;
3367 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3369 if(bufferLen
> offset
-totalBufferLen
)
3371 /* Offset is in this buffer */
3372 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
3373 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3374 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_release
);
3378 totalBufferLen
+= bufferLen
;
3380 BufferList
= BufferList
->next
;
3383 /* Offset is out of range of the queue */
3390 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3391 * or Second offset supplied by the application). This takes into account the
3392 * fact that the buffer format may have been modifed since.
3394 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3396 const ALbuffer
*Buffer
= NULL
;
3397 const ALbufferlistitem
*BufferList
;
3398 ALdouble dbloff
, dblfrac
;
3400 /* Find the first valid Buffer in the Queue */
3401 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3404 if(BufferList
->buffer
)
3406 Buffer
= BufferList
->buffer
;
3409 BufferList
= BufferList
->next
;
3413 Source
->OffsetType
= AL_NONE
;
3414 Source
->Offset
= 0.0;
3418 switch(Source
->OffsetType
)
3420 case AL_BYTE_OFFSET
:
3421 /* Determine the ByteOffset (and ensure it is block aligned) */
3422 *offset
= (ALuint
)Source
->Offset
;
3423 if(Buffer
->OriginalType
== UserFmtIMA4
)
3425 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3426 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3427 *offset
*= Buffer
->OriginalAlign
;
3429 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3431 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3432 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3433 *offset
*= Buffer
->OriginalAlign
;
3436 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3440 case AL_SAMPLE_OFFSET
:
3441 dblfrac
= modf(Source
->Offset
, &dbloff
);
3442 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3443 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3447 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3448 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3449 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3452 Source
->OffsetType
= AL_NONE
;
3453 Source
->Offset
= 0.0;
3461 * Destroys all sources in the source map.
3463 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3465 ALCdevice
*device
= Context
->Device
;
3467 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3469 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3470 Context
->SourceMap
.values
[pos
] = NULL
;
3472 DeinitSource(temp
, device
->NumAuxSends
);
3474 FreeThunkEntry(temp
->id
);
3475 memset(temp
, 0, sizeof(*temp
));