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 "alAuxEffectSlot.h"
35 #include "ringbuffer.h"
37 #include "backends/base.h"
43 static ALsource
*AllocSource(ALCcontext
*context
);
44 static void FreeSource(ALCcontext
*context
, ALsource
*source
);
45 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
46 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
47 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
);
48 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
49 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
50 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
51 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
);
52 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
);
54 static inline void LockSourceList(ALCcontext
*context
)
55 { almtx_lock(&context
->SourceLock
); }
56 static inline void UnlockSourceList(ALCcontext
*context
)
57 { almtx_unlock(&context
->SourceLock
); }
59 static inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
)
61 SourceSubList
*sublist
;
62 ALuint lidx
= (id
-1) >> 6;
63 ALsizei slidx
= (id
-1) & 0x3f;
65 if(UNLIKELY(lidx
>= VECTOR_SIZE(context
->SourceList
)))
67 sublist
= &VECTOR_ELEM(context
->SourceList
, lidx
);
68 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
70 return sublist
->Sources
+ slidx
;
73 static inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
)
75 BufferSubList
*sublist
;
76 ALuint lidx
= (id
-1) >> 6;
77 ALsizei slidx
= (id
-1) & 0x3f;
79 if(UNLIKELY(lidx
>= VECTOR_SIZE(device
->BufferList
)))
81 sublist
= &VECTOR_ELEM(device
->BufferList
, lidx
);
82 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
84 return sublist
->Buffers
+ slidx
;
87 static inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
)
89 FilterSubList
*sublist
;
90 ALuint lidx
= (id
-1) >> 6;
91 ALsizei slidx
= (id
-1) & 0x3f;
93 if(UNLIKELY(lidx
>= VECTOR_SIZE(device
->FilterList
)))
95 sublist
= &VECTOR_ELEM(device
->FilterList
, lidx
);
96 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
98 return sublist
->Filters
+ slidx
;
101 static inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
)
104 if(UNLIKELY(id
>= VECTOR_SIZE(context
->EffectSlotList
)))
106 return VECTOR_ELEM(context
->EffectSlotList
, id
);
110 typedef enum SourceProp
{
113 srcMinGain
= AL_MIN_GAIN
,
114 srcMaxGain
= AL_MAX_GAIN
,
115 srcMaxDistance
= AL_MAX_DISTANCE
,
116 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
117 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
118 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
119 srcSecOffset
= AL_SEC_OFFSET
,
120 srcSampleOffset
= AL_SAMPLE_OFFSET
,
121 srcByteOffset
= AL_BYTE_OFFSET
,
122 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
123 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
124 srcRefDistance
= AL_REFERENCE_DISTANCE
,
126 srcPosition
= AL_POSITION
,
127 srcVelocity
= AL_VELOCITY
,
128 srcDirection
= AL_DIRECTION
,
130 srcSourceRelative
= AL_SOURCE_RELATIVE
,
131 srcLooping
= AL_LOOPING
,
132 srcBuffer
= AL_BUFFER
,
133 srcSourceState
= AL_SOURCE_STATE
,
134 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
135 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
136 srcSourceType
= AL_SOURCE_TYPE
,
139 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
140 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
141 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
142 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
143 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
144 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
145 srcDirectFilter
= AL_DIRECT_FILTER
,
146 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
148 /* AL_SOFT_direct_channels */
149 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
151 /* AL_EXT_source_distance_model */
152 srcDistanceModel
= AL_DISTANCE_MODEL
,
154 /* AL_SOFT_source_latency */
155 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
156 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
158 /* AL_EXT_STEREO_ANGLES */
159 srcAngles
= AL_STEREO_ANGLES
,
161 /* AL_EXT_SOURCE_RADIUS */
162 srcRadius
= AL_SOURCE_RADIUS
,
165 srcOrientation
= AL_ORIENTATION
,
167 /* AL_SOFT_source_resampler */
168 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
170 /* AL_SOFT_source_spatialize */
171 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
173 /* ALC_SOFT_device_clock */
174 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
175 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
178 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
179 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
180 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
182 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
183 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
184 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
186 static inline ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
188 ALint idx
= source
->VoiceIdx
;
189 if(idx
>= 0 && idx
< context
->VoiceCount
)
191 ALvoice
*voice
= context
->Voices
[idx
];
192 if(ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
) == source
)
195 source
->VoiceIdx
= -1;
200 * Returns if the last known state for the source was playing or paused. Does
201 * not sync with the mixer voice.
203 static inline bool IsPlayingOrPaused(ALsource
*source
)
204 { return source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
; }
207 * Returns an updated source state using the matching voice's status (or lack
210 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
212 if(!voice
&& source
->state
== AL_PLAYING
)
213 source
->state
= AL_STOPPED
;
214 return source
->state
;
218 * Returns if the source should specify an update, given the context's
219 * deferring state and the source's last known state.
221 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
223 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
224 IsPlayingOrPaused(source
);
228 /** Can only be called while the mixer is locked! */
229 static void SendStateChangeEvent(ALCcontext
*context
, ALuint id
, ALenum state
)
231 ALbitfieldSOFT enabledevt
;
234 enabledevt
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_acquire
);
235 if(!(enabledevt
&EventType_SourceStateChange
)) return;
237 evt
.EnumType
= EventType_SourceStateChange
;
238 evt
.Type
= AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
;
241 snprintf(evt
.Message
, sizeof(evt
.Message
), "Source ID %u state changed to %s", id
,
242 (state
==AL_INITIAL
) ? "AL_INITIAL" :
243 (state
==AL_PLAYING
) ? "AL_PLAYING" :
244 (state
==AL_PAUSED
) ? "AL_PAUSED" :
245 (state
==AL_STOPPED
) ? "AL_STOPPED" : "<unknown>"
247 /* The mixer may have queued a state change that's not yet been processed,
248 * and we don't want state change messages to occur out of order, so send
249 * it through the async queue to ensure proper ordering.
251 if(ll_ringbuffer_write_space(context
->AsyncEvents
) > 0)
252 ll_ringbuffer_write(context
->AsyncEvents
, (const char*)&evt
, 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_FLAG_CLEAR(&Source->PropsClean, 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
&& isfinite(*values
));
669 Source
->Radius
= *values
;
673 case AL_STEREO_ANGLES
:
674 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
676 Source
->StereoPan
[0] = values
[0];
677 Source
->StereoPan
[1] = values
[1];
683 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
685 Source
->Position
[0] = values
[0];
686 Source
->Position
[1] = values
[1];
687 Source
->Position
[2] = values
[2];
692 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
694 Source
->Velocity
[0] = values
[0];
695 Source
->Velocity
[1] = values
[1];
696 Source
->Velocity
[2] = values
[2];
701 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
703 Source
->Direction
[0] = values
[0];
704 Source
->Direction
[1] = values
[1];
705 Source
->Direction
[2] = values
[2];
710 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
711 isfinite(values
[3]) && isfinite(values
[4]) && 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
, NULL
, almemory_order_release
);
794 /* If the source is playing, wait for the current mix to finish
795 * to ensure it isn't currently looping back or reaching the
798 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
805 LockBufferList(device
);
806 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
808 UnlockBufferList(device
);
809 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
813 if(buffer
&& buffer
->MappedAccess
!= 0 &&
814 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
816 UnlockBufferList(device
);
817 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
818 "Setting non-persistently mapped buffer %u", buffer
->id
);
822 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
823 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
825 UnlockBufferList(device
);
826 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
827 "Setting buffer on playing or paused source %u", Source
->id
);
831 oldlist
= Source
->queue
;
834 /* Add the selected buffer to a one-item queue */
835 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
,
836 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
837 ATOMIC_INIT(&newlist
->next
, NULL
);
838 newlist
->num_buffers
= 1;
839 newlist
->buffers
[0] = buffer
;
840 IncrementRef(&buffer
->ref
);
842 /* Source is now Static */
843 Source
->SourceType
= AL_STATIC
;
844 Source
->queue
= newlist
;
848 /* Source is now Undetermined */
849 Source
->SourceType
= AL_UNDETERMINED
;
850 Source
->queue
= NULL
;
852 UnlockBufferList(device
);
854 /* Delete all elements in the previous queue */
855 while(oldlist
!= NULL
)
858 ALbufferlistitem
*temp
= oldlist
;
859 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
861 for(i
= 0;i
< temp
->num_buffers
;i
++)
864 DecrementRef(&temp
->buffers
[i
]->ref
);
871 case AL_SAMPLE_OFFSET
:
873 CHECKVAL(*values
>= 0);
875 Source
->OffsetType
= prop
;
876 Source
->Offset
= *values
;
878 if(IsPlayingOrPaused(Source
))
882 ALCdevice_Lock(Context
->Device
);
883 voice
= GetSourceVoice(Source
, Context
);
886 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
888 ALCdevice_Unlock(Context
->Device
);
889 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
890 "Invalid source offset");
893 ALCdevice_Unlock(Context
->Device
);
897 case AL_DIRECT_FILTER
:
898 LockFilterList(device
);
899 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
901 UnlockFilterList(device
);
902 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
908 Source
->Direct
.Gain
= 1.0f
;
909 Source
->Direct
.GainHF
= 1.0f
;
910 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
911 Source
->Direct
.GainLF
= 1.0f
;
912 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
916 Source
->Direct
.Gain
= filter
->Gain
;
917 Source
->Direct
.GainHF
= filter
->GainHF
;
918 Source
->Direct
.HFReference
= filter
->HFReference
;
919 Source
->Direct
.GainLF
= filter
->GainLF
;
920 Source
->Direct
.LFReference
= filter
->LFReference
;
922 UnlockFilterList(device
);
926 case AL_DIRECT_FILTER_GAINHF_AUTO
:
927 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
929 Source
->DryGainHFAuto
= *values
;
933 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
934 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
936 Source
->WetGainAuto
= *values
;
940 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
941 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
943 Source
->WetGainHFAuto
= *values
;
947 case AL_DIRECT_CHANNELS_SOFT
:
948 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
950 Source
->DirectChannels
= *values
;
954 case AL_DISTANCE_MODEL
:
955 CHECKVAL(*values
== AL_NONE
||
956 *values
== AL_INVERSE_DISTANCE
||
957 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
958 *values
== AL_LINEAR_DISTANCE
||
959 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
960 *values
== AL_EXPONENT_DISTANCE
||
961 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
963 Source
->DistanceModel
= *values
;
964 if(Context
->SourceDistanceModel
)
968 case AL_SOURCE_RESAMPLER_SOFT
:
969 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
971 Source
->Resampler
= *values
;
975 case AL_SOURCE_SPATIALIZE_SOFT
:
976 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
978 Source
->Spatialize
= *values
;
983 case AL_AUXILIARY_SEND_FILTER
:
984 LockEffectSlotList(Context
);
985 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
))
987 UnlockEffectSlotList(Context
);
988 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
991 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
))
993 UnlockEffectSlotList(Context
);
994 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
996 LockFilterList(device
);
997 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
))
999 UnlockFilterList(device
);
1000 UnlockEffectSlotList(Context
);
1001 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1007 /* Disable filter */
1008 Source
->Send
[values
[1]].Gain
= 1.0f
;
1009 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1010 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1011 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1012 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1016 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1017 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1018 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1019 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1020 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1022 UnlockFilterList(device
);
1024 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1027 /* Add refcount on the new slot, and release the previous slot */
1028 if(slot
) IncrementRef(&slot
->ref
);
1029 if(Source
->Send
[values
[1]].Slot
)
1030 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1031 Source
->Send
[values
[1]].Slot
= slot
;
1033 /* We must force an update if the auxiliary slot changed on an
1034 * active source, in case the slot is about to be deleted.
1036 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1037 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
1039 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
1043 if(slot
) IncrementRef(&slot
->ref
);
1044 if(Source
->Send
[values
[1]].Slot
)
1045 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1046 Source
->Send
[values
[1]].Slot
= slot
;
1049 UnlockEffectSlotList(Context
);
1055 case AL_CONE_INNER_ANGLE
:
1056 case AL_CONE_OUTER_ANGLE
:
1061 case AL_REFERENCE_DISTANCE
:
1062 case AL_ROLLOFF_FACTOR
:
1063 case AL_CONE_OUTER_GAIN
:
1064 case AL_MAX_DISTANCE
:
1065 case AL_DOPPLER_FACTOR
:
1066 case AL_CONE_OUTER_GAINHF
:
1067 case AL_AIR_ABSORPTION_FACTOR
:
1068 case AL_ROOM_ROLLOFF_FACTOR
:
1069 case AL_SOURCE_RADIUS
:
1070 fvals
[0] = (ALfloat
)*values
;
1071 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1077 fvals
[0] = (ALfloat
)values
[0];
1078 fvals
[1] = (ALfloat
)values
[1];
1079 fvals
[2] = (ALfloat
)values
[2];
1080 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1083 case AL_ORIENTATION
:
1084 fvals
[0] = (ALfloat
)values
[0];
1085 fvals
[1] = (ALfloat
)values
[1];
1086 fvals
[2] = (ALfloat
)values
[2];
1087 fvals
[3] = (ALfloat
)values
[3];
1088 fvals
[4] = (ALfloat
)values
[4];
1089 fvals
[5] = (ALfloat
)values
[5];
1090 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1092 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1093 case AL_SEC_OFFSET_LATENCY_SOFT
:
1094 case AL_SEC_OFFSET_CLOCK_SOFT
:
1095 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1096 case AL_STEREO_ANGLES
:
1100 ERR("Unexpected property: 0x%04x\n", prop
);
1101 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1105 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1112 case AL_SOURCE_TYPE
:
1113 case AL_BUFFERS_QUEUED
:
1114 case AL_BUFFERS_PROCESSED
:
1115 case AL_SOURCE_STATE
:
1116 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1117 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1119 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1120 "Setting read-only source property 0x%04x", prop
);
1123 case AL_SOURCE_RELATIVE
:
1126 case AL_SAMPLE_OFFSET
:
1127 case AL_BYTE_OFFSET
:
1128 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1129 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1130 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1131 case AL_DIRECT_CHANNELS_SOFT
:
1132 case AL_DISTANCE_MODEL
:
1133 case AL_SOURCE_RESAMPLER_SOFT
:
1134 case AL_SOURCE_SPATIALIZE_SOFT
:
1135 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1137 ivals
[0] = (ALint
)*values
;
1138 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1142 case AL_DIRECT_FILTER
:
1143 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1145 ivals
[0] = (ALuint
)*values
;
1146 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1149 case AL_AUXILIARY_SEND_FILTER
:
1150 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1151 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1152 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1154 ivals
[0] = (ALuint
)values
[0];
1155 ivals
[1] = (ALuint
)values
[1];
1156 ivals
[2] = (ALuint
)values
[2];
1157 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1160 case AL_CONE_INNER_ANGLE
:
1161 case AL_CONE_OUTER_ANGLE
:
1166 case AL_REFERENCE_DISTANCE
:
1167 case AL_ROLLOFF_FACTOR
:
1168 case AL_CONE_OUTER_GAIN
:
1169 case AL_MAX_DISTANCE
:
1170 case AL_DOPPLER_FACTOR
:
1171 case AL_CONE_OUTER_GAINHF
:
1172 case AL_AIR_ABSORPTION_FACTOR
:
1173 case AL_ROOM_ROLLOFF_FACTOR
:
1174 case AL_SOURCE_RADIUS
:
1175 fvals
[0] = (ALfloat
)*values
;
1176 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1182 fvals
[0] = (ALfloat
)values
[0];
1183 fvals
[1] = (ALfloat
)values
[1];
1184 fvals
[2] = (ALfloat
)values
[2];
1185 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1188 case AL_ORIENTATION
:
1189 fvals
[0] = (ALfloat
)values
[0];
1190 fvals
[1] = (ALfloat
)values
[1];
1191 fvals
[2] = (ALfloat
)values
[2];
1192 fvals
[3] = (ALfloat
)values
[3];
1193 fvals
[4] = (ALfloat
)values
[4];
1194 fvals
[5] = (ALfloat
)values
[5];
1195 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1197 case AL_SEC_OFFSET_LATENCY_SOFT
:
1198 case AL_SEC_OFFSET_CLOCK_SOFT
:
1199 case AL_STEREO_ANGLES
:
1203 ERR("Unexpected property: 0x%04x\n", prop
);
1204 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1211 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1213 ALCdevice
*device
= Context
->Device
;
1214 ClockLatency clocktime
;
1222 *values
= Source
->Gain
;
1226 *values
= Source
->Pitch
;
1229 case AL_MAX_DISTANCE
:
1230 *values
= Source
->MaxDistance
;
1233 case AL_ROLLOFF_FACTOR
:
1234 *values
= Source
->RolloffFactor
;
1237 case AL_REFERENCE_DISTANCE
:
1238 *values
= Source
->RefDistance
;
1241 case AL_CONE_INNER_ANGLE
:
1242 *values
= Source
->InnerAngle
;
1245 case AL_CONE_OUTER_ANGLE
:
1246 *values
= Source
->OuterAngle
;
1250 *values
= Source
->MinGain
;
1254 *values
= Source
->MaxGain
;
1257 case AL_CONE_OUTER_GAIN
:
1258 *values
= Source
->OuterGain
;
1262 case AL_SAMPLE_OFFSET
:
1263 case AL_BYTE_OFFSET
:
1264 *values
= GetSourceOffset(Source
, prop
, Context
);
1267 case AL_CONE_OUTER_GAINHF
:
1268 *values
= Source
->OuterGainHF
;
1271 case AL_AIR_ABSORPTION_FACTOR
:
1272 *values
= Source
->AirAbsorptionFactor
;
1275 case AL_ROOM_ROLLOFF_FACTOR
:
1276 *values
= Source
->RoomRolloffFactor
;
1279 case AL_DOPPLER_FACTOR
:
1280 *values
= Source
->DopplerFactor
;
1283 case AL_SOURCE_RADIUS
:
1284 *values
= Source
->Radius
;
1287 case AL_STEREO_ANGLES
:
1288 values
[0] = Source
->StereoPan
[0];
1289 values
[1] = Source
->StereoPan
[1];
1292 case AL_SEC_OFFSET_LATENCY_SOFT
:
1293 /* Get the source offset with the clock time first. Then get the
1294 * clock time with the device latency. Order is important.
1296 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1297 almtx_lock(&device
->BackendLock
);
1298 clocktime
= V0(device
->Backend
,getClockLatency
)();
1299 almtx_unlock(&device
->BackendLock
);
1300 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1301 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1304 /* If the clock time incremented, reduce the latency by that
1305 * much since it's that much closer to the source offset it got
1308 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1309 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1314 case AL_SEC_OFFSET_CLOCK_SOFT
:
1315 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1316 values
[1] = srcclock
/ 1000000000.0;
1320 values
[0] = Source
->Position
[0];
1321 values
[1] = Source
->Position
[1];
1322 values
[2] = Source
->Position
[2];
1326 values
[0] = Source
->Velocity
[0];
1327 values
[1] = Source
->Velocity
[1];
1328 values
[2] = Source
->Velocity
[2];
1332 values
[0] = Source
->Direction
[0];
1333 values
[1] = Source
->Direction
[1];
1334 values
[2] = Source
->Direction
[2];
1337 case AL_ORIENTATION
:
1338 values
[0] = Source
->Orientation
[0][0];
1339 values
[1] = Source
->Orientation
[0][1];
1340 values
[2] = Source
->Orientation
[0][2];
1341 values
[3] = Source
->Orientation
[1][0];
1342 values
[4] = Source
->Orientation
[1][1];
1343 values
[5] = Source
->Orientation
[1][2];
1347 case AL_SOURCE_RELATIVE
:
1349 case AL_SOURCE_STATE
:
1350 case AL_BUFFERS_QUEUED
:
1351 case AL_BUFFERS_PROCESSED
:
1352 case AL_SOURCE_TYPE
:
1353 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1354 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1355 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1356 case AL_DIRECT_CHANNELS_SOFT
:
1357 case AL_DISTANCE_MODEL
:
1358 case AL_SOURCE_RESAMPLER_SOFT
:
1359 case AL_SOURCE_SPATIALIZE_SOFT
:
1360 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1361 *values
= (ALdouble
)ivals
[0];
1365 case AL_DIRECT_FILTER
:
1366 case AL_AUXILIARY_SEND_FILTER
:
1367 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1368 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1372 ERR("Unexpected property: 0x%04x\n", prop
);
1373 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1377 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1379 ALbufferlistitem
*BufferList
;
1385 case AL_SOURCE_RELATIVE
:
1386 *values
= Source
->HeadRelative
;
1390 *values
= Source
->Looping
;
1394 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1395 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1396 BufferList
->buffers
[0]->id
: 0;
1399 case AL_SOURCE_STATE
:
1400 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1403 case AL_BUFFERS_QUEUED
:
1404 if(!(BufferList
=Source
->queue
))
1410 count
+= BufferList
->num_buffers
;
1411 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1412 } while(BufferList
!= NULL
);
1417 case AL_BUFFERS_PROCESSED
:
1418 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1420 /* Buffers on a looping source are in a perpetual state of
1421 * PENDING, so don't report any as PROCESSED */
1426 const ALbufferlistitem
*BufferList
= Source
->queue
;
1427 const ALbufferlistitem
*Current
= NULL
;
1431 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1432 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
1433 else if(Source
->state
== AL_INITIAL
)
1434 Current
= BufferList
;
1436 while(BufferList
&& BufferList
!= Current
)
1438 played
+= BufferList
->num_buffers
;
1439 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1440 almemory_order_relaxed
);
1446 case AL_SOURCE_TYPE
:
1447 *values
= Source
->SourceType
;
1450 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1451 *values
= Source
->DryGainHFAuto
;
1454 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1455 *values
= Source
->WetGainAuto
;
1458 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1459 *values
= Source
->WetGainHFAuto
;
1462 case AL_DIRECT_CHANNELS_SOFT
:
1463 *values
= Source
->DirectChannels
;
1466 case AL_DISTANCE_MODEL
:
1467 *values
= Source
->DistanceModel
;
1470 case AL_SOURCE_RESAMPLER_SOFT
:
1471 *values
= Source
->Resampler
;
1474 case AL_SOURCE_SPATIALIZE_SOFT
:
1475 *values
= Source
->Spatialize
;
1478 /* 1x float/double */
1479 case AL_CONE_INNER_ANGLE
:
1480 case AL_CONE_OUTER_ANGLE
:
1485 case AL_REFERENCE_DISTANCE
:
1486 case AL_ROLLOFF_FACTOR
:
1487 case AL_CONE_OUTER_GAIN
:
1488 case AL_MAX_DISTANCE
:
1490 case AL_SAMPLE_OFFSET
:
1491 case AL_BYTE_OFFSET
:
1492 case AL_DOPPLER_FACTOR
:
1493 case AL_AIR_ABSORPTION_FACTOR
:
1494 case AL_ROOM_ROLLOFF_FACTOR
:
1495 case AL_CONE_OUTER_GAINHF
:
1496 case AL_SOURCE_RADIUS
:
1497 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1498 *values
= (ALint
)dvals
[0];
1501 /* 3x float/double */
1505 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1507 values
[0] = (ALint
)dvals
[0];
1508 values
[1] = (ALint
)dvals
[1];
1509 values
[2] = (ALint
)dvals
[2];
1513 /* 6x float/double */
1514 case AL_ORIENTATION
:
1515 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1517 values
[0] = (ALint
)dvals
[0];
1518 values
[1] = (ALint
)dvals
[1];
1519 values
[2] = (ALint
)dvals
[2];
1520 values
[3] = (ALint
)dvals
[3];
1521 values
[4] = (ALint
)dvals
[4];
1522 values
[5] = (ALint
)dvals
[5];
1526 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1527 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1528 break; /* i64 only */
1529 case AL_SEC_OFFSET_LATENCY_SOFT
:
1530 case AL_SEC_OFFSET_CLOCK_SOFT
:
1531 break; /* Double only */
1532 case AL_STEREO_ANGLES
:
1533 break; /* Float/double only */
1535 case AL_DIRECT_FILTER
:
1536 case AL_AUXILIARY_SEND_FILTER
:
1540 ERR("Unexpected property: 0x%04x\n", prop
);
1541 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1545 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1547 ALCdevice
*device
= Context
->Device
;
1548 ClockLatency clocktime
;
1556 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1557 /* Get the source offset with the clock time first. Then get the
1558 * clock time with the device latency. Order is important.
1560 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1561 almtx_lock(&device
->BackendLock
);
1562 clocktime
= V0(device
->Backend
,getClockLatency
)();
1563 almtx_unlock(&device
->BackendLock
);
1564 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1565 values
[1] = clocktime
.Latency
;
1568 /* If the clock time incremented, reduce the latency by that
1569 * much since it's that much closer to the source offset it got
1572 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1573 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1577 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1578 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1579 values
[1] = srcclock
;
1582 /* 1x float/double */
1583 case AL_CONE_INNER_ANGLE
:
1584 case AL_CONE_OUTER_ANGLE
:
1589 case AL_REFERENCE_DISTANCE
:
1590 case AL_ROLLOFF_FACTOR
:
1591 case AL_CONE_OUTER_GAIN
:
1592 case AL_MAX_DISTANCE
:
1594 case AL_SAMPLE_OFFSET
:
1595 case AL_BYTE_OFFSET
:
1596 case AL_DOPPLER_FACTOR
:
1597 case AL_AIR_ABSORPTION_FACTOR
:
1598 case AL_ROOM_ROLLOFF_FACTOR
:
1599 case AL_CONE_OUTER_GAINHF
:
1600 case AL_SOURCE_RADIUS
:
1601 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1602 *values
= (ALint64
)dvals
[0];
1605 /* 3x float/double */
1609 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1611 values
[0] = (ALint64
)dvals
[0];
1612 values
[1] = (ALint64
)dvals
[1];
1613 values
[2] = (ALint64
)dvals
[2];
1617 /* 6x float/double */
1618 case AL_ORIENTATION
:
1619 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1621 values
[0] = (ALint64
)dvals
[0];
1622 values
[1] = (ALint64
)dvals
[1];
1623 values
[2] = (ALint64
)dvals
[2];
1624 values
[3] = (ALint64
)dvals
[3];
1625 values
[4] = (ALint64
)dvals
[4];
1626 values
[5] = (ALint64
)dvals
[5];
1631 case AL_SOURCE_RELATIVE
:
1633 case AL_SOURCE_STATE
:
1634 case AL_BUFFERS_QUEUED
:
1635 case AL_BUFFERS_PROCESSED
:
1636 case AL_SOURCE_TYPE
:
1637 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1638 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1639 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1640 case AL_DIRECT_CHANNELS_SOFT
:
1641 case AL_DISTANCE_MODEL
:
1642 case AL_SOURCE_RESAMPLER_SOFT
:
1643 case AL_SOURCE_SPATIALIZE_SOFT
:
1644 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1650 case AL_DIRECT_FILTER
:
1651 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1652 *values
= (ALuint
)ivals
[0];
1656 case AL_AUXILIARY_SEND_FILTER
:
1657 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1659 values
[0] = (ALuint
)ivals
[0];
1660 values
[1] = (ALuint
)ivals
[1];
1661 values
[2] = (ALuint
)ivals
[2];
1665 case AL_SEC_OFFSET_LATENCY_SOFT
:
1666 case AL_SEC_OFFSET_CLOCK_SOFT
:
1667 break; /* Double only */
1668 case AL_STEREO_ANGLES
:
1669 break; /* Float/double only */
1672 ERR("Unexpected property: 0x%04x\n", prop
);
1673 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1678 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1680 ALCcontext
*context
;
1683 context
= GetContextRef();
1684 if(!context
) return;
1687 alSetError(context
, AL_INVALID_VALUE
, "Generating %d sources", n
);
1688 else for(cur
= 0;cur
< n
;cur
++)
1690 ALsource
*source
= AllocSource(context
);
1693 alDeleteSources(cur
, sources
);
1696 sources
[cur
] = source
->id
;
1699 ALCcontext_DecRef(context
);
1703 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1705 ALCcontext
*context
;
1709 context
= GetContextRef();
1710 if(!context
) return;
1712 LockSourceList(context
);
1714 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d sources", n
);
1716 /* Check that all Sources are valid */
1717 for(i
= 0;i
< n
;i
++)
1719 if(LookupSource(context
, sources
[i
]) == NULL
)
1720 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
1722 for(i
= 0;i
< n
;i
++)
1724 if((Source
=LookupSource(context
, sources
[i
])) != NULL
)
1725 FreeSource(context
, Source
);
1729 UnlockSourceList(context
);
1730 ALCcontext_DecRef(context
);
1734 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1736 ALCcontext
*context
;
1739 context
= GetContextRef();
1740 if(!context
) return AL_FALSE
;
1742 LockSourceList(context
);
1743 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1744 UnlockSourceList(context
);
1746 ALCcontext_DecRef(context
);
1752 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1754 ALCcontext
*Context
;
1757 Context
= GetContextRef();
1758 if(!Context
) return;
1760 almtx_lock(&Context
->PropLock
);
1761 LockSourceList(Context
);
1762 if((Source
=LookupSource(Context
, source
)) == NULL
)
1763 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1764 else if(!(FloatValsByProp(param
) == 1))
1765 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
1767 SetSourcefv(Source
, Context
, param
, &value
);
1768 UnlockSourceList(Context
);
1769 almtx_unlock(&Context
->PropLock
);
1771 ALCcontext_DecRef(Context
);
1774 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1776 ALCcontext
*Context
;
1779 Context
= GetContextRef();
1780 if(!Context
) return;
1782 almtx_lock(&Context
->PropLock
);
1783 LockSourceList(Context
);
1784 if((Source
=LookupSource(Context
, source
)) == NULL
)
1785 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1786 else if(!(FloatValsByProp(param
) == 3))
1787 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
1790 ALfloat fvals
[3] = { value1
, value2
, value3
};
1791 SetSourcefv(Source
, Context
, param
, fvals
);
1793 UnlockSourceList(Context
);
1794 almtx_unlock(&Context
->PropLock
);
1796 ALCcontext_DecRef(Context
);
1799 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1801 ALCcontext
*Context
;
1804 Context
= GetContextRef();
1805 if(!Context
) return;
1807 almtx_lock(&Context
->PropLock
);
1808 LockSourceList(Context
);
1809 if((Source
=LookupSource(Context
, source
)) == NULL
)
1810 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1812 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1813 else if(!(FloatValsByProp(param
) > 0))
1814 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
1816 SetSourcefv(Source
, Context
, param
, values
);
1817 UnlockSourceList(Context
);
1818 almtx_unlock(&Context
->PropLock
);
1820 ALCcontext_DecRef(Context
);
1824 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1826 ALCcontext
*Context
;
1829 Context
= GetContextRef();
1830 if(!Context
) return;
1832 almtx_lock(&Context
->PropLock
);
1833 LockSourceList(Context
);
1834 if((Source
=LookupSource(Context
, source
)) == NULL
)
1835 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1836 else if(!(DoubleValsByProp(param
) == 1))
1837 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
1840 ALfloat fval
= (ALfloat
)value
;
1841 SetSourcefv(Source
, Context
, param
, &fval
);
1843 UnlockSourceList(Context
);
1844 almtx_unlock(&Context
->PropLock
);
1846 ALCcontext_DecRef(Context
);
1849 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1851 ALCcontext
*Context
;
1854 Context
= GetContextRef();
1855 if(!Context
) return;
1857 almtx_lock(&Context
->PropLock
);
1858 LockSourceList(Context
);
1859 if((Source
=LookupSource(Context
, source
)) == NULL
)
1860 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1861 else if(!(DoubleValsByProp(param
) == 3))
1862 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
1865 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1866 SetSourcefv(Source
, Context
, param
, fvals
);
1868 UnlockSourceList(Context
);
1869 almtx_unlock(&Context
->PropLock
);
1871 ALCcontext_DecRef(Context
);
1874 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1876 ALCcontext
*Context
;
1880 Context
= GetContextRef();
1881 if(!Context
) return;
1883 almtx_lock(&Context
->PropLock
);
1884 LockSourceList(Context
);
1885 if((Source
=LookupSource(Context
, source
)) == NULL
)
1886 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1888 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1889 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1890 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
1896 for(i
= 0;i
< count
;i
++)
1897 fvals
[i
] = (ALfloat
)values
[i
];
1898 SetSourcefv(Source
, Context
, param
, fvals
);
1900 UnlockSourceList(Context
);
1901 almtx_unlock(&Context
->PropLock
);
1903 ALCcontext_DecRef(Context
);
1907 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1909 ALCcontext
*Context
;
1912 Context
= GetContextRef();
1913 if(!Context
) return;
1915 almtx_lock(&Context
->PropLock
);
1916 LockSourceList(Context
);
1917 if((Source
=LookupSource(Context
, source
)) == NULL
)
1918 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1919 else if(!(IntValsByProp(param
) == 1))
1920 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
1922 SetSourceiv(Source
, Context
, param
, &value
);
1923 UnlockSourceList(Context
);
1924 almtx_unlock(&Context
->PropLock
);
1926 ALCcontext_DecRef(Context
);
1929 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1931 ALCcontext
*Context
;
1934 Context
= GetContextRef();
1935 if(!Context
) return;
1937 almtx_lock(&Context
->PropLock
);
1938 LockSourceList(Context
);
1939 if((Source
=LookupSource(Context
, source
)) == NULL
)
1940 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1941 else if(!(IntValsByProp(param
) == 3))
1942 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
1945 ALint ivals
[3] = { value1
, value2
, value3
};
1946 SetSourceiv(Source
, Context
, param
, ivals
);
1948 UnlockSourceList(Context
);
1949 almtx_unlock(&Context
->PropLock
);
1951 ALCcontext_DecRef(Context
);
1954 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1956 ALCcontext
*Context
;
1959 Context
= GetContextRef();
1960 if(!Context
) return;
1962 almtx_lock(&Context
->PropLock
);
1963 LockSourceList(Context
);
1964 if((Source
=LookupSource(Context
, source
)) == NULL
)
1965 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1967 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1968 else if(!(IntValsByProp(param
) > 0))
1969 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
1971 SetSourceiv(Source
, Context
, param
, values
);
1972 UnlockSourceList(Context
);
1973 almtx_unlock(&Context
->PropLock
);
1975 ALCcontext_DecRef(Context
);
1979 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1981 ALCcontext
*Context
;
1984 Context
= GetContextRef();
1985 if(!Context
) return;
1987 almtx_lock(&Context
->PropLock
);
1988 LockSourceList(Context
);
1989 if((Source
=LookupSource(Context
, source
)) == NULL
)
1990 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1991 else if(!(Int64ValsByProp(param
) == 1))
1992 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
1994 SetSourcei64v(Source
, Context
, param
, &value
);
1995 UnlockSourceList(Context
);
1996 almtx_unlock(&Context
->PropLock
);
1998 ALCcontext_DecRef(Context
);
2001 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2003 ALCcontext
*Context
;
2006 Context
= GetContextRef();
2007 if(!Context
) return;
2009 almtx_lock(&Context
->PropLock
);
2010 LockSourceList(Context
);
2011 if((Source
=LookupSource(Context
, source
)) == NULL
)
2012 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2013 else if(!(Int64ValsByProp(param
) == 3))
2014 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2017 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2018 SetSourcei64v(Source
, Context
, param
, i64vals
);
2020 UnlockSourceList(Context
);
2021 almtx_unlock(&Context
->PropLock
);
2023 ALCcontext_DecRef(Context
);
2026 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2028 ALCcontext
*Context
;
2031 Context
= GetContextRef();
2032 if(!Context
) return;
2034 almtx_lock(&Context
->PropLock
);
2035 LockSourceList(Context
);
2036 if((Source
=LookupSource(Context
, source
)) == NULL
)
2037 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2039 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2040 else if(!(Int64ValsByProp(param
) > 0))
2041 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2043 SetSourcei64v(Source
, Context
, param
, values
);
2044 UnlockSourceList(Context
);
2045 almtx_unlock(&Context
->PropLock
);
2047 ALCcontext_DecRef(Context
);
2051 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2053 ALCcontext
*Context
;
2056 Context
= GetContextRef();
2057 if(!Context
) return;
2059 LockSourceList(Context
);
2060 if((Source
=LookupSource(Context
, source
)) == NULL
)
2061 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2063 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2064 else if(!(FloatValsByProp(param
) == 1))
2065 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2069 if(GetSourcedv(Source
, Context
, param
, &dval
))
2070 *value
= (ALfloat
)dval
;
2072 UnlockSourceList(Context
);
2074 ALCcontext_DecRef(Context
);
2078 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2080 ALCcontext
*Context
;
2083 Context
= GetContextRef();
2084 if(!Context
) return;
2086 LockSourceList(Context
);
2087 if((Source
=LookupSource(Context
, source
)) == NULL
)
2088 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2089 else if(!(value1
&& value2
&& value3
))
2090 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2091 else if(!(FloatValsByProp(param
) == 3))
2092 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2096 if(GetSourcedv(Source
, Context
, param
, dvals
))
2098 *value1
= (ALfloat
)dvals
[0];
2099 *value2
= (ALfloat
)dvals
[1];
2100 *value3
= (ALfloat
)dvals
[2];
2103 UnlockSourceList(Context
);
2105 ALCcontext_DecRef(Context
);
2109 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2111 ALCcontext
*Context
;
2115 Context
= GetContextRef();
2116 if(!Context
) return;
2118 LockSourceList(Context
);
2119 if((Source
=LookupSource(Context
, source
)) == NULL
)
2120 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2122 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2123 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2124 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2128 if(GetSourcedv(Source
, Context
, param
, dvals
))
2131 for(i
= 0;i
< count
;i
++)
2132 values
[i
] = (ALfloat
)dvals
[i
];
2135 UnlockSourceList(Context
);
2137 ALCcontext_DecRef(Context
);
2141 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2143 ALCcontext
*Context
;
2146 Context
= GetContextRef();
2147 if(!Context
) return;
2149 LockSourceList(Context
);
2150 if((Source
=LookupSource(Context
, source
)) == NULL
)
2151 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2153 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2154 else if(!(DoubleValsByProp(param
) == 1))
2155 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2157 GetSourcedv(Source
, Context
, param
, value
);
2158 UnlockSourceList(Context
);
2160 ALCcontext_DecRef(Context
);
2163 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2165 ALCcontext
*Context
;
2168 Context
= GetContextRef();
2169 if(!Context
) return;
2171 LockSourceList(Context
);
2172 if((Source
=LookupSource(Context
, source
)) == NULL
)
2173 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2174 else if(!(value1
&& value2
&& value3
))
2175 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2176 else if(!(DoubleValsByProp(param
) == 3))
2177 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2181 if(GetSourcedv(Source
, Context
, param
, dvals
))
2188 UnlockSourceList(Context
);
2190 ALCcontext_DecRef(Context
);
2193 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2195 ALCcontext
*Context
;
2198 Context
= GetContextRef();
2199 if(!Context
) return;
2201 LockSourceList(Context
);
2202 if((Source
=LookupSource(Context
, source
)) == NULL
)
2203 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2205 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2206 else if(!(DoubleValsByProp(param
) > 0))
2207 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2209 GetSourcedv(Source
, Context
, param
, values
);
2210 UnlockSourceList(Context
);
2212 ALCcontext_DecRef(Context
);
2216 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2218 ALCcontext
*Context
;
2221 Context
= GetContextRef();
2222 if(!Context
) return;
2224 LockSourceList(Context
);
2225 if((Source
=LookupSource(Context
, source
)) == NULL
)
2226 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2228 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2229 else if(!(IntValsByProp(param
) == 1))
2230 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2232 GetSourceiv(Source
, Context
, param
, value
);
2233 UnlockSourceList(Context
);
2235 ALCcontext_DecRef(Context
);
2239 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2241 ALCcontext
*Context
;
2244 Context
= GetContextRef();
2245 if(!Context
) return;
2247 LockSourceList(Context
);
2248 if((Source
=LookupSource(Context
, source
)) == NULL
)
2249 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2250 else if(!(value1
&& value2
&& value3
))
2251 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2252 else if(!(IntValsByProp(param
) == 3))
2253 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2257 if(GetSourceiv(Source
, Context
, param
, ivals
))
2264 UnlockSourceList(Context
);
2266 ALCcontext_DecRef(Context
);
2270 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2272 ALCcontext
*Context
;
2275 Context
= GetContextRef();
2276 if(!Context
) return;
2278 LockSourceList(Context
);
2279 if((Source
=LookupSource(Context
, source
)) == NULL
)
2280 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2282 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2283 else if(!(IntValsByProp(param
) > 0))
2284 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2286 GetSourceiv(Source
, Context
, param
, values
);
2287 UnlockSourceList(Context
);
2289 ALCcontext_DecRef(Context
);
2293 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2295 ALCcontext
*Context
;
2298 Context
= GetContextRef();
2299 if(!Context
) return;
2301 LockSourceList(Context
);
2302 if((Source
=LookupSource(Context
, source
)) == NULL
)
2303 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2305 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2306 else if(!(Int64ValsByProp(param
) == 1))
2307 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2309 GetSourcei64v(Source
, Context
, param
, value
);
2310 UnlockSourceList(Context
);
2312 ALCcontext_DecRef(Context
);
2315 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2317 ALCcontext
*Context
;
2320 Context
= GetContextRef();
2321 if(!Context
) return;
2323 LockSourceList(Context
);
2324 if((Source
=LookupSource(Context
, source
)) == NULL
)
2325 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2326 else if(!(value1
&& value2
&& value3
))
2327 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2328 else if(!(Int64ValsByProp(param
) == 3))
2329 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2333 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2335 *value1
= i64vals
[0];
2336 *value2
= i64vals
[1];
2337 *value3
= i64vals
[2];
2340 UnlockSourceList(Context
);
2342 ALCcontext_DecRef(Context
);
2345 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2347 ALCcontext
*Context
;
2350 Context
= GetContextRef();
2351 if(!Context
) return;
2353 LockSourceList(Context
);
2354 if((Source
=LookupSource(Context
, source
)) == NULL
)
2355 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2357 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2358 else if(!(Int64ValsByProp(param
) > 0))
2359 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2361 GetSourcei64v(Source
, Context
, param
, values
);
2362 UnlockSourceList(Context
);
2364 ALCcontext_DecRef(Context
);
2368 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2370 alSourcePlayv(1, &source
);
2372 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2374 ALCcontext
*context
;
2380 context
= GetContextRef();
2381 if(!context
) return;
2383 LockSourceList(context
);
2385 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Playing %d sources", n
);
2386 for(i
= 0;i
< n
;i
++)
2388 if(!LookupSource(context
, sources
[i
]))
2389 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2392 device
= context
->Device
;
2393 ALCdevice_Lock(device
);
2394 /* If the device is disconnected, go right to stopped. */
2395 if(!ATOMIC_LOAD(&device
->Connected
, almemory_order_acquire
))
2397 /* TODO: Send state change event? */
2398 for(i
= 0;i
< n
;i
++)
2400 source
= LookupSource(context
, sources
[i
]);
2401 source
->OffsetType
= AL_NONE
;
2402 source
->Offset
= 0.0;
2403 source
->state
= AL_STOPPED
;
2405 ALCdevice_Unlock(device
);
2409 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2411 ALsizei newcount
= context
->MaxVoices
<< 1;
2412 if(context
->MaxVoices
>= newcount
)
2414 ALCdevice_Unlock(device
);
2415 SETERR_GOTO(context
, AL_OUT_OF_MEMORY
, done
,
2416 "Overflow increasing voice count %d -> %d", context
->MaxVoices
, newcount
);
2418 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2421 for(i
= 0;i
< n
;i
++)
2423 ALbufferlistitem
*BufferList
;
2424 ALbuffer
*buffer
= NULL
;
2425 bool start_fading
= false;
2429 source
= LookupSource(context
, sources
[i
]);
2430 /* Check that there is a queue containing at least one valid, non zero
2433 BufferList
= source
->queue
;
2437 for(b
= 0;b
< BufferList
->num_buffers
;b
++)
2439 buffer
= BufferList
->buffers
[b
];
2440 if(buffer
&& buffer
->SampleLen
> 0) break;
2442 if(buffer
&& buffer
->SampleLen
> 0) break;
2443 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2446 /* If there's nothing to play, go right to stopped. */
2447 if(UNLIKELY(!BufferList
))
2449 /* NOTE: A source without any playable buffers should not have an
2450 * ALvoice since it shouldn't be in a playing or paused state. So
2451 * there's no need to look up its voice and clear the source.
2453 ALenum oldstate
= GetSourceState(source
, NULL
);
2454 source
->OffsetType
= AL_NONE
;
2455 source
->Offset
= 0.0;
2456 if(oldstate
!= AL_STOPPED
)
2458 source
->state
= AL_STOPPED
;
2459 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2464 voice
= GetSourceVoice(source
, context
);
2465 switch(GetSourceState(source
, voice
))
2468 assert(voice
!= NULL
);
2469 /* A source that's already playing is restarted from the beginning. */
2470 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2471 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2472 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2476 assert(voice
!= NULL
);
2477 /* A source that's paused simply resumes. */
2478 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2479 source
->state
= AL_PLAYING
;
2480 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2487 /* Make sure this source isn't already active, and if not, look for an
2488 * unused voice to put it in.
2490 assert(voice
== NULL
);
2491 for(j
= 0;j
< context
->VoiceCount
;j
++)
2493 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2500 vidx
= context
->VoiceCount
++;
2501 voice
= context
->Voices
[vidx
];
2502 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2504 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2505 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2507 /* A source that's not playing or paused has any offset applied when it
2511 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2513 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2514 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2515 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2516 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2517 if(source
->OffsetType
!= AL_NONE
)
2519 ApplyOffset(source
, voice
);
2520 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2521 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2522 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2525 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2526 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2528 /* Clear previous samples. */
2529 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2531 /* Clear the stepping value so the mixer knows not to mix this until
2532 * the update gets applied.
2536 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2537 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2538 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2539 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2540 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2541 if(device
->AvgSpeakerDist
> 0.0f
)
2543 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2544 (device
->AvgSpeakerDist
* device
->Frequency
);
2545 for(j
= 0;j
< voice
->NumChannels
;j
++)
2546 NfcFilterCreate(&voice
->Direct
.Params
[j
].NFCtrlFilter
, 0.0f
, w1
);
2549 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2550 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2551 source
->state
= AL_PLAYING
;
2552 source
->VoiceIdx
= vidx
;
2554 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2556 ALCdevice_Unlock(device
);
2559 UnlockSourceList(context
);
2560 ALCcontext_DecRef(context
);
2563 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2565 alSourcePausev(1, &source
);
2567 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2569 ALCcontext
*context
;
2575 context
= GetContextRef();
2576 if(!context
) return;
2578 LockSourceList(context
);
2580 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Pausing %d sources", n
);
2581 for(i
= 0;i
< n
;i
++)
2583 if(!LookupSource(context
, sources
[i
]))
2584 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2587 device
= context
->Device
;
2588 ALCdevice_Lock(device
);
2589 for(i
= 0;i
< n
;i
++)
2591 source
= LookupSource(context
, sources
[i
]);
2592 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2593 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2594 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2596 source
->state
= AL_PAUSED
;
2597 SendStateChangeEvent(context
, source
->id
, AL_PAUSED
);
2600 ALCdevice_Unlock(device
);
2603 UnlockSourceList(context
);
2604 ALCcontext_DecRef(context
);
2607 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2609 alSourceStopv(1, &source
);
2611 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2613 ALCcontext
*context
;
2619 context
= GetContextRef();
2620 if(!context
) return;
2622 LockSourceList(context
);
2624 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Stopping %d sources", n
);
2625 for(i
= 0;i
< n
;i
++)
2627 if(!LookupSource(context
, sources
[i
]))
2628 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2631 device
= context
->Device
;
2632 ALCdevice_Lock(device
);
2633 for(i
= 0;i
< n
;i
++)
2636 source
= LookupSource(context
, sources
[i
]);
2637 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2639 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2640 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2643 oldstate
= GetSourceState(source
, voice
);
2644 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2646 source
->state
= AL_STOPPED
;
2647 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2649 source
->OffsetType
= AL_NONE
;
2650 source
->Offset
= 0.0;
2652 ALCdevice_Unlock(device
);
2655 UnlockSourceList(context
);
2656 ALCcontext_DecRef(context
);
2659 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2661 alSourceRewindv(1, &source
);
2663 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2665 ALCcontext
*context
;
2671 context
= GetContextRef();
2672 if(!context
) return;
2674 LockSourceList(context
);
2676 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Rewinding %d sources", n
);
2677 for(i
= 0;i
< n
;i
++)
2679 if(!LookupSource(context
, sources
[i
]))
2680 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2683 device
= context
->Device
;
2684 ALCdevice_Lock(device
);
2685 for(i
= 0;i
< n
;i
++)
2687 source
= LookupSource(context
, sources
[i
]);
2688 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2690 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2691 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2694 if(GetSourceState(source
, voice
) != AL_INITIAL
)
2696 source
->state
= AL_INITIAL
;
2697 SendStateChangeEvent(context
, source
->id
, AL_INITIAL
);
2699 source
->OffsetType
= AL_NONE
;
2700 source
->Offset
= 0.0;
2702 ALCdevice_Unlock(device
);
2705 UnlockSourceList(context
);
2706 ALCcontext_DecRef(context
);
2710 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2713 ALCcontext
*context
;
2716 ALbufferlistitem
*BufferListStart
;
2717 ALbufferlistitem
*BufferList
;
2718 ALbuffer
*BufferFmt
= NULL
;
2723 context
= GetContextRef();
2724 if(!context
) return;
2726 device
= context
->Device
;
2728 LockSourceList(context
);
2730 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Queueing %d buffers", nb
);
2731 if((source
=LookupSource(context
, src
)) == NULL
)
2732 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2734 if(source
->SourceType
== AL_STATIC
)
2736 /* Can't queue on a Static Source */
2737 SETERR_GOTO(context
, AL_INVALID_OPERATION
, done
, "Queueing onto static source %u", src
);
2740 /* Check for a valid Buffer, for its frequency and format */
2741 BufferList
= source
->queue
;
2744 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2746 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2749 if(BufferFmt
) break;
2750 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2753 LockBufferList(device
);
2754 BufferListStart
= NULL
;
2756 for(i
= 0;i
< nb
;i
++)
2758 ALbuffer
*buffer
= NULL
;
2759 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2760 SETERR_GOTO(context
, AL_INVALID_NAME
, buffer_error
, "Queueing invalid buffer ID %u",
2763 if(!BufferListStart
)
2765 BufferListStart
= al_calloc(DEF_ALIGN
,
2766 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2767 BufferList
= BufferListStart
;
2771 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
,
2772 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2773 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2776 ATOMIC_INIT(&BufferList
->next
, NULL
);
2777 BufferList
->num_buffers
= 1;
2778 BufferList
->buffers
[0] = buffer
;
2779 if(!buffer
) continue;
2781 IncrementRef(&buffer
->ref
);
2783 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2784 SETERR_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
,
2785 "Queueing non-persistently mapped buffer %u", buffer
->id
);
2787 if(BufferFmt
== NULL
)
2789 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2790 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2791 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2793 alSetError(context
, AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
2796 /* A buffer failed (invalid ID or format), so unlock and release
2797 * each buffer we had. */
2798 while(BufferListStart
)
2800 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2801 almemory_order_relaxed
);
2802 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2804 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2805 DecrementRef(&buffer
->ref
);
2807 al_free(BufferListStart
);
2808 BufferListStart
= next
;
2810 UnlockBufferList(device
);
2814 /* All buffers good. */
2815 UnlockBufferList(device
);
2817 /* Source is now streaming */
2818 source
->SourceType
= AL_STREAMING
;
2820 if(!(BufferList
=source
->queue
))
2821 source
->queue
= BufferListStart
;
2824 ALbufferlistitem
*next
;
2825 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2827 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2831 UnlockSourceList(context
);
2832 ALCcontext_DecRef(context
);
2835 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2837 ALCcontext
*context
;
2839 ALbufferlistitem
*BufferList
;
2840 ALbufferlistitem
*Current
;
2844 context
= GetContextRef();
2845 if(!context
) return;
2847 LockSourceList(context
);
2849 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing %d buffers", nb
);
2850 if((source
=LookupSource(context
, src
)) == NULL
)
2851 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2853 /* Nothing to unqueue. */
2854 if(nb
== 0) goto done
;
2857 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from looping source %u", src
);
2858 if(source
->SourceType
!= AL_STREAMING
)
2859 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from a non-streaming source %u",
2862 /* Make sure enough buffers have been processed to unqueue. */
2863 BufferList
= source
->queue
;
2865 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2866 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
2867 else if(source
->state
== AL_INITIAL
)
2868 Current
= BufferList
;
2869 if(BufferList
== Current
)
2870 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2872 i
= BufferList
->num_buffers
;
2875 /* If the next bufferlist to check is NULL or is the current one, it's
2876 * trying to unqueue pending buffers.
2878 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2879 if(!next
|| next
== Current
)
2880 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2883 i
+= BufferList
->num_buffers
;
2888 ALbufferlistitem
*head
= source
->queue
;
2889 ALbufferlistitem
*next
= ATOMIC_LOAD(&head
->next
, almemory_order_relaxed
);
2890 for(i
= 0;i
< head
->num_buffers
&& nb
> 0;i
++,nb
--)
2892 ALbuffer
*buffer
= head
->buffers
[i
];
2897 *(buffers
++) = buffer
->id
;
2898 DecrementRef(&buffer
->ref
);
2901 if(i
< head
->num_buffers
)
2903 /* This head has some buffers left over, so move them to the front
2904 * and update the count.
2907 while(i
< head
->num_buffers
)
2908 head
->buffers
[j
++] = head
->buffers
[i
++];
2909 head
->num_buffers
= j
;
2913 /* Otherwise, free this item and set the source queue head to the next
2917 source
->queue
= next
;
2921 UnlockSourceList(context
);
2922 ALCcontext_DecRef(context
);
2926 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2930 Source
->InnerAngle
= 360.0f
;
2931 Source
->OuterAngle
= 360.0f
;
2932 Source
->Pitch
= 1.0f
;
2933 Source
->Position
[0] = 0.0f
;
2934 Source
->Position
[1] = 0.0f
;
2935 Source
->Position
[2] = 0.0f
;
2936 Source
->Velocity
[0] = 0.0f
;
2937 Source
->Velocity
[1] = 0.0f
;
2938 Source
->Velocity
[2] = 0.0f
;
2939 Source
->Direction
[0] = 0.0f
;
2940 Source
->Direction
[1] = 0.0f
;
2941 Source
->Direction
[2] = 0.0f
;
2942 Source
->Orientation
[0][0] = 0.0f
;
2943 Source
->Orientation
[0][1] = 0.0f
;
2944 Source
->Orientation
[0][2] = -1.0f
;
2945 Source
->Orientation
[1][0] = 0.0f
;
2946 Source
->Orientation
[1][1] = 1.0f
;
2947 Source
->Orientation
[1][2] = 0.0f
;
2948 Source
->RefDistance
= 1.0f
;
2949 Source
->MaxDistance
= FLT_MAX
;
2950 Source
->RolloffFactor
= 1.0f
;
2951 Source
->Gain
= 1.0f
;
2952 Source
->MinGain
= 0.0f
;
2953 Source
->MaxGain
= 1.0f
;
2954 Source
->OuterGain
= 0.0f
;
2955 Source
->OuterGainHF
= 1.0f
;
2957 Source
->DryGainHFAuto
= AL_TRUE
;
2958 Source
->WetGainAuto
= AL_TRUE
;
2959 Source
->WetGainHFAuto
= AL_TRUE
;
2960 Source
->AirAbsorptionFactor
= 0.0f
;
2961 Source
->RoomRolloffFactor
= 0.0f
;
2962 Source
->DopplerFactor
= 1.0f
;
2963 Source
->HeadRelative
= AL_FALSE
;
2964 Source
->Looping
= AL_FALSE
;
2965 Source
->DistanceModel
= DefaultDistanceModel
;
2966 Source
->Resampler
= ResamplerDefault
;
2967 Source
->DirectChannels
= AL_FALSE
;
2968 Source
->Spatialize
= SpatializeAuto
;
2970 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2971 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2973 Source
->Radius
= 0.0f
;
2975 Source
->Direct
.Gain
= 1.0f
;
2976 Source
->Direct
.GainHF
= 1.0f
;
2977 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2978 Source
->Direct
.GainLF
= 1.0f
;
2979 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2980 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2981 for(i
= 0;i
< num_sends
;i
++)
2983 Source
->Send
[i
].Slot
= NULL
;
2984 Source
->Send
[i
].Gain
= 1.0f
;
2985 Source
->Send
[i
].GainHF
= 1.0f
;
2986 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2987 Source
->Send
[i
].GainLF
= 1.0f
;
2988 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2991 Source
->Offset
= 0.0;
2992 Source
->OffsetType
= AL_NONE
;
2993 Source
->SourceType
= AL_UNDETERMINED
;
2994 Source
->state
= AL_INITIAL
;
2996 Source
->queue
= NULL
;
2998 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3001 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3003 Source
->VoiceIdx
= -1;
3006 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3008 ALbufferlistitem
*BufferList
;
3011 BufferList
= source
->queue
;
3012 while(BufferList
!= NULL
)
3014 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3015 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3017 if(BufferList
->buffers
[i
] != NULL
)
3018 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3020 al_free(BufferList
);
3023 source
->queue
= NULL
;
3027 for(i
= 0;i
< num_sends
;i
++)
3029 if(source
->Send
[i
].Slot
)
3030 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3031 source
->Send
[i
].Slot
= NULL
;
3033 al_free(source
->Send
);
3034 source
->Send
= NULL
;
3038 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3040 struct ALvoiceProps
*props
;
3043 /* Get an unused property container, or allocate a new one as needed. */
3044 props
= ATOMIC_LOAD(&context
->FreeVoiceProps
, almemory_order_acquire
);
3046 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3049 struct ALvoiceProps
*next
;
3051 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3052 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeVoiceProps
, &props
, next
,
3053 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3056 /* Copy in current property values. */
3057 props
->Pitch
= source
->Pitch
;
3058 props
->Gain
= source
->Gain
;
3059 props
->OuterGain
= source
->OuterGain
;
3060 props
->MinGain
= source
->MinGain
;
3061 props
->MaxGain
= source
->MaxGain
;
3062 props
->InnerAngle
= source
->InnerAngle
;
3063 props
->OuterAngle
= source
->OuterAngle
;
3064 props
->RefDistance
= source
->RefDistance
;
3065 props
->MaxDistance
= source
->MaxDistance
;
3066 props
->RolloffFactor
= source
->RolloffFactor
;
3067 for(i
= 0;i
< 3;i
++)
3068 props
->Position
[i
] = source
->Position
[i
];
3069 for(i
= 0;i
< 3;i
++)
3070 props
->Velocity
[i
] = source
->Velocity
[i
];
3071 for(i
= 0;i
< 3;i
++)
3072 props
->Direction
[i
] = source
->Direction
[i
];
3073 for(i
= 0;i
< 2;i
++)
3076 for(j
= 0;j
< 3;j
++)
3077 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3079 props
->HeadRelative
= source
->HeadRelative
;
3080 props
->DistanceModel
= source
->DistanceModel
;
3081 props
->Resampler
= source
->Resampler
;
3082 props
->DirectChannels
= source
->DirectChannels
;
3083 props
->SpatializeMode
= source
->Spatialize
;
3085 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3086 props
->WetGainAuto
= source
->WetGainAuto
;
3087 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3088 props
->OuterGainHF
= source
->OuterGainHF
;
3090 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3091 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3092 props
->DopplerFactor
= source
->DopplerFactor
;
3094 props
->StereoPan
[0] = source
->StereoPan
[0];
3095 props
->StereoPan
[1] = source
->StereoPan
[1];
3097 props
->Radius
= source
->Radius
;
3099 props
->Direct
.Gain
= source
->Direct
.Gain
;
3100 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3101 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3102 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3103 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3105 for(i
= 0;i
< num_sends
;i
++)
3107 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3108 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3109 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3110 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3111 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3112 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3115 /* Set the new container for updating internal parameters. */
3116 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3119 /* If there was an unused update container, put it back in the
3122 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &context
->FreeVoiceProps
, props
);
3126 void UpdateAllSourceProps(ALCcontext
*context
)
3128 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3131 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3133 ALvoice
*voice
= context
->Voices
[pos
];
3134 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3135 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3136 UpdateSourceProps(source
, voice
, num_sends
, context
);
3141 /* GetSourceSampleOffset
3143 * Gets the current read offset for the given Source, in 32.32 fixed-point
3144 * samples. The offset is relative to the start of the queue (not the start of
3145 * the current buffer).
3147 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3149 ALCdevice
*device
= context
->Device
;
3150 const ALbufferlistitem
*Current
;
3158 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3160 *clocktime
= GetDeviceClockTime(device
);
3162 voice
= GetSourceVoice(Source
, context
);
3165 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3167 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3168 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3171 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3172 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3176 const ALbufferlistitem
*BufferList
= Source
->queue
;
3177 while(BufferList
&& BufferList
!= Current
)
3179 ALsizei max_len
= 0;
3182 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3184 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3185 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3187 readPos
+= (ALuint64
)max_len
<< 32;
3188 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3189 almemory_order_relaxed
);
3191 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3194 return (ALint64
)readPos
;
3197 /* GetSourceSecOffset
3199 * Gets the current read offset for the given Source, in seconds. The offset is
3200 * relative to the start of the queue (not the start of the current buffer).
3202 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3204 ALCdevice
*device
= context
->Device
;
3205 const ALbufferlistitem
*Current
;
3214 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3216 *clocktime
= GetDeviceClockTime(device
);
3218 voice
= GetSourceVoice(Source
, context
);
3221 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3223 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3225 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3227 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3228 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3233 const ALbufferlistitem
*BufferList
= Source
->queue
;
3234 const ALbuffer
*BufferFmt
= NULL
;
3235 while(BufferList
&& BufferList
!= Current
)
3237 ALsizei max_len
= 0;
3240 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3242 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3245 if(!BufferFmt
) BufferFmt
= buffer
;
3246 max_len
= maxi(max_len
, buffer
->SampleLen
);
3249 readPos
+= (ALuint64
)max_len
<< FRACTIONBITS
;
3250 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3251 almemory_order_relaxed
);
3254 while(BufferList
&& !BufferFmt
)
3257 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3258 BufferFmt
= BufferList
->buffers
[i
];
3259 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3260 almemory_order_relaxed
);
3262 assert(BufferFmt
!= NULL
);
3264 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3265 (ALdouble
)BufferFmt
->Frequency
;
3273 * Gets the current read offset for the given Source, in the appropriate format
3274 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3275 * queue (not the start of the current buffer).
3277 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3279 ALCdevice
*device
= context
->Device
;
3280 const ALbufferlistitem
*Current
;
3282 ALsizei readPosFrac
;
3289 readPos
= readPosFrac
= 0;
3290 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3292 voice
= GetSourceVoice(Source
, context
);
3295 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3297 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3298 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3300 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3301 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3306 const ALbufferlistitem
*BufferList
= Source
->queue
;
3307 const ALbuffer
*BufferFmt
= NULL
;
3308 ALboolean readFin
= AL_FALSE
;
3309 ALuint totalBufferLen
= 0;
3311 while(BufferList
!= NULL
)
3313 ALsizei max_len
= 0;
3316 readFin
= readFin
|| (BufferList
== Current
);
3317 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3319 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3322 if(!BufferFmt
) BufferFmt
= buffer
;
3323 max_len
= maxi(max_len
, buffer
->SampleLen
);
3326 totalBufferLen
+= max_len
;
3327 if(!readFin
) readPos
+= max_len
;
3329 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3330 almemory_order_relaxed
);
3332 assert(BufferFmt
!= NULL
);
3335 readPos
%= totalBufferLen
;
3338 /* Wrap back to 0 */
3339 if(readPos
>= totalBufferLen
)
3340 readPos
= readPosFrac
= 0;
3347 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3350 case AL_SAMPLE_OFFSET
:
3351 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3354 case AL_BYTE_OFFSET
:
3355 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3357 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3358 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3359 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3361 /* Round down to nearest ADPCM block */
3362 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3364 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3366 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3367 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3368 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3370 /* Round down to nearest ADPCM block */
3371 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3375 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
3376 BufferFmt
->FmtType
);
3377 offset
= (ALdouble
)(readPos
* FrameSize
);
3389 * Apply the stored playback offset to the Source. This function will update
3390 * the number of buffers "played" given the stored offset.
3392 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3394 ALbufferlistitem
*BufferList
;
3395 ALuint bufferLen
, totalBufferLen
;
3399 /* Get sample frame offset */
3400 if(!GetSampleOffset(Source
, &offset
, &frac
))
3404 BufferList
= Source
->queue
;
3405 while(BufferList
&& totalBufferLen
<= offset
)
3407 ALsizei max_len
= 0;
3410 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3412 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3413 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3415 bufferLen
= max_len
;
3417 if(bufferLen
> offset
-totalBufferLen
)
3419 /* Offset is in this buffer */
3420 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3421 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3422 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3426 totalBufferLen
+= bufferLen
;
3428 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3431 /* Offset is out of range of the queue */
3438 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3439 * or Second offset supplied by the application). This takes into account the
3440 * fact that the buffer format may have been modifed since.
3442 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3444 const ALbuffer
*BufferFmt
= NULL
;
3445 const ALbufferlistitem
*BufferList
;
3446 ALdouble dbloff
, dblfrac
;
3448 /* Find the first valid Buffer in the Queue */
3449 BufferList
= Source
->queue
;
3453 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3454 BufferFmt
= BufferList
->buffers
[i
];
3455 if(BufferFmt
) break;
3456 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3457 almemory_order_relaxed
);
3461 Source
->OffsetType
= AL_NONE
;
3462 Source
->Offset
= 0.0;
3466 switch(Source
->OffsetType
)
3468 case AL_BYTE_OFFSET
:
3469 /* Determine the ByteOffset (and ensure it is block aligned) */
3470 *offset
= (ALuint
)Source
->Offset
;
3471 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3473 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3474 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3475 *offset
*= BufferFmt
->OriginalAlign
;
3477 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3479 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3480 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3481 *offset
*= BufferFmt
->OriginalAlign
;
3484 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
3488 case AL_SAMPLE_OFFSET
:
3489 dblfrac
= modf(Source
->Offset
, &dbloff
);
3490 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3491 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3495 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3496 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3497 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3500 Source
->OffsetType
= AL_NONE
;
3501 Source
->Offset
= 0.0;
3507 static ALsource
*AllocSource(ALCcontext
*context
)
3509 ALCdevice
*device
= context
->Device
;
3510 SourceSubList
*sublist
, *subend
;
3511 ALsource
*source
= NULL
;
3515 almtx_lock(&context
->SourceLock
);
3516 if(context
->NumSources
>= device
->SourcesMax
)
3518 almtx_unlock(&context
->SourceLock
);
3519 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
3522 sublist
= VECTOR_BEGIN(context
->SourceList
);
3523 subend
= VECTOR_END(context
->SourceList
);
3524 for(;sublist
!= subend
;++sublist
)
3526 if(sublist
->FreeMask
)
3528 slidx
= CTZ64(sublist
->FreeMask
);
3529 source
= sublist
->Sources
+ slidx
;
3534 if(UNLIKELY(!source
))
3536 const SourceSubList empty_sublist
= { 0, NULL
};
3537 /* Don't allocate so many list entries that the 32-bit ID could
3540 if(UNLIKELY(VECTOR_SIZE(context
->SourceList
) >= 1<<25))
3542 almtx_unlock(&device
->BufferLock
);
3543 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
3546 lidx
= (ALsizei
)VECTOR_SIZE(context
->SourceList
);
3547 VECTOR_PUSH_BACK(context
->SourceList
, empty_sublist
);
3548 sublist
= &VECTOR_BACK(context
->SourceList
);
3549 sublist
->FreeMask
= ~U64(0);
3550 sublist
->Sources
= al_calloc(16, sizeof(ALsource
)*64);
3551 if(UNLIKELY(!sublist
->Sources
))
3553 VECTOR_POP_BACK(context
->SourceList
);
3554 almtx_unlock(&context
->SourceLock
);
3555 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
3560 source
= sublist
->Sources
+ slidx
;
3563 memset(source
, 0, sizeof(*source
));
3564 InitSourceParams(source
, device
->NumAuxSends
);
3566 /* Add 1 to avoid source ID 0. */
3567 source
->id
= ((lidx
<<6) | slidx
) + 1;
3569 context
->NumSources
++;
3570 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
3571 almtx_unlock(&context
->SourceLock
);
3576 static void FreeSource(ALCcontext
*context
, ALsource
*source
)
3578 ALCdevice
*device
= context
->Device
;
3579 ALuint id
= source
->id
- 1;
3580 ALsizei lidx
= id
>> 6;
3581 ALsizei slidx
= id
& 0x3f;
3584 ALCdevice_Lock(device
);
3585 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
3587 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
3588 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3590 ALCdevice_Unlock(device
);
3592 DeinitSource(source
, device
->NumAuxSends
);
3593 memset(source
, 0, sizeof(*source
));
3595 VECTOR_ELEM(context
->SourceList
, lidx
).FreeMask
|= U64(1) << slidx
;
3596 context
->NumSources
--;
3601 * Destroys all sources in the source map.
3603 ALvoid
ReleaseALSources(ALCcontext
*context
)
3605 ALCdevice
*device
= context
->Device
;
3606 SourceSubList
*sublist
= VECTOR_BEGIN(context
->SourceList
);
3607 SourceSubList
*subend
= VECTOR_END(context
->SourceList
);
3608 size_t leftover
= 0;
3609 for(;sublist
!= subend
;++sublist
)
3611 ALuint64 usemask
= ~sublist
->FreeMask
;
3614 ALsizei idx
= CTZ64(usemask
);
3615 ALsource
*source
= sublist
->Sources
+ idx
;
3617 DeinitSource(source
, device
->NumAuxSends
);
3618 memset(source
, 0, sizeof(*source
));
3621 usemask
&= ~(U64(1) << idx
);
3623 sublist
->FreeMask
= ~usemask
;
3626 WARN("(%p) Deleted "SZFMT
" Source%s\n", device
, leftover
, (leftover
==1)?"":"s");