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
, ALCcontext
*context
);
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
,
123 /* AL_SOFT_source_spatialize */
124 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
127 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
128 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
129 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
131 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
132 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
133 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
135 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
137 ALvoice
**voice
= context
->Voices
;
138 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
139 while(voice
!= voice_end
)
141 if(ATOMIC_LOAD(&(*voice
)->Source
, almemory_order_acquire
) == source
)
149 * Returns if the last known state for the source was playing or paused. Does
150 * not sync with the mixer voice.
152 static inline bool IsPlayingOrPaused(ALsource
*source
)
154 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
155 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
159 * Returns an updated source state using the matching voice's status (or lack
162 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
166 ALenum state
= AL_PLAYING
;
167 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
168 almemory_order_acq_rel
, almemory_order_acquire
))
172 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
176 * Returns if the source should specify an update, given the context's
177 * deferring state and the source's last known state.
179 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
181 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
182 IsPlayingOrPaused(source
);
185 static ALint
FloatValsByProp(ALenum prop
)
187 if(prop
!= (ALenum
)((SourceProp
)prop
))
189 switch((SourceProp
)prop
)
195 case AL_MAX_DISTANCE
:
196 case AL_ROLLOFF_FACTOR
:
197 case AL_DOPPLER_FACTOR
:
198 case AL_CONE_OUTER_GAIN
:
200 case AL_SAMPLE_OFFSET
:
202 case AL_CONE_INNER_ANGLE
:
203 case AL_CONE_OUTER_ANGLE
:
204 case AL_REFERENCE_DISTANCE
:
205 case AL_CONE_OUTER_GAINHF
:
206 case AL_AIR_ABSORPTION_FACTOR
:
207 case AL_ROOM_ROLLOFF_FACTOR
:
208 case AL_DIRECT_FILTER_GAINHF_AUTO
:
209 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
210 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
211 case AL_DIRECT_CHANNELS_SOFT
:
212 case AL_DISTANCE_MODEL
:
213 case AL_SOURCE_RELATIVE
:
215 case AL_SOURCE_STATE
:
216 case AL_BUFFERS_QUEUED
:
217 case AL_BUFFERS_PROCESSED
:
219 case AL_BYTE_LENGTH_SOFT
:
220 case AL_SAMPLE_LENGTH_SOFT
:
221 case AL_SEC_LENGTH_SOFT
:
222 case AL_SOURCE_RADIUS
:
223 case AL_SOURCE_RESAMPLER_SOFT
:
224 case AL_SOURCE_SPATIALIZE_SOFT
:
227 case AL_STEREO_ANGLES
:
238 case AL_SEC_OFFSET_LATENCY_SOFT
:
239 break; /* Double only */
242 case AL_DIRECT_FILTER
:
243 case AL_AUXILIARY_SEND_FILTER
:
244 break; /* i/i64 only */
245 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
246 break; /* i64 only */
250 static ALint
DoubleValsByProp(ALenum prop
)
252 if(prop
!= (ALenum
)((SourceProp
)prop
))
254 switch((SourceProp
)prop
)
260 case AL_MAX_DISTANCE
:
261 case AL_ROLLOFF_FACTOR
:
262 case AL_DOPPLER_FACTOR
:
263 case AL_CONE_OUTER_GAIN
:
265 case AL_SAMPLE_OFFSET
:
267 case AL_CONE_INNER_ANGLE
:
268 case AL_CONE_OUTER_ANGLE
:
269 case AL_REFERENCE_DISTANCE
:
270 case AL_CONE_OUTER_GAINHF
:
271 case AL_AIR_ABSORPTION_FACTOR
:
272 case AL_ROOM_ROLLOFF_FACTOR
:
273 case AL_DIRECT_FILTER_GAINHF_AUTO
:
274 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
275 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
276 case AL_DIRECT_CHANNELS_SOFT
:
277 case AL_DISTANCE_MODEL
:
278 case AL_SOURCE_RELATIVE
:
280 case AL_SOURCE_STATE
:
281 case AL_BUFFERS_QUEUED
:
282 case AL_BUFFERS_PROCESSED
:
284 case AL_BYTE_LENGTH_SOFT
:
285 case AL_SAMPLE_LENGTH_SOFT
:
286 case AL_SEC_LENGTH_SOFT
:
287 case AL_SOURCE_RADIUS
:
288 case AL_SOURCE_RESAMPLER_SOFT
:
289 case AL_SOURCE_SPATIALIZE_SOFT
:
292 case AL_SEC_OFFSET_LATENCY_SOFT
:
293 case AL_STEREO_ANGLES
:
305 case AL_DIRECT_FILTER
:
306 case AL_AUXILIARY_SEND_FILTER
:
307 break; /* i/i64 only */
308 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
309 break; /* i64 only */
314 static ALint
IntValsByProp(ALenum prop
)
316 if(prop
!= (ALenum
)((SourceProp
)prop
))
318 switch((SourceProp
)prop
)
324 case AL_MAX_DISTANCE
:
325 case AL_ROLLOFF_FACTOR
:
326 case AL_DOPPLER_FACTOR
:
327 case AL_CONE_OUTER_GAIN
:
329 case AL_SAMPLE_OFFSET
:
331 case AL_CONE_INNER_ANGLE
:
332 case AL_CONE_OUTER_ANGLE
:
333 case AL_REFERENCE_DISTANCE
:
334 case AL_CONE_OUTER_GAINHF
:
335 case AL_AIR_ABSORPTION_FACTOR
:
336 case AL_ROOM_ROLLOFF_FACTOR
:
337 case AL_DIRECT_FILTER_GAINHF_AUTO
:
338 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
339 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
340 case AL_DIRECT_CHANNELS_SOFT
:
341 case AL_DISTANCE_MODEL
:
342 case AL_SOURCE_RELATIVE
:
345 case AL_SOURCE_STATE
:
346 case AL_BUFFERS_QUEUED
:
347 case AL_BUFFERS_PROCESSED
:
349 case AL_DIRECT_FILTER
:
350 case AL_BYTE_LENGTH_SOFT
:
351 case AL_SAMPLE_LENGTH_SOFT
:
352 case AL_SEC_LENGTH_SOFT
:
353 case AL_SOURCE_RADIUS
:
354 case AL_SOURCE_RESAMPLER_SOFT
:
355 case AL_SOURCE_SPATIALIZE_SOFT
:
361 case AL_AUXILIARY_SEND_FILTER
:
367 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
368 break; /* i64 only */
369 case AL_SEC_OFFSET_LATENCY_SOFT
:
370 break; /* Double only */
371 case AL_STEREO_ANGLES
:
372 break; /* Float/double only */
376 static ALint
Int64ValsByProp(ALenum prop
)
378 if(prop
!= (ALenum
)((SourceProp
)prop
))
380 switch((SourceProp
)prop
)
386 case AL_MAX_DISTANCE
:
387 case AL_ROLLOFF_FACTOR
:
388 case AL_DOPPLER_FACTOR
:
389 case AL_CONE_OUTER_GAIN
:
391 case AL_SAMPLE_OFFSET
:
393 case AL_CONE_INNER_ANGLE
:
394 case AL_CONE_OUTER_ANGLE
:
395 case AL_REFERENCE_DISTANCE
:
396 case AL_CONE_OUTER_GAINHF
:
397 case AL_AIR_ABSORPTION_FACTOR
:
398 case AL_ROOM_ROLLOFF_FACTOR
:
399 case AL_DIRECT_FILTER_GAINHF_AUTO
:
400 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
401 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
402 case AL_DIRECT_CHANNELS_SOFT
:
403 case AL_DISTANCE_MODEL
:
404 case AL_SOURCE_RELATIVE
:
407 case AL_SOURCE_STATE
:
408 case AL_BUFFERS_QUEUED
:
409 case AL_BUFFERS_PROCESSED
:
411 case AL_DIRECT_FILTER
:
412 case AL_BYTE_LENGTH_SOFT
:
413 case AL_SAMPLE_LENGTH_SOFT
:
414 case AL_SEC_LENGTH_SOFT
:
415 case AL_SOURCE_RADIUS
:
416 case AL_SOURCE_RESAMPLER_SOFT
:
417 case AL_SOURCE_SPATIALIZE_SOFT
:
420 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
426 case AL_AUXILIARY_SEND_FILTER
:
432 case AL_SEC_OFFSET_LATENCY_SOFT
:
433 break; /* Double only */
434 case AL_STEREO_ANGLES
:
435 break; /* Float/double only */
441 #define CHECKVAL(x) do { \
443 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
446 #define DO_UPDATEPROPS() do { \
448 if(SourceShouldUpdate(Source, Context) && \
449 (voice=GetSourceVoice(Source, Context)) != NULL) \
450 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
452 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
455 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
457 ALCdevice
*device
= Context
->Device
;
462 case AL_BYTE_LENGTH_SOFT
:
463 case AL_SAMPLE_LENGTH_SOFT
:
464 case AL_SEC_LENGTH_SOFT
:
465 case AL_SEC_OFFSET_LATENCY_SOFT
:
467 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
470 CHECKVAL(*values
>= 0.0f
);
472 Source
->Pitch
= *values
;
476 case AL_CONE_INNER_ANGLE
:
477 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
479 Source
->InnerAngle
= *values
;
483 case AL_CONE_OUTER_ANGLE
:
484 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
486 Source
->OuterAngle
= *values
;
491 CHECKVAL(*values
>= 0.0f
);
493 Source
->Gain
= *values
;
497 case AL_MAX_DISTANCE
:
498 CHECKVAL(*values
>= 0.0f
);
500 Source
->MaxDistance
= *values
;
504 case AL_ROLLOFF_FACTOR
:
505 CHECKVAL(*values
>= 0.0f
);
507 Source
->RolloffFactor
= *values
;
511 case AL_REFERENCE_DISTANCE
:
512 CHECKVAL(*values
>= 0.0f
);
514 Source
->RefDistance
= *values
;
519 CHECKVAL(*values
>= 0.0f
);
521 Source
->MinGain
= *values
;
526 CHECKVAL(*values
>= 0.0f
);
528 Source
->MaxGain
= *values
;
532 case AL_CONE_OUTER_GAIN
:
533 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
535 Source
->OuterGain
= *values
;
539 case AL_CONE_OUTER_GAINHF
:
540 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
542 Source
->OuterGainHF
= *values
;
546 case AL_AIR_ABSORPTION_FACTOR
:
547 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
549 Source
->AirAbsorptionFactor
= *values
;
553 case AL_ROOM_ROLLOFF_FACTOR
:
554 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
556 Source
->RoomRolloffFactor
= *values
;
560 case AL_DOPPLER_FACTOR
:
561 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
563 Source
->DopplerFactor
= *values
;
568 case AL_SAMPLE_OFFSET
:
570 CHECKVAL(*values
>= 0.0f
);
572 Source
->OffsetType
= prop
;
573 Source
->Offset
= *values
;
575 if(IsPlayingOrPaused(Source
))
579 ALCdevice_Lock(Context
->Device
);
580 /* Double-check that the source is still playing while we have
583 voice
= GetSourceVoice(Source
, Context
);
586 WriteLock(&Source
->queue_lock
);
587 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
589 WriteUnlock(&Source
->queue_lock
);
590 ALCdevice_Unlock(Context
->Device
);
591 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
593 WriteUnlock(&Source
->queue_lock
);
595 ALCdevice_Unlock(Context
->Device
);
599 case AL_SOURCE_RADIUS
:
600 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
602 Source
->Radius
= *values
;
606 case AL_STEREO_ANGLES
:
607 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
609 Source
->StereoPan
[0] = values
[0];
610 Source
->StereoPan
[1] = values
[1];
616 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
618 Source
->Position
[0] = values
[0];
619 Source
->Position
[1] = values
[1];
620 Source
->Position
[2] = values
[2];
625 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
627 Source
->Velocity
[0] = values
[0];
628 Source
->Velocity
[1] = values
[1];
629 Source
->Velocity
[2] = values
[2];
634 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
636 Source
->Direction
[0] = values
[0];
637 Source
->Direction
[1] = values
[1];
638 Source
->Direction
[2] = values
[2];
643 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
644 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
646 Source
->Orientation
[0][0] = values
[0];
647 Source
->Orientation
[0][1] = values
[1];
648 Source
->Orientation
[0][2] = values
[2];
649 Source
->Orientation
[1][0] = values
[3];
650 Source
->Orientation
[1][1] = values
[4];
651 Source
->Orientation
[1][2] = values
[5];
656 case AL_SOURCE_RELATIVE
:
658 case AL_SOURCE_STATE
:
660 case AL_DISTANCE_MODEL
:
661 case AL_DIRECT_FILTER_GAINHF_AUTO
:
662 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
663 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
664 case AL_DIRECT_CHANNELS_SOFT
:
665 case AL_SOURCE_RESAMPLER_SOFT
:
666 case AL_SOURCE_SPATIALIZE_SOFT
:
667 ival
= (ALint
)values
[0];
668 return SetSourceiv(Source
, Context
, prop
, &ival
);
670 case AL_BUFFERS_QUEUED
:
671 case AL_BUFFERS_PROCESSED
:
672 ival
= (ALint
)((ALuint
)values
[0]);
673 return SetSourceiv(Source
, Context
, prop
, &ival
);
676 case AL_DIRECT_FILTER
:
677 case AL_AUXILIARY_SEND_FILTER
:
678 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
682 ERR("Unexpected property: 0x%04x\n", prop
);
683 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
686 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
688 ALCdevice
*device
= Context
->Device
;
689 ALbuffer
*buffer
= NULL
;
690 ALfilter
*filter
= NULL
;
691 ALeffectslot
*slot
= NULL
;
692 ALbufferlistitem
*oldlist
;
697 case AL_SOURCE_STATE
:
699 case AL_BUFFERS_QUEUED
:
700 case AL_BUFFERS_PROCESSED
:
701 case AL_BYTE_LENGTH_SOFT
:
702 case AL_SAMPLE_LENGTH_SOFT
:
703 case AL_SEC_LENGTH_SOFT
:
705 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
707 case AL_SOURCE_RELATIVE
:
708 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
710 Source
->HeadRelative
= (ALboolean
)*values
;
715 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
717 WriteLock(&Source
->queue_lock
);
718 Source
->Looping
= (ALboolean
)*values
;
719 if(IsPlayingOrPaused(Source
))
721 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
725 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
727 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
729 /* If the source is playing, wait for the current mix to finish
730 * to ensure it isn't currently looping back or reaching the
733 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
737 WriteUnlock(&Source
->queue_lock
);
741 LockBuffersRead(device
);
742 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
744 UnlockBuffersRead(device
);
745 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
748 WriteLock(&Source
->queue_lock
);
750 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
751 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
753 WriteUnlock(&Source
->queue_lock
);
754 UnlockBuffersRead(device
);
755 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
759 oldlist
= Source
->queue
;
762 /* Add the selected buffer to a one-item queue */
763 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
764 newlist
->buffer
= buffer
;
765 ATOMIC_INIT(&newlist
->next
, NULL
);
766 IncrementRef(&buffer
->ref
);
768 /* Source is now Static */
769 Source
->SourceType
= AL_STATIC
;
770 Source
->queue
= newlist
;
774 /* Source is now Undetermined */
775 Source
->SourceType
= AL_UNDETERMINED
;
776 Source
->queue
= NULL
;
778 WriteUnlock(&Source
->queue_lock
);
779 UnlockBuffersRead(device
);
781 /* Delete all elements in the previous queue */
782 while(oldlist
!= NULL
)
784 ALbufferlistitem
*temp
= oldlist
;
785 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
788 DecrementRef(&temp
->buffer
->ref
);
794 case AL_SAMPLE_OFFSET
:
796 CHECKVAL(*values
>= 0);
798 Source
->OffsetType
= prop
;
799 Source
->Offset
= *values
;
801 if(IsPlayingOrPaused(Source
))
805 ALCdevice_Lock(Context
->Device
);
806 voice
= GetSourceVoice(Source
, Context
);
809 WriteLock(&Source
->queue_lock
);
810 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
812 WriteUnlock(&Source
->queue_lock
);
813 ALCdevice_Unlock(Context
->Device
);
814 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
816 WriteUnlock(&Source
->queue_lock
);
818 ALCdevice_Unlock(Context
->Device
);
822 case AL_DIRECT_FILTER
:
823 LockFiltersRead(device
);
824 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
826 UnlockFiltersRead(device
);
827 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
832 Source
->Direct
.Gain
= 1.0f
;
833 Source
->Direct
.GainHF
= 1.0f
;
834 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
835 Source
->Direct
.GainLF
= 1.0f
;
836 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
840 Source
->Direct
.Gain
= filter
->Gain
;
841 Source
->Direct
.GainHF
= filter
->GainHF
;
842 Source
->Direct
.HFReference
= filter
->HFReference
;
843 Source
->Direct
.GainLF
= filter
->GainLF
;
844 Source
->Direct
.LFReference
= filter
->LFReference
;
846 UnlockFiltersRead(device
);
850 case AL_DIRECT_FILTER_GAINHF_AUTO
:
851 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
853 Source
->DryGainHFAuto
= *values
;
857 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
858 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
860 Source
->WetGainAuto
= *values
;
864 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
865 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
867 Source
->WetGainHFAuto
= *values
;
871 case AL_DIRECT_CHANNELS_SOFT
:
872 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
874 Source
->DirectChannels
= *values
;
878 case AL_DISTANCE_MODEL
:
879 CHECKVAL(*values
== AL_NONE
||
880 *values
== AL_INVERSE_DISTANCE
||
881 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
882 *values
== AL_LINEAR_DISTANCE
||
883 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
884 *values
== AL_EXPONENT_DISTANCE
||
885 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
887 Source
->DistanceModel
= *values
;
888 if(Context
->SourceDistanceModel
)
892 case AL_SOURCE_RESAMPLER_SOFT
:
893 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
895 Source
->Resampler
= *values
;
899 case AL_SOURCE_SPATIALIZE_SOFT
:
900 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
902 Source
->Spatialize
= *values
;
907 case AL_AUXILIARY_SEND_FILTER
:
908 LockEffectSlotsRead(Context
);
909 LockFiltersRead(device
);
910 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
911 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
912 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
914 UnlockFiltersRead(device
);
915 UnlockEffectSlotsRead(Context
);
916 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
922 Source
->Send
[values
[1]].Gain
= 1.0f
;
923 Source
->Send
[values
[1]].GainHF
= 1.0f
;
924 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
925 Source
->Send
[values
[1]].GainLF
= 1.0f
;
926 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
930 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
931 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
932 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
933 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
934 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
936 UnlockFiltersRead(device
);
938 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
941 /* Add refcount on the new slot, and release the previous slot */
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
;
947 /* We must force an update if the auxiliary slot changed on an
948 * active source, in case the slot is about to be deleted.
950 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
951 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
953 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
957 if(slot
) IncrementRef(&slot
->ref
);
958 if(Source
->Send
[values
[1]].Slot
)
959 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
960 Source
->Send
[values
[1]].Slot
= slot
;
963 UnlockEffectSlotsRead(Context
);
969 case AL_CONE_INNER_ANGLE
:
970 case AL_CONE_OUTER_ANGLE
:
975 case AL_REFERENCE_DISTANCE
:
976 case AL_ROLLOFF_FACTOR
:
977 case AL_CONE_OUTER_GAIN
:
978 case AL_MAX_DISTANCE
:
979 case AL_DOPPLER_FACTOR
:
980 case AL_CONE_OUTER_GAINHF
:
981 case AL_AIR_ABSORPTION_FACTOR
:
982 case AL_ROOM_ROLLOFF_FACTOR
:
983 case AL_SOURCE_RADIUS
:
984 fvals
[0] = (ALfloat
)*values
;
985 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
991 fvals
[0] = (ALfloat
)values
[0];
992 fvals
[1] = (ALfloat
)values
[1];
993 fvals
[2] = (ALfloat
)values
[2];
994 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
998 fvals
[0] = (ALfloat
)values
[0];
999 fvals
[1] = (ALfloat
)values
[1];
1000 fvals
[2] = (ALfloat
)values
[2];
1001 fvals
[3] = (ALfloat
)values
[3];
1002 fvals
[4] = (ALfloat
)values
[4];
1003 fvals
[5] = (ALfloat
)values
[5];
1004 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1006 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1007 case AL_SEC_OFFSET_LATENCY_SOFT
:
1008 case AL_STEREO_ANGLES
:
1012 ERR("Unexpected property: 0x%04x\n", prop
);
1013 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1016 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1023 case AL_SOURCE_TYPE
:
1024 case AL_BUFFERS_QUEUED
:
1025 case AL_BUFFERS_PROCESSED
:
1026 case AL_SOURCE_STATE
:
1027 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1028 case AL_BYTE_LENGTH_SOFT
:
1029 case AL_SAMPLE_LENGTH_SOFT
:
1030 case AL_SEC_LENGTH_SOFT
:
1032 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
1036 case AL_SOURCE_RELATIVE
:
1039 case AL_SAMPLE_OFFSET
:
1040 case AL_BYTE_OFFSET
:
1041 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1042 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1043 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1044 case AL_DIRECT_CHANNELS_SOFT
:
1045 case AL_DISTANCE_MODEL
:
1046 case AL_SOURCE_RESAMPLER_SOFT
:
1047 case AL_SOURCE_SPATIALIZE_SOFT
:
1048 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1050 ivals
[0] = (ALint
)*values
;
1051 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1055 case AL_DIRECT_FILTER
:
1056 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1058 ivals
[0] = (ALuint
)*values
;
1059 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1062 case AL_AUXILIARY_SEND_FILTER
:
1063 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1064 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1065 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1067 ivals
[0] = (ALuint
)values
[0];
1068 ivals
[1] = (ALuint
)values
[1];
1069 ivals
[2] = (ALuint
)values
[2];
1070 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1073 case AL_CONE_INNER_ANGLE
:
1074 case AL_CONE_OUTER_ANGLE
:
1079 case AL_REFERENCE_DISTANCE
:
1080 case AL_ROLLOFF_FACTOR
:
1081 case AL_CONE_OUTER_GAIN
:
1082 case AL_MAX_DISTANCE
:
1083 case AL_DOPPLER_FACTOR
:
1084 case AL_CONE_OUTER_GAINHF
:
1085 case AL_AIR_ABSORPTION_FACTOR
:
1086 case AL_ROOM_ROLLOFF_FACTOR
:
1087 case AL_SOURCE_RADIUS
:
1088 fvals
[0] = (ALfloat
)*values
;
1089 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1095 fvals
[0] = (ALfloat
)values
[0];
1096 fvals
[1] = (ALfloat
)values
[1];
1097 fvals
[2] = (ALfloat
)values
[2];
1098 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1101 case AL_ORIENTATION
:
1102 fvals
[0] = (ALfloat
)values
[0];
1103 fvals
[1] = (ALfloat
)values
[1];
1104 fvals
[2] = (ALfloat
)values
[2];
1105 fvals
[3] = (ALfloat
)values
[3];
1106 fvals
[4] = (ALfloat
)values
[4];
1107 fvals
[5] = (ALfloat
)values
[5];
1108 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1110 case AL_SEC_OFFSET_LATENCY_SOFT
:
1111 case AL_STEREO_ANGLES
:
1115 ERR("Unexpected property: 0x%04x\n", prop
);
1116 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1122 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1124 ALCdevice
*device
= Context
->Device
;
1125 ALbufferlistitem
*BufferList
;
1126 ClockLatency clocktime
;
1134 *values
= Source
->Gain
;
1138 *values
= Source
->Pitch
;
1141 case AL_MAX_DISTANCE
:
1142 *values
= Source
->MaxDistance
;
1145 case AL_ROLLOFF_FACTOR
:
1146 *values
= Source
->RolloffFactor
;
1149 case AL_REFERENCE_DISTANCE
:
1150 *values
= Source
->RefDistance
;
1153 case AL_CONE_INNER_ANGLE
:
1154 *values
= Source
->InnerAngle
;
1157 case AL_CONE_OUTER_ANGLE
:
1158 *values
= Source
->OuterAngle
;
1162 *values
= Source
->MinGain
;
1166 *values
= Source
->MaxGain
;
1169 case AL_CONE_OUTER_GAIN
:
1170 *values
= Source
->OuterGain
;
1174 case AL_SAMPLE_OFFSET
:
1175 case AL_BYTE_OFFSET
:
1176 *values
= GetSourceOffset(Source
, prop
, Context
);
1179 case AL_CONE_OUTER_GAINHF
:
1180 *values
= Source
->OuterGainHF
;
1183 case AL_AIR_ABSORPTION_FACTOR
:
1184 *values
= Source
->AirAbsorptionFactor
;
1187 case AL_ROOM_ROLLOFF_FACTOR
:
1188 *values
= Source
->RoomRolloffFactor
;
1191 case AL_DOPPLER_FACTOR
:
1192 *values
= Source
->DopplerFactor
;
1195 case AL_SEC_LENGTH_SOFT
:
1196 ReadLock(&Source
->queue_lock
);
1197 if(!(BufferList
=Source
->queue
))
1204 ALbuffer
*buffer
= BufferList
->buffer
;
1205 if(buffer
&& buffer
->SampleLen
> 0)
1207 freq
= buffer
->Frequency
;
1208 length
+= buffer
->SampleLen
;
1210 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1211 } while(BufferList
!= NULL
);
1212 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1214 ReadUnlock(&Source
->queue_lock
);
1217 case AL_SOURCE_RADIUS
:
1218 *values
= Source
->Radius
;
1221 case AL_STEREO_ANGLES
:
1222 values
[0] = Source
->StereoPan
[0];
1223 values
[1] = Source
->StereoPan
[1];
1226 case AL_SEC_OFFSET_LATENCY_SOFT
:
1227 /* Get the source offset with the clock time first. Then get the
1228 * clock time with the device latency. Order is important.
1230 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1231 clocktime
= V0(device
->Backend
,getClockLatency
)();
1232 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1233 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1236 /* If the clock time incremented, reduce the latency by that
1237 * much since it's that much closer to the source offset it got
1240 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1241 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1247 values
[0] = Source
->Position
[0];
1248 values
[1] = Source
->Position
[1];
1249 values
[2] = Source
->Position
[2];
1253 values
[0] = Source
->Velocity
[0];
1254 values
[1] = Source
->Velocity
[1];
1255 values
[2] = Source
->Velocity
[2];
1259 values
[0] = Source
->Direction
[0];
1260 values
[1] = Source
->Direction
[1];
1261 values
[2] = Source
->Direction
[2];
1264 case AL_ORIENTATION
:
1265 values
[0] = Source
->Orientation
[0][0];
1266 values
[1] = Source
->Orientation
[0][1];
1267 values
[2] = Source
->Orientation
[0][2];
1268 values
[3] = Source
->Orientation
[1][0];
1269 values
[4] = Source
->Orientation
[1][1];
1270 values
[5] = Source
->Orientation
[1][2];
1274 case AL_SOURCE_RELATIVE
:
1276 case AL_SOURCE_STATE
:
1277 case AL_BUFFERS_QUEUED
:
1278 case AL_BUFFERS_PROCESSED
:
1279 case AL_SOURCE_TYPE
:
1280 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1281 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1282 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1283 case AL_DIRECT_CHANNELS_SOFT
:
1284 case AL_BYTE_LENGTH_SOFT
:
1285 case AL_SAMPLE_LENGTH_SOFT
:
1286 case AL_DISTANCE_MODEL
:
1287 case AL_SOURCE_RESAMPLER_SOFT
:
1288 case AL_SOURCE_SPATIALIZE_SOFT
:
1289 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1290 *values
= (ALdouble
)ivals
[0];
1294 case AL_DIRECT_FILTER
:
1295 case AL_AUXILIARY_SEND_FILTER
:
1296 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1300 ERR("Unexpected property: 0x%04x\n", prop
);
1301 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1304 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1306 ALbufferlistitem
*BufferList
;
1312 case AL_SOURCE_RELATIVE
:
1313 *values
= Source
->HeadRelative
;
1317 *values
= Source
->Looping
;
1321 ReadLock(&Source
->queue_lock
);
1322 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1323 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1324 ReadUnlock(&Source
->queue_lock
);
1327 case AL_SOURCE_STATE
:
1328 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1331 case AL_BYTE_LENGTH_SOFT
:
1332 ReadLock(&Source
->queue_lock
);
1333 if(!(BufferList
=Source
->queue
))
1339 ALbuffer
*buffer
= BufferList
->buffer
;
1340 if(buffer
&& buffer
->SampleLen
> 0)
1342 ALuint byte_align
, sample_align
;
1343 if(buffer
->OriginalType
== UserFmtIMA4
)
1345 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1346 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1347 sample_align
= buffer
->OriginalAlign
;
1349 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1351 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1352 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1353 sample_align
= buffer
->OriginalAlign
;
1357 ALsizei align
= buffer
->OriginalAlign
;
1358 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1359 sample_align
= buffer
->OriginalAlign
;
1362 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1364 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1365 } while(BufferList
!= NULL
);
1368 ReadUnlock(&Source
->queue_lock
);
1371 case AL_SAMPLE_LENGTH_SOFT
:
1372 ReadLock(&Source
->queue_lock
);
1373 if(!(BufferList
=Source
->queue
))
1379 ALbuffer
*buffer
= BufferList
->buffer
;
1380 if(buffer
) length
+= buffer
->SampleLen
;
1381 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1382 } while(BufferList
!= NULL
);
1385 ReadUnlock(&Source
->queue_lock
);
1388 case AL_BUFFERS_QUEUED
:
1389 ReadLock(&Source
->queue_lock
);
1390 if(!(BufferList
=Source
->queue
))
1397 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1398 } while(BufferList
!= NULL
);
1401 ReadUnlock(&Source
->queue_lock
);
1404 case AL_BUFFERS_PROCESSED
:
1405 ReadLock(&Source
->queue_lock
);
1406 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1408 /* Buffers on a looping source are in a perpetual state of
1409 * PENDING, so don't report any as PROCESSED */
1414 const ALbufferlistitem
*BufferList
= Source
->queue
;
1415 const ALbufferlistitem
*Current
= NULL
;
1419 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1420 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1421 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1422 Current
= BufferList
;
1424 while(BufferList
&& BufferList
!= Current
)
1427 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1428 almemory_order_relaxed
);
1432 ReadUnlock(&Source
->queue_lock
);
1435 case AL_SOURCE_TYPE
:
1436 *values
= Source
->SourceType
;
1439 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1440 *values
= Source
->DryGainHFAuto
;
1443 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1444 *values
= Source
->WetGainAuto
;
1447 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1448 *values
= Source
->WetGainHFAuto
;
1451 case AL_DIRECT_CHANNELS_SOFT
:
1452 *values
= Source
->DirectChannels
;
1455 case AL_DISTANCE_MODEL
:
1456 *values
= Source
->DistanceModel
;
1459 case AL_SOURCE_RESAMPLER_SOFT
:
1460 *values
= Source
->Resampler
;
1463 case AL_SOURCE_SPATIALIZE_SOFT
:
1464 *values
= Source
->Spatialize
;
1467 /* 1x float/double */
1468 case AL_CONE_INNER_ANGLE
:
1469 case AL_CONE_OUTER_ANGLE
:
1474 case AL_REFERENCE_DISTANCE
:
1475 case AL_ROLLOFF_FACTOR
:
1476 case AL_CONE_OUTER_GAIN
:
1477 case AL_MAX_DISTANCE
:
1479 case AL_SAMPLE_OFFSET
:
1480 case AL_BYTE_OFFSET
:
1481 case AL_DOPPLER_FACTOR
:
1482 case AL_AIR_ABSORPTION_FACTOR
:
1483 case AL_ROOM_ROLLOFF_FACTOR
:
1484 case AL_CONE_OUTER_GAINHF
:
1485 case AL_SEC_LENGTH_SOFT
:
1486 case AL_SOURCE_RADIUS
:
1487 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1488 *values
= (ALint
)dvals
[0];
1491 /* 3x float/double */
1495 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1497 values
[0] = (ALint
)dvals
[0];
1498 values
[1] = (ALint
)dvals
[1];
1499 values
[2] = (ALint
)dvals
[2];
1503 /* 6x float/double */
1504 case AL_ORIENTATION
:
1505 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1507 values
[0] = (ALint
)dvals
[0];
1508 values
[1] = (ALint
)dvals
[1];
1509 values
[2] = (ALint
)dvals
[2];
1510 values
[3] = (ALint
)dvals
[3];
1511 values
[4] = (ALint
)dvals
[4];
1512 values
[5] = (ALint
)dvals
[5];
1516 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1517 break; /* i64 only */
1518 case AL_SEC_OFFSET_LATENCY_SOFT
:
1519 break; /* Double only */
1520 case AL_STEREO_ANGLES
:
1521 break; /* Float/double only */
1523 case AL_DIRECT_FILTER
:
1524 case AL_AUXILIARY_SEND_FILTER
:
1528 ERR("Unexpected property: 0x%04x\n", prop
);
1529 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1532 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1534 ALCdevice
*device
= Context
->Device
;
1535 ClockLatency clocktime
;
1543 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1544 /* Get the source offset with the clock time first. Then get the
1545 * clock time with the device latency. Order is important.
1547 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1548 clocktime
= V0(device
->Backend
,getClockLatency
)();
1549 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1550 values
[1] = clocktime
.Latency
;
1553 /* If the clock time incremented, reduce the latency by that
1554 * much since it's that much closer to the source offset it got
1557 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1558 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1562 /* 1x float/double */
1563 case AL_CONE_INNER_ANGLE
:
1564 case AL_CONE_OUTER_ANGLE
:
1569 case AL_REFERENCE_DISTANCE
:
1570 case AL_ROLLOFF_FACTOR
:
1571 case AL_CONE_OUTER_GAIN
:
1572 case AL_MAX_DISTANCE
:
1574 case AL_SAMPLE_OFFSET
:
1575 case AL_BYTE_OFFSET
:
1576 case AL_DOPPLER_FACTOR
:
1577 case AL_AIR_ABSORPTION_FACTOR
:
1578 case AL_ROOM_ROLLOFF_FACTOR
:
1579 case AL_CONE_OUTER_GAINHF
:
1580 case AL_SEC_LENGTH_SOFT
:
1581 case AL_SOURCE_RADIUS
:
1582 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1583 *values
= (ALint64
)dvals
[0];
1586 /* 3x float/double */
1590 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1592 values
[0] = (ALint64
)dvals
[0];
1593 values
[1] = (ALint64
)dvals
[1];
1594 values
[2] = (ALint64
)dvals
[2];
1598 /* 6x float/double */
1599 case AL_ORIENTATION
:
1600 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1602 values
[0] = (ALint64
)dvals
[0];
1603 values
[1] = (ALint64
)dvals
[1];
1604 values
[2] = (ALint64
)dvals
[2];
1605 values
[3] = (ALint64
)dvals
[3];
1606 values
[4] = (ALint64
)dvals
[4];
1607 values
[5] = (ALint64
)dvals
[5];
1612 case AL_SOURCE_RELATIVE
:
1614 case AL_SOURCE_STATE
:
1615 case AL_BUFFERS_QUEUED
:
1616 case AL_BUFFERS_PROCESSED
:
1617 case AL_BYTE_LENGTH_SOFT
:
1618 case AL_SAMPLE_LENGTH_SOFT
:
1619 case AL_SOURCE_TYPE
:
1620 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1621 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1622 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1623 case AL_DIRECT_CHANNELS_SOFT
:
1624 case AL_DISTANCE_MODEL
:
1625 case AL_SOURCE_RESAMPLER_SOFT
:
1626 case AL_SOURCE_SPATIALIZE_SOFT
:
1627 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1633 case AL_DIRECT_FILTER
:
1634 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1635 *values
= (ALuint
)ivals
[0];
1639 case AL_AUXILIARY_SEND_FILTER
:
1640 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1642 values
[0] = (ALuint
)ivals
[0];
1643 values
[1] = (ALuint
)ivals
[1];
1644 values
[2] = (ALuint
)ivals
[2];
1648 case AL_SEC_OFFSET_LATENCY_SOFT
:
1649 break; /* Double only */
1650 case AL_STEREO_ANGLES
:
1651 break; /* Float/double only */
1654 ERR("Unexpected property: 0x%04x\n", prop
);
1655 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1659 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1662 ALCcontext
*context
;
1666 context
= GetContextRef();
1667 if(!context
) return;
1670 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1671 device
= context
->Device
;
1672 for(cur
= 0;cur
< n
;cur
++)
1674 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1677 alDeleteSources(cur
, sources
);
1678 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1680 InitSourceParams(source
, device
->NumAuxSends
);
1682 err
= NewThunkEntry(&source
->id
);
1683 if(err
== AL_NO_ERROR
)
1684 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1685 if(err
!= AL_NO_ERROR
)
1687 FreeThunkEntry(source
->id
);
1688 memset(source
, 0, sizeof(ALsource
));
1691 alDeleteSources(cur
, sources
);
1692 SET_ERROR_AND_GOTO(context
, err
, done
);
1695 sources
[cur
] = source
->id
;
1699 ALCcontext_DecRef(context
);
1703 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1706 ALCcontext
*context
;
1710 context
= GetContextRef();
1711 if(!context
) return;
1713 LockSourcesWrite(context
);
1715 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1717 /* Check that all Sources are valid */
1718 for(i
= 0;i
< n
;i
++)
1720 if(LookupSource(context
, sources
[i
]) == NULL
)
1721 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1723 device
= context
->Device
;
1724 for(i
= 0;i
< n
;i
++)
1728 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1730 FreeThunkEntry(Source
->id
);
1732 ALCdevice_Lock(device
);
1733 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1735 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1736 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1738 ALCdevice_Unlock(device
);
1740 DeinitSource(Source
, device
->NumAuxSends
);
1742 memset(Source
, 0, sizeof(*Source
));
1747 UnlockSourcesWrite(context
);
1748 ALCcontext_DecRef(context
);
1752 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1754 ALCcontext
*context
;
1757 context
= GetContextRef();
1758 if(!context
) return AL_FALSE
;
1760 LockSourcesRead(context
);
1761 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1762 UnlockSourcesRead(context
);
1764 ALCcontext_DecRef(context
);
1770 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
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
) == 1))
1783 alSetError(Context
, AL_INVALID_ENUM
);
1785 SetSourcefv(Source
, Context
, param
, &value
);
1786 UnlockSourcesRead(Context
);
1787 WriteUnlock(&Context
->PropLock
);
1789 ALCcontext_DecRef(Context
);
1792 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1794 ALCcontext
*Context
;
1797 Context
= GetContextRef();
1798 if(!Context
) return;
1800 WriteLock(&Context
->PropLock
);
1801 LockSourcesRead(Context
);
1802 if((Source
=LookupSource(Context
, source
)) == NULL
)
1803 alSetError(Context
, AL_INVALID_NAME
);
1804 else if(!(FloatValsByProp(param
) == 3))
1805 alSetError(Context
, AL_INVALID_ENUM
);
1808 ALfloat fvals
[3] = { value1
, value2
, value3
};
1809 SetSourcefv(Source
, Context
, param
, fvals
);
1811 UnlockSourcesRead(Context
);
1812 WriteUnlock(&Context
->PropLock
);
1814 ALCcontext_DecRef(Context
);
1817 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1819 ALCcontext
*Context
;
1822 Context
= GetContextRef();
1823 if(!Context
) return;
1825 WriteLock(&Context
->PropLock
);
1826 LockSourcesRead(Context
);
1827 if((Source
=LookupSource(Context
, source
)) == NULL
)
1828 alSetError(Context
, AL_INVALID_NAME
);
1830 alSetError(Context
, AL_INVALID_VALUE
);
1831 else if(!(FloatValsByProp(param
) > 0))
1832 alSetError(Context
, AL_INVALID_ENUM
);
1834 SetSourcefv(Source
, Context
, param
, values
);
1835 UnlockSourcesRead(Context
);
1836 WriteUnlock(&Context
->PropLock
);
1838 ALCcontext_DecRef(Context
);
1842 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1844 ALCcontext
*Context
;
1847 Context
= GetContextRef();
1848 if(!Context
) return;
1850 WriteLock(&Context
->PropLock
);
1851 LockSourcesRead(Context
);
1852 if((Source
=LookupSource(Context
, source
)) == NULL
)
1853 alSetError(Context
, AL_INVALID_NAME
);
1854 else if(!(DoubleValsByProp(param
) == 1))
1855 alSetError(Context
, AL_INVALID_ENUM
);
1858 ALfloat fval
= (ALfloat
)value
;
1859 SetSourcefv(Source
, Context
, param
, &fval
);
1861 UnlockSourcesRead(Context
);
1862 WriteUnlock(&Context
->PropLock
);
1864 ALCcontext_DecRef(Context
);
1867 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1869 ALCcontext
*Context
;
1872 Context
= GetContextRef();
1873 if(!Context
) return;
1875 WriteLock(&Context
->PropLock
);
1876 LockSourcesRead(Context
);
1877 if((Source
=LookupSource(Context
, source
)) == NULL
)
1878 alSetError(Context
, AL_INVALID_NAME
);
1879 else if(!(DoubleValsByProp(param
) == 3))
1880 alSetError(Context
, AL_INVALID_ENUM
);
1883 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1884 SetSourcefv(Source
, Context
, param
, fvals
);
1886 UnlockSourcesRead(Context
);
1887 WriteUnlock(&Context
->PropLock
);
1889 ALCcontext_DecRef(Context
);
1892 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1894 ALCcontext
*Context
;
1898 Context
= GetContextRef();
1899 if(!Context
) return;
1901 WriteLock(&Context
->PropLock
);
1902 LockSourcesRead(Context
);
1903 if((Source
=LookupSource(Context
, source
)) == NULL
)
1904 alSetError(Context
, AL_INVALID_NAME
);
1906 alSetError(Context
, AL_INVALID_VALUE
);
1907 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1908 alSetError(Context
, AL_INVALID_ENUM
);
1914 for(i
= 0;i
< count
;i
++)
1915 fvals
[i
] = (ALfloat
)values
[i
];
1916 SetSourcefv(Source
, Context
, param
, fvals
);
1918 UnlockSourcesRead(Context
);
1919 WriteUnlock(&Context
->PropLock
);
1921 ALCcontext_DecRef(Context
);
1925 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
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
) == 1))
1938 alSetError(Context
, AL_INVALID_ENUM
);
1940 SetSourceiv(Source
, Context
, param
, &value
);
1941 UnlockSourcesRead(Context
);
1942 WriteUnlock(&Context
->PropLock
);
1944 ALCcontext_DecRef(Context
);
1947 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1949 ALCcontext
*Context
;
1952 Context
= GetContextRef();
1953 if(!Context
) return;
1955 WriteLock(&Context
->PropLock
);
1956 LockSourcesRead(Context
);
1957 if((Source
=LookupSource(Context
, source
)) == NULL
)
1958 alSetError(Context
, AL_INVALID_NAME
);
1959 else if(!(IntValsByProp(param
) == 3))
1960 alSetError(Context
, AL_INVALID_ENUM
);
1963 ALint ivals
[3] = { value1
, value2
, value3
};
1964 SetSourceiv(Source
, Context
, param
, ivals
);
1966 UnlockSourcesRead(Context
);
1967 WriteUnlock(&Context
->PropLock
);
1969 ALCcontext_DecRef(Context
);
1972 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1974 ALCcontext
*Context
;
1977 Context
= GetContextRef();
1978 if(!Context
) return;
1980 WriteLock(&Context
->PropLock
);
1981 LockSourcesRead(Context
);
1982 if((Source
=LookupSource(Context
, source
)) == NULL
)
1983 alSetError(Context
, AL_INVALID_NAME
);
1985 alSetError(Context
, AL_INVALID_VALUE
);
1986 else if(!(IntValsByProp(param
) > 0))
1987 alSetError(Context
, AL_INVALID_ENUM
);
1989 SetSourceiv(Source
, Context
, param
, values
);
1990 UnlockSourcesRead(Context
);
1991 WriteUnlock(&Context
->PropLock
);
1993 ALCcontext_DecRef(Context
);
1997 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
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
) == 1))
2010 alSetError(Context
, AL_INVALID_ENUM
);
2012 SetSourcei64v(Source
, Context
, param
, &value
);
2013 UnlockSourcesRead(Context
);
2014 WriteUnlock(&Context
->PropLock
);
2016 ALCcontext_DecRef(Context
);
2019 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2021 ALCcontext
*Context
;
2024 Context
= GetContextRef();
2025 if(!Context
) return;
2027 WriteLock(&Context
->PropLock
);
2028 LockSourcesRead(Context
);
2029 if((Source
=LookupSource(Context
, source
)) == NULL
)
2030 alSetError(Context
, AL_INVALID_NAME
);
2031 else if(!(Int64ValsByProp(param
) == 3))
2032 alSetError(Context
, AL_INVALID_ENUM
);
2035 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2036 SetSourcei64v(Source
, Context
, param
, i64vals
);
2038 UnlockSourcesRead(Context
);
2039 WriteUnlock(&Context
->PropLock
);
2041 ALCcontext_DecRef(Context
);
2044 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2046 ALCcontext
*Context
;
2049 Context
= GetContextRef();
2050 if(!Context
) return;
2052 WriteLock(&Context
->PropLock
);
2053 LockSourcesRead(Context
);
2054 if((Source
=LookupSource(Context
, source
)) == NULL
)
2055 alSetError(Context
, AL_INVALID_NAME
);
2057 alSetError(Context
, AL_INVALID_VALUE
);
2058 else if(!(Int64ValsByProp(param
) > 0))
2059 alSetError(Context
, AL_INVALID_ENUM
);
2061 SetSourcei64v(Source
, Context
, param
, values
);
2062 UnlockSourcesRead(Context
);
2063 WriteUnlock(&Context
->PropLock
);
2065 ALCcontext_DecRef(Context
);
2069 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2071 ALCcontext
*Context
;
2074 Context
= GetContextRef();
2075 if(!Context
) return;
2077 ReadLock(&Context
->PropLock
);
2078 LockSourcesRead(Context
);
2079 if((Source
=LookupSource(Context
, source
)) == NULL
)
2080 alSetError(Context
, AL_INVALID_NAME
);
2082 alSetError(Context
, AL_INVALID_VALUE
);
2083 else if(!(FloatValsByProp(param
) == 1))
2084 alSetError(Context
, AL_INVALID_ENUM
);
2088 if(GetSourcedv(Source
, Context
, param
, &dval
))
2089 *value
= (ALfloat
)dval
;
2091 UnlockSourcesRead(Context
);
2092 ReadUnlock(&Context
->PropLock
);
2094 ALCcontext_DecRef(Context
);
2098 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2100 ALCcontext
*Context
;
2103 Context
= GetContextRef();
2104 if(!Context
) return;
2106 ReadLock(&Context
->PropLock
);
2107 LockSourcesRead(Context
);
2108 if((Source
=LookupSource(Context
, source
)) == NULL
)
2109 alSetError(Context
, AL_INVALID_NAME
);
2110 else if(!(value1
&& value2
&& value3
))
2111 alSetError(Context
, AL_INVALID_VALUE
);
2112 else if(!(FloatValsByProp(param
) == 3))
2113 alSetError(Context
, AL_INVALID_ENUM
);
2117 if(GetSourcedv(Source
, Context
, param
, dvals
))
2119 *value1
= (ALfloat
)dvals
[0];
2120 *value2
= (ALfloat
)dvals
[1];
2121 *value3
= (ALfloat
)dvals
[2];
2124 UnlockSourcesRead(Context
);
2125 ReadUnlock(&Context
->PropLock
);
2127 ALCcontext_DecRef(Context
);
2131 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2133 ALCcontext
*Context
;
2137 Context
= GetContextRef();
2138 if(!Context
) return;
2140 ReadLock(&Context
->PropLock
);
2141 LockSourcesRead(Context
);
2142 if((Source
=LookupSource(Context
, source
)) == NULL
)
2143 alSetError(Context
, AL_INVALID_NAME
);
2145 alSetError(Context
, AL_INVALID_VALUE
);
2146 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2147 alSetError(Context
, AL_INVALID_ENUM
);
2151 if(GetSourcedv(Source
, Context
, param
, dvals
))
2154 for(i
= 0;i
< count
;i
++)
2155 values
[i
] = (ALfloat
)dvals
[i
];
2158 UnlockSourcesRead(Context
);
2159 ReadUnlock(&Context
->PropLock
);
2161 ALCcontext_DecRef(Context
);
2165 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2167 ALCcontext
*Context
;
2170 Context
= GetContextRef();
2171 if(!Context
) return;
2173 ReadLock(&Context
->PropLock
);
2174 LockSourcesRead(Context
);
2175 if((Source
=LookupSource(Context
, source
)) == NULL
)
2176 alSetError(Context
, AL_INVALID_NAME
);
2178 alSetError(Context
, AL_INVALID_VALUE
);
2179 else if(!(DoubleValsByProp(param
) == 1))
2180 alSetError(Context
, AL_INVALID_ENUM
);
2182 GetSourcedv(Source
, Context
, param
, value
);
2183 UnlockSourcesRead(Context
);
2184 ReadUnlock(&Context
->PropLock
);
2186 ALCcontext_DecRef(Context
);
2189 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2191 ALCcontext
*Context
;
2194 Context
= GetContextRef();
2195 if(!Context
) return;
2197 ReadLock(&Context
->PropLock
);
2198 LockSourcesRead(Context
);
2199 if((Source
=LookupSource(Context
, source
)) == NULL
)
2200 alSetError(Context
, AL_INVALID_NAME
);
2201 else if(!(value1
&& value2
&& value3
))
2202 alSetError(Context
, AL_INVALID_VALUE
);
2203 else if(!(DoubleValsByProp(param
) == 3))
2204 alSetError(Context
, AL_INVALID_ENUM
);
2208 if(GetSourcedv(Source
, Context
, param
, dvals
))
2215 UnlockSourcesRead(Context
);
2216 ReadUnlock(&Context
->PropLock
);
2218 ALCcontext_DecRef(Context
);
2221 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2223 ALCcontext
*Context
;
2226 Context
= GetContextRef();
2227 if(!Context
) return;
2229 ReadLock(&Context
->PropLock
);
2230 LockSourcesRead(Context
);
2231 if((Source
=LookupSource(Context
, source
)) == NULL
)
2232 alSetError(Context
, AL_INVALID_NAME
);
2234 alSetError(Context
, AL_INVALID_VALUE
);
2235 else if(!(DoubleValsByProp(param
) > 0))
2236 alSetError(Context
, AL_INVALID_ENUM
);
2238 GetSourcedv(Source
, Context
, param
, values
);
2239 UnlockSourcesRead(Context
);
2240 ReadUnlock(&Context
->PropLock
);
2242 ALCcontext_DecRef(Context
);
2246 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2248 ALCcontext
*Context
;
2251 Context
= GetContextRef();
2252 if(!Context
) return;
2254 ReadLock(&Context
->PropLock
);
2255 LockSourcesRead(Context
);
2256 if((Source
=LookupSource(Context
, source
)) == NULL
)
2257 alSetError(Context
, AL_INVALID_NAME
);
2259 alSetError(Context
, AL_INVALID_VALUE
);
2260 else if(!(IntValsByProp(param
) == 1))
2261 alSetError(Context
, AL_INVALID_ENUM
);
2263 GetSourceiv(Source
, Context
, param
, value
);
2264 UnlockSourcesRead(Context
);
2265 ReadUnlock(&Context
->PropLock
);
2267 ALCcontext_DecRef(Context
);
2271 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2273 ALCcontext
*Context
;
2276 Context
= GetContextRef();
2277 if(!Context
) return;
2279 ReadLock(&Context
->PropLock
);
2280 LockSourcesRead(Context
);
2281 if((Source
=LookupSource(Context
, source
)) == NULL
)
2282 alSetError(Context
, AL_INVALID_NAME
);
2283 else if(!(value1
&& value2
&& value3
))
2284 alSetError(Context
, AL_INVALID_VALUE
);
2285 else if(!(IntValsByProp(param
) == 3))
2286 alSetError(Context
, AL_INVALID_ENUM
);
2290 if(GetSourceiv(Source
, Context
, param
, ivals
))
2297 UnlockSourcesRead(Context
);
2298 ReadUnlock(&Context
->PropLock
);
2300 ALCcontext_DecRef(Context
);
2304 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
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
);
2317 alSetError(Context
, AL_INVALID_VALUE
);
2318 else if(!(IntValsByProp(param
) > 0))
2319 alSetError(Context
, AL_INVALID_ENUM
);
2321 GetSourceiv(Source
, Context
, param
, values
);
2322 UnlockSourcesRead(Context
);
2323 ReadUnlock(&Context
->PropLock
);
2325 ALCcontext_DecRef(Context
);
2329 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2331 ALCcontext
*Context
;
2334 Context
= GetContextRef();
2335 if(!Context
) return;
2337 ReadLock(&Context
->PropLock
);
2338 LockSourcesRead(Context
);
2339 if((Source
=LookupSource(Context
, source
)) == NULL
)
2340 alSetError(Context
, AL_INVALID_NAME
);
2342 alSetError(Context
, AL_INVALID_VALUE
);
2343 else if(!(Int64ValsByProp(param
) == 1))
2344 alSetError(Context
, AL_INVALID_ENUM
);
2346 GetSourcei64v(Source
, Context
, param
, value
);
2347 UnlockSourcesRead(Context
);
2348 ReadUnlock(&Context
->PropLock
);
2350 ALCcontext_DecRef(Context
);
2353 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2355 ALCcontext
*Context
;
2358 Context
= GetContextRef();
2359 if(!Context
) return;
2361 ReadLock(&Context
->PropLock
);
2362 LockSourcesRead(Context
);
2363 if((Source
=LookupSource(Context
, source
)) == NULL
)
2364 alSetError(Context
, AL_INVALID_NAME
);
2365 else if(!(value1
&& value2
&& value3
))
2366 alSetError(Context
, AL_INVALID_VALUE
);
2367 else if(!(Int64ValsByProp(param
) == 3))
2368 alSetError(Context
, AL_INVALID_ENUM
);
2372 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2374 *value1
= i64vals
[0];
2375 *value2
= i64vals
[1];
2376 *value3
= i64vals
[2];
2379 UnlockSourcesRead(Context
);
2380 ReadUnlock(&Context
->PropLock
);
2382 ALCcontext_DecRef(Context
);
2385 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2387 ALCcontext
*Context
;
2390 Context
= GetContextRef();
2391 if(!Context
) return;
2393 ReadLock(&Context
->PropLock
);
2394 LockSourcesRead(Context
);
2395 if((Source
=LookupSource(Context
, source
)) == NULL
)
2396 alSetError(Context
, AL_INVALID_NAME
);
2398 alSetError(Context
, AL_INVALID_VALUE
);
2399 else if(!(Int64ValsByProp(param
) > 0))
2400 alSetError(Context
, AL_INVALID_ENUM
);
2402 GetSourcei64v(Source
, Context
, param
, values
);
2403 UnlockSourcesRead(Context
);
2404 ReadUnlock(&Context
->PropLock
);
2406 ALCcontext_DecRef(Context
);
2410 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2412 alSourcePlayv(1, &source
);
2414 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2416 ALCcontext
*context
;
2422 context
= GetContextRef();
2423 if(!context
) return;
2425 LockSourcesRead(context
);
2427 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2428 for(i
= 0;i
< n
;i
++)
2430 if(!LookupSource(context
, sources
[i
]))
2431 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2434 device
= context
->Device
;
2435 ALCdevice_Lock(device
);
2436 /* If the device is disconnected, go right to stopped. */
2437 if(!device
->Connected
)
2439 for(i
= 0;i
< n
;i
++)
2441 source
= LookupSource(context
, sources
[i
]);
2442 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2444 ALCdevice_Unlock(device
);
2448 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2450 ALsizei newcount
= context
->MaxVoices
<< 1;
2451 if(context
->MaxVoices
>= newcount
)
2453 ALCdevice_Unlock(device
);
2454 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2456 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2459 for(i
= 0;i
< n
;i
++)
2461 ALbufferlistitem
*BufferList
;
2462 ALbuffer
*buffer
= NULL
;
2463 bool start_fading
= false;
2466 source
= LookupSource(context
, sources
[i
]);
2467 WriteLock(&source
->queue_lock
);
2468 /* Check that there is a queue containing at least one valid, non zero
2471 BufferList
= source
->queue
;
2474 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2476 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2479 /* If there's nothing to play, go right to stopped. */
2482 /* NOTE: A source without any playable buffers should not have an
2483 * ALvoice since it shouldn't be in a playing or paused state. So
2484 * there's no need to look up its voice and clear the source.
2486 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2487 source
->OffsetType
= AL_NONE
;
2488 source
->Offset
= 0.0;
2492 voice
= GetSourceVoice(source
, context
);
2493 switch(GetSourceState(source
, voice
))
2496 assert(voice
!= NULL
);
2497 /* A source that's already playing is restarted from the beginning. */
2498 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2499 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2500 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2504 assert(voice
!= NULL
);
2505 /* A source that's paused simply resumes. */
2506 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2507 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2514 /* Make sure this source isn't already active, and if not, look for an
2515 * unused voice to put it in.
2517 assert(voice
== NULL
);
2518 for(j
= 0;j
< context
->VoiceCount
;j
++)
2520 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2522 voice
= context
->Voices
[j
];
2527 voice
= context
->Voices
[context
->VoiceCount
++];
2528 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2530 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2531 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2533 /* A source that's not playing or paused has any offset applied when it
2537 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2539 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2540 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2541 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2542 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2543 if(source
->OffsetType
!= AL_NONE
)
2545 ApplyOffset(source
, voice
);
2546 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2547 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2548 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2551 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2552 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2554 /* Clear previous samples. */
2555 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2557 /* Clear the stepping value so the mixer knows not to mix this until
2558 * the update gets applied.
2562 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2563 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2564 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2565 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2566 if(device
->AvgSpeakerDist
> 0.0f
)
2568 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2569 (device
->AvgSpeakerDist
* device
->Frequency
);
2570 for(j
= 0;j
< voice
->NumChannels
;j
++)
2572 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2573 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2574 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2578 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2579 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2580 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2582 WriteUnlock(&source
->queue_lock
);
2584 ALCdevice_Unlock(device
);
2587 UnlockSourcesRead(context
);
2588 ALCcontext_DecRef(context
);
2591 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2593 alSourcePausev(1, &source
);
2595 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2597 ALCcontext
*context
;
2603 context
= GetContextRef();
2604 if(!context
) return;
2606 LockSourcesRead(context
);
2608 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2609 for(i
= 0;i
< n
;i
++)
2611 if(!LookupSource(context
, sources
[i
]))
2612 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2615 device
= context
->Device
;
2616 ALCdevice_Lock(device
);
2617 for(i
= 0;i
< n
;i
++)
2619 source
= LookupSource(context
, sources
[i
]);
2620 WriteLock(&source
->queue_lock
);
2621 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2623 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2624 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2627 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2628 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2629 WriteUnlock(&source
->queue_lock
);
2631 ALCdevice_Unlock(device
);
2634 UnlockSourcesRead(context
);
2635 ALCcontext_DecRef(context
);
2638 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2640 alSourceStopv(1, &source
);
2642 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2644 ALCcontext
*context
;
2650 context
= GetContextRef();
2651 if(!context
) return;
2653 LockSourcesRead(context
);
2655 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2656 for(i
= 0;i
< n
;i
++)
2658 if(!LookupSource(context
, sources
[i
]))
2659 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2662 device
= context
->Device
;
2663 ALCdevice_Lock(device
);
2664 for(i
= 0;i
< n
;i
++)
2666 source
= LookupSource(context
, sources
[i
]);
2667 WriteLock(&source
->queue_lock
);
2668 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2670 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2671 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2672 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2675 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2676 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2677 source
->OffsetType
= AL_NONE
;
2678 source
->Offset
= 0.0;
2679 WriteUnlock(&source
->queue_lock
);
2681 ALCdevice_Unlock(device
);
2684 UnlockSourcesRead(context
);
2685 ALCcontext_DecRef(context
);
2688 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2690 alSourceRewindv(1, &source
);
2692 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2694 ALCcontext
*context
;
2700 context
= GetContextRef();
2701 if(!context
) return;
2703 LockSourcesRead(context
);
2705 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2706 for(i
= 0;i
< n
;i
++)
2708 if(!LookupSource(context
, sources
[i
]))
2709 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2712 device
= context
->Device
;
2713 ALCdevice_Lock(device
);
2714 for(i
= 0;i
< n
;i
++)
2716 source
= LookupSource(context
, sources
[i
]);
2717 WriteLock(&source
->queue_lock
);
2718 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2720 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2721 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2722 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2725 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2726 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2727 source
->OffsetType
= AL_NONE
;
2728 source
->Offset
= 0.0;
2729 WriteUnlock(&source
->queue_lock
);
2731 ALCdevice_Unlock(device
);
2734 UnlockSourcesRead(context
);
2735 ALCcontext_DecRef(context
);
2739 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2742 ALCcontext
*context
;
2745 ALbufferlistitem
*BufferListStart
;
2746 ALbufferlistitem
*BufferList
;
2747 ALbuffer
*BufferFmt
= NULL
;
2752 context
= GetContextRef();
2753 if(!context
) return;
2755 device
= context
->Device
;
2757 LockSourcesRead(context
);
2759 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2760 if((source
=LookupSource(context
, src
)) == NULL
)
2761 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2763 WriteLock(&source
->queue_lock
);
2764 if(source
->SourceType
== AL_STATIC
)
2766 WriteUnlock(&source
->queue_lock
);
2767 /* Can't queue on a Static Source */
2768 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2771 /* Check for a valid Buffer, for its frequency and format */
2772 BufferList
= source
->queue
;
2775 if(BufferList
->buffer
)
2777 BufferFmt
= BufferList
->buffer
;
2780 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2783 LockBuffersRead(device
);
2784 BufferListStart
= NULL
;
2786 for(i
= 0;i
< nb
;i
++)
2788 ALbuffer
*buffer
= NULL
;
2789 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2791 WriteUnlock(&source
->queue_lock
);
2792 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2795 if(!BufferListStart
)
2797 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2798 BufferList
= BufferListStart
;
2802 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2803 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2806 BufferList
->buffer
= buffer
;
2807 ATOMIC_INIT(&BufferList
->next
, NULL
);
2808 if(!buffer
) continue;
2810 /* Hold a read lock on each buffer being queued while checking all
2811 * provided buffers. This is done so other threads don't see an extra
2812 * reference on some buffers if this operation ends up failing. */
2813 ReadLock(&buffer
->lock
);
2814 IncrementRef(&buffer
->ref
);
2816 if(BufferFmt
== NULL
)
2818 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2819 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2820 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2822 WriteUnlock(&source
->queue_lock
);
2823 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2826 /* A buffer failed (invalid ID or format), so unlock and release
2827 * each buffer we had. */
2828 while(BufferListStart
)
2830 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2831 almemory_order_relaxed
);
2832 if((buffer
=BufferListStart
->buffer
) != NULL
)
2834 DecrementRef(&buffer
->ref
);
2835 ReadUnlock(&buffer
->lock
);
2837 al_free(BufferListStart
);
2838 BufferListStart
= next
;
2840 UnlockBuffersRead(device
);
2844 /* All buffers good, unlock them now. */
2845 BufferList
= BufferListStart
;
2846 while(BufferList
!= NULL
)
2848 ALbuffer
*buffer
= BufferList
->buffer
;
2849 if(buffer
) ReadUnlock(&buffer
->lock
);
2850 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2852 UnlockBuffersRead(device
);
2854 /* Source is now streaming */
2855 source
->SourceType
= AL_STREAMING
;
2857 if(!(BufferList
=source
->queue
))
2858 source
->queue
= BufferListStart
;
2861 ALbufferlistitem
*next
;
2862 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2864 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2866 WriteUnlock(&source
->queue_lock
);
2869 UnlockSourcesRead(context
);
2870 ALCcontext_DecRef(context
);
2873 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2875 ALCcontext
*context
;
2877 ALbufferlistitem
*OldHead
;
2878 ALbufferlistitem
*OldTail
;
2879 ALbufferlistitem
*Current
;
2883 context
= GetContextRef();
2884 if(!context
) return;
2886 LockSourcesRead(context
);
2888 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2890 if((source
=LookupSource(context
, src
)) == NULL
)
2891 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2893 /* Nothing to unqueue. */
2894 if(nb
== 0) goto done
;
2896 WriteLock(&source
->queue_lock
);
2897 if(source
->Looping
|| source
->SourceType
!= AL_STREAMING
)
2899 WriteUnlock(&source
->queue_lock
);
2900 /* Trying to unqueue buffers on a looping or non-streaming source. */
2901 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2904 /* Find the new buffer queue head */
2905 OldTail
= source
->queue
;
2907 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2908 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2909 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2911 if(OldTail
!= Current
)
2913 for(i
= 1;i
< nb
;i
++)
2915 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldTail
->next
, almemory_order_relaxed
);
2916 if(!next
|| next
== Current
) break;
2922 WriteUnlock(&source
->queue_lock
);
2923 /* Trying to unqueue pending buffers. */
2924 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2927 /* Swap it, and cut the new head from the old. */
2928 OldHead
= source
->queue
;
2929 source
->queue
= ATOMIC_EXCHANGE_PTR(&OldTail
->next
, NULL
, almemory_order_acq_rel
);
2930 WriteUnlock(&source
->queue_lock
);
2932 while(OldHead
!= NULL
)
2934 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldHead
->next
, almemory_order_relaxed
);
2935 ALbuffer
*buffer
= OldHead
->buffer
;
2941 *(buffers
++) = buffer
->id
;
2942 DecrementRef(&buffer
->ref
);
2950 UnlockSourcesRead(context
);
2951 ALCcontext_DecRef(context
);
2955 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2959 RWLockInit(&Source
->queue_lock
);
2961 Source
->InnerAngle
= 360.0f
;
2962 Source
->OuterAngle
= 360.0f
;
2963 Source
->Pitch
= 1.0f
;
2964 Source
->Position
[0] = 0.0f
;
2965 Source
->Position
[1] = 0.0f
;
2966 Source
->Position
[2] = 0.0f
;
2967 Source
->Velocity
[0] = 0.0f
;
2968 Source
->Velocity
[1] = 0.0f
;
2969 Source
->Velocity
[2] = 0.0f
;
2970 Source
->Direction
[0] = 0.0f
;
2971 Source
->Direction
[1] = 0.0f
;
2972 Source
->Direction
[2] = 0.0f
;
2973 Source
->Orientation
[0][0] = 0.0f
;
2974 Source
->Orientation
[0][1] = 0.0f
;
2975 Source
->Orientation
[0][2] = -1.0f
;
2976 Source
->Orientation
[1][0] = 0.0f
;
2977 Source
->Orientation
[1][1] = 1.0f
;
2978 Source
->Orientation
[1][2] = 0.0f
;
2979 Source
->RefDistance
= 1.0f
;
2980 Source
->MaxDistance
= FLT_MAX
;
2981 Source
->RolloffFactor
= 1.0f
;
2982 Source
->Gain
= 1.0f
;
2983 Source
->MinGain
= 0.0f
;
2984 Source
->MaxGain
= 1.0f
;
2985 Source
->OuterGain
= 0.0f
;
2986 Source
->OuterGainHF
= 1.0f
;
2988 Source
->DryGainHFAuto
= AL_TRUE
;
2989 Source
->WetGainAuto
= AL_TRUE
;
2990 Source
->WetGainHFAuto
= AL_TRUE
;
2991 Source
->AirAbsorptionFactor
= 0.0f
;
2992 Source
->RoomRolloffFactor
= 0.0f
;
2993 Source
->DopplerFactor
= 1.0f
;
2994 Source
->HeadRelative
= AL_FALSE
;
2995 Source
->Looping
= AL_FALSE
;
2996 Source
->DistanceModel
= DefaultDistanceModel
;
2997 Source
->Resampler
= ResamplerDefault
;
2998 Source
->DirectChannels
= AL_FALSE
;
2999 Source
->Spatialize
= SpatializeAuto
;
3001 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
3002 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
3004 Source
->Radius
= 0.0f
;
3006 Source
->Direct
.Gain
= 1.0f
;
3007 Source
->Direct
.GainHF
= 1.0f
;
3008 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
3009 Source
->Direct
.GainLF
= 1.0f
;
3010 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
3011 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
3012 for(i
= 0;i
< num_sends
;i
++)
3014 Source
->Send
[i
].Slot
= NULL
;
3015 Source
->Send
[i
].Gain
= 1.0f
;
3016 Source
->Send
[i
].GainHF
= 1.0f
;
3017 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
3018 Source
->Send
[i
].GainLF
= 1.0f
;
3019 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
3022 Source
->Offset
= 0.0;
3023 Source
->OffsetType
= AL_NONE
;
3024 Source
->SourceType
= AL_UNDETERMINED
;
3025 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
3027 Source
->queue
= NULL
;
3029 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3032 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3035 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3037 ALbufferlistitem
*BufferList
;
3040 BufferList
= source
->queue
;
3041 while(BufferList
!= NULL
)
3043 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3044 if(BufferList
->buffer
!= NULL
)
3045 DecrementRef(&BufferList
->buffer
->ref
);
3046 al_free(BufferList
);
3049 source
->queue
= NULL
;
3053 for(i
= 0;i
< num_sends
;i
++)
3055 if(source
->Send
[i
].Slot
)
3056 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3057 source
->Send
[i
].Slot
= NULL
;
3059 al_free(source
->Send
);
3060 source
->Send
= NULL
;
3064 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3066 struct ALvoiceProps
*props
;
3069 /* Get an unused property container, or allocate a new one as needed. */
3070 props
= ATOMIC_LOAD(&context
->FreeVoiceProps
, almemory_order_acquire
);
3072 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3075 struct ALvoiceProps
*next
;
3077 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3078 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeVoiceProps
, &props
, next
,
3079 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3082 /* Copy in current property values. */
3083 props
->Pitch
= source
->Pitch
;
3084 props
->Gain
= source
->Gain
;
3085 props
->OuterGain
= source
->OuterGain
;
3086 props
->MinGain
= source
->MinGain
;
3087 props
->MaxGain
= source
->MaxGain
;
3088 props
->InnerAngle
= source
->InnerAngle
;
3089 props
->OuterAngle
= source
->OuterAngle
;
3090 props
->RefDistance
= source
->RefDistance
;
3091 props
->MaxDistance
= source
->MaxDistance
;
3092 props
->RolloffFactor
= source
->RolloffFactor
;
3093 for(i
= 0;i
< 3;i
++)
3094 props
->Position
[i
] = source
->Position
[i
];
3095 for(i
= 0;i
< 3;i
++)
3096 props
->Velocity
[i
] = source
->Velocity
[i
];
3097 for(i
= 0;i
< 3;i
++)
3098 props
->Direction
[i
] = source
->Direction
[i
];
3099 for(i
= 0;i
< 2;i
++)
3102 for(j
= 0;j
< 3;j
++)
3103 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3105 props
->HeadRelative
= source
->HeadRelative
;
3106 props
->DistanceModel
= source
->DistanceModel
;
3107 props
->Resampler
= source
->Resampler
;
3108 props
->DirectChannels
= source
->DirectChannels
;
3109 props
->SpatializeMode
= source
->Spatialize
;
3111 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3112 props
->WetGainAuto
= source
->WetGainAuto
;
3113 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3114 props
->OuterGainHF
= source
->OuterGainHF
;
3116 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3117 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3118 props
->DopplerFactor
= source
->DopplerFactor
;
3120 props
->StereoPan
[0] = source
->StereoPan
[0];
3121 props
->StereoPan
[1] = source
->StereoPan
[1];
3123 props
->Radius
= source
->Radius
;
3125 props
->Direct
.Gain
= source
->Direct
.Gain
;
3126 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3127 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3128 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3129 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3131 for(i
= 0;i
< num_sends
;i
++)
3133 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3134 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3135 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3136 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3137 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3138 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3141 /* Set the new container for updating internal parameters. */
3142 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3145 /* If there was an unused update container, put it back in the
3148 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &context
->FreeVoiceProps
, props
);
3152 void UpdateAllSourceProps(ALCcontext
*context
)
3154 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3157 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3159 ALvoice
*voice
= context
->Voices
[pos
];
3160 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3161 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3162 UpdateSourceProps(source
, voice
, num_sends
, context
);
3167 /* GetSourceSampleOffset
3169 * Gets the current read offset for the given Source, in 32.32 fixed-point
3170 * samples. The offset is relative to the start of the queue (not the start of
3171 * the current buffer).
3173 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3175 ALCdevice
*device
= context
->Device
;
3176 const ALbufferlistitem
*Current
;
3181 ReadLock(&Source
->queue_lock
);
3185 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3187 *clocktime
= GetDeviceClockTime(device
);
3189 voice
= GetSourceVoice(Source
, context
);
3192 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3194 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3195 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3198 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3199 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3203 const ALbufferlistitem
*BufferList
= Source
->queue
;
3204 while(BufferList
&& BufferList
!= Current
)
3206 if(BufferList
->buffer
)
3207 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3208 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3209 almemory_order_relaxed
);
3211 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3214 ReadUnlock(&Source
->queue_lock
);
3215 return (ALint64
)readPos
;
3218 /* GetSourceSecOffset
3220 * Gets the current read offset for the given Source, in seconds. The offset is
3221 * relative to the start of the queue (not the start of the current buffer).
3223 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3225 ALCdevice
*device
= context
->Device
;
3226 const ALbufferlistitem
*Current
;
3232 ReadLock(&Source
->queue_lock
);
3236 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3238 *clocktime
= GetDeviceClockTime(device
);
3240 voice
= GetSourceVoice(Source
, context
);
3243 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3245 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3247 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3249 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3250 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3255 const ALbufferlistitem
*BufferList
= Source
->queue
;
3256 const ALbuffer
*BufferFmt
= NULL
;
3257 while(BufferList
&& BufferList
!= Current
)
3259 const ALbuffer
*buffer
= BufferList
->buffer
;
3262 if(!BufferFmt
) BufferFmt
= buffer
;
3263 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3265 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3266 almemory_order_relaxed
);
3269 while(BufferList
&& !BufferFmt
)
3271 BufferFmt
= BufferList
->buffer
;
3272 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3273 almemory_order_relaxed
);
3275 assert(BufferFmt
!= NULL
);
3277 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3278 (ALdouble
)BufferFmt
->Frequency
;
3281 ReadUnlock(&Source
->queue_lock
);
3287 * Gets the current read offset for the given Source, in the appropriate format
3288 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3289 * queue (not the start of the current buffer).
3291 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3293 ALCdevice
*device
= context
->Device
;
3294 const ALbufferlistitem
*Current
;
3296 ALsizei readPosFrac
;
3301 ReadLock(&Source
->queue_lock
);
3304 readPos
= readPosFrac
= 0;
3305 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3307 voice
= GetSourceVoice(Source
, context
);
3310 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3312 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3313 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3315 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3316 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3321 const ALbufferlistitem
*BufferList
= Source
->queue
;
3322 const ALbuffer
*BufferFmt
= NULL
;
3323 ALboolean readFin
= AL_FALSE
;
3324 ALuint totalBufferLen
= 0;
3326 while(BufferList
!= NULL
)
3328 const ALbuffer
*buffer
;
3329 readFin
= readFin
|| (BufferList
== Current
);
3330 if((buffer
=BufferList
->buffer
) != NULL
)
3332 if(!BufferFmt
) BufferFmt
= buffer
;
3333 totalBufferLen
+= buffer
->SampleLen
;
3334 if(!readFin
) readPos
+= buffer
->SampleLen
;
3336 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3337 almemory_order_relaxed
);
3339 assert(BufferFmt
!= NULL
);
3342 readPos
%= totalBufferLen
;
3345 /* Wrap back to 0 */
3346 if(readPos
>= totalBufferLen
)
3347 readPos
= readPosFrac
= 0;
3354 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3357 case AL_SAMPLE_OFFSET
:
3358 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3361 case AL_BYTE_OFFSET
:
3362 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3364 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3365 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3366 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3368 /* Round down to nearest ADPCM block */
3369 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3371 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3373 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3374 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3375 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3377 /* Round down to nearest ADPCM block */
3378 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3382 ALuint FrameSize
= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3383 BufferFmt
->OriginalType
);
3384 offset
= (ALdouble
)(readPos
* FrameSize
);
3390 ReadUnlock(&Source
->queue_lock
);
3397 * Apply the stored playback offset to the Source. This function will update
3398 * the number of buffers "played" given the stored offset.
3400 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3402 ALbufferlistitem
*BufferList
;
3403 const ALbuffer
*Buffer
;
3404 ALuint bufferLen
, totalBufferLen
;
3408 /* Get sample frame offset */
3409 if(!GetSampleOffset(Source
, &offset
, &frac
))
3413 BufferList
= Source
->queue
;
3414 while(BufferList
&& totalBufferLen
<= offset
)
3416 Buffer
= BufferList
->buffer
;
3417 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3419 if(bufferLen
> offset
-totalBufferLen
)
3421 /* Offset is in this buffer */
3422 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3423 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3424 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3428 totalBufferLen
+= bufferLen
;
3430 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3433 /* Offset is out of range of the queue */
3440 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3441 * or Second offset supplied by the application). This takes into account the
3442 * fact that the buffer format may have been modifed since.
3444 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3446 const ALbuffer
*BufferFmt
= NULL
;
3447 const ALbufferlistitem
*BufferList
;
3448 ALdouble dbloff
, dblfrac
;
3450 /* Find the first valid Buffer in the Queue */
3451 BufferList
= Source
->queue
;
3454 if((BufferFmt
=BufferList
->buffer
) != NULL
)
3456 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3457 almemory_order_relaxed
);
3461 Source
->OffsetType
= AL_NONE
;
3462 Source
->Offset
= 0.0;
3466 switch(Source
->OffsetType
)
3468 case AL_BYTE_OFFSET
:
3469 /* Determine the ByteOffset (and ensure it is block aligned) */
3470 *offset
= (ALuint
)Source
->Offset
;
3471 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3473 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3474 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3475 *offset
*= BufferFmt
->OriginalAlign
;
3477 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3479 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3480 *offset
/= align
* ChannelsFromUserFmt(BufferFmt
->OriginalChannels
);
3481 *offset
*= BufferFmt
->OriginalAlign
;
3484 *offset
/= FrameSizeFromUserFmt(BufferFmt
->OriginalChannels
,
3485 BufferFmt
->OriginalType
);
3489 case AL_SAMPLE_OFFSET
:
3490 dblfrac
= modf(Source
->Offset
, &dbloff
);
3491 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3492 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3496 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3497 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3498 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3501 Source
->OffsetType
= AL_NONE
;
3502 Source
->Offset
= 0.0;
3510 * Destroys all sources in the source map.
3512 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3514 ALCdevice
*device
= Context
->Device
;
3516 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3518 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3519 Context
->SourceMap
.values
[pos
] = NULL
;
3521 DeinitSource(temp
, device
->NumAuxSends
);
3523 FreeThunkEntry(temp
->id
);
3524 memset(temp
, 0, sizeof(*temp
));