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
);
50 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
51 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
52 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
);
53 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
54 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
56 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
);
57 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
);
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(ATOMIC_LOAD(&(*voice
)->Source
, almemory_order_acquire
) == source
)
143 * Returns if the last known state for the source was playing or paused. Does
144 * not sync with the mixer voice.
146 static inline bool IsPlayingOrPaused(ALsource
*source
)
148 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
149 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
153 * Returns an updated source state using the matching voice's status (or lack
156 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
160 ALenum state
= AL_PLAYING
;
161 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
162 almemory_order_acq_rel
, almemory_order_acquire
))
166 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
170 * Returns if the source should specify an update, given the context's
171 * deferring state and the source's last known state.
173 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
175 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
176 IsPlayingOrPaused(source
);
179 static ALint
FloatValsByProp(ALenum prop
)
181 if(prop
!= (ALenum
)((SourceProp
)prop
))
183 switch((SourceProp
)prop
)
189 case AL_MAX_DISTANCE
:
190 case AL_ROLLOFF_FACTOR
:
191 case AL_DOPPLER_FACTOR
:
192 case AL_CONE_OUTER_GAIN
:
194 case AL_SAMPLE_OFFSET
:
196 case AL_CONE_INNER_ANGLE
:
197 case AL_CONE_OUTER_ANGLE
:
198 case AL_REFERENCE_DISTANCE
:
199 case AL_CONE_OUTER_GAINHF
:
200 case AL_AIR_ABSORPTION_FACTOR
:
201 case AL_ROOM_ROLLOFF_FACTOR
:
202 case AL_DIRECT_FILTER_GAINHF_AUTO
:
203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
205 case AL_DIRECT_CHANNELS_SOFT
:
206 case AL_DISTANCE_MODEL
:
207 case AL_SOURCE_RELATIVE
:
209 case AL_SOURCE_STATE
:
210 case AL_BUFFERS_QUEUED
:
211 case AL_BUFFERS_PROCESSED
:
213 case AL_BYTE_LENGTH_SOFT
:
214 case AL_SAMPLE_LENGTH_SOFT
:
215 case AL_SEC_LENGTH_SOFT
:
216 case AL_SOURCE_RADIUS
:
219 case AL_STEREO_ANGLES
:
230 case AL_SEC_OFFSET_LATENCY_SOFT
:
231 break; /* Double only */
234 case AL_DIRECT_FILTER
:
235 case AL_AUXILIARY_SEND_FILTER
:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
238 break; /* i64 only */
242 static ALint
DoubleValsByProp(ALenum prop
)
244 if(prop
!= (ALenum
)((SourceProp
)prop
))
246 switch((SourceProp
)prop
)
252 case AL_MAX_DISTANCE
:
253 case AL_ROLLOFF_FACTOR
:
254 case AL_DOPPLER_FACTOR
:
255 case AL_CONE_OUTER_GAIN
:
257 case AL_SAMPLE_OFFSET
:
259 case AL_CONE_INNER_ANGLE
:
260 case AL_CONE_OUTER_ANGLE
:
261 case AL_REFERENCE_DISTANCE
:
262 case AL_CONE_OUTER_GAINHF
:
263 case AL_AIR_ABSORPTION_FACTOR
:
264 case AL_ROOM_ROLLOFF_FACTOR
:
265 case AL_DIRECT_FILTER_GAINHF_AUTO
:
266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
268 case AL_DIRECT_CHANNELS_SOFT
:
269 case AL_DISTANCE_MODEL
:
270 case AL_SOURCE_RELATIVE
:
272 case AL_SOURCE_STATE
:
273 case AL_BUFFERS_QUEUED
:
274 case AL_BUFFERS_PROCESSED
:
276 case AL_BYTE_LENGTH_SOFT
:
277 case AL_SAMPLE_LENGTH_SOFT
:
278 case AL_SEC_LENGTH_SOFT
:
279 case AL_SOURCE_RADIUS
:
282 case AL_SEC_OFFSET_LATENCY_SOFT
:
283 case AL_STEREO_ANGLES
:
295 case AL_DIRECT_FILTER
:
296 case AL_AUXILIARY_SEND_FILTER
:
297 break; /* i/i64 only */
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
299 break; /* i64 only */
304 static ALint
IntValsByProp(ALenum prop
)
306 if(prop
!= (ALenum
)((SourceProp
)prop
))
308 switch((SourceProp
)prop
)
314 case AL_MAX_DISTANCE
:
315 case AL_ROLLOFF_FACTOR
:
316 case AL_DOPPLER_FACTOR
:
317 case AL_CONE_OUTER_GAIN
:
319 case AL_SAMPLE_OFFSET
:
321 case AL_CONE_INNER_ANGLE
:
322 case AL_CONE_OUTER_ANGLE
:
323 case AL_REFERENCE_DISTANCE
:
324 case AL_CONE_OUTER_GAINHF
:
325 case AL_AIR_ABSORPTION_FACTOR
:
326 case AL_ROOM_ROLLOFF_FACTOR
:
327 case AL_DIRECT_FILTER_GAINHF_AUTO
:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
330 case AL_DIRECT_CHANNELS_SOFT
:
331 case AL_DISTANCE_MODEL
:
332 case AL_SOURCE_RELATIVE
:
335 case AL_SOURCE_STATE
:
336 case AL_BUFFERS_QUEUED
:
337 case AL_BUFFERS_PROCESSED
:
339 case AL_DIRECT_FILTER
:
340 case AL_BYTE_LENGTH_SOFT
:
341 case AL_SAMPLE_LENGTH_SOFT
:
342 case AL_SEC_LENGTH_SOFT
:
343 case AL_SOURCE_RADIUS
:
349 case AL_AUXILIARY_SEND_FILTER
:
355 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
356 break; /* i64 only */
357 case AL_SEC_OFFSET_LATENCY_SOFT
:
358 break; /* Double only */
359 case AL_STEREO_ANGLES
:
360 break; /* Float/double only */
364 static ALint
Int64ValsByProp(ALenum prop
)
366 if(prop
!= (ALenum
)((SourceProp
)prop
))
368 switch((SourceProp
)prop
)
374 case AL_MAX_DISTANCE
:
375 case AL_ROLLOFF_FACTOR
:
376 case AL_DOPPLER_FACTOR
:
377 case AL_CONE_OUTER_GAIN
:
379 case AL_SAMPLE_OFFSET
:
381 case AL_CONE_INNER_ANGLE
:
382 case AL_CONE_OUTER_ANGLE
:
383 case AL_REFERENCE_DISTANCE
:
384 case AL_CONE_OUTER_GAINHF
:
385 case AL_AIR_ABSORPTION_FACTOR
:
386 case AL_ROOM_ROLLOFF_FACTOR
:
387 case AL_DIRECT_FILTER_GAINHF_AUTO
:
388 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
389 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
390 case AL_DIRECT_CHANNELS_SOFT
:
391 case AL_DISTANCE_MODEL
:
392 case AL_SOURCE_RELATIVE
:
395 case AL_SOURCE_STATE
:
396 case AL_BUFFERS_QUEUED
:
397 case AL_BUFFERS_PROCESSED
:
399 case AL_DIRECT_FILTER
:
400 case AL_BYTE_LENGTH_SOFT
:
401 case AL_SAMPLE_LENGTH_SOFT
:
402 case AL_SEC_LENGTH_SOFT
:
403 case AL_SOURCE_RADIUS
:
406 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
412 case AL_AUXILIARY_SEND_FILTER
:
418 case AL_SEC_OFFSET_LATENCY_SOFT
:
419 break; /* Double only */
420 case AL_STEREO_ANGLES
:
421 break; /* Float/double only */
427 #define CHECKVAL(x) do { \
429 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
432 #define DO_UPDATEPROPS() do { \
434 if(SourceShouldUpdate(Source, Context) && \
435 (voice=GetSourceVoice(Source, Context)) != NULL) \
436 UpdateSourceProps(Source, voice, device->NumAuxSends); \
438 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
441 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
443 ALCdevice
*device
= Context
->Device
;
448 case AL_BYTE_LENGTH_SOFT
:
449 case AL_SAMPLE_LENGTH_SOFT
:
450 case AL_SEC_LENGTH_SOFT
:
451 case AL_SEC_OFFSET_LATENCY_SOFT
:
453 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
456 CHECKVAL(*values
>= 0.0f
);
458 Source
->Pitch
= *values
;
462 case AL_CONE_INNER_ANGLE
:
463 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
465 Source
->InnerAngle
= *values
;
469 case AL_CONE_OUTER_ANGLE
:
470 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
472 Source
->OuterAngle
= *values
;
477 CHECKVAL(*values
>= 0.0f
);
479 Source
->Gain
= *values
;
483 case AL_MAX_DISTANCE
:
484 CHECKVAL(*values
>= 0.0f
);
486 Source
->MaxDistance
= *values
;
490 case AL_ROLLOFF_FACTOR
:
491 CHECKVAL(*values
>= 0.0f
);
493 Source
->RollOffFactor
= *values
;
497 case AL_REFERENCE_DISTANCE
:
498 CHECKVAL(*values
>= 0.0f
);
500 Source
->RefDistance
= *values
;
505 CHECKVAL(*values
>= 0.0f
);
507 Source
->MinGain
= *values
;
512 CHECKVAL(*values
>= 0.0f
);
514 Source
->MaxGain
= *values
;
518 case AL_CONE_OUTER_GAIN
:
519 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
521 Source
->OuterGain
= *values
;
525 case AL_CONE_OUTER_GAINHF
:
526 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
528 Source
->OuterGainHF
= *values
;
532 case AL_AIR_ABSORPTION_FACTOR
:
533 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
535 Source
->AirAbsorptionFactor
= *values
;
539 case AL_ROOM_ROLLOFF_FACTOR
:
540 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
542 Source
->RoomRolloffFactor
= *values
;
546 case AL_DOPPLER_FACTOR
:
547 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
549 Source
->DopplerFactor
= *values
;
554 case AL_SAMPLE_OFFSET
:
556 CHECKVAL(*values
>= 0.0f
);
558 Source
->OffsetType
= prop
;
559 Source
->Offset
= *values
;
561 if(IsPlayingOrPaused(Source
))
565 ALCdevice_Lock(Context
->Device
);
566 /* Double-check that the source is still playing while we have
569 voice
= GetSourceVoice(Source
, Context
);
572 WriteLock(&Source
->queue_lock
);
573 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
575 WriteUnlock(&Source
->queue_lock
);
576 ALCdevice_Unlock(Context
->Device
);
577 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
579 WriteUnlock(&Source
->queue_lock
);
581 ALCdevice_Unlock(Context
->Device
);
585 case AL_SOURCE_RADIUS
:
586 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
588 Source
->Radius
= *values
;
592 case AL_STEREO_ANGLES
:
593 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
595 Source
->StereoPan
[0] = values
[0];
596 Source
->StereoPan
[1] = values
[1];
602 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
604 Source
->Position
[0] = values
[0];
605 Source
->Position
[1] = values
[1];
606 Source
->Position
[2] = values
[2];
611 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
613 Source
->Velocity
[0] = values
[0];
614 Source
->Velocity
[1] = values
[1];
615 Source
->Velocity
[2] = values
[2];
620 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
622 Source
->Direction
[0] = values
[0];
623 Source
->Direction
[1] = values
[1];
624 Source
->Direction
[2] = values
[2];
629 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
630 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
632 Source
->Orientation
[0][0] = values
[0];
633 Source
->Orientation
[0][1] = values
[1];
634 Source
->Orientation
[0][2] = values
[2];
635 Source
->Orientation
[1][0] = values
[3];
636 Source
->Orientation
[1][1] = values
[4];
637 Source
->Orientation
[1][2] = values
[5];
642 case AL_SOURCE_RELATIVE
:
644 case AL_SOURCE_STATE
:
646 case AL_DISTANCE_MODEL
:
647 case AL_DIRECT_FILTER_GAINHF_AUTO
:
648 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
649 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
650 case AL_DIRECT_CHANNELS_SOFT
:
651 ival
= (ALint
)values
[0];
652 return SetSourceiv(Source
, Context
, prop
, &ival
);
654 case AL_BUFFERS_QUEUED
:
655 case AL_BUFFERS_PROCESSED
:
656 ival
= (ALint
)((ALuint
)values
[0]);
657 return SetSourceiv(Source
, Context
, prop
, &ival
);
660 case AL_DIRECT_FILTER
:
661 case AL_AUXILIARY_SEND_FILTER
:
662 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
666 ERR("Unexpected property: 0x%04x\n", prop
);
667 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
670 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
672 ALCdevice
*device
= Context
->Device
;
673 ALbuffer
*buffer
= NULL
;
674 ALfilter
*filter
= NULL
;
675 ALeffectslot
*slot
= NULL
;
676 ALbufferlistitem
*oldlist
;
681 case AL_SOURCE_STATE
:
683 case AL_BUFFERS_QUEUED
:
684 case AL_BUFFERS_PROCESSED
:
685 case AL_BYTE_LENGTH_SOFT
:
686 case AL_SAMPLE_LENGTH_SOFT
:
687 case AL_SEC_LENGTH_SOFT
:
689 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
691 case AL_SOURCE_RELATIVE
:
692 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
694 Source
->HeadRelative
= (ALboolean
)*values
;
699 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
701 WriteLock(&Source
->queue_lock
);
702 Source
->Looping
= (ALboolean
)*values
;
703 if(IsPlayingOrPaused(Source
))
705 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
709 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
711 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
713 /* If the source is playing, wait for the current mix to finish
714 * to ensure it isn't currently looping back or reaching the
717 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
721 WriteUnlock(&Source
->queue_lock
);
725 LockBuffersRead(device
);
726 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
728 UnlockBuffersRead(device
);
729 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
732 WriteLock(&Source
->queue_lock
);
734 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
735 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
737 WriteUnlock(&Source
->queue_lock
);
738 UnlockBuffersRead(device
);
739 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
743 oldlist
= Source
->queue
;
746 /* Add the selected buffer to a one-item queue */
747 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
748 newlist
->buffer
= buffer
;
749 newlist
->next
= NULL
;
750 IncrementRef(&buffer
->ref
);
752 /* Source is now Static */
753 Source
->SourceType
= AL_STATIC
;
754 Source
->queue
= newlist
;
758 /* Source is now Undetermined */
759 Source
->SourceType
= AL_UNDETERMINED
;
760 Source
->queue
= NULL
;
762 WriteUnlock(&Source
->queue_lock
);
763 UnlockBuffersRead(device
);
765 /* Delete all elements in the previous queue */
766 while(oldlist
!= NULL
)
768 ALbufferlistitem
*temp
= oldlist
;
769 oldlist
= temp
->next
;
772 DecrementRef(&temp
->buffer
->ref
);
778 case AL_SAMPLE_OFFSET
:
780 CHECKVAL(*values
>= 0);
782 Source
->OffsetType
= prop
;
783 Source
->Offset
= *values
;
785 if(IsPlayingOrPaused(Source
))
789 ALCdevice_Lock(Context
->Device
);
790 voice
= GetSourceVoice(Source
, Context
);
793 WriteLock(&Source
->queue_lock
);
794 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
796 WriteUnlock(&Source
->queue_lock
);
797 ALCdevice_Unlock(Context
->Device
);
798 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
800 WriteUnlock(&Source
->queue_lock
);
802 ALCdevice_Unlock(Context
->Device
);
806 case AL_DIRECT_FILTER
:
807 LockFiltersRead(device
);
808 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
810 UnlockFiltersRead(device
);
811 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
816 Source
->Direct
.Gain
= 1.0f
;
817 Source
->Direct
.GainHF
= 1.0f
;
818 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
819 Source
->Direct
.GainLF
= 1.0f
;
820 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
824 Source
->Direct
.Gain
= filter
->Gain
;
825 Source
->Direct
.GainHF
= filter
->GainHF
;
826 Source
->Direct
.HFReference
= filter
->HFReference
;
827 Source
->Direct
.GainLF
= filter
->GainLF
;
828 Source
->Direct
.LFReference
= filter
->LFReference
;
830 UnlockFiltersRead(device
);
834 case AL_DIRECT_FILTER_GAINHF_AUTO
:
835 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
837 Source
->DryGainHFAuto
= *values
;
841 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
842 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
844 Source
->WetGainAuto
= *values
;
848 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
849 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
851 Source
->WetGainHFAuto
= *values
;
855 case AL_DIRECT_CHANNELS_SOFT
:
856 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
858 Source
->DirectChannels
= *values
;
862 case AL_DISTANCE_MODEL
:
863 CHECKVAL(*values
== AL_NONE
||
864 *values
== AL_INVERSE_DISTANCE
||
865 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
866 *values
== AL_LINEAR_DISTANCE
||
867 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
868 *values
== AL_EXPONENT_DISTANCE
||
869 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
871 Source
->DistanceModel
= *values
;
872 if(Context
->SourceDistanceModel
)
877 case AL_AUXILIARY_SEND_FILTER
:
878 LockEffectSlotsRead(Context
);
879 LockFiltersRead(device
);
880 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
881 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
882 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
884 UnlockFiltersRead(device
);
885 UnlockEffectSlotsRead(Context
);
886 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
892 Source
->Send
[values
[1]].Gain
= 1.0f
;
893 Source
->Send
[values
[1]].GainHF
= 1.0f
;
894 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
895 Source
->Send
[values
[1]].GainLF
= 1.0f
;
896 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
900 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
901 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
902 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
903 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
904 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
906 UnlockFiltersRead(device
);
908 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
911 /* Add refcount on the new slot, and release the previous slot */
912 if(slot
) IncrementRef(&slot
->ref
);
913 if(Source
->Send
[values
[1]].Slot
)
914 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
915 Source
->Send
[values
[1]].Slot
= slot
;
917 /* We must force an update if the auxiliary slot changed on an
918 * active source, in case the slot is about to be deleted.
920 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
921 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
);
923 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
927 if(slot
) IncrementRef(&slot
->ref
);
928 if(Source
->Send
[values
[1]].Slot
)
929 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
930 Source
->Send
[values
[1]].Slot
= slot
;
933 UnlockEffectSlotsRead(Context
);
939 case AL_CONE_INNER_ANGLE
:
940 case AL_CONE_OUTER_ANGLE
:
945 case AL_REFERENCE_DISTANCE
:
946 case AL_ROLLOFF_FACTOR
:
947 case AL_CONE_OUTER_GAIN
:
948 case AL_MAX_DISTANCE
:
949 case AL_DOPPLER_FACTOR
:
950 case AL_CONE_OUTER_GAINHF
:
951 case AL_AIR_ABSORPTION_FACTOR
:
952 case AL_ROOM_ROLLOFF_FACTOR
:
953 case AL_SOURCE_RADIUS
:
954 fvals
[0] = (ALfloat
)*values
;
955 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
961 fvals
[0] = (ALfloat
)values
[0];
962 fvals
[1] = (ALfloat
)values
[1];
963 fvals
[2] = (ALfloat
)values
[2];
964 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
968 fvals
[0] = (ALfloat
)values
[0];
969 fvals
[1] = (ALfloat
)values
[1];
970 fvals
[2] = (ALfloat
)values
[2];
971 fvals
[3] = (ALfloat
)values
[3];
972 fvals
[4] = (ALfloat
)values
[4];
973 fvals
[5] = (ALfloat
)values
[5];
974 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
976 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
977 case AL_SEC_OFFSET_LATENCY_SOFT
:
978 case AL_STEREO_ANGLES
:
982 ERR("Unexpected property: 0x%04x\n", prop
);
983 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
986 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
994 case AL_BUFFERS_QUEUED
:
995 case AL_BUFFERS_PROCESSED
:
996 case AL_SOURCE_STATE
:
997 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
998 case AL_BYTE_LENGTH_SOFT
:
999 case AL_SAMPLE_LENGTH_SOFT
:
1000 case AL_SEC_LENGTH_SOFT
:
1002 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
1006 case AL_SOURCE_RELATIVE
:
1009 case AL_SAMPLE_OFFSET
:
1010 case AL_BYTE_OFFSET
:
1011 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1012 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1013 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1014 case AL_DIRECT_CHANNELS_SOFT
:
1015 case AL_DISTANCE_MODEL
:
1016 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1018 ivals
[0] = (ALint
)*values
;
1019 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1023 case AL_DIRECT_FILTER
:
1024 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1026 ivals
[0] = (ALuint
)*values
;
1027 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1030 case AL_AUXILIARY_SEND_FILTER
:
1031 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1032 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1033 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1035 ivals
[0] = (ALuint
)values
[0];
1036 ivals
[1] = (ALuint
)values
[1];
1037 ivals
[2] = (ALuint
)values
[2];
1038 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1041 case AL_CONE_INNER_ANGLE
:
1042 case AL_CONE_OUTER_ANGLE
:
1047 case AL_REFERENCE_DISTANCE
:
1048 case AL_ROLLOFF_FACTOR
:
1049 case AL_CONE_OUTER_GAIN
:
1050 case AL_MAX_DISTANCE
:
1051 case AL_DOPPLER_FACTOR
:
1052 case AL_CONE_OUTER_GAINHF
:
1053 case AL_AIR_ABSORPTION_FACTOR
:
1054 case AL_ROOM_ROLLOFF_FACTOR
:
1055 case AL_SOURCE_RADIUS
:
1056 fvals
[0] = (ALfloat
)*values
;
1057 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1063 fvals
[0] = (ALfloat
)values
[0];
1064 fvals
[1] = (ALfloat
)values
[1];
1065 fvals
[2] = (ALfloat
)values
[2];
1066 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1069 case AL_ORIENTATION
:
1070 fvals
[0] = (ALfloat
)values
[0];
1071 fvals
[1] = (ALfloat
)values
[1];
1072 fvals
[2] = (ALfloat
)values
[2];
1073 fvals
[3] = (ALfloat
)values
[3];
1074 fvals
[4] = (ALfloat
)values
[4];
1075 fvals
[5] = (ALfloat
)values
[5];
1076 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1078 case AL_SEC_OFFSET_LATENCY_SOFT
:
1079 case AL_STEREO_ANGLES
:
1083 ERR("Unexpected property: 0x%04x\n", prop
);
1084 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1090 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1092 ALCdevice
*device
= Context
->Device
;
1093 ALbufferlistitem
*BufferList
;
1094 ClockLatency clocktime
;
1102 *values
= Source
->Gain
;
1106 *values
= Source
->Pitch
;
1109 case AL_MAX_DISTANCE
:
1110 *values
= Source
->MaxDistance
;
1113 case AL_ROLLOFF_FACTOR
:
1114 *values
= Source
->RollOffFactor
;
1117 case AL_REFERENCE_DISTANCE
:
1118 *values
= Source
->RefDistance
;
1121 case AL_CONE_INNER_ANGLE
:
1122 *values
= Source
->InnerAngle
;
1125 case AL_CONE_OUTER_ANGLE
:
1126 *values
= Source
->OuterAngle
;
1130 *values
= Source
->MinGain
;
1134 *values
= Source
->MaxGain
;
1137 case AL_CONE_OUTER_GAIN
:
1138 *values
= Source
->OuterGain
;
1142 case AL_SAMPLE_OFFSET
:
1143 case AL_BYTE_OFFSET
:
1144 *values
= GetSourceOffset(Source
, prop
, Context
);
1147 case AL_CONE_OUTER_GAINHF
:
1148 *values
= Source
->OuterGainHF
;
1151 case AL_AIR_ABSORPTION_FACTOR
:
1152 *values
= Source
->AirAbsorptionFactor
;
1155 case AL_ROOM_ROLLOFF_FACTOR
:
1156 *values
= Source
->RoomRolloffFactor
;
1159 case AL_DOPPLER_FACTOR
:
1160 *values
= Source
->DopplerFactor
;
1163 case AL_SEC_LENGTH_SOFT
:
1164 ReadLock(&Source
->queue_lock
);
1165 if(!(BufferList
=Source
->queue
))
1172 ALbuffer
*buffer
= BufferList
->buffer
;
1173 if(buffer
&& buffer
->SampleLen
> 0)
1175 freq
= buffer
->Frequency
;
1176 length
+= buffer
->SampleLen
;
1178 } while((BufferList
=BufferList
->next
) != NULL
);
1179 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1181 ReadUnlock(&Source
->queue_lock
);
1184 case AL_SOURCE_RADIUS
:
1185 *values
= Source
->Radius
;
1188 case AL_STEREO_ANGLES
:
1189 values
[0] = Source
->StereoPan
[0];
1190 values
[1] = Source
->StereoPan
[1];
1193 case AL_SEC_OFFSET_LATENCY_SOFT
:
1194 /* Get the source offset with the clock time first. Then get the
1195 * clock time with the device latency. Order is important.
1197 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1198 clocktime
= V0(device
->Backend
,getClockLatency
)();
1199 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1200 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1203 /* If the clock time incremented, reduce the latency by that
1204 * much since it's that much closer to the source offset it got
1207 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1208 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1214 values
[0] = Source
->Position
[0];
1215 values
[1] = Source
->Position
[1];
1216 values
[2] = Source
->Position
[2];
1220 values
[0] = Source
->Velocity
[0];
1221 values
[1] = Source
->Velocity
[1];
1222 values
[2] = Source
->Velocity
[2];
1226 values
[0] = Source
->Direction
[0];
1227 values
[1] = Source
->Direction
[1];
1228 values
[2] = Source
->Direction
[2];
1231 case AL_ORIENTATION
:
1232 values
[0] = Source
->Orientation
[0][0];
1233 values
[1] = Source
->Orientation
[0][1];
1234 values
[2] = Source
->Orientation
[0][2];
1235 values
[3] = Source
->Orientation
[1][0];
1236 values
[4] = Source
->Orientation
[1][1];
1237 values
[5] = Source
->Orientation
[1][2];
1241 case AL_SOURCE_RELATIVE
:
1243 case AL_SOURCE_STATE
:
1244 case AL_BUFFERS_QUEUED
:
1245 case AL_BUFFERS_PROCESSED
:
1246 case AL_SOURCE_TYPE
:
1247 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1248 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1249 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1250 case AL_DIRECT_CHANNELS_SOFT
:
1251 case AL_BYTE_LENGTH_SOFT
:
1252 case AL_SAMPLE_LENGTH_SOFT
:
1253 case AL_DISTANCE_MODEL
:
1254 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1255 *values
= (ALdouble
)ivals
[0];
1259 case AL_DIRECT_FILTER
:
1260 case AL_AUXILIARY_SEND_FILTER
:
1261 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1265 ERR("Unexpected property: 0x%04x\n", prop
);
1266 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1269 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1271 ALbufferlistitem
*BufferList
;
1277 case AL_SOURCE_RELATIVE
:
1278 *values
= Source
->HeadRelative
;
1282 *values
= Source
->Looping
;
1286 ReadLock(&Source
->queue_lock
);
1287 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1288 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1289 ReadUnlock(&Source
->queue_lock
);
1292 case AL_SOURCE_STATE
:
1293 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1296 case AL_BYTE_LENGTH_SOFT
:
1297 ReadLock(&Source
->queue_lock
);
1298 if(!(BufferList
=Source
->queue
))
1304 ALbuffer
*buffer
= BufferList
->buffer
;
1305 if(buffer
&& buffer
->SampleLen
> 0)
1307 ALuint byte_align
, sample_align
;
1308 if(buffer
->OriginalType
== UserFmtIMA4
)
1310 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1311 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1312 sample_align
= buffer
->OriginalAlign
;
1314 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1316 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1317 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1318 sample_align
= buffer
->OriginalAlign
;
1322 ALsizei align
= buffer
->OriginalAlign
;
1323 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1324 sample_align
= buffer
->OriginalAlign
;
1327 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1329 } while((BufferList
=BufferList
->next
) != NULL
);
1332 ReadUnlock(&Source
->queue_lock
);
1335 case AL_SAMPLE_LENGTH_SOFT
:
1336 ReadLock(&Source
->queue_lock
);
1337 if(!(BufferList
=Source
->queue
))
1343 ALbuffer
*buffer
= BufferList
->buffer
;
1344 if(buffer
) length
+= buffer
->SampleLen
;
1345 } while((BufferList
=BufferList
->next
) != NULL
);
1348 ReadUnlock(&Source
->queue_lock
);
1351 case AL_BUFFERS_QUEUED
:
1352 ReadLock(&Source
->queue_lock
);
1353 if(!(BufferList
=Source
->queue
))
1360 } while((BufferList
=BufferList
->next
) != NULL
);
1363 ReadUnlock(&Source
->queue_lock
);
1366 case AL_BUFFERS_PROCESSED
:
1367 ReadLock(&Source
->queue_lock
);
1368 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1370 /* Buffers on a looping source are in a perpetual state of
1371 * PENDING, so don't report any as PROCESSED */
1376 const ALbufferlistitem
*BufferList
= Source
->queue
;
1377 const ALbufferlistitem
*Current
= NULL
;
1381 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1382 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1383 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1384 Current
= BufferList
;
1386 while(BufferList
&& BufferList
!= Current
)
1389 BufferList
= BufferList
->next
;
1393 ReadUnlock(&Source
->queue_lock
);
1396 case AL_SOURCE_TYPE
:
1397 *values
= Source
->SourceType
;
1400 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1401 *values
= Source
->DryGainHFAuto
;
1404 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1405 *values
= Source
->WetGainAuto
;
1408 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1409 *values
= Source
->WetGainHFAuto
;
1412 case AL_DIRECT_CHANNELS_SOFT
:
1413 *values
= Source
->DirectChannels
;
1416 case AL_DISTANCE_MODEL
:
1417 *values
= Source
->DistanceModel
;
1420 /* 1x float/double */
1421 case AL_CONE_INNER_ANGLE
:
1422 case AL_CONE_OUTER_ANGLE
:
1427 case AL_REFERENCE_DISTANCE
:
1428 case AL_ROLLOFF_FACTOR
:
1429 case AL_CONE_OUTER_GAIN
:
1430 case AL_MAX_DISTANCE
:
1432 case AL_SAMPLE_OFFSET
:
1433 case AL_BYTE_OFFSET
:
1434 case AL_DOPPLER_FACTOR
:
1435 case AL_AIR_ABSORPTION_FACTOR
:
1436 case AL_ROOM_ROLLOFF_FACTOR
:
1437 case AL_CONE_OUTER_GAINHF
:
1438 case AL_SEC_LENGTH_SOFT
:
1439 case AL_SOURCE_RADIUS
:
1440 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1441 *values
= (ALint
)dvals
[0];
1444 /* 3x float/double */
1448 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1450 values
[0] = (ALint
)dvals
[0];
1451 values
[1] = (ALint
)dvals
[1];
1452 values
[2] = (ALint
)dvals
[2];
1456 /* 6x float/double */
1457 case AL_ORIENTATION
:
1458 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1460 values
[0] = (ALint
)dvals
[0];
1461 values
[1] = (ALint
)dvals
[1];
1462 values
[2] = (ALint
)dvals
[2];
1463 values
[3] = (ALint
)dvals
[3];
1464 values
[4] = (ALint
)dvals
[4];
1465 values
[5] = (ALint
)dvals
[5];
1469 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1470 break; /* i64 only */
1471 case AL_SEC_OFFSET_LATENCY_SOFT
:
1472 break; /* Double only */
1473 case AL_STEREO_ANGLES
:
1474 break; /* Float/double only */
1476 case AL_DIRECT_FILTER
:
1477 case AL_AUXILIARY_SEND_FILTER
:
1481 ERR("Unexpected property: 0x%04x\n", prop
);
1482 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1485 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1487 ALCdevice
*device
= Context
->Device
;
1488 ClockLatency clocktime
;
1496 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1497 /* Get the source offset with the clock time first. Then get the
1498 * clock time with the device latency. Order is important.
1500 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1501 clocktime
= V0(device
->Backend
,getClockLatency
)();
1502 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1503 values
[1] = clocktime
.Latency
;
1506 /* If the clock time incremented, reduce the latency by that
1507 * much since it's that much closer to the source offset it got
1510 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1511 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1515 /* 1x float/double */
1516 case AL_CONE_INNER_ANGLE
:
1517 case AL_CONE_OUTER_ANGLE
:
1522 case AL_REFERENCE_DISTANCE
:
1523 case AL_ROLLOFF_FACTOR
:
1524 case AL_CONE_OUTER_GAIN
:
1525 case AL_MAX_DISTANCE
:
1527 case AL_SAMPLE_OFFSET
:
1528 case AL_BYTE_OFFSET
:
1529 case AL_DOPPLER_FACTOR
:
1530 case AL_AIR_ABSORPTION_FACTOR
:
1531 case AL_ROOM_ROLLOFF_FACTOR
:
1532 case AL_CONE_OUTER_GAINHF
:
1533 case AL_SEC_LENGTH_SOFT
:
1534 case AL_SOURCE_RADIUS
:
1535 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1536 *values
= (ALint64
)dvals
[0];
1539 /* 3x float/double */
1543 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1545 values
[0] = (ALint64
)dvals
[0];
1546 values
[1] = (ALint64
)dvals
[1];
1547 values
[2] = (ALint64
)dvals
[2];
1551 /* 6x float/double */
1552 case AL_ORIENTATION
:
1553 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1555 values
[0] = (ALint64
)dvals
[0];
1556 values
[1] = (ALint64
)dvals
[1];
1557 values
[2] = (ALint64
)dvals
[2];
1558 values
[3] = (ALint64
)dvals
[3];
1559 values
[4] = (ALint64
)dvals
[4];
1560 values
[5] = (ALint64
)dvals
[5];
1565 case AL_SOURCE_RELATIVE
:
1567 case AL_SOURCE_STATE
:
1568 case AL_BUFFERS_QUEUED
:
1569 case AL_BUFFERS_PROCESSED
:
1570 case AL_BYTE_LENGTH_SOFT
:
1571 case AL_SAMPLE_LENGTH_SOFT
:
1572 case AL_SOURCE_TYPE
:
1573 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1574 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1575 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1576 case AL_DIRECT_CHANNELS_SOFT
:
1577 case AL_DISTANCE_MODEL
:
1578 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1584 case AL_DIRECT_FILTER
:
1585 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1586 *values
= (ALuint
)ivals
[0];
1590 case AL_AUXILIARY_SEND_FILTER
:
1591 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1593 values
[0] = (ALuint
)ivals
[0];
1594 values
[1] = (ALuint
)ivals
[1];
1595 values
[2] = (ALuint
)ivals
[2];
1599 case AL_SEC_OFFSET_LATENCY_SOFT
:
1600 break; /* Double only */
1601 case AL_STEREO_ANGLES
:
1602 break; /* Float/double only */
1605 ERR("Unexpected property: 0x%04x\n", prop
);
1606 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1610 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1613 ALCcontext
*context
;
1617 context
= GetContextRef();
1618 if(!context
) return;
1621 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1622 device
= context
->Device
;
1623 for(cur
= 0;cur
< n
;cur
++)
1625 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1628 alDeleteSources(cur
, sources
);
1629 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1631 InitSourceParams(source
, device
->NumAuxSends
);
1633 err
= NewThunkEntry(&source
->id
);
1634 if(err
== AL_NO_ERROR
)
1635 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1636 if(err
!= AL_NO_ERROR
)
1638 FreeThunkEntry(source
->id
);
1639 memset(source
, 0, sizeof(ALsource
));
1642 alDeleteSources(cur
, sources
);
1643 SET_ERROR_AND_GOTO(context
, err
, done
);
1646 sources
[cur
] = source
->id
;
1650 ALCcontext_DecRef(context
);
1654 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1657 ALCcontext
*context
;
1661 context
= GetContextRef();
1662 if(!context
) return;
1664 LockSourcesWrite(context
);
1666 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1668 /* Check that all Sources are valid */
1669 for(i
= 0;i
< n
;i
++)
1671 if(LookupSource(context
, sources
[i
]) == NULL
)
1672 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1674 device
= context
->Device
;
1675 for(i
= 0;i
< n
;i
++)
1679 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1681 FreeThunkEntry(Source
->id
);
1683 ALCdevice_Lock(device
);
1684 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1686 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1687 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1689 ALCdevice_Unlock(device
);
1691 DeinitSource(Source
, device
->NumAuxSends
);
1693 memset(Source
, 0, sizeof(*Source
));
1698 UnlockSourcesWrite(context
);
1699 ALCcontext_DecRef(context
);
1703 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1705 ALCcontext
*context
;
1708 context
= GetContextRef();
1709 if(!context
) return AL_FALSE
;
1711 LockSourcesRead(context
);
1712 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1713 UnlockSourcesRead(context
);
1715 ALCcontext_DecRef(context
);
1721 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1723 ALCcontext
*Context
;
1726 Context
= GetContextRef();
1727 if(!Context
) return;
1729 WriteLock(&Context
->PropLock
);
1730 LockSourcesRead(Context
);
1731 if((Source
=LookupSource(Context
, source
)) == NULL
)
1732 alSetError(Context
, AL_INVALID_NAME
);
1733 else if(!(FloatValsByProp(param
) == 1))
1734 alSetError(Context
, AL_INVALID_ENUM
);
1736 SetSourcefv(Source
, Context
, param
, &value
);
1737 UnlockSourcesRead(Context
);
1738 WriteUnlock(&Context
->PropLock
);
1740 ALCcontext_DecRef(Context
);
1743 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1745 ALCcontext
*Context
;
1748 Context
= GetContextRef();
1749 if(!Context
) return;
1751 WriteLock(&Context
->PropLock
);
1752 LockSourcesRead(Context
);
1753 if((Source
=LookupSource(Context
, source
)) == NULL
)
1754 alSetError(Context
, AL_INVALID_NAME
);
1755 else if(!(FloatValsByProp(param
) == 3))
1756 alSetError(Context
, AL_INVALID_ENUM
);
1759 ALfloat fvals
[3] = { value1
, value2
, value3
};
1760 SetSourcefv(Source
, Context
, param
, fvals
);
1762 UnlockSourcesRead(Context
);
1763 WriteUnlock(&Context
->PropLock
);
1765 ALCcontext_DecRef(Context
);
1768 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1770 ALCcontext
*Context
;
1773 Context
= GetContextRef();
1774 if(!Context
) return;
1776 WriteLock(&Context
->PropLock
);
1777 LockSourcesRead(Context
);
1778 if((Source
=LookupSource(Context
, source
)) == NULL
)
1779 alSetError(Context
, AL_INVALID_NAME
);
1781 alSetError(Context
, AL_INVALID_VALUE
);
1782 else if(!(FloatValsByProp(param
) > 0))
1783 alSetError(Context
, AL_INVALID_ENUM
);
1785 SetSourcefv(Source
, Context
, param
, values
);
1786 UnlockSourcesRead(Context
);
1787 WriteUnlock(&Context
->PropLock
);
1789 ALCcontext_DecRef(Context
);
1793 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1795 ALCcontext
*Context
;
1798 Context
= GetContextRef();
1799 if(!Context
) return;
1801 WriteLock(&Context
->PropLock
);
1802 LockSourcesRead(Context
);
1803 if((Source
=LookupSource(Context
, source
)) == NULL
)
1804 alSetError(Context
, AL_INVALID_NAME
);
1805 else if(!(DoubleValsByProp(param
) == 1))
1806 alSetError(Context
, AL_INVALID_ENUM
);
1809 ALfloat fval
= (ALfloat
)value
;
1810 SetSourcefv(Source
, Context
, param
, &fval
);
1812 UnlockSourcesRead(Context
);
1813 WriteUnlock(&Context
->PropLock
);
1815 ALCcontext_DecRef(Context
);
1818 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1820 ALCcontext
*Context
;
1823 Context
= GetContextRef();
1824 if(!Context
) return;
1826 WriteLock(&Context
->PropLock
);
1827 LockSourcesRead(Context
);
1828 if((Source
=LookupSource(Context
, source
)) == NULL
)
1829 alSetError(Context
, AL_INVALID_NAME
);
1830 else if(!(DoubleValsByProp(param
) == 3))
1831 alSetError(Context
, AL_INVALID_ENUM
);
1834 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1835 SetSourcefv(Source
, Context
, param
, fvals
);
1837 UnlockSourcesRead(Context
);
1838 WriteUnlock(&Context
->PropLock
);
1840 ALCcontext_DecRef(Context
);
1843 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1845 ALCcontext
*Context
;
1849 Context
= GetContextRef();
1850 if(!Context
) return;
1852 WriteLock(&Context
->PropLock
);
1853 LockSourcesRead(Context
);
1854 if((Source
=LookupSource(Context
, source
)) == NULL
)
1855 alSetError(Context
, AL_INVALID_NAME
);
1857 alSetError(Context
, AL_INVALID_VALUE
);
1858 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1859 alSetError(Context
, AL_INVALID_ENUM
);
1865 for(i
= 0;i
< count
;i
++)
1866 fvals
[i
] = (ALfloat
)values
[i
];
1867 SetSourcefv(Source
, Context
, param
, fvals
);
1869 UnlockSourcesRead(Context
);
1870 WriteUnlock(&Context
->PropLock
);
1872 ALCcontext_DecRef(Context
);
1876 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1878 ALCcontext
*Context
;
1881 Context
= GetContextRef();
1882 if(!Context
) return;
1884 WriteLock(&Context
->PropLock
);
1885 LockSourcesRead(Context
);
1886 if((Source
=LookupSource(Context
, source
)) == NULL
)
1887 alSetError(Context
, AL_INVALID_NAME
);
1888 else if(!(IntValsByProp(param
) == 1))
1889 alSetError(Context
, AL_INVALID_ENUM
);
1891 SetSourceiv(Source
, Context
, param
, &value
);
1892 UnlockSourcesRead(Context
);
1893 WriteUnlock(&Context
->PropLock
);
1895 ALCcontext_DecRef(Context
);
1898 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1900 ALCcontext
*Context
;
1903 Context
= GetContextRef();
1904 if(!Context
) return;
1906 WriteLock(&Context
->PropLock
);
1907 LockSourcesRead(Context
);
1908 if((Source
=LookupSource(Context
, source
)) == NULL
)
1909 alSetError(Context
, AL_INVALID_NAME
);
1910 else if(!(IntValsByProp(param
) == 3))
1911 alSetError(Context
, AL_INVALID_ENUM
);
1914 ALint ivals
[3] = { value1
, value2
, value3
};
1915 SetSourceiv(Source
, Context
, param
, ivals
);
1917 UnlockSourcesRead(Context
);
1918 WriteUnlock(&Context
->PropLock
);
1920 ALCcontext_DecRef(Context
);
1923 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1925 ALCcontext
*Context
;
1928 Context
= GetContextRef();
1929 if(!Context
) return;
1931 WriteLock(&Context
->PropLock
);
1932 LockSourcesRead(Context
);
1933 if((Source
=LookupSource(Context
, source
)) == NULL
)
1934 alSetError(Context
, AL_INVALID_NAME
);
1936 alSetError(Context
, AL_INVALID_VALUE
);
1937 else if(!(IntValsByProp(param
) > 0))
1938 alSetError(Context
, AL_INVALID_ENUM
);
1940 SetSourceiv(Source
, Context
, param
, values
);
1941 UnlockSourcesRead(Context
);
1942 WriteUnlock(&Context
->PropLock
);
1944 ALCcontext_DecRef(Context
);
1948 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1950 ALCcontext
*Context
;
1953 Context
= GetContextRef();
1954 if(!Context
) return;
1956 WriteLock(&Context
->PropLock
);
1957 LockSourcesRead(Context
);
1958 if((Source
=LookupSource(Context
, source
)) == NULL
)
1959 alSetError(Context
, AL_INVALID_NAME
);
1960 else if(!(Int64ValsByProp(param
) == 1))
1961 alSetError(Context
, AL_INVALID_ENUM
);
1963 SetSourcei64v(Source
, Context
, param
, &value
);
1964 UnlockSourcesRead(Context
);
1965 WriteUnlock(&Context
->PropLock
);
1967 ALCcontext_DecRef(Context
);
1970 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1972 ALCcontext
*Context
;
1975 Context
= GetContextRef();
1976 if(!Context
) return;
1978 WriteLock(&Context
->PropLock
);
1979 LockSourcesRead(Context
);
1980 if((Source
=LookupSource(Context
, source
)) == NULL
)
1981 alSetError(Context
, AL_INVALID_NAME
);
1982 else if(!(Int64ValsByProp(param
) == 3))
1983 alSetError(Context
, AL_INVALID_ENUM
);
1986 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1987 SetSourcei64v(Source
, Context
, param
, i64vals
);
1989 UnlockSourcesRead(Context
);
1990 WriteUnlock(&Context
->PropLock
);
1992 ALCcontext_DecRef(Context
);
1995 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1997 ALCcontext
*Context
;
2000 Context
= GetContextRef();
2001 if(!Context
) return;
2003 WriteLock(&Context
->PropLock
);
2004 LockSourcesRead(Context
);
2005 if((Source
=LookupSource(Context
, source
)) == NULL
)
2006 alSetError(Context
, AL_INVALID_NAME
);
2008 alSetError(Context
, AL_INVALID_VALUE
);
2009 else if(!(Int64ValsByProp(param
) > 0))
2010 alSetError(Context
, AL_INVALID_ENUM
);
2012 SetSourcei64v(Source
, Context
, param
, values
);
2013 UnlockSourcesRead(Context
);
2014 WriteUnlock(&Context
->PropLock
);
2016 ALCcontext_DecRef(Context
);
2020 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2022 ALCcontext
*Context
;
2025 Context
= GetContextRef();
2026 if(!Context
) return;
2028 ReadLock(&Context
->PropLock
);
2029 LockSourcesRead(Context
);
2030 if((Source
=LookupSource(Context
, source
)) == NULL
)
2031 alSetError(Context
, AL_INVALID_NAME
);
2033 alSetError(Context
, AL_INVALID_VALUE
);
2034 else if(!(FloatValsByProp(param
) == 1))
2035 alSetError(Context
, AL_INVALID_ENUM
);
2039 if(GetSourcedv(Source
, Context
, param
, &dval
))
2040 *value
= (ALfloat
)dval
;
2042 UnlockSourcesRead(Context
);
2043 ReadUnlock(&Context
->PropLock
);
2045 ALCcontext_DecRef(Context
);
2049 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2051 ALCcontext
*Context
;
2054 Context
= GetContextRef();
2055 if(!Context
) return;
2057 ReadLock(&Context
->PropLock
);
2058 LockSourcesRead(Context
);
2059 if((Source
=LookupSource(Context
, source
)) == NULL
)
2060 alSetError(Context
, AL_INVALID_NAME
);
2061 else if(!(value1
&& value2
&& value3
))
2062 alSetError(Context
, AL_INVALID_VALUE
);
2063 else if(!(FloatValsByProp(param
) == 3))
2064 alSetError(Context
, AL_INVALID_ENUM
);
2068 if(GetSourcedv(Source
, Context
, param
, dvals
))
2070 *value1
= (ALfloat
)dvals
[0];
2071 *value2
= (ALfloat
)dvals
[1];
2072 *value3
= (ALfloat
)dvals
[2];
2075 UnlockSourcesRead(Context
);
2076 ReadUnlock(&Context
->PropLock
);
2078 ALCcontext_DecRef(Context
);
2082 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2084 ALCcontext
*Context
;
2088 Context
= GetContextRef();
2089 if(!Context
) return;
2091 ReadLock(&Context
->PropLock
);
2092 LockSourcesRead(Context
);
2093 if((Source
=LookupSource(Context
, source
)) == NULL
)
2094 alSetError(Context
, AL_INVALID_NAME
);
2096 alSetError(Context
, AL_INVALID_VALUE
);
2097 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2098 alSetError(Context
, AL_INVALID_ENUM
);
2102 if(GetSourcedv(Source
, Context
, param
, dvals
))
2105 for(i
= 0;i
< count
;i
++)
2106 values
[i
] = (ALfloat
)dvals
[i
];
2109 UnlockSourcesRead(Context
);
2110 ReadUnlock(&Context
->PropLock
);
2112 ALCcontext_DecRef(Context
);
2116 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2118 ALCcontext
*Context
;
2121 Context
= GetContextRef();
2122 if(!Context
) return;
2124 ReadLock(&Context
->PropLock
);
2125 LockSourcesRead(Context
);
2126 if((Source
=LookupSource(Context
, source
)) == NULL
)
2127 alSetError(Context
, AL_INVALID_NAME
);
2129 alSetError(Context
, AL_INVALID_VALUE
);
2130 else if(!(DoubleValsByProp(param
) == 1))
2131 alSetError(Context
, AL_INVALID_ENUM
);
2133 GetSourcedv(Source
, Context
, param
, value
);
2134 UnlockSourcesRead(Context
);
2135 ReadUnlock(&Context
->PropLock
);
2137 ALCcontext_DecRef(Context
);
2140 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2142 ALCcontext
*Context
;
2145 Context
= GetContextRef();
2146 if(!Context
) return;
2148 ReadLock(&Context
->PropLock
);
2149 LockSourcesRead(Context
);
2150 if((Source
=LookupSource(Context
, source
)) == NULL
)
2151 alSetError(Context
, AL_INVALID_NAME
);
2152 else if(!(value1
&& value2
&& value3
))
2153 alSetError(Context
, AL_INVALID_VALUE
);
2154 else if(!(DoubleValsByProp(param
) == 3))
2155 alSetError(Context
, AL_INVALID_ENUM
);
2159 if(GetSourcedv(Source
, Context
, param
, dvals
))
2166 UnlockSourcesRead(Context
);
2167 ReadUnlock(&Context
->PropLock
);
2169 ALCcontext_DecRef(Context
);
2172 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2174 ALCcontext
*Context
;
2177 Context
= GetContextRef();
2178 if(!Context
) return;
2180 ReadLock(&Context
->PropLock
);
2181 LockSourcesRead(Context
);
2182 if((Source
=LookupSource(Context
, source
)) == NULL
)
2183 alSetError(Context
, AL_INVALID_NAME
);
2185 alSetError(Context
, AL_INVALID_VALUE
);
2186 else if(!(DoubleValsByProp(param
) > 0))
2187 alSetError(Context
, AL_INVALID_ENUM
);
2189 GetSourcedv(Source
, Context
, param
, values
);
2190 UnlockSourcesRead(Context
);
2191 ReadUnlock(&Context
->PropLock
);
2193 ALCcontext_DecRef(Context
);
2197 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2199 ALCcontext
*Context
;
2202 Context
= GetContextRef();
2203 if(!Context
) return;
2205 ReadLock(&Context
->PropLock
);
2206 LockSourcesRead(Context
);
2207 if((Source
=LookupSource(Context
, source
)) == NULL
)
2208 alSetError(Context
, AL_INVALID_NAME
);
2210 alSetError(Context
, AL_INVALID_VALUE
);
2211 else if(!(IntValsByProp(param
) == 1))
2212 alSetError(Context
, AL_INVALID_ENUM
);
2214 GetSourceiv(Source
, Context
, param
, value
);
2215 UnlockSourcesRead(Context
);
2216 ReadUnlock(&Context
->PropLock
);
2218 ALCcontext_DecRef(Context
);
2222 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2224 ALCcontext
*Context
;
2227 Context
= GetContextRef();
2228 if(!Context
) return;
2230 ReadLock(&Context
->PropLock
);
2231 LockSourcesRead(Context
);
2232 if((Source
=LookupSource(Context
, source
)) == NULL
)
2233 alSetError(Context
, AL_INVALID_NAME
);
2234 else if(!(value1
&& value2
&& value3
))
2235 alSetError(Context
, AL_INVALID_VALUE
);
2236 else if(!(IntValsByProp(param
) == 3))
2237 alSetError(Context
, AL_INVALID_ENUM
);
2241 if(GetSourceiv(Source
, Context
, param
, ivals
))
2248 UnlockSourcesRead(Context
);
2249 ReadUnlock(&Context
->PropLock
);
2251 ALCcontext_DecRef(Context
);
2255 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2257 ALCcontext
*Context
;
2260 Context
= GetContextRef();
2261 if(!Context
) return;
2263 ReadLock(&Context
->PropLock
);
2264 LockSourcesRead(Context
);
2265 if((Source
=LookupSource(Context
, source
)) == NULL
)
2266 alSetError(Context
, AL_INVALID_NAME
);
2268 alSetError(Context
, AL_INVALID_VALUE
);
2269 else if(!(IntValsByProp(param
) > 0))
2270 alSetError(Context
, AL_INVALID_ENUM
);
2272 GetSourceiv(Source
, Context
, param
, values
);
2273 UnlockSourcesRead(Context
);
2274 ReadUnlock(&Context
->PropLock
);
2276 ALCcontext_DecRef(Context
);
2280 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2282 ALCcontext
*Context
;
2285 Context
= GetContextRef();
2286 if(!Context
) return;
2288 ReadLock(&Context
->PropLock
);
2289 LockSourcesRead(Context
);
2290 if((Source
=LookupSource(Context
, source
)) == NULL
)
2291 alSetError(Context
, AL_INVALID_NAME
);
2293 alSetError(Context
, AL_INVALID_VALUE
);
2294 else if(!(Int64ValsByProp(param
) == 1))
2295 alSetError(Context
, AL_INVALID_ENUM
);
2297 GetSourcei64v(Source
, Context
, param
, value
);
2298 UnlockSourcesRead(Context
);
2299 ReadUnlock(&Context
->PropLock
);
2301 ALCcontext_DecRef(Context
);
2304 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2306 ALCcontext
*Context
;
2309 Context
= GetContextRef();
2310 if(!Context
) return;
2312 ReadLock(&Context
->PropLock
);
2313 LockSourcesRead(Context
);
2314 if((Source
=LookupSource(Context
, source
)) == NULL
)
2315 alSetError(Context
, AL_INVALID_NAME
);
2316 else if(!(value1
&& value2
&& value3
))
2317 alSetError(Context
, AL_INVALID_VALUE
);
2318 else if(!(Int64ValsByProp(param
) == 3))
2319 alSetError(Context
, AL_INVALID_ENUM
);
2323 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2325 *value1
= i64vals
[0];
2326 *value2
= i64vals
[1];
2327 *value3
= i64vals
[2];
2330 UnlockSourcesRead(Context
);
2331 ReadUnlock(&Context
->PropLock
);
2333 ALCcontext_DecRef(Context
);
2336 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2338 ALCcontext
*Context
;
2341 Context
= GetContextRef();
2342 if(!Context
) return;
2344 ReadLock(&Context
->PropLock
);
2345 LockSourcesRead(Context
);
2346 if((Source
=LookupSource(Context
, source
)) == NULL
)
2347 alSetError(Context
, AL_INVALID_NAME
);
2349 alSetError(Context
, AL_INVALID_VALUE
);
2350 else if(!(Int64ValsByProp(param
) > 0))
2351 alSetError(Context
, AL_INVALID_ENUM
);
2353 GetSourcei64v(Source
, Context
, param
, values
);
2354 UnlockSourcesRead(Context
);
2355 ReadUnlock(&Context
->PropLock
);
2357 ALCcontext_DecRef(Context
);
2361 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2363 alSourcePlayv(1, &source
);
2365 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2367 ALCcontext
*context
;
2373 context
= GetContextRef();
2374 if(!context
) return;
2376 LockSourcesRead(context
);
2378 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2379 for(i
= 0;i
< n
;i
++)
2381 if(!LookupSource(context
, sources
[i
]))
2382 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2385 device
= context
->Device
;
2386 ALCdevice_Lock(device
);
2387 /* If the device is disconnected, go right to stopped. */
2388 if(!device
->Connected
)
2390 for(i
= 0;i
< n
;i
++)
2392 source
= LookupSource(context
, sources
[i
]);
2393 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2395 ALCdevice_Unlock(device
);
2399 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2401 ALsizei newcount
= context
->MaxVoices
<< 1;
2402 if(context
->MaxVoices
>= newcount
)
2404 ALCdevice_Unlock(device
);
2405 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2407 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2410 for(i
= 0;i
< n
;i
++)
2412 ALbufferlistitem
*BufferList
;
2413 ALbuffer
*buffer
= NULL
;
2415 source
= LookupSource(context
, sources
[i
]);
2416 WriteLock(&source
->queue_lock
);
2417 /* Check that there is a queue containing at least one valid, non zero
2420 BufferList
= source
->queue
;
2423 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2425 BufferList
= BufferList
->next
;
2428 /* If there's nothing to play, go right to stopped. */
2431 /* NOTE: A source without any playable buffers should not have an
2432 * ALvoice since it shouldn't be in a playing or paused state. So
2433 * there's no need to look up its voice and clear the source.
2435 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2436 source
->OffsetType
= AL_NONE
;
2437 source
->Offset
= 0.0;
2441 voice
= GetSourceVoice(source
, context
);
2442 switch(GetSourceState(source
, voice
))
2445 assert(voice
!= NULL
);
2446 /* A source that's already playing is restarted from the beginning. */
2447 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2448 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2449 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2453 assert(voice
!= NULL
);
2454 /* A source that's paused simply resumes. Make sure it uses the
2455 * volume last specified; there's no reason to fade from where
2458 voice
->Flags
&= ~VOICE_IS_MOVING
;
2459 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2460 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2467 /* Make sure this source isn't already active, and if not, look for an
2468 * unused voice to put it in.
2470 assert(voice
== NULL
);
2471 for(j
= 0;j
< context
->VoiceCount
;j
++)
2473 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2475 voice
= context
->Voices
[j
];
2480 voice
= context
->Voices
[context
->VoiceCount
++];
2481 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2483 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2484 UpdateSourceProps(source
, voice
, device
->NumAuxSends
);
2486 /* A source that's not playing or paused has any offset applied when it
2490 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2492 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2493 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2494 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2495 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2496 if(source
->OffsetType
!= AL_NONE
)
2497 ApplyOffset(source
, voice
);
2499 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2500 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2502 /* Clear previous samples. */
2503 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2505 /* Clear the stepping value so the mixer knows not to mix this until
2506 * the update gets applied.
2511 for(j
= 0;j
< voice
->NumChannels
;j
++)
2512 memset(&voice
->Direct
.Params
[j
].Hrtf
.State
, 0,
2513 sizeof(voice
->Direct
.Params
[j
].Hrtf
.State
));
2514 if(device
->AvgSpeakerDist
> 0.0f
)
2516 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2517 (device
->AvgSpeakerDist
* device
->Frequency
);
2518 for(j
= 0;j
< voice
->NumChannels
;j
++)
2520 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2521 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2522 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2526 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2527 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2528 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2530 WriteUnlock(&source
->queue_lock
);
2532 ALCdevice_Unlock(device
);
2535 UnlockSourcesRead(context
);
2536 ALCcontext_DecRef(context
);
2539 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2541 alSourcePausev(1, &source
);
2543 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2545 ALCcontext
*context
;
2551 context
= GetContextRef();
2552 if(!context
) return;
2554 LockSourcesRead(context
);
2556 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2557 for(i
= 0;i
< n
;i
++)
2559 if(!LookupSource(context
, sources
[i
]))
2560 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2563 device
= context
->Device
;
2564 ALCdevice_Lock(device
);
2565 for(i
= 0;i
< n
;i
++)
2567 source
= LookupSource(context
, sources
[i
]);
2568 WriteLock(&source
->queue_lock
);
2569 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2571 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2572 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2575 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2576 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2577 WriteUnlock(&source
->queue_lock
);
2579 ALCdevice_Unlock(device
);
2582 UnlockSourcesRead(context
);
2583 ALCcontext_DecRef(context
);
2586 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2588 alSourceStopv(1, &source
);
2590 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2592 ALCcontext
*context
;
2598 context
= GetContextRef();
2599 if(!context
) return;
2601 LockSourcesRead(context
);
2603 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2604 for(i
= 0;i
< n
;i
++)
2606 if(!LookupSource(context
, sources
[i
]))
2607 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2610 device
= context
->Device
;
2611 ALCdevice_Lock(device
);
2612 for(i
= 0;i
< n
;i
++)
2614 source
= LookupSource(context
, sources
[i
]);
2615 WriteLock(&source
->queue_lock
);
2616 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2618 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2619 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2620 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2623 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2624 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2625 source
->OffsetType
= AL_NONE
;
2626 source
->Offset
= 0.0;
2627 WriteUnlock(&source
->queue_lock
);
2629 ALCdevice_Unlock(device
);
2632 UnlockSourcesRead(context
);
2633 ALCcontext_DecRef(context
);
2636 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2638 alSourceRewindv(1, &source
);
2640 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2642 ALCcontext
*context
;
2648 context
= GetContextRef();
2649 if(!context
) return;
2651 LockSourcesRead(context
);
2653 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2654 for(i
= 0;i
< n
;i
++)
2656 if(!LookupSource(context
, sources
[i
]))
2657 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2660 device
= context
->Device
;
2661 ALCdevice_Lock(device
);
2662 for(i
= 0;i
< n
;i
++)
2664 source
= LookupSource(context
, sources
[i
]);
2665 WriteLock(&source
->queue_lock
);
2666 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2668 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2669 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2670 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2673 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2674 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2675 source
->OffsetType
= AL_NONE
;
2676 source
->Offset
= 0.0;
2677 WriteUnlock(&source
->queue_lock
);
2679 ALCdevice_Unlock(device
);
2682 UnlockSourcesRead(context
);
2683 ALCcontext_DecRef(context
);
2687 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2690 ALCcontext
*context
;
2693 ALbufferlistitem
*BufferListStart
;
2694 ALbufferlistitem
*BufferList
;
2695 ALbuffer
*BufferFmt
= NULL
;
2700 context
= GetContextRef();
2701 if(!context
) return;
2703 device
= context
->Device
;
2705 LockSourcesRead(context
);
2707 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2708 if((source
=LookupSource(context
, src
)) == NULL
)
2709 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2711 WriteLock(&source
->queue_lock
);
2712 if(source
->SourceType
== AL_STATIC
)
2714 WriteUnlock(&source
->queue_lock
);
2715 /* Can't queue on a Static Source */
2716 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2719 /* Check for a valid Buffer, for its frequency and format */
2720 BufferList
= source
->queue
;
2723 if(BufferList
->buffer
)
2725 BufferFmt
= BufferList
->buffer
;
2728 BufferList
= BufferList
->next
;
2731 LockBuffersRead(device
);
2732 BufferListStart
= NULL
;
2734 for(i
= 0;i
< nb
;i
++)
2736 ALbuffer
*buffer
= NULL
;
2737 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2739 WriteUnlock(&source
->queue_lock
);
2740 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2743 if(!BufferListStart
)
2745 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2746 BufferList
= BufferListStart
;
2750 BufferList
->next
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2751 BufferList
= BufferList
->next
;
2753 BufferList
->buffer
= buffer
;
2754 BufferList
->next
= NULL
;
2755 if(!buffer
) continue;
2757 /* Hold a read lock on each buffer being queued while checking all
2758 * provided buffers. This is done so other threads don't see an extra
2759 * reference on some buffers if this operation ends up failing. */
2760 ReadLock(&buffer
->lock
);
2761 IncrementRef(&buffer
->ref
);
2763 if(BufferFmt
== NULL
)
2765 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2766 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2767 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2769 WriteUnlock(&source
->queue_lock
);
2770 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2773 /* A buffer failed (invalid ID or format), so unlock and release
2774 * each buffer we had. */
2775 while(BufferListStart
)
2777 ALbufferlistitem
*next
= BufferListStart
->next
;
2778 if((buffer
=BufferListStart
->buffer
) != NULL
)
2780 DecrementRef(&buffer
->ref
);
2781 ReadUnlock(&buffer
->lock
);
2783 al_free(BufferListStart
);
2784 BufferListStart
= next
;
2786 UnlockBuffersRead(device
);
2790 /* All buffers good, unlock them now. */
2791 BufferList
= BufferListStart
;
2792 while(BufferList
!= NULL
)
2794 ALbuffer
*buffer
= BufferList
->buffer
;
2795 if(buffer
) ReadUnlock(&buffer
->lock
);
2796 BufferList
= BufferList
->next
;
2798 UnlockBuffersRead(device
);
2800 /* Source is now streaming */
2801 source
->SourceType
= AL_STREAMING
;
2803 if(!(BufferList
=source
->queue
))
2804 source
->queue
= BufferListStart
;
2807 while(BufferList
->next
!= NULL
)
2808 BufferList
= BufferList
->next
;
2809 BufferList
->next
= BufferListStart
;
2811 WriteUnlock(&source
->queue_lock
);
2814 UnlockSourcesRead(context
);
2815 ALCcontext_DecRef(context
);
2818 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2820 ALCcontext
*context
;
2822 ALbufferlistitem
*OldHead
;
2823 ALbufferlistitem
*OldTail
;
2824 ALbufferlistitem
*Current
;
2828 context
= GetContextRef();
2829 if(!context
) return;
2831 LockSourcesRead(context
);
2833 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2835 if((source
=LookupSource(context
, src
)) == NULL
)
2836 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2838 /* Nothing to unqueue. */
2839 if(nb
== 0) goto done
;
2841 WriteLock(&source
->queue_lock
);
2842 if(source
->Looping
|| source
->SourceType
!= AL_STREAMING
)
2844 WriteUnlock(&source
->queue_lock
);
2845 /* Trying to unqueue buffers on a looping or non-streaming source. */
2846 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2849 /* Find the new buffer queue head */
2850 OldTail
= source
->queue
;
2852 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2853 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2854 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2856 if(OldTail
!= Current
)
2858 for(i
= 1;i
< nb
;i
++)
2860 ALbufferlistitem
*next
= OldTail
->next
;
2861 if(!next
|| next
== Current
) break;
2867 WriteUnlock(&source
->queue_lock
);
2868 /* Trying to unqueue pending buffers. */
2869 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2872 /* Swap it, and cut the new head from the old. */
2873 OldHead
= source
->queue
;
2874 source
->queue
= OldTail
->next
;
2875 OldTail
->next
= NULL
;
2876 WriteUnlock(&source
->queue_lock
);
2878 while(OldHead
!= NULL
)
2880 ALbufferlistitem
*next
= OldHead
->next
;
2881 ALbuffer
*buffer
= OldHead
->buffer
;
2887 *(buffers
++) = buffer
->id
;
2888 DecrementRef(&buffer
->ref
);
2896 UnlockSourcesRead(context
);
2897 ALCcontext_DecRef(context
);
2901 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2905 RWLockInit(&Source
->queue_lock
);
2907 Source
->InnerAngle
= 360.0f
;
2908 Source
->OuterAngle
= 360.0f
;
2909 Source
->Pitch
= 1.0f
;
2910 Source
->Position
[0] = 0.0f
;
2911 Source
->Position
[1] = 0.0f
;
2912 Source
->Position
[2] = 0.0f
;
2913 Source
->Velocity
[0] = 0.0f
;
2914 Source
->Velocity
[1] = 0.0f
;
2915 Source
->Velocity
[2] = 0.0f
;
2916 Source
->Direction
[0] = 0.0f
;
2917 Source
->Direction
[1] = 0.0f
;
2918 Source
->Direction
[2] = 0.0f
;
2919 Source
->Orientation
[0][0] = 0.0f
;
2920 Source
->Orientation
[0][1] = 0.0f
;
2921 Source
->Orientation
[0][2] = -1.0f
;
2922 Source
->Orientation
[1][0] = 0.0f
;
2923 Source
->Orientation
[1][1] = 1.0f
;
2924 Source
->Orientation
[1][2] = 0.0f
;
2925 Source
->RefDistance
= 1.0f
;
2926 Source
->MaxDistance
= FLT_MAX
;
2927 Source
->RollOffFactor
= 1.0f
;
2928 Source
->Gain
= 1.0f
;
2929 Source
->MinGain
= 0.0f
;
2930 Source
->MaxGain
= 1.0f
;
2931 Source
->OuterGain
= 0.0f
;
2932 Source
->OuterGainHF
= 1.0f
;
2934 Source
->DryGainHFAuto
= AL_TRUE
;
2935 Source
->WetGainAuto
= AL_TRUE
;
2936 Source
->WetGainHFAuto
= AL_TRUE
;
2937 Source
->AirAbsorptionFactor
= 0.0f
;
2938 Source
->RoomRolloffFactor
= 0.0f
;
2939 Source
->DopplerFactor
= 1.0f
;
2940 Source
->HeadRelative
= AL_FALSE
;
2941 Source
->Looping
= AL_FALSE
;
2942 Source
->DistanceModel
= DefaultDistanceModel
;
2943 Source
->DirectChannels
= AL_FALSE
;
2945 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2946 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2948 Source
->Radius
= 0.0f
;
2950 Source
->Direct
.Gain
= 1.0f
;
2951 Source
->Direct
.GainHF
= 1.0f
;
2952 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2953 Source
->Direct
.GainLF
= 1.0f
;
2954 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2955 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2956 for(i
= 0;i
< num_sends
;i
++)
2958 Source
->Send
[i
].Slot
= NULL
;
2959 Source
->Send
[i
].Gain
= 1.0f
;
2960 Source
->Send
[i
].GainHF
= 1.0f
;
2961 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2962 Source
->Send
[i
].GainLF
= 1.0f
;
2963 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2966 Source
->Offset
= 0.0;
2967 Source
->OffsetType
= AL_NONE
;
2968 Source
->SourceType
= AL_UNDETERMINED
;
2969 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2971 Source
->queue
= NULL
;
2973 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2976 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
2979 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2981 ALbufferlistitem
*BufferList
;
2984 BufferList
= source
->queue
;
2985 while(BufferList
!= NULL
)
2987 ALbufferlistitem
*next
= BufferList
->next
;
2988 if(BufferList
->buffer
!= NULL
)
2989 DecrementRef(&BufferList
->buffer
->ref
);
2990 al_free(BufferList
);
2993 source
->queue
= NULL
;
2997 for(i
= 0;i
< num_sends
;i
++)
2999 if(source
->Send
[i
].Slot
)
3000 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3001 source
->Send
[i
].Slot
= NULL
;
3003 al_free(source
->Send
);
3004 source
->Send
= NULL
;
3008 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
)
3010 struct ALvoiceProps
*props
;
3013 /* Get an unused property container, or allocate a new one as needed. */
3014 props
= ATOMIC_LOAD(&voice
->FreeList
, almemory_order_acquire
);
3016 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3019 struct ALvoiceProps
*next
;
3021 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3022 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice
->FreeList
, &props
, next
,
3023 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3026 /* Copy in current property values. */
3027 props
->Pitch
= source
->Pitch
;
3028 props
->Gain
= source
->Gain
;
3029 props
->OuterGain
= source
->OuterGain
;
3030 props
->MinGain
= source
->MinGain
;
3031 props
->MaxGain
= source
->MaxGain
;
3032 props
->InnerAngle
= source
->InnerAngle
;
3033 props
->OuterAngle
= source
->OuterAngle
;
3034 props
->RefDistance
= source
->RefDistance
;
3035 props
->MaxDistance
= source
->MaxDistance
;
3036 props
->RollOffFactor
= source
->RollOffFactor
;
3037 for(i
= 0;i
< 3;i
++)
3038 props
->Position
[i
] = source
->Position
[i
];
3039 for(i
= 0;i
< 3;i
++)
3040 props
->Velocity
[i
] = source
->Velocity
[i
];
3041 for(i
= 0;i
< 3;i
++)
3042 props
->Direction
[i
] = source
->Direction
[i
];
3043 for(i
= 0;i
< 2;i
++)
3046 for(j
= 0;j
< 3;j
++)
3047 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3049 props
->HeadRelative
= source
->HeadRelative
;
3050 props
->DistanceModel
= source
->DistanceModel
;
3051 props
->DirectChannels
= source
->DirectChannels
;
3053 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3054 props
->WetGainAuto
= source
->WetGainAuto
;
3055 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3056 props
->OuterGainHF
= source
->OuterGainHF
;
3058 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3059 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3060 props
->DopplerFactor
= source
->DopplerFactor
;
3062 props
->StereoPan
[0] = source
->StereoPan
[0];
3063 props
->StereoPan
[1] = source
->StereoPan
[1];
3065 props
->Radius
= source
->Radius
;
3067 props
->Direct
.Gain
= source
->Direct
.Gain
;
3068 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3069 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3070 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3071 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3073 for(i
= 0;i
< num_sends
;i
++)
3075 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3076 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3077 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3078 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3079 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3080 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3083 /* Set the new container for updating internal parameters. */
3084 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3087 /* If there was an unused update container, put it back in the
3090 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &voice
->FreeList
, props
);
3094 void UpdateAllSourceProps(ALCcontext
*context
)
3096 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3099 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3101 ALvoice
*voice
= context
->Voices
[pos
];
3102 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3103 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3104 UpdateSourceProps(source
, voice
, num_sends
);
3109 /* GetSourceSampleOffset
3111 * Gets the current read offset for the given Source, in 32.32 fixed-point
3112 * samples. The offset is relative to the start of the queue (not the start of
3113 * the current buffer).
3115 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3117 ALCdevice
*device
= context
->Device
;
3118 const ALbufferlistitem
*Current
;
3123 ReadLock(&Source
->queue_lock
);
3127 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3129 *clocktime
= GetDeviceClockTime(device
);
3131 voice
= GetSourceVoice(Source
, context
);
3134 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3136 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3137 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3140 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3141 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3145 const ALbufferlistitem
*BufferList
= Source
->queue
;
3146 while(BufferList
&& BufferList
!= Current
)
3148 if(BufferList
->buffer
)
3149 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3150 BufferList
= BufferList
->next
;
3152 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3155 ReadUnlock(&Source
->queue_lock
);
3156 return (ALint64
)readPos
;
3159 /* GetSourceSecOffset
3161 * Gets the current read offset for the given Source, in seconds. The offset is
3162 * relative to the start of the queue (not the start of the current buffer).
3164 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3166 ALCdevice
*device
= context
->Device
;
3167 const ALbufferlistitem
*Current
;
3173 ReadLock(&Source
->queue_lock
);
3177 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3179 *clocktime
= GetDeviceClockTime(device
);
3181 voice
= GetSourceVoice(Source
, context
);
3184 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3186 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3188 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3190 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3191 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3196 const ALbufferlistitem
*BufferList
= Source
->queue
;
3197 const ALbuffer
*BufferFmt
= NULL
;
3198 while(BufferList
&& BufferList
!= Current
)
3200 const ALbuffer
*buffer
= BufferList
->buffer
;
3203 if(!BufferFmt
) BufferFmt
= buffer
;
3204 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3206 BufferList
= BufferList
->next
;
3209 while(BufferList
&& !BufferFmt
)
3211 BufferFmt
= BufferList
->buffer
;
3212 BufferList
= BufferList
->next
;
3214 assert(BufferFmt
!= NULL
);
3216 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3217 (ALdouble
)BufferFmt
->Frequency
;
3220 ReadUnlock(&Source
->queue_lock
);
3226 * Gets the current read offset for the given Source, in the appropriate format
3227 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3228 * queue (not the start of the current buffer).
3230 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3232 ALCdevice
*device
= context
->Device
;
3233 const ALbufferlistitem
*Current
;
3235 ALsizei readPosFrac
;
3240 ReadLock(&Source
->queue_lock
);
3243 readPos
= readPosFrac
= 0;
3244 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3246 voice
= GetSourceVoice(Source
, context
);
3249 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3251 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3252 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3254 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3255 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3260 const ALbufferlistitem
*BufferList
= Source
->queue
;
3261 const ALbuffer
*BufferFmt
= NULL
;
3262 ALboolean readFin
= AL_FALSE
;
3263 ALuint totalBufferLen
= 0;
3265 while(BufferList
!= NULL
)
3267 const ALbuffer
*buffer
;
3268 readFin
= readFin
|| (BufferList
== Current
);
3269 if((buffer
=BufferList
->buffer
) != NULL
)
3271 if(!BufferFmt
) BufferFmt
= buffer
;
3272 totalBufferLen
+= buffer
->SampleLen
;
3273 if(!readFin
) readPos
+= buffer
->SampleLen
;
3275 BufferList
= BufferList
->next
;
3277 assert(BufferFmt
!= NULL
);
3280 readPos
%= totalBufferLen
;
3283 /* Wrap back to 0 */
3284 if(readPos
>= totalBufferLen
)
3285 readPos
= readPosFrac
= 0;
3292 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3295 case AL_SAMPLE_OFFSET
:
3296 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3299 case AL_BYTE_OFFSET
:
3300 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3302 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3303 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3304 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3306 /* Round down to nearest ADPCM block */
3307 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3309 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3311 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3312 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3313 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3315 /* Round down to nearest ADPCM block */
3316 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3320 ALuint FrameSize
= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3321 BufferFmt
->OriginalType
);
3322 offset
= (ALdouble
)(readPos
* FrameSize
);
3328 ReadUnlock(&Source
->queue_lock
);
3335 * Apply the stored playback offset to the Source. This function will update
3336 * the number of buffers "played" given the stored offset.
3338 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3340 ALbufferlistitem
*BufferList
;
3341 const ALbuffer
*Buffer
;
3342 ALuint bufferLen
, totalBufferLen
;
3346 /* Get sample frame offset */
3347 if(!GetSampleOffset(Source
, &offset
, &frac
))
3351 BufferList
= Source
->queue
;
3352 while(BufferList
&& totalBufferLen
<= offset
)
3354 Buffer
= BufferList
->buffer
;
3355 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3357 if(bufferLen
> offset
-totalBufferLen
)
3359 /* Offset is in this buffer */
3360 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3361 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3362 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3366 totalBufferLen
+= bufferLen
;
3368 BufferList
= BufferList
->next
;
3371 /* Offset is out of range of the queue */
3378 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3379 * or Second offset supplied by the application). This takes into account the
3380 * fact that the buffer format may have been modifed since.
3382 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3384 const ALbuffer
*BufferFmt
= NULL
;
3385 const ALbufferlistitem
*BufferList
;
3386 ALdouble dbloff
, dblfrac
;
3388 /* Find the first valid Buffer in the Queue */
3389 BufferList
= Source
->queue
;
3392 if((BufferFmt
=BufferList
->buffer
) != NULL
)
3394 BufferList
= BufferList
->next
;
3398 Source
->OffsetType
= AL_NONE
;
3399 Source
->Offset
= 0.0;
3403 switch(Source
->OffsetType
)
3405 case AL_BYTE_OFFSET
:
3406 /* Determine the ByteOffset (and ensure it is block aligned) */
3407 *offset
= (ALuint
)Source
->Offset
;
3408 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3410 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3411 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3412 *offset
*= BufferFmt
->OriginalAlign
;
3414 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3416 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3417 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3418 *offset
*= BufferFmt
->OriginalAlign
;
3421 *offset
/= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3422 BufferFmt
->OriginalType
);
3426 case AL_SAMPLE_OFFSET
:
3427 dblfrac
= modf(Source
->Offset
, &dbloff
);
3428 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3429 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3433 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3434 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3435 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3438 Source
->OffsetType
= AL_NONE
;
3439 Source
->Offset
= 0.0;
3447 * Destroys all sources in the source map.
3449 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3451 ALCdevice
*device
= Context
->Device
;
3453 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3455 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3456 Context
->SourceMap
.values
[pos
] = NULL
;
3458 DeinitSource(temp
, device
->NumAuxSends
);
3460 FreeThunkEntry(temp
->id
);
3461 memset(temp
, 0, sizeof(*temp
));