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
34 #include "alcontext.h"
39 #include "alAuxEffectSlot.h"
40 #include "ringbuffer.h"
42 #include "backends/base.h"
48 static ALsource
*AllocSource(ALCcontext
*context
);
49 static void FreeSource(ALCcontext
*context
, ALsource
*source
);
50 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
51 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
52 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
);
53 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
54 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
56 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
);
57 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
);
59 static inline void LockSourceList(ALCcontext
*context
)
60 { almtx_lock(&context
->SourceLock
); }
61 static inline void UnlockSourceList(ALCcontext
*context
)
62 { almtx_unlock(&context
->SourceLock
); }
64 static inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
)
66 ALuint lidx
= (id
-1) >> 6;
67 ALsizei slidx
= (id
-1) & 0x3f;
69 if(UNLIKELY(lidx
>= context
->SourceList
.size()))
71 SourceSubList
&sublist
{context
->SourceList
[lidx
]};
72 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
74 return sublist
.Sources
+ slidx
;
77 static inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
)
79 ALuint lidx
= (id
-1) >> 6;
80 ALsizei slidx
= (id
-1) & 0x3f;
82 if(UNLIKELY(lidx
>= device
->BufferList
.size()))
84 BufferSubList
&sublist
= device
->BufferList
[lidx
];
85 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
87 return sublist
.Buffers
+ slidx
;
90 static inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
)
92 ALuint lidx
= (id
-1) >> 6;
93 ALsizei slidx
= (id
-1) & 0x3f;
95 if(UNLIKELY(lidx
>= device
->FilterList
.size()))
97 FilterSubList
&sublist
= device
->FilterList
[lidx
];
98 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
100 return sublist
.Filters
+ slidx
;
103 static inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
)
106 if(UNLIKELY(id
>= context
->EffectSlotList
.size()))
108 return context
->EffectSlotList
[id
];
112 typedef enum SourceProp
{
115 srcMinGain
= AL_MIN_GAIN
,
116 srcMaxGain
= AL_MAX_GAIN
,
117 srcMaxDistance
= AL_MAX_DISTANCE
,
118 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
119 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
120 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
121 srcSecOffset
= AL_SEC_OFFSET
,
122 srcSampleOffset
= AL_SAMPLE_OFFSET
,
123 srcByteOffset
= AL_BYTE_OFFSET
,
124 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
125 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
126 srcRefDistance
= AL_REFERENCE_DISTANCE
,
128 srcPosition
= AL_POSITION
,
129 srcVelocity
= AL_VELOCITY
,
130 srcDirection
= AL_DIRECTION
,
132 srcSourceRelative
= AL_SOURCE_RELATIVE
,
133 srcLooping
= AL_LOOPING
,
134 srcBuffer
= AL_BUFFER
,
135 srcSourceState
= AL_SOURCE_STATE
,
136 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
137 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
138 srcSourceType
= AL_SOURCE_TYPE
,
141 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
142 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
143 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
144 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
145 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
146 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
147 srcDirectFilter
= AL_DIRECT_FILTER
,
148 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
150 /* AL_SOFT_direct_channels */
151 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
153 /* AL_EXT_source_distance_model */
154 srcDistanceModel
= AL_DISTANCE_MODEL
,
156 /* AL_SOFT_source_latency */
157 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
158 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
160 /* AL_EXT_STEREO_ANGLES */
161 srcAngles
= AL_STEREO_ANGLES
,
163 /* AL_EXT_SOURCE_RADIUS */
164 srcRadius
= AL_SOURCE_RADIUS
,
167 srcOrientation
= AL_ORIENTATION
,
169 /* AL_SOFT_source_resampler */
170 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
172 /* AL_SOFT_source_spatialize */
173 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
175 /* ALC_SOFT_device_clock */
176 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
177 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
180 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
181 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
182 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
184 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
185 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
186 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
188 static inline ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
190 ALint idx
= source
->VoiceIdx
;
191 if(idx
>= 0 && idx
< context
->VoiceCount
)
193 ALvoice
*voice
= context
->Voices
[idx
];
194 if(ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
) == source
)
197 source
->VoiceIdx
= -1;
202 * Returns if the last known state for the source was playing or paused. Does
203 * not sync with the mixer voice.
205 static inline bool IsPlayingOrPaused(ALsource
*source
)
206 { return source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
; }
209 * Returns an updated source state using the matching voice's status (or lack
212 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
214 if(!voice
&& source
->state
== AL_PLAYING
)
215 source
->state
= AL_STOPPED
;
216 return source
->state
;
220 * Returns if the source should specify an update, given the context's
221 * deferring state and the source's last known state.
223 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
225 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
226 IsPlayingOrPaused(source
);
230 /** Can only be called while the mixer is locked! */
231 static void SendStateChangeEvent(ALCcontext
*context
, ALuint id
, ALenum state
)
233 AsyncEvent evt
= ASYNC_EVENT(EventType_SourceStateChange
);
234 ALbitfieldSOFT enabledevt
;
236 enabledevt
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_acquire
);
237 if(!(enabledevt
&EventType_SourceStateChange
)) return;
239 evt
.u
.user
.type
= AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
;
241 evt
.u
.user
.param
= state
;
242 snprintf(evt
.u
.user
.msg
, sizeof(evt
.u
.user
.msg
), "Source ID %u state changed to %s", id
,
243 (state
==AL_INITIAL
) ? "AL_INITIAL" :
244 (state
==AL_PLAYING
) ? "AL_PLAYING" :
245 (state
==AL_PAUSED
) ? "AL_PAUSED" :
246 (state
==AL_STOPPED
) ? "AL_STOPPED" : "<unknown>"
248 /* The mixer may have queued a state change that's not yet been processed,
249 * and we don't want state change messages to occur out of order, so send
250 * it through the async queue to ensure proper ordering.
252 if(ll_ringbuffer_write(context
->AsyncEvents
, (const char*)&evt
, 1) == 1)
253 alsem_post(&context
->EventSem
);
257 static ALint
FloatValsByProp(ALenum prop
)
259 if(prop
!= (ALenum
)((SourceProp
)prop
))
261 switch((SourceProp
)prop
)
267 case AL_MAX_DISTANCE
:
268 case AL_ROLLOFF_FACTOR
:
269 case AL_DOPPLER_FACTOR
:
270 case AL_CONE_OUTER_GAIN
:
272 case AL_SAMPLE_OFFSET
:
274 case AL_CONE_INNER_ANGLE
:
275 case AL_CONE_OUTER_ANGLE
:
276 case AL_REFERENCE_DISTANCE
:
277 case AL_CONE_OUTER_GAINHF
:
278 case AL_AIR_ABSORPTION_FACTOR
:
279 case AL_ROOM_ROLLOFF_FACTOR
:
280 case AL_DIRECT_FILTER_GAINHF_AUTO
:
281 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
282 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
283 case AL_DIRECT_CHANNELS_SOFT
:
284 case AL_DISTANCE_MODEL
:
285 case AL_SOURCE_RELATIVE
:
287 case AL_SOURCE_STATE
:
288 case AL_BUFFERS_QUEUED
:
289 case AL_BUFFERS_PROCESSED
:
291 case AL_SOURCE_RADIUS
:
292 case AL_SOURCE_RESAMPLER_SOFT
:
293 case AL_SOURCE_SPATIALIZE_SOFT
:
296 case AL_STEREO_ANGLES
:
307 case AL_SEC_OFFSET_LATENCY_SOFT
:
308 case AL_SEC_OFFSET_CLOCK_SOFT
:
309 break; /* Double only */
312 case AL_DIRECT_FILTER
:
313 case AL_AUXILIARY_SEND_FILTER
:
314 break; /* i/i64 only */
315 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
316 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
317 break; /* i64 only */
321 static ALint
DoubleValsByProp(ALenum prop
)
323 if(prop
!= (ALenum
)((SourceProp
)prop
))
325 switch((SourceProp
)prop
)
331 case AL_MAX_DISTANCE
:
332 case AL_ROLLOFF_FACTOR
:
333 case AL_DOPPLER_FACTOR
:
334 case AL_CONE_OUTER_GAIN
:
336 case AL_SAMPLE_OFFSET
:
338 case AL_CONE_INNER_ANGLE
:
339 case AL_CONE_OUTER_ANGLE
:
340 case AL_REFERENCE_DISTANCE
:
341 case AL_CONE_OUTER_GAINHF
:
342 case AL_AIR_ABSORPTION_FACTOR
:
343 case AL_ROOM_ROLLOFF_FACTOR
:
344 case AL_DIRECT_FILTER_GAINHF_AUTO
:
345 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
346 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
347 case AL_DIRECT_CHANNELS_SOFT
:
348 case AL_DISTANCE_MODEL
:
349 case AL_SOURCE_RELATIVE
:
351 case AL_SOURCE_STATE
:
352 case AL_BUFFERS_QUEUED
:
353 case AL_BUFFERS_PROCESSED
:
355 case AL_SOURCE_RADIUS
:
356 case AL_SOURCE_RESAMPLER_SOFT
:
357 case AL_SOURCE_SPATIALIZE_SOFT
:
360 case AL_SEC_OFFSET_LATENCY_SOFT
:
361 case AL_SEC_OFFSET_CLOCK_SOFT
:
362 case AL_STEREO_ANGLES
:
374 case AL_DIRECT_FILTER
:
375 case AL_AUXILIARY_SEND_FILTER
:
376 break; /* i/i64 only */
377 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
378 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
379 break; /* i64 only */
384 static ALint
IntValsByProp(ALenum prop
)
386 if(prop
!= (ALenum
)((SourceProp
)prop
))
388 switch((SourceProp
)prop
)
394 case AL_MAX_DISTANCE
:
395 case AL_ROLLOFF_FACTOR
:
396 case AL_DOPPLER_FACTOR
:
397 case AL_CONE_OUTER_GAIN
:
399 case AL_SAMPLE_OFFSET
:
401 case AL_CONE_INNER_ANGLE
:
402 case AL_CONE_OUTER_ANGLE
:
403 case AL_REFERENCE_DISTANCE
:
404 case AL_CONE_OUTER_GAINHF
:
405 case AL_AIR_ABSORPTION_FACTOR
:
406 case AL_ROOM_ROLLOFF_FACTOR
:
407 case AL_DIRECT_FILTER_GAINHF_AUTO
:
408 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
409 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
410 case AL_DIRECT_CHANNELS_SOFT
:
411 case AL_DISTANCE_MODEL
:
412 case AL_SOURCE_RELATIVE
:
415 case AL_SOURCE_STATE
:
416 case AL_BUFFERS_QUEUED
:
417 case AL_BUFFERS_PROCESSED
:
419 case AL_DIRECT_FILTER
:
420 case AL_SOURCE_RADIUS
:
421 case AL_SOURCE_RESAMPLER_SOFT
:
422 case AL_SOURCE_SPATIALIZE_SOFT
:
428 case AL_AUXILIARY_SEND_FILTER
:
434 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
435 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
436 break; /* i64 only */
437 case AL_SEC_OFFSET_LATENCY_SOFT
:
438 case AL_SEC_OFFSET_CLOCK_SOFT
:
439 break; /* Double only */
440 case AL_STEREO_ANGLES
:
441 break; /* Float/double only */
445 static ALint
Int64ValsByProp(ALenum prop
)
447 if(prop
!= (ALenum
)((SourceProp
)prop
))
449 switch((SourceProp
)prop
)
455 case AL_MAX_DISTANCE
:
456 case AL_ROLLOFF_FACTOR
:
457 case AL_DOPPLER_FACTOR
:
458 case AL_CONE_OUTER_GAIN
:
460 case AL_SAMPLE_OFFSET
:
462 case AL_CONE_INNER_ANGLE
:
463 case AL_CONE_OUTER_ANGLE
:
464 case AL_REFERENCE_DISTANCE
:
465 case AL_CONE_OUTER_GAINHF
:
466 case AL_AIR_ABSORPTION_FACTOR
:
467 case AL_ROOM_ROLLOFF_FACTOR
:
468 case AL_DIRECT_FILTER_GAINHF_AUTO
:
469 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
470 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
471 case AL_DIRECT_CHANNELS_SOFT
:
472 case AL_DISTANCE_MODEL
:
473 case AL_SOURCE_RELATIVE
:
476 case AL_SOURCE_STATE
:
477 case AL_BUFFERS_QUEUED
:
478 case AL_BUFFERS_PROCESSED
:
480 case AL_DIRECT_FILTER
:
481 case AL_SOURCE_RADIUS
:
482 case AL_SOURCE_RESAMPLER_SOFT
:
483 case AL_SOURCE_SPATIALIZE_SOFT
:
486 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
487 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
493 case AL_AUXILIARY_SEND_FILTER
:
499 case AL_SEC_OFFSET_LATENCY_SOFT
:
500 case AL_SEC_OFFSET_CLOCK_SOFT
:
501 break; /* Double only */
502 case AL_STEREO_ANGLES
:
503 break; /* Float/double only */
509 #define CHECKVAL(x) do { \
512 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
517 #define DO_UPDATEPROPS() do { \
519 if(SourceShouldUpdate(Source, Context) && \
520 (voice=GetSourceVoice(Source, Context)) != NULL) \
521 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
523 ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \
526 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
528 ALCdevice
*device
= Context
->Device
;
533 case AL_SEC_OFFSET_LATENCY_SOFT
:
534 case AL_SEC_OFFSET_CLOCK_SOFT
:
536 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
537 "Setting read-only source property 0x%04x", prop
);
540 CHECKVAL(*values
>= 0.0f
);
542 Source
->Pitch
= *values
;
546 case AL_CONE_INNER_ANGLE
:
547 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
549 Source
->InnerAngle
= *values
;
553 case AL_CONE_OUTER_ANGLE
:
554 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
556 Source
->OuterAngle
= *values
;
561 CHECKVAL(*values
>= 0.0f
);
563 Source
->Gain
= *values
;
567 case AL_MAX_DISTANCE
:
568 CHECKVAL(*values
>= 0.0f
);
570 Source
->MaxDistance
= *values
;
574 case AL_ROLLOFF_FACTOR
:
575 CHECKVAL(*values
>= 0.0f
);
577 Source
->RolloffFactor
= *values
;
581 case AL_REFERENCE_DISTANCE
:
582 CHECKVAL(*values
>= 0.0f
);
584 Source
->RefDistance
= *values
;
589 CHECKVAL(*values
>= 0.0f
);
591 Source
->MinGain
= *values
;
596 CHECKVAL(*values
>= 0.0f
);
598 Source
->MaxGain
= *values
;
602 case AL_CONE_OUTER_GAIN
:
603 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
605 Source
->OuterGain
= *values
;
609 case AL_CONE_OUTER_GAINHF
:
610 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
612 Source
->OuterGainHF
= *values
;
616 case AL_AIR_ABSORPTION_FACTOR
:
617 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
619 Source
->AirAbsorptionFactor
= *values
;
623 case AL_ROOM_ROLLOFF_FACTOR
:
624 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
626 Source
->RoomRolloffFactor
= *values
;
630 case AL_DOPPLER_FACTOR
:
631 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
633 Source
->DopplerFactor
= *values
;
638 case AL_SAMPLE_OFFSET
:
640 CHECKVAL(*values
>= 0.0f
);
642 Source
->OffsetType
= prop
;
643 Source
->Offset
= *values
;
645 if(IsPlayingOrPaused(Source
))
649 ALCdevice_Lock(Context
->Device
);
650 /* Double-check that the source is still playing while we have
653 voice
= GetSourceVoice(Source
, Context
);
656 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
658 ALCdevice_Unlock(Context
->Device
);
659 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid offset");
662 ALCdevice_Unlock(Context
->Device
);
666 case AL_SOURCE_RADIUS
:
667 CHECKVAL(*values
>= 0.0f
&& std::isfinite(*values
));
669 Source
->Radius
= *values
;
673 case AL_STEREO_ANGLES
:
674 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]));
676 Source
->StereoPan
[0] = values
[0];
677 Source
->StereoPan
[1] = values
[1];
683 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
685 Source
->Position
[0] = values
[0];
686 Source
->Position
[1] = values
[1];
687 Source
->Position
[2] = values
[2];
692 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
694 Source
->Velocity
[0] = values
[0];
695 Source
->Velocity
[1] = values
[1];
696 Source
->Velocity
[2] = values
[2];
701 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
703 Source
->Direction
[0] = values
[0];
704 Source
->Direction
[1] = values
[1];
705 Source
->Direction
[2] = values
[2];
710 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
711 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5]));
713 Source
->Orientation
[0][0] = values
[0];
714 Source
->Orientation
[0][1] = values
[1];
715 Source
->Orientation
[0][2] = values
[2];
716 Source
->Orientation
[1][0] = values
[3];
717 Source
->Orientation
[1][1] = values
[4];
718 Source
->Orientation
[1][2] = values
[5];
723 case AL_SOURCE_RELATIVE
:
725 case AL_SOURCE_STATE
:
727 case AL_DISTANCE_MODEL
:
728 case AL_DIRECT_FILTER_GAINHF_AUTO
:
729 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
730 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
731 case AL_DIRECT_CHANNELS_SOFT
:
732 case AL_SOURCE_RESAMPLER_SOFT
:
733 case AL_SOURCE_SPATIALIZE_SOFT
:
734 ival
= (ALint
)values
[0];
735 return SetSourceiv(Source
, Context
, prop
, &ival
);
737 case AL_BUFFERS_QUEUED
:
738 case AL_BUFFERS_PROCESSED
:
739 ival
= (ALint
)((ALuint
)values
[0]);
740 return SetSourceiv(Source
, Context
, prop
, &ival
);
743 case AL_DIRECT_FILTER
:
744 case AL_AUXILIARY_SEND_FILTER
:
745 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
746 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
750 ERR("Unexpected property: 0x%04x\n", prop
);
751 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source float property 0x%04x", prop
);
754 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
756 ALCdevice
*device
= Context
->Device
;
757 ALbuffer
*buffer
= NULL
;
758 ALfilter
*filter
= NULL
;
759 ALeffectslot
*slot
= NULL
;
760 ALbufferlistitem
*oldlist
;
765 case AL_SOURCE_STATE
:
767 case AL_BUFFERS_QUEUED
:
768 case AL_BUFFERS_PROCESSED
:
770 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
771 "Setting read-only source property 0x%04x", prop
);
773 case AL_SOURCE_RELATIVE
:
774 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
776 Source
->HeadRelative
= (ALboolean
)*values
;
781 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
783 Source
->Looping
= (ALboolean
)*values
;
784 if(IsPlayingOrPaused(Source
))
786 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
790 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
792 ATOMIC_STORE(&voice
->loop_buffer
, static_cast<ALbufferlistitem
*>(nullptr),
793 almemory_order_release
);
795 /* If the source is playing, wait for the current mix to finish
796 * to ensure it isn't currently looping back or reaching the
799 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
806 LockBufferList(device
);
807 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
809 UnlockBufferList(device
);
810 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
814 if(buffer
&& buffer
->MappedAccess
!= 0 &&
815 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
817 UnlockBufferList(device
);
818 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
819 "Setting non-persistently mapped buffer %u", buffer
->id
);
823 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
824 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
826 UnlockBufferList(device
);
827 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
828 "Setting buffer on playing or paused source %u", Source
->id
);
832 oldlist
= Source
->queue
;
835 /* Add the selected buffer to a one-item queue */
836 ALbufferlistitem
*newlist
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
837 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
838 ATOMIC_INIT(&newlist
->next
, static_cast<ALbufferlistitem
*>(nullptr));
839 newlist
->max_samples
= buffer
->SampleLen
;
840 newlist
->num_buffers
= 1;
841 newlist
->buffers
[0] = buffer
;
842 IncrementRef(&buffer
->ref
);
844 /* Source is now Static */
845 Source
->SourceType
= AL_STATIC
;
846 Source
->queue
= newlist
;
850 /* Source is now Undetermined */
851 Source
->SourceType
= AL_UNDETERMINED
;
852 Source
->queue
= NULL
;
854 UnlockBufferList(device
);
856 /* Delete all elements in the previous queue */
857 while(oldlist
!= NULL
)
860 ALbufferlistitem
*temp
= oldlist
;
861 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
863 for(i
= 0;i
< temp
->num_buffers
;i
++)
866 DecrementRef(&temp
->buffers
[i
]->ref
);
873 case AL_SAMPLE_OFFSET
:
875 CHECKVAL(*values
>= 0);
877 Source
->OffsetType
= prop
;
878 Source
->Offset
= *values
;
880 if(IsPlayingOrPaused(Source
))
884 ALCdevice_Lock(Context
->Device
);
885 voice
= GetSourceVoice(Source
, Context
);
888 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
890 ALCdevice_Unlock(Context
->Device
);
891 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
892 "Invalid source offset");
895 ALCdevice_Unlock(Context
->Device
);
899 case AL_DIRECT_FILTER
:
900 LockFilterList(device
);
901 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
903 UnlockFilterList(device
);
904 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
910 Source
->Direct
.Gain
= 1.0f
;
911 Source
->Direct
.GainHF
= 1.0f
;
912 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
913 Source
->Direct
.GainLF
= 1.0f
;
914 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
918 Source
->Direct
.Gain
= filter
->Gain
;
919 Source
->Direct
.GainHF
= filter
->GainHF
;
920 Source
->Direct
.HFReference
= filter
->HFReference
;
921 Source
->Direct
.GainLF
= filter
->GainLF
;
922 Source
->Direct
.LFReference
= filter
->LFReference
;
924 UnlockFilterList(device
);
928 case AL_DIRECT_FILTER_GAINHF_AUTO
:
929 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
931 Source
->DryGainHFAuto
= *values
;
935 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
936 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
938 Source
->WetGainAuto
= *values
;
942 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
943 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
945 Source
->WetGainHFAuto
= *values
;
949 case AL_DIRECT_CHANNELS_SOFT
:
950 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
952 Source
->DirectChannels
= *values
;
956 case AL_DISTANCE_MODEL
:
957 CHECKVAL(*values
== AL_NONE
||
958 *values
== AL_INVERSE_DISTANCE
||
959 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
960 *values
== AL_LINEAR_DISTANCE
||
961 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
962 *values
== AL_EXPONENT_DISTANCE
||
963 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
965 Source
->mDistanceModel
= static_cast<DistanceModel
>(*values
);
966 if(Context
->SourceDistanceModel
)
970 case AL_SOURCE_RESAMPLER_SOFT
:
971 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
973 Source
->Resampler
= static_cast<enum Resampler
>(*values
);
977 case AL_SOURCE_SPATIALIZE_SOFT
:
978 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
980 Source
->Spatialize
= static_cast<enum SpatializeMode
>(*values
);
985 case AL_AUXILIARY_SEND_FILTER
:
986 LockEffectSlotList(Context
);
987 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
))
989 UnlockEffectSlotList(Context
);
990 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
993 if((ALuint
)values
[1] >= (ALuint
)device
->NumAuxSends
)
995 UnlockEffectSlotList(Context
);
996 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
998 LockFilterList(device
);
999 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
))
1001 UnlockFilterList(device
);
1002 UnlockEffectSlotList(Context
);
1003 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1009 /* Disable filter */
1010 Source
->Send
[values
[1]].Gain
= 1.0f
;
1011 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1012 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1013 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1014 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1018 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1019 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1020 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1021 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1022 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1024 UnlockFilterList(device
);
1026 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1029 /* Add refcount on the new slot, and release the previous slot */
1030 if(slot
) IncrementRef(&slot
->ref
);
1031 if(Source
->Send
[values
[1]].Slot
)
1032 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1033 Source
->Send
[values
[1]].Slot
= slot
;
1035 /* We must force an update if the auxiliary slot changed on an
1036 * active source, in case the slot is about to be deleted.
1038 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1039 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
1041 ATOMIC_STORE(&Source
->PropsClean
, AL_FALSE
, almemory_order_release
);
1045 if(slot
) IncrementRef(&slot
->ref
);
1046 if(Source
->Send
[values
[1]].Slot
)
1047 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1048 Source
->Send
[values
[1]].Slot
= slot
;
1051 UnlockEffectSlotList(Context
);
1057 case AL_CONE_INNER_ANGLE
:
1058 case AL_CONE_OUTER_ANGLE
:
1063 case AL_REFERENCE_DISTANCE
:
1064 case AL_ROLLOFF_FACTOR
:
1065 case AL_CONE_OUTER_GAIN
:
1066 case AL_MAX_DISTANCE
:
1067 case AL_DOPPLER_FACTOR
:
1068 case AL_CONE_OUTER_GAINHF
:
1069 case AL_AIR_ABSORPTION_FACTOR
:
1070 case AL_ROOM_ROLLOFF_FACTOR
:
1071 case AL_SOURCE_RADIUS
:
1072 fvals
[0] = (ALfloat
)*values
;
1073 return SetSourcefv(Source
, Context
, prop
, fvals
);
1079 fvals
[0] = (ALfloat
)values
[0];
1080 fvals
[1] = (ALfloat
)values
[1];
1081 fvals
[2] = (ALfloat
)values
[2];
1082 return SetSourcefv(Source
, Context
, prop
, fvals
);
1085 case AL_ORIENTATION
:
1086 fvals
[0] = (ALfloat
)values
[0];
1087 fvals
[1] = (ALfloat
)values
[1];
1088 fvals
[2] = (ALfloat
)values
[2];
1089 fvals
[3] = (ALfloat
)values
[3];
1090 fvals
[4] = (ALfloat
)values
[4];
1091 fvals
[5] = (ALfloat
)values
[5];
1092 return SetSourcefv(Source
, Context
, prop
, fvals
);
1094 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1095 case AL_SEC_OFFSET_LATENCY_SOFT
:
1096 case AL_SEC_OFFSET_CLOCK_SOFT
:
1097 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1098 case AL_STEREO_ANGLES
:
1102 ERR("Unexpected property: 0x%04x\n", prop
);
1103 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1107 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1114 case AL_SOURCE_TYPE
:
1115 case AL_BUFFERS_QUEUED
:
1116 case AL_BUFFERS_PROCESSED
:
1117 case AL_SOURCE_STATE
:
1118 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1119 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1121 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1122 "Setting read-only source property 0x%04x", prop
);
1125 case AL_SOURCE_RELATIVE
:
1128 case AL_SAMPLE_OFFSET
:
1129 case AL_BYTE_OFFSET
:
1130 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1131 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1132 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1133 case AL_DIRECT_CHANNELS_SOFT
:
1134 case AL_DISTANCE_MODEL
:
1135 case AL_SOURCE_RESAMPLER_SOFT
:
1136 case AL_SOURCE_SPATIALIZE_SOFT
:
1137 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1139 ivals
[0] = (ALint
)*values
;
1140 return SetSourceiv(Source
, Context
, prop
, ivals
);
1144 case AL_DIRECT_FILTER
:
1145 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1147 ivals
[0] = (ALuint
)*values
;
1148 return SetSourceiv(Source
, Context
, prop
, ivals
);
1151 case AL_AUXILIARY_SEND_FILTER
:
1152 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1153 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1154 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1156 ivals
[0] = (ALuint
)values
[0];
1157 ivals
[1] = (ALuint
)values
[1];
1158 ivals
[2] = (ALuint
)values
[2];
1159 return SetSourceiv(Source
, Context
, prop
, ivals
);
1162 case AL_CONE_INNER_ANGLE
:
1163 case AL_CONE_OUTER_ANGLE
:
1168 case AL_REFERENCE_DISTANCE
:
1169 case AL_ROLLOFF_FACTOR
:
1170 case AL_CONE_OUTER_GAIN
:
1171 case AL_MAX_DISTANCE
:
1172 case AL_DOPPLER_FACTOR
:
1173 case AL_CONE_OUTER_GAINHF
:
1174 case AL_AIR_ABSORPTION_FACTOR
:
1175 case AL_ROOM_ROLLOFF_FACTOR
:
1176 case AL_SOURCE_RADIUS
:
1177 fvals
[0] = (ALfloat
)*values
;
1178 return SetSourcefv(Source
, Context
, prop
, fvals
);
1184 fvals
[0] = (ALfloat
)values
[0];
1185 fvals
[1] = (ALfloat
)values
[1];
1186 fvals
[2] = (ALfloat
)values
[2];
1187 return SetSourcefv(Source
, Context
, prop
, fvals
);
1190 case AL_ORIENTATION
:
1191 fvals
[0] = (ALfloat
)values
[0];
1192 fvals
[1] = (ALfloat
)values
[1];
1193 fvals
[2] = (ALfloat
)values
[2];
1194 fvals
[3] = (ALfloat
)values
[3];
1195 fvals
[4] = (ALfloat
)values
[4];
1196 fvals
[5] = (ALfloat
)values
[5];
1197 return SetSourcefv(Source
, Context
, prop
, fvals
);
1199 case AL_SEC_OFFSET_LATENCY_SOFT
:
1200 case AL_SEC_OFFSET_CLOCK_SOFT
:
1201 case AL_STEREO_ANGLES
:
1205 ERR("Unexpected property: 0x%04x\n", prop
);
1206 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1213 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1215 ALCdevice
*device
= Context
->Device
;
1216 ClockLatency clocktime
;
1224 *values
= Source
->Gain
;
1228 *values
= Source
->Pitch
;
1231 case AL_MAX_DISTANCE
:
1232 *values
= Source
->MaxDistance
;
1235 case AL_ROLLOFF_FACTOR
:
1236 *values
= Source
->RolloffFactor
;
1239 case AL_REFERENCE_DISTANCE
:
1240 *values
= Source
->RefDistance
;
1243 case AL_CONE_INNER_ANGLE
:
1244 *values
= Source
->InnerAngle
;
1247 case AL_CONE_OUTER_ANGLE
:
1248 *values
= Source
->OuterAngle
;
1252 *values
= Source
->MinGain
;
1256 *values
= Source
->MaxGain
;
1259 case AL_CONE_OUTER_GAIN
:
1260 *values
= Source
->OuterGain
;
1264 case AL_SAMPLE_OFFSET
:
1265 case AL_BYTE_OFFSET
:
1266 *values
= GetSourceOffset(Source
, prop
, Context
);
1269 case AL_CONE_OUTER_GAINHF
:
1270 *values
= Source
->OuterGainHF
;
1273 case AL_AIR_ABSORPTION_FACTOR
:
1274 *values
= Source
->AirAbsorptionFactor
;
1277 case AL_ROOM_ROLLOFF_FACTOR
:
1278 *values
= Source
->RoomRolloffFactor
;
1281 case AL_DOPPLER_FACTOR
:
1282 *values
= Source
->DopplerFactor
;
1285 case AL_SOURCE_RADIUS
:
1286 *values
= Source
->Radius
;
1289 case AL_STEREO_ANGLES
:
1290 values
[0] = Source
->StereoPan
[0];
1291 values
[1] = Source
->StereoPan
[1];
1294 case AL_SEC_OFFSET_LATENCY_SOFT
:
1295 /* Get the source offset with the clock time first. Then get the
1296 * clock time with the device latency. Order is important.
1298 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1299 almtx_lock(&device
->BackendLock
);
1300 clocktime
= GetClockLatency(device
);
1301 almtx_unlock(&device
->BackendLock
);
1302 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1303 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1306 /* If the clock time incremented, reduce the latency by that
1307 * much since it's that much closer to the source offset it got
1310 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1311 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1316 case AL_SEC_OFFSET_CLOCK_SOFT
:
1317 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1318 values
[1] = srcclock
/ 1000000000.0;
1322 values
[0] = Source
->Position
[0];
1323 values
[1] = Source
->Position
[1];
1324 values
[2] = Source
->Position
[2];
1328 values
[0] = Source
->Velocity
[0];
1329 values
[1] = Source
->Velocity
[1];
1330 values
[2] = Source
->Velocity
[2];
1334 values
[0] = Source
->Direction
[0];
1335 values
[1] = Source
->Direction
[1];
1336 values
[2] = Source
->Direction
[2];
1339 case AL_ORIENTATION
:
1340 values
[0] = Source
->Orientation
[0][0];
1341 values
[1] = Source
->Orientation
[0][1];
1342 values
[2] = Source
->Orientation
[0][2];
1343 values
[3] = Source
->Orientation
[1][0];
1344 values
[4] = Source
->Orientation
[1][1];
1345 values
[5] = Source
->Orientation
[1][2];
1349 case AL_SOURCE_RELATIVE
:
1351 case AL_SOURCE_STATE
:
1352 case AL_BUFFERS_QUEUED
:
1353 case AL_BUFFERS_PROCESSED
:
1354 case AL_SOURCE_TYPE
:
1355 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1356 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1357 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1358 case AL_DIRECT_CHANNELS_SOFT
:
1359 case AL_DISTANCE_MODEL
:
1360 case AL_SOURCE_RESAMPLER_SOFT
:
1361 case AL_SOURCE_SPATIALIZE_SOFT
:
1362 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1363 *values
= (ALdouble
)ivals
[0];
1367 case AL_DIRECT_FILTER
:
1368 case AL_AUXILIARY_SEND_FILTER
:
1369 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1370 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1374 ERR("Unexpected property: 0x%04x\n", prop
);
1375 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1379 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1381 ALbufferlistitem
*BufferList
;
1387 case AL_SOURCE_RELATIVE
:
1388 *values
= Source
->HeadRelative
;
1392 *values
= Source
->Looping
;
1396 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1397 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1398 BufferList
->buffers
[0]->id
: 0;
1401 case AL_SOURCE_STATE
:
1402 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1405 case AL_BUFFERS_QUEUED
:
1406 if(!(BufferList
=Source
->queue
))
1412 count
+= BufferList
->num_buffers
;
1413 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1414 } while(BufferList
!= NULL
);
1419 case AL_BUFFERS_PROCESSED
:
1420 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1422 /* Buffers on a looping source are in a perpetual state of
1423 * PENDING, so don't report any as PROCESSED */
1428 const ALbufferlistitem
*BufferList
= Source
->queue
;
1429 const ALbufferlistitem
*Current
= NULL
;
1433 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1434 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
1435 else if(Source
->state
== AL_INITIAL
)
1436 Current
= BufferList
;
1438 while(BufferList
&& BufferList
!= Current
)
1440 played
+= BufferList
->num_buffers
;
1441 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
1447 case AL_SOURCE_TYPE
:
1448 *values
= Source
->SourceType
;
1451 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1452 *values
= Source
->DryGainHFAuto
;
1455 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1456 *values
= Source
->WetGainAuto
;
1459 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1460 *values
= Source
->WetGainHFAuto
;
1463 case AL_DIRECT_CHANNELS_SOFT
:
1464 *values
= Source
->DirectChannels
;
1467 case AL_DISTANCE_MODEL
:
1468 *values
= static_cast<int>(Source
->mDistanceModel
);
1471 case AL_SOURCE_RESAMPLER_SOFT
:
1472 *values
= Source
->Resampler
;
1475 case AL_SOURCE_SPATIALIZE_SOFT
:
1476 *values
= Source
->Spatialize
;
1479 /* 1x float/double */
1480 case AL_CONE_INNER_ANGLE
:
1481 case AL_CONE_OUTER_ANGLE
:
1486 case AL_REFERENCE_DISTANCE
:
1487 case AL_ROLLOFF_FACTOR
:
1488 case AL_CONE_OUTER_GAIN
:
1489 case AL_MAX_DISTANCE
:
1491 case AL_SAMPLE_OFFSET
:
1492 case AL_BYTE_OFFSET
:
1493 case AL_DOPPLER_FACTOR
:
1494 case AL_AIR_ABSORPTION_FACTOR
:
1495 case AL_ROOM_ROLLOFF_FACTOR
:
1496 case AL_CONE_OUTER_GAINHF
:
1497 case AL_SOURCE_RADIUS
:
1498 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1499 *values
= (ALint
)dvals
[0];
1502 /* 3x float/double */
1506 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1508 values
[0] = (ALint
)dvals
[0];
1509 values
[1] = (ALint
)dvals
[1];
1510 values
[2] = (ALint
)dvals
[2];
1514 /* 6x float/double */
1515 case AL_ORIENTATION
:
1516 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1518 values
[0] = (ALint
)dvals
[0];
1519 values
[1] = (ALint
)dvals
[1];
1520 values
[2] = (ALint
)dvals
[2];
1521 values
[3] = (ALint
)dvals
[3];
1522 values
[4] = (ALint
)dvals
[4];
1523 values
[5] = (ALint
)dvals
[5];
1527 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1528 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1529 break; /* i64 only */
1530 case AL_SEC_OFFSET_LATENCY_SOFT
:
1531 case AL_SEC_OFFSET_CLOCK_SOFT
:
1532 break; /* Double only */
1533 case AL_STEREO_ANGLES
:
1534 break; /* Float/double only */
1536 case AL_DIRECT_FILTER
:
1537 case AL_AUXILIARY_SEND_FILTER
:
1541 ERR("Unexpected property: 0x%04x\n", prop
);
1542 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1546 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1548 ALCdevice
*device
= Context
->Device
;
1549 ClockLatency clocktime
;
1557 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1558 /* Get the source offset with the clock time first. Then get the
1559 * clock time with the device latency. Order is important.
1561 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1562 almtx_lock(&device
->BackendLock
);
1563 clocktime
= GetClockLatency(device
);
1564 almtx_unlock(&device
->BackendLock
);
1565 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1566 values
[1] = clocktime
.Latency
;
1569 /* If the clock time incremented, reduce the latency by that
1570 * much since it's that much closer to the source offset it got
1573 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1574 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1578 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1579 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1580 values
[1] = srcclock
;
1583 /* 1x float/double */
1584 case AL_CONE_INNER_ANGLE
:
1585 case AL_CONE_OUTER_ANGLE
:
1590 case AL_REFERENCE_DISTANCE
:
1591 case AL_ROLLOFF_FACTOR
:
1592 case AL_CONE_OUTER_GAIN
:
1593 case AL_MAX_DISTANCE
:
1595 case AL_SAMPLE_OFFSET
:
1596 case AL_BYTE_OFFSET
:
1597 case AL_DOPPLER_FACTOR
:
1598 case AL_AIR_ABSORPTION_FACTOR
:
1599 case AL_ROOM_ROLLOFF_FACTOR
:
1600 case AL_CONE_OUTER_GAINHF
:
1601 case AL_SOURCE_RADIUS
:
1602 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1603 *values
= (ALint64
)dvals
[0];
1606 /* 3x float/double */
1610 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1612 values
[0] = (ALint64
)dvals
[0];
1613 values
[1] = (ALint64
)dvals
[1];
1614 values
[2] = (ALint64
)dvals
[2];
1618 /* 6x float/double */
1619 case AL_ORIENTATION
:
1620 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1622 values
[0] = (ALint64
)dvals
[0];
1623 values
[1] = (ALint64
)dvals
[1];
1624 values
[2] = (ALint64
)dvals
[2];
1625 values
[3] = (ALint64
)dvals
[3];
1626 values
[4] = (ALint64
)dvals
[4];
1627 values
[5] = (ALint64
)dvals
[5];
1632 case AL_SOURCE_RELATIVE
:
1634 case AL_SOURCE_STATE
:
1635 case AL_BUFFERS_QUEUED
:
1636 case AL_BUFFERS_PROCESSED
:
1637 case AL_SOURCE_TYPE
:
1638 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1639 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1640 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1641 case AL_DIRECT_CHANNELS_SOFT
:
1642 case AL_DISTANCE_MODEL
:
1643 case AL_SOURCE_RESAMPLER_SOFT
:
1644 case AL_SOURCE_SPATIALIZE_SOFT
:
1645 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1651 case AL_DIRECT_FILTER
:
1652 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1653 *values
= (ALuint
)ivals
[0];
1657 case AL_AUXILIARY_SEND_FILTER
:
1658 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1660 values
[0] = (ALuint
)ivals
[0];
1661 values
[1] = (ALuint
)ivals
[1];
1662 values
[2] = (ALuint
)ivals
[2];
1666 case AL_SEC_OFFSET_LATENCY_SOFT
:
1667 case AL_SEC_OFFSET_CLOCK_SOFT
:
1668 break; /* Double only */
1669 case AL_STEREO_ANGLES
:
1670 break; /* Float/double only */
1673 ERR("Unexpected property: 0x%04x\n", prop
);
1674 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1679 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1681 ALCcontext
*context
;
1684 context
= GetContextRef();
1685 if(!context
) return;
1688 alSetError(context
, AL_INVALID_VALUE
, "Generating %d sources", n
);
1689 else for(cur
= 0;cur
< n
;cur
++)
1691 ALsource
*source
= AllocSource(context
);
1694 alDeleteSources(cur
, sources
);
1697 sources
[cur
] = source
->id
;
1700 ALCcontext_DecRef(context
);
1704 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1706 ALCcontext
*context
;
1710 context
= GetContextRef();
1711 if(!context
) return;
1713 LockSourceList(context
);
1715 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d sources", n
);
1717 /* Check that all Sources are valid */
1718 for(i
= 0;i
< n
;i
++)
1720 if(LookupSource(context
, sources
[i
]) == NULL
)
1721 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
1723 for(i
= 0;i
< n
;i
++)
1725 if((Source
=LookupSource(context
, sources
[i
])) != NULL
)
1726 FreeSource(context
, Source
);
1730 UnlockSourceList(context
);
1731 ALCcontext_DecRef(context
);
1735 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1737 ALCcontext
*context
;
1740 context
= GetContextRef();
1741 if(!context
) return AL_FALSE
;
1743 LockSourceList(context
);
1744 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1745 UnlockSourceList(context
);
1747 ALCcontext_DecRef(context
);
1753 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1755 ALCcontext
*Context
;
1758 Context
= GetContextRef();
1759 if(!Context
) return;
1761 almtx_lock(&Context
->PropLock
);
1762 LockSourceList(Context
);
1763 if((Source
=LookupSource(Context
, source
)) == NULL
)
1764 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1765 else if(FloatValsByProp(param
) != 1)
1766 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
1768 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), &value
);
1769 UnlockSourceList(Context
);
1770 almtx_unlock(&Context
->PropLock
);
1772 ALCcontext_DecRef(Context
);
1775 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1777 ALCcontext
*Context
;
1780 Context
= GetContextRef();
1781 if(!Context
) return;
1783 almtx_lock(&Context
->PropLock
);
1784 LockSourceList(Context
);
1785 if((Source
=LookupSource(Context
, source
)) == NULL
)
1786 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1787 else if(FloatValsByProp(param
) != 3)
1788 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
1791 ALfloat fvals
[3] = { value1
, value2
, value3
};
1792 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), fvals
);
1794 UnlockSourceList(Context
);
1795 almtx_unlock(&Context
->PropLock
);
1797 ALCcontext_DecRef(Context
);
1800 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1802 ALCcontext
*Context
;
1805 Context
= GetContextRef();
1806 if(!Context
) return;
1808 almtx_lock(&Context
->PropLock
);
1809 LockSourceList(Context
);
1810 if((Source
=LookupSource(Context
, source
)) == NULL
)
1811 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1813 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1814 else if(FloatValsByProp(param
) < 1)
1815 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
1817 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), values
);
1818 UnlockSourceList(Context
);
1819 almtx_unlock(&Context
->PropLock
);
1821 ALCcontext_DecRef(Context
);
1825 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1827 ALCcontext
*Context
;
1830 Context
= GetContextRef();
1831 if(!Context
) return;
1833 almtx_lock(&Context
->PropLock
);
1834 LockSourceList(Context
);
1835 if((Source
=LookupSource(Context
, source
)) == NULL
)
1836 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1837 else if(DoubleValsByProp(param
) != 1)
1838 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
1841 ALfloat fval
= (ALfloat
)value
;
1842 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), &fval
);
1844 UnlockSourceList(Context
);
1845 almtx_unlock(&Context
->PropLock
);
1847 ALCcontext_DecRef(Context
);
1850 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1852 ALCcontext
*Context
;
1855 Context
= GetContextRef();
1856 if(!Context
) return;
1858 almtx_lock(&Context
->PropLock
);
1859 LockSourceList(Context
);
1860 if((Source
=LookupSource(Context
, source
)) == NULL
)
1861 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1862 else if(DoubleValsByProp(param
) != 3)
1863 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
1866 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1867 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), fvals
);
1869 UnlockSourceList(Context
);
1870 almtx_unlock(&Context
->PropLock
);
1872 ALCcontext_DecRef(Context
);
1875 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1877 ALCcontext
*Context
;
1881 Context
= GetContextRef();
1882 if(!Context
) return;
1884 almtx_lock(&Context
->PropLock
);
1885 LockSourceList(Context
);
1886 if((Source
=LookupSource(Context
, source
)) == NULL
)
1887 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1889 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1890 else if((count
=DoubleValsByProp(param
)) < 1 || count
> 6)
1891 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
1897 for(i
= 0;i
< count
;i
++)
1898 fvals
[i
] = (ALfloat
)values
[i
];
1899 SetSourcefv(Source
, Context
, static_cast<SourceProp
>(param
), fvals
);
1901 UnlockSourceList(Context
);
1902 almtx_unlock(&Context
->PropLock
);
1904 ALCcontext_DecRef(Context
);
1908 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1910 ALCcontext
*Context
;
1913 Context
= GetContextRef();
1914 if(!Context
) return;
1916 almtx_lock(&Context
->PropLock
);
1917 LockSourceList(Context
);
1918 if((Source
=LookupSource(Context
, source
)) == NULL
)
1919 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1920 else if(IntValsByProp(param
) != 1)
1921 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
1923 SetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), &value
);
1924 UnlockSourceList(Context
);
1925 almtx_unlock(&Context
->PropLock
);
1927 ALCcontext_DecRef(Context
);
1930 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1932 ALCcontext
*Context
;
1935 Context
= GetContextRef();
1936 if(!Context
) return;
1938 almtx_lock(&Context
->PropLock
);
1939 LockSourceList(Context
);
1940 if((Source
=LookupSource(Context
, source
)) == NULL
)
1941 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1942 else if(IntValsByProp(param
) != 3)
1943 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
1946 ALint ivals
[3] = { value1
, value2
, value3
};
1947 SetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), ivals
);
1949 UnlockSourceList(Context
);
1950 almtx_unlock(&Context
->PropLock
);
1952 ALCcontext_DecRef(Context
);
1955 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1957 ALCcontext
*Context
;
1960 Context
= GetContextRef();
1961 if(!Context
) return;
1963 almtx_lock(&Context
->PropLock
);
1964 LockSourceList(Context
);
1965 if((Source
=LookupSource(Context
, source
)) == NULL
)
1966 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1968 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1969 else if(IntValsByProp(param
) < 1)
1970 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
1972 SetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), values
);
1973 UnlockSourceList(Context
);
1974 almtx_unlock(&Context
->PropLock
);
1976 ALCcontext_DecRef(Context
);
1980 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1982 ALCcontext
*Context
;
1985 Context
= GetContextRef();
1986 if(!Context
) return;
1988 almtx_lock(&Context
->PropLock
);
1989 LockSourceList(Context
);
1990 if((Source
=LookupSource(Context
, source
)) == NULL
)
1991 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1992 else if(Int64ValsByProp(param
) != 1)
1993 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
1995 SetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), &value
);
1996 UnlockSourceList(Context
);
1997 almtx_unlock(&Context
->PropLock
);
1999 ALCcontext_DecRef(Context
);
2002 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2004 ALCcontext
*Context
;
2007 Context
= GetContextRef();
2008 if(!Context
) return;
2010 almtx_lock(&Context
->PropLock
);
2011 LockSourceList(Context
);
2012 if((Source
=LookupSource(Context
, source
)) == NULL
)
2013 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2014 else if(Int64ValsByProp(param
) != 3)
2015 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2018 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2019 SetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), i64vals
);
2021 UnlockSourceList(Context
);
2022 almtx_unlock(&Context
->PropLock
);
2024 ALCcontext_DecRef(Context
);
2027 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2029 ALCcontext
*Context
;
2032 Context
= GetContextRef();
2033 if(!Context
) return;
2035 almtx_lock(&Context
->PropLock
);
2036 LockSourceList(Context
);
2037 if((Source
=LookupSource(Context
, source
)) == NULL
)
2038 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2040 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2041 else if(Int64ValsByProp(param
) < 1)
2042 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2044 SetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), values
);
2045 UnlockSourceList(Context
);
2046 almtx_unlock(&Context
->PropLock
);
2048 ALCcontext_DecRef(Context
);
2052 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2054 ALCcontext
*Context
;
2057 Context
= GetContextRef();
2058 if(!Context
) return;
2060 LockSourceList(Context
);
2061 if((Source
=LookupSource(Context
, source
)) == NULL
)
2062 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2064 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2065 else if(FloatValsByProp(param
) != 1)
2066 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2070 if(GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), &dval
))
2071 *value
= (ALfloat
)dval
;
2073 UnlockSourceList(Context
);
2075 ALCcontext_DecRef(Context
);
2079 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2081 ALCcontext
*Context
;
2084 Context
= GetContextRef();
2085 if(!Context
) return;
2087 LockSourceList(Context
);
2088 if((Source
=LookupSource(Context
, source
)) == NULL
)
2089 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2090 else if(!(value1
&& value2
&& value3
))
2091 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2092 else if(FloatValsByProp(param
) != 3)
2093 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2097 if(GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), dvals
))
2099 *value1
= (ALfloat
)dvals
[0];
2100 *value2
= (ALfloat
)dvals
[1];
2101 *value3
= (ALfloat
)dvals
[2];
2104 UnlockSourceList(Context
);
2106 ALCcontext_DecRef(Context
);
2110 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2112 ALCcontext
*Context
;
2116 Context
= GetContextRef();
2117 if(!Context
) return;
2119 LockSourceList(Context
);
2120 if((Source
=LookupSource(Context
, source
)) == NULL
)
2121 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2123 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2124 else if((count
=FloatValsByProp(param
)) < 1 && count
> 6)
2125 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2129 if(GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), dvals
))
2132 for(i
= 0;i
< count
;i
++)
2133 values
[i
] = (ALfloat
)dvals
[i
];
2136 UnlockSourceList(Context
);
2138 ALCcontext_DecRef(Context
);
2142 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2144 ALCcontext
*Context
;
2147 Context
= GetContextRef();
2148 if(!Context
) return;
2150 LockSourceList(Context
);
2151 if((Source
=LookupSource(Context
, source
)) == NULL
)
2152 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2154 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2155 else if(DoubleValsByProp(param
) != 1)
2156 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2158 GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), value
);
2159 UnlockSourceList(Context
);
2161 ALCcontext_DecRef(Context
);
2164 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2166 ALCcontext
*Context
;
2169 Context
= GetContextRef();
2170 if(!Context
) return;
2172 LockSourceList(Context
);
2173 if((Source
=LookupSource(Context
, source
)) == NULL
)
2174 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2175 else if(!(value1
&& value2
&& value3
))
2176 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2177 else if(DoubleValsByProp(param
) != 3)
2178 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2182 if(GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), dvals
))
2189 UnlockSourceList(Context
);
2191 ALCcontext_DecRef(Context
);
2194 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2196 ALCcontext
*Context
;
2199 Context
= GetContextRef();
2200 if(!Context
) return;
2202 LockSourceList(Context
);
2203 if((Source
=LookupSource(Context
, source
)) == NULL
)
2204 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2206 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2207 else if(DoubleValsByProp(param
) < 1)
2208 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2210 GetSourcedv(Source
, Context
, static_cast<SourceProp
>(param
), values
);
2211 UnlockSourceList(Context
);
2213 ALCcontext_DecRef(Context
);
2217 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2219 ALCcontext
*Context
;
2222 Context
= GetContextRef();
2223 if(!Context
) return;
2225 LockSourceList(Context
);
2226 if((Source
=LookupSource(Context
, source
)) == NULL
)
2227 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2229 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2230 else if(IntValsByProp(param
) != 1)
2231 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2233 GetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), value
);
2234 UnlockSourceList(Context
);
2236 ALCcontext_DecRef(Context
);
2240 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2242 ALCcontext
*Context
;
2245 Context
= GetContextRef();
2246 if(!Context
) return;
2248 LockSourceList(Context
);
2249 if((Source
=LookupSource(Context
, source
)) == NULL
)
2250 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2251 else if(!(value1
&& value2
&& value3
))
2252 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2253 else if(IntValsByProp(param
) != 3)
2254 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2258 if(GetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), ivals
))
2265 UnlockSourceList(Context
);
2267 ALCcontext_DecRef(Context
);
2271 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2273 ALCcontext
*Context
;
2276 Context
= GetContextRef();
2277 if(!Context
) return;
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(IntValsByProp(param
) < 1)
2285 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2287 GetSourceiv(Source
, Context
, static_cast<SourceProp
>(param
), values
);
2288 UnlockSourceList(Context
);
2290 ALCcontext_DecRef(Context
);
2294 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2296 ALCcontext
*Context
;
2299 Context
= GetContextRef();
2300 if(!Context
) return;
2302 LockSourceList(Context
);
2303 if((Source
=LookupSource(Context
, source
)) == NULL
)
2304 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2306 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2307 else if(Int64ValsByProp(param
) != 1)
2308 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2310 GetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), value
);
2311 UnlockSourceList(Context
);
2313 ALCcontext_DecRef(Context
);
2316 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2318 ALCcontext
*Context
;
2321 Context
= GetContextRef();
2322 if(!Context
) return;
2324 LockSourceList(Context
);
2325 if((Source
=LookupSource(Context
, source
)) == NULL
)
2326 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2327 else if(!(value1
&& value2
&& value3
))
2328 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2329 else if(Int64ValsByProp(param
) != 3)
2330 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2334 if(GetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), i64vals
))
2336 *value1
= i64vals
[0];
2337 *value2
= i64vals
[1];
2338 *value3
= i64vals
[2];
2341 UnlockSourceList(Context
);
2343 ALCcontext_DecRef(Context
);
2346 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2348 ALCcontext
*Context
;
2351 Context
= GetContextRef();
2352 if(!Context
) return;
2354 LockSourceList(Context
);
2355 if((Source
=LookupSource(Context
, source
)) == NULL
)
2356 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2358 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2359 else if(Int64ValsByProp(param
) < 1)
2360 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2362 GetSourcei64v(Source
, Context
, static_cast<SourceProp
>(param
), values
);
2363 UnlockSourceList(Context
);
2365 ALCcontext_DecRef(Context
);
2369 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2371 alSourcePlayv(1, &source
);
2373 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2375 ALCcontext
*context
;
2381 context
= GetContextRef();
2382 if(!context
) return;
2384 LockSourceList(context
);
2386 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Playing %d sources", n
);
2387 for(i
= 0;i
< n
;i
++)
2389 if(!LookupSource(context
, sources
[i
]))
2390 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2393 device
= context
->Device
;
2394 ALCdevice_Lock(device
);
2395 /* If the device is disconnected, go right to stopped. */
2396 if(!ATOMIC_LOAD(&device
->Connected
, almemory_order_acquire
))
2398 /* TODO: Send state change event? */
2399 for(i
= 0;i
< n
;i
++)
2401 source
= LookupSource(context
, sources
[i
]);
2402 source
->OffsetType
= AL_NONE
;
2403 source
->Offset
= 0.0;
2404 source
->state
= AL_STOPPED
;
2406 ALCdevice_Unlock(device
);
2410 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2412 ALsizei newcount
= context
->MaxVoices
<< 1;
2413 if(context
->MaxVoices
>= newcount
)
2415 ALCdevice_Unlock(device
);
2416 SETERR_GOTO(context
, AL_OUT_OF_MEMORY
, done
,
2417 "Overflow increasing voice count %d -> %d", context
->MaxVoices
, newcount
);
2419 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2422 for(i
= 0;i
< n
;i
++)
2424 ALbufferlistitem
*BufferList
;
2425 bool start_fading
= false;
2428 source
= LookupSource(context
, sources
[i
]);
2429 /* Check that there is a queue containing at least one valid, non zero
2432 BufferList
= source
->queue
;
2433 while(BufferList
&& BufferList
->max_samples
== 0)
2434 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2436 /* If there's nothing to play, go right to stopped. */
2437 if(UNLIKELY(!BufferList
))
2439 /* NOTE: A source without any playable buffers should not have an
2440 * ALvoice since it shouldn't be in a playing or paused state. So
2441 * there's no need to look up its voice and clear the source.
2443 ALenum oldstate
= GetSourceState(source
, NULL
);
2444 source
->OffsetType
= AL_NONE
;
2445 source
->Offset
= 0.0;
2446 if(oldstate
!= AL_STOPPED
)
2448 source
->state
= AL_STOPPED
;
2449 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2454 voice
= GetSourceVoice(source
, context
);
2455 switch(GetSourceState(source
, voice
))
2458 assert(voice
!= NULL
);
2459 /* A source that's already playing is restarted from the beginning. */
2460 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2461 ATOMIC_STORE(&voice
->position
, 0u, almemory_order_relaxed
);
2462 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2466 assert(voice
!= NULL
);
2467 /* A source that's paused simply resumes. */
2468 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2469 source
->state
= AL_PLAYING
;
2470 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2477 /* Look for an unused voice to play this source with. */
2478 assert(voice
== NULL
);
2479 for(j
= 0;j
< context
->VoiceCount
;j
++)
2481 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2488 vidx
= context
->VoiceCount
++;
2489 voice
= context
->Voices
[vidx
];
2490 voice
->Playing
.store(false, std::memory_order_release
);
2492 source
->PropsClean
.exchange(AL_TRUE
, std::memory_order_acquire
);
2493 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2495 /* A source that's not playing or paused has any offset applied when it
2499 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2501 ATOMIC_STORE(&voice
->loop_buffer
, static_cast<ALbufferlistitem
*>(nullptr),
2502 almemory_order_relaxed
);
2503 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2504 ATOMIC_STORE(&voice
->position
, 0u, almemory_order_relaxed
);
2505 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2506 if(ApplyOffset(source
, voice
) != AL_FALSE
)
2507 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2508 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2509 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2511 for(j
= 0;j
< BufferList
->num_buffers
;j
++)
2513 ALbuffer
*buffer
= BufferList
->buffers
[j
];
2516 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2517 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2522 /* Clear previous samples. */
2523 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2525 /* Clear the stepping value so the mixer knows not to mix this until
2526 * the update gets applied.
2530 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2531 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2532 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2533 for(j
= 0;j
< device
->NumAuxSends
;j
++)
2534 memset(voice
->Send
[j
].Params
, 0, sizeof(voice
->Send
[j
].Params
[0])*voice
->NumChannels
);
2535 if(device
->AvgSpeakerDist
> 0.0f
)
2537 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2538 (device
->AvgSpeakerDist
* device
->Frequency
);
2539 for(j
= 0;j
< voice
->NumChannels
;j
++)
2540 NfcFilterCreate(&voice
->Direct
.Params
[j
].NFCtrlFilter
, 0.0f
, w1
);
2543 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2544 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2545 source
->state
= AL_PLAYING
;
2546 source
->VoiceIdx
= vidx
;
2548 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2550 ALCdevice_Unlock(device
);
2553 UnlockSourceList(context
);
2554 ALCcontext_DecRef(context
);
2557 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2559 alSourcePausev(1, &source
);
2561 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2563 ALCcontext
*context
;
2569 context
= GetContextRef();
2570 if(!context
) return;
2572 LockSourceList(context
);
2574 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Pausing %d sources", n
);
2575 for(i
= 0;i
< n
;i
++)
2577 if(!LookupSource(context
, sources
[i
]))
2578 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2581 device
= context
->Device
;
2582 ALCdevice_Lock(device
);
2583 for(i
= 0;i
< n
;i
++)
2585 source
= LookupSource(context
, sources
[i
]);
2586 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2587 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2588 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2590 source
->state
= AL_PAUSED
;
2591 SendStateChangeEvent(context
, source
->id
, AL_PAUSED
);
2594 ALCdevice_Unlock(device
);
2597 UnlockSourceList(context
);
2598 ALCcontext_DecRef(context
);
2601 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2603 alSourceStopv(1, &source
);
2605 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2607 ALCcontext
*context
;
2613 context
= GetContextRef();
2614 if(!context
) return;
2616 LockSourceList(context
);
2618 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Stopping %d sources", n
);
2619 for(i
= 0;i
< n
;i
++)
2621 if(!LookupSource(context
, sources
[i
]))
2622 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2625 device
= context
->Device
;
2626 ALCdevice_Lock(device
);
2627 for(i
= 0;i
< n
;i
++)
2630 source
= LookupSource(context
, sources
[i
]);
2631 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2633 ATOMIC_STORE(&voice
->Source
, static_cast<ALsource
*>(nullptr), almemory_order_relaxed
);
2634 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2637 oldstate
= GetSourceState(source
, voice
);
2638 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2640 source
->state
= AL_STOPPED
;
2641 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2643 source
->OffsetType
= AL_NONE
;
2644 source
->Offset
= 0.0;
2646 ALCdevice_Unlock(device
);
2649 UnlockSourceList(context
);
2650 ALCcontext_DecRef(context
);
2653 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2655 alSourceRewindv(1, &source
);
2657 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2659 ALCcontext
*context
;
2665 context
= GetContextRef();
2666 if(!context
) return;
2668 LockSourceList(context
);
2670 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Rewinding %d sources", n
);
2671 for(i
= 0;i
< n
;i
++)
2673 if(!LookupSource(context
, sources
[i
]))
2674 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2677 device
= context
->Device
;
2678 ALCdevice_Lock(device
);
2679 for(i
= 0;i
< n
;i
++)
2681 source
= LookupSource(context
, sources
[i
]);
2682 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2684 ATOMIC_STORE(&voice
->Source
, static_cast<ALsource
*>(nullptr), almemory_order_relaxed
);
2685 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2688 if(GetSourceState(source
, voice
) != AL_INITIAL
)
2690 source
->state
= AL_INITIAL
;
2691 SendStateChangeEvent(context
, source
->id
, AL_INITIAL
);
2693 source
->OffsetType
= AL_NONE
;
2694 source
->Offset
= 0.0;
2696 ALCdevice_Unlock(device
);
2699 UnlockSourceList(context
);
2700 ALCcontext_DecRef(context
);
2704 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2707 ALCcontext
*context
;
2710 ALbufferlistitem
*BufferListStart
;
2711 ALbufferlistitem
*BufferList
;
2712 ALbuffer
*BufferFmt
= NULL
;
2717 context
= GetContextRef();
2718 if(!context
) return;
2720 device
= context
->Device
;
2722 LockSourceList(context
);
2724 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Queueing %d buffers", nb
);
2725 if((source
=LookupSource(context
, src
)) == NULL
)
2726 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2728 if(source
->SourceType
== AL_STATIC
)
2730 /* Can't queue on a Static Source */
2731 SETERR_GOTO(context
, AL_INVALID_OPERATION
, done
, "Queueing onto static source %u", src
);
2734 /* Check for a valid Buffer, for its frequency and format */
2735 BufferList
= source
->queue
;
2738 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2740 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2743 if(BufferFmt
) break;
2744 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2747 LockBufferList(device
);
2748 BufferListStart
= NULL
;
2750 for(i
= 0;i
< nb
;i
++)
2752 ALbuffer
*buffer
= NULL
;
2753 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2754 SETERR_GOTO(context
, AL_INVALID_NAME
, buffer_error
, "Queueing invalid buffer ID %u",
2757 if(!BufferListStart
)
2759 BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
2760 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
2761 BufferList
= BufferListStart
;
2765 ALbufferlistitem
*item
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
2766 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
2767 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2770 ATOMIC_INIT(&BufferList
->next
, static_cast<ALbufferlistitem
*>(nullptr));
2771 BufferList
->max_samples
= buffer
? buffer
->SampleLen
: 0;
2772 BufferList
->num_buffers
= 1;
2773 BufferList
->buffers
[0] = buffer
;
2774 if(!buffer
) continue;
2776 IncrementRef(&buffer
->ref
);
2778 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2779 SETERR_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
,
2780 "Queueing non-persistently mapped buffer %u", buffer
->id
);
2782 if(BufferFmt
== NULL
)
2784 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2785 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2786 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2788 alSetError(context
, AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
2791 /* A buffer failed (invalid ID or format), so unlock and release
2792 * each buffer we had. */
2793 while(BufferListStart
)
2795 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2796 almemory_order_relaxed
);
2797 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2799 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2800 DecrementRef(&buffer
->ref
);
2802 al_free(BufferListStart
);
2803 BufferListStart
= next
;
2805 UnlockBufferList(device
);
2809 /* All buffers good. */
2810 UnlockBufferList(device
);
2812 /* Source is now streaming */
2813 source
->SourceType
= AL_STREAMING
;
2815 if(!(BufferList
=source
->queue
))
2816 source
->queue
= BufferListStart
;
2819 ALbufferlistitem
*next
;
2820 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2822 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2826 UnlockSourceList(context
);
2827 ALCcontext_DecRef(context
);
2830 AL_API
void AL_APIENTRY
alSourceQueueBufferLayersSOFT(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2833 ALCcontext
*context
;
2834 ALbufferlistitem
*BufferListStart
;
2835 ALbufferlistitem
*BufferList
;
2836 ALbuffer
*BufferFmt
= NULL
;
2843 context
= GetContextRef();
2844 if(!context
) return;
2846 device
= context
->Device
;
2848 LockSourceList(context
);
2849 if(!(nb
>= 0 && nb
< 16))
2850 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Queueing %d buffer layers", nb
);
2851 if((source
=LookupSource(context
, src
)) == NULL
)
2852 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2854 if(source
->SourceType
== AL_STATIC
)
2856 /* Can't queue on a Static Source */
2857 SETERR_GOTO(context
, AL_INVALID_OPERATION
, done
, "Queueing onto static source %u", src
);
2860 /* Check for a valid Buffer, for its frequency and format */
2861 BufferList
= source
->queue
;
2864 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2866 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2869 if(BufferFmt
) break;
2870 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2873 LockBufferList(device
);
2874 BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
2875 FAM_SIZE(ALbufferlistitem
, buffers
, nb
)));
2876 BufferList
= BufferListStart
;
2877 ATOMIC_INIT(&BufferList
->next
, static_cast<ALbufferlistitem
*>(nullptr));
2878 BufferList
->max_samples
= 0;
2879 BufferList
->num_buffers
= 0;
2880 for(i
= 0;i
< nb
;i
++)
2882 ALbuffer
*buffer
= NULL
;
2883 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2884 SETERR_GOTO(context
, AL_INVALID_NAME
, buffer_error
, "Queueing invalid buffer ID %u",
2887 BufferList
->buffers
[BufferList
->num_buffers
++] = buffer
;
2888 if(!buffer
) continue;
2890 IncrementRef(&buffer
->ref
);
2892 BufferList
->max_samples
= maxi(BufferList
->max_samples
, buffer
->SampleLen
);
2894 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2895 SETERR_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
,
2896 "Queueing non-persistently mapped buffer %u", buffer
->id
);
2898 if(BufferFmt
== NULL
)
2900 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2901 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2902 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2904 alSetError(context
, AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
2907 /* A buffer failed (invalid ID or format), so unlock and release
2908 * each buffer we had. */
2909 while(BufferListStart
)
2911 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2912 almemory_order_relaxed
);
2913 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2915 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2916 DecrementRef(&buffer
->ref
);
2918 al_free(BufferListStart
);
2919 BufferListStart
= next
;
2921 UnlockBufferList(device
);
2925 /* All buffers good. */
2926 UnlockBufferList(device
);
2928 /* Source is now streaming */
2929 source
->SourceType
= AL_STREAMING
;
2931 if(!(BufferList
=source
->queue
))
2932 source
->queue
= BufferListStart
;
2935 ALbufferlistitem
*next
;
2936 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2938 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2942 UnlockSourceList(context
);
2943 ALCcontext_DecRef(context
);
2946 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2948 ALCcontext
*context
;
2950 ALbufferlistitem
*BufferList
;
2951 ALbufferlistitem
*Current
;
2955 context
= GetContextRef();
2956 if(!context
) return;
2958 LockSourceList(context
);
2960 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing %d buffers", nb
);
2961 if((source
=LookupSource(context
, src
)) == NULL
)
2962 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2964 /* Nothing to unqueue. */
2965 if(nb
== 0) goto done
;
2968 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from looping source %u", src
);
2969 if(source
->SourceType
!= AL_STREAMING
)
2970 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from a non-streaming source %u",
2973 /* Make sure enough buffers have been processed to unqueue. */
2974 BufferList
= source
->queue
;
2976 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2977 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
2978 else if(source
->state
== AL_INITIAL
)
2979 Current
= BufferList
;
2980 if(BufferList
== Current
)
2981 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2983 i
= BufferList
->num_buffers
;
2986 /* If the next bufferlist to check is NULL or is the current one, it's
2987 * trying to unqueue pending buffers.
2989 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2990 if(!next
|| next
== Current
)
2991 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2994 i
+= BufferList
->num_buffers
;
2999 ALbufferlistitem
*head
= source
->queue
;
3000 ALbufferlistitem
*next
= ATOMIC_LOAD(&head
->next
, almemory_order_relaxed
);
3001 for(i
= 0;i
< head
->num_buffers
&& nb
> 0;i
++,nb
--)
3003 ALbuffer
*buffer
= head
->buffers
[i
];
3008 *(buffers
++) = buffer
->id
;
3009 DecrementRef(&buffer
->ref
);
3012 if(i
< head
->num_buffers
)
3014 /* This head has some buffers left over, so move them to the front
3015 * and update the sample and buffer count.
3017 ALsizei max_length
= 0;
3019 while(i
< head
->num_buffers
)
3021 ALbuffer
*buffer
= head
->buffers
[i
++];
3022 if(buffer
) max_length
= maxi(max_length
, buffer
->SampleLen
);
3023 head
->buffers
[j
++] = buffer
;
3025 head
->max_samples
= max_length
;
3026 head
->num_buffers
= j
;
3030 /* Otherwise, free this item and set the source queue head to the next
3034 source
->queue
= next
;
3038 UnlockSourceList(context
);
3039 ALCcontext_DecRef(context
);
3043 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
3047 Source
->InnerAngle
= 360.0f
;
3048 Source
->OuterAngle
= 360.0f
;
3049 Source
->Pitch
= 1.0f
;
3050 Source
->Position
[0] = 0.0f
;
3051 Source
->Position
[1] = 0.0f
;
3052 Source
->Position
[2] = 0.0f
;
3053 Source
->Velocity
[0] = 0.0f
;
3054 Source
->Velocity
[1] = 0.0f
;
3055 Source
->Velocity
[2] = 0.0f
;
3056 Source
->Direction
[0] = 0.0f
;
3057 Source
->Direction
[1] = 0.0f
;
3058 Source
->Direction
[2] = 0.0f
;
3059 Source
->Orientation
[0][0] = 0.0f
;
3060 Source
->Orientation
[0][1] = 0.0f
;
3061 Source
->Orientation
[0][2] = -1.0f
;
3062 Source
->Orientation
[1][0] = 0.0f
;
3063 Source
->Orientation
[1][1] = 1.0f
;
3064 Source
->Orientation
[1][2] = 0.0f
;
3065 Source
->RefDistance
= 1.0f
;
3066 Source
->MaxDistance
= FLT_MAX
;
3067 Source
->RolloffFactor
= 1.0f
;
3068 Source
->Gain
= 1.0f
;
3069 Source
->MinGain
= 0.0f
;
3070 Source
->MaxGain
= 1.0f
;
3071 Source
->OuterGain
= 0.0f
;
3072 Source
->OuterGainHF
= 1.0f
;
3074 Source
->DryGainHFAuto
= AL_TRUE
;
3075 Source
->WetGainAuto
= AL_TRUE
;
3076 Source
->WetGainHFAuto
= AL_TRUE
;
3077 Source
->AirAbsorptionFactor
= 0.0f
;
3078 Source
->RoomRolloffFactor
= 0.0f
;
3079 Source
->DopplerFactor
= 1.0f
;
3080 Source
->HeadRelative
= AL_FALSE
;
3081 Source
->Looping
= AL_FALSE
;
3082 Source
->mDistanceModel
= DistanceModel::Default
;
3083 Source
->Resampler
= ResamplerDefault
;
3084 Source
->DirectChannels
= AL_FALSE
;
3085 Source
->Spatialize
= SpatializeAuto
;
3087 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
3088 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
3090 Source
->Radius
= 0.0f
;
3092 Source
->Direct
.Gain
= 1.0f
;
3093 Source
->Direct
.GainHF
= 1.0f
;
3094 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
3095 Source
->Direct
.GainLF
= 1.0f
;
3096 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
3097 Source
->Send
= static_cast<decltype(Source
->Send
)>(al_calloc(16,
3098 num_sends
*sizeof(Source
->Send
[0])));
3099 for(i
= 0;i
< num_sends
;i
++)
3101 Source
->Send
[i
].Slot
= NULL
;
3102 Source
->Send
[i
].Gain
= 1.0f
;
3103 Source
->Send
[i
].GainHF
= 1.0f
;
3104 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
3105 Source
->Send
[i
].GainLF
= 1.0f
;
3106 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
3109 Source
->Offset
= 0.0;
3110 Source
->OffsetType
= AL_NONE
;
3111 Source
->SourceType
= AL_UNDETERMINED
;
3112 Source
->state
= AL_INITIAL
;
3114 Source
->queue
= NULL
;
3116 ATOMIC_INIT(&Source
->PropsClean
, AL_TRUE
);
3118 Source
->VoiceIdx
= -1;
3121 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3123 ALbufferlistitem
*BufferList
;
3126 BufferList
= source
->queue
;
3127 while(BufferList
!= NULL
)
3129 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3130 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3132 if(BufferList
->buffers
[i
] != NULL
)
3133 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3135 al_free(BufferList
);
3138 source
->queue
= NULL
;
3142 for(i
= 0;i
< num_sends
;i
++)
3144 if(source
->Send
[i
].Slot
)
3145 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3146 source
->Send
[i
].Slot
= NULL
;
3148 al_free(source
->Send
);
3149 source
->Send
= NULL
;
3153 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3155 struct ALvoiceProps
*props
;
3158 /* Get an unused property container, or allocate a new one as needed. */
3159 props
= context
->FreeVoiceProps
.load(std::memory_order_acquire
);
3161 props
= static_cast<ALvoiceProps
*>(al_calloc(16,
3162 FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
)));
3165 struct ALvoiceProps
*next
;
3167 next
= props
->next
.load(std::memory_order_relaxed
);
3168 } while(context
->FreeVoiceProps
.compare_exchange_weak(props
, next
,
3169 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0);
3172 /* Copy in current property values. */
3173 props
->Pitch
= source
->Pitch
;
3174 props
->Gain
= source
->Gain
;
3175 props
->OuterGain
= source
->OuterGain
;
3176 props
->MinGain
= source
->MinGain
;
3177 props
->MaxGain
= source
->MaxGain
;
3178 props
->InnerAngle
= source
->InnerAngle
;
3179 props
->OuterAngle
= source
->OuterAngle
;
3180 props
->RefDistance
= source
->RefDistance
;
3181 props
->MaxDistance
= source
->MaxDistance
;
3182 props
->RolloffFactor
= source
->RolloffFactor
;
3183 for(i
= 0;i
< 3;i
++)
3184 props
->Position
[i
] = source
->Position
[i
];
3185 for(i
= 0;i
< 3;i
++)
3186 props
->Velocity
[i
] = source
->Velocity
[i
];
3187 for(i
= 0;i
< 3;i
++)
3188 props
->Direction
[i
] = source
->Direction
[i
];
3189 for(i
= 0;i
< 2;i
++)
3192 for(j
= 0;j
< 3;j
++)
3193 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3195 props
->HeadRelative
= source
->HeadRelative
;
3196 props
->mDistanceModel
= source
->mDistanceModel
;
3197 props
->Resampler
= source
->Resampler
;
3198 props
->DirectChannels
= source
->DirectChannels
;
3199 props
->SpatializeMode
= source
->Spatialize
;
3201 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3202 props
->WetGainAuto
= source
->WetGainAuto
;
3203 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3204 props
->OuterGainHF
= source
->OuterGainHF
;
3206 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3207 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3208 props
->DopplerFactor
= source
->DopplerFactor
;
3210 props
->StereoPan
[0] = source
->StereoPan
[0];
3211 props
->StereoPan
[1] = source
->StereoPan
[1];
3213 props
->Radius
= source
->Radius
;
3215 props
->Direct
.Gain
= source
->Direct
.Gain
;
3216 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3217 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3218 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3219 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3221 for(i
= 0;i
< num_sends
;i
++)
3223 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3224 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3225 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3226 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3227 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3228 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3231 /* Set the new container for updating internal parameters. */
3232 props
= voice
->Update
.exchange(props
, std::memory_order_acq_rel
);
3235 /* If there was an unused update container, put it back in the
3238 AtomicReplaceHead(context
->FreeVoiceProps
, props
);
3242 void UpdateAllSourceProps(ALCcontext
*context
)
3244 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3247 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3249 ALvoice
*voice
= context
->Voices
[pos
];
3250 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3251 if(source
&& !source
->PropsClean
.exchange(AL_TRUE
, std::memory_order_acq_rel
))
3252 UpdateSourceProps(source
, voice
, num_sends
, context
);
3257 /* GetSourceSampleOffset
3259 * Gets the current read offset for the given Source, in 32.32 fixed-point
3260 * samples. The offset is relative to the start of the queue (not the start of
3261 * the current buffer).
3263 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3265 ALCdevice
*device
= context
->Device
;
3266 const ALbufferlistitem
*Current
;
3274 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3276 *clocktime
= GetDeviceClockTime(device
);
3278 voice
= GetSourceVoice(Source
, context
);
3281 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3283 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3284 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3287 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3288 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3292 const ALbufferlistitem
*BufferList
= Source
->queue
;
3293 while(BufferList
&& BufferList
!= Current
)
3295 readPos
+= (ALuint64
)BufferList
->max_samples
<< 32;
3296 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3298 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3301 return (ALint64
)readPos
;
3304 /* GetSourceSecOffset
3306 * Gets the current read offset for the given Source, in seconds. The offset is
3307 * relative to the start of the queue (not the start of the current buffer).
3309 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3311 ALCdevice
*device
= context
->Device
;
3312 const ALbufferlistitem
*Current
;
3321 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3323 *clocktime
= GetDeviceClockTime(device
);
3325 voice
= GetSourceVoice(Source
, context
);
3328 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3330 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3332 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3334 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3335 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3340 const ALbufferlistitem
*BufferList
= Source
->queue
;
3341 const ALbuffer
*BufferFmt
= NULL
;
3342 while(BufferList
&& BufferList
!= Current
)
3345 while(!BufferFmt
&& i
< BufferList
->num_buffers
)
3346 BufferFmt
= BufferList
->buffers
[i
++];
3347 readPos
+= (ALuint64
)BufferList
->max_samples
<< FRACTIONBITS
;
3348 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3351 while(BufferList
&& !BufferFmt
)
3354 while(!BufferFmt
&& i
< BufferList
->num_buffers
)
3355 BufferFmt
= BufferList
->buffers
[i
++];
3356 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3358 assert(BufferFmt
!= NULL
);
3360 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3361 (ALdouble
)BufferFmt
->Frequency
;
3369 * Gets the current read offset for the given Source, in the appropriate format
3370 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3371 * queue (not the start of the current buffer).
3373 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3375 ALCdevice
*device
= context
->Device
;
3376 const ALbufferlistitem
*Current
;
3378 ALsizei readPosFrac
;
3385 readPos
= readPosFrac
= 0;
3386 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3388 voice
= GetSourceVoice(Source
, context
);
3391 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3393 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3394 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3396 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3397 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3402 const ALbufferlistitem
*BufferList
= Source
->queue
;
3403 const ALbuffer
*BufferFmt
= NULL
;
3404 ALboolean readFin
= AL_FALSE
;
3405 ALuint totalBufferLen
= 0;
3407 while(BufferList
!= NULL
)
3410 while(!BufferFmt
&& i
< BufferList
->num_buffers
)
3411 BufferFmt
= BufferList
->buffers
[i
++];
3413 readFin
|= (BufferList
== Current
);
3414 totalBufferLen
+= BufferList
->max_samples
;
3415 if(!readFin
) readPos
+= BufferList
->max_samples
;
3417 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3419 assert(BufferFmt
!= NULL
);
3422 readPos
%= totalBufferLen
;
3425 /* Wrap back to 0 */
3426 if(readPos
>= totalBufferLen
)
3427 readPos
= readPosFrac
= 0;
3434 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3437 case AL_SAMPLE_OFFSET
:
3438 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3441 case AL_BYTE_OFFSET
:
3442 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3444 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3445 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3446 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3448 /* Round down to nearest ADPCM block */
3449 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3451 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3453 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3454 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3455 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3457 /* Round down to nearest ADPCM block */
3458 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3462 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
3463 BufferFmt
->FmtType
);
3464 offset
= (ALdouble
)(readPos
* FrameSize
);
3476 * Apply the stored playback offset to the Source. This function will update
3477 * the number of buffers "played" given the stored offset.
3479 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3481 ALbufferlistitem
*BufferList
;
3482 ALuint totalBufferLen
;
3486 /* Get sample frame offset */
3487 if(!GetSampleOffset(Source
, &offset
, &frac
))
3491 BufferList
= Source
->queue
;
3492 while(BufferList
&& totalBufferLen
<= offset
)
3494 if((ALuint
)BufferList
->max_samples
> offset
-totalBufferLen
)
3496 /* Offset is in this buffer */
3497 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3498 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3499 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3502 totalBufferLen
+= BufferList
->max_samples
;
3504 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3507 /* Offset is out of range of the queue */
3514 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3515 * or Second offset supplied by the application). This takes into account the
3516 * fact that the buffer format may have been modifed since.
3518 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3520 const ALbuffer
*BufferFmt
= NULL
;
3521 const ALbufferlistitem
*BufferList
;
3522 ALdouble dbloff
, dblfrac
;
3524 /* Find the first valid Buffer in the Queue */
3525 BufferList
= Source
->queue
;
3529 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3530 BufferFmt
= BufferList
->buffers
[i
];
3531 if(BufferFmt
) break;
3532 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3536 Source
->OffsetType
= AL_NONE
;
3537 Source
->Offset
= 0.0;
3541 switch(Source
->OffsetType
)
3543 case AL_BYTE_OFFSET
:
3544 /* Determine the ByteOffset (and ensure it is block aligned) */
3545 *offset
= (ALuint
)Source
->Offset
;
3546 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3548 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3549 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3550 *offset
*= BufferFmt
->OriginalAlign
;
3552 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3554 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3555 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3556 *offset
*= BufferFmt
->OriginalAlign
;
3559 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
3563 case AL_SAMPLE_OFFSET
:
3564 dblfrac
= modf(Source
->Offset
, &dbloff
);
3565 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3566 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3570 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3571 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3572 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3575 Source
->OffsetType
= AL_NONE
;
3576 Source
->Offset
= 0.0;
3582 static ALsource
*AllocSource(ALCcontext
*context
)
3584 ALCdevice
*device
{context
->Device
};
3585 almtx_lock(&context
->SourceLock
);
3586 if(context
->NumSources
>= device
->SourcesMax
)
3588 almtx_unlock(&context
->SourceLock
);
3589 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
3592 auto sublist
= std::find_if(context
->SourceList
.begin(), context
->SourceList
.end(),
3593 [](const SourceSubList
&entry
) -> bool
3594 { return entry
.FreeMask
!= 0; }
3596 ALsizei lidx
= std::distance(context
->SourceList
.begin(), sublist
);
3599 if(LIKELY(sublist
!= context
->SourceList
.end()))
3601 slidx
= CTZ64(sublist
->FreeMask
);
3602 source
= sublist
->Sources
+ slidx
;
3606 /* Don't allocate so many list entries that the 32-bit ID could
3609 if(UNLIKELY(context
->SourceList
.size() >= 1<<25))
3611 almtx_unlock(&device
->BufferLock
);
3612 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
3615 context
->SourceList
.emplace_back();
3616 sublist
= context
->SourceList
.end() - 1;
3618 sublist
->FreeMask
= ~U64(0);
3619 sublist
->Sources
= static_cast<ALsource
*>(al_calloc(16, sizeof(ALsource
)*64));
3620 if(UNLIKELY(!sublist
->Sources
))
3622 context
->SourceList
.pop_back();
3623 almtx_unlock(&context
->SourceLock
);
3624 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
3629 source
= sublist
->Sources
+ slidx
;
3632 source
= new (source
) ALsource
{};
3633 InitSourceParams(source
, device
->NumAuxSends
);
3635 /* Add 1 to avoid source ID 0. */
3636 source
->id
= ((lidx
<<6) | slidx
) + 1;
3638 context
->NumSources
++;
3639 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
3640 almtx_unlock(&context
->SourceLock
);
3645 static void FreeSource(ALCcontext
*context
, ALsource
*source
)
3647 ALCdevice
*device
= context
->Device
;
3648 ALuint id
= source
->id
- 1;
3649 ALsizei lidx
= id
>> 6;
3650 ALsizei slidx
= id
& 0x3f;
3653 ALCdevice_Lock(device
);
3654 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
3656 ATOMIC_STORE(&voice
->Source
, static_cast<ALsource
*>(nullptr), almemory_order_relaxed
);
3657 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3659 ALCdevice_Unlock(device
);
3661 DeinitSource(source
, device
->NumAuxSends
);
3662 source
->~ALsource();
3664 context
->SourceList
[lidx
].FreeMask
|= U64(1) << slidx
;
3665 context
->NumSources
--;
3670 * Destroys all sources in the source map.
3672 ALvoid
ReleaseALSources(ALCcontext
*context
)
3674 ALCdevice
*device
= context
->Device
;
3675 size_t leftover
= 0;
3676 for(auto &sublist
: context
->SourceList
)
3678 ALuint64 usemask
= ~sublist
.FreeMask
;
3681 ALsizei idx
= CTZ64(usemask
);
3682 ALsource
*source
= sublist
.Sources
+ idx
;
3684 DeinitSource(source
, device
->NumAuxSends
);
3685 source
->~ALsource();
3688 usemask
&= ~(U64(1) << idx
);
3690 sublist
.FreeMask
= ~usemask
;
3693 WARN("(%p) Deleted " SZFMT
" Source%s\n", device
, leftover
, (leftover
==1)?"":"s");