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
,
126 /* ALC_SOFT_device_clock */
127 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
128 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
131 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
132 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
133 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
135 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
136 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
137 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
139 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
141 ALvoice
**voice
= context
->Voices
;
142 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
143 while(voice
!= voice_end
)
145 if(ATOMIC_LOAD(&(*voice
)->Source
, almemory_order_acquire
) == source
)
153 * Returns if the last known state for the source was playing or paused. Does
154 * not sync with the mixer voice.
156 static inline bool IsPlayingOrPaused(ALsource
*source
)
158 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
159 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
163 * Returns an updated source state using the matching voice's status (or lack
166 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
170 ALenum state
= AL_PLAYING
;
171 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
172 almemory_order_acq_rel
, almemory_order_acquire
))
176 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
180 * Returns if the source should specify an update, given the context's
181 * deferring state and the source's last known state.
183 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
185 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
186 IsPlayingOrPaused(source
);
189 static ALint
FloatValsByProp(ALenum prop
)
191 if(prop
!= (ALenum
)((SourceProp
)prop
))
193 switch((SourceProp
)prop
)
199 case AL_MAX_DISTANCE
:
200 case AL_ROLLOFF_FACTOR
:
201 case AL_DOPPLER_FACTOR
:
202 case AL_CONE_OUTER_GAIN
:
204 case AL_SAMPLE_OFFSET
:
206 case AL_CONE_INNER_ANGLE
:
207 case AL_CONE_OUTER_ANGLE
:
208 case AL_REFERENCE_DISTANCE
:
209 case AL_CONE_OUTER_GAINHF
:
210 case AL_AIR_ABSORPTION_FACTOR
:
211 case AL_ROOM_ROLLOFF_FACTOR
:
212 case AL_DIRECT_FILTER_GAINHF_AUTO
:
213 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
214 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
215 case AL_DIRECT_CHANNELS_SOFT
:
216 case AL_DISTANCE_MODEL
:
217 case AL_SOURCE_RELATIVE
:
219 case AL_SOURCE_STATE
:
220 case AL_BUFFERS_QUEUED
:
221 case AL_BUFFERS_PROCESSED
:
223 case AL_BYTE_LENGTH_SOFT
:
224 case AL_SAMPLE_LENGTH_SOFT
:
225 case AL_SEC_LENGTH_SOFT
:
226 case AL_SOURCE_RADIUS
:
227 case AL_SOURCE_RESAMPLER_SOFT
:
228 case AL_SOURCE_SPATIALIZE_SOFT
:
231 case AL_STEREO_ANGLES
:
242 case AL_SEC_OFFSET_LATENCY_SOFT
:
243 case AL_SEC_OFFSET_CLOCK_SOFT
:
244 break; /* Double only */
247 case AL_DIRECT_FILTER
:
248 case AL_AUXILIARY_SEND_FILTER
:
249 break; /* i/i64 only */
250 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
251 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
252 break; /* i64 only */
256 static ALint
DoubleValsByProp(ALenum prop
)
258 if(prop
!= (ALenum
)((SourceProp
)prop
))
260 switch((SourceProp
)prop
)
266 case AL_MAX_DISTANCE
:
267 case AL_ROLLOFF_FACTOR
:
268 case AL_DOPPLER_FACTOR
:
269 case AL_CONE_OUTER_GAIN
:
271 case AL_SAMPLE_OFFSET
:
273 case AL_CONE_INNER_ANGLE
:
274 case AL_CONE_OUTER_ANGLE
:
275 case AL_REFERENCE_DISTANCE
:
276 case AL_CONE_OUTER_GAINHF
:
277 case AL_AIR_ABSORPTION_FACTOR
:
278 case AL_ROOM_ROLLOFF_FACTOR
:
279 case AL_DIRECT_FILTER_GAINHF_AUTO
:
280 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
281 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
282 case AL_DIRECT_CHANNELS_SOFT
:
283 case AL_DISTANCE_MODEL
:
284 case AL_SOURCE_RELATIVE
:
286 case AL_SOURCE_STATE
:
287 case AL_BUFFERS_QUEUED
:
288 case AL_BUFFERS_PROCESSED
:
290 case AL_BYTE_LENGTH_SOFT
:
291 case AL_SAMPLE_LENGTH_SOFT
:
292 case AL_SEC_LENGTH_SOFT
:
293 case AL_SOURCE_RADIUS
:
294 case AL_SOURCE_RESAMPLER_SOFT
:
295 case AL_SOURCE_SPATIALIZE_SOFT
:
298 case AL_SEC_OFFSET_LATENCY_SOFT
:
299 case AL_SEC_OFFSET_CLOCK_SOFT
:
300 case AL_STEREO_ANGLES
:
312 case AL_DIRECT_FILTER
:
313 case AL_AUXILIARY_SEND_FILTER
:
314 break; /* i/i64 only */
315 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
316 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
317 break; /* i64 only */
322 static ALint
IntValsByProp(ALenum prop
)
324 if(prop
!= (ALenum
)((SourceProp
)prop
))
326 switch((SourceProp
)prop
)
332 case AL_MAX_DISTANCE
:
333 case AL_ROLLOFF_FACTOR
:
334 case AL_DOPPLER_FACTOR
:
335 case AL_CONE_OUTER_GAIN
:
337 case AL_SAMPLE_OFFSET
:
339 case AL_CONE_INNER_ANGLE
:
340 case AL_CONE_OUTER_ANGLE
:
341 case AL_REFERENCE_DISTANCE
:
342 case AL_CONE_OUTER_GAINHF
:
343 case AL_AIR_ABSORPTION_FACTOR
:
344 case AL_ROOM_ROLLOFF_FACTOR
:
345 case AL_DIRECT_FILTER_GAINHF_AUTO
:
346 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
347 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
348 case AL_DIRECT_CHANNELS_SOFT
:
349 case AL_DISTANCE_MODEL
:
350 case AL_SOURCE_RELATIVE
:
353 case AL_SOURCE_STATE
:
354 case AL_BUFFERS_QUEUED
:
355 case AL_BUFFERS_PROCESSED
:
357 case AL_DIRECT_FILTER
:
358 case AL_BYTE_LENGTH_SOFT
:
359 case AL_SAMPLE_LENGTH_SOFT
:
360 case AL_SEC_LENGTH_SOFT
:
361 case AL_SOURCE_RADIUS
:
362 case AL_SOURCE_RESAMPLER_SOFT
:
363 case AL_SOURCE_SPATIALIZE_SOFT
:
369 case AL_AUXILIARY_SEND_FILTER
:
375 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
376 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
377 break; /* i64 only */
378 case AL_SEC_OFFSET_LATENCY_SOFT
:
379 case AL_SEC_OFFSET_CLOCK_SOFT
:
380 break; /* Double only */
381 case AL_STEREO_ANGLES
:
382 break; /* Float/double only */
386 static ALint
Int64ValsByProp(ALenum prop
)
388 if(prop
!= (ALenum
)((SourceProp
)prop
))
390 switch((SourceProp
)prop
)
396 case AL_MAX_DISTANCE
:
397 case AL_ROLLOFF_FACTOR
:
398 case AL_DOPPLER_FACTOR
:
399 case AL_CONE_OUTER_GAIN
:
401 case AL_SAMPLE_OFFSET
:
403 case AL_CONE_INNER_ANGLE
:
404 case AL_CONE_OUTER_ANGLE
:
405 case AL_REFERENCE_DISTANCE
:
406 case AL_CONE_OUTER_GAINHF
:
407 case AL_AIR_ABSORPTION_FACTOR
:
408 case AL_ROOM_ROLLOFF_FACTOR
:
409 case AL_DIRECT_FILTER_GAINHF_AUTO
:
410 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
411 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
412 case AL_DIRECT_CHANNELS_SOFT
:
413 case AL_DISTANCE_MODEL
:
414 case AL_SOURCE_RELATIVE
:
417 case AL_SOURCE_STATE
:
418 case AL_BUFFERS_QUEUED
:
419 case AL_BUFFERS_PROCESSED
:
421 case AL_DIRECT_FILTER
:
422 case AL_BYTE_LENGTH_SOFT
:
423 case AL_SAMPLE_LENGTH_SOFT
:
424 case AL_SEC_LENGTH_SOFT
:
425 case AL_SOURCE_RADIUS
:
426 case AL_SOURCE_RESAMPLER_SOFT
:
427 case AL_SOURCE_SPATIALIZE_SOFT
:
430 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
431 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
437 case AL_AUXILIARY_SEND_FILTER
:
443 case AL_SEC_OFFSET_LATENCY_SOFT
:
444 case AL_SEC_OFFSET_CLOCK_SOFT
:
445 break; /* Double only */
446 case AL_STEREO_ANGLES
:
447 break; /* Float/double only */
453 #define CHECKVAL(x) do { \
455 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
458 #define DO_UPDATEPROPS() do { \
460 if(SourceShouldUpdate(Source, Context) && \
461 (voice=GetSourceVoice(Source, Context)) != NULL) \
462 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
464 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
467 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
469 ALCdevice
*device
= Context
->Device
;
474 case AL_BYTE_LENGTH_SOFT
:
475 case AL_SAMPLE_LENGTH_SOFT
:
476 case AL_SEC_LENGTH_SOFT
:
477 case AL_SEC_OFFSET_LATENCY_SOFT
:
478 case AL_SEC_OFFSET_CLOCK_SOFT
:
480 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
483 CHECKVAL(*values
>= 0.0f
);
485 Source
->Pitch
= *values
;
489 case AL_CONE_INNER_ANGLE
:
490 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
492 Source
->InnerAngle
= *values
;
496 case AL_CONE_OUTER_ANGLE
:
497 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
499 Source
->OuterAngle
= *values
;
504 CHECKVAL(*values
>= 0.0f
);
506 Source
->Gain
= *values
;
510 case AL_MAX_DISTANCE
:
511 CHECKVAL(*values
>= 0.0f
);
513 Source
->MaxDistance
= *values
;
517 case AL_ROLLOFF_FACTOR
:
518 CHECKVAL(*values
>= 0.0f
);
520 Source
->RolloffFactor
= *values
;
524 case AL_REFERENCE_DISTANCE
:
525 CHECKVAL(*values
>= 0.0f
);
527 Source
->RefDistance
= *values
;
532 CHECKVAL(*values
>= 0.0f
);
534 Source
->MinGain
= *values
;
539 CHECKVAL(*values
>= 0.0f
);
541 Source
->MaxGain
= *values
;
545 case AL_CONE_OUTER_GAIN
:
546 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
548 Source
->OuterGain
= *values
;
552 case AL_CONE_OUTER_GAINHF
:
553 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
555 Source
->OuterGainHF
= *values
;
559 case AL_AIR_ABSORPTION_FACTOR
:
560 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
562 Source
->AirAbsorptionFactor
= *values
;
566 case AL_ROOM_ROLLOFF_FACTOR
:
567 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
569 Source
->RoomRolloffFactor
= *values
;
573 case AL_DOPPLER_FACTOR
:
574 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
576 Source
->DopplerFactor
= *values
;
581 case AL_SAMPLE_OFFSET
:
583 CHECKVAL(*values
>= 0.0f
);
585 Source
->OffsetType
= prop
;
586 Source
->Offset
= *values
;
588 if(IsPlayingOrPaused(Source
))
592 ALCdevice_Lock(Context
->Device
);
593 /* Double-check that the source is still playing while we have
596 voice
= GetSourceVoice(Source
, Context
);
599 WriteLock(&Source
->queue_lock
);
600 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
602 WriteUnlock(&Source
->queue_lock
);
603 ALCdevice_Unlock(Context
->Device
);
604 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
606 WriteUnlock(&Source
->queue_lock
);
608 ALCdevice_Unlock(Context
->Device
);
612 case AL_SOURCE_RADIUS
:
613 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
615 Source
->Radius
= *values
;
619 case AL_STEREO_ANGLES
:
620 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
622 Source
->StereoPan
[0] = values
[0];
623 Source
->StereoPan
[1] = values
[1];
629 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
631 Source
->Position
[0] = values
[0];
632 Source
->Position
[1] = values
[1];
633 Source
->Position
[2] = values
[2];
638 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
640 Source
->Velocity
[0] = values
[0];
641 Source
->Velocity
[1] = values
[1];
642 Source
->Velocity
[2] = values
[2];
647 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
649 Source
->Direction
[0] = values
[0];
650 Source
->Direction
[1] = values
[1];
651 Source
->Direction
[2] = values
[2];
656 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
657 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
659 Source
->Orientation
[0][0] = values
[0];
660 Source
->Orientation
[0][1] = values
[1];
661 Source
->Orientation
[0][2] = values
[2];
662 Source
->Orientation
[1][0] = values
[3];
663 Source
->Orientation
[1][1] = values
[4];
664 Source
->Orientation
[1][2] = values
[5];
669 case AL_SOURCE_RELATIVE
:
671 case AL_SOURCE_STATE
:
673 case AL_DISTANCE_MODEL
:
674 case AL_DIRECT_FILTER_GAINHF_AUTO
:
675 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
676 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
677 case AL_DIRECT_CHANNELS_SOFT
:
678 case AL_SOURCE_RESAMPLER_SOFT
:
679 case AL_SOURCE_SPATIALIZE_SOFT
:
680 ival
= (ALint
)values
[0];
681 return SetSourceiv(Source
, Context
, prop
, &ival
);
683 case AL_BUFFERS_QUEUED
:
684 case AL_BUFFERS_PROCESSED
:
685 ival
= (ALint
)((ALuint
)values
[0]);
686 return SetSourceiv(Source
, Context
, prop
, &ival
);
689 case AL_DIRECT_FILTER
:
690 case AL_AUXILIARY_SEND_FILTER
:
691 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
692 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
696 ERR("Unexpected property: 0x%04x\n", prop
);
697 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
700 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
702 ALCdevice
*device
= Context
->Device
;
703 ALbuffer
*buffer
= NULL
;
704 ALfilter
*filter
= NULL
;
705 ALeffectslot
*slot
= NULL
;
706 ALbufferlistitem
*oldlist
;
711 case AL_SOURCE_STATE
:
713 case AL_BUFFERS_QUEUED
:
714 case AL_BUFFERS_PROCESSED
:
715 case AL_BYTE_LENGTH_SOFT
:
716 case AL_SAMPLE_LENGTH_SOFT
:
717 case AL_SEC_LENGTH_SOFT
:
719 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
721 case AL_SOURCE_RELATIVE
:
722 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
724 Source
->HeadRelative
= (ALboolean
)*values
;
729 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
731 WriteLock(&Source
->queue_lock
);
732 Source
->Looping
= (ALboolean
)*values
;
733 if(IsPlayingOrPaused(Source
))
735 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
739 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
741 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
743 /* If the source is playing, wait for the current mix to finish
744 * to ensure it isn't currently looping back or reaching the
747 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
751 WriteUnlock(&Source
->queue_lock
);
755 LockBuffersRead(device
);
756 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
758 UnlockBuffersRead(device
);
759 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
762 WriteLock(&Source
->queue_lock
);
763 if(buffer
&& buffer
->MappedAccess
!= 0 &&
764 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
766 WriteUnlock(&Source
->queue_lock
);
767 UnlockBuffersRead(device
);
768 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
772 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
773 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
775 WriteUnlock(&Source
->queue_lock
);
776 UnlockBuffersRead(device
);
777 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
781 oldlist
= Source
->queue
;
784 /* Add the selected buffer to a one-item queue */
785 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
,
786 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
787 ATOMIC_INIT(&newlist
->next
, NULL
);
788 newlist
->num_buffers
= 1;
789 newlist
->buffers
[0] = buffer
;
790 IncrementRef(&buffer
->ref
);
792 /* Source is now Static */
793 Source
->SourceType
= AL_STATIC
;
794 Source
->queue
= newlist
;
798 /* Source is now Undetermined */
799 Source
->SourceType
= AL_UNDETERMINED
;
800 Source
->queue
= NULL
;
802 WriteUnlock(&Source
->queue_lock
);
803 UnlockBuffersRead(device
);
805 /* Delete all elements in the previous queue */
806 while(oldlist
!= NULL
)
809 ALbufferlistitem
*temp
= oldlist
;
810 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
812 for(i
= 0;i
< temp
->num_buffers
;i
++)
815 DecrementRef(&temp
->buffers
[i
]->ref
);
822 case AL_SAMPLE_OFFSET
:
824 CHECKVAL(*values
>= 0);
826 Source
->OffsetType
= prop
;
827 Source
->Offset
= *values
;
829 if(IsPlayingOrPaused(Source
))
833 ALCdevice_Lock(Context
->Device
);
834 voice
= GetSourceVoice(Source
, Context
);
837 WriteLock(&Source
->queue_lock
);
838 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
840 WriteUnlock(&Source
->queue_lock
);
841 ALCdevice_Unlock(Context
->Device
);
842 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
844 WriteUnlock(&Source
->queue_lock
);
846 ALCdevice_Unlock(Context
->Device
);
850 case AL_DIRECT_FILTER
:
851 LockFiltersRead(device
);
852 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
854 UnlockFiltersRead(device
);
855 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
860 Source
->Direct
.Gain
= 1.0f
;
861 Source
->Direct
.GainHF
= 1.0f
;
862 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
863 Source
->Direct
.GainLF
= 1.0f
;
864 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
868 Source
->Direct
.Gain
= filter
->Gain
;
869 Source
->Direct
.GainHF
= filter
->GainHF
;
870 Source
->Direct
.HFReference
= filter
->HFReference
;
871 Source
->Direct
.GainLF
= filter
->GainLF
;
872 Source
->Direct
.LFReference
= filter
->LFReference
;
874 UnlockFiltersRead(device
);
878 case AL_DIRECT_FILTER_GAINHF_AUTO
:
879 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
881 Source
->DryGainHFAuto
= *values
;
885 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
886 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
888 Source
->WetGainAuto
= *values
;
892 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
893 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
895 Source
->WetGainHFAuto
= *values
;
899 case AL_DIRECT_CHANNELS_SOFT
:
900 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
902 Source
->DirectChannels
= *values
;
906 case AL_DISTANCE_MODEL
:
907 CHECKVAL(*values
== AL_NONE
||
908 *values
== AL_INVERSE_DISTANCE
||
909 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
910 *values
== AL_LINEAR_DISTANCE
||
911 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
912 *values
== AL_EXPONENT_DISTANCE
||
913 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
915 Source
->DistanceModel
= *values
;
916 if(Context
->SourceDistanceModel
)
920 case AL_SOURCE_RESAMPLER_SOFT
:
921 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
923 Source
->Resampler
= *values
;
927 case AL_SOURCE_SPATIALIZE_SOFT
:
928 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
930 Source
->Spatialize
= *values
;
935 case AL_AUXILIARY_SEND_FILTER
:
936 LockEffectSlotsRead(Context
);
937 LockFiltersRead(device
);
938 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
939 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
940 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
942 UnlockFiltersRead(device
);
943 UnlockEffectSlotsRead(Context
);
944 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
950 Source
->Send
[values
[1]].Gain
= 1.0f
;
951 Source
->Send
[values
[1]].GainHF
= 1.0f
;
952 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
953 Source
->Send
[values
[1]].GainLF
= 1.0f
;
954 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
958 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
959 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
960 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
961 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
962 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
964 UnlockFiltersRead(device
);
966 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
969 /* Add refcount on the new slot, and release the previous slot */
970 if(slot
) IncrementRef(&slot
->ref
);
971 if(Source
->Send
[values
[1]].Slot
)
972 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
973 Source
->Send
[values
[1]].Slot
= slot
;
975 /* We must force an update if the auxiliary slot changed on an
976 * active source, in case the slot is about to be deleted.
978 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
979 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
981 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
985 if(slot
) IncrementRef(&slot
->ref
);
986 if(Source
->Send
[values
[1]].Slot
)
987 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
988 Source
->Send
[values
[1]].Slot
= slot
;
991 UnlockEffectSlotsRead(Context
);
997 case AL_CONE_INNER_ANGLE
:
998 case AL_CONE_OUTER_ANGLE
:
1003 case AL_REFERENCE_DISTANCE
:
1004 case AL_ROLLOFF_FACTOR
:
1005 case AL_CONE_OUTER_GAIN
:
1006 case AL_MAX_DISTANCE
:
1007 case AL_DOPPLER_FACTOR
:
1008 case AL_CONE_OUTER_GAINHF
:
1009 case AL_AIR_ABSORPTION_FACTOR
:
1010 case AL_ROOM_ROLLOFF_FACTOR
:
1011 case AL_SOURCE_RADIUS
:
1012 fvals
[0] = (ALfloat
)*values
;
1013 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1019 fvals
[0] = (ALfloat
)values
[0];
1020 fvals
[1] = (ALfloat
)values
[1];
1021 fvals
[2] = (ALfloat
)values
[2];
1022 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1025 case AL_ORIENTATION
:
1026 fvals
[0] = (ALfloat
)values
[0];
1027 fvals
[1] = (ALfloat
)values
[1];
1028 fvals
[2] = (ALfloat
)values
[2];
1029 fvals
[3] = (ALfloat
)values
[3];
1030 fvals
[4] = (ALfloat
)values
[4];
1031 fvals
[5] = (ALfloat
)values
[5];
1032 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1034 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1035 case AL_SEC_OFFSET_LATENCY_SOFT
:
1036 case AL_SEC_OFFSET_CLOCK_SOFT
:
1037 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1038 case AL_STEREO_ANGLES
:
1042 ERR("Unexpected property: 0x%04x\n", prop
);
1043 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1046 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1053 case AL_SOURCE_TYPE
:
1054 case AL_BUFFERS_QUEUED
:
1055 case AL_BUFFERS_PROCESSED
:
1056 case AL_SOURCE_STATE
:
1057 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1058 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1059 case AL_BYTE_LENGTH_SOFT
:
1060 case AL_SAMPLE_LENGTH_SOFT
:
1061 case AL_SEC_LENGTH_SOFT
:
1063 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
1067 case AL_SOURCE_RELATIVE
:
1070 case AL_SAMPLE_OFFSET
:
1071 case AL_BYTE_OFFSET
:
1072 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1073 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1074 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1075 case AL_DIRECT_CHANNELS_SOFT
:
1076 case AL_DISTANCE_MODEL
:
1077 case AL_SOURCE_RESAMPLER_SOFT
:
1078 case AL_SOURCE_SPATIALIZE_SOFT
:
1079 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1081 ivals
[0] = (ALint
)*values
;
1082 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1086 case AL_DIRECT_FILTER
:
1087 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1089 ivals
[0] = (ALuint
)*values
;
1090 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1093 case AL_AUXILIARY_SEND_FILTER
:
1094 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1095 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1096 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1098 ivals
[0] = (ALuint
)values
[0];
1099 ivals
[1] = (ALuint
)values
[1];
1100 ivals
[2] = (ALuint
)values
[2];
1101 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1104 case AL_CONE_INNER_ANGLE
:
1105 case AL_CONE_OUTER_ANGLE
:
1110 case AL_REFERENCE_DISTANCE
:
1111 case AL_ROLLOFF_FACTOR
:
1112 case AL_CONE_OUTER_GAIN
:
1113 case AL_MAX_DISTANCE
:
1114 case AL_DOPPLER_FACTOR
:
1115 case AL_CONE_OUTER_GAINHF
:
1116 case AL_AIR_ABSORPTION_FACTOR
:
1117 case AL_ROOM_ROLLOFF_FACTOR
:
1118 case AL_SOURCE_RADIUS
:
1119 fvals
[0] = (ALfloat
)*values
;
1120 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1126 fvals
[0] = (ALfloat
)values
[0];
1127 fvals
[1] = (ALfloat
)values
[1];
1128 fvals
[2] = (ALfloat
)values
[2];
1129 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1132 case AL_ORIENTATION
:
1133 fvals
[0] = (ALfloat
)values
[0];
1134 fvals
[1] = (ALfloat
)values
[1];
1135 fvals
[2] = (ALfloat
)values
[2];
1136 fvals
[3] = (ALfloat
)values
[3];
1137 fvals
[4] = (ALfloat
)values
[4];
1138 fvals
[5] = (ALfloat
)values
[5];
1139 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1141 case AL_SEC_OFFSET_LATENCY_SOFT
:
1142 case AL_SEC_OFFSET_CLOCK_SOFT
:
1143 case AL_STEREO_ANGLES
:
1147 ERR("Unexpected property: 0x%04x\n", prop
);
1148 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1154 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1156 ALCdevice
*device
= Context
->Device
;
1157 ALbufferlistitem
*BufferList
;
1158 ClockLatency clocktime
;
1166 *values
= Source
->Gain
;
1170 *values
= Source
->Pitch
;
1173 case AL_MAX_DISTANCE
:
1174 *values
= Source
->MaxDistance
;
1177 case AL_ROLLOFF_FACTOR
:
1178 *values
= Source
->RolloffFactor
;
1181 case AL_REFERENCE_DISTANCE
:
1182 *values
= Source
->RefDistance
;
1185 case AL_CONE_INNER_ANGLE
:
1186 *values
= Source
->InnerAngle
;
1189 case AL_CONE_OUTER_ANGLE
:
1190 *values
= Source
->OuterAngle
;
1194 *values
= Source
->MinGain
;
1198 *values
= Source
->MaxGain
;
1201 case AL_CONE_OUTER_GAIN
:
1202 *values
= Source
->OuterGain
;
1206 case AL_SAMPLE_OFFSET
:
1207 case AL_BYTE_OFFSET
:
1208 *values
= GetSourceOffset(Source
, prop
, Context
);
1211 case AL_CONE_OUTER_GAINHF
:
1212 *values
= Source
->OuterGainHF
;
1215 case AL_AIR_ABSORPTION_FACTOR
:
1216 *values
= Source
->AirAbsorptionFactor
;
1219 case AL_ROOM_ROLLOFF_FACTOR
:
1220 *values
= Source
->RoomRolloffFactor
;
1223 case AL_DOPPLER_FACTOR
:
1224 *values
= Source
->DopplerFactor
;
1227 case AL_SEC_LENGTH_SOFT
:
1228 ReadLock(&Source
->queue_lock
);
1229 if(!(BufferList
=Source
->queue
))
1236 ALsizei max_len
= 0;
1238 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1240 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1241 if(buffer
&& buffer
->SampleLen
> 0)
1243 freq
= buffer
->Frequency
;
1244 max_len
= maxi(max_len
, buffer
->SampleLen
);
1248 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1249 } while(BufferList
!= NULL
);
1250 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1252 ReadUnlock(&Source
->queue_lock
);
1255 case AL_SOURCE_RADIUS
:
1256 *values
= Source
->Radius
;
1259 case AL_STEREO_ANGLES
:
1260 values
[0] = Source
->StereoPan
[0];
1261 values
[1] = Source
->StereoPan
[1];
1264 case AL_SEC_OFFSET_LATENCY_SOFT
:
1265 /* Get the source offset with the clock time first. Then get the
1266 * clock time with the device latency. Order is important.
1268 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1269 clocktime
= V0(device
->Backend
,getClockLatency
)();
1270 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1271 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1274 /* If the clock time incremented, reduce the latency by that
1275 * much since it's that much closer to the source offset it got
1278 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1279 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1284 case AL_SEC_OFFSET_CLOCK_SOFT
:
1285 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1286 values
[1] = srcclock
/ 1000000000.0;
1290 values
[0] = Source
->Position
[0];
1291 values
[1] = Source
->Position
[1];
1292 values
[2] = Source
->Position
[2];
1296 values
[0] = Source
->Velocity
[0];
1297 values
[1] = Source
->Velocity
[1];
1298 values
[2] = Source
->Velocity
[2];
1302 values
[0] = Source
->Direction
[0];
1303 values
[1] = Source
->Direction
[1];
1304 values
[2] = Source
->Direction
[2];
1307 case AL_ORIENTATION
:
1308 values
[0] = Source
->Orientation
[0][0];
1309 values
[1] = Source
->Orientation
[0][1];
1310 values
[2] = Source
->Orientation
[0][2];
1311 values
[3] = Source
->Orientation
[1][0];
1312 values
[4] = Source
->Orientation
[1][1];
1313 values
[5] = Source
->Orientation
[1][2];
1317 case AL_SOURCE_RELATIVE
:
1319 case AL_SOURCE_STATE
:
1320 case AL_BUFFERS_QUEUED
:
1321 case AL_BUFFERS_PROCESSED
:
1322 case AL_SOURCE_TYPE
:
1323 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1324 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1325 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1326 case AL_DIRECT_CHANNELS_SOFT
:
1327 case AL_BYTE_LENGTH_SOFT
:
1328 case AL_SAMPLE_LENGTH_SOFT
:
1329 case AL_DISTANCE_MODEL
:
1330 case AL_SOURCE_RESAMPLER_SOFT
:
1331 case AL_SOURCE_SPATIALIZE_SOFT
:
1332 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1333 *values
= (ALdouble
)ivals
[0];
1337 case AL_DIRECT_FILTER
:
1338 case AL_AUXILIARY_SEND_FILTER
:
1339 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1340 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1344 ERR("Unexpected property: 0x%04x\n", prop
);
1345 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1348 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1350 ALbufferlistitem
*BufferList
;
1356 case AL_SOURCE_RELATIVE
:
1357 *values
= Source
->HeadRelative
;
1361 *values
= Source
->Looping
;
1365 ReadLock(&Source
->queue_lock
);
1366 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1367 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1368 BufferList
->buffers
[0]->id
: 0;
1369 ReadUnlock(&Source
->queue_lock
);
1372 case AL_SOURCE_STATE
:
1373 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1376 case AL_BYTE_LENGTH_SOFT
:
1377 ReadLock(&Source
->queue_lock
);
1378 if(!(BufferList
=Source
->queue
))
1384 ALsizei max_len
= 0;
1386 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1388 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1389 if(buffer
&& buffer
->SampleLen
> 0)
1391 ALuint byte_align
, sample_align
;
1392 if(buffer
->OriginalType
== UserFmtIMA4
)
1394 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1395 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1396 sample_align
= buffer
->OriginalAlign
;
1398 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1400 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1401 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1402 sample_align
= buffer
->OriginalAlign
;
1406 ALsizei align
= buffer
->OriginalAlign
;
1407 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1408 sample_align
= buffer
->OriginalAlign
;
1411 max_len
= maxi(max_len
, buffer
->SampleLen
/ sample_align
* byte_align
);
1416 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1417 } while(BufferList
!= NULL
);
1420 ReadUnlock(&Source
->queue_lock
);
1423 case AL_SAMPLE_LENGTH_SOFT
:
1424 ReadLock(&Source
->queue_lock
);
1425 if(!(BufferList
=Source
->queue
))
1431 ALsizei max_len
= 0;
1433 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1435 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1436 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
1439 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1440 } while(BufferList
!= NULL
);
1443 ReadUnlock(&Source
->queue_lock
);
1446 case AL_BUFFERS_QUEUED
:
1447 ReadLock(&Source
->queue_lock
);
1448 if(!(BufferList
=Source
->queue
))
1455 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1456 } while(BufferList
!= NULL
);
1459 ReadUnlock(&Source
->queue_lock
);
1462 case AL_BUFFERS_PROCESSED
:
1463 ReadLock(&Source
->queue_lock
);
1464 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1466 /* Buffers on a looping source are in a perpetual state of
1467 * PENDING, so don't report any as PROCESSED */
1472 const ALbufferlistitem
*BufferList
= Source
->queue
;
1473 const ALbufferlistitem
*Current
= NULL
;
1477 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1478 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1479 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1480 Current
= BufferList
;
1482 while(BufferList
&& BufferList
!= Current
)
1485 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1486 almemory_order_relaxed
);
1490 ReadUnlock(&Source
->queue_lock
);
1493 case AL_SOURCE_TYPE
:
1494 *values
= Source
->SourceType
;
1497 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1498 *values
= Source
->DryGainHFAuto
;
1501 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1502 *values
= Source
->WetGainAuto
;
1505 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1506 *values
= Source
->WetGainHFAuto
;
1509 case AL_DIRECT_CHANNELS_SOFT
:
1510 *values
= Source
->DirectChannels
;
1513 case AL_DISTANCE_MODEL
:
1514 *values
= Source
->DistanceModel
;
1517 case AL_SOURCE_RESAMPLER_SOFT
:
1518 *values
= Source
->Resampler
;
1521 case AL_SOURCE_SPATIALIZE_SOFT
:
1522 *values
= Source
->Spatialize
;
1525 /* 1x float/double */
1526 case AL_CONE_INNER_ANGLE
:
1527 case AL_CONE_OUTER_ANGLE
:
1532 case AL_REFERENCE_DISTANCE
:
1533 case AL_ROLLOFF_FACTOR
:
1534 case AL_CONE_OUTER_GAIN
:
1535 case AL_MAX_DISTANCE
:
1537 case AL_SAMPLE_OFFSET
:
1538 case AL_BYTE_OFFSET
:
1539 case AL_DOPPLER_FACTOR
:
1540 case AL_AIR_ABSORPTION_FACTOR
:
1541 case AL_ROOM_ROLLOFF_FACTOR
:
1542 case AL_CONE_OUTER_GAINHF
:
1543 case AL_SEC_LENGTH_SOFT
:
1544 case AL_SOURCE_RADIUS
:
1545 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1546 *values
= (ALint
)dvals
[0];
1549 /* 3x float/double */
1553 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1555 values
[0] = (ALint
)dvals
[0];
1556 values
[1] = (ALint
)dvals
[1];
1557 values
[2] = (ALint
)dvals
[2];
1561 /* 6x float/double */
1562 case AL_ORIENTATION
:
1563 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1565 values
[0] = (ALint
)dvals
[0];
1566 values
[1] = (ALint
)dvals
[1];
1567 values
[2] = (ALint
)dvals
[2];
1568 values
[3] = (ALint
)dvals
[3];
1569 values
[4] = (ALint
)dvals
[4];
1570 values
[5] = (ALint
)dvals
[5];
1574 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1575 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1576 break; /* i64 only */
1577 case AL_SEC_OFFSET_LATENCY_SOFT
:
1578 case AL_SEC_OFFSET_CLOCK_SOFT
:
1579 break; /* Double only */
1580 case AL_STEREO_ANGLES
:
1581 break; /* Float/double only */
1583 case AL_DIRECT_FILTER
:
1584 case AL_AUXILIARY_SEND_FILTER
:
1588 ERR("Unexpected property: 0x%04x\n", prop
);
1589 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1592 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1594 ALCdevice
*device
= Context
->Device
;
1595 ClockLatency clocktime
;
1603 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1604 /* Get the source offset with the clock time first. Then get the
1605 * clock time with the device latency. Order is important.
1607 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1608 clocktime
= V0(device
->Backend
,getClockLatency
)();
1609 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1610 values
[1] = clocktime
.Latency
;
1613 /* If the clock time incremented, reduce the latency by that
1614 * much since it's that much closer to the source offset it got
1617 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1618 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1622 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1623 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1624 values
[1] = srcclock
;
1627 /* 1x float/double */
1628 case AL_CONE_INNER_ANGLE
:
1629 case AL_CONE_OUTER_ANGLE
:
1634 case AL_REFERENCE_DISTANCE
:
1635 case AL_ROLLOFF_FACTOR
:
1636 case AL_CONE_OUTER_GAIN
:
1637 case AL_MAX_DISTANCE
:
1639 case AL_SAMPLE_OFFSET
:
1640 case AL_BYTE_OFFSET
:
1641 case AL_DOPPLER_FACTOR
:
1642 case AL_AIR_ABSORPTION_FACTOR
:
1643 case AL_ROOM_ROLLOFF_FACTOR
:
1644 case AL_CONE_OUTER_GAINHF
:
1645 case AL_SEC_LENGTH_SOFT
:
1646 case AL_SOURCE_RADIUS
:
1647 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1648 *values
= (ALint64
)dvals
[0];
1651 /* 3x float/double */
1655 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1657 values
[0] = (ALint64
)dvals
[0];
1658 values
[1] = (ALint64
)dvals
[1];
1659 values
[2] = (ALint64
)dvals
[2];
1663 /* 6x float/double */
1664 case AL_ORIENTATION
:
1665 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1667 values
[0] = (ALint64
)dvals
[0];
1668 values
[1] = (ALint64
)dvals
[1];
1669 values
[2] = (ALint64
)dvals
[2];
1670 values
[3] = (ALint64
)dvals
[3];
1671 values
[4] = (ALint64
)dvals
[4];
1672 values
[5] = (ALint64
)dvals
[5];
1677 case AL_SOURCE_RELATIVE
:
1679 case AL_SOURCE_STATE
:
1680 case AL_BUFFERS_QUEUED
:
1681 case AL_BUFFERS_PROCESSED
:
1682 case AL_BYTE_LENGTH_SOFT
:
1683 case AL_SAMPLE_LENGTH_SOFT
:
1684 case AL_SOURCE_TYPE
:
1685 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1686 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1687 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1688 case AL_DIRECT_CHANNELS_SOFT
:
1689 case AL_DISTANCE_MODEL
:
1690 case AL_SOURCE_RESAMPLER_SOFT
:
1691 case AL_SOURCE_SPATIALIZE_SOFT
:
1692 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1698 case AL_DIRECT_FILTER
:
1699 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1700 *values
= (ALuint
)ivals
[0];
1704 case AL_AUXILIARY_SEND_FILTER
:
1705 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1707 values
[0] = (ALuint
)ivals
[0];
1708 values
[1] = (ALuint
)ivals
[1];
1709 values
[2] = (ALuint
)ivals
[2];
1713 case AL_SEC_OFFSET_LATENCY_SOFT
:
1714 case AL_SEC_OFFSET_CLOCK_SOFT
:
1715 break; /* Double only */
1716 case AL_STEREO_ANGLES
:
1717 break; /* Float/double only */
1720 ERR("Unexpected property: 0x%04x\n", prop
);
1721 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1725 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1728 ALCcontext
*context
;
1732 context
= GetContextRef();
1733 if(!context
) return;
1736 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1737 device
= context
->Device
;
1738 for(cur
= 0;cur
< n
;cur
++)
1740 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1743 alDeleteSources(cur
, sources
);
1744 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1746 InitSourceParams(source
, device
->NumAuxSends
);
1748 err
= NewThunkEntry(&source
->id
);
1749 if(err
== AL_NO_ERROR
)
1750 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1751 if(err
!= AL_NO_ERROR
)
1753 FreeThunkEntry(source
->id
);
1754 memset(source
, 0, sizeof(ALsource
));
1757 alDeleteSources(cur
, sources
);
1758 SET_ERROR_AND_GOTO(context
, err
, done
);
1761 sources
[cur
] = source
->id
;
1765 ALCcontext_DecRef(context
);
1769 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1772 ALCcontext
*context
;
1776 context
= GetContextRef();
1777 if(!context
) return;
1779 LockSourcesWrite(context
);
1781 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1783 /* Check that all Sources are valid */
1784 for(i
= 0;i
< n
;i
++)
1786 if(LookupSource(context
, sources
[i
]) == NULL
)
1787 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1789 device
= context
->Device
;
1790 for(i
= 0;i
< n
;i
++)
1794 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1796 FreeThunkEntry(Source
->id
);
1798 ALCdevice_Lock(device
);
1799 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1801 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1802 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1804 ALCdevice_Unlock(device
);
1806 DeinitSource(Source
, device
->NumAuxSends
);
1808 memset(Source
, 0, sizeof(*Source
));
1813 UnlockSourcesWrite(context
);
1814 ALCcontext_DecRef(context
);
1818 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1820 ALCcontext
*context
;
1823 context
= GetContextRef();
1824 if(!context
) return AL_FALSE
;
1826 LockSourcesRead(context
);
1827 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1828 UnlockSourcesRead(context
);
1830 ALCcontext_DecRef(context
);
1836 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1838 ALCcontext
*Context
;
1841 Context
= GetContextRef();
1842 if(!Context
) return;
1844 WriteLock(&Context
->PropLock
);
1845 LockSourcesRead(Context
);
1846 if((Source
=LookupSource(Context
, source
)) == NULL
)
1847 alSetError(Context
, AL_INVALID_NAME
);
1848 else if(!(FloatValsByProp(param
) == 1))
1849 alSetError(Context
, AL_INVALID_ENUM
);
1851 SetSourcefv(Source
, Context
, param
, &value
);
1852 UnlockSourcesRead(Context
);
1853 WriteUnlock(&Context
->PropLock
);
1855 ALCcontext_DecRef(Context
);
1858 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1860 ALCcontext
*Context
;
1863 Context
= GetContextRef();
1864 if(!Context
) return;
1866 WriteLock(&Context
->PropLock
);
1867 LockSourcesRead(Context
);
1868 if((Source
=LookupSource(Context
, source
)) == NULL
)
1869 alSetError(Context
, AL_INVALID_NAME
);
1870 else if(!(FloatValsByProp(param
) == 3))
1871 alSetError(Context
, AL_INVALID_ENUM
);
1874 ALfloat fvals
[3] = { value1
, value2
, value3
};
1875 SetSourcefv(Source
, Context
, param
, fvals
);
1877 UnlockSourcesRead(Context
);
1878 WriteUnlock(&Context
->PropLock
);
1880 ALCcontext_DecRef(Context
);
1883 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1885 ALCcontext
*Context
;
1888 Context
= GetContextRef();
1889 if(!Context
) return;
1891 WriteLock(&Context
->PropLock
);
1892 LockSourcesRead(Context
);
1893 if((Source
=LookupSource(Context
, source
)) == NULL
)
1894 alSetError(Context
, AL_INVALID_NAME
);
1896 alSetError(Context
, AL_INVALID_VALUE
);
1897 else if(!(FloatValsByProp(param
) > 0))
1898 alSetError(Context
, AL_INVALID_ENUM
);
1900 SetSourcefv(Source
, Context
, param
, values
);
1901 UnlockSourcesRead(Context
);
1902 WriteUnlock(&Context
->PropLock
);
1904 ALCcontext_DecRef(Context
);
1908 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1910 ALCcontext
*Context
;
1913 Context
= GetContextRef();
1914 if(!Context
) return;
1916 WriteLock(&Context
->PropLock
);
1917 LockSourcesRead(Context
);
1918 if((Source
=LookupSource(Context
, source
)) == NULL
)
1919 alSetError(Context
, AL_INVALID_NAME
);
1920 else if(!(DoubleValsByProp(param
) == 1))
1921 alSetError(Context
, AL_INVALID_ENUM
);
1924 ALfloat fval
= (ALfloat
)value
;
1925 SetSourcefv(Source
, Context
, param
, &fval
);
1927 UnlockSourcesRead(Context
);
1928 WriteUnlock(&Context
->PropLock
);
1930 ALCcontext_DecRef(Context
);
1933 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1935 ALCcontext
*Context
;
1938 Context
= GetContextRef();
1939 if(!Context
) return;
1941 WriteLock(&Context
->PropLock
);
1942 LockSourcesRead(Context
);
1943 if((Source
=LookupSource(Context
, source
)) == NULL
)
1944 alSetError(Context
, AL_INVALID_NAME
);
1945 else if(!(DoubleValsByProp(param
) == 3))
1946 alSetError(Context
, AL_INVALID_ENUM
);
1949 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1950 SetSourcefv(Source
, Context
, param
, fvals
);
1952 UnlockSourcesRead(Context
);
1953 WriteUnlock(&Context
->PropLock
);
1955 ALCcontext_DecRef(Context
);
1958 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1960 ALCcontext
*Context
;
1964 Context
= GetContextRef();
1965 if(!Context
) return;
1967 WriteLock(&Context
->PropLock
);
1968 LockSourcesRead(Context
);
1969 if((Source
=LookupSource(Context
, source
)) == NULL
)
1970 alSetError(Context
, AL_INVALID_NAME
);
1972 alSetError(Context
, AL_INVALID_VALUE
);
1973 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1974 alSetError(Context
, AL_INVALID_ENUM
);
1980 for(i
= 0;i
< count
;i
++)
1981 fvals
[i
] = (ALfloat
)values
[i
];
1982 SetSourcefv(Source
, Context
, param
, fvals
);
1984 UnlockSourcesRead(Context
);
1985 WriteUnlock(&Context
->PropLock
);
1987 ALCcontext_DecRef(Context
);
1991 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1993 ALCcontext
*Context
;
1996 Context
= GetContextRef();
1997 if(!Context
) return;
1999 WriteLock(&Context
->PropLock
);
2000 LockSourcesRead(Context
);
2001 if((Source
=LookupSource(Context
, source
)) == NULL
)
2002 alSetError(Context
, AL_INVALID_NAME
);
2003 else if(!(IntValsByProp(param
) == 1))
2004 alSetError(Context
, AL_INVALID_ENUM
);
2006 SetSourceiv(Source
, Context
, param
, &value
);
2007 UnlockSourcesRead(Context
);
2008 WriteUnlock(&Context
->PropLock
);
2010 ALCcontext_DecRef(Context
);
2013 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
2015 ALCcontext
*Context
;
2018 Context
= GetContextRef();
2019 if(!Context
) return;
2021 WriteLock(&Context
->PropLock
);
2022 LockSourcesRead(Context
);
2023 if((Source
=LookupSource(Context
, source
)) == NULL
)
2024 alSetError(Context
, AL_INVALID_NAME
);
2025 else if(!(IntValsByProp(param
) == 3))
2026 alSetError(Context
, AL_INVALID_ENUM
);
2029 ALint ivals
[3] = { value1
, value2
, value3
};
2030 SetSourceiv(Source
, Context
, param
, ivals
);
2032 UnlockSourcesRead(Context
);
2033 WriteUnlock(&Context
->PropLock
);
2035 ALCcontext_DecRef(Context
);
2038 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
2040 ALCcontext
*Context
;
2043 Context
= GetContextRef();
2044 if(!Context
) return;
2046 WriteLock(&Context
->PropLock
);
2047 LockSourcesRead(Context
);
2048 if((Source
=LookupSource(Context
, source
)) == NULL
)
2049 alSetError(Context
, AL_INVALID_NAME
);
2051 alSetError(Context
, AL_INVALID_VALUE
);
2052 else if(!(IntValsByProp(param
) > 0))
2053 alSetError(Context
, AL_INVALID_ENUM
);
2055 SetSourceiv(Source
, Context
, param
, values
);
2056 UnlockSourcesRead(Context
);
2057 WriteUnlock(&Context
->PropLock
);
2059 ALCcontext_DecRef(Context
);
2063 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
2065 ALCcontext
*Context
;
2068 Context
= GetContextRef();
2069 if(!Context
) return;
2071 WriteLock(&Context
->PropLock
);
2072 LockSourcesRead(Context
);
2073 if((Source
=LookupSource(Context
, source
)) == NULL
)
2074 alSetError(Context
, AL_INVALID_NAME
);
2075 else if(!(Int64ValsByProp(param
) == 1))
2076 alSetError(Context
, AL_INVALID_ENUM
);
2078 SetSourcei64v(Source
, Context
, param
, &value
);
2079 UnlockSourcesRead(Context
);
2080 WriteUnlock(&Context
->PropLock
);
2082 ALCcontext_DecRef(Context
);
2085 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2087 ALCcontext
*Context
;
2090 Context
= GetContextRef();
2091 if(!Context
) return;
2093 WriteLock(&Context
->PropLock
);
2094 LockSourcesRead(Context
);
2095 if((Source
=LookupSource(Context
, source
)) == NULL
)
2096 alSetError(Context
, AL_INVALID_NAME
);
2097 else if(!(Int64ValsByProp(param
) == 3))
2098 alSetError(Context
, AL_INVALID_ENUM
);
2101 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2102 SetSourcei64v(Source
, Context
, param
, i64vals
);
2104 UnlockSourcesRead(Context
);
2105 WriteUnlock(&Context
->PropLock
);
2107 ALCcontext_DecRef(Context
);
2110 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2112 ALCcontext
*Context
;
2115 Context
= GetContextRef();
2116 if(!Context
) return;
2118 WriteLock(&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(!(Int64ValsByProp(param
) > 0))
2125 alSetError(Context
, AL_INVALID_ENUM
);
2127 SetSourcei64v(Source
, Context
, param
, values
);
2128 UnlockSourcesRead(Context
);
2129 WriteUnlock(&Context
->PropLock
);
2131 ALCcontext_DecRef(Context
);
2135 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2137 ALCcontext
*Context
;
2140 Context
= GetContextRef();
2141 if(!Context
) return;
2143 ReadLock(&Context
->PropLock
);
2144 LockSourcesRead(Context
);
2145 if((Source
=LookupSource(Context
, source
)) == NULL
)
2146 alSetError(Context
, AL_INVALID_NAME
);
2148 alSetError(Context
, AL_INVALID_VALUE
);
2149 else if(!(FloatValsByProp(param
) == 1))
2150 alSetError(Context
, AL_INVALID_ENUM
);
2154 if(GetSourcedv(Source
, Context
, param
, &dval
))
2155 *value
= (ALfloat
)dval
;
2157 UnlockSourcesRead(Context
);
2158 ReadUnlock(&Context
->PropLock
);
2160 ALCcontext_DecRef(Context
);
2164 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2166 ALCcontext
*Context
;
2169 Context
= GetContextRef();
2170 if(!Context
) return;
2172 ReadLock(&Context
->PropLock
);
2173 LockSourcesRead(Context
);
2174 if((Source
=LookupSource(Context
, source
)) == NULL
)
2175 alSetError(Context
, AL_INVALID_NAME
);
2176 else if(!(value1
&& value2
&& value3
))
2177 alSetError(Context
, AL_INVALID_VALUE
);
2178 else if(!(FloatValsByProp(param
) == 3))
2179 alSetError(Context
, AL_INVALID_ENUM
);
2183 if(GetSourcedv(Source
, Context
, param
, dvals
))
2185 *value1
= (ALfloat
)dvals
[0];
2186 *value2
= (ALfloat
)dvals
[1];
2187 *value3
= (ALfloat
)dvals
[2];
2190 UnlockSourcesRead(Context
);
2191 ReadUnlock(&Context
->PropLock
);
2193 ALCcontext_DecRef(Context
);
2197 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2199 ALCcontext
*Context
;
2203 Context
= GetContextRef();
2204 if(!Context
) return;
2206 ReadLock(&Context
->PropLock
);
2207 LockSourcesRead(Context
);
2208 if((Source
=LookupSource(Context
, source
)) == NULL
)
2209 alSetError(Context
, AL_INVALID_NAME
);
2211 alSetError(Context
, AL_INVALID_VALUE
);
2212 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2213 alSetError(Context
, AL_INVALID_ENUM
);
2217 if(GetSourcedv(Source
, Context
, param
, dvals
))
2220 for(i
= 0;i
< count
;i
++)
2221 values
[i
] = (ALfloat
)dvals
[i
];
2224 UnlockSourcesRead(Context
);
2225 ReadUnlock(&Context
->PropLock
);
2227 ALCcontext_DecRef(Context
);
2231 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2233 ALCcontext
*Context
;
2236 Context
= GetContextRef();
2237 if(!Context
) return;
2239 ReadLock(&Context
->PropLock
);
2240 LockSourcesRead(Context
);
2241 if((Source
=LookupSource(Context
, source
)) == NULL
)
2242 alSetError(Context
, AL_INVALID_NAME
);
2244 alSetError(Context
, AL_INVALID_VALUE
);
2245 else if(!(DoubleValsByProp(param
) == 1))
2246 alSetError(Context
, AL_INVALID_ENUM
);
2248 GetSourcedv(Source
, Context
, param
, value
);
2249 UnlockSourcesRead(Context
);
2250 ReadUnlock(&Context
->PropLock
);
2252 ALCcontext_DecRef(Context
);
2255 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2257 ALCcontext
*Context
;
2260 Context
= GetContextRef();
2261 if(!Context
) return;
2263 ReadLock(&Context
->PropLock
);
2264 LockSourcesRead(Context
);
2265 if((Source
=LookupSource(Context
, source
)) == NULL
)
2266 alSetError(Context
, AL_INVALID_NAME
);
2267 else if(!(value1
&& value2
&& value3
))
2268 alSetError(Context
, AL_INVALID_VALUE
);
2269 else if(!(DoubleValsByProp(param
) == 3))
2270 alSetError(Context
, AL_INVALID_ENUM
);
2274 if(GetSourcedv(Source
, Context
, param
, dvals
))
2281 UnlockSourcesRead(Context
);
2282 ReadUnlock(&Context
->PropLock
);
2284 ALCcontext_DecRef(Context
);
2287 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2289 ALCcontext
*Context
;
2292 Context
= GetContextRef();
2293 if(!Context
) return;
2295 ReadLock(&Context
->PropLock
);
2296 LockSourcesRead(Context
);
2297 if((Source
=LookupSource(Context
, source
)) == NULL
)
2298 alSetError(Context
, AL_INVALID_NAME
);
2300 alSetError(Context
, AL_INVALID_VALUE
);
2301 else if(!(DoubleValsByProp(param
) > 0))
2302 alSetError(Context
, AL_INVALID_ENUM
);
2304 GetSourcedv(Source
, Context
, param
, values
);
2305 UnlockSourcesRead(Context
);
2306 ReadUnlock(&Context
->PropLock
);
2308 ALCcontext_DecRef(Context
);
2312 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2314 ALCcontext
*Context
;
2317 Context
= GetContextRef();
2318 if(!Context
) return;
2320 ReadLock(&Context
->PropLock
);
2321 LockSourcesRead(Context
);
2322 if((Source
=LookupSource(Context
, source
)) == NULL
)
2323 alSetError(Context
, AL_INVALID_NAME
);
2325 alSetError(Context
, AL_INVALID_VALUE
);
2326 else if(!(IntValsByProp(param
) == 1))
2327 alSetError(Context
, AL_INVALID_ENUM
);
2329 GetSourceiv(Source
, Context
, param
, value
);
2330 UnlockSourcesRead(Context
);
2331 ReadUnlock(&Context
->PropLock
);
2333 ALCcontext_DecRef(Context
);
2337 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2339 ALCcontext
*Context
;
2342 Context
= GetContextRef();
2343 if(!Context
) return;
2345 ReadLock(&Context
->PropLock
);
2346 LockSourcesRead(Context
);
2347 if((Source
=LookupSource(Context
, source
)) == NULL
)
2348 alSetError(Context
, AL_INVALID_NAME
);
2349 else if(!(value1
&& value2
&& value3
))
2350 alSetError(Context
, AL_INVALID_VALUE
);
2351 else if(!(IntValsByProp(param
) == 3))
2352 alSetError(Context
, AL_INVALID_ENUM
);
2356 if(GetSourceiv(Source
, Context
, param
, ivals
))
2363 UnlockSourcesRead(Context
);
2364 ReadUnlock(&Context
->PropLock
);
2366 ALCcontext_DecRef(Context
);
2370 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2372 ALCcontext
*Context
;
2375 Context
= GetContextRef();
2376 if(!Context
) return;
2378 ReadLock(&Context
->PropLock
);
2379 LockSourcesRead(Context
);
2380 if((Source
=LookupSource(Context
, source
)) == NULL
)
2381 alSetError(Context
, AL_INVALID_NAME
);
2383 alSetError(Context
, AL_INVALID_VALUE
);
2384 else if(!(IntValsByProp(param
) > 0))
2385 alSetError(Context
, AL_INVALID_ENUM
);
2387 GetSourceiv(Source
, Context
, param
, values
);
2388 UnlockSourcesRead(Context
);
2389 ReadUnlock(&Context
->PropLock
);
2391 ALCcontext_DecRef(Context
);
2395 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2397 ALCcontext
*Context
;
2400 Context
= GetContextRef();
2401 if(!Context
) return;
2403 ReadLock(&Context
->PropLock
);
2404 LockSourcesRead(Context
);
2405 if((Source
=LookupSource(Context
, source
)) == NULL
)
2406 alSetError(Context
, AL_INVALID_NAME
);
2408 alSetError(Context
, AL_INVALID_VALUE
);
2409 else if(!(Int64ValsByProp(param
) == 1))
2410 alSetError(Context
, AL_INVALID_ENUM
);
2412 GetSourcei64v(Source
, Context
, param
, value
);
2413 UnlockSourcesRead(Context
);
2414 ReadUnlock(&Context
->PropLock
);
2416 ALCcontext_DecRef(Context
);
2419 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2421 ALCcontext
*Context
;
2424 Context
= GetContextRef();
2425 if(!Context
) return;
2427 ReadLock(&Context
->PropLock
);
2428 LockSourcesRead(Context
);
2429 if((Source
=LookupSource(Context
, source
)) == NULL
)
2430 alSetError(Context
, AL_INVALID_NAME
);
2431 else if(!(value1
&& value2
&& value3
))
2432 alSetError(Context
, AL_INVALID_VALUE
);
2433 else if(!(Int64ValsByProp(param
) == 3))
2434 alSetError(Context
, AL_INVALID_ENUM
);
2438 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2440 *value1
= i64vals
[0];
2441 *value2
= i64vals
[1];
2442 *value3
= i64vals
[2];
2445 UnlockSourcesRead(Context
);
2446 ReadUnlock(&Context
->PropLock
);
2448 ALCcontext_DecRef(Context
);
2451 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2453 ALCcontext
*Context
;
2456 Context
= GetContextRef();
2457 if(!Context
) return;
2459 ReadLock(&Context
->PropLock
);
2460 LockSourcesRead(Context
);
2461 if((Source
=LookupSource(Context
, source
)) == NULL
)
2462 alSetError(Context
, AL_INVALID_NAME
);
2464 alSetError(Context
, AL_INVALID_VALUE
);
2465 else if(!(Int64ValsByProp(param
) > 0))
2466 alSetError(Context
, AL_INVALID_ENUM
);
2468 GetSourcei64v(Source
, Context
, param
, values
);
2469 UnlockSourcesRead(Context
);
2470 ReadUnlock(&Context
->PropLock
);
2472 ALCcontext_DecRef(Context
);
2476 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2478 alSourcePlayv(1, &source
);
2480 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2482 ALCcontext
*context
;
2488 context
= GetContextRef();
2489 if(!context
) return;
2491 LockSourcesRead(context
);
2493 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2494 for(i
= 0;i
< n
;i
++)
2496 if(!LookupSource(context
, sources
[i
]))
2497 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2500 device
= context
->Device
;
2501 ALCdevice_Lock(device
);
2502 /* If the device is disconnected, go right to stopped. */
2503 if(!device
->Connected
)
2505 for(i
= 0;i
< n
;i
++)
2507 source
= LookupSource(context
, sources
[i
]);
2508 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2510 ALCdevice_Unlock(device
);
2514 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2516 ALsizei newcount
= context
->MaxVoices
<< 1;
2517 if(context
->MaxVoices
>= newcount
)
2519 ALCdevice_Unlock(device
);
2520 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2522 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2525 for(i
= 0;i
< n
;i
++)
2527 ALbufferlistitem
*BufferList
;
2528 ALbuffer
*buffer
= NULL
;
2529 bool start_fading
= false;
2532 source
= LookupSource(context
, sources
[i
]);
2533 WriteLock(&source
->queue_lock
);
2534 /* Check that there is a queue containing at least one valid, non zero
2537 BufferList
= source
->queue
;
2541 for(b
= 0;b
< BufferList
->num_buffers
;b
++)
2543 buffer
= BufferList
->buffers
[b
];
2544 if(buffer
&& buffer
->SampleLen
> 0) break;
2546 if(buffer
&& buffer
->SampleLen
> 0) break;
2547 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2550 /* If there's nothing to play, go right to stopped. */
2553 /* NOTE: A source without any playable buffers should not have an
2554 * ALvoice since it shouldn't be in a playing or paused state. So
2555 * there's no need to look up its voice and clear the source.
2557 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2558 source
->OffsetType
= AL_NONE
;
2559 source
->Offset
= 0.0;
2563 voice
= GetSourceVoice(source
, context
);
2564 switch(GetSourceState(source
, voice
))
2567 assert(voice
!= NULL
);
2568 /* A source that's already playing is restarted from the beginning. */
2569 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2570 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2571 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2575 assert(voice
!= NULL
);
2576 /* A source that's paused simply resumes. */
2577 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2578 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2585 /* Make sure this source isn't already active, and if not, look for an
2586 * unused voice to put it in.
2588 assert(voice
== NULL
);
2589 for(j
= 0;j
< context
->VoiceCount
;j
++)
2591 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2593 voice
= context
->Voices
[j
];
2598 voice
= context
->Voices
[context
->VoiceCount
++];
2599 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2601 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2602 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2604 /* A source that's not playing or paused has any offset applied when it
2608 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2610 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2611 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2612 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2613 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2614 if(source
->OffsetType
!= AL_NONE
)
2616 ApplyOffset(source
, voice
);
2617 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2618 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2619 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2622 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2623 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2625 /* Clear previous samples. */
2626 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2628 /* Clear the stepping value so the mixer knows not to mix this until
2629 * the update gets applied.
2633 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2634 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2635 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2636 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2637 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2638 if(device
->AvgSpeakerDist
> 0.0f
)
2640 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2641 (device
->AvgSpeakerDist
* device
->Frequency
);
2642 for(j
= 0;j
< voice
->NumChannels
;j
++)
2644 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2645 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2646 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2650 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2651 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2652 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2654 WriteUnlock(&source
->queue_lock
);
2656 ALCdevice_Unlock(device
);
2659 UnlockSourcesRead(context
);
2660 ALCcontext_DecRef(context
);
2663 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2665 alSourcePausev(1, &source
);
2667 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2669 ALCcontext
*context
;
2675 context
= GetContextRef();
2676 if(!context
) return;
2678 LockSourcesRead(context
);
2680 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2681 for(i
= 0;i
< n
;i
++)
2683 if(!LookupSource(context
, sources
[i
]))
2684 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2687 device
= context
->Device
;
2688 ALCdevice_Lock(device
);
2689 for(i
= 0;i
< n
;i
++)
2691 source
= LookupSource(context
, sources
[i
]);
2692 WriteLock(&source
->queue_lock
);
2693 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2695 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2696 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2699 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2700 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2701 WriteUnlock(&source
->queue_lock
);
2703 ALCdevice_Unlock(device
);
2706 UnlockSourcesRead(context
);
2707 ALCcontext_DecRef(context
);
2710 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2712 alSourceStopv(1, &source
);
2714 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2716 ALCcontext
*context
;
2722 context
= GetContextRef();
2723 if(!context
) return;
2725 LockSourcesRead(context
);
2727 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2728 for(i
= 0;i
< n
;i
++)
2730 if(!LookupSource(context
, sources
[i
]))
2731 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2734 device
= context
->Device
;
2735 ALCdevice_Lock(device
);
2736 for(i
= 0;i
< n
;i
++)
2738 source
= LookupSource(context
, sources
[i
]);
2739 WriteLock(&source
->queue_lock
);
2740 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2742 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2743 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2744 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2747 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2748 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2749 source
->OffsetType
= AL_NONE
;
2750 source
->Offset
= 0.0;
2751 WriteUnlock(&source
->queue_lock
);
2753 ALCdevice_Unlock(device
);
2756 UnlockSourcesRead(context
);
2757 ALCcontext_DecRef(context
);
2760 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2762 alSourceRewindv(1, &source
);
2764 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2766 ALCcontext
*context
;
2772 context
= GetContextRef();
2773 if(!context
) return;
2775 LockSourcesRead(context
);
2777 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2778 for(i
= 0;i
< n
;i
++)
2780 if(!LookupSource(context
, sources
[i
]))
2781 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2784 device
= context
->Device
;
2785 ALCdevice_Lock(device
);
2786 for(i
= 0;i
< n
;i
++)
2788 source
= LookupSource(context
, sources
[i
]);
2789 WriteLock(&source
->queue_lock
);
2790 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2792 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2793 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2794 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2797 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2798 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2799 source
->OffsetType
= AL_NONE
;
2800 source
->Offset
= 0.0;
2801 WriteUnlock(&source
->queue_lock
);
2803 ALCdevice_Unlock(device
);
2806 UnlockSourcesRead(context
);
2807 ALCcontext_DecRef(context
);
2811 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2814 ALCcontext
*context
;
2817 ALbufferlistitem
*BufferListStart
;
2818 ALbufferlistitem
*BufferList
;
2819 ALbuffer
*BufferFmt
= NULL
;
2824 context
= GetContextRef();
2825 if(!context
) return;
2827 device
= context
->Device
;
2829 LockSourcesRead(context
);
2831 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2832 if((source
=LookupSource(context
, src
)) == NULL
)
2833 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2835 WriteLock(&source
->queue_lock
);
2836 if(source
->SourceType
== AL_STATIC
)
2838 WriteUnlock(&source
->queue_lock
);
2839 /* Can't queue on a Static Source */
2840 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2843 /* Check for a valid Buffer, for its frequency and format */
2844 BufferList
= source
->queue
;
2847 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2849 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2852 if(BufferFmt
) break;
2853 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2856 LockBuffersRead(device
);
2857 BufferListStart
= NULL
;
2859 for(i
= 0;i
< nb
;i
++)
2861 ALbuffer
*buffer
= NULL
;
2862 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2864 WriteUnlock(&source
->queue_lock
);
2865 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2868 if(!BufferListStart
)
2870 BufferListStart
= al_calloc(DEF_ALIGN
,
2871 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2872 BufferList
= BufferListStart
;
2876 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
,
2877 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2878 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2881 ATOMIC_INIT(&BufferList
->next
, NULL
);
2882 BufferList
->num_buffers
= 1;
2883 BufferList
->buffers
[0] = buffer
;
2884 if(!buffer
) continue;
2886 /* Hold a read lock on each buffer being queued while checking all
2887 * provided buffers. This is done so other threads don't see an extra
2888 * reference on some buffers if this operation ends up failing. */
2889 ReadLock(&buffer
->lock
);
2890 IncrementRef(&buffer
->ref
);
2892 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2894 WriteUnlock(&source
->queue_lock
);
2895 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2898 if(BufferFmt
== NULL
)
2900 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2901 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2902 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2904 WriteUnlock(&source
->queue_lock
);
2905 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2908 /* A buffer failed (invalid ID or format), so unlock and release
2909 * each buffer we had. */
2910 while(BufferListStart
)
2912 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2913 almemory_order_relaxed
);
2914 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2916 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2918 DecrementRef(&buffer
->ref
);
2919 ReadUnlock(&buffer
->lock
);
2922 al_free(BufferListStart
);
2923 BufferListStart
= next
;
2925 UnlockBuffersRead(device
);
2929 /* All buffers good, unlock them now. */
2930 BufferList
= BufferListStart
;
2931 while(BufferList
!= NULL
)
2933 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2935 ALbuffer
*buffer
= BufferList
->buffers
[i
];
2936 if(buffer
) ReadUnlock(&buffer
->lock
);
2938 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2940 UnlockBuffersRead(device
);
2942 /* Source is now streaming */
2943 source
->SourceType
= AL_STREAMING
;
2945 if(!(BufferList
=source
->queue
))
2946 source
->queue
= BufferListStart
;
2949 ALbufferlistitem
*next
;
2950 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2952 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2954 WriteUnlock(&source
->queue_lock
);
2957 UnlockSourcesRead(context
);
2958 ALCcontext_DecRef(context
);
2961 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2963 ALCcontext
*context
;
2965 ALbufferlistitem
*OldHead
;
2966 ALbufferlistitem
*OldTail
;
2967 ALbufferlistitem
*Current
;
2971 context
= GetContextRef();
2972 if(!context
) return;
2974 LockSourcesRead(context
);
2976 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2978 if((source
=LookupSource(context
, src
)) == NULL
)
2979 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2981 /* Nothing to unqueue. */
2982 if(nb
== 0) goto done
;
2984 WriteLock(&source
->queue_lock
);
2985 if(source
->Looping
|| source
->SourceType
!= AL_STREAMING
)
2987 WriteUnlock(&source
->queue_lock
);
2988 /* Trying to unqueue buffers on a looping or non-streaming source. */
2989 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2992 /* Find the new buffer queue head */
2993 OldTail
= source
->queue
;
2995 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2996 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2997 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2999 if(OldTail
!= Current
&& OldTail
->num_buffers
== 1)
3001 for(i
= 1;i
< nb
;i
++)
3003 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldTail
->next
, almemory_order_relaxed
);
3004 if(!next
|| next
== Current
|| next
->num_buffers
!= 1) break;
3010 WriteUnlock(&source
->queue_lock
);
3011 /* Trying to unqueue pending buffers. */
3012 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
3015 /* Swap it, and cut the new head from the old. */
3016 OldHead
= source
->queue
;
3017 source
->queue
= ATOMIC_EXCHANGE_PTR(&OldTail
->next
, NULL
, almemory_order_acq_rel
);
3018 WriteUnlock(&source
->queue_lock
);
3020 while(OldHead
!= NULL
)
3022 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldHead
->next
, almemory_order_relaxed
);
3023 ALbuffer
*buffer
= OldHead
->buffers
[0];
3029 *(buffers
++) = buffer
->id
;
3030 DecrementRef(&buffer
->ref
);
3038 UnlockSourcesRead(context
);
3039 ALCcontext_DecRef(context
);
3043 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
3047 RWLockInit(&Source
->queue_lock
);
3049 Source
->InnerAngle
= 360.0f
;
3050 Source
->OuterAngle
= 360.0f
;
3051 Source
->Pitch
= 1.0f
;
3052 Source
->Position
[0] = 0.0f
;
3053 Source
->Position
[1] = 0.0f
;
3054 Source
->Position
[2] = 0.0f
;
3055 Source
->Velocity
[0] = 0.0f
;
3056 Source
->Velocity
[1] = 0.0f
;
3057 Source
->Velocity
[2] = 0.0f
;
3058 Source
->Direction
[0] = 0.0f
;
3059 Source
->Direction
[1] = 0.0f
;
3060 Source
->Direction
[2] = 0.0f
;
3061 Source
->Orientation
[0][0] = 0.0f
;
3062 Source
->Orientation
[0][1] = 0.0f
;
3063 Source
->Orientation
[0][2] = -1.0f
;
3064 Source
->Orientation
[1][0] = 0.0f
;
3065 Source
->Orientation
[1][1] = 1.0f
;
3066 Source
->Orientation
[1][2] = 0.0f
;
3067 Source
->RefDistance
= 1.0f
;
3068 Source
->MaxDistance
= FLT_MAX
;
3069 Source
->RolloffFactor
= 1.0f
;
3070 Source
->Gain
= 1.0f
;
3071 Source
->MinGain
= 0.0f
;
3072 Source
->MaxGain
= 1.0f
;
3073 Source
->OuterGain
= 0.0f
;
3074 Source
->OuterGainHF
= 1.0f
;
3076 Source
->DryGainHFAuto
= AL_TRUE
;
3077 Source
->WetGainAuto
= AL_TRUE
;
3078 Source
->WetGainHFAuto
= AL_TRUE
;
3079 Source
->AirAbsorptionFactor
= 0.0f
;
3080 Source
->RoomRolloffFactor
= 0.0f
;
3081 Source
->DopplerFactor
= 1.0f
;
3082 Source
->HeadRelative
= AL_FALSE
;
3083 Source
->Looping
= AL_FALSE
;
3084 Source
->DistanceModel
= DefaultDistanceModel
;
3085 Source
->Resampler
= ResamplerDefault
;
3086 Source
->DirectChannels
= AL_FALSE
;
3087 Source
->Spatialize
= SpatializeAuto
;
3089 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
3090 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
3092 Source
->Radius
= 0.0f
;
3094 Source
->Direct
.Gain
= 1.0f
;
3095 Source
->Direct
.GainHF
= 1.0f
;
3096 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
3097 Source
->Direct
.GainLF
= 1.0f
;
3098 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
3099 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
3100 for(i
= 0;i
< num_sends
;i
++)
3102 Source
->Send
[i
].Slot
= NULL
;
3103 Source
->Send
[i
].Gain
= 1.0f
;
3104 Source
->Send
[i
].GainHF
= 1.0f
;
3105 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
3106 Source
->Send
[i
].GainLF
= 1.0f
;
3107 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
3110 Source
->Offset
= 0.0;
3111 Source
->OffsetType
= AL_NONE
;
3112 Source
->SourceType
= AL_UNDETERMINED
;
3113 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
3115 Source
->queue
= NULL
;
3117 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3120 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3123 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3125 ALbufferlistitem
*BufferList
;
3128 BufferList
= source
->queue
;
3129 while(BufferList
!= NULL
)
3131 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3132 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3134 if(BufferList
->buffers
[i
] != NULL
)
3135 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3137 al_free(BufferList
);
3140 source
->queue
= NULL
;
3144 for(i
= 0;i
< num_sends
;i
++)
3146 if(source
->Send
[i
].Slot
)
3147 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3148 source
->Send
[i
].Slot
= NULL
;
3150 al_free(source
->Send
);
3151 source
->Send
= NULL
;
3155 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3157 struct ALvoiceProps
*props
;
3160 /* Get an unused property container, or allocate a new one as needed. */
3161 props
= ATOMIC_LOAD(&context
->FreeVoiceProps
, almemory_order_acquire
);
3163 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3166 struct ALvoiceProps
*next
;
3168 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3169 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeVoiceProps
, &props
, next
,
3170 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3173 /* Copy in current property values. */
3174 props
->Pitch
= source
->Pitch
;
3175 props
->Gain
= source
->Gain
;
3176 props
->OuterGain
= source
->OuterGain
;
3177 props
->MinGain
= source
->MinGain
;
3178 props
->MaxGain
= source
->MaxGain
;
3179 props
->InnerAngle
= source
->InnerAngle
;
3180 props
->OuterAngle
= source
->OuterAngle
;
3181 props
->RefDistance
= source
->RefDistance
;
3182 props
->MaxDistance
= source
->MaxDistance
;
3183 props
->RolloffFactor
= source
->RolloffFactor
;
3184 for(i
= 0;i
< 3;i
++)
3185 props
->Position
[i
] = source
->Position
[i
];
3186 for(i
= 0;i
< 3;i
++)
3187 props
->Velocity
[i
] = source
->Velocity
[i
];
3188 for(i
= 0;i
< 3;i
++)
3189 props
->Direction
[i
] = source
->Direction
[i
];
3190 for(i
= 0;i
< 2;i
++)
3193 for(j
= 0;j
< 3;j
++)
3194 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3196 props
->HeadRelative
= source
->HeadRelative
;
3197 props
->DistanceModel
= source
->DistanceModel
;
3198 props
->Resampler
= source
->Resampler
;
3199 props
->DirectChannels
= source
->DirectChannels
;
3200 props
->SpatializeMode
= source
->Spatialize
;
3202 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3203 props
->WetGainAuto
= source
->WetGainAuto
;
3204 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3205 props
->OuterGainHF
= source
->OuterGainHF
;
3207 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3208 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3209 props
->DopplerFactor
= source
->DopplerFactor
;
3211 props
->StereoPan
[0] = source
->StereoPan
[0];
3212 props
->StereoPan
[1] = source
->StereoPan
[1];
3214 props
->Radius
= source
->Radius
;
3216 props
->Direct
.Gain
= source
->Direct
.Gain
;
3217 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3218 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3219 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3220 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3222 for(i
= 0;i
< num_sends
;i
++)
3224 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3225 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3226 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3227 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3228 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3229 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3232 /* Set the new container for updating internal parameters. */
3233 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3236 /* If there was an unused update container, put it back in the
3239 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &context
->FreeVoiceProps
, props
);
3243 void UpdateAllSourceProps(ALCcontext
*context
)
3245 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3248 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3250 ALvoice
*voice
= context
->Voices
[pos
];
3251 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3252 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3253 UpdateSourceProps(source
, voice
, num_sends
, context
);
3258 /* GetSourceSampleOffset
3260 * Gets the current read offset for the given Source, in 32.32 fixed-point
3261 * samples. The offset is relative to the start of the queue (not the start of
3262 * the current buffer).
3264 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3266 ALCdevice
*device
= context
->Device
;
3267 const ALbufferlistitem
*Current
;
3272 ReadLock(&Source
->queue_lock
);
3276 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3278 *clocktime
= GetDeviceClockTime(device
);
3280 voice
= GetSourceVoice(Source
, context
);
3283 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3285 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3286 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3289 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3290 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3294 const ALbufferlistitem
*BufferList
= Source
->queue
;
3295 while(BufferList
&& BufferList
!= Current
)
3297 ALsizei max_len
= 0;
3300 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3302 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3303 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3305 readPos
+= (ALuint64
)max_len
<< 32;
3306 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3307 almemory_order_relaxed
);
3309 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3312 ReadUnlock(&Source
->queue_lock
);
3313 return (ALint64
)readPos
;
3316 /* GetSourceSecOffset
3318 * Gets the current read offset for the given Source, in seconds. The offset is
3319 * relative to the start of the queue (not the start of the current buffer).
3321 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3323 ALCdevice
*device
= context
->Device
;
3324 const ALbufferlistitem
*Current
;
3330 ReadLock(&Source
->queue_lock
);
3334 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3336 *clocktime
= GetDeviceClockTime(device
);
3338 voice
= GetSourceVoice(Source
, context
);
3341 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3343 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3345 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3347 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3348 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3353 const ALbufferlistitem
*BufferList
= Source
->queue
;
3354 const ALbuffer
*BufferFmt
= NULL
;
3355 while(BufferList
&& BufferList
!= Current
)
3357 ALsizei max_len
= 0;
3360 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3362 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3365 if(!BufferFmt
) BufferFmt
= buffer
;
3366 max_len
= maxi(max_len
, buffer
->SampleLen
);
3369 readPos
+= (ALuint64
)max_len
<< FRACTIONBITS
;
3370 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3371 almemory_order_relaxed
);
3374 while(BufferList
&& !BufferFmt
)
3377 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3378 BufferFmt
= BufferList
->buffers
[i
];
3379 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3380 almemory_order_relaxed
);
3382 assert(BufferFmt
!= NULL
);
3384 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3385 (ALdouble
)BufferFmt
->Frequency
;
3388 ReadUnlock(&Source
->queue_lock
);
3394 * Gets the current read offset for the given Source, in the appropriate format
3395 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3396 * queue (not the start of the current buffer).
3398 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3400 ALCdevice
*device
= context
->Device
;
3401 const ALbufferlistitem
*Current
;
3403 ALsizei readPosFrac
;
3408 ReadLock(&Source
->queue_lock
);
3411 readPos
= readPosFrac
= 0;
3412 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3414 voice
= GetSourceVoice(Source
, context
);
3417 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3419 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3420 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3422 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3423 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3428 const ALbufferlistitem
*BufferList
= Source
->queue
;
3429 const ALbuffer
*BufferFmt
= NULL
;
3430 ALboolean readFin
= AL_FALSE
;
3431 ALuint totalBufferLen
= 0;
3433 while(BufferList
!= NULL
)
3435 ALsizei max_len
= 0;
3438 readFin
= readFin
|| (BufferList
== Current
);
3439 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3441 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3444 if(!BufferFmt
) BufferFmt
= buffer
;
3445 max_len
= maxi(max_len
, buffer
->SampleLen
);
3448 totalBufferLen
+= max_len
;
3449 if(!readFin
) readPos
+= max_len
;
3451 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3452 almemory_order_relaxed
);
3454 assert(BufferFmt
!= NULL
);
3457 readPos
%= totalBufferLen
;
3460 /* Wrap back to 0 */
3461 if(readPos
>= totalBufferLen
)
3462 readPos
= readPosFrac
= 0;
3469 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3472 case AL_SAMPLE_OFFSET
:
3473 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3476 case AL_BYTE_OFFSET
:
3477 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3479 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3480 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3481 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3483 /* Round down to nearest ADPCM block */
3484 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3486 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3488 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3489 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3490 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3492 /* Round down to nearest ADPCM block */
3493 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3497 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
3498 BufferFmt
->FmtType
);
3499 offset
= (ALdouble
)(readPos
* FrameSize
);
3505 ReadUnlock(&Source
->queue_lock
);
3512 * Apply the stored playback offset to the Source. This function will update
3513 * the number of buffers "played" given the stored offset.
3515 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3517 ALbufferlistitem
*BufferList
;
3518 ALuint bufferLen
, totalBufferLen
;
3522 /* Get sample frame offset */
3523 if(!GetSampleOffset(Source
, &offset
, &frac
))
3527 BufferList
= Source
->queue
;
3528 while(BufferList
&& totalBufferLen
<= offset
)
3530 ALsizei max_len
= 0;
3533 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3535 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3536 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3538 bufferLen
= max_len
;
3540 if(bufferLen
> offset
-totalBufferLen
)
3542 /* Offset is in this buffer */
3543 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3544 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3545 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3549 totalBufferLen
+= bufferLen
;
3551 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3554 /* Offset is out of range of the queue */
3561 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3562 * or Second offset supplied by the application). This takes into account the
3563 * fact that the buffer format may have been modifed since.
3565 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3567 const ALbuffer
*BufferFmt
= NULL
;
3568 const ALbufferlistitem
*BufferList
;
3569 ALdouble dbloff
, dblfrac
;
3571 /* Find the first valid Buffer in the Queue */
3572 BufferList
= Source
->queue
;
3576 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3577 BufferFmt
= BufferList
->buffers
[i
];
3578 if(BufferFmt
) break;
3579 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3580 almemory_order_relaxed
);
3584 Source
->OffsetType
= AL_NONE
;
3585 Source
->Offset
= 0.0;
3589 switch(Source
->OffsetType
)
3591 case AL_BYTE_OFFSET
:
3592 /* Determine the ByteOffset (and ensure it is block aligned) */
3593 *offset
= (ALuint
)Source
->Offset
;
3594 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3596 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3597 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3598 *offset
*= BufferFmt
->OriginalAlign
;
3600 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3602 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3603 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3604 *offset
*= BufferFmt
->OriginalAlign
;
3607 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
3611 case AL_SAMPLE_OFFSET
:
3612 dblfrac
= modf(Source
->Offset
, &dbloff
);
3613 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3614 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3618 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3619 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3620 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3623 Source
->OffsetType
= AL_NONE
;
3624 Source
->Offset
= 0.0;
3632 * Destroys all sources in the source map.
3634 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3636 ALCdevice
*device
= Context
->Device
;
3638 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3640 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3641 Context
->SourceMap
.values
[pos
] = NULL
;
3643 DeinitSource(temp
, device
->NumAuxSends
);
3645 FreeThunkEntry(temp
->id
);
3646 memset(temp
, 0, sizeof(*temp
));