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
,
120 /* AL_SOFT_source_resampler */
121 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
124 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
125 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
126 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
128 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
129 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
130 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
132 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
134 ALvoice
**voice
= context
->Voices
;
135 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
136 while(voice
!= voice_end
)
138 if(ATOMIC_LOAD(&(*voice
)->Source
, almemory_order_acquire
) == source
)
146 * Returns if the last known state for the source was playing or paused. Does
147 * not sync with the mixer voice.
149 static inline bool IsPlayingOrPaused(ALsource
*source
)
151 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
152 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
156 * Returns an updated source state using the matching voice's status (or lack
159 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
163 ALenum state
= AL_PLAYING
;
164 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
165 almemory_order_acq_rel
, almemory_order_acquire
))
169 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
173 * Returns if the source should specify an update, given the context's
174 * deferring state and the source's last known state.
176 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
178 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
179 IsPlayingOrPaused(source
);
182 static ALint
FloatValsByProp(ALenum prop
)
184 if(prop
!= (ALenum
)((SourceProp
)prop
))
186 switch((SourceProp
)prop
)
192 case AL_MAX_DISTANCE
:
193 case AL_ROLLOFF_FACTOR
:
194 case AL_DOPPLER_FACTOR
:
195 case AL_CONE_OUTER_GAIN
:
197 case AL_SAMPLE_OFFSET
:
199 case AL_CONE_INNER_ANGLE
:
200 case AL_CONE_OUTER_ANGLE
:
201 case AL_REFERENCE_DISTANCE
:
202 case AL_CONE_OUTER_GAINHF
:
203 case AL_AIR_ABSORPTION_FACTOR
:
204 case AL_ROOM_ROLLOFF_FACTOR
:
205 case AL_DIRECT_FILTER_GAINHF_AUTO
:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
208 case AL_DIRECT_CHANNELS_SOFT
:
209 case AL_DISTANCE_MODEL
:
210 case AL_SOURCE_RELATIVE
:
212 case AL_SOURCE_STATE
:
213 case AL_BUFFERS_QUEUED
:
214 case AL_BUFFERS_PROCESSED
:
216 case AL_BYTE_LENGTH_SOFT
:
217 case AL_SAMPLE_LENGTH_SOFT
:
218 case AL_SEC_LENGTH_SOFT
:
219 case AL_SOURCE_RADIUS
:
220 case AL_SOURCE_RESAMPLER_SOFT
:
223 case AL_STEREO_ANGLES
:
234 case AL_SEC_OFFSET_LATENCY_SOFT
:
235 break; /* Double only */
238 case AL_DIRECT_FILTER
:
239 case AL_AUXILIARY_SEND_FILTER
:
240 break; /* i/i64 only */
241 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
242 break; /* i64 only */
246 static ALint
DoubleValsByProp(ALenum prop
)
248 if(prop
!= (ALenum
)((SourceProp
)prop
))
250 switch((SourceProp
)prop
)
256 case AL_MAX_DISTANCE
:
257 case AL_ROLLOFF_FACTOR
:
258 case AL_DOPPLER_FACTOR
:
259 case AL_CONE_OUTER_GAIN
:
261 case AL_SAMPLE_OFFSET
:
263 case AL_CONE_INNER_ANGLE
:
264 case AL_CONE_OUTER_ANGLE
:
265 case AL_REFERENCE_DISTANCE
:
266 case AL_CONE_OUTER_GAINHF
:
267 case AL_AIR_ABSORPTION_FACTOR
:
268 case AL_ROOM_ROLLOFF_FACTOR
:
269 case AL_DIRECT_FILTER_GAINHF_AUTO
:
270 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
271 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
272 case AL_DIRECT_CHANNELS_SOFT
:
273 case AL_DISTANCE_MODEL
:
274 case AL_SOURCE_RELATIVE
:
276 case AL_SOURCE_STATE
:
277 case AL_BUFFERS_QUEUED
:
278 case AL_BUFFERS_PROCESSED
:
280 case AL_BYTE_LENGTH_SOFT
:
281 case AL_SAMPLE_LENGTH_SOFT
:
282 case AL_SEC_LENGTH_SOFT
:
283 case AL_SOURCE_RADIUS
:
284 case AL_SOURCE_RESAMPLER_SOFT
:
287 case AL_SEC_OFFSET_LATENCY_SOFT
:
288 case AL_STEREO_ANGLES
:
300 case AL_DIRECT_FILTER
:
301 case AL_AUXILIARY_SEND_FILTER
:
302 break; /* i/i64 only */
303 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
304 break; /* i64 only */
309 static ALint
IntValsByProp(ALenum prop
)
311 if(prop
!= (ALenum
)((SourceProp
)prop
))
313 switch((SourceProp
)prop
)
319 case AL_MAX_DISTANCE
:
320 case AL_ROLLOFF_FACTOR
:
321 case AL_DOPPLER_FACTOR
:
322 case AL_CONE_OUTER_GAIN
:
324 case AL_SAMPLE_OFFSET
:
326 case AL_CONE_INNER_ANGLE
:
327 case AL_CONE_OUTER_ANGLE
:
328 case AL_REFERENCE_DISTANCE
:
329 case AL_CONE_OUTER_GAINHF
:
330 case AL_AIR_ABSORPTION_FACTOR
:
331 case AL_ROOM_ROLLOFF_FACTOR
:
332 case AL_DIRECT_FILTER_GAINHF_AUTO
:
333 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
334 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
335 case AL_DIRECT_CHANNELS_SOFT
:
336 case AL_DISTANCE_MODEL
:
337 case AL_SOURCE_RELATIVE
:
340 case AL_SOURCE_STATE
:
341 case AL_BUFFERS_QUEUED
:
342 case AL_BUFFERS_PROCESSED
:
344 case AL_DIRECT_FILTER
:
345 case AL_BYTE_LENGTH_SOFT
:
346 case AL_SAMPLE_LENGTH_SOFT
:
347 case AL_SEC_LENGTH_SOFT
:
348 case AL_SOURCE_RADIUS
:
349 case AL_SOURCE_RESAMPLER_SOFT
:
355 case AL_AUXILIARY_SEND_FILTER
:
361 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
362 break; /* i64 only */
363 case AL_SEC_OFFSET_LATENCY_SOFT
:
364 break; /* Double only */
365 case AL_STEREO_ANGLES
:
366 break; /* Float/double only */
370 static ALint
Int64ValsByProp(ALenum prop
)
372 if(prop
!= (ALenum
)((SourceProp
)prop
))
374 switch((SourceProp
)prop
)
380 case AL_MAX_DISTANCE
:
381 case AL_ROLLOFF_FACTOR
:
382 case AL_DOPPLER_FACTOR
:
383 case AL_CONE_OUTER_GAIN
:
385 case AL_SAMPLE_OFFSET
:
387 case AL_CONE_INNER_ANGLE
:
388 case AL_CONE_OUTER_ANGLE
:
389 case AL_REFERENCE_DISTANCE
:
390 case AL_CONE_OUTER_GAINHF
:
391 case AL_AIR_ABSORPTION_FACTOR
:
392 case AL_ROOM_ROLLOFF_FACTOR
:
393 case AL_DIRECT_FILTER_GAINHF_AUTO
:
394 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
395 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
396 case AL_DIRECT_CHANNELS_SOFT
:
397 case AL_DISTANCE_MODEL
:
398 case AL_SOURCE_RELATIVE
:
401 case AL_SOURCE_STATE
:
402 case AL_BUFFERS_QUEUED
:
403 case AL_BUFFERS_PROCESSED
:
405 case AL_DIRECT_FILTER
:
406 case AL_BYTE_LENGTH_SOFT
:
407 case AL_SAMPLE_LENGTH_SOFT
:
408 case AL_SEC_LENGTH_SOFT
:
409 case AL_SOURCE_RADIUS
:
410 case AL_SOURCE_RESAMPLER_SOFT
:
413 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
419 case AL_AUXILIARY_SEND_FILTER
:
425 case AL_SEC_OFFSET_LATENCY_SOFT
:
426 break; /* Double only */
427 case AL_STEREO_ANGLES
:
428 break; /* Float/double only */
434 #define CHECKVAL(x) do { \
436 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
439 #define DO_UPDATEPROPS() do { \
441 if(SourceShouldUpdate(Source, Context) && \
442 (voice=GetSourceVoice(Source, Context)) != NULL) \
443 UpdateSourceProps(Source, voice, device->NumAuxSends); \
445 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
448 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
450 ALCdevice
*device
= Context
->Device
;
455 case AL_BYTE_LENGTH_SOFT
:
456 case AL_SAMPLE_LENGTH_SOFT
:
457 case AL_SEC_LENGTH_SOFT
:
458 case AL_SEC_OFFSET_LATENCY_SOFT
:
460 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
463 CHECKVAL(*values
>= 0.0f
);
465 Source
->Pitch
= *values
;
469 case AL_CONE_INNER_ANGLE
:
470 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
472 Source
->InnerAngle
= *values
;
476 case AL_CONE_OUTER_ANGLE
:
477 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
479 Source
->OuterAngle
= *values
;
484 CHECKVAL(*values
>= 0.0f
);
486 Source
->Gain
= *values
;
490 case AL_MAX_DISTANCE
:
491 CHECKVAL(*values
>= 0.0f
);
493 Source
->MaxDistance
= *values
;
497 case AL_ROLLOFF_FACTOR
:
498 CHECKVAL(*values
>= 0.0f
);
500 Source
->RollOffFactor
= *values
;
504 case AL_REFERENCE_DISTANCE
:
505 CHECKVAL(*values
>= 0.0f
);
507 Source
->RefDistance
= *values
;
512 CHECKVAL(*values
>= 0.0f
);
514 Source
->MinGain
= *values
;
519 CHECKVAL(*values
>= 0.0f
);
521 Source
->MaxGain
= *values
;
525 case AL_CONE_OUTER_GAIN
:
526 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
528 Source
->OuterGain
= *values
;
532 case AL_CONE_OUTER_GAINHF
:
533 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
535 Source
->OuterGainHF
= *values
;
539 case AL_AIR_ABSORPTION_FACTOR
:
540 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
542 Source
->AirAbsorptionFactor
= *values
;
546 case AL_ROOM_ROLLOFF_FACTOR
:
547 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
549 Source
->RoomRolloffFactor
= *values
;
553 case AL_DOPPLER_FACTOR
:
554 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
556 Source
->DopplerFactor
= *values
;
561 case AL_SAMPLE_OFFSET
:
563 CHECKVAL(*values
>= 0.0f
);
565 Source
->OffsetType
= prop
;
566 Source
->Offset
= *values
;
568 if(IsPlayingOrPaused(Source
))
572 ALCdevice_Lock(Context
->Device
);
573 /* Double-check that the source is still playing while we have
576 voice
= GetSourceVoice(Source
, Context
);
579 WriteLock(&Source
->queue_lock
);
580 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
582 WriteUnlock(&Source
->queue_lock
);
583 ALCdevice_Unlock(Context
->Device
);
584 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
586 WriteUnlock(&Source
->queue_lock
);
588 ALCdevice_Unlock(Context
->Device
);
592 case AL_SOURCE_RADIUS
:
593 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
595 Source
->Radius
= *values
;
599 case AL_STEREO_ANGLES
:
600 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
602 Source
->StereoPan
[0] = values
[0];
603 Source
->StereoPan
[1] = values
[1];
609 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
611 Source
->Position
[0] = values
[0];
612 Source
->Position
[1] = values
[1];
613 Source
->Position
[2] = values
[2];
618 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
620 Source
->Velocity
[0] = values
[0];
621 Source
->Velocity
[1] = values
[1];
622 Source
->Velocity
[2] = values
[2];
627 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
629 Source
->Direction
[0] = values
[0];
630 Source
->Direction
[1] = values
[1];
631 Source
->Direction
[2] = values
[2];
636 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
637 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
639 Source
->Orientation
[0][0] = values
[0];
640 Source
->Orientation
[0][1] = values
[1];
641 Source
->Orientation
[0][2] = values
[2];
642 Source
->Orientation
[1][0] = values
[3];
643 Source
->Orientation
[1][1] = values
[4];
644 Source
->Orientation
[1][2] = values
[5];
649 case AL_SOURCE_RELATIVE
:
651 case AL_SOURCE_STATE
:
653 case AL_DISTANCE_MODEL
:
654 case AL_DIRECT_FILTER_GAINHF_AUTO
:
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
656 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
657 case AL_DIRECT_CHANNELS_SOFT
:
658 case AL_SOURCE_RESAMPLER_SOFT
:
659 ival
= (ALint
)values
[0];
660 return SetSourceiv(Source
, Context
, prop
, &ival
);
662 case AL_BUFFERS_QUEUED
:
663 case AL_BUFFERS_PROCESSED
:
664 ival
= (ALint
)((ALuint
)values
[0]);
665 return SetSourceiv(Source
, Context
, prop
, &ival
);
668 case AL_DIRECT_FILTER
:
669 case AL_AUXILIARY_SEND_FILTER
:
670 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
674 ERR("Unexpected property: 0x%04x\n", prop
);
675 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
678 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
680 ALCdevice
*device
= Context
->Device
;
681 ALbuffer
*buffer
= NULL
;
682 ALfilter
*filter
= NULL
;
683 ALeffectslot
*slot
= NULL
;
684 ALbufferlistitem
*oldlist
;
689 case AL_SOURCE_STATE
:
691 case AL_BUFFERS_QUEUED
:
692 case AL_BUFFERS_PROCESSED
:
693 case AL_BYTE_LENGTH_SOFT
:
694 case AL_SAMPLE_LENGTH_SOFT
:
695 case AL_SEC_LENGTH_SOFT
:
697 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
699 case AL_SOURCE_RELATIVE
:
700 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
702 Source
->HeadRelative
= (ALboolean
)*values
;
707 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
709 WriteLock(&Source
->queue_lock
);
710 Source
->Looping
= (ALboolean
)*values
;
711 if(IsPlayingOrPaused(Source
))
713 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
717 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
719 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
721 /* If the source is playing, wait for the current mix to finish
722 * to ensure it isn't currently looping back or reaching the
725 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
729 WriteUnlock(&Source
->queue_lock
);
733 LockBuffersRead(device
);
734 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
736 UnlockBuffersRead(device
);
737 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
740 WriteLock(&Source
->queue_lock
);
742 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
743 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
745 WriteUnlock(&Source
->queue_lock
);
746 UnlockBuffersRead(device
);
747 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
751 oldlist
= Source
->queue
;
754 /* Add the selected buffer to a one-item queue */
755 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
756 newlist
->buffer
= buffer
;
757 ATOMIC_INIT(&newlist
->next
, NULL
);
758 IncrementRef(&buffer
->ref
);
760 /* Source is now Static */
761 Source
->SourceType
= AL_STATIC
;
762 Source
->queue
= newlist
;
766 /* Source is now Undetermined */
767 Source
->SourceType
= AL_UNDETERMINED
;
768 Source
->queue
= NULL
;
770 WriteUnlock(&Source
->queue_lock
);
771 UnlockBuffersRead(device
);
773 /* Delete all elements in the previous queue */
774 while(oldlist
!= NULL
)
776 ALbufferlistitem
*temp
= oldlist
;
777 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
780 DecrementRef(&temp
->buffer
->ref
);
786 case AL_SAMPLE_OFFSET
:
788 CHECKVAL(*values
>= 0);
790 Source
->OffsetType
= prop
;
791 Source
->Offset
= *values
;
793 if(IsPlayingOrPaused(Source
))
797 ALCdevice_Lock(Context
->Device
);
798 voice
= GetSourceVoice(Source
, Context
);
801 WriteLock(&Source
->queue_lock
);
802 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
804 WriteUnlock(&Source
->queue_lock
);
805 ALCdevice_Unlock(Context
->Device
);
806 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
808 WriteUnlock(&Source
->queue_lock
);
810 ALCdevice_Unlock(Context
->Device
);
814 case AL_DIRECT_FILTER
:
815 LockFiltersRead(device
);
816 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
818 UnlockFiltersRead(device
);
819 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
824 Source
->Direct
.Gain
= 1.0f
;
825 Source
->Direct
.GainHF
= 1.0f
;
826 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
827 Source
->Direct
.GainLF
= 1.0f
;
828 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
832 Source
->Direct
.Gain
= filter
->Gain
;
833 Source
->Direct
.GainHF
= filter
->GainHF
;
834 Source
->Direct
.HFReference
= filter
->HFReference
;
835 Source
->Direct
.GainLF
= filter
->GainLF
;
836 Source
->Direct
.LFReference
= filter
->LFReference
;
838 UnlockFiltersRead(device
);
842 case AL_DIRECT_FILTER_GAINHF_AUTO
:
843 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
845 Source
->DryGainHFAuto
= *values
;
849 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
850 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
852 Source
->WetGainAuto
= *values
;
856 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
857 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
859 Source
->WetGainHFAuto
= *values
;
863 case AL_DIRECT_CHANNELS_SOFT
:
864 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
866 Source
->DirectChannels
= *values
;
870 case AL_DISTANCE_MODEL
:
871 CHECKVAL(*values
== AL_NONE
||
872 *values
== AL_INVERSE_DISTANCE
||
873 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
874 *values
== AL_LINEAR_DISTANCE
||
875 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
876 *values
== AL_EXPONENT_DISTANCE
||
877 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
879 Source
->DistanceModel
= *values
;
880 if(Context
->SourceDistanceModel
)
884 case AL_SOURCE_RESAMPLER_SOFT
:
885 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
887 Source
->Resampler
= *values
;
892 case AL_AUXILIARY_SEND_FILTER
:
893 LockEffectSlotsRead(Context
);
894 LockFiltersRead(device
);
895 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
896 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
897 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
899 UnlockFiltersRead(device
);
900 UnlockEffectSlotsRead(Context
);
901 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
907 Source
->Send
[values
[1]].Gain
= 1.0f
;
908 Source
->Send
[values
[1]].GainHF
= 1.0f
;
909 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
910 Source
->Send
[values
[1]].GainLF
= 1.0f
;
911 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
915 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
916 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
917 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
918 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
919 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
921 UnlockFiltersRead(device
);
923 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
926 /* Add refcount on the new slot, and release the previous slot */
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
;
932 /* We must force an update if the auxiliary slot changed on an
933 * active source, in case the slot is about to be deleted.
935 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
936 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
);
938 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
942 if(slot
) IncrementRef(&slot
->ref
);
943 if(Source
->Send
[values
[1]].Slot
)
944 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
945 Source
->Send
[values
[1]].Slot
= slot
;
948 UnlockEffectSlotsRead(Context
);
954 case AL_CONE_INNER_ANGLE
:
955 case AL_CONE_OUTER_ANGLE
:
960 case AL_REFERENCE_DISTANCE
:
961 case AL_ROLLOFF_FACTOR
:
962 case AL_CONE_OUTER_GAIN
:
963 case AL_MAX_DISTANCE
:
964 case AL_DOPPLER_FACTOR
:
965 case AL_CONE_OUTER_GAINHF
:
966 case AL_AIR_ABSORPTION_FACTOR
:
967 case AL_ROOM_ROLLOFF_FACTOR
:
968 case AL_SOURCE_RADIUS
:
969 fvals
[0] = (ALfloat
)*values
;
970 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
976 fvals
[0] = (ALfloat
)values
[0];
977 fvals
[1] = (ALfloat
)values
[1];
978 fvals
[2] = (ALfloat
)values
[2];
979 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
983 fvals
[0] = (ALfloat
)values
[0];
984 fvals
[1] = (ALfloat
)values
[1];
985 fvals
[2] = (ALfloat
)values
[2];
986 fvals
[3] = (ALfloat
)values
[3];
987 fvals
[4] = (ALfloat
)values
[4];
988 fvals
[5] = (ALfloat
)values
[5];
989 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
991 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
992 case AL_SEC_OFFSET_LATENCY_SOFT
:
993 case AL_STEREO_ANGLES
:
997 ERR("Unexpected property: 0x%04x\n", prop
);
998 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1001 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1008 case AL_SOURCE_TYPE
:
1009 case AL_BUFFERS_QUEUED
:
1010 case AL_BUFFERS_PROCESSED
:
1011 case AL_SOURCE_STATE
:
1012 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1013 case AL_BYTE_LENGTH_SOFT
:
1014 case AL_SAMPLE_LENGTH_SOFT
:
1015 case AL_SEC_LENGTH_SOFT
:
1017 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
1021 case AL_SOURCE_RELATIVE
:
1024 case AL_SAMPLE_OFFSET
:
1025 case AL_BYTE_OFFSET
:
1026 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1027 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1028 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1029 case AL_DIRECT_CHANNELS_SOFT
:
1030 case AL_DISTANCE_MODEL
:
1031 case AL_SOURCE_RESAMPLER_SOFT
:
1032 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1034 ivals
[0] = (ALint
)*values
;
1035 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1039 case AL_DIRECT_FILTER
:
1040 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1042 ivals
[0] = (ALuint
)*values
;
1043 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1046 case AL_AUXILIARY_SEND_FILTER
:
1047 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1048 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1049 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1051 ivals
[0] = (ALuint
)values
[0];
1052 ivals
[1] = (ALuint
)values
[1];
1053 ivals
[2] = (ALuint
)values
[2];
1054 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1057 case AL_CONE_INNER_ANGLE
:
1058 case AL_CONE_OUTER_ANGLE
:
1063 case AL_REFERENCE_DISTANCE
:
1064 case AL_ROLLOFF_FACTOR
:
1065 case AL_CONE_OUTER_GAIN
:
1066 case AL_MAX_DISTANCE
:
1067 case AL_DOPPLER_FACTOR
:
1068 case AL_CONE_OUTER_GAINHF
:
1069 case AL_AIR_ABSORPTION_FACTOR
:
1070 case AL_ROOM_ROLLOFF_FACTOR
:
1071 case AL_SOURCE_RADIUS
:
1072 fvals
[0] = (ALfloat
)*values
;
1073 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1079 fvals
[0] = (ALfloat
)values
[0];
1080 fvals
[1] = (ALfloat
)values
[1];
1081 fvals
[2] = (ALfloat
)values
[2];
1082 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1085 case AL_ORIENTATION
:
1086 fvals
[0] = (ALfloat
)values
[0];
1087 fvals
[1] = (ALfloat
)values
[1];
1088 fvals
[2] = (ALfloat
)values
[2];
1089 fvals
[3] = (ALfloat
)values
[3];
1090 fvals
[4] = (ALfloat
)values
[4];
1091 fvals
[5] = (ALfloat
)values
[5];
1092 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1094 case AL_SEC_OFFSET_LATENCY_SOFT
:
1095 case AL_STEREO_ANGLES
:
1099 ERR("Unexpected property: 0x%04x\n", prop
);
1100 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1106 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1108 ALCdevice
*device
= Context
->Device
;
1109 ALbufferlistitem
*BufferList
;
1110 ClockLatency clocktime
;
1118 *values
= Source
->Gain
;
1122 *values
= Source
->Pitch
;
1125 case AL_MAX_DISTANCE
:
1126 *values
= Source
->MaxDistance
;
1129 case AL_ROLLOFF_FACTOR
:
1130 *values
= Source
->RollOffFactor
;
1133 case AL_REFERENCE_DISTANCE
:
1134 *values
= Source
->RefDistance
;
1137 case AL_CONE_INNER_ANGLE
:
1138 *values
= Source
->InnerAngle
;
1141 case AL_CONE_OUTER_ANGLE
:
1142 *values
= Source
->OuterAngle
;
1146 *values
= Source
->MinGain
;
1150 *values
= Source
->MaxGain
;
1153 case AL_CONE_OUTER_GAIN
:
1154 *values
= Source
->OuterGain
;
1158 case AL_SAMPLE_OFFSET
:
1159 case AL_BYTE_OFFSET
:
1160 *values
= GetSourceOffset(Source
, prop
, Context
);
1163 case AL_CONE_OUTER_GAINHF
:
1164 *values
= Source
->OuterGainHF
;
1167 case AL_AIR_ABSORPTION_FACTOR
:
1168 *values
= Source
->AirAbsorptionFactor
;
1171 case AL_ROOM_ROLLOFF_FACTOR
:
1172 *values
= Source
->RoomRolloffFactor
;
1175 case AL_DOPPLER_FACTOR
:
1176 *values
= Source
->DopplerFactor
;
1179 case AL_SEC_LENGTH_SOFT
:
1180 ReadLock(&Source
->queue_lock
);
1181 if(!(BufferList
=Source
->queue
))
1188 ALbuffer
*buffer
= BufferList
->buffer
;
1189 if(buffer
&& buffer
->SampleLen
> 0)
1191 freq
= buffer
->Frequency
;
1192 length
+= buffer
->SampleLen
;
1194 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1195 } while(BufferList
!= NULL
);
1196 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1198 ReadUnlock(&Source
->queue_lock
);
1201 case AL_SOURCE_RADIUS
:
1202 *values
= Source
->Radius
;
1205 case AL_STEREO_ANGLES
:
1206 values
[0] = Source
->StereoPan
[0];
1207 values
[1] = Source
->StereoPan
[1];
1210 case AL_SEC_OFFSET_LATENCY_SOFT
:
1211 /* Get the source offset with the clock time first. Then get the
1212 * clock time with the device latency. Order is important.
1214 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1215 clocktime
= V0(device
->Backend
,getClockLatency
)();
1216 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1217 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1220 /* If the clock time incremented, reduce the latency by that
1221 * much since it's that much closer to the source offset it got
1224 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1225 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1231 values
[0] = Source
->Position
[0];
1232 values
[1] = Source
->Position
[1];
1233 values
[2] = Source
->Position
[2];
1237 values
[0] = Source
->Velocity
[0];
1238 values
[1] = Source
->Velocity
[1];
1239 values
[2] = Source
->Velocity
[2];
1243 values
[0] = Source
->Direction
[0];
1244 values
[1] = Source
->Direction
[1];
1245 values
[2] = Source
->Direction
[2];
1248 case AL_ORIENTATION
:
1249 values
[0] = Source
->Orientation
[0][0];
1250 values
[1] = Source
->Orientation
[0][1];
1251 values
[2] = Source
->Orientation
[0][2];
1252 values
[3] = Source
->Orientation
[1][0];
1253 values
[4] = Source
->Orientation
[1][1];
1254 values
[5] = Source
->Orientation
[1][2];
1258 case AL_SOURCE_RELATIVE
:
1260 case AL_SOURCE_STATE
:
1261 case AL_BUFFERS_QUEUED
:
1262 case AL_BUFFERS_PROCESSED
:
1263 case AL_SOURCE_TYPE
:
1264 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1265 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1266 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1267 case AL_DIRECT_CHANNELS_SOFT
:
1268 case AL_BYTE_LENGTH_SOFT
:
1269 case AL_SAMPLE_LENGTH_SOFT
:
1270 case AL_DISTANCE_MODEL
:
1271 case AL_SOURCE_RESAMPLER_SOFT
:
1272 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1273 *values
= (ALdouble
)ivals
[0];
1277 case AL_DIRECT_FILTER
:
1278 case AL_AUXILIARY_SEND_FILTER
:
1279 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1283 ERR("Unexpected property: 0x%04x\n", prop
);
1284 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1287 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1289 ALbufferlistitem
*BufferList
;
1295 case AL_SOURCE_RELATIVE
:
1296 *values
= Source
->HeadRelative
;
1300 *values
= Source
->Looping
;
1304 ReadLock(&Source
->queue_lock
);
1305 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1306 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1307 ReadUnlock(&Source
->queue_lock
);
1310 case AL_SOURCE_STATE
:
1311 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1314 case AL_BYTE_LENGTH_SOFT
:
1315 ReadLock(&Source
->queue_lock
);
1316 if(!(BufferList
=Source
->queue
))
1322 ALbuffer
*buffer
= BufferList
->buffer
;
1323 if(buffer
&& buffer
->SampleLen
> 0)
1325 ALuint byte_align
, sample_align
;
1326 if(buffer
->OriginalType
== UserFmtIMA4
)
1328 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1329 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1330 sample_align
= buffer
->OriginalAlign
;
1332 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1334 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1335 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1336 sample_align
= buffer
->OriginalAlign
;
1340 ALsizei align
= buffer
->OriginalAlign
;
1341 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1342 sample_align
= buffer
->OriginalAlign
;
1345 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1347 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1348 } while(BufferList
!= NULL
);
1351 ReadUnlock(&Source
->queue_lock
);
1354 case AL_SAMPLE_LENGTH_SOFT
:
1355 ReadLock(&Source
->queue_lock
);
1356 if(!(BufferList
=Source
->queue
))
1362 ALbuffer
*buffer
= BufferList
->buffer
;
1363 if(buffer
) length
+= buffer
->SampleLen
;
1364 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1365 } while(BufferList
!= NULL
);
1368 ReadUnlock(&Source
->queue_lock
);
1371 case AL_BUFFERS_QUEUED
:
1372 ReadLock(&Source
->queue_lock
);
1373 if(!(BufferList
=Source
->queue
))
1380 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1381 } while(BufferList
!= NULL
);
1384 ReadUnlock(&Source
->queue_lock
);
1387 case AL_BUFFERS_PROCESSED
:
1388 ReadLock(&Source
->queue_lock
);
1389 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1391 /* Buffers on a looping source are in a perpetual state of
1392 * PENDING, so don't report any as PROCESSED */
1397 const ALbufferlistitem
*BufferList
= Source
->queue
;
1398 const ALbufferlistitem
*Current
= NULL
;
1402 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1403 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1404 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1405 Current
= BufferList
;
1407 while(BufferList
&& BufferList
!= Current
)
1410 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1411 almemory_order_relaxed
);
1415 ReadUnlock(&Source
->queue_lock
);
1418 case AL_SOURCE_TYPE
:
1419 *values
= Source
->SourceType
;
1422 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1423 *values
= Source
->DryGainHFAuto
;
1426 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1427 *values
= Source
->WetGainAuto
;
1430 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1431 *values
= Source
->WetGainHFAuto
;
1434 case AL_DIRECT_CHANNELS_SOFT
:
1435 *values
= Source
->DirectChannels
;
1438 case AL_DISTANCE_MODEL
:
1439 *values
= Source
->DistanceModel
;
1442 case AL_SOURCE_RESAMPLER_SOFT
:
1443 *values
= Source
->Resampler
;
1446 /* 1x float/double */
1447 case AL_CONE_INNER_ANGLE
:
1448 case AL_CONE_OUTER_ANGLE
:
1453 case AL_REFERENCE_DISTANCE
:
1454 case AL_ROLLOFF_FACTOR
:
1455 case AL_CONE_OUTER_GAIN
:
1456 case AL_MAX_DISTANCE
:
1458 case AL_SAMPLE_OFFSET
:
1459 case AL_BYTE_OFFSET
:
1460 case AL_DOPPLER_FACTOR
:
1461 case AL_AIR_ABSORPTION_FACTOR
:
1462 case AL_ROOM_ROLLOFF_FACTOR
:
1463 case AL_CONE_OUTER_GAINHF
:
1464 case AL_SEC_LENGTH_SOFT
:
1465 case AL_SOURCE_RADIUS
:
1466 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1467 *values
= (ALint
)dvals
[0];
1470 /* 3x float/double */
1474 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1476 values
[0] = (ALint
)dvals
[0];
1477 values
[1] = (ALint
)dvals
[1];
1478 values
[2] = (ALint
)dvals
[2];
1482 /* 6x float/double */
1483 case AL_ORIENTATION
:
1484 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1486 values
[0] = (ALint
)dvals
[0];
1487 values
[1] = (ALint
)dvals
[1];
1488 values
[2] = (ALint
)dvals
[2];
1489 values
[3] = (ALint
)dvals
[3];
1490 values
[4] = (ALint
)dvals
[4];
1491 values
[5] = (ALint
)dvals
[5];
1495 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1496 break; /* i64 only */
1497 case AL_SEC_OFFSET_LATENCY_SOFT
:
1498 break; /* Double only */
1499 case AL_STEREO_ANGLES
:
1500 break; /* Float/double only */
1502 case AL_DIRECT_FILTER
:
1503 case AL_AUXILIARY_SEND_FILTER
:
1507 ERR("Unexpected property: 0x%04x\n", prop
);
1508 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1511 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1513 ALCdevice
*device
= Context
->Device
;
1514 ClockLatency clocktime
;
1522 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1523 /* Get the source offset with the clock time first. Then get the
1524 * clock time with the device latency. Order is important.
1526 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1527 clocktime
= V0(device
->Backend
,getClockLatency
)();
1528 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1529 values
[1] = clocktime
.Latency
;
1532 /* If the clock time incremented, reduce the latency by that
1533 * much since it's that much closer to the source offset it got
1536 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1537 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1541 /* 1x float/double */
1542 case AL_CONE_INNER_ANGLE
:
1543 case AL_CONE_OUTER_ANGLE
:
1548 case AL_REFERENCE_DISTANCE
:
1549 case AL_ROLLOFF_FACTOR
:
1550 case AL_CONE_OUTER_GAIN
:
1551 case AL_MAX_DISTANCE
:
1553 case AL_SAMPLE_OFFSET
:
1554 case AL_BYTE_OFFSET
:
1555 case AL_DOPPLER_FACTOR
:
1556 case AL_AIR_ABSORPTION_FACTOR
:
1557 case AL_ROOM_ROLLOFF_FACTOR
:
1558 case AL_CONE_OUTER_GAINHF
:
1559 case AL_SEC_LENGTH_SOFT
:
1560 case AL_SOURCE_RADIUS
:
1561 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1562 *values
= (ALint64
)dvals
[0];
1565 /* 3x float/double */
1569 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1571 values
[0] = (ALint64
)dvals
[0];
1572 values
[1] = (ALint64
)dvals
[1];
1573 values
[2] = (ALint64
)dvals
[2];
1577 /* 6x float/double */
1578 case AL_ORIENTATION
:
1579 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1581 values
[0] = (ALint64
)dvals
[0];
1582 values
[1] = (ALint64
)dvals
[1];
1583 values
[2] = (ALint64
)dvals
[2];
1584 values
[3] = (ALint64
)dvals
[3];
1585 values
[4] = (ALint64
)dvals
[4];
1586 values
[5] = (ALint64
)dvals
[5];
1591 case AL_SOURCE_RELATIVE
:
1593 case AL_SOURCE_STATE
:
1594 case AL_BUFFERS_QUEUED
:
1595 case AL_BUFFERS_PROCESSED
:
1596 case AL_BYTE_LENGTH_SOFT
:
1597 case AL_SAMPLE_LENGTH_SOFT
:
1598 case AL_SOURCE_TYPE
:
1599 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1600 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1601 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1602 case AL_DIRECT_CHANNELS_SOFT
:
1603 case AL_DISTANCE_MODEL
:
1604 case AL_SOURCE_RESAMPLER_SOFT
:
1605 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1611 case AL_DIRECT_FILTER
:
1612 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1613 *values
= (ALuint
)ivals
[0];
1617 case AL_AUXILIARY_SEND_FILTER
:
1618 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1620 values
[0] = (ALuint
)ivals
[0];
1621 values
[1] = (ALuint
)ivals
[1];
1622 values
[2] = (ALuint
)ivals
[2];
1626 case AL_SEC_OFFSET_LATENCY_SOFT
:
1627 break; /* Double only */
1628 case AL_STEREO_ANGLES
:
1629 break; /* Float/double only */
1632 ERR("Unexpected property: 0x%04x\n", prop
);
1633 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1637 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1640 ALCcontext
*context
;
1644 context
= GetContextRef();
1645 if(!context
) return;
1648 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1649 device
= context
->Device
;
1650 for(cur
= 0;cur
< n
;cur
++)
1652 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1655 alDeleteSources(cur
, sources
);
1656 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1658 InitSourceParams(source
, device
->NumAuxSends
);
1660 err
= NewThunkEntry(&source
->id
);
1661 if(err
== AL_NO_ERROR
)
1662 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1663 if(err
!= AL_NO_ERROR
)
1665 FreeThunkEntry(source
->id
);
1666 memset(source
, 0, sizeof(ALsource
));
1669 alDeleteSources(cur
, sources
);
1670 SET_ERROR_AND_GOTO(context
, err
, done
);
1673 sources
[cur
] = source
->id
;
1677 ALCcontext_DecRef(context
);
1681 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1684 ALCcontext
*context
;
1688 context
= GetContextRef();
1689 if(!context
) return;
1691 LockSourcesWrite(context
);
1693 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1695 /* Check that all Sources are valid */
1696 for(i
= 0;i
< n
;i
++)
1698 if(LookupSource(context
, sources
[i
]) == NULL
)
1699 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1701 device
= context
->Device
;
1702 for(i
= 0;i
< n
;i
++)
1706 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1708 FreeThunkEntry(Source
->id
);
1710 ALCdevice_Lock(device
);
1711 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1713 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1714 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1716 ALCdevice_Unlock(device
);
1718 DeinitSource(Source
, device
->NumAuxSends
);
1720 memset(Source
, 0, sizeof(*Source
));
1725 UnlockSourcesWrite(context
);
1726 ALCcontext_DecRef(context
);
1730 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1732 ALCcontext
*context
;
1735 context
= GetContextRef();
1736 if(!context
) return AL_FALSE
;
1738 LockSourcesRead(context
);
1739 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1740 UnlockSourcesRead(context
);
1742 ALCcontext_DecRef(context
);
1748 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1750 ALCcontext
*Context
;
1753 Context
= GetContextRef();
1754 if(!Context
) return;
1756 WriteLock(&Context
->PropLock
);
1757 LockSourcesRead(Context
);
1758 if((Source
=LookupSource(Context
, source
)) == NULL
)
1759 alSetError(Context
, AL_INVALID_NAME
);
1760 else if(!(FloatValsByProp(param
) == 1))
1761 alSetError(Context
, AL_INVALID_ENUM
);
1763 SetSourcefv(Source
, Context
, param
, &value
);
1764 UnlockSourcesRead(Context
);
1765 WriteUnlock(&Context
->PropLock
);
1767 ALCcontext_DecRef(Context
);
1770 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1772 ALCcontext
*Context
;
1775 Context
= GetContextRef();
1776 if(!Context
) return;
1778 WriteLock(&Context
->PropLock
);
1779 LockSourcesRead(Context
);
1780 if((Source
=LookupSource(Context
, source
)) == NULL
)
1781 alSetError(Context
, AL_INVALID_NAME
);
1782 else if(!(FloatValsByProp(param
) == 3))
1783 alSetError(Context
, AL_INVALID_ENUM
);
1786 ALfloat fvals
[3] = { value1
, value2
, value3
};
1787 SetSourcefv(Source
, Context
, param
, fvals
);
1789 UnlockSourcesRead(Context
);
1790 WriteUnlock(&Context
->PropLock
);
1792 ALCcontext_DecRef(Context
);
1795 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1797 ALCcontext
*Context
;
1800 Context
= GetContextRef();
1801 if(!Context
) return;
1803 WriteLock(&Context
->PropLock
);
1804 LockSourcesRead(Context
);
1805 if((Source
=LookupSource(Context
, source
)) == NULL
)
1806 alSetError(Context
, AL_INVALID_NAME
);
1808 alSetError(Context
, AL_INVALID_VALUE
);
1809 else if(!(FloatValsByProp(param
) > 0))
1810 alSetError(Context
, AL_INVALID_ENUM
);
1812 SetSourcefv(Source
, Context
, param
, values
);
1813 UnlockSourcesRead(Context
);
1814 WriteUnlock(&Context
->PropLock
);
1816 ALCcontext_DecRef(Context
);
1820 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1822 ALCcontext
*Context
;
1825 Context
= GetContextRef();
1826 if(!Context
) return;
1828 WriteLock(&Context
->PropLock
);
1829 LockSourcesRead(Context
);
1830 if((Source
=LookupSource(Context
, source
)) == NULL
)
1831 alSetError(Context
, AL_INVALID_NAME
);
1832 else if(!(DoubleValsByProp(param
) == 1))
1833 alSetError(Context
, AL_INVALID_ENUM
);
1836 ALfloat fval
= (ALfloat
)value
;
1837 SetSourcefv(Source
, Context
, param
, &fval
);
1839 UnlockSourcesRead(Context
);
1840 WriteUnlock(&Context
->PropLock
);
1842 ALCcontext_DecRef(Context
);
1845 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1847 ALCcontext
*Context
;
1850 Context
= GetContextRef();
1851 if(!Context
) return;
1853 WriteLock(&Context
->PropLock
);
1854 LockSourcesRead(Context
);
1855 if((Source
=LookupSource(Context
, source
)) == NULL
)
1856 alSetError(Context
, AL_INVALID_NAME
);
1857 else if(!(DoubleValsByProp(param
) == 3))
1858 alSetError(Context
, AL_INVALID_ENUM
);
1861 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1862 SetSourcefv(Source
, Context
, param
, fvals
);
1864 UnlockSourcesRead(Context
);
1865 WriteUnlock(&Context
->PropLock
);
1867 ALCcontext_DecRef(Context
);
1870 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1872 ALCcontext
*Context
;
1876 Context
= GetContextRef();
1877 if(!Context
) return;
1879 WriteLock(&Context
->PropLock
);
1880 LockSourcesRead(Context
);
1881 if((Source
=LookupSource(Context
, source
)) == NULL
)
1882 alSetError(Context
, AL_INVALID_NAME
);
1884 alSetError(Context
, AL_INVALID_VALUE
);
1885 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1886 alSetError(Context
, AL_INVALID_ENUM
);
1892 for(i
= 0;i
< count
;i
++)
1893 fvals
[i
] = (ALfloat
)values
[i
];
1894 SetSourcefv(Source
, Context
, param
, fvals
);
1896 UnlockSourcesRead(Context
);
1897 WriteUnlock(&Context
->PropLock
);
1899 ALCcontext_DecRef(Context
);
1903 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1905 ALCcontext
*Context
;
1908 Context
= GetContextRef();
1909 if(!Context
) return;
1911 WriteLock(&Context
->PropLock
);
1912 LockSourcesRead(Context
);
1913 if((Source
=LookupSource(Context
, source
)) == NULL
)
1914 alSetError(Context
, AL_INVALID_NAME
);
1915 else if(!(IntValsByProp(param
) == 1))
1916 alSetError(Context
, AL_INVALID_ENUM
);
1918 SetSourceiv(Source
, Context
, param
, &value
);
1919 UnlockSourcesRead(Context
);
1920 WriteUnlock(&Context
->PropLock
);
1922 ALCcontext_DecRef(Context
);
1925 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1927 ALCcontext
*Context
;
1930 Context
= GetContextRef();
1931 if(!Context
) return;
1933 WriteLock(&Context
->PropLock
);
1934 LockSourcesRead(Context
);
1935 if((Source
=LookupSource(Context
, source
)) == NULL
)
1936 alSetError(Context
, AL_INVALID_NAME
);
1937 else if(!(IntValsByProp(param
) == 3))
1938 alSetError(Context
, AL_INVALID_ENUM
);
1941 ALint ivals
[3] = { value1
, value2
, value3
};
1942 SetSourceiv(Source
, Context
, param
, ivals
);
1944 UnlockSourcesRead(Context
);
1945 WriteUnlock(&Context
->PropLock
);
1947 ALCcontext_DecRef(Context
);
1950 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1952 ALCcontext
*Context
;
1955 Context
= GetContextRef();
1956 if(!Context
) return;
1958 WriteLock(&Context
->PropLock
);
1959 LockSourcesRead(Context
);
1960 if((Source
=LookupSource(Context
, source
)) == NULL
)
1961 alSetError(Context
, AL_INVALID_NAME
);
1963 alSetError(Context
, AL_INVALID_VALUE
);
1964 else if(!(IntValsByProp(param
) > 0))
1965 alSetError(Context
, AL_INVALID_ENUM
);
1967 SetSourceiv(Source
, Context
, param
, values
);
1968 UnlockSourcesRead(Context
);
1969 WriteUnlock(&Context
->PropLock
);
1971 ALCcontext_DecRef(Context
);
1975 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1977 ALCcontext
*Context
;
1980 Context
= GetContextRef();
1981 if(!Context
) return;
1983 WriteLock(&Context
->PropLock
);
1984 LockSourcesRead(Context
);
1985 if((Source
=LookupSource(Context
, source
)) == NULL
)
1986 alSetError(Context
, AL_INVALID_NAME
);
1987 else if(!(Int64ValsByProp(param
) == 1))
1988 alSetError(Context
, AL_INVALID_ENUM
);
1990 SetSourcei64v(Source
, Context
, param
, &value
);
1991 UnlockSourcesRead(Context
);
1992 WriteUnlock(&Context
->PropLock
);
1994 ALCcontext_DecRef(Context
);
1997 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1999 ALCcontext
*Context
;
2002 Context
= GetContextRef();
2003 if(!Context
) return;
2005 WriteLock(&Context
->PropLock
);
2006 LockSourcesRead(Context
);
2007 if((Source
=LookupSource(Context
, source
)) == NULL
)
2008 alSetError(Context
, AL_INVALID_NAME
);
2009 else if(!(Int64ValsByProp(param
) == 3))
2010 alSetError(Context
, AL_INVALID_ENUM
);
2013 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2014 SetSourcei64v(Source
, Context
, param
, i64vals
);
2016 UnlockSourcesRead(Context
);
2017 WriteUnlock(&Context
->PropLock
);
2019 ALCcontext_DecRef(Context
);
2022 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2024 ALCcontext
*Context
;
2027 Context
= GetContextRef();
2028 if(!Context
) return;
2030 WriteLock(&Context
->PropLock
);
2031 LockSourcesRead(Context
);
2032 if((Source
=LookupSource(Context
, source
)) == NULL
)
2033 alSetError(Context
, AL_INVALID_NAME
);
2035 alSetError(Context
, AL_INVALID_VALUE
);
2036 else if(!(Int64ValsByProp(param
) > 0))
2037 alSetError(Context
, AL_INVALID_ENUM
);
2039 SetSourcei64v(Source
, Context
, param
, values
);
2040 UnlockSourcesRead(Context
);
2041 WriteUnlock(&Context
->PropLock
);
2043 ALCcontext_DecRef(Context
);
2047 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2049 ALCcontext
*Context
;
2052 Context
= GetContextRef();
2053 if(!Context
) return;
2055 ReadLock(&Context
->PropLock
);
2056 LockSourcesRead(Context
);
2057 if((Source
=LookupSource(Context
, source
)) == NULL
)
2058 alSetError(Context
, AL_INVALID_NAME
);
2060 alSetError(Context
, AL_INVALID_VALUE
);
2061 else if(!(FloatValsByProp(param
) == 1))
2062 alSetError(Context
, AL_INVALID_ENUM
);
2066 if(GetSourcedv(Source
, Context
, param
, &dval
))
2067 *value
= (ALfloat
)dval
;
2069 UnlockSourcesRead(Context
);
2070 ReadUnlock(&Context
->PropLock
);
2072 ALCcontext_DecRef(Context
);
2076 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2078 ALCcontext
*Context
;
2081 Context
= GetContextRef();
2082 if(!Context
) return;
2084 ReadLock(&Context
->PropLock
);
2085 LockSourcesRead(Context
);
2086 if((Source
=LookupSource(Context
, source
)) == NULL
)
2087 alSetError(Context
, AL_INVALID_NAME
);
2088 else if(!(value1
&& value2
&& value3
))
2089 alSetError(Context
, AL_INVALID_VALUE
);
2090 else if(!(FloatValsByProp(param
) == 3))
2091 alSetError(Context
, AL_INVALID_ENUM
);
2095 if(GetSourcedv(Source
, Context
, param
, dvals
))
2097 *value1
= (ALfloat
)dvals
[0];
2098 *value2
= (ALfloat
)dvals
[1];
2099 *value3
= (ALfloat
)dvals
[2];
2102 UnlockSourcesRead(Context
);
2103 ReadUnlock(&Context
->PropLock
);
2105 ALCcontext_DecRef(Context
);
2109 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2111 ALCcontext
*Context
;
2115 Context
= GetContextRef();
2116 if(!Context
) return;
2118 ReadLock(&Context
->PropLock
);
2119 LockSourcesRead(Context
);
2120 if((Source
=LookupSource(Context
, source
)) == NULL
)
2121 alSetError(Context
, AL_INVALID_NAME
);
2123 alSetError(Context
, AL_INVALID_VALUE
);
2124 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2125 alSetError(Context
, AL_INVALID_ENUM
);
2129 if(GetSourcedv(Source
, Context
, param
, dvals
))
2132 for(i
= 0;i
< count
;i
++)
2133 values
[i
] = (ALfloat
)dvals
[i
];
2136 UnlockSourcesRead(Context
);
2137 ReadUnlock(&Context
->PropLock
);
2139 ALCcontext_DecRef(Context
);
2143 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2145 ALCcontext
*Context
;
2148 Context
= GetContextRef();
2149 if(!Context
) return;
2151 ReadLock(&Context
->PropLock
);
2152 LockSourcesRead(Context
);
2153 if((Source
=LookupSource(Context
, source
)) == NULL
)
2154 alSetError(Context
, AL_INVALID_NAME
);
2156 alSetError(Context
, AL_INVALID_VALUE
);
2157 else if(!(DoubleValsByProp(param
) == 1))
2158 alSetError(Context
, AL_INVALID_ENUM
);
2160 GetSourcedv(Source
, Context
, param
, value
);
2161 UnlockSourcesRead(Context
);
2162 ReadUnlock(&Context
->PropLock
);
2164 ALCcontext_DecRef(Context
);
2167 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2169 ALCcontext
*Context
;
2172 Context
= GetContextRef();
2173 if(!Context
) return;
2175 ReadLock(&Context
->PropLock
);
2176 LockSourcesRead(Context
);
2177 if((Source
=LookupSource(Context
, source
)) == NULL
)
2178 alSetError(Context
, AL_INVALID_NAME
);
2179 else if(!(value1
&& value2
&& value3
))
2180 alSetError(Context
, AL_INVALID_VALUE
);
2181 else if(!(DoubleValsByProp(param
) == 3))
2182 alSetError(Context
, AL_INVALID_ENUM
);
2186 if(GetSourcedv(Source
, Context
, param
, dvals
))
2193 UnlockSourcesRead(Context
);
2194 ReadUnlock(&Context
->PropLock
);
2196 ALCcontext_DecRef(Context
);
2199 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2201 ALCcontext
*Context
;
2204 Context
= GetContextRef();
2205 if(!Context
) return;
2207 ReadLock(&Context
->PropLock
);
2208 LockSourcesRead(Context
);
2209 if((Source
=LookupSource(Context
, source
)) == NULL
)
2210 alSetError(Context
, AL_INVALID_NAME
);
2212 alSetError(Context
, AL_INVALID_VALUE
);
2213 else if(!(DoubleValsByProp(param
) > 0))
2214 alSetError(Context
, AL_INVALID_ENUM
);
2216 GetSourcedv(Source
, Context
, param
, values
);
2217 UnlockSourcesRead(Context
);
2218 ReadUnlock(&Context
->PropLock
);
2220 ALCcontext_DecRef(Context
);
2224 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2226 ALCcontext
*Context
;
2229 Context
= GetContextRef();
2230 if(!Context
) return;
2232 ReadLock(&Context
->PropLock
);
2233 LockSourcesRead(Context
);
2234 if((Source
=LookupSource(Context
, source
)) == NULL
)
2235 alSetError(Context
, AL_INVALID_NAME
);
2237 alSetError(Context
, AL_INVALID_VALUE
);
2238 else if(!(IntValsByProp(param
) == 1))
2239 alSetError(Context
, AL_INVALID_ENUM
);
2241 GetSourceiv(Source
, Context
, param
, value
);
2242 UnlockSourcesRead(Context
);
2243 ReadUnlock(&Context
->PropLock
);
2245 ALCcontext_DecRef(Context
);
2249 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2251 ALCcontext
*Context
;
2254 Context
= GetContextRef();
2255 if(!Context
) return;
2257 ReadLock(&Context
->PropLock
);
2258 LockSourcesRead(Context
);
2259 if((Source
=LookupSource(Context
, source
)) == NULL
)
2260 alSetError(Context
, AL_INVALID_NAME
);
2261 else if(!(value1
&& value2
&& value3
))
2262 alSetError(Context
, AL_INVALID_VALUE
);
2263 else if(!(IntValsByProp(param
) == 3))
2264 alSetError(Context
, AL_INVALID_ENUM
);
2268 if(GetSourceiv(Source
, Context
, param
, ivals
))
2275 UnlockSourcesRead(Context
);
2276 ReadUnlock(&Context
->PropLock
);
2278 ALCcontext_DecRef(Context
);
2282 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2284 ALCcontext
*Context
;
2287 Context
= GetContextRef();
2288 if(!Context
) return;
2290 ReadLock(&Context
->PropLock
);
2291 LockSourcesRead(Context
);
2292 if((Source
=LookupSource(Context
, source
)) == NULL
)
2293 alSetError(Context
, AL_INVALID_NAME
);
2295 alSetError(Context
, AL_INVALID_VALUE
);
2296 else if(!(IntValsByProp(param
) > 0))
2297 alSetError(Context
, AL_INVALID_ENUM
);
2299 GetSourceiv(Source
, Context
, param
, values
);
2300 UnlockSourcesRead(Context
);
2301 ReadUnlock(&Context
->PropLock
);
2303 ALCcontext_DecRef(Context
);
2307 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2309 ALCcontext
*Context
;
2312 Context
= GetContextRef();
2313 if(!Context
) return;
2315 ReadLock(&Context
->PropLock
);
2316 LockSourcesRead(Context
);
2317 if((Source
=LookupSource(Context
, source
)) == NULL
)
2318 alSetError(Context
, AL_INVALID_NAME
);
2320 alSetError(Context
, AL_INVALID_VALUE
);
2321 else if(!(Int64ValsByProp(param
) == 1))
2322 alSetError(Context
, AL_INVALID_ENUM
);
2324 GetSourcei64v(Source
, Context
, param
, value
);
2325 UnlockSourcesRead(Context
);
2326 ReadUnlock(&Context
->PropLock
);
2328 ALCcontext_DecRef(Context
);
2331 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2333 ALCcontext
*Context
;
2336 Context
= GetContextRef();
2337 if(!Context
) return;
2339 ReadLock(&Context
->PropLock
);
2340 LockSourcesRead(Context
);
2341 if((Source
=LookupSource(Context
, source
)) == NULL
)
2342 alSetError(Context
, AL_INVALID_NAME
);
2343 else if(!(value1
&& value2
&& value3
))
2344 alSetError(Context
, AL_INVALID_VALUE
);
2345 else if(!(Int64ValsByProp(param
) == 3))
2346 alSetError(Context
, AL_INVALID_ENUM
);
2350 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2352 *value1
= i64vals
[0];
2353 *value2
= i64vals
[1];
2354 *value3
= i64vals
[2];
2357 UnlockSourcesRead(Context
);
2358 ReadUnlock(&Context
->PropLock
);
2360 ALCcontext_DecRef(Context
);
2363 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2365 ALCcontext
*Context
;
2368 Context
= GetContextRef();
2369 if(!Context
) return;
2371 ReadLock(&Context
->PropLock
);
2372 LockSourcesRead(Context
);
2373 if((Source
=LookupSource(Context
, source
)) == NULL
)
2374 alSetError(Context
, AL_INVALID_NAME
);
2376 alSetError(Context
, AL_INVALID_VALUE
);
2377 else if(!(Int64ValsByProp(param
) > 0))
2378 alSetError(Context
, AL_INVALID_ENUM
);
2380 GetSourcei64v(Source
, Context
, param
, values
);
2381 UnlockSourcesRead(Context
);
2382 ReadUnlock(&Context
->PropLock
);
2384 ALCcontext_DecRef(Context
);
2388 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2390 alSourcePlayv(1, &source
);
2392 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2394 ALCcontext
*context
;
2400 context
= GetContextRef();
2401 if(!context
) return;
2403 LockSourcesRead(context
);
2405 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2406 for(i
= 0;i
< n
;i
++)
2408 if(!LookupSource(context
, sources
[i
]))
2409 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2412 device
= context
->Device
;
2413 ALCdevice_Lock(device
);
2414 /* If the device is disconnected, go right to stopped. */
2415 if(!device
->Connected
)
2417 for(i
= 0;i
< n
;i
++)
2419 source
= LookupSource(context
, sources
[i
]);
2420 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2422 ALCdevice_Unlock(device
);
2426 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2428 ALsizei newcount
= context
->MaxVoices
<< 1;
2429 if(context
->MaxVoices
>= newcount
)
2431 ALCdevice_Unlock(device
);
2432 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2434 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2437 for(i
= 0;i
< n
;i
++)
2439 ALbufferlistitem
*BufferList
;
2440 ALbuffer
*buffer
= NULL
;
2441 bool start_moving
= false;
2444 source
= LookupSource(context
, sources
[i
]);
2445 WriteLock(&source
->queue_lock
);
2446 /* Check that there is a queue containing at least one valid, non zero
2449 BufferList
= source
->queue
;
2452 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2454 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2457 /* If there's nothing to play, go right to stopped. */
2460 /* NOTE: A source without any playable buffers should not have an
2461 * ALvoice since it shouldn't be in a playing or paused state. So
2462 * there's no need to look up its voice and clear the source.
2464 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2465 source
->OffsetType
= AL_NONE
;
2466 source
->Offset
= 0.0;
2470 voice
= GetSourceVoice(source
, context
);
2471 switch(GetSourceState(source
, voice
))
2474 assert(voice
!= NULL
);
2475 /* A source that's already playing is restarted from the beginning. */
2476 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2477 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2478 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2482 assert(voice
!= NULL
);
2483 /* A source that's paused simply resumes. Clear its mixing
2484 * parameters and mark it as 'moving' so it fades in from
2488 voice
->Flags
|= VOICE_IS_MOVING
;
2489 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*
2490 voice
->NumChannels
);
2491 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2492 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*
2493 voice
->NumChannels
);
2494 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2495 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2502 /* Make sure this source isn't already active, and if not, look for an
2503 * unused voice to put it in.
2505 assert(voice
== NULL
);
2506 for(j
= 0;j
< context
->VoiceCount
;j
++)
2508 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2510 voice
= context
->Voices
[j
];
2515 voice
= context
->Voices
[context
->VoiceCount
++];
2516 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2518 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2519 UpdateSourceProps(source
, voice
, device
->NumAuxSends
);
2521 /* A source that's not playing or paused has any offset applied when it
2525 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2527 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2528 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2529 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2530 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2531 if(source
->OffsetType
!= AL_NONE
)
2533 ApplyOffset(source
, voice
);
2534 start_moving
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2535 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2536 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2539 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2540 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2542 /* Clear previous samples. */
2543 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2545 /* Clear the stepping value so the mixer knows not to mix this until
2546 * the update gets applied.
2550 voice
->Flags
= start_moving
? VOICE_IS_MOVING
: 0;
2551 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2552 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2553 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2554 if(device
->AvgSpeakerDist
> 0.0f
)
2556 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2557 (device
->AvgSpeakerDist
* device
->Frequency
);
2558 for(j
= 0;j
< voice
->NumChannels
;j
++)
2560 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2561 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2562 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2566 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2567 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2568 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2570 WriteUnlock(&source
->queue_lock
);
2572 ALCdevice_Unlock(device
);
2575 UnlockSourcesRead(context
);
2576 ALCcontext_DecRef(context
);
2579 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2581 alSourcePausev(1, &source
);
2583 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2585 ALCcontext
*context
;
2591 context
= GetContextRef();
2592 if(!context
) return;
2594 LockSourcesRead(context
);
2596 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2597 for(i
= 0;i
< n
;i
++)
2599 if(!LookupSource(context
, sources
[i
]))
2600 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2603 device
= context
->Device
;
2604 ALCdevice_Lock(device
);
2605 for(i
= 0;i
< n
;i
++)
2607 source
= LookupSource(context
, sources
[i
]);
2608 WriteLock(&source
->queue_lock
);
2609 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2611 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2612 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2615 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2616 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2617 WriteUnlock(&source
->queue_lock
);
2619 ALCdevice_Unlock(device
);
2622 UnlockSourcesRead(context
);
2623 ALCcontext_DecRef(context
);
2626 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2628 alSourceStopv(1, &source
);
2630 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2632 ALCcontext
*context
;
2638 context
= GetContextRef();
2639 if(!context
) return;
2641 LockSourcesRead(context
);
2643 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2644 for(i
= 0;i
< n
;i
++)
2646 if(!LookupSource(context
, sources
[i
]))
2647 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2650 device
= context
->Device
;
2651 ALCdevice_Lock(device
);
2652 for(i
= 0;i
< n
;i
++)
2654 source
= LookupSource(context
, sources
[i
]);
2655 WriteLock(&source
->queue_lock
);
2656 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2658 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2659 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2660 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2663 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2664 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2665 source
->OffsetType
= AL_NONE
;
2666 source
->Offset
= 0.0;
2667 WriteUnlock(&source
->queue_lock
);
2669 ALCdevice_Unlock(device
);
2672 UnlockSourcesRead(context
);
2673 ALCcontext_DecRef(context
);
2676 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2678 alSourceRewindv(1, &source
);
2680 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2682 ALCcontext
*context
;
2688 context
= GetContextRef();
2689 if(!context
) return;
2691 LockSourcesRead(context
);
2693 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2694 for(i
= 0;i
< n
;i
++)
2696 if(!LookupSource(context
, sources
[i
]))
2697 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2700 device
= context
->Device
;
2701 ALCdevice_Lock(device
);
2702 for(i
= 0;i
< n
;i
++)
2704 source
= LookupSource(context
, sources
[i
]);
2705 WriteLock(&source
->queue_lock
);
2706 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2708 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2709 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2710 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2713 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2714 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2715 source
->OffsetType
= AL_NONE
;
2716 source
->Offset
= 0.0;
2717 WriteUnlock(&source
->queue_lock
);
2719 ALCdevice_Unlock(device
);
2722 UnlockSourcesRead(context
);
2723 ALCcontext_DecRef(context
);
2727 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2730 ALCcontext
*context
;
2733 ALbufferlistitem
*BufferListStart
;
2734 ALbufferlistitem
*BufferList
;
2735 ALbuffer
*BufferFmt
= NULL
;
2740 context
= GetContextRef();
2741 if(!context
) return;
2743 device
= context
->Device
;
2745 LockSourcesRead(context
);
2747 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2748 if((source
=LookupSource(context
, src
)) == NULL
)
2749 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2751 WriteLock(&source
->queue_lock
);
2752 if(source
->SourceType
== AL_STATIC
)
2754 WriteUnlock(&source
->queue_lock
);
2755 /* Can't queue on a Static Source */
2756 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2759 /* Check for a valid Buffer, for its frequency and format */
2760 BufferList
= source
->queue
;
2763 if(BufferList
->buffer
)
2765 BufferFmt
= BufferList
->buffer
;
2768 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2771 LockBuffersRead(device
);
2772 BufferListStart
= NULL
;
2774 for(i
= 0;i
< nb
;i
++)
2776 ALbuffer
*buffer
= NULL
;
2777 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2779 WriteUnlock(&source
->queue_lock
);
2780 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2783 if(!BufferListStart
)
2785 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2786 BufferList
= BufferListStart
;
2790 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2791 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2794 BufferList
->buffer
= buffer
;
2795 ATOMIC_INIT(&BufferList
->next
, NULL
);
2796 if(!buffer
) continue;
2798 /* Hold a read lock on each buffer being queued while checking all
2799 * provided buffers. This is done so other threads don't see an extra
2800 * reference on some buffers if this operation ends up failing. */
2801 ReadLock(&buffer
->lock
);
2802 IncrementRef(&buffer
->ref
);
2804 if(BufferFmt
== NULL
)
2806 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2807 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2808 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2810 WriteUnlock(&source
->queue_lock
);
2811 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2814 /* A buffer failed (invalid ID or format), so unlock and release
2815 * each buffer we had. */
2816 while(BufferListStart
)
2818 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2819 almemory_order_relaxed
);
2820 if((buffer
=BufferListStart
->buffer
) != NULL
)
2822 DecrementRef(&buffer
->ref
);
2823 ReadUnlock(&buffer
->lock
);
2825 al_free(BufferListStart
);
2826 BufferListStart
= next
;
2828 UnlockBuffersRead(device
);
2832 /* All buffers good, unlock them now. */
2833 BufferList
= BufferListStart
;
2834 while(BufferList
!= NULL
)
2836 ALbuffer
*buffer
= BufferList
->buffer
;
2837 if(buffer
) ReadUnlock(&buffer
->lock
);
2838 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2840 UnlockBuffersRead(device
);
2842 /* Source is now streaming */
2843 source
->SourceType
= AL_STREAMING
;
2845 if(!(BufferList
=source
->queue
))
2846 source
->queue
= BufferListStart
;
2849 ALbufferlistitem
*next
;
2850 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2852 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2854 WriteUnlock(&source
->queue_lock
);
2857 UnlockSourcesRead(context
);
2858 ALCcontext_DecRef(context
);
2861 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2863 ALCcontext
*context
;
2865 ALbufferlistitem
*OldHead
;
2866 ALbufferlistitem
*OldTail
;
2867 ALbufferlistitem
*Current
;
2871 context
= GetContextRef();
2872 if(!context
) return;
2874 LockSourcesRead(context
);
2876 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2878 if((source
=LookupSource(context
, src
)) == NULL
)
2879 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2881 /* Nothing to unqueue. */
2882 if(nb
== 0) goto done
;
2884 WriteLock(&source
->queue_lock
);
2885 if(source
->Looping
|| source
->SourceType
!= AL_STREAMING
)
2887 WriteUnlock(&source
->queue_lock
);
2888 /* Trying to unqueue buffers on a looping or non-streaming source. */
2889 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2892 /* Find the new buffer queue head */
2893 OldTail
= source
->queue
;
2895 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2896 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2897 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2899 if(OldTail
!= Current
)
2901 for(i
= 1;i
< nb
;i
++)
2903 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldTail
->next
, almemory_order_relaxed
);
2904 if(!next
|| next
== Current
) break;
2910 WriteUnlock(&source
->queue_lock
);
2911 /* Trying to unqueue pending buffers. */
2912 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2915 /* Swap it, and cut the new head from the old. */
2916 OldHead
= source
->queue
;
2917 source
->queue
= ATOMIC_EXCHANGE_PTR(&OldTail
->next
, NULL
, almemory_order_acq_rel
);
2918 WriteUnlock(&source
->queue_lock
);
2920 while(OldHead
!= NULL
)
2922 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldHead
->next
, almemory_order_relaxed
);
2923 ALbuffer
*buffer
= OldHead
->buffer
;
2929 *(buffers
++) = buffer
->id
;
2930 DecrementRef(&buffer
->ref
);
2938 UnlockSourcesRead(context
);
2939 ALCcontext_DecRef(context
);
2943 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2947 RWLockInit(&Source
->queue_lock
);
2949 Source
->InnerAngle
= 360.0f
;
2950 Source
->OuterAngle
= 360.0f
;
2951 Source
->Pitch
= 1.0f
;
2952 Source
->Position
[0] = 0.0f
;
2953 Source
->Position
[1] = 0.0f
;
2954 Source
->Position
[2] = 0.0f
;
2955 Source
->Velocity
[0] = 0.0f
;
2956 Source
->Velocity
[1] = 0.0f
;
2957 Source
->Velocity
[2] = 0.0f
;
2958 Source
->Direction
[0] = 0.0f
;
2959 Source
->Direction
[1] = 0.0f
;
2960 Source
->Direction
[2] = 0.0f
;
2961 Source
->Orientation
[0][0] = 0.0f
;
2962 Source
->Orientation
[0][1] = 0.0f
;
2963 Source
->Orientation
[0][2] = -1.0f
;
2964 Source
->Orientation
[1][0] = 0.0f
;
2965 Source
->Orientation
[1][1] = 1.0f
;
2966 Source
->Orientation
[1][2] = 0.0f
;
2967 Source
->RefDistance
= 1.0f
;
2968 Source
->MaxDistance
= FLT_MAX
;
2969 Source
->RollOffFactor
= 1.0f
;
2970 Source
->Gain
= 1.0f
;
2971 Source
->MinGain
= 0.0f
;
2972 Source
->MaxGain
= 1.0f
;
2973 Source
->OuterGain
= 0.0f
;
2974 Source
->OuterGainHF
= 1.0f
;
2976 Source
->DryGainHFAuto
= AL_TRUE
;
2977 Source
->WetGainAuto
= AL_TRUE
;
2978 Source
->WetGainHFAuto
= AL_TRUE
;
2979 Source
->AirAbsorptionFactor
= 0.0f
;
2980 Source
->RoomRolloffFactor
= 0.0f
;
2981 Source
->DopplerFactor
= 1.0f
;
2982 Source
->HeadRelative
= AL_FALSE
;
2983 Source
->Looping
= AL_FALSE
;
2984 Source
->DistanceModel
= DefaultDistanceModel
;
2985 Source
->Resampler
= ResamplerDefault
;
2986 Source
->DirectChannels
= AL_FALSE
;
2988 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2989 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2991 Source
->Radius
= 0.0f
;
2993 Source
->Direct
.Gain
= 1.0f
;
2994 Source
->Direct
.GainHF
= 1.0f
;
2995 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2996 Source
->Direct
.GainLF
= 1.0f
;
2997 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2998 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2999 for(i
= 0;i
< num_sends
;i
++)
3001 Source
->Send
[i
].Slot
= NULL
;
3002 Source
->Send
[i
].Gain
= 1.0f
;
3003 Source
->Send
[i
].GainHF
= 1.0f
;
3004 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
3005 Source
->Send
[i
].GainLF
= 1.0f
;
3006 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
3009 Source
->Offset
= 0.0;
3010 Source
->OffsetType
= AL_NONE
;
3011 Source
->SourceType
= AL_UNDETERMINED
;
3012 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
3014 Source
->queue
= NULL
;
3016 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3019 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3022 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3024 ALbufferlistitem
*BufferList
;
3027 BufferList
= source
->queue
;
3028 while(BufferList
!= NULL
)
3030 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3031 if(BufferList
->buffer
!= NULL
)
3032 DecrementRef(&BufferList
->buffer
->ref
);
3033 al_free(BufferList
);
3036 source
->queue
= NULL
;
3040 for(i
= 0;i
< num_sends
;i
++)
3042 if(source
->Send
[i
].Slot
)
3043 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3044 source
->Send
[i
].Slot
= NULL
;
3046 al_free(source
->Send
);
3047 source
->Send
= NULL
;
3051 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
)
3053 struct ALvoiceProps
*props
;
3056 /* Get an unused property container, or allocate a new one as needed. */
3057 props
= ATOMIC_LOAD(&voice
->FreeList
, almemory_order_acquire
);
3059 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3062 struct ALvoiceProps
*next
;
3064 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3065 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice
->FreeList
, &props
, next
,
3066 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3069 /* Copy in current property values. */
3070 props
->Pitch
= source
->Pitch
;
3071 props
->Gain
= source
->Gain
;
3072 props
->OuterGain
= source
->OuterGain
;
3073 props
->MinGain
= source
->MinGain
;
3074 props
->MaxGain
= source
->MaxGain
;
3075 props
->InnerAngle
= source
->InnerAngle
;
3076 props
->OuterAngle
= source
->OuterAngle
;
3077 props
->RefDistance
= source
->RefDistance
;
3078 props
->MaxDistance
= source
->MaxDistance
;
3079 props
->RollOffFactor
= source
->RollOffFactor
;
3080 for(i
= 0;i
< 3;i
++)
3081 props
->Position
[i
] = source
->Position
[i
];
3082 for(i
= 0;i
< 3;i
++)
3083 props
->Velocity
[i
] = source
->Velocity
[i
];
3084 for(i
= 0;i
< 3;i
++)
3085 props
->Direction
[i
] = source
->Direction
[i
];
3086 for(i
= 0;i
< 2;i
++)
3089 for(j
= 0;j
< 3;j
++)
3090 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3092 props
->HeadRelative
= source
->HeadRelative
;
3093 props
->DistanceModel
= source
->DistanceModel
;
3094 props
->Resampler
= source
->Resampler
;
3095 props
->DirectChannels
= source
->DirectChannels
;
3097 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3098 props
->WetGainAuto
= source
->WetGainAuto
;
3099 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3100 props
->OuterGainHF
= source
->OuterGainHF
;
3102 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3103 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3104 props
->DopplerFactor
= source
->DopplerFactor
;
3106 props
->StereoPan
[0] = source
->StereoPan
[0];
3107 props
->StereoPan
[1] = source
->StereoPan
[1];
3109 props
->Radius
= source
->Radius
;
3111 props
->Direct
.Gain
= source
->Direct
.Gain
;
3112 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3113 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3114 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3115 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3117 for(i
= 0;i
< num_sends
;i
++)
3119 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3120 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3121 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3122 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3123 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3124 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3127 /* Set the new container for updating internal parameters. */
3128 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3131 /* If there was an unused update container, put it back in the
3134 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &voice
->FreeList
, props
);
3138 void UpdateAllSourceProps(ALCcontext
*context
)
3140 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3143 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3145 ALvoice
*voice
= context
->Voices
[pos
];
3146 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3147 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3148 UpdateSourceProps(source
, voice
, num_sends
);
3153 /* GetSourceSampleOffset
3155 * Gets the current read offset for the given Source, in 32.32 fixed-point
3156 * samples. The offset is relative to the start of the queue (not the start of
3157 * the current buffer).
3159 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3161 ALCdevice
*device
= context
->Device
;
3162 const ALbufferlistitem
*Current
;
3167 ReadLock(&Source
->queue_lock
);
3171 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3173 *clocktime
= GetDeviceClockTime(device
);
3175 voice
= GetSourceVoice(Source
, context
);
3178 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3180 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3181 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3184 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3185 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3189 const ALbufferlistitem
*BufferList
= Source
->queue
;
3190 while(BufferList
&& BufferList
!= Current
)
3192 if(BufferList
->buffer
)
3193 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3194 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3195 almemory_order_relaxed
);
3197 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3200 ReadUnlock(&Source
->queue_lock
);
3201 return (ALint64
)readPos
;
3204 /* GetSourceSecOffset
3206 * Gets the current read offset for the given Source, in seconds. The offset is
3207 * relative to the start of the queue (not the start of the current buffer).
3209 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3211 ALCdevice
*device
= context
->Device
;
3212 const ALbufferlistitem
*Current
;
3218 ReadLock(&Source
->queue_lock
);
3222 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3224 *clocktime
= GetDeviceClockTime(device
);
3226 voice
= GetSourceVoice(Source
, context
);
3229 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3231 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3233 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3235 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3236 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3241 const ALbufferlistitem
*BufferList
= Source
->queue
;
3242 const ALbuffer
*BufferFmt
= NULL
;
3243 while(BufferList
&& BufferList
!= Current
)
3245 const ALbuffer
*buffer
= BufferList
->buffer
;
3248 if(!BufferFmt
) BufferFmt
= buffer
;
3249 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3251 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3252 almemory_order_relaxed
);
3255 while(BufferList
&& !BufferFmt
)
3257 BufferFmt
= BufferList
->buffer
;
3258 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3259 almemory_order_relaxed
);
3261 assert(BufferFmt
!= NULL
);
3263 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3264 (ALdouble
)BufferFmt
->Frequency
;
3267 ReadUnlock(&Source
->queue_lock
);
3273 * Gets the current read offset for the given Source, in the appropriate format
3274 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3275 * queue (not the start of the current buffer).
3277 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3279 ALCdevice
*device
= context
->Device
;
3280 const ALbufferlistitem
*Current
;
3282 ALsizei readPosFrac
;
3287 ReadLock(&Source
->queue_lock
);
3290 readPos
= readPosFrac
= 0;
3291 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3293 voice
= GetSourceVoice(Source
, context
);
3296 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3298 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3299 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3301 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3302 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3307 const ALbufferlistitem
*BufferList
= Source
->queue
;
3308 const ALbuffer
*BufferFmt
= NULL
;
3309 ALboolean readFin
= AL_FALSE
;
3310 ALuint totalBufferLen
= 0;
3312 while(BufferList
!= NULL
)
3314 const ALbuffer
*buffer
;
3315 readFin
= readFin
|| (BufferList
== Current
);
3316 if((buffer
=BufferList
->buffer
) != NULL
)
3318 if(!BufferFmt
) BufferFmt
= buffer
;
3319 totalBufferLen
+= buffer
->SampleLen
;
3320 if(!readFin
) readPos
+= buffer
->SampleLen
;
3322 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3323 almemory_order_relaxed
);
3325 assert(BufferFmt
!= NULL
);
3328 readPos
%= totalBufferLen
;
3331 /* Wrap back to 0 */
3332 if(readPos
>= totalBufferLen
)
3333 readPos
= readPosFrac
= 0;
3340 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3343 case AL_SAMPLE_OFFSET
:
3344 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3347 case AL_BYTE_OFFSET
:
3348 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3350 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3351 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3352 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3354 /* Round down to nearest ADPCM block */
3355 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3357 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3359 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3360 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3361 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3363 /* Round down to nearest ADPCM block */
3364 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3368 ALuint FrameSize
= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3369 BufferFmt
->OriginalType
);
3370 offset
= (ALdouble
)(readPos
* FrameSize
);
3376 ReadUnlock(&Source
->queue_lock
);
3383 * Apply the stored playback offset to the Source. This function will update
3384 * the number of buffers "played" given the stored offset.
3386 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3388 ALbufferlistitem
*BufferList
;
3389 const ALbuffer
*Buffer
;
3390 ALuint bufferLen
, totalBufferLen
;
3394 /* Get sample frame offset */
3395 if(!GetSampleOffset(Source
, &offset
, &frac
))
3399 BufferList
= Source
->queue
;
3400 while(BufferList
&& totalBufferLen
<= offset
)
3402 Buffer
= BufferList
->buffer
;
3403 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3405 if(bufferLen
> offset
-totalBufferLen
)
3407 /* Offset is in this buffer */
3408 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3409 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3410 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3414 totalBufferLen
+= bufferLen
;
3416 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3419 /* Offset is out of range of the queue */
3426 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3427 * or Second offset supplied by the application). This takes into account the
3428 * fact that the buffer format may have been modifed since.
3430 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3432 const ALbuffer
*BufferFmt
= NULL
;
3433 const ALbufferlistitem
*BufferList
;
3434 ALdouble dbloff
, dblfrac
;
3436 /* Find the first valid Buffer in the Queue */
3437 BufferList
= Source
->queue
;
3440 if((BufferFmt
=BufferList
->buffer
) != NULL
)
3442 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3443 almemory_order_relaxed
);
3447 Source
->OffsetType
= AL_NONE
;
3448 Source
->Offset
= 0.0;
3452 switch(Source
->OffsetType
)
3454 case AL_BYTE_OFFSET
:
3455 /* Determine the ByteOffset (and ensure it is block aligned) */
3456 *offset
= (ALuint
)Source
->Offset
;
3457 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3459 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3460 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3461 *offset
*= BufferFmt
->OriginalAlign
;
3463 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3465 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3466 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3467 *offset
*= BufferFmt
->OriginalAlign
;
3470 *offset
/= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3471 BufferFmt
->OriginalType
);
3475 case AL_SAMPLE_OFFSET
:
3476 dblfrac
= modf(Source
->Offset
, &dbloff
);
3477 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3478 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3482 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3483 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3484 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3487 Source
->OffsetType
= AL_NONE
;
3488 Source
->Offset
= 0.0;
3496 * Destroys all sources in the source map.
3498 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3500 ALCdevice
*device
= Context
->Device
;
3502 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3504 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3505 Context
->SourceMap
.values
[pos
] = NULL
;
3507 DeinitSource(temp
, device
->NumAuxSends
);
3509 FreeThunkEntry(temp
->id
);
3510 memset(temp
, 0, sizeof(*temp
));