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 static ALsource
*AllocSource(ALCcontext
*context
);
44 static void FreeSource(ALCcontext
*context
, ALsource
*source
);
45 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
46 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
47 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
);
48 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
49 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
50 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
51 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
);
52 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
);
54 static inline void LockSourceList(ALCcontext
*context
)
55 { almtx_lock(&context
->SourceLock
); }
56 static inline void UnlockSourceList(ALCcontext
*context
)
57 { almtx_unlock(&context
->SourceLock
); }
59 static inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
)
61 SourceSubList
*sublist
;
62 ALuint lidx
= (id
-1) >> 6;
63 ALsizei slidx
= (id
-1) & 0x3f;
65 if(UNLIKELY(lidx
>= VECTOR_SIZE(context
->SourceList
)))
67 sublist
= &VECTOR_ELEM(context
->SourceList
, lidx
);
68 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
70 return sublist
->Sources
+ slidx
;
73 static inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
)
75 BufferSubList
*sublist
;
76 ALuint lidx
= (id
-1) >> 6;
77 ALsizei slidx
= (id
-1) & 0x3f;
79 if(UNLIKELY(lidx
>= VECTOR_SIZE(device
->BufferList
)))
81 sublist
= &VECTOR_ELEM(device
->BufferList
, lidx
);
82 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
84 return sublist
->Buffers
+ slidx
;
87 static inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
)
89 FilterSubList
*sublist
;
90 ALuint lidx
= (id
-1) >> 6;
91 ALsizei slidx
= (id
-1) & 0x3f;
93 if(UNLIKELY(lidx
>= VECTOR_SIZE(device
->FilterList
)))
95 sublist
= &VECTOR_ELEM(device
->FilterList
, lidx
);
96 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
98 return sublist
->Filters
+ slidx
;
101 static inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
)
104 if(UNLIKELY(id
>= VECTOR_SIZE(context
->EffectSlotList
)))
106 return VECTOR_ELEM(context
->EffectSlotList
, id
);
110 typedef enum SourceProp
{
113 srcMinGain
= AL_MIN_GAIN
,
114 srcMaxGain
= AL_MAX_GAIN
,
115 srcMaxDistance
= AL_MAX_DISTANCE
,
116 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
117 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
118 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
119 srcSecOffset
= AL_SEC_OFFSET
,
120 srcSampleOffset
= AL_SAMPLE_OFFSET
,
121 srcByteOffset
= AL_BYTE_OFFSET
,
122 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
123 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
124 srcRefDistance
= AL_REFERENCE_DISTANCE
,
126 srcPosition
= AL_POSITION
,
127 srcVelocity
= AL_VELOCITY
,
128 srcDirection
= AL_DIRECTION
,
130 srcSourceRelative
= AL_SOURCE_RELATIVE
,
131 srcLooping
= AL_LOOPING
,
132 srcBuffer
= AL_BUFFER
,
133 srcSourceState
= AL_SOURCE_STATE
,
134 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
135 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
136 srcSourceType
= AL_SOURCE_TYPE
,
139 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
140 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
141 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
142 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
143 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
144 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
145 srcDirectFilter
= AL_DIRECT_FILTER
,
146 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
148 /* AL_SOFT_direct_channels */
149 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
151 /* AL_EXT_source_distance_model */
152 srcDistanceModel
= AL_DISTANCE_MODEL
,
154 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
155 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
156 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
158 /* AL_SOFT_source_latency */
159 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
160 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
162 /* AL_EXT_STEREO_ANGLES */
163 srcAngles
= AL_STEREO_ANGLES
,
165 /* AL_EXT_SOURCE_RADIUS */
166 srcRadius
= AL_SOURCE_RADIUS
,
169 srcOrientation
= AL_ORIENTATION
,
171 /* AL_SOFT_source_resampler */
172 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
174 /* AL_SOFT_source_spatialize */
175 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
177 /* ALC_SOFT_device_clock */
178 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
179 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
182 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
183 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
184 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
186 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
187 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
188 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
190 static inline ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
192 ALint idx
= source
->VoiceIdx
;
193 if(idx
>= 0 && idx
< context
->VoiceCount
)
195 ALvoice
*voice
= context
->Voices
[idx
];
196 if(ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
) == source
)
199 source
->VoiceIdx
= -1;
204 * Returns if the last known state for the source was playing or paused. Does
205 * not sync with the mixer voice.
207 static inline bool IsPlayingOrPaused(ALsource
*source
)
209 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
210 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
214 * Returns an updated source state using the matching voice's status (or lack
217 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
221 ALenum state
= AL_PLAYING
;
222 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
223 almemory_order_acq_rel
, almemory_order_acquire
))
227 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
231 * Returns if the source should specify an update, given the context's
232 * deferring state and the source's last known state.
234 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
236 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
237 IsPlayingOrPaused(source
);
240 static ALint
FloatValsByProp(ALenum prop
)
242 if(prop
!= (ALenum
)((SourceProp
)prop
))
244 switch((SourceProp
)prop
)
250 case AL_MAX_DISTANCE
:
251 case AL_ROLLOFF_FACTOR
:
252 case AL_DOPPLER_FACTOR
:
253 case AL_CONE_OUTER_GAIN
:
255 case AL_SAMPLE_OFFSET
:
257 case AL_CONE_INNER_ANGLE
:
258 case AL_CONE_OUTER_ANGLE
:
259 case AL_REFERENCE_DISTANCE
:
260 case AL_CONE_OUTER_GAINHF
:
261 case AL_AIR_ABSORPTION_FACTOR
:
262 case AL_ROOM_ROLLOFF_FACTOR
:
263 case AL_DIRECT_FILTER_GAINHF_AUTO
:
264 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
265 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
266 case AL_DIRECT_CHANNELS_SOFT
:
267 case AL_DISTANCE_MODEL
:
268 case AL_SOURCE_RELATIVE
:
270 case AL_SOURCE_STATE
:
271 case AL_BUFFERS_QUEUED
:
272 case AL_BUFFERS_PROCESSED
:
274 case AL_BYTE_LENGTH_SOFT
:
275 case AL_SAMPLE_LENGTH_SOFT
:
276 case AL_SEC_LENGTH_SOFT
:
277 case AL_SOURCE_RADIUS
:
278 case AL_SOURCE_RESAMPLER_SOFT
:
279 case AL_SOURCE_SPATIALIZE_SOFT
:
282 case AL_STEREO_ANGLES
:
293 case AL_SEC_OFFSET_LATENCY_SOFT
:
294 case AL_SEC_OFFSET_CLOCK_SOFT
:
295 break; /* Double only */
298 case AL_DIRECT_FILTER
:
299 case AL_AUXILIARY_SEND_FILTER
:
300 break; /* i/i64 only */
301 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
302 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
303 break; /* i64 only */
307 static ALint
DoubleValsByProp(ALenum prop
)
309 if(prop
!= (ALenum
)((SourceProp
)prop
))
311 switch((SourceProp
)prop
)
317 case AL_MAX_DISTANCE
:
318 case AL_ROLLOFF_FACTOR
:
319 case AL_DOPPLER_FACTOR
:
320 case AL_CONE_OUTER_GAIN
:
322 case AL_SAMPLE_OFFSET
:
324 case AL_CONE_INNER_ANGLE
:
325 case AL_CONE_OUTER_ANGLE
:
326 case AL_REFERENCE_DISTANCE
:
327 case AL_CONE_OUTER_GAINHF
:
328 case AL_AIR_ABSORPTION_FACTOR
:
329 case AL_ROOM_ROLLOFF_FACTOR
:
330 case AL_DIRECT_FILTER_GAINHF_AUTO
:
331 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
332 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
333 case AL_DIRECT_CHANNELS_SOFT
:
334 case AL_DISTANCE_MODEL
:
335 case AL_SOURCE_RELATIVE
:
337 case AL_SOURCE_STATE
:
338 case AL_BUFFERS_QUEUED
:
339 case AL_BUFFERS_PROCESSED
:
341 case AL_BYTE_LENGTH_SOFT
:
342 case AL_SAMPLE_LENGTH_SOFT
:
343 case AL_SEC_LENGTH_SOFT
:
344 case AL_SOURCE_RADIUS
:
345 case AL_SOURCE_RESAMPLER_SOFT
:
346 case AL_SOURCE_SPATIALIZE_SOFT
:
349 case AL_SEC_OFFSET_LATENCY_SOFT
:
350 case AL_SEC_OFFSET_CLOCK_SOFT
:
351 case AL_STEREO_ANGLES
:
363 case AL_DIRECT_FILTER
:
364 case AL_AUXILIARY_SEND_FILTER
:
365 break; /* i/i64 only */
366 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
367 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
368 break; /* i64 only */
373 static ALint
IntValsByProp(ALenum prop
)
375 if(prop
!= (ALenum
)((SourceProp
)prop
))
377 switch((SourceProp
)prop
)
383 case AL_MAX_DISTANCE
:
384 case AL_ROLLOFF_FACTOR
:
385 case AL_DOPPLER_FACTOR
:
386 case AL_CONE_OUTER_GAIN
:
388 case AL_SAMPLE_OFFSET
:
390 case AL_CONE_INNER_ANGLE
:
391 case AL_CONE_OUTER_ANGLE
:
392 case AL_REFERENCE_DISTANCE
:
393 case AL_CONE_OUTER_GAINHF
:
394 case AL_AIR_ABSORPTION_FACTOR
:
395 case AL_ROOM_ROLLOFF_FACTOR
:
396 case AL_DIRECT_FILTER_GAINHF_AUTO
:
397 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
398 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
399 case AL_DIRECT_CHANNELS_SOFT
:
400 case AL_DISTANCE_MODEL
:
401 case AL_SOURCE_RELATIVE
:
404 case AL_SOURCE_STATE
:
405 case AL_BUFFERS_QUEUED
:
406 case AL_BUFFERS_PROCESSED
:
408 case AL_DIRECT_FILTER
:
409 case AL_BYTE_LENGTH_SOFT
:
410 case AL_SAMPLE_LENGTH_SOFT
:
411 case AL_SEC_LENGTH_SOFT
:
412 case AL_SOURCE_RADIUS
:
413 case AL_SOURCE_RESAMPLER_SOFT
:
414 case AL_SOURCE_SPATIALIZE_SOFT
:
420 case AL_AUXILIARY_SEND_FILTER
:
426 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
427 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
428 break; /* i64 only */
429 case AL_SEC_OFFSET_LATENCY_SOFT
:
430 case AL_SEC_OFFSET_CLOCK_SOFT
:
431 break; /* Double only */
432 case AL_STEREO_ANGLES
:
433 break; /* Float/double only */
437 static ALint
Int64ValsByProp(ALenum prop
)
439 if(prop
!= (ALenum
)((SourceProp
)prop
))
441 switch((SourceProp
)prop
)
447 case AL_MAX_DISTANCE
:
448 case AL_ROLLOFF_FACTOR
:
449 case AL_DOPPLER_FACTOR
:
450 case AL_CONE_OUTER_GAIN
:
452 case AL_SAMPLE_OFFSET
:
454 case AL_CONE_INNER_ANGLE
:
455 case AL_CONE_OUTER_ANGLE
:
456 case AL_REFERENCE_DISTANCE
:
457 case AL_CONE_OUTER_GAINHF
:
458 case AL_AIR_ABSORPTION_FACTOR
:
459 case AL_ROOM_ROLLOFF_FACTOR
:
460 case AL_DIRECT_FILTER_GAINHF_AUTO
:
461 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
462 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
463 case AL_DIRECT_CHANNELS_SOFT
:
464 case AL_DISTANCE_MODEL
:
465 case AL_SOURCE_RELATIVE
:
468 case AL_SOURCE_STATE
:
469 case AL_BUFFERS_QUEUED
:
470 case AL_BUFFERS_PROCESSED
:
472 case AL_DIRECT_FILTER
:
473 case AL_BYTE_LENGTH_SOFT
:
474 case AL_SAMPLE_LENGTH_SOFT
:
475 case AL_SEC_LENGTH_SOFT
:
476 case AL_SOURCE_RADIUS
:
477 case AL_SOURCE_RESAMPLER_SOFT
:
478 case AL_SOURCE_SPATIALIZE_SOFT
:
481 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
482 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
488 case AL_AUXILIARY_SEND_FILTER
:
494 case AL_SEC_OFFSET_LATENCY_SOFT
:
495 case AL_SEC_OFFSET_CLOCK_SOFT
:
496 break; /* Double only */
497 case AL_STEREO_ANGLES
:
498 break; /* Float/double only */
504 #define CHECKVAL(x) do { \
507 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
512 #define DO_UPDATEPROPS() do { \
514 if(SourceShouldUpdate(Source, Context) && \
515 (voice=GetSourceVoice(Source, Context)) != NULL) \
516 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
518 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
521 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
523 ALCdevice
*device
= Context
->Device
;
528 case AL_BYTE_LENGTH_SOFT
:
529 case AL_SAMPLE_LENGTH_SOFT
:
530 case AL_SEC_LENGTH_SOFT
:
531 case AL_SEC_OFFSET_LATENCY_SOFT
:
532 case AL_SEC_OFFSET_CLOCK_SOFT
:
534 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
535 "Setting read-only source property 0x%04x", prop
);
538 CHECKVAL(*values
>= 0.0f
);
540 Source
->Pitch
= *values
;
544 case AL_CONE_INNER_ANGLE
:
545 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
547 Source
->InnerAngle
= *values
;
551 case AL_CONE_OUTER_ANGLE
:
552 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
554 Source
->OuterAngle
= *values
;
559 CHECKVAL(*values
>= 0.0f
);
561 Source
->Gain
= *values
;
565 case AL_MAX_DISTANCE
:
566 CHECKVAL(*values
>= 0.0f
);
568 Source
->MaxDistance
= *values
;
572 case AL_ROLLOFF_FACTOR
:
573 CHECKVAL(*values
>= 0.0f
);
575 Source
->RolloffFactor
= *values
;
579 case AL_REFERENCE_DISTANCE
:
580 CHECKVAL(*values
>= 0.0f
);
582 Source
->RefDistance
= *values
;
587 CHECKVAL(*values
>= 0.0f
);
589 Source
->MinGain
= *values
;
594 CHECKVAL(*values
>= 0.0f
);
596 Source
->MaxGain
= *values
;
600 case AL_CONE_OUTER_GAIN
:
601 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
603 Source
->OuterGain
= *values
;
607 case AL_CONE_OUTER_GAINHF
:
608 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
610 Source
->OuterGainHF
= *values
;
614 case AL_AIR_ABSORPTION_FACTOR
:
615 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
617 Source
->AirAbsorptionFactor
= *values
;
621 case AL_ROOM_ROLLOFF_FACTOR
:
622 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
624 Source
->RoomRolloffFactor
= *values
;
628 case AL_DOPPLER_FACTOR
:
629 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
631 Source
->DopplerFactor
= *values
;
636 case AL_SAMPLE_OFFSET
:
638 CHECKVAL(*values
>= 0.0f
);
640 Source
->OffsetType
= prop
;
641 Source
->Offset
= *values
;
643 if(IsPlayingOrPaused(Source
))
647 ALCdevice_Lock(Context
->Device
);
648 /* Double-check that the source is still playing while we have
651 voice
= GetSourceVoice(Source
, Context
);
654 WriteLock(&Source
->queue_lock
);
655 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
657 WriteUnlock(&Source
->queue_lock
);
658 ALCdevice_Unlock(Context
->Device
);
659 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid offset");
661 WriteUnlock(&Source
->queue_lock
);
663 ALCdevice_Unlock(Context
->Device
);
667 case AL_SOURCE_RADIUS
:
668 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
670 Source
->Radius
= *values
;
674 case AL_STEREO_ANGLES
:
675 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
677 Source
->StereoPan
[0] = values
[0];
678 Source
->StereoPan
[1] = values
[1];
684 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
686 Source
->Position
[0] = values
[0];
687 Source
->Position
[1] = values
[1];
688 Source
->Position
[2] = values
[2];
693 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
695 Source
->Velocity
[0] = values
[0];
696 Source
->Velocity
[1] = values
[1];
697 Source
->Velocity
[2] = values
[2];
702 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
704 Source
->Direction
[0] = values
[0];
705 Source
->Direction
[1] = values
[1];
706 Source
->Direction
[2] = values
[2];
711 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
712 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
714 Source
->Orientation
[0][0] = values
[0];
715 Source
->Orientation
[0][1] = values
[1];
716 Source
->Orientation
[0][2] = values
[2];
717 Source
->Orientation
[1][0] = values
[3];
718 Source
->Orientation
[1][1] = values
[4];
719 Source
->Orientation
[1][2] = values
[5];
724 case AL_SOURCE_RELATIVE
:
726 case AL_SOURCE_STATE
:
728 case AL_DISTANCE_MODEL
:
729 case AL_DIRECT_FILTER_GAINHF_AUTO
:
730 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
731 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
732 case AL_DIRECT_CHANNELS_SOFT
:
733 case AL_SOURCE_RESAMPLER_SOFT
:
734 case AL_SOURCE_SPATIALIZE_SOFT
:
735 ival
= (ALint
)values
[0];
736 return SetSourceiv(Source
, Context
, prop
, &ival
);
738 case AL_BUFFERS_QUEUED
:
739 case AL_BUFFERS_PROCESSED
:
740 ival
= (ALint
)((ALuint
)values
[0]);
741 return SetSourceiv(Source
, Context
, prop
, &ival
);
744 case AL_DIRECT_FILTER
:
745 case AL_AUXILIARY_SEND_FILTER
:
746 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
747 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
751 ERR("Unexpected property: 0x%04x\n", prop
);
752 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source float property 0x%04x", prop
);
755 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
757 ALCdevice
*device
= Context
->Device
;
758 ALbuffer
*buffer
= NULL
;
759 ALfilter
*filter
= NULL
;
760 ALeffectslot
*slot
= NULL
;
761 ALbufferlistitem
*oldlist
;
766 case AL_SOURCE_STATE
:
768 case AL_BUFFERS_QUEUED
:
769 case AL_BUFFERS_PROCESSED
:
770 case AL_BYTE_LENGTH_SOFT
:
771 case AL_SAMPLE_LENGTH_SOFT
:
772 case AL_SEC_LENGTH_SOFT
:
774 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
775 "Setting read-only source property 0x%04x", prop
);
777 case AL_SOURCE_RELATIVE
:
778 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
780 Source
->HeadRelative
= (ALboolean
)*values
;
785 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
787 WriteLock(&Source
->queue_lock
);
788 Source
->Looping
= (ALboolean
)*values
;
789 if(IsPlayingOrPaused(Source
))
791 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
795 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
797 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
799 /* If the source is playing, wait for the current mix to finish
800 * to ensure it isn't currently looping back or reaching the
803 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
807 WriteUnlock(&Source
->queue_lock
);
811 LockBufferList(device
);
812 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
814 UnlockBufferList(device
);
815 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
819 WriteLock(&Source
->queue_lock
);
820 if(buffer
&& buffer
->MappedAccess
!= 0 &&
821 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
823 WriteUnlock(&Source
->queue_lock
);
824 UnlockBufferList(device
);
825 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
826 "Setting non-persistently mapped buffer %u", buffer
->id
);
830 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
831 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
833 WriteUnlock(&Source
->queue_lock
);
834 UnlockBufferList(device
);
835 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
836 "Setting buffer on playing or paused source %u", Source
->id
);
840 oldlist
= Source
->queue
;
843 /* Add the selected buffer to a one-item queue */
844 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
,
845 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
846 ATOMIC_INIT(&newlist
->next
, NULL
);
847 newlist
->num_buffers
= 1;
848 newlist
->buffers
[0] = buffer
;
849 IncrementRef(&buffer
->ref
);
851 /* Source is now Static */
852 Source
->SourceType
= AL_STATIC
;
853 Source
->queue
= newlist
;
857 /* Source is now Undetermined */
858 Source
->SourceType
= AL_UNDETERMINED
;
859 Source
->queue
= NULL
;
861 WriteUnlock(&Source
->queue_lock
);
862 UnlockBufferList(device
);
864 /* Delete all elements in the previous queue */
865 while(oldlist
!= NULL
)
868 ALbufferlistitem
*temp
= oldlist
;
869 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
871 for(i
= 0;i
< temp
->num_buffers
;i
++)
874 DecrementRef(&temp
->buffers
[i
]->ref
);
881 case AL_SAMPLE_OFFSET
:
883 CHECKVAL(*values
>= 0);
885 Source
->OffsetType
= prop
;
886 Source
->Offset
= *values
;
888 if(IsPlayingOrPaused(Source
))
892 ALCdevice_Lock(Context
->Device
);
893 voice
= GetSourceVoice(Source
, Context
);
896 WriteLock(&Source
->queue_lock
);
897 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
899 WriteUnlock(&Source
->queue_lock
);
900 ALCdevice_Unlock(Context
->Device
);
901 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
902 "Invalid source offset");
904 WriteUnlock(&Source
->queue_lock
);
906 ALCdevice_Unlock(Context
->Device
);
910 case AL_DIRECT_FILTER
:
911 LockFilterList(device
);
912 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
914 UnlockFilterList(device
);
915 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
921 Source
->Direct
.Gain
= 1.0f
;
922 Source
->Direct
.GainHF
= 1.0f
;
923 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
924 Source
->Direct
.GainLF
= 1.0f
;
925 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
929 Source
->Direct
.Gain
= filter
->Gain
;
930 Source
->Direct
.GainHF
= filter
->GainHF
;
931 Source
->Direct
.HFReference
= filter
->HFReference
;
932 Source
->Direct
.GainLF
= filter
->GainLF
;
933 Source
->Direct
.LFReference
= filter
->LFReference
;
935 UnlockFilterList(device
);
939 case AL_DIRECT_FILTER_GAINHF_AUTO
:
940 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
942 Source
->DryGainHFAuto
= *values
;
946 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
947 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
949 Source
->WetGainAuto
= *values
;
953 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
954 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
956 Source
->WetGainHFAuto
= *values
;
960 case AL_DIRECT_CHANNELS_SOFT
:
961 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
963 Source
->DirectChannels
= *values
;
967 case AL_DISTANCE_MODEL
:
968 CHECKVAL(*values
== AL_NONE
||
969 *values
== AL_INVERSE_DISTANCE
||
970 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
971 *values
== AL_LINEAR_DISTANCE
||
972 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
973 *values
== AL_EXPONENT_DISTANCE
||
974 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
976 Source
->DistanceModel
= *values
;
977 if(Context
->SourceDistanceModel
)
981 case AL_SOURCE_RESAMPLER_SOFT
:
982 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
984 Source
->Resampler
= *values
;
988 case AL_SOURCE_SPATIALIZE_SOFT
:
989 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
991 Source
->Spatialize
= *values
;
996 case AL_AUXILIARY_SEND_FILTER
:
997 LockEffectSlotList(Context
);
998 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
))
1000 UnlockEffectSlotList(Context
);
1001 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
1004 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
))
1006 UnlockEffectSlotList(Context
);
1007 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
1009 LockFilterList(device
);
1010 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
))
1012 UnlockFilterList(device
);
1013 UnlockEffectSlotList(Context
);
1014 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1020 /* Disable filter */
1021 Source
->Send
[values
[1]].Gain
= 1.0f
;
1022 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1023 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1024 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1025 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1029 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1030 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1031 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1032 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1033 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1035 UnlockFilterList(device
);
1037 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1040 /* Add refcount on the new slot, and release the previous slot */
1041 if(slot
) IncrementRef(&slot
->ref
);
1042 if(Source
->Send
[values
[1]].Slot
)
1043 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1044 Source
->Send
[values
[1]].Slot
= slot
;
1046 /* We must force an update if the auxiliary slot changed on an
1047 * active source, in case the slot is about to be deleted.
1049 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1050 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
1052 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
1056 if(slot
) IncrementRef(&slot
->ref
);
1057 if(Source
->Send
[values
[1]].Slot
)
1058 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1059 Source
->Send
[values
[1]].Slot
= slot
;
1062 UnlockEffectSlotList(Context
);
1068 case AL_CONE_INNER_ANGLE
:
1069 case AL_CONE_OUTER_ANGLE
:
1074 case AL_REFERENCE_DISTANCE
:
1075 case AL_ROLLOFF_FACTOR
:
1076 case AL_CONE_OUTER_GAIN
:
1077 case AL_MAX_DISTANCE
:
1078 case AL_DOPPLER_FACTOR
:
1079 case AL_CONE_OUTER_GAINHF
:
1080 case AL_AIR_ABSORPTION_FACTOR
:
1081 case AL_ROOM_ROLLOFF_FACTOR
:
1082 case AL_SOURCE_RADIUS
:
1083 fvals
[0] = (ALfloat
)*values
;
1084 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1090 fvals
[0] = (ALfloat
)values
[0];
1091 fvals
[1] = (ALfloat
)values
[1];
1092 fvals
[2] = (ALfloat
)values
[2];
1093 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1096 case AL_ORIENTATION
:
1097 fvals
[0] = (ALfloat
)values
[0];
1098 fvals
[1] = (ALfloat
)values
[1];
1099 fvals
[2] = (ALfloat
)values
[2];
1100 fvals
[3] = (ALfloat
)values
[3];
1101 fvals
[4] = (ALfloat
)values
[4];
1102 fvals
[5] = (ALfloat
)values
[5];
1103 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1105 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1106 case AL_SEC_OFFSET_LATENCY_SOFT
:
1107 case AL_SEC_OFFSET_CLOCK_SOFT
:
1108 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1109 case AL_STEREO_ANGLES
:
1113 ERR("Unexpected property: 0x%04x\n", prop
);
1114 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1118 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1125 case AL_SOURCE_TYPE
:
1126 case AL_BUFFERS_QUEUED
:
1127 case AL_BUFFERS_PROCESSED
:
1128 case AL_SOURCE_STATE
:
1129 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1130 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1131 case AL_BYTE_LENGTH_SOFT
:
1132 case AL_SAMPLE_LENGTH_SOFT
:
1133 case AL_SEC_LENGTH_SOFT
:
1135 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1136 "Setting read-only source property 0x%04x", prop
);
1139 case AL_SOURCE_RELATIVE
:
1142 case AL_SAMPLE_OFFSET
:
1143 case AL_BYTE_OFFSET
:
1144 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1145 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1146 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1147 case AL_DIRECT_CHANNELS_SOFT
:
1148 case AL_DISTANCE_MODEL
:
1149 case AL_SOURCE_RESAMPLER_SOFT
:
1150 case AL_SOURCE_SPATIALIZE_SOFT
:
1151 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1153 ivals
[0] = (ALint
)*values
;
1154 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1158 case AL_DIRECT_FILTER
:
1159 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1161 ivals
[0] = (ALuint
)*values
;
1162 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1165 case AL_AUXILIARY_SEND_FILTER
:
1166 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1167 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1168 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1170 ivals
[0] = (ALuint
)values
[0];
1171 ivals
[1] = (ALuint
)values
[1];
1172 ivals
[2] = (ALuint
)values
[2];
1173 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1176 case AL_CONE_INNER_ANGLE
:
1177 case AL_CONE_OUTER_ANGLE
:
1182 case AL_REFERENCE_DISTANCE
:
1183 case AL_ROLLOFF_FACTOR
:
1184 case AL_CONE_OUTER_GAIN
:
1185 case AL_MAX_DISTANCE
:
1186 case AL_DOPPLER_FACTOR
:
1187 case AL_CONE_OUTER_GAINHF
:
1188 case AL_AIR_ABSORPTION_FACTOR
:
1189 case AL_ROOM_ROLLOFF_FACTOR
:
1190 case AL_SOURCE_RADIUS
:
1191 fvals
[0] = (ALfloat
)*values
;
1192 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1198 fvals
[0] = (ALfloat
)values
[0];
1199 fvals
[1] = (ALfloat
)values
[1];
1200 fvals
[2] = (ALfloat
)values
[2];
1201 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1204 case AL_ORIENTATION
:
1205 fvals
[0] = (ALfloat
)values
[0];
1206 fvals
[1] = (ALfloat
)values
[1];
1207 fvals
[2] = (ALfloat
)values
[2];
1208 fvals
[3] = (ALfloat
)values
[3];
1209 fvals
[4] = (ALfloat
)values
[4];
1210 fvals
[5] = (ALfloat
)values
[5];
1211 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1213 case AL_SEC_OFFSET_LATENCY_SOFT
:
1214 case AL_SEC_OFFSET_CLOCK_SOFT
:
1215 case AL_STEREO_ANGLES
:
1219 ERR("Unexpected property: 0x%04x\n", prop
);
1220 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1227 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1229 ALCdevice
*device
= Context
->Device
;
1230 ALbufferlistitem
*BufferList
;
1231 ClockLatency clocktime
;
1239 *values
= Source
->Gain
;
1243 *values
= Source
->Pitch
;
1246 case AL_MAX_DISTANCE
:
1247 *values
= Source
->MaxDistance
;
1250 case AL_ROLLOFF_FACTOR
:
1251 *values
= Source
->RolloffFactor
;
1254 case AL_REFERENCE_DISTANCE
:
1255 *values
= Source
->RefDistance
;
1258 case AL_CONE_INNER_ANGLE
:
1259 *values
= Source
->InnerAngle
;
1262 case AL_CONE_OUTER_ANGLE
:
1263 *values
= Source
->OuterAngle
;
1267 *values
= Source
->MinGain
;
1271 *values
= Source
->MaxGain
;
1274 case AL_CONE_OUTER_GAIN
:
1275 *values
= Source
->OuterGain
;
1279 case AL_SAMPLE_OFFSET
:
1280 case AL_BYTE_OFFSET
:
1281 *values
= GetSourceOffset(Source
, prop
, Context
);
1284 case AL_CONE_OUTER_GAINHF
:
1285 *values
= Source
->OuterGainHF
;
1288 case AL_AIR_ABSORPTION_FACTOR
:
1289 *values
= Source
->AirAbsorptionFactor
;
1292 case AL_ROOM_ROLLOFF_FACTOR
:
1293 *values
= Source
->RoomRolloffFactor
;
1296 case AL_DOPPLER_FACTOR
:
1297 *values
= Source
->DopplerFactor
;
1300 case AL_SEC_LENGTH_SOFT
:
1301 ReadLock(&Source
->queue_lock
);
1302 if(!(BufferList
=Source
->queue
))
1309 ALsizei max_len
= 0;
1311 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1313 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1314 if(buffer
&& buffer
->SampleLen
> 0)
1316 freq
= buffer
->Frequency
;
1317 max_len
= maxi(max_len
, buffer
->SampleLen
);
1321 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1322 } while(BufferList
!= NULL
);
1323 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1325 ReadUnlock(&Source
->queue_lock
);
1328 case AL_SOURCE_RADIUS
:
1329 *values
= Source
->Radius
;
1332 case AL_STEREO_ANGLES
:
1333 values
[0] = Source
->StereoPan
[0];
1334 values
[1] = Source
->StereoPan
[1];
1337 case AL_SEC_OFFSET_LATENCY_SOFT
:
1338 /* Get the source offset with the clock time first. Then get the
1339 * clock time with the device latency. Order is important.
1341 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1342 clocktime
= V0(device
->Backend
,getClockLatency
)();
1343 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1344 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1347 /* If the clock time incremented, reduce the latency by that
1348 * much since it's that much closer to the source offset it got
1351 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1352 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1357 case AL_SEC_OFFSET_CLOCK_SOFT
:
1358 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1359 values
[1] = srcclock
/ 1000000000.0;
1363 values
[0] = Source
->Position
[0];
1364 values
[1] = Source
->Position
[1];
1365 values
[2] = Source
->Position
[2];
1369 values
[0] = Source
->Velocity
[0];
1370 values
[1] = Source
->Velocity
[1];
1371 values
[2] = Source
->Velocity
[2];
1375 values
[0] = Source
->Direction
[0];
1376 values
[1] = Source
->Direction
[1];
1377 values
[2] = Source
->Direction
[2];
1380 case AL_ORIENTATION
:
1381 values
[0] = Source
->Orientation
[0][0];
1382 values
[1] = Source
->Orientation
[0][1];
1383 values
[2] = Source
->Orientation
[0][2];
1384 values
[3] = Source
->Orientation
[1][0];
1385 values
[4] = Source
->Orientation
[1][1];
1386 values
[5] = Source
->Orientation
[1][2];
1390 case AL_SOURCE_RELATIVE
:
1392 case AL_SOURCE_STATE
:
1393 case AL_BUFFERS_QUEUED
:
1394 case AL_BUFFERS_PROCESSED
:
1395 case AL_SOURCE_TYPE
:
1396 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1397 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1398 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1399 case AL_DIRECT_CHANNELS_SOFT
:
1400 case AL_BYTE_LENGTH_SOFT
:
1401 case AL_SAMPLE_LENGTH_SOFT
:
1402 case AL_DISTANCE_MODEL
:
1403 case AL_SOURCE_RESAMPLER_SOFT
:
1404 case AL_SOURCE_SPATIALIZE_SOFT
:
1405 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1406 *values
= (ALdouble
)ivals
[0];
1410 case AL_DIRECT_FILTER
:
1411 case AL_AUXILIARY_SEND_FILTER
:
1412 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1413 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1417 ERR("Unexpected property: 0x%04x\n", prop
);
1418 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1422 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1424 ALbufferlistitem
*BufferList
;
1430 case AL_SOURCE_RELATIVE
:
1431 *values
= Source
->HeadRelative
;
1435 *values
= Source
->Looping
;
1439 ReadLock(&Source
->queue_lock
);
1440 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1441 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1442 BufferList
->buffers
[0]->id
: 0;
1443 ReadUnlock(&Source
->queue_lock
);
1446 case AL_SOURCE_STATE
:
1447 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1450 case AL_BYTE_LENGTH_SOFT
:
1451 ReadLock(&Source
->queue_lock
);
1452 if(!(BufferList
=Source
->queue
))
1458 ALsizei max_len
= 0;
1460 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1462 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1463 if(buffer
&& buffer
->SampleLen
> 0)
1465 ALuint byte_align
, sample_align
;
1466 if(buffer
->OriginalType
== UserFmtIMA4
)
1468 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1469 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1470 sample_align
= buffer
->OriginalAlign
;
1472 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1474 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1475 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1476 sample_align
= buffer
->OriginalAlign
;
1480 ALsizei align
= buffer
->OriginalAlign
;
1481 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1482 sample_align
= buffer
->OriginalAlign
;
1485 max_len
= maxi(max_len
, buffer
->SampleLen
/ sample_align
* byte_align
);
1490 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1491 } while(BufferList
!= NULL
);
1494 ReadUnlock(&Source
->queue_lock
);
1497 case AL_SAMPLE_LENGTH_SOFT
:
1498 ReadLock(&Source
->queue_lock
);
1499 if(!(BufferList
=Source
->queue
))
1505 ALsizei max_len
= 0;
1507 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
1509 ALbuffer
*buffer
= BufferList
->buffers
[i
];
1510 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
1513 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1514 } while(BufferList
!= NULL
);
1517 ReadUnlock(&Source
->queue_lock
);
1520 case AL_BUFFERS_QUEUED
:
1521 ReadLock(&Source
->queue_lock
);
1522 if(!(BufferList
=Source
->queue
))
1529 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1530 } while(BufferList
!= NULL
);
1533 ReadUnlock(&Source
->queue_lock
);
1536 case AL_BUFFERS_PROCESSED
:
1537 ReadLock(&Source
->queue_lock
);
1538 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1540 /* Buffers on a looping source are in a perpetual state of
1541 * PENDING, so don't report any as PROCESSED */
1546 const ALbufferlistitem
*BufferList
= Source
->queue
;
1547 const ALbufferlistitem
*Current
= NULL
;
1551 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1552 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1553 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1554 Current
= BufferList
;
1556 while(BufferList
&& BufferList
!= Current
)
1559 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1560 almemory_order_relaxed
);
1564 ReadUnlock(&Source
->queue_lock
);
1567 case AL_SOURCE_TYPE
:
1568 *values
= Source
->SourceType
;
1571 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1572 *values
= Source
->DryGainHFAuto
;
1575 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1576 *values
= Source
->WetGainAuto
;
1579 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1580 *values
= Source
->WetGainHFAuto
;
1583 case AL_DIRECT_CHANNELS_SOFT
:
1584 *values
= Source
->DirectChannels
;
1587 case AL_DISTANCE_MODEL
:
1588 *values
= Source
->DistanceModel
;
1591 case AL_SOURCE_RESAMPLER_SOFT
:
1592 *values
= Source
->Resampler
;
1595 case AL_SOURCE_SPATIALIZE_SOFT
:
1596 *values
= Source
->Spatialize
;
1599 /* 1x float/double */
1600 case AL_CONE_INNER_ANGLE
:
1601 case AL_CONE_OUTER_ANGLE
:
1606 case AL_REFERENCE_DISTANCE
:
1607 case AL_ROLLOFF_FACTOR
:
1608 case AL_CONE_OUTER_GAIN
:
1609 case AL_MAX_DISTANCE
:
1611 case AL_SAMPLE_OFFSET
:
1612 case AL_BYTE_OFFSET
:
1613 case AL_DOPPLER_FACTOR
:
1614 case AL_AIR_ABSORPTION_FACTOR
:
1615 case AL_ROOM_ROLLOFF_FACTOR
:
1616 case AL_CONE_OUTER_GAINHF
:
1617 case AL_SEC_LENGTH_SOFT
:
1618 case AL_SOURCE_RADIUS
:
1619 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1620 *values
= (ALint
)dvals
[0];
1623 /* 3x float/double */
1627 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1629 values
[0] = (ALint
)dvals
[0];
1630 values
[1] = (ALint
)dvals
[1];
1631 values
[2] = (ALint
)dvals
[2];
1635 /* 6x float/double */
1636 case AL_ORIENTATION
:
1637 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1639 values
[0] = (ALint
)dvals
[0];
1640 values
[1] = (ALint
)dvals
[1];
1641 values
[2] = (ALint
)dvals
[2];
1642 values
[3] = (ALint
)dvals
[3];
1643 values
[4] = (ALint
)dvals
[4];
1644 values
[5] = (ALint
)dvals
[5];
1648 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1649 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1650 break; /* i64 only */
1651 case AL_SEC_OFFSET_LATENCY_SOFT
:
1652 case AL_SEC_OFFSET_CLOCK_SOFT
:
1653 break; /* Double only */
1654 case AL_STEREO_ANGLES
:
1655 break; /* Float/double only */
1657 case AL_DIRECT_FILTER
:
1658 case AL_AUXILIARY_SEND_FILTER
:
1662 ERR("Unexpected property: 0x%04x\n", prop
);
1663 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1667 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1669 ALCdevice
*device
= Context
->Device
;
1670 ClockLatency clocktime
;
1678 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1679 /* Get the source offset with the clock time first. Then get the
1680 * clock time with the device latency. Order is important.
1682 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1683 clocktime
= V0(device
->Backend
,getClockLatency
)();
1684 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1685 values
[1] = clocktime
.Latency
;
1688 /* If the clock time incremented, reduce the latency by that
1689 * much since it's that much closer to the source offset it got
1692 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1693 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1697 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1698 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1699 values
[1] = srcclock
;
1702 /* 1x float/double */
1703 case AL_CONE_INNER_ANGLE
:
1704 case AL_CONE_OUTER_ANGLE
:
1709 case AL_REFERENCE_DISTANCE
:
1710 case AL_ROLLOFF_FACTOR
:
1711 case AL_CONE_OUTER_GAIN
:
1712 case AL_MAX_DISTANCE
:
1714 case AL_SAMPLE_OFFSET
:
1715 case AL_BYTE_OFFSET
:
1716 case AL_DOPPLER_FACTOR
:
1717 case AL_AIR_ABSORPTION_FACTOR
:
1718 case AL_ROOM_ROLLOFF_FACTOR
:
1719 case AL_CONE_OUTER_GAINHF
:
1720 case AL_SEC_LENGTH_SOFT
:
1721 case AL_SOURCE_RADIUS
:
1722 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1723 *values
= (ALint64
)dvals
[0];
1726 /* 3x float/double */
1730 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1732 values
[0] = (ALint64
)dvals
[0];
1733 values
[1] = (ALint64
)dvals
[1];
1734 values
[2] = (ALint64
)dvals
[2];
1738 /* 6x float/double */
1739 case AL_ORIENTATION
:
1740 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1742 values
[0] = (ALint64
)dvals
[0];
1743 values
[1] = (ALint64
)dvals
[1];
1744 values
[2] = (ALint64
)dvals
[2];
1745 values
[3] = (ALint64
)dvals
[3];
1746 values
[4] = (ALint64
)dvals
[4];
1747 values
[5] = (ALint64
)dvals
[5];
1752 case AL_SOURCE_RELATIVE
:
1754 case AL_SOURCE_STATE
:
1755 case AL_BUFFERS_QUEUED
:
1756 case AL_BUFFERS_PROCESSED
:
1757 case AL_BYTE_LENGTH_SOFT
:
1758 case AL_SAMPLE_LENGTH_SOFT
:
1759 case AL_SOURCE_TYPE
:
1760 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1761 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1762 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1763 case AL_DIRECT_CHANNELS_SOFT
:
1764 case AL_DISTANCE_MODEL
:
1765 case AL_SOURCE_RESAMPLER_SOFT
:
1766 case AL_SOURCE_SPATIALIZE_SOFT
:
1767 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1773 case AL_DIRECT_FILTER
:
1774 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1775 *values
= (ALuint
)ivals
[0];
1779 case AL_AUXILIARY_SEND_FILTER
:
1780 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1782 values
[0] = (ALuint
)ivals
[0];
1783 values
[1] = (ALuint
)ivals
[1];
1784 values
[2] = (ALuint
)ivals
[2];
1788 case AL_SEC_OFFSET_LATENCY_SOFT
:
1789 case AL_SEC_OFFSET_CLOCK_SOFT
:
1790 break; /* Double only */
1791 case AL_STEREO_ANGLES
:
1792 break; /* Float/double only */
1795 ERR("Unexpected property: 0x%04x\n", prop
);
1796 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1801 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1803 ALCcontext
*context
;
1806 context
= GetContextRef();
1807 if(!context
) return;
1810 alSetError(context
, AL_INVALID_VALUE
, "Generating %d sources", n
);
1811 else for(cur
= 0;cur
< n
;cur
++)
1813 ALsource
*source
= AllocSource(context
);
1816 alDeleteSources(cur
, sources
);
1819 sources
[cur
] = source
->id
;
1822 ALCcontext_DecRef(context
);
1826 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1828 ALCcontext
*context
;
1832 context
= GetContextRef();
1833 if(!context
) return;
1835 LockSourceList(context
);
1837 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d sources", n
);
1839 /* Check that all Sources are valid */
1840 for(i
= 0;i
< n
;i
++)
1842 if(LookupSource(context
, sources
[i
]) == NULL
)
1843 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
1845 for(i
= 0;i
< n
;i
++)
1847 if((Source
=LookupSource(context
, sources
[i
])) != NULL
)
1848 FreeSource(context
, Source
);
1852 UnlockSourceList(context
);
1853 ALCcontext_DecRef(context
);
1857 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1859 ALCcontext
*context
;
1862 context
= GetContextRef();
1863 if(!context
) return AL_FALSE
;
1865 LockSourceList(context
);
1866 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1867 UnlockSourceList(context
);
1869 ALCcontext_DecRef(context
);
1875 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1877 ALCcontext
*Context
;
1880 Context
= GetContextRef();
1881 if(!Context
) return;
1883 WriteLock(&Context
->PropLock
);
1884 LockSourceList(Context
);
1885 if((Source
=LookupSource(Context
, source
)) == NULL
)
1886 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1887 else if(!(FloatValsByProp(param
) == 1))
1888 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
1890 SetSourcefv(Source
, Context
, param
, &value
);
1891 UnlockSourceList(Context
);
1892 WriteUnlock(&Context
->PropLock
);
1894 ALCcontext_DecRef(Context
);
1897 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1899 ALCcontext
*Context
;
1902 Context
= GetContextRef();
1903 if(!Context
) return;
1905 WriteLock(&Context
->PropLock
);
1906 LockSourceList(Context
);
1907 if((Source
=LookupSource(Context
, source
)) == NULL
)
1908 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1909 else if(!(FloatValsByProp(param
) == 3))
1910 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
1913 ALfloat fvals
[3] = { value1
, value2
, value3
};
1914 SetSourcefv(Source
, Context
, param
, fvals
);
1916 UnlockSourceList(Context
);
1917 WriteUnlock(&Context
->PropLock
);
1919 ALCcontext_DecRef(Context
);
1922 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1924 ALCcontext
*Context
;
1927 Context
= GetContextRef();
1928 if(!Context
) return;
1930 WriteLock(&Context
->PropLock
);
1931 LockSourceList(Context
);
1932 if((Source
=LookupSource(Context
, source
)) == NULL
)
1933 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1935 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1936 else if(!(FloatValsByProp(param
) > 0))
1937 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
1939 SetSourcefv(Source
, Context
, param
, values
);
1940 UnlockSourceList(Context
);
1941 WriteUnlock(&Context
->PropLock
);
1943 ALCcontext_DecRef(Context
);
1947 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1949 ALCcontext
*Context
;
1952 Context
= GetContextRef();
1953 if(!Context
) return;
1955 WriteLock(&Context
->PropLock
);
1956 LockSourceList(Context
);
1957 if((Source
=LookupSource(Context
, source
)) == NULL
)
1958 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1959 else if(!(DoubleValsByProp(param
) == 1))
1960 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
1963 ALfloat fval
= (ALfloat
)value
;
1964 SetSourcefv(Source
, Context
, param
, &fval
);
1966 UnlockSourceList(Context
);
1967 WriteUnlock(&Context
->PropLock
);
1969 ALCcontext_DecRef(Context
);
1972 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1974 ALCcontext
*Context
;
1977 Context
= GetContextRef();
1978 if(!Context
) return;
1980 WriteLock(&Context
->PropLock
);
1981 LockSourceList(Context
);
1982 if((Source
=LookupSource(Context
, source
)) == NULL
)
1983 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1984 else if(!(DoubleValsByProp(param
) == 3))
1985 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
1988 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1989 SetSourcefv(Source
, Context
, param
, fvals
);
1991 UnlockSourceList(Context
);
1992 WriteUnlock(&Context
->PropLock
);
1994 ALCcontext_DecRef(Context
);
1997 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1999 ALCcontext
*Context
;
2003 Context
= GetContextRef();
2004 if(!Context
) return;
2006 WriteLock(&Context
->PropLock
);
2007 LockSourceList(Context
);
2008 if((Source
=LookupSource(Context
, source
)) == NULL
)
2009 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2011 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2012 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
2013 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2019 for(i
= 0;i
< count
;i
++)
2020 fvals
[i
] = (ALfloat
)values
[i
];
2021 SetSourcefv(Source
, Context
, param
, fvals
);
2023 UnlockSourceList(Context
);
2024 WriteUnlock(&Context
->PropLock
);
2026 ALCcontext_DecRef(Context
);
2030 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
2032 ALCcontext
*Context
;
2035 Context
= GetContextRef();
2036 if(!Context
) return;
2038 WriteLock(&Context
->PropLock
);
2039 LockSourceList(Context
);
2040 if((Source
=LookupSource(Context
, source
)) == NULL
)
2041 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2042 else if(!(IntValsByProp(param
) == 1))
2043 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2045 SetSourceiv(Source
, Context
, param
, &value
);
2046 UnlockSourceList(Context
);
2047 WriteUnlock(&Context
->PropLock
);
2049 ALCcontext_DecRef(Context
);
2052 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
2054 ALCcontext
*Context
;
2057 Context
= GetContextRef();
2058 if(!Context
) return;
2060 WriteLock(&Context
->PropLock
);
2061 LockSourceList(Context
);
2062 if((Source
=LookupSource(Context
, source
)) == NULL
)
2063 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2064 else if(!(IntValsByProp(param
) == 3))
2065 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2068 ALint ivals
[3] = { value1
, value2
, value3
};
2069 SetSourceiv(Source
, Context
, param
, ivals
);
2071 UnlockSourceList(Context
);
2072 WriteUnlock(&Context
->PropLock
);
2074 ALCcontext_DecRef(Context
);
2077 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
2079 ALCcontext
*Context
;
2082 Context
= GetContextRef();
2083 if(!Context
) return;
2085 WriteLock(&Context
->PropLock
);
2086 LockSourceList(Context
);
2087 if((Source
=LookupSource(Context
, source
)) == NULL
)
2088 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2090 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2091 else if(!(IntValsByProp(param
) > 0))
2092 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2094 SetSourceiv(Source
, Context
, param
, values
);
2095 UnlockSourceList(Context
);
2096 WriteUnlock(&Context
->PropLock
);
2098 ALCcontext_DecRef(Context
);
2102 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
2104 ALCcontext
*Context
;
2107 Context
= GetContextRef();
2108 if(!Context
) return;
2110 WriteLock(&Context
->PropLock
);
2111 LockSourceList(Context
);
2112 if((Source
=LookupSource(Context
, source
)) == NULL
)
2113 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2114 else if(!(Int64ValsByProp(param
) == 1))
2115 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2117 SetSourcei64v(Source
, Context
, param
, &value
);
2118 UnlockSourceList(Context
);
2119 WriteUnlock(&Context
->PropLock
);
2121 ALCcontext_DecRef(Context
);
2124 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2126 ALCcontext
*Context
;
2129 Context
= GetContextRef();
2130 if(!Context
) return;
2132 WriteLock(&Context
->PropLock
);
2133 LockSourceList(Context
);
2134 if((Source
=LookupSource(Context
, source
)) == NULL
)
2135 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2136 else if(!(Int64ValsByProp(param
) == 3))
2137 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2140 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2141 SetSourcei64v(Source
, Context
, param
, i64vals
);
2143 UnlockSourceList(Context
);
2144 WriteUnlock(&Context
->PropLock
);
2146 ALCcontext_DecRef(Context
);
2149 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2151 ALCcontext
*Context
;
2154 Context
= GetContextRef();
2155 if(!Context
) return;
2157 WriteLock(&Context
->PropLock
);
2158 LockSourceList(Context
);
2159 if((Source
=LookupSource(Context
, source
)) == NULL
)
2160 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2162 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2163 else if(!(Int64ValsByProp(param
) > 0))
2164 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2166 SetSourcei64v(Source
, Context
, param
, values
);
2167 UnlockSourceList(Context
);
2168 WriteUnlock(&Context
->PropLock
);
2170 ALCcontext_DecRef(Context
);
2174 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2176 ALCcontext
*Context
;
2179 Context
= GetContextRef();
2180 if(!Context
) return;
2182 ReadLock(&Context
->PropLock
);
2183 LockSourceList(Context
);
2184 if((Source
=LookupSource(Context
, source
)) == NULL
)
2185 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2187 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2188 else if(!(FloatValsByProp(param
) == 1))
2189 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2193 if(GetSourcedv(Source
, Context
, param
, &dval
))
2194 *value
= (ALfloat
)dval
;
2196 UnlockSourceList(Context
);
2197 ReadUnlock(&Context
->PropLock
);
2199 ALCcontext_DecRef(Context
);
2203 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2205 ALCcontext
*Context
;
2208 Context
= GetContextRef();
2209 if(!Context
) return;
2211 ReadLock(&Context
->PropLock
);
2212 LockSourceList(Context
);
2213 if((Source
=LookupSource(Context
, source
)) == NULL
)
2214 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2215 else if(!(value1
&& value2
&& value3
))
2216 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2217 else if(!(FloatValsByProp(param
) == 3))
2218 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2222 if(GetSourcedv(Source
, Context
, param
, dvals
))
2224 *value1
= (ALfloat
)dvals
[0];
2225 *value2
= (ALfloat
)dvals
[1];
2226 *value3
= (ALfloat
)dvals
[2];
2229 UnlockSourceList(Context
);
2230 ReadUnlock(&Context
->PropLock
);
2232 ALCcontext_DecRef(Context
);
2236 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2238 ALCcontext
*Context
;
2242 Context
= GetContextRef();
2243 if(!Context
) return;
2245 ReadLock(&Context
->PropLock
);
2246 LockSourceList(Context
);
2247 if((Source
=LookupSource(Context
, source
)) == NULL
)
2248 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2250 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2251 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2252 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2256 if(GetSourcedv(Source
, Context
, param
, dvals
))
2259 for(i
= 0;i
< count
;i
++)
2260 values
[i
] = (ALfloat
)dvals
[i
];
2263 UnlockSourceList(Context
);
2264 ReadUnlock(&Context
->PropLock
);
2266 ALCcontext_DecRef(Context
);
2270 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2272 ALCcontext
*Context
;
2275 Context
= GetContextRef();
2276 if(!Context
) return;
2278 ReadLock(&Context
->PropLock
);
2279 LockSourceList(Context
);
2280 if((Source
=LookupSource(Context
, source
)) == NULL
)
2281 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2283 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2284 else if(!(DoubleValsByProp(param
) == 1))
2285 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2287 GetSourcedv(Source
, Context
, param
, value
);
2288 UnlockSourceList(Context
);
2289 ReadUnlock(&Context
->PropLock
);
2291 ALCcontext_DecRef(Context
);
2294 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2296 ALCcontext
*Context
;
2299 Context
= GetContextRef();
2300 if(!Context
) return;
2302 ReadLock(&Context
->PropLock
);
2303 LockSourceList(Context
);
2304 if((Source
=LookupSource(Context
, source
)) == NULL
)
2305 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2306 else if(!(value1
&& value2
&& value3
))
2307 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2308 else if(!(DoubleValsByProp(param
) == 3))
2309 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2313 if(GetSourcedv(Source
, Context
, param
, dvals
))
2320 UnlockSourceList(Context
);
2321 ReadUnlock(&Context
->PropLock
);
2323 ALCcontext_DecRef(Context
);
2326 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2328 ALCcontext
*Context
;
2331 Context
= GetContextRef();
2332 if(!Context
) return;
2334 ReadLock(&Context
->PropLock
);
2335 LockSourceList(Context
);
2336 if((Source
=LookupSource(Context
, source
)) == NULL
)
2337 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2339 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2340 else if(!(DoubleValsByProp(param
) > 0))
2341 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2343 GetSourcedv(Source
, Context
, param
, values
);
2344 UnlockSourceList(Context
);
2345 ReadUnlock(&Context
->PropLock
);
2347 ALCcontext_DecRef(Context
);
2351 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2353 ALCcontext
*Context
;
2356 Context
= GetContextRef();
2357 if(!Context
) return;
2359 ReadLock(&Context
->PropLock
);
2360 LockSourceList(Context
);
2361 if((Source
=LookupSource(Context
, source
)) == NULL
)
2362 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2364 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2365 else if(!(IntValsByProp(param
) == 1))
2366 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2368 GetSourceiv(Source
, Context
, param
, value
);
2369 UnlockSourceList(Context
);
2370 ReadUnlock(&Context
->PropLock
);
2372 ALCcontext_DecRef(Context
);
2376 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2378 ALCcontext
*Context
;
2381 Context
= GetContextRef();
2382 if(!Context
) return;
2384 ReadLock(&Context
->PropLock
);
2385 LockSourceList(Context
);
2386 if((Source
=LookupSource(Context
, source
)) == NULL
)
2387 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2388 else if(!(value1
&& value2
&& value3
))
2389 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2390 else if(!(IntValsByProp(param
) == 3))
2391 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2395 if(GetSourceiv(Source
, Context
, param
, ivals
))
2402 UnlockSourceList(Context
);
2403 ReadUnlock(&Context
->PropLock
);
2405 ALCcontext_DecRef(Context
);
2409 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2411 ALCcontext
*Context
;
2414 Context
= GetContextRef();
2415 if(!Context
) return;
2417 ReadLock(&Context
->PropLock
);
2418 LockSourceList(Context
);
2419 if((Source
=LookupSource(Context
, source
)) == NULL
)
2420 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2422 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2423 else if(!(IntValsByProp(param
) > 0))
2424 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2426 GetSourceiv(Source
, Context
, param
, values
);
2427 UnlockSourceList(Context
);
2428 ReadUnlock(&Context
->PropLock
);
2430 ALCcontext_DecRef(Context
);
2434 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2436 ALCcontext
*Context
;
2439 Context
= GetContextRef();
2440 if(!Context
) return;
2442 ReadLock(&Context
->PropLock
);
2443 LockSourceList(Context
);
2444 if((Source
=LookupSource(Context
, source
)) == NULL
)
2445 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2447 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2448 else if(!(Int64ValsByProp(param
) == 1))
2449 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2451 GetSourcei64v(Source
, Context
, param
, value
);
2452 UnlockSourceList(Context
);
2453 ReadUnlock(&Context
->PropLock
);
2455 ALCcontext_DecRef(Context
);
2458 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2460 ALCcontext
*Context
;
2463 Context
= GetContextRef();
2464 if(!Context
) return;
2466 ReadLock(&Context
->PropLock
);
2467 LockSourceList(Context
);
2468 if((Source
=LookupSource(Context
, source
)) == NULL
)
2469 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2470 else if(!(value1
&& value2
&& value3
))
2471 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2472 else if(!(Int64ValsByProp(param
) == 3))
2473 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2477 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2479 *value1
= i64vals
[0];
2480 *value2
= i64vals
[1];
2481 *value3
= i64vals
[2];
2484 UnlockSourceList(Context
);
2485 ReadUnlock(&Context
->PropLock
);
2487 ALCcontext_DecRef(Context
);
2490 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2492 ALCcontext
*Context
;
2495 Context
= GetContextRef();
2496 if(!Context
) return;
2498 ReadLock(&Context
->PropLock
);
2499 LockSourceList(Context
);
2500 if((Source
=LookupSource(Context
, source
)) == NULL
)
2501 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2503 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2504 else if(!(Int64ValsByProp(param
) > 0))
2505 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2507 GetSourcei64v(Source
, Context
, param
, values
);
2508 UnlockSourceList(Context
);
2509 ReadUnlock(&Context
->PropLock
);
2511 ALCcontext_DecRef(Context
);
2515 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2517 alSourcePlayv(1, &source
);
2519 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2521 ALCcontext
*context
;
2527 context
= GetContextRef();
2528 if(!context
) return;
2530 LockSourceList(context
);
2532 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Playing %d sources", n
);
2533 for(i
= 0;i
< n
;i
++)
2535 if(!LookupSource(context
, sources
[i
]))
2536 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2539 device
= context
->Device
;
2540 ALCdevice_Lock(device
);
2541 /* If the device is disconnected, go right to stopped. */
2542 if(!device
->Connected
)
2544 for(i
= 0;i
< n
;i
++)
2546 source
= LookupSource(context
, sources
[i
]);
2547 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2549 ALCdevice_Unlock(device
);
2553 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2555 ALsizei newcount
= context
->MaxVoices
<< 1;
2556 if(context
->MaxVoices
>= newcount
)
2558 ALCdevice_Unlock(device
);
2559 SETERR_GOTO(context
, AL_OUT_OF_MEMORY
, done
,
2560 "Overflow increasing voice count %d -> %d", context
->MaxVoices
, newcount
);
2562 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2565 for(i
= 0;i
< n
;i
++)
2567 ALbufferlistitem
*BufferList
;
2568 ALbuffer
*buffer
= NULL
;
2569 bool start_fading
= false;
2573 source
= LookupSource(context
, sources
[i
]);
2574 WriteLock(&source
->queue_lock
);
2575 /* Check that there is a queue containing at least one valid, non zero
2578 BufferList
= source
->queue
;
2582 for(b
= 0;b
< BufferList
->num_buffers
;b
++)
2584 buffer
= BufferList
->buffers
[b
];
2585 if(buffer
&& buffer
->SampleLen
> 0) break;
2587 if(buffer
&& buffer
->SampleLen
> 0) break;
2588 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2591 /* If there's nothing to play, go right to stopped. */
2594 /* NOTE: A source without any playable buffers should not have an
2595 * ALvoice since it shouldn't be in a playing or paused state. So
2596 * there's no need to look up its voice and clear the source.
2598 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2599 source
->OffsetType
= AL_NONE
;
2600 source
->Offset
= 0.0;
2604 voice
= GetSourceVoice(source
, context
);
2605 switch(GetSourceState(source
, voice
))
2608 assert(voice
!= NULL
);
2609 /* A source that's already playing is restarted from the beginning. */
2610 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2611 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2612 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2616 assert(voice
!= NULL
);
2617 /* A source that's paused simply resumes. */
2618 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2619 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2626 /* Make sure this source isn't already active, and if not, look for an
2627 * unused voice to put it in.
2629 assert(voice
== NULL
);
2630 for(j
= 0;j
< context
->VoiceCount
;j
++)
2632 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2639 vidx
= context
->VoiceCount
++;
2640 voice
= context
->Voices
[vidx
];
2641 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2643 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2644 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2646 /* A source that's not playing or paused has any offset applied when it
2650 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2652 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2653 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2654 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2655 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2656 if(source
->OffsetType
!= AL_NONE
)
2658 ApplyOffset(source
, voice
);
2659 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2660 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2661 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2664 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2665 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2667 /* Clear previous samples. */
2668 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2670 /* Clear the stepping value so the mixer knows not to mix this until
2671 * the update gets applied.
2675 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2676 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2677 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2678 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2679 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2680 if(device
->AvgSpeakerDist
> 0.0f
)
2682 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2683 (device
->AvgSpeakerDist
* device
->Frequency
);
2684 for(j
= 0;j
< voice
->NumChannels
;j
++)
2686 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2687 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2688 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2692 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2693 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2694 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2695 source
->VoiceIdx
= vidx
;
2697 WriteUnlock(&source
->queue_lock
);
2699 ALCdevice_Unlock(device
);
2702 UnlockSourceList(context
);
2703 ALCcontext_DecRef(context
);
2706 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2708 alSourcePausev(1, &source
);
2710 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2712 ALCcontext
*context
;
2718 context
= GetContextRef();
2719 if(!context
) return;
2721 LockSourceList(context
);
2723 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Pausing %d sources", n
);
2724 for(i
= 0;i
< n
;i
++)
2726 if(!LookupSource(context
, sources
[i
]))
2727 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2730 device
= context
->Device
;
2731 ALCdevice_Lock(device
);
2732 for(i
= 0;i
< n
;i
++)
2734 source
= LookupSource(context
, sources
[i
]);
2735 WriteLock(&source
->queue_lock
);
2736 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2738 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2739 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2742 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2743 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2744 WriteUnlock(&source
->queue_lock
);
2746 ALCdevice_Unlock(device
);
2749 UnlockSourceList(context
);
2750 ALCcontext_DecRef(context
);
2753 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2755 alSourceStopv(1, &source
);
2757 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2759 ALCcontext
*context
;
2765 context
= GetContextRef();
2766 if(!context
) return;
2768 LockSourceList(context
);
2770 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Stopping %d sources", n
);
2771 for(i
= 0;i
< n
;i
++)
2773 if(!LookupSource(context
, sources
[i
]))
2774 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2777 device
= context
->Device
;
2778 ALCdevice_Lock(device
);
2779 for(i
= 0;i
< n
;i
++)
2781 source
= LookupSource(context
, sources
[i
]);
2782 WriteLock(&source
->queue_lock
);
2783 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2785 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2786 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2787 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2790 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2791 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2792 source
->OffsetType
= AL_NONE
;
2793 source
->Offset
= 0.0;
2794 WriteUnlock(&source
->queue_lock
);
2796 ALCdevice_Unlock(device
);
2799 UnlockSourceList(context
);
2800 ALCcontext_DecRef(context
);
2803 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2805 alSourceRewindv(1, &source
);
2807 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2809 ALCcontext
*context
;
2815 context
= GetContextRef();
2816 if(!context
) return;
2818 LockSourceList(context
);
2820 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Rewinding %d sources", n
);
2821 for(i
= 0;i
< n
;i
++)
2823 if(!LookupSource(context
, sources
[i
]))
2824 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2827 device
= context
->Device
;
2828 ALCdevice_Lock(device
);
2829 for(i
= 0;i
< n
;i
++)
2831 source
= LookupSource(context
, sources
[i
]);
2832 WriteLock(&source
->queue_lock
);
2833 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2835 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2836 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2837 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2840 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2841 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2842 source
->OffsetType
= AL_NONE
;
2843 source
->Offset
= 0.0;
2844 WriteUnlock(&source
->queue_lock
);
2846 ALCdevice_Unlock(device
);
2849 UnlockSourceList(context
);
2850 ALCcontext_DecRef(context
);
2854 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2857 ALCcontext
*context
;
2860 ALbufferlistitem
*BufferListStart
;
2861 ALbufferlistitem
*BufferList
;
2862 ALbuffer
*BufferFmt
= NULL
;
2867 context
= GetContextRef();
2868 if(!context
) return;
2870 device
= context
->Device
;
2872 LockSourceList(context
);
2874 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Queueing %d buffers", nb
);
2875 if((source
=LookupSource(context
, src
)) == NULL
)
2876 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2878 WriteLock(&source
->queue_lock
);
2879 if(source
->SourceType
== AL_STATIC
)
2881 WriteUnlock(&source
->queue_lock
);
2882 /* Can't queue on a Static Source */
2883 SETERR_GOTO(context
, AL_INVALID_OPERATION
, done
, "Queueing onto static source %u", src
);
2886 /* Check for a valid Buffer, for its frequency and format */
2887 BufferList
= source
->queue
;
2890 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2892 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2895 if(BufferFmt
) break;
2896 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2899 LockBufferList(device
);
2900 BufferListStart
= NULL
;
2902 for(i
= 0;i
< nb
;i
++)
2904 ALbuffer
*buffer
= NULL
;
2905 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2907 WriteUnlock(&source
->queue_lock
);
2908 SETERR_GOTO(context
, AL_INVALID_NAME
, buffer_error
, "Queueing invalid buffer ID %u",
2912 if(!BufferListStart
)
2914 BufferListStart
= al_calloc(DEF_ALIGN
,
2915 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2916 BufferList
= BufferListStart
;
2920 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
,
2921 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2922 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2925 ATOMIC_INIT(&BufferList
->next
, NULL
);
2926 BufferList
->num_buffers
= 1;
2927 BufferList
->buffers
[0] = buffer
;
2928 if(!buffer
) continue;
2930 /* Hold a read lock on each buffer being queued while checking all
2931 * provided buffers. This is done so other threads don't see an extra
2932 * reference on some buffers if this operation ends up failing. */
2933 ReadLock(&buffer
->lock
);
2934 IncrementRef(&buffer
->ref
);
2936 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2938 WriteUnlock(&source
->queue_lock
);
2939 SETERR_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
,
2940 "Queueing non-persistently mapped buffer %u", buffer
->id
);
2943 if(BufferFmt
== NULL
)
2945 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2946 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2947 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2949 WriteUnlock(&source
->queue_lock
);
2950 alSetError(context
, AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
2953 /* A buffer failed (invalid ID or format), so unlock and release
2954 * each buffer we had. */
2955 while(BufferListStart
)
2957 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2958 almemory_order_relaxed
);
2959 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2961 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2963 DecrementRef(&buffer
->ref
);
2964 ReadUnlock(&buffer
->lock
);
2967 al_free(BufferListStart
);
2968 BufferListStart
= next
;
2970 UnlockBufferList(device
);
2974 /* All buffers good, unlock them now. */
2975 BufferList
= BufferListStart
;
2976 while(BufferList
!= NULL
)
2978 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2980 ALbuffer
*buffer
= BufferList
->buffers
[i
];
2981 if(buffer
) ReadUnlock(&buffer
->lock
);
2983 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2985 UnlockBufferList(device
);
2987 /* Source is now streaming */
2988 source
->SourceType
= AL_STREAMING
;
2990 if(!(BufferList
=source
->queue
))
2991 source
->queue
= BufferListStart
;
2994 ALbufferlistitem
*next
;
2995 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2997 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2999 WriteUnlock(&source
->queue_lock
);
3002 UnlockSourceList(context
);
3003 ALCcontext_DecRef(context
);
3006 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
3008 ALCcontext
*context
;
3010 ALbufferlistitem
*OldHead
;
3011 ALbufferlistitem
*OldTail
;
3012 ALbufferlistitem
*Current
;
3016 context
= GetContextRef();
3017 if(!context
) return;
3019 LockSourceList(context
);
3021 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing %d buffers", nb
);
3022 if((source
=LookupSource(context
, src
)) == NULL
)
3023 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
3025 /* Nothing to unqueue. */
3026 if(nb
== 0) goto done
;
3028 WriteLock(&source
->queue_lock
);
3031 WriteUnlock(&source
->queue_lock
);
3032 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from looping source %u", src
);
3034 if(source
->SourceType
!= AL_STREAMING
)
3036 WriteUnlock(&source
->queue_lock
);
3037 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from a non-streaming source %u",
3041 /* Find the new buffer queue head */
3042 OldTail
= source
->queue
;
3044 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
3045 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
3046 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
3048 if(OldTail
!= Current
&& OldTail
->num_buffers
== 1)
3050 for(i
= 1;i
< nb
;i
++)
3052 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldTail
->next
, almemory_order_relaxed
);
3053 if(!next
|| next
== Current
|| next
->num_buffers
!= 1) break;
3059 WriteUnlock(&source
->queue_lock
);
3060 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
3063 /* Swap it, and cut the new head from the old. */
3064 OldHead
= source
->queue
;
3065 source
->queue
= ATOMIC_EXCHANGE_PTR(&OldTail
->next
, NULL
, almemory_order_acq_rel
);
3066 WriteUnlock(&source
->queue_lock
);
3068 while(OldHead
!= NULL
)
3070 ALbufferlistitem
*next
= ATOMIC_LOAD(&OldHead
->next
, almemory_order_relaxed
);
3071 ALbuffer
*buffer
= OldHead
->buffers
[0];
3077 *(buffers
++) = buffer
->id
;
3078 DecrementRef(&buffer
->ref
);
3086 UnlockSourceList(context
);
3087 ALCcontext_DecRef(context
);
3091 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
3095 RWLockInit(&Source
->queue_lock
);
3097 Source
->InnerAngle
= 360.0f
;
3098 Source
->OuterAngle
= 360.0f
;
3099 Source
->Pitch
= 1.0f
;
3100 Source
->Position
[0] = 0.0f
;
3101 Source
->Position
[1] = 0.0f
;
3102 Source
->Position
[2] = 0.0f
;
3103 Source
->Velocity
[0] = 0.0f
;
3104 Source
->Velocity
[1] = 0.0f
;
3105 Source
->Velocity
[2] = 0.0f
;
3106 Source
->Direction
[0] = 0.0f
;
3107 Source
->Direction
[1] = 0.0f
;
3108 Source
->Direction
[2] = 0.0f
;
3109 Source
->Orientation
[0][0] = 0.0f
;
3110 Source
->Orientation
[0][1] = 0.0f
;
3111 Source
->Orientation
[0][2] = -1.0f
;
3112 Source
->Orientation
[1][0] = 0.0f
;
3113 Source
->Orientation
[1][1] = 1.0f
;
3114 Source
->Orientation
[1][2] = 0.0f
;
3115 Source
->RefDistance
= 1.0f
;
3116 Source
->MaxDistance
= FLT_MAX
;
3117 Source
->RolloffFactor
= 1.0f
;
3118 Source
->Gain
= 1.0f
;
3119 Source
->MinGain
= 0.0f
;
3120 Source
->MaxGain
= 1.0f
;
3121 Source
->OuterGain
= 0.0f
;
3122 Source
->OuterGainHF
= 1.0f
;
3124 Source
->DryGainHFAuto
= AL_TRUE
;
3125 Source
->WetGainAuto
= AL_TRUE
;
3126 Source
->WetGainHFAuto
= AL_TRUE
;
3127 Source
->AirAbsorptionFactor
= 0.0f
;
3128 Source
->RoomRolloffFactor
= 0.0f
;
3129 Source
->DopplerFactor
= 1.0f
;
3130 Source
->HeadRelative
= AL_FALSE
;
3131 Source
->Looping
= AL_FALSE
;
3132 Source
->DistanceModel
= DefaultDistanceModel
;
3133 Source
->Resampler
= ResamplerDefault
;
3134 Source
->DirectChannels
= AL_FALSE
;
3135 Source
->Spatialize
= SpatializeAuto
;
3137 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
3138 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
3140 Source
->Radius
= 0.0f
;
3142 Source
->Direct
.Gain
= 1.0f
;
3143 Source
->Direct
.GainHF
= 1.0f
;
3144 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
3145 Source
->Direct
.GainLF
= 1.0f
;
3146 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
3147 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
3148 for(i
= 0;i
< num_sends
;i
++)
3150 Source
->Send
[i
].Slot
= NULL
;
3151 Source
->Send
[i
].Gain
= 1.0f
;
3152 Source
->Send
[i
].GainHF
= 1.0f
;
3153 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
3154 Source
->Send
[i
].GainLF
= 1.0f
;
3155 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
3158 Source
->Offset
= 0.0;
3159 Source
->OffsetType
= AL_NONE
;
3160 Source
->SourceType
= AL_UNDETERMINED
;
3161 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
3163 Source
->queue
= NULL
;
3165 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3168 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3170 Source
->VoiceIdx
= -1;
3173 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3175 ALbufferlistitem
*BufferList
;
3178 BufferList
= source
->queue
;
3179 while(BufferList
!= NULL
)
3181 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3182 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3184 if(BufferList
->buffers
[i
] != NULL
)
3185 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3187 al_free(BufferList
);
3190 source
->queue
= NULL
;
3194 for(i
= 0;i
< num_sends
;i
++)
3196 if(source
->Send
[i
].Slot
)
3197 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3198 source
->Send
[i
].Slot
= NULL
;
3200 al_free(source
->Send
);
3201 source
->Send
= NULL
;
3205 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3207 struct ALvoiceProps
*props
;
3210 /* Get an unused property container, or allocate a new one as needed. */
3211 props
= ATOMIC_LOAD(&context
->FreeVoiceProps
, almemory_order_acquire
);
3213 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3216 struct ALvoiceProps
*next
;
3218 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3219 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeVoiceProps
, &props
, next
,
3220 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3223 /* Copy in current property values. */
3224 props
->Pitch
= source
->Pitch
;
3225 props
->Gain
= source
->Gain
;
3226 props
->OuterGain
= source
->OuterGain
;
3227 props
->MinGain
= source
->MinGain
;
3228 props
->MaxGain
= source
->MaxGain
;
3229 props
->InnerAngle
= source
->InnerAngle
;
3230 props
->OuterAngle
= source
->OuterAngle
;
3231 props
->RefDistance
= source
->RefDistance
;
3232 props
->MaxDistance
= source
->MaxDistance
;
3233 props
->RolloffFactor
= source
->RolloffFactor
;
3234 for(i
= 0;i
< 3;i
++)
3235 props
->Position
[i
] = source
->Position
[i
];
3236 for(i
= 0;i
< 3;i
++)
3237 props
->Velocity
[i
] = source
->Velocity
[i
];
3238 for(i
= 0;i
< 3;i
++)
3239 props
->Direction
[i
] = source
->Direction
[i
];
3240 for(i
= 0;i
< 2;i
++)
3243 for(j
= 0;j
< 3;j
++)
3244 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3246 props
->HeadRelative
= source
->HeadRelative
;
3247 props
->DistanceModel
= source
->DistanceModel
;
3248 props
->Resampler
= source
->Resampler
;
3249 props
->DirectChannels
= source
->DirectChannels
;
3250 props
->SpatializeMode
= source
->Spatialize
;
3252 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3253 props
->WetGainAuto
= source
->WetGainAuto
;
3254 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3255 props
->OuterGainHF
= source
->OuterGainHF
;
3257 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3258 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3259 props
->DopplerFactor
= source
->DopplerFactor
;
3261 props
->StereoPan
[0] = source
->StereoPan
[0];
3262 props
->StereoPan
[1] = source
->StereoPan
[1];
3264 props
->Radius
= source
->Radius
;
3266 props
->Direct
.Gain
= source
->Direct
.Gain
;
3267 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3268 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3269 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3270 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3272 for(i
= 0;i
< num_sends
;i
++)
3274 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3275 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3276 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3277 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3278 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3279 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3282 /* Set the new container for updating internal parameters. */
3283 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3286 /* If there was an unused update container, put it back in the
3289 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &context
->FreeVoiceProps
, props
);
3293 void UpdateAllSourceProps(ALCcontext
*context
)
3295 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3298 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3300 ALvoice
*voice
= context
->Voices
[pos
];
3301 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3302 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3303 UpdateSourceProps(source
, voice
, num_sends
, context
);
3308 /* GetSourceSampleOffset
3310 * Gets the current read offset for the given Source, in 32.32 fixed-point
3311 * samples. The offset is relative to the start of the queue (not the start of
3312 * the current buffer).
3314 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3316 ALCdevice
*device
= context
->Device
;
3317 const ALbufferlistitem
*Current
;
3322 ReadLock(&Source
->queue_lock
);
3326 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3328 *clocktime
= GetDeviceClockTime(device
);
3330 voice
= GetSourceVoice(Source
, context
);
3333 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3335 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3336 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3339 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3340 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3344 const ALbufferlistitem
*BufferList
= Source
->queue
;
3345 while(BufferList
&& BufferList
!= Current
)
3347 ALsizei max_len
= 0;
3350 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3352 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3353 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3355 readPos
+= (ALuint64
)max_len
<< 32;
3356 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3357 almemory_order_relaxed
);
3359 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3362 ReadUnlock(&Source
->queue_lock
);
3363 return (ALint64
)readPos
;
3366 /* GetSourceSecOffset
3368 * Gets the current read offset for the given Source, in seconds. The offset is
3369 * relative to the start of the queue (not the start of the current buffer).
3371 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3373 ALCdevice
*device
= context
->Device
;
3374 const ALbufferlistitem
*Current
;
3380 ReadLock(&Source
->queue_lock
);
3384 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3386 *clocktime
= GetDeviceClockTime(device
);
3388 voice
= GetSourceVoice(Source
, context
);
3391 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3393 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3395 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3397 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3398 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3403 const ALbufferlistitem
*BufferList
= Source
->queue
;
3404 const ALbuffer
*BufferFmt
= NULL
;
3405 while(BufferList
&& BufferList
!= Current
)
3407 ALsizei max_len
= 0;
3410 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3412 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3415 if(!BufferFmt
) BufferFmt
= buffer
;
3416 max_len
= maxi(max_len
, buffer
->SampleLen
);
3419 readPos
+= (ALuint64
)max_len
<< FRACTIONBITS
;
3420 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3421 almemory_order_relaxed
);
3424 while(BufferList
&& !BufferFmt
)
3427 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3428 BufferFmt
= BufferList
->buffers
[i
];
3429 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3430 almemory_order_relaxed
);
3432 assert(BufferFmt
!= NULL
);
3434 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3435 (ALdouble
)BufferFmt
->Frequency
;
3438 ReadUnlock(&Source
->queue_lock
);
3444 * Gets the current read offset for the given Source, in the appropriate format
3445 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3446 * queue (not the start of the current buffer).
3448 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3450 ALCdevice
*device
= context
->Device
;
3451 const ALbufferlistitem
*Current
;
3453 ALsizei readPosFrac
;
3458 ReadLock(&Source
->queue_lock
);
3461 readPos
= readPosFrac
= 0;
3462 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3464 voice
= GetSourceVoice(Source
, context
);
3467 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3469 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3470 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3472 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3473 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3478 const ALbufferlistitem
*BufferList
= Source
->queue
;
3479 const ALbuffer
*BufferFmt
= NULL
;
3480 ALboolean readFin
= AL_FALSE
;
3481 ALuint totalBufferLen
= 0;
3483 while(BufferList
!= NULL
)
3485 ALsizei max_len
= 0;
3488 readFin
= readFin
|| (BufferList
== Current
);
3489 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3491 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3494 if(!BufferFmt
) BufferFmt
= buffer
;
3495 max_len
= maxi(max_len
, buffer
->SampleLen
);
3498 totalBufferLen
+= max_len
;
3499 if(!readFin
) readPos
+= max_len
;
3501 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3502 almemory_order_relaxed
);
3504 assert(BufferFmt
!= NULL
);
3507 readPos
%= totalBufferLen
;
3510 /* Wrap back to 0 */
3511 if(readPos
>= totalBufferLen
)
3512 readPos
= readPosFrac
= 0;
3519 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3522 case AL_SAMPLE_OFFSET
:
3523 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3526 case AL_BYTE_OFFSET
:
3527 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3529 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3530 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3531 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3533 /* Round down to nearest ADPCM block */
3534 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3536 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3538 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3539 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3540 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3542 /* Round down to nearest ADPCM block */
3543 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3547 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
3548 BufferFmt
->FmtType
);
3549 offset
= (ALdouble
)(readPos
* FrameSize
);
3555 ReadUnlock(&Source
->queue_lock
);
3562 * Apply the stored playback offset to the Source. This function will update
3563 * the number of buffers "played" given the stored offset.
3565 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3567 ALbufferlistitem
*BufferList
;
3568 ALuint bufferLen
, totalBufferLen
;
3572 /* Get sample frame offset */
3573 if(!GetSampleOffset(Source
, &offset
, &frac
))
3577 BufferList
= Source
->queue
;
3578 while(BufferList
&& totalBufferLen
<= offset
)
3580 ALsizei max_len
= 0;
3583 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3585 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3586 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3588 bufferLen
= max_len
;
3590 if(bufferLen
> offset
-totalBufferLen
)
3592 /* Offset is in this buffer */
3593 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3594 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3595 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3599 totalBufferLen
+= bufferLen
;
3601 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3604 /* Offset is out of range of the queue */
3611 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3612 * or Second offset supplied by the application). This takes into account the
3613 * fact that the buffer format may have been modifed since.
3615 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3617 const ALbuffer
*BufferFmt
= NULL
;
3618 const ALbufferlistitem
*BufferList
;
3619 ALdouble dbloff
, dblfrac
;
3621 /* Find the first valid Buffer in the Queue */
3622 BufferList
= Source
->queue
;
3626 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3627 BufferFmt
= BufferList
->buffers
[i
];
3628 if(BufferFmt
) break;
3629 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3630 almemory_order_relaxed
);
3634 Source
->OffsetType
= AL_NONE
;
3635 Source
->Offset
= 0.0;
3639 switch(Source
->OffsetType
)
3641 case AL_BYTE_OFFSET
:
3642 /* Determine the ByteOffset (and ensure it is block aligned) */
3643 *offset
= (ALuint
)Source
->Offset
;
3644 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3646 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3647 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3648 *offset
*= BufferFmt
->OriginalAlign
;
3650 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3652 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3653 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3654 *offset
*= BufferFmt
->OriginalAlign
;
3657 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
3661 case AL_SAMPLE_OFFSET
:
3662 dblfrac
= modf(Source
->Offset
, &dbloff
);
3663 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3664 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3668 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3669 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3670 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3673 Source
->OffsetType
= AL_NONE
;
3674 Source
->Offset
= 0.0;
3680 static ALsource
*AllocSource(ALCcontext
*context
)
3682 ALCdevice
*device
= context
->Device
;
3683 SourceSubList
*sublist
, *subend
;
3684 ALsource
*source
= NULL
;
3688 almtx_lock(&context
->SourceLock
);
3689 if(context
->NumSources
>= device
->SourcesMax
)
3691 almtx_unlock(&context
->SourceLock
);
3692 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
3695 sublist
= VECTOR_BEGIN(context
->SourceList
);
3696 subend
= VECTOR_END(context
->SourceList
);
3697 for(;sublist
!= subend
;++sublist
)
3699 if(sublist
->FreeMask
)
3701 slidx
= CTZ64(sublist
->FreeMask
);
3702 source
= sublist
->Sources
+ slidx
;
3707 if(UNLIKELY(!source
))
3709 const SourceSubList empty_sublist
= { 0, NULL
};
3710 /* Don't allocate so many list entries that the 32-bit ID could
3713 if(UNLIKELY(VECTOR_SIZE(context
->SourceList
) >= 1<<25))
3715 almtx_unlock(&device
->BufferLock
);
3716 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
3719 lidx
= (ALsizei
)VECTOR_SIZE(context
->SourceList
);
3720 VECTOR_PUSH_BACK(context
->SourceList
, empty_sublist
);
3721 sublist
= &VECTOR_BACK(context
->SourceList
);
3722 sublist
->FreeMask
= ~U64(0);
3723 sublist
->Sources
= al_calloc(16, sizeof(ALsource
)*64);
3724 if(UNLIKELY(!sublist
->Sources
))
3726 VECTOR_POP_BACK(context
->SourceList
);
3727 almtx_unlock(&context
->SourceLock
);
3728 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
3733 source
= sublist
->Sources
+ slidx
;
3736 memset(source
, 0, sizeof(*source
));
3737 InitSourceParams(source
, device
->NumAuxSends
);
3739 /* Add 1 to avoid source ID 0. */
3740 source
->id
= ((lidx
<<6) | slidx
) + 1;
3742 context
->NumSources
++;
3743 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
3744 almtx_unlock(&context
->SourceLock
);
3749 static void FreeSource(ALCcontext
*context
, ALsource
*source
)
3751 ALCdevice
*device
= context
->Device
;
3752 ALuint id
= source
->id
- 1;
3753 ALsizei lidx
= id
>> 6;
3754 ALsizei slidx
= id
& 0x3f;
3757 ALCdevice_Lock(device
);
3758 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
3760 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
3761 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3763 ALCdevice_Unlock(device
);
3765 DeinitSource(source
, device
->NumAuxSends
);
3766 memset(source
, 0, sizeof(*source
));
3768 VECTOR_ELEM(context
->SourceList
, lidx
).FreeMask
|= U64(1) << slidx
;
3769 context
->NumSources
--;
3774 * Destroys all sources in the source map.
3776 ALvoid
ReleaseALSources(ALCcontext
*context
)
3778 ALCdevice
*device
= context
->Device
;
3779 SourceSubList
*sublist
= VECTOR_BEGIN(context
->SourceList
);
3780 SourceSubList
*subend
= VECTOR_END(context
->SourceList
);
3781 size_t leftover
= 0;
3782 for(;sublist
!= subend
;++sublist
)
3784 ALuint64 usemask
= ~sublist
->FreeMask
;
3787 ALsizei idx
= CTZ64(usemask
);
3788 ALsource
*source
= sublist
->Sources
+ idx
;
3790 DeinitSource(source
, device
->NumAuxSends
);
3791 memset(source
, 0, sizeof(*source
));
3794 usemask
&= ~(U64(1) << idx
);
3796 sublist
->FreeMask
= ~usemask
;
3799 WARN("(%p) Deleted "SZFMT
" Source%s\n", device
, leftover
, (leftover
==1)?"":"s");