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(context
->AsyncEvents
, (const char*)&evt
, 1) == 1)
252 alsem_post(&context
->EventSem
);
256 static ALint
FloatValsByProp(ALenum prop
)
258 if(prop
!= (ALenum
)((SourceProp
)prop
))
260 switch((SourceProp
)prop
)
266 case AL_MAX_DISTANCE
:
267 case AL_ROLLOFF_FACTOR
:
268 case AL_DOPPLER_FACTOR
:
269 case AL_CONE_OUTER_GAIN
:
271 case AL_SAMPLE_OFFSET
:
273 case AL_CONE_INNER_ANGLE
:
274 case AL_CONE_OUTER_ANGLE
:
275 case AL_REFERENCE_DISTANCE
:
276 case AL_CONE_OUTER_GAINHF
:
277 case AL_AIR_ABSORPTION_FACTOR
:
278 case AL_ROOM_ROLLOFF_FACTOR
:
279 case AL_DIRECT_FILTER_GAINHF_AUTO
:
280 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
281 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
282 case AL_DIRECT_CHANNELS_SOFT
:
283 case AL_DISTANCE_MODEL
:
284 case AL_SOURCE_RELATIVE
:
286 case AL_SOURCE_STATE
:
287 case AL_BUFFERS_QUEUED
:
288 case AL_BUFFERS_PROCESSED
:
290 case AL_SOURCE_RADIUS
:
291 case AL_SOURCE_RESAMPLER_SOFT
:
292 case AL_SOURCE_SPATIALIZE_SOFT
:
295 case AL_STEREO_ANGLES
:
306 case AL_SEC_OFFSET_LATENCY_SOFT
:
307 case AL_SEC_OFFSET_CLOCK_SOFT
:
308 break; /* Double only */
311 case AL_DIRECT_FILTER
:
312 case AL_AUXILIARY_SEND_FILTER
:
313 break; /* i/i64 only */
314 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
315 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
316 break; /* i64 only */
320 static ALint
DoubleValsByProp(ALenum prop
)
322 if(prop
!= (ALenum
)((SourceProp
)prop
))
324 switch((SourceProp
)prop
)
330 case AL_MAX_DISTANCE
:
331 case AL_ROLLOFF_FACTOR
:
332 case AL_DOPPLER_FACTOR
:
333 case AL_CONE_OUTER_GAIN
:
335 case AL_SAMPLE_OFFSET
:
337 case AL_CONE_INNER_ANGLE
:
338 case AL_CONE_OUTER_ANGLE
:
339 case AL_REFERENCE_DISTANCE
:
340 case AL_CONE_OUTER_GAINHF
:
341 case AL_AIR_ABSORPTION_FACTOR
:
342 case AL_ROOM_ROLLOFF_FACTOR
:
343 case AL_DIRECT_FILTER_GAINHF_AUTO
:
344 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
345 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
346 case AL_DIRECT_CHANNELS_SOFT
:
347 case AL_DISTANCE_MODEL
:
348 case AL_SOURCE_RELATIVE
:
350 case AL_SOURCE_STATE
:
351 case AL_BUFFERS_QUEUED
:
352 case AL_BUFFERS_PROCESSED
:
354 case AL_SOURCE_RADIUS
:
355 case AL_SOURCE_RESAMPLER_SOFT
:
356 case AL_SOURCE_SPATIALIZE_SOFT
:
359 case AL_SEC_OFFSET_LATENCY_SOFT
:
360 case AL_SEC_OFFSET_CLOCK_SOFT
:
361 case AL_STEREO_ANGLES
:
373 case AL_DIRECT_FILTER
:
374 case AL_AUXILIARY_SEND_FILTER
:
375 break; /* i/i64 only */
376 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
377 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
378 break; /* i64 only */
383 static ALint
IntValsByProp(ALenum prop
)
385 if(prop
!= (ALenum
)((SourceProp
)prop
))
387 switch((SourceProp
)prop
)
393 case AL_MAX_DISTANCE
:
394 case AL_ROLLOFF_FACTOR
:
395 case AL_DOPPLER_FACTOR
:
396 case AL_CONE_OUTER_GAIN
:
398 case AL_SAMPLE_OFFSET
:
400 case AL_CONE_INNER_ANGLE
:
401 case AL_CONE_OUTER_ANGLE
:
402 case AL_REFERENCE_DISTANCE
:
403 case AL_CONE_OUTER_GAINHF
:
404 case AL_AIR_ABSORPTION_FACTOR
:
405 case AL_ROOM_ROLLOFF_FACTOR
:
406 case AL_DIRECT_FILTER_GAINHF_AUTO
:
407 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
408 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
409 case AL_DIRECT_CHANNELS_SOFT
:
410 case AL_DISTANCE_MODEL
:
411 case AL_SOURCE_RELATIVE
:
414 case AL_SOURCE_STATE
:
415 case AL_BUFFERS_QUEUED
:
416 case AL_BUFFERS_PROCESSED
:
418 case AL_DIRECT_FILTER
:
419 case AL_SOURCE_RADIUS
:
420 case AL_SOURCE_RESAMPLER_SOFT
:
421 case AL_SOURCE_SPATIALIZE_SOFT
:
427 case AL_AUXILIARY_SEND_FILTER
:
433 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
434 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
435 break; /* i64 only */
436 case AL_SEC_OFFSET_LATENCY_SOFT
:
437 case AL_SEC_OFFSET_CLOCK_SOFT
:
438 break; /* Double only */
439 case AL_STEREO_ANGLES
:
440 break; /* Float/double only */
444 static ALint
Int64ValsByProp(ALenum prop
)
446 if(prop
!= (ALenum
)((SourceProp
)prop
))
448 switch((SourceProp
)prop
)
454 case AL_MAX_DISTANCE
:
455 case AL_ROLLOFF_FACTOR
:
456 case AL_DOPPLER_FACTOR
:
457 case AL_CONE_OUTER_GAIN
:
459 case AL_SAMPLE_OFFSET
:
461 case AL_CONE_INNER_ANGLE
:
462 case AL_CONE_OUTER_ANGLE
:
463 case AL_REFERENCE_DISTANCE
:
464 case AL_CONE_OUTER_GAINHF
:
465 case AL_AIR_ABSORPTION_FACTOR
:
466 case AL_ROOM_ROLLOFF_FACTOR
:
467 case AL_DIRECT_FILTER_GAINHF_AUTO
:
468 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
469 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
470 case AL_DIRECT_CHANNELS_SOFT
:
471 case AL_DISTANCE_MODEL
:
472 case AL_SOURCE_RELATIVE
:
475 case AL_SOURCE_STATE
:
476 case AL_BUFFERS_QUEUED
:
477 case AL_BUFFERS_PROCESSED
:
479 case AL_DIRECT_FILTER
:
480 case AL_SOURCE_RADIUS
:
481 case AL_SOURCE_RESAMPLER_SOFT
:
482 case AL_SOURCE_SPATIALIZE_SOFT
:
485 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
486 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
492 case AL_AUXILIARY_SEND_FILTER
:
498 case AL_SEC_OFFSET_LATENCY_SOFT
:
499 case AL_SEC_OFFSET_CLOCK_SOFT
:
500 break; /* Double only */
501 case AL_STEREO_ANGLES
:
502 break; /* Float/double only */
508 #define CHECKVAL(x) do { \
511 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
516 #define DO_UPDATEPROPS() do { \
518 if(SourceShouldUpdate(Source, Context) && \
519 (voice=GetSourceVoice(Source, Context)) != NULL) \
520 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
522 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
525 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
527 ALCdevice
*device
= Context
->Device
;
532 case AL_SEC_OFFSET_LATENCY_SOFT
:
533 case AL_SEC_OFFSET_CLOCK_SOFT
:
535 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
536 "Setting read-only source property 0x%04x", prop
);
539 CHECKVAL(*values
>= 0.0f
);
541 Source
->Pitch
= *values
;
545 case AL_CONE_INNER_ANGLE
:
546 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
548 Source
->InnerAngle
= *values
;
552 case AL_CONE_OUTER_ANGLE
:
553 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
555 Source
->OuterAngle
= *values
;
560 CHECKVAL(*values
>= 0.0f
);
562 Source
->Gain
= *values
;
566 case AL_MAX_DISTANCE
:
567 CHECKVAL(*values
>= 0.0f
);
569 Source
->MaxDistance
= *values
;
573 case AL_ROLLOFF_FACTOR
:
574 CHECKVAL(*values
>= 0.0f
);
576 Source
->RolloffFactor
= *values
;
580 case AL_REFERENCE_DISTANCE
:
581 CHECKVAL(*values
>= 0.0f
);
583 Source
->RefDistance
= *values
;
588 CHECKVAL(*values
>= 0.0f
);
590 Source
->MinGain
= *values
;
595 CHECKVAL(*values
>= 0.0f
);
597 Source
->MaxGain
= *values
;
601 case AL_CONE_OUTER_GAIN
:
602 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
604 Source
->OuterGain
= *values
;
608 case AL_CONE_OUTER_GAINHF
:
609 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
611 Source
->OuterGainHF
= *values
;
615 case AL_AIR_ABSORPTION_FACTOR
:
616 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
618 Source
->AirAbsorptionFactor
= *values
;
622 case AL_ROOM_ROLLOFF_FACTOR
:
623 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
625 Source
->RoomRolloffFactor
= *values
;
629 case AL_DOPPLER_FACTOR
:
630 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
632 Source
->DopplerFactor
= *values
;
637 case AL_SAMPLE_OFFSET
:
639 CHECKVAL(*values
>= 0.0f
);
641 Source
->OffsetType
= prop
;
642 Source
->Offset
= *values
;
644 if(IsPlayingOrPaused(Source
))
648 ALCdevice_Lock(Context
->Device
);
649 /* Double-check that the source is still playing while we have
652 voice
= GetSourceVoice(Source
, Context
);
655 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
657 ALCdevice_Unlock(Context
->Device
);
658 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid offset");
661 ALCdevice_Unlock(Context
->Device
);
665 case AL_SOURCE_RADIUS
:
666 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
668 Source
->Radius
= *values
;
672 case AL_STEREO_ANGLES
:
673 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
675 Source
->StereoPan
[0] = values
[0];
676 Source
->StereoPan
[1] = values
[1];
682 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
684 Source
->Position
[0] = values
[0];
685 Source
->Position
[1] = values
[1];
686 Source
->Position
[2] = values
[2];
691 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
693 Source
->Velocity
[0] = values
[0];
694 Source
->Velocity
[1] = values
[1];
695 Source
->Velocity
[2] = values
[2];
700 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
702 Source
->Direction
[0] = values
[0];
703 Source
->Direction
[1] = values
[1];
704 Source
->Direction
[2] = values
[2];
709 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
710 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
712 Source
->Orientation
[0][0] = values
[0];
713 Source
->Orientation
[0][1] = values
[1];
714 Source
->Orientation
[0][2] = values
[2];
715 Source
->Orientation
[1][0] = values
[3];
716 Source
->Orientation
[1][1] = values
[4];
717 Source
->Orientation
[1][2] = values
[5];
722 case AL_SOURCE_RELATIVE
:
724 case AL_SOURCE_STATE
:
726 case AL_DISTANCE_MODEL
:
727 case AL_DIRECT_FILTER_GAINHF_AUTO
:
728 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
729 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
730 case AL_DIRECT_CHANNELS_SOFT
:
731 case AL_SOURCE_RESAMPLER_SOFT
:
732 case AL_SOURCE_SPATIALIZE_SOFT
:
733 ival
= (ALint
)values
[0];
734 return SetSourceiv(Source
, Context
, prop
, &ival
);
736 case AL_BUFFERS_QUEUED
:
737 case AL_BUFFERS_PROCESSED
:
738 ival
= (ALint
)((ALuint
)values
[0]);
739 return SetSourceiv(Source
, Context
, prop
, &ival
);
742 case AL_DIRECT_FILTER
:
743 case AL_AUXILIARY_SEND_FILTER
:
744 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
745 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
749 ERR("Unexpected property: 0x%04x\n", prop
);
750 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source float property 0x%04x", prop
);
753 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
755 ALCdevice
*device
= Context
->Device
;
756 ALbuffer
*buffer
= NULL
;
757 ALfilter
*filter
= NULL
;
758 ALeffectslot
*slot
= NULL
;
759 ALbufferlistitem
*oldlist
;
764 case AL_SOURCE_STATE
:
766 case AL_BUFFERS_QUEUED
:
767 case AL_BUFFERS_PROCESSED
:
769 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
770 "Setting read-only source property 0x%04x", prop
);
772 case AL_SOURCE_RELATIVE
:
773 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
775 Source
->HeadRelative
= (ALboolean
)*values
;
780 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
782 Source
->Looping
= (ALboolean
)*values
;
783 if(IsPlayingOrPaused(Source
))
785 ALvoice
*voice
= GetSourceVoice(Source
, Context
);
789 ATOMIC_STORE(&voice
->loop_buffer
, Source
->queue
, almemory_order_release
);
791 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_release
);
793 /* If the source is playing, wait for the current mix to finish
794 * to ensure it isn't currently looping back or reaching the
797 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
804 LockBufferList(device
);
805 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
807 UnlockBufferList(device
);
808 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
812 if(buffer
&& buffer
->MappedAccess
!= 0 &&
813 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
815 UnlockBufferList(device
);
816 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
817 "Setting non-persistently mapped buffer %u", buffer
->id
);
821 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
822 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
824 UnlockBufferList(device
);
825 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
826 "Setting buffer on playing or paused source %u", Source
->id
);
830 oldlist
= Source
->queue
;
833 /* Add the selected buffer to a one-item queue */
834 ALbufferlistitem
*newlist
= al_calloc(DEF_ALIGN
,
835 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
836 ATOMIC_INIT(&newlist
->next
, NULL
);
837 newlist
->num_buffers
= 1;
838 newlist
->buffers
[0] = buffer
;
839 IncrementRef(&buffer
->ref
);
841 /* Source is now Static */
842 Source
->SourceType
= AL_STATIC
;
843 Source
->queue
= newlist
;
847 /* Source is now Undetermined */
848 Source
->SourceType
= AL_UNDETERMINED
;
849 Source
->queue
= NULL
;
851 UnlockBufferList(device
);
853 /* Delete all elements in the previous queue */
854 while(oldlist
!= NULL
)
857 ALbufferlistitem
*temp
= oldlist
;
858 oldlist
= ATOMIC_LOAD(&temp
->next
, almemory_order_relaxed
);
860 for(i
= 0;i
< temp
->num_buffers
;i
++)
863 DecrementRef(&temp
->buffers
[i
]->ref
);
870 case AL_SAMPLE_OFFSET
:
872 CHECKVAL(*values
>= 0);
874 Source
->OffsetType
= prop
;
875 Source
->Offset
= *values
;
877 if(IsPlayingOrPaused(Source
))
881 ALCdevice_Lock(Context
->Device
);
882 voice
= GetSourceVoice(Source
, Context
);
885 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
887 ALCdevice_Unlock(Context
->Device
);
888 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
889 "Invalid source offset");
892 ALCdevice_Unlock(Context
->Device
);
896 case AL_DIRECT_FILTER
:
897 LockFilterList(device
);
898 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
900 UnlockFilterList(device
);
901 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
907 Source
->Direct
.Gain
= 1.0f
;
908 Source
->Direct
.GainHF
= 1.0f
;
909 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
910 Source
->Direct
.GainLF
= 1.0f
;
911 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
915 Source
->Direct
.Gain
= filter
->Gain
;
916 Source
->Direct
.GainHF
= filter
->GainHF
;
917 Source
->Direct
.HFReference
= filter
->HFReference
;
918 Source
->Direct
.GainLF
= filter
->GainLF
;
919 Source
->Direct
.LFReference
= filter
->LFReference
;
921 UnlockFilterList(device
);
925 case AL_DIRECT_FILTER_GAINHF_AUTO
:
926 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
928 Source
->DryGainHFAuto
= *values
;
932 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
933 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
935 Source
->WetGainAuto
= *values
;
939 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
940 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
942 Source
->WetGainHFAuto
= *values
;
946 case AL_DIRECT_CHANNELS_SOFT
:
947 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
949 Source
->DirectChannels
= *values
;
953 case AL_DISTANCE_MODEL
:
954 CHECKVAL(*values
== AL_NONE
||
955 *values
== AL_INVERSE_DISTANCE
||
956 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
957 *values
== AL_LINEAR_DISTANCE
||
958 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
959 *values
== AL_EXPONENT_DISTANCE
||
960 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
962 Source
->DistanceModel
= *values
;
963 if(Context
->SourceDistanceModel
)
967 case AL_SOURCE_RESAMPLER_SOFT
:
968 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
970 Source
->Resampler
= *values
;
974 case AL_SOURCE_SPATIALIZE_SOFT
:
975 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
977 Source
->Spatialize
= *values
;
982 case AL_AUXILIARY_SEND_FILTER
:
983 LockEffectSlotList(Context
);
984 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
))
986 UnlockEffectSlotList(Context
);
987 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
990 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
))
992 UnlockEffectSlotList(Context
);
993 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
995 LockFilterList(device
);
996 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
))
998 UnlockFilterList(device
);
999 UnlockEffectSlotList(Context
);
1000 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1006 /* Disable filter */
1007 Source
->Send
[values
[1]].Gain
= 1.0f
;
1008 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1009 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1010 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1011 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1015 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1016 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1017 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1018 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1019 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1021 UnlockFilterList(device
);
1023 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1026 /* Add refcount on the new slot, and release the previous slot */
1027 if(slot
) IncrementRef(&slot
->ref
);
1028 if(Source
->Send
[values
[1]].Slot
)
1029 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1030 Source
->Send
[values
[1]].Slot
= slot
;
1032 /* We must force an update if the auxiliary slot changed on an
1033 * active source, in case the slot is about to be deleted.
1035 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1036 UpdateSourceProps(Source
, voice
, device
->NumAuxSends
, Context
);
1038 ATOMIC_FLAG_CLEAR(&Source
->PropsClean
, almemory_order_release
);
1042 if(slot
) IncrementRef(&slot
->ref
);
1043 if(Source
->Send
[values
[1]].Slot
)
1044 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1045 Source
->Send
[values
[1]].Slot
= slot
;
1048 UnlockEffectSlotList(Context
);
1054 case AL_CONE_INNER_ANGLE
:
1055 case AL_CONE_OUTER_ANGLE
:
1060 case AL_REFERENCE_DISTANCE
:
1061 case AL_ROLLOFF_FACTOR
:
1062 case AL_CONE_OUTER_GAIN
:
1063 case AL_MAX_DISTANCE
:
1064 case AL_DOPPLER_FACTOR
:
1065 case AL_CONE_OUTER_GAINHF
:
1066 case AL_AIR_ABSORPTION_FACTOR
:
1067 case AL_ROOM_ROLLOFF_FACTOR
:
1068 case AL_SOURCE_RADIUS
:
1069 fvals
[0] = (ALfloat
)*values
;
1070 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1076 fvals
[0] = (ALfloat
)values
[0];
1077 fvals
[1] = (ALfloat
)values
[1];
1078 fvals
[2] = (ALfloat
)values
[2];
1079 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1082 case AL_ORIENTATION
:
1083 fvals
[0] = (ALfloat
)values
[0];
1084 fvals
[1] = (ALfloat
)values
[1];
1085 fvals
[2] = (ALfloat
)values
[2];
1086 fvals
[3] = (ALfloat
)values
[3];
1087 fvals
[4] = (ALfloat
)values
[4];
1088 fvals
[5] = (ALfloat
)values
[5];
1089 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1091 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1092 case AL_SEC_OFFSET_LATENCY_SOFT
:
1093 case AL_SEC_OFFSET_CLOCK_SOFT
:
1094 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1095 case AL_STEREO_ANGLES
:
1099 ERR("Unexpected property: 0x%04x\n", prop
);
1100 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1104 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1111 case AL_SOURCE_TYPE
:
1112 case AL_BUFFERS_QUEUED
:
1113 case AL_BUFFERS_PROCESSED
:
1114 case AL_SOURCE_STATE
:
1115 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1116 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1118 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1119 "Setting read-only source property 0x%04x", prop
);
1122 case AL_SOURCE_RELATIVE
:
1125 case AL_SAMPLE_OFFSET
:
1126 case AL_BYTE_OFFSET
:
1127 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1128 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1129 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1130 case AL_DIRECT_CHANNELS_SOFT
:
1131 case AL_DISTANCE_MODEL
:
1132 case AL_SOURCE_RESAMPLER_SOFT
:
1133 case AL_SOURCE_SPATIALIZE_SOFT
:
1134 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1136 ivals
[0] = (ALint
)*values
;
1137 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1141 case AL_DIRECT_FILTER
:
1142 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1144 ivals
[0] = (ALuint
)*values
;
1145 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1148 case AL_AUXILIARY_SEND_FILTER
:
1149 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1150 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1151 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1153 ivals
[0] = (ALuint
)values
[0];
1154 ivals
[1] = (ALuint
)values
[1];
1155 ivals
[2] = (ALuint
)values
[2];
1156 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1159 case AL_CONE_INNER_ANGLE
:
1160 case AL_CONE_OUTER_ANGLE
:
1165 case AL_REFERENCE_DISTANCE
:
1166 case AL_ROLLOFF_FACTOR
:
1167 case AL_CONE_OUTER_GAIN
:
1168 case AL_MAX_DISTANCE
:
1169 case AL_DOPPLER_FACTOR
:
1170 case AL_CONE_OUTER_GAINHF
:
1171 case AL_AIR_ABSORPTION_FACTOR
:
1172 case AL_ROOM_ROLLOFF_FACTOR
:
1173 case AL_SOURCE_RADIUS
:
1174 fvals
[0] = (ALfloat
)*values
;
1175 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1181 fvals
[0] = (ALfloat
)values
[0];
1182 fvals
[1] = (ALfloat
)values
[1];
1183 fvals
[2] = (ALfloat
)values
[2];
1184 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1187 case AL_ORIENTATION
:
1188 fvals
[0] = (ALfloat
)values
[0];
1189 fvals
[1] = (ALfloat
)values
[1];
1190 fvals
[2] = (ALfloat
)values
[2];
1191 fvals
[3] = (ALfloat
)values
[3];
1192 fvals
[4] = (ALfloat
)values
[4];
1193 fvals
[5] = (ALfloat
)values
[5];
1194 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1196 case AL_SEC_OFFSET_LATENCY_SOFT
:
1197 case AL_SEC_OFFSET_CLOCK_SOFT
:
1198 case AL_STEREO_ANGLES
:
1202 ERR("Unexpected property: 0x%04x\n", prop
);
1203 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1210 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1212 ALCdevice
*device
= Context
->Device
;
1213 ClockLatency clocktime
;
1221 *values
= Source
->Gain
;
1225 *values
= Source
->Pitch
;
1228 case AL_MAX_DISTANCE
:
1229 *values
= Source
->MaxDistance
;
1232 case AL_ROLLOFF_FACTOR
:
1233 *values
= Source
->RolloffFactor
;
1236 case AL_REFERENCE_DISTANCE
:
1237 *values
= Source
->RefDistance
;
1240 case AL_CONE_INNER_ANGLE
:
1241 *values
= Source
->InnerAngle
;
1244 case AL_CONE_OUTER_ANGLE
:
1245 *values
= Source
->OuterAngle
;
1249 *values
= Source
->MinGain
;
1253 *values
= Source
->MaxGain
;
1256 case AL_CONE_OUTER_GAIN
:
1257 *values
= Source
->OuterGain
;
1261 case AL_SAMPLE_OFFSET
:
1262 case AL_BYTE_OFFSET
:
1263 *values
= GetSourceOffset(Source
, prop
, Context
);
1266 case AL_CONE_OUTER_GAINHF
:
1267 *values
= Source
->OuterGainHF
;
1270 case AL_AIR_ABSORPTION_FACTOR
:
1271 *values
= Source
->AirAbsorptionFactor
;
1274 case AL_ROOM_ROLLOFF_FACTOR
:
1275 *values
= Source
->RoomRolloffFactor
;
1278 case AL_DOPPLER_FACTOR
:
1279 *values
= Source
->DopplerFactor
;
1282 case AL_SOURCE_RADIUS
:
1283 *values
= Source
->Radius
;
1286 case AL_STEREO_ANGLES
:
1287 values
[0] = Source
->StereoPan
[0];
1288 values
[1] = Source
->StereoPan
[1];
1291 case AL_SEC_OFFSET_LATENCY_SOFT
:
1292 /* Get the source offset with the clock time first. Then get the
1293 * clock time with the device latency. Order is important.
1295 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1296 almtx_lock(&device
->BackendLock
);
1297 clocktime
= V0(device
->Backend
,getClockLatency
)();
1298 almtx_unlock(&device
->BackendLock
);
1299 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1300 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1303 /* If the clock time incremented, reduce the latency by that
1304 * much since it's that much closer to the source offset it got
1307 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1308 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1313 case AL_SEC_OFFSET_CLOCK_SOFT
:
1314 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1315 values
[1] = srcclock
/ 1000000000.0;
1319 values
[0] = Source
->Position
[0];
1320 values
[1] = Source
->Position
[1];
1321 values
[2] = Source
->Position
[2];
1325 values
[0] = Source
->Velocity
[0];
1326 values
[1] = Source
->Velocity
[1];
1327 values
[2] = Source
->Velocity
[2];
1331 values
[0] = Source
->Direction
[0];
1332 values
[1] = Source
->Direction
[1];
1333 values
[2] = Source
->Direction
[2];
1336 case AL_ORIENTATION
:
1337 values
[0] = Source
->Orientation
[0][0];
1338 values
[1] = Source
->Orientation
[0][1];
1339 values
[2] = Source
->Orientation
[0][2];
1340 values
[3] = Source
->Orientation
[1][0];
1341 values
[4] = Source
->Orientation
[1][1];
1342 values
[5] = Source
->Orientation
[1][2];
1346 case AL_SOURCE_RELATIVE
:
1348 case AL_SOURCE_STATE
:
1349 case AL_BUFFERS_QUEUED
:
1350 case AL_BUFFERS_PROCESSED
:
1351 case AL_SOURCE_TYPE
:
1352 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1353 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1354 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1355 case AL_DIRECT_CHANNELS_SOFT
:
1356 case AL_DISTANCE_MODEL
:
1357 case AL_SOURCE_RESAMPLER_SOFT
:
1358 case AL_SOURCE_SPATIALIZE_SOFT
:
1359 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1360 *values
= (ALdouble
)ivals
[0];
1364 case AL_DIRECT_FILTER
:
1365 case AL_AUXILIARY_SEND_FILTER
:
1366 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1367 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1371 ERR("Unexpected property: 0x%04x\n", prop
);
1372 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1376 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1378 ALbufferlistitem
*BufferList
;
1384 case AL_SOURCE_RELATIVE
:
1385 *values
= Source
->HeadRelative
;
1389 *values
= Source
->Looping
;
1393 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: NULL
;
1394 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1395 BufferList
->buffers
[0]->id
: 0;
1398 case AL_SOURCE_STATE
:
1399 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1402 case AL_BUFFERS_QUEUED
:
1403 if(!(BufferList
=Source
->queue
))
1409 count
+= BufferList
->num_buffers
;
1410 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
1411 } while(BufferList
!= NULL
);
1416 case AL_BUFFERS_PROCESSED
:
1417 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1419 /* Buffers on a looping source are in a perpetual state of
1420 * PENDING, so don't report any as PROCESSED */
1425 const ALbufferlistitem
*BufferList
= Source
->queue
;
1426 const ALbufferlistitem
*Current
= NULL
;
1430 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1431 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
1432 else if(Source
->state
== AL_INITIAL
)
1433 Current
= BufferList
;
1435 while(BufferList
&& BufferList
!= Current
)
1437 played
+= BufferList
->num_buffers
;
1438 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
1439 almemory_order_relaxed
);
1445 case AL_SOURCE_TYPE
:
1446 *values
= Source
->SourceType
;
1449 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1450 *values
= Source
->DryGainHFAuto
;
1453 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1454 *values
= Source
->WetGainAuto
;
1457 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1458 *values
= Source
->WetGainHFAuto
;
1461 case AL_DIRECT_CHANNELS_SOFT
:
1462 *values
= Source
->DirectChannels
;
1465 case AL_DISTANCE_MODEL
:
1466 *values
= Source
->DistanceModel
;
1469 case AL_SOURCE_RESAMPLER_SOFT
:
1470 *values
= Source
->Resampler
;
1473 case AL_SOURCE_SPATIALIZE_SOFT
:
1474 *values
= Source
->Spatialize
;
1477 /* 1x float/double */
1478 case AL_CONE_INNER_ANGLE
:
1479 case AL_CONE_OUTER_ANGLE
:
1484 case AL_REFERENCE_DISTANCE
:
1485 case AL_ROLLOFF_FACTOR
:
1486 case AL_CONE_OUTER_GAIN
:
1487 case AL_MAX_DISTANCE
:
1489 case AL_SAMPLE_OFFSET
:
1490 case AL_BYTE_OFFSET
:
1491 case AL_DOPPLER_FACTOR
:
1492 case AL_AIR_ABSORPTION_FACTOR
:
1493 case AL_ROOM_ROLLOFF_FACTOR
:
1494 case AL_CONE_OUTER_GAINHF
:
1495 case AL_SOURCE_RADIUS
:
1496 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1497 *values
= (ALint
)dvals
[0];
1500 /* 3x float/double */
1504 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1506 values
[0] = (ALint
)dvals
[0];
1507 values
[1] = (ALint
)dvals
[1];
1508 values
[2] = (ALint
)dvals
[2];
1512 /* 6x float/double */
1513 case AL_ORIENTATION
:
1514 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1516 values
[0] = (ALint
)dvals
[0];
1517 values
[1] = (ALint
)dvals
[1];
1518 values
[2] = (ALint
)dvals
[2];
1519 values
[3] = (ALint
)dvals
[3];
1520 values
[4] = (ALint
)dvals
[4];
1521 values
[5] = (ALint
)dvals
[5];
1525 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1526 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1527 break; /* i64 only */
1528 case AL_SEC_OFFSET_LATENCY_SOFT
:
1529 case AL_SEC_OFFSET_CLOCK_SOFT
:
1530 break; /* Double only */
1531 case AL_STEREO_ANGLES
:
1532 break; /* Float/double only */
1534 case AL_DIRECT_FILTER
:
1535 case AL_AUXILIARY_SEND_FILTER
:
1539 ERR("Unexpected property: 0x%04x\n", prop
);
1540 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1544 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1546 ALCdevice
*device
= Context
->Device
;
1547 ClockLatency clocktime
;
1555 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1556 /* Get the source offset with the clock time first. Then get the
1557 * clock time with the device latency. Order is important.
1559 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1560 almtx_lock(&device
->BackendLock
);
1561 clocktime
= V0(device
->Backend
,getClockLatency
)();
1562 almtx_unlock(&device
->BackendLock
);
1563 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1564 values
[1] = clocktime
.Latency
;
1567 /* If the clock time incremented, reduce the latency by that
1568 * much since it's that much closer to the source offset it got
1571 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1572 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1576 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1577 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1578 values
[1] = srcclock
;
1581 /* 1x float/double */
1582 case AL_CONE_INNER_ANGLE
:
1583 case AL_CONE_OUTER_ANGLE
:
1588 case AL_REFERENCE_DISTANCE
:
1589 case AL_ROLLOFF_FACTOR
:
1590 case AL_CONE_OUTER_GAIN
:
1591 case AL_MAX_DISTANCE
:
1593 case AL_SAMPLE_OFFSET
:
1594 case AL_BYTE_OFFSET
:
1595 case AL_DOPPLER_FACTOR
:
1596 case AL_AIR_ABSORPTION_FACTOR
:
1597 case AL_ROOM_ROLLOFF_FACTOR
:
1598 case AL_CONE_OUTER_GAINHF
:
1599 case AL_SOURCE_RADIUS
:
1600 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1601 *values
= (ALint64
)dvals
[0];
1604 /* 3x float/double */
1608 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1610 values
[0] = (ALint64
)dvals
[0];
1611 values
[1] = (ALint64
)dvals
[1];
1612 values
[2] = (ALint64
)dvals
[2];
1616 /* 6x float/double */
1617 case AL_ORIENTATION
:
1618 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1620 values
[0] = (ALint64
)dvals
[0];
1621 values
[1] = (ALint64
)dvals
[1];
1622 values
[2] = (ALint64
)dvals
[2];
1623 values
[3] = (ALint64
)dvals
[3];
1624 values
[4] = (ALint64
)dvals
[4];
1625 values
[5] = (ALint64
)dvals
[5];
1630 case AL_SOURCE_RELATIVE
:
1632 case AL_SOURCE_STATE
:
1633 case AL_BUFFERS_QUEUED
:
1634 case AL_BUFFERS_PROCESSED
:
1635 case AL_SOURCE_TYPE
:
1636 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1637 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1638 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1639 case AL_DIRECT_CHANNELS_SOFT
:
1640 case AL_DISTANCE_MODEL
:
1641 case AL_SOURCE_RESAMPLER_SOFT
:
1642 case AL_SOURCE_SPATIALIZE_SOFT
:
1643 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1649 case AL_DIRECT_FILTER
:
1650 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1651 *values
= (ALuint
)ivals
[0];
1655 case AL_AUXILIARY_SEND_FILTER
:
1656 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1658 values
[0] = (ALuint
)ivals
[0];
1659 values
[1] = (ALuint
)ivals
[1];
1660 values
[2] = (ALuint
)ivals
[2];
1664 case AL_SEC_OFFSET_LATENCY_SOFT
:
1665 case AL_SEC_OFFSET_CLOCK_SOFT
:
1666 break; /* Double only */
1667 case AL_STEREO_ANGLES
:
1668 break; /* Float/double only */
1671 ERR("Unexpected property: 0x%04x\n", prop
);
1672 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1677 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1679 ALCcontext
*context
;
1682 context
= GetContextRef();
1683 if(!context
) return;
1686 alSetError(context
, AL_INVALID_VALUE
, "Generating %d sources", n
);
1687 else for(cur
= 0;cur
< n
;cur
++)
1689 ALsource
*source
= AllocSource(context
);
1692 alDeleteSources(cur
, sources
);
1695 sources
[cur
] = source
->id
;
1698 ALCcontext_DecRef(context
);
1702 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1704 ALCcontext
*context
;
1708 context
= GetContextRef();
1709 if(!context
) return;
1711 LockSourceList(context
);
1713 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d sources", n
);
1715 /* Check that all Sources are valid */
1716 for(i
= 0;i
< n
;i
++)
1718 if(LookupSource(context
, sources
[i
]) == NULL
)
1719 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
1721 for(i
= 0;i
< n
;i
++)
1723 if((Source
=LookupSource(context
, sources
[i
])) != NULL
)
1724 FreeSource(context
, Source
);
1728 UnlockSourceList(context
);
1729 ALCcontext_DecRef(context
);
1733 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1735 ALCcontext
*context
;
1738 context
= GetContextRef();
1739 if(!context
) return AL_FALSE
;
1741 LockSourceList(context
);
1742 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1743 UnlockSourceList(context
);
1745 ALCcontext_DecRef(context
);
1751 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1753 ALCcontext
*Context
;
1756 Context
= GetContextRef();
1757 if(!Context
) return;
1759 almtx_lock(&Context
->PropLock
);
1760 LockSourceList(Context
);
1761 if((Source
=LookupSource(Context
, source
)) == NULL
)
1762 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1763 else if(!(FloatValsByProp(param
) == 1))
1764 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
1766 SetSourcefv(Source
, Context
, param
, &value
);
1767 UnlockSourceList(Context
);
1768 almtx_unlock(&Context
->PropLock
);
1770 ALCcontext_DecRef(Context
);
1773 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1775 ALCcontext
*Context
;
1778 Context
= GetContextRef();
1779 if(!Context
) return;
1781 almtx_lock(&Context
->PropLock
);
1782 LockSourceList(Context
);
1783 if((Source
=LookupSource(Context
, source
)) == NULL
)
1784 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1785 else if(!(FloatValsByProp(param
) == 3))
1786 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
1789 ALfloat fvals
[3] = { value1
, value2
, value3
};
1790 SetSourcefv(Source
, Context
, param
, fvals
);
1792 UnlockSourceList(Context
);
1793 almtx_unlock(&Context
->PropLock
);
1795 ALCcontext_DecRef(Context
);
1798 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1800 ALCcontext
*Context
;
1803 Context
= GetContextRef();
1804 if(!Context
) return;
1806 almtx_lock(&Context
->PropLock
);
1807 LockSourceList(Context
);
1808 if((Source
=LookupSource(Context
, source
)) == NULL
)
1809 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1811 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1812 else if(!(FloatValsByProp(param
) > 0))
1813 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
1815 SetSourcefv(Source
, Context
, param
, values
);
1816 UnlockSourceList(Context
);
1817 almtx_unlock(&Context
->PropLock
);
1819 ALCcontext_DecRef(Context
);
1823 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1825 ALCcontext
*Context
;
1828 Context
= GetContextRef();
1829 if(!Context
) return;
1831 almtx_lock(&Context
->PropLock
);
1832 LockSourceList(Context
);
1833 if((Source
=LookupSource(Context
, source
)) == NULL
)
1834 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1835 else if(!(DoubleValsByProp(param
) == 1))
1836 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
1839 ALfloat fval
= (ALfloat
)value
;
1840 SetSourcefv(Source
, Context
, param
, &fval
);
1842 UnlockSourceList(Context
);
1843 almtx_unlock(&Context
->PropLock
);
1845 ALCcontext_DecRef(Context
);
1848 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1850 ALCcontext
*Context
;
1853 Context
= GetContextRef();
1854 if(!Context
) return;
1856 almtx_lock(&Context
->PropLock
);
1857 LockSourceList(Context
);
1858 if((Source
=LookupSource(Context
, source
)) == NULL
)
1859 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1860 else if(!(DoubleValsByProp(param
) == 3))
1861 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
1864 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1865 SetSourcefv(Source
, Context
, param
, fvals
);
1867 UnlockSourceList(Context
);
1868 almtx_unlock(&Context
->PropLock
);
1870 ALCcontext_DecRef(Context
);
1873 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1875 ALCcontext
*Context
;
1879 Context
= GetContextRef();
1880 if(!Context
) return;
1882 almtx_lock(&Context
->PropLock
);
1883 LockSourceList(Context
);
1884 if((Source
=LookupSource(Context
, source
)) == NULL
)
1885 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1887 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1888 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1889 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
1895 for(i
= 0;i
< count
;i
++)
1896 fvals
[i
] = (ALfloat
)values
[i
];
1897 SetSourcefv(Source
, Context
, param
, fvals
);
1899 UnlockSourceList(Context
);
1900 almtx_unlock(&Context
->PropLock
);
1902 ALCcontext_DecRef(Context
);
1906 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1908 ALCcontext
*Context
;
1911 Context
= GetContextRef();
1912 if(!Context
) return;
1914 almtx_lock(&Context
->PropLock
);
1915 LockSourceList(Context
);
1916 if((Source
=LookupSource(Context
, source
)) == NULL
)
1917 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1918 else if(!(IntValsByProp(param
) == 1))
1919 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
1921 SetSourceiv(Source
, Context
, param
, &value
);
1922 UnlockSourceList(Context
);
1923 almtx_unlock(&Context
->PropLock
);
1925 ALCcontext_DecRef(Context
);
1928 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1930 ALCcontext
*Context
;
1933 Context
= GetContextRef();
1934 if(!Context
) return;
1936 almtx_lock(&Context
->PropLock
);
1937 LockSourceList(Context
);
1938 if((Source
=LookupSource(Context
, source
)) == NULL
)
1939 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1940 else if(!(IntValsByProp(param
) == 3))
1941 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
1944 ALint ivals
[3] = { value1
, value2
, value3
};
1945 SetSourceiv(Source
, Context
, param
, ivals
);
1947 UnlockSourceList(Context
);
1948 almtx_unlock(&Context
->PropLock
);
1950 ALCcontext_DecRef(Context
);
1953 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1955 ALCcontext
*Context
;
1958 Context
= GetContextRef();
1959 if(!Context
) return;
1961 almtx_lock(&Context
->PropLock
);
1962 LockSourceList(Context
);
1963 if((Source
=LookupSource(Context
, source
)) == NULL
)
1964 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1966 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
1967 else if(!(IntValsByProp(param
) > 0))
1968 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
1970 SetSourceiv(Source
, Context
, param
, values
);
1971 UnlockSourceList(Context
);
1972 almtx_unlock(&Context
->PropLock
);
1974 ALCcontext_DecRef(Context
);
1978 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1980 ALCcontext
*Context
;
1983 Context
= GetContextRef();
1984 if(!Context
) return;
1986 almtx_lock(&Context
->PropLock
);
1987 LockSourceList(Context
);
1988 if((Source
=LookupSource(Context
, source
)) == NULL
)
1989 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
1990 else if(!(Int64ValsByProp(param
) == 1))
1991 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
1993 SetSourcei64v(Source
, Context
, param
, &value
);
1994 UnlockSourceList(Context
);
1995 almtx_unlock(&Context
->PropLock
);
1997 ALCcontext_DecRef(Context
);
2000 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2002 ALCcontext
*Context
;
2005 Context
= GetContextRef();
2006 if(!Context
) return;
2008 almtx_lock(&Context
->PropLock
);
2009 LockSourceList(Context
);
2010 if((Source
=LookupSource(Context
, source
)) == NULL
)
2011 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2012 else if(!(Int64ValsByProp(param
) == 3))
2013 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2016 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2017 SetSourcei64v(Source
, Context
, param
, i64vals
);
2019 UnlockSourceList(Context
);
2020 almtx_unlock(&Context
->PropLock
);
2022 ALCcontext_DecRef(Context
);
2025 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2027 ALCcontext
*Context
;
2030 Context
= GetContextRef();
2031 if(!Context
) return;
2033 almtx_lock(&Context
->PropLock
);
2034 LockSourceList(Context
);
2035 if((Source
=LookupSource(Context
, source
)) == NULL
)
2036 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2038 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2039 else if(!(Int64ValsByProp(param
) > 0))
2040 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2042 SetSourcei64v(Source
, Context
, param
, values
);
2043 UnlockSourceList(Context
);
2044 almtx_unlock(&Context
->PropLock
);
2046 ALCcontext_DecRef(Context
);
2050 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2052 ALCcontext
*Context
;
2055 Context
= GetContextRef();
2056 if(!Context
) return;
2058 LockSourceList(Context
);
2059 if((Source
=LookupSource(Context
, source
)) == NULL
)
2060 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2062 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2063 else if(!(FloatValsByProp(param
) == 1))
2064 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2068 if(GetSourcedv(Source
, Context
, param
, &dval
))
2069 *value
= (ALfloat
)dval
;
2071 UnlockSourceList(Context
);
2073 ALCcontext_DecRef(Context
);
2077 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2079 ALCcontext
*Context
;
2082 Context
= GetContextRef();
2083 if(!Context
) return;
2085 LockSourceList(Context
);
2086 if((Source
=LookupSource(Context
, source
)) == NULL
)
2087 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2088 else if(!(value1
&& value2
&& value3
))
2089 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2090 else if(!(FloatValsByProp(param
) == 3))
2091 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2095 if(GetSourcedv(Source
, Context
, param
, dvals
))
2097 *value1
= (ALfloat
)dvals
[0];
2098 *value2
= (ALfloat
)dvals
[1];
2099 *value3
= (ALfloat
)dvals
[2];
2102 UnlockSourceList(Context
);
2104 ALCcontext_DecRef(Context
);
2108 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2110 ALCcontext
*Context
;
2114 Context
= GetContextRef();
2115 if(!Context
) return;
2117 LockSourceList(Context
);
2118 if((Source
=LookupSource(Context
, source
)) == NULL
)
2119 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2121 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2122 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2123 alSetError(Context
, AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2127 if(GetSourcedv(Source
, Context
, param
, dvals
))
2130 for(i
= 0;i
< count
;i
++)
2131 values
[i
] = (ALfloat
)dvals
[i
];
2134 UnlockSourceList(Context
);
2136 ALCcontext_DecRef(Context
);
2140 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2142 ALCcontext
*Context
;
2145 Context
= GetContextRef();
2146 if(!Context
) return;
2148 LockSourceList(Context
);
2149 if((Source
=LookupSource(Context
, source
)) == NULL
)
2150 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2152 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2153 else if(!(DoubleValsByProp(param
) == 1))
2154 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2156 GetSourcedv(Source
, Context
, param
, value
);
2157 UnlockSourceList(Context
);
2159 ALCcontext_DecRef(Context
);
2162 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2164 ALCcontext
*Context
;
2167 Context
= GetContextRef();
2168 if(!Context
) return;
2170 LockSourceList(Context
);
2171 if((Source
=LookupSource(Context
, source
)) == NULL
)
2172 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2173 else if(!(value1
&& value2
&& value3
))
2174 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2175 else if(!(DoubleValsByProp(param
) == 3))
2176 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2180 if(GetSourcedv(Source
, Context
, param
, dvals
))
2187 UnlockSourceList(Context
);
2189 ALCcontext_DecRef(Context
);
2192 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2194 ALCcontext
*Context
;
2197 Context
= GetContextRef();
2198 if(!Context
) return;
2200 LockSourceList(Context
);
2201 if((Source
=LookupSource(Context
, source
)) == NULL
)
2202 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2204 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2205 else if(!(DoubleValsByProp(param
) > 0))
2206 alSetError(Context
, AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2208 GetSourcedv(Source
, Context
, param
, values
);
2209 UnlockSourceList(Context
);
2211 ALCcontext_DecRef(Context
);
2215 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2217 ALCcontext
*Context
;
2220 Context
= GetContextRef();
2221 if(!Context
) return;
2223 LockSourceList(Context
);
2224 if((Source
=LookupSource(Context
, source
)) == NULL
)
2225 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2227 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2228 else if(!(IntValsByProp(param
) == 1))
2229 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2231 GetSourceiv(Source
, Context
, param
, value
);
2232 UnlockSourceList(Context
);
2234 ALCcontext_DecRef(Context
);
2238 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2240 ALCcontext
*Context
;
2243 Context
= GetContextRef();
2244 if(!Context
) return;
2246 LockSourceList(Context
);
2247 if((Source
=LookupSource(Context
, source
)) == NULL
)
2248 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2249 else if(!(value1
&& value2
&& value3
))
2250 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2251 else if(!(IntValsByProp(param
) == 3))
2252 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2256 if(GetSourceiv(Source
, Context
, param
, ivals
))
2263 UnlockSourceList(Context
);
2265 ALCcontext_DecRef(Context
);
2269 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2271 ALCcontext
*Context
;
2274 Context
= GetContextRef();
2275 if(!Context
) return;
2277 LockSourceList(Context
);
2278 if((Source
=LookupSource(Context
, source
)) == NULL
)
2279 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2281 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2282 else if(!(IntValsByProp(param
) > 0))
2283 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2285 GetSourceiv(Source
, Context
, param
, values
);
2286 UnlockSourceList(Context
);
2288 ALCcontext_DecRef(Context
);
2292 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2294 ALCcontext
*Context
;
2297 Context
= GetContextRef();
2298 if(!Context
) return;
2300 LockSourceList(Context
);
2301 if((Source
=LookupSource(Context
, source
)) == NULL
)
2302 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2304 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2305 else if(!(Int64ValsByProp(param
) == 1))
2306 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2308 GetSourcei64v(Source
, Context
, param
, value
);
2309 UnlockSourceList(Context
);
2311 ALCcontext_DecRef(Context
);
2314 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2316 ALCcontext
*Context
;
2319 Context
= GetContextRef();
2320 if(!Context
) return;
2322 LockSourceList(Context
);
2323 if((Source
=LookupSource(Context
, source
)) == NULL
)
2324 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2325 else if(!(value1
&& value2
&& value3
))
2326 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2327 else if(!(Int64ValsByProp(param
) == 3))
2328 alSetError(Context
, AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2332 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2334 *value1
= i64vals
[0];
2335 *value2
= i64vals
[1];
2336 *value3
= i64vals
[2];
2339 UnlockSourceList(Context
);
2341 ALCcontext_DecRef(Context
);
2344 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2346 ALCcontext
*Context
;
2349 Context
= GetContextRef();
2350 if(!Context
) return;
2352 LockSourceList(Context
);
2353 if((Source
=LookupSource(Context
, source
)) == NULL
)
2354 alSetError(Context
, AL_INVALID_NAME
, "Invalid source ID %u", source
);
2356 alSetError(Context
, AL_INVALID_VALUE
, "NULL pointer");
2357 else if(!(Int64ValsByProp(param
) > 0))
2358 alSetError(Context
, AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2360 GetSourcei64v(Source
, Context
, param
, values
);
2361 UnlockSourceList(Context
);
2363 ALCcontext_DecRef(Context
);
2367 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2369 alSourcePlayv(1, &source
);
2371 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2373 ALCcontext
*context
;
2379 context
= GetContextRef();
2380 if(!context
) return;
2382 LockSourceList(context
);
2384 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Playing %d sources", n
);
2385 for(i
= 0;i
< n
;i
++)
2387 if(!LookupSource(context
, sources
[i
]))
2388 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2391 device
= context
->Device
;
2392 ALCdevice_Lock(device
);
2393 /* If the device is disconnected, go right to stopped. */
2394 if(!ATOMIC_LOAD(&device
->Connected
, almemory_order_acquire
))
2396 /* TODO: Send state change event? */
2397 for(i
= 0;i
< n
;i
++)
2399 source
= LookupSource(context
, sources
[i
]);
2400 source
->OffsetType
= AL_NONE
;
2401 source
->Offset
= 0.0;
2402 source
->state
= AL_STOPPED
;
2404 ALCdevice_Unlock(device
);
2408 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2410 ALsizei newcount
= context
->MaxVoices
<< 1;
2411 if(context
->MaxVoices
>= newcount
)
2413 ALCdevice_Unlock(device
);
2414 SETERR_GOTO(context
, AL_OUT_OF_MEMORY
, done
,
2415 "Overflow increasing voice count %d -> %d", context
->MaxVoices
, newcount
);
2417 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2420 for(i
= 0;i
< n
;i
++)
2422 ALbufferlistitem
*BufferList
;
2423 ALbuffer
*buffer
= NULL
;
2424 bool start_fading
= false;
2428 source
= LookupSource(context
, sources
[i
]);
2429 /* Check that there is a queue containing at least one valid, non zero
2432 BufferList
= source
->queue
;
2436 for(b
= 0;b
< BufferList
->num_buffers
;b
++)
2438 buffer
= BufferList
->buffers
[b
];
2439 if(buffer
&& buffer
->SampleLen
> 0) break;
2441 if(buffer
&& buffer
->SampleLen
> 0) break;
2442 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2445 /* If there's nothing to play, go right to stopped. */
2446 if(UNLIKELY(!BufferList
))
2448 /* NOTE: A source without any playable buffers should not have an
2449 * ALvoice since it shouldn't be in a playing or paused state. So
2450 * there's no need to look up its voice and clear the source.
2452 ALenum oldstate
= GetSourceState(source
, NULL
);
2453 source
->OffsetType
= AL_NONE
;
2454 source
->Offset
= 0.0;
2455 if(oldstate
!= AL_STOPPED
)
2457 source
->state
= AL_STOPPED
;
2458 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2463 voice
= GetSourceVoice(source
, context
);
2464 switch(GetSourceState(source
, voice
))
2467 assert(voice
!= NULL
);
2468 /* A source that's already playing is restarted from the beginning. */
2469 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2470 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2471 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2475 assert(voice
!= NULL
);
2476 /* A source that's paused simply resumes. */
2477 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2478 source
->state
= AL_PLAYING
;
2479 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2486 /* Make sure this source isn't already active, and if not, look for an
2487 * unused voice to put it in.
2489 assert(voice
== NULL
);
2490 for(j
= 0;j
< context
->VoiceCount
;j
++)
2492 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2499 vidx
= context
->VoiceCount
++;
2500 voice
= context
->Voices
[vidx
];
2501 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2503 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2504 UpdateSourceProps(source
, voice
, device
->NumAuxSends
, context
);
2506 /* A source that's not playing or paused has any offset applied when it
2510 ATOMIC_STORE(&voice
->loop_buffer
, source
->queue
, almemory_order_relaxed
);
2512 ATOMIC_STORE(&voice
->loop_buffer
, NULL
, almemory_order_relaxed
);
2513 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2514 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2515 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2516 if(source
->OffsetType
!= AL_NONE
)
2518 ApplyOffset(source
, voice
);
2519 start_fading
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) != 0 ||
2520 ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) != 0 ||
2521 ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
) != BufferList
;
2524 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2525 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2527 /* Clear previous samples. */
2528 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2530 /* Clear the stepping value so the mixer knows not to mix this until
2531 * the update gets applied.
2535 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2536 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2537 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2538 for(s
= 0;s
< device
->NumAuxSends
;s
++)
2539 memset(voice
->Send
[s
].Params
, 0, sizeof(voice
->Send
[s
].Params
[0])*voice
->NumChannels
);
2540 if(device
->AvgSpeakerDist
> 0.0f
)
2542 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2543 (device
->AvgSpeakerDist
* device
->Frequency
);
2544 for(j
= 0;j
< voice
->NumChannels
;j
++)
2545 NfcFilterCreate(&voice
->Direct
.Params
[j
].NFCtrlFilter
, 0.0f
, w1
);
2548 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2549 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2550 source
->state
= AL_PLAYING
;
2551 source
->VoiceIdx
= vidx
;
2553 SendStateChangeEvent(context
, source
->id
, AL_PLAYING
);
2555 ALCdevice_Unlock(device
);
2558 UnlockSourceList(context
);
2559 ALCcontext_DecRef(context
);
2562 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2564 alSourcePausev(1, &source
);
2566 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2568 ALCcontext
*context
;
2574 context
= GetContextRef();
2575 if(!context
) return;
2577 LockSourceList(context
);
2579 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Pausing %d sources", n
);
2580 for(i
= 0;i
< n
;i
++)
2582 if(!LookupSource(context
, sources
[i
]))
2583 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2586 device
= context
->Device
;
2587 ALCdevice_Lock(device
);
2588 for(i
= 0;i
< n
;i
++)
2590 source
= LookupSource(context
, sources
[i
]);
2591 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2592 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2593 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2595 source
->state
= AL_PAUSED
;
2596 SendStateChangeEvent(context
, source
->id
, AL_PAUSED
);
2599 ALCdevice_Unlock(device
);
2602 UnlockSourceList(context
);
2603 ALCcontext_DecRef(context
);
2606 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2608 alSourceStopv(1, &source
);
2610 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2612 ALCcontext
*context
;
2618 context
= GetContextRef();
2619 if(!context
) return;
2621 LockSourceList(context
);
2623 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Stopping %d sources", n
);
2624 for(i
= 0;i
< n
;i
++)
2626 if(!LookupSource(context
, sources
[i
]))
2627 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2630 device
= context
->Device
;
2631 ALCdevice_Lock(device
);
2632 for(i
= 0;i
< n
;i
++)
2635 source
= LookupSource(context
, sources
[i
]);
2636 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2638 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2639 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2642 oldstate
= GetSourceState(source
, voice
);
2643 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2645 source
->state
= AL_STOPPED
;
2646 SendStateChangeEvent(context
, source
->id
, AL_STOPPED
);
2648 source
->OffsetType
= AL_NONE
;
2649 source
->Offset
= 0.0;
2651 ALCdevice_Unlock(device
);
2654 UnlockSourceList(context
);
2655 ALCcontext_DecRef(context
);
2658 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2660 alSourceRewindv(1, &source
);
2662 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2664 ALCcontext
*context
;
2670 context
= GetContextRef();
2671 if(!context
) return;
2673 LockSourceList(context
);
2675 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Rewinding %d sources", n
);
2676 for(i
= 0;i
< n
;i
++)
2678 if(!LookupSource(context
, sources
[i
]))
2679 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", sources
[i
]);
2682 device
= context
->Device
;
2683 ALCdevice_Lock(device
);
2684 for(i
= 0;i
< n
;i
++)
2686 source
= LookupSource(context
, sources
[i
]);
2687 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2689 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2690 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2693 if(GetSourceState(source
, voice
) != AL_INITIAL
)
2695 source
->state
= AL_INITIAL
;
2696 SendStateChangeEvent(context
, source
->id
, AL_INITIAL
);
2698 source
->OffsetType
= AL_NONE
;
2699 source
->Offset
= 0.0;
2701 ALCdevice_Unlock(device
);
2704 UnlockSourceList(context
);
2705 ALCcontext_DecRef(context
);
2709 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2712 ALCcontext
*context
;
2715 ALbufferlistitem
*BufferListStart
;
2716 ALbufferlistitem
*BufferList
;
2717 ALbuffer
*BufferFmt
= NULL
;
2722 context
= GetContextRef();
2723 if(!context
) return;
2725 device
= context
->Device
;
2727 LockSourceList(context
);
2729 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Queueing %d buffers", nb
);
2730 if((source
=LookupSource(context
, src
)) == NULL
)
2731 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2733 if(source
->SourceType
== AL_STATIC
)
2735 /* Can't queue on a Static Source */
2736 SETERR_GOTO(context
, AL_INVALID_OPERATION
, done
, "Queueing onto static source %u", src
);
2739 /* Check for a valid Buffer, for its frequency and format */
2740 BufferList
= source
->queue
;
2743 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
2745 if((BufferFmt
=BufferList
->buffers
[i
]) != NULL
)
2748 if(BufferFmt
) break;
2749 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2752 LockBufferList(device
);
2753 BufferListStart
= NULL
;
2755 for(i
= 0;i
< nb
;i
++)
2757 ALbuffer
*buffer
= NULL
;
2758 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2759 SETERR_GOTO(context
, AL_INVALID_NAME
, buffer_error
, "Queueing invalid buffer ID %u",
2762 if(!BufferListStart
)
2764 BufferListStart
= al_calloc(DEF_ALIGN
,
2765 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2766 BufferList
= BufferListStart
;
2770 ALbufferlistitem
*item
= al_calloc(DEF_ALIGN
,
2771 FAM_SIZE(ALbufferlistitem
, buffers
, 1));
2772 ATOMIC_STORE(&BufferList
->next
, item
, almemory_order_relaxed
);
2775 ATOMIC_INIT(&BufferList
->next
, NULL
);
2776 BufferList
->num_buffers
= 1;
2777 BufferList
->buffers
[0] = buffer
;
2778 if(!buffer
) continue;
2780 IncrementRef(&buffer
->ref
);
2782 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
2783 SETERR_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
,
2784 "Queueing non-persistently mapped buffer %u", buffer
->id
);
2786 if(BufferFmt
== NULL
)
2788 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2789 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
2790 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2792 alSetError(context
, AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
2795 /* A buffer failed (invalid ID or format), so unlock and release
2796 * each buffer we had. */
2797 while(BufferListStart
)
2799 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferListStart
->next
,
2800 almemory_order_relaxed
);
2801 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
2803 if((buffer
=BufferListStart
->buffers
[i
]) != NULL
)
2804 DecrementRef(&buffer
->ref
);
2806 al_free(BufferListStart
);
2807 BufferListStart
= next
;
2809 UnlockBufferList(device
);
2813 /* All buffers good. */
2814 UnlockBufferList(device
);
2816 /* Source is now streaming */
2817 source
->SourceType
= AL_STREAMING
;
2819 if(!(BufferList
=source
->queue
))
2820 source
->queue
= BufferListStart
;
2823 ALbufferlistitem
*next
;
2824 while((next
=ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
)) != NULL
)
2826 ATOMIC_STORE(&BufferList
->next
, BufferListStart
, almemory_order_release
);
2830 UnlockSourceList(context
);
2831 ALCcontext_DecRef(context
);
2834 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2836 ALCcontext
*context
;
2838 ALbufferlistitem
*BufferList
;
2839 ALbufferlistitem
*Current
;
2843 context
= GetContextRef();
2844 if(!context
) return;
2846 LockSourceList(context
);
2848 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing %d buffers", nb
);
2849 if((source
=LookupSource(context
, src
)) == NULL
)
2850 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid source ID %u", src
);
2852 /* Nothing to unqueue. */
2853 if(nb
== 0) goto done
;
2856 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from looping source %u", src
);
2857 if(source
->SourceType
!= AL_STREAMING
)
2858 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing from a non-streaming source %u",
2861 /* Make sure enough buffers have been processed to unqueue. */
2862 BufferList
= source
->queue
;
2864 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2865 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
2866 else if(source
->state
== AL_INITIAL
)
2867 Current
= BufferList
;
2868 if(BufferList
== Current
)
2869 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2871 i
= BufferList
->num_buffers
;
2874 /* If the next bufferlist to check is NULL or is the current one, it's
2875 * trying to unqueue pending buffers.
2877 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
2878 if(!next
|| next
== Current
)
2879 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Unqueueing pending buffers");
2882 i
+= BufferList
->num_buffers
;
2887 ALbufferlistitem
*head
= source
->queue
;
2888 ALbufferlistitem
*next
= ATOMIC_LOAD(&head
->next
, almemory_order_relaxed
);
2889 for(i
= 0;i
< head
->num_buffers
&& nb
> 0;i
++,nb
--)
2891 ALbuffer
*buffer
= head
->buffers
[i
];
2896 *(buffers
++) = buffer
->id
;
2897 DecrementRef(&buffer
->ref
);
2900 if(i
< head
->num_buffers
)
2902 /* This head has some buffers left over, so move them to the front
2903 * and update the count.
2906 while(i
< head
->num_buffers
)
2907 head
->buffers
[j
++] = head
->buffers
[i
++];
2908 head
->num_buffers
= j
;
2912 /* Otherwise, free this item and set the source queue head to the next
2916 source
->queue
= next
;
2920 UnlockSourceList(context
);
2921 ALCcontext_DecRef(context
);
2925 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2929 Source
->InnerAngle
= 360.0f
;
2930 Source
->OuterAngle
= 360.0f
;
2931 Source
->Pitch
= 1.0f
;
2932 Source
->Position
[0] = 0.0f
;
2933 Source
->Position
[1] = 0.0f
;
2934 Source
->Position
[2] = 0.0f
;
2935 Source
->Velocity
[0] = 0.0f
;
2936 Source
->Velocity
[1] = 0.0f
;
2937 Source
->Velocity
[2] = 0.0f
;
2938 Source
->Direction
[0] = 0.0f
;
2939 Source
->Direction
[1] = 0.0f
;
2940 Source
->Direction
[2] = 0.0f
;
2941 Source
->Orientation
[0][0] = 0.0f
;
2942 Source
->Orientation
[0][1] = 0.0f
;
2943 Source
->Orientation
[0][2] = -1.0f
;
2944 Source
->Orientation
[1][0] = 0.0f
;
2945 Source
->Orientation
[1][1] = 1.0f
;
2946 Source
->Orientation
[1][2] = 0.0f
;
2947 Source
->RefDistance
= 1.0f
;
2948 Source
->MaxDistance
= FLT_MAX
;
2949 Source
->RolloffFactor
= 1.0f
;
2950 Source
->Gain
= 1.0f
;
2951 Source
->MinGain
= 0.0f
;
2952 Source
->MaxGain
= 1.0f
;
2953 Source
->OuterGain
= 0.0f
;
2954 Source
->OuterGainHF
= 1.0f
;
2956 Source
->DryGainHFAuto
= AL_TRUE
;
2957 Source
->WetGainAuto
= AL_TRUE
;
2958 Source
->WetGainHFAuto
= AL_TRUE
;
2959 Source
->AirAbsorptionFactor
= 0.0f
;
2960 Source
->RoomRolloffFactor
= 0.0f
;
2961 Source
->DopplerFactor
= 1.0f
;
2962 Source
->HeadRelative
= AL_FALSE
;
2963 Source
->Looping
= AL_FALSE
;
2964 Source
->DistanceModel
= DefaultDistanceModel
;
2965 Source
->Resampler
= ResamplerDefault
;
2966 Source
->DirectChannels
= AL_FALSE
;
2967 Source
->Spatialize
= SpatializeAuto
;
2969 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2970 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2972 Source
->Radius
= 0.0f
;
2974 Source
->Direct
.Gain
= 1.0f
;
2975 Source
->Direct
.GainHF
= 1.0f
;
2976 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2977 Source
->Direct
.GainLF
= 1.0f
;
2978 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2979 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2980 for(i
= 0;i
< num_sends
;i
++)
2982 Source
->Send
[i
].Slot
= NULL
;
2983 Source
->Send
[i
].Gain
= 1.0f
;
2984 Source
->Send
[i
].GainHF
= 1.0f
;
2985 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2986 Source
->Send
[i
].GainLF
= 1.0f
;
2987 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2990 Source
->Offset
= 0.0;
2991 Source
->OffsetType
= AL_NONE
;
2992 Source
->SourceType
= AL_UNDETERMINED
;
2993 Source
->state
= AL_INITIAL
;
2995 Source
->queue
= NULL
;
2997 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3000 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
3002 Source
->VoiceIdx
= -1;
3005 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
3007 ALbufferlistitem
*BufferList
;
3010 BufferList
= source
->queue
;
3011 while(BufferList
!= NULL
)
3013 ALbufferlistitem
*next
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3014 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3016 if(BufferList
->buffers
[i
] != NULL
)
3017 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3019 al_free(BufferList
);
3022 source
->queue
= NULL
;
3026 for(i
= 0;i
< num_sends
;i
++)
3028 if(source
->Send
[i
].Slot
)
3029 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3030 source
->Send
[i
].Slot
= NULL
;
3032 al_free(source
->Send
);
3033 source
->Send
= NULL
;
3037 static void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALsizei num_sends
, ALCcontext
*context
)
3039 struct ALvoiceProps
*props
;
3042 /* Get an unused property container, or allocate a new one as needed. */
3043 props
= ATOMIC_LOAD(&context
->FreeVoiceProps
, almemory_order_acquire
);
3045 props
= al_calloc(16, FAM_SIZE(struct ALvoiceProps
, Send
, num_sends
));
3048 struct ALvoiceProps
*next
;
3050 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3051 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeVoiceProps
, &props
, next
,
3052 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3055 /* Copy in current property values. */
3056 props
->Pitch
= source
->Pitch
;
3057 props
->Gain
= source
->Gain
;
3058 props
->OuterGain
= source
->OuterGain
;
3059 props
->MinGain
= source
->MinGain
;
3060 props
->MaxGain
= source
->MaxGain
;
3061 props
->InnerAngle
= source
->InnerAngle
;
3062 props
->OuterAngle
= source
->OuterAngle
;
3063 props
->RefDistance
= source
->RefDistance
;
3064 props
->MaxDistance
= source
->MaxDistance
;
3065 props
->RolloffFactor
= source
->RolloffFactor
;
3066 for(i
= 0;i
< 3;i
++)
3067 props
->Position
[i
] = source
->Position
[i
];
3068 for(i
= 0;i
< 3;i
++)
3069 props
->Velocity
[i
] = source
->Velocity
[i
];
3070 for(i
= 0;i
< 3;i
++)
3071 props
->Direction
[i
] = source
->Direction
[i
];
3072 for(i
= 0;i
< 2;i
++)
3075 for(j
= 0;j
< 3;j
++)
3076 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3078 props
->HeadRelative
= source
->HeadRelative
;
3079 props
->DistanceModel
= source
->DistanceModel
;
3080 props
->Resampler
= source
->Resampler
;
3081 props
->DirectChannels
= source
->DirectChannels
;
3082 props
->SpatializeMode
= source
->Spatialize
;
3084 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3085 props
->WetGainAuto
= source
->WetGainAuto
;
3086 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3087 props
->OuterGainHF
= source
->OuterGainHF
;
3089 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3090 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3091 props
->DopplerFactor
= source
->DopplerFactor
;
3093 props
->StereoPan
[0] = source
->StereoPan
[0];
3094 props
->StereoPan
[1] = source
->StereoPan
[1];
3096 props
->Radius
= source
->Radius
;
3098 props
->Direct
.Gain
= source
->Direct
.Gain
;
3099 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3100 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3101 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3102 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3104 for(i
= 0;i
< num_sends
;i
++)
3106 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3107 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3108 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3109 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3110 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3111 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3114 /* Set the new container for updating internal parameters. */
3115 props
= ATOMIC_EXCHANGE_PTR(&voice
->Update
, props
, almemory_order_acq_rel
);
3118 /* If there was an unused update container, put it back in the
3121 ATOMIC_REPLACE_HEAD(struct ALvoiceProps
*, &context
->FreeVoiceProps
, props
);
3125 void UpdateAllSourceProps(ALCcontext
*context
)
3127 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3130 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3132 ALvoice
*voice
= context
->Voices
[pos
];
3133 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3134 if(source
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3135 UpdateSourceProps(source
, voice
, num_sends
, context
);
3140 /* GetSourceSampleOffset
3142 * Gets the current read offset for the given Source, in 32.32 fixed-point
3143 * samples. The offset is relative to the start of the queue (not the start of
3144 * the current buffer).
3146 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3148 ALCdevice
*device
= context
->Device
;
3149 const ALbufferlistitem
*Current
;
3157 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3159 *clocktime
= GetDeviceClockTime(device
);
3161 voice
= GetSourceVoice(Source
, context
);
3164 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3166 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3167 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3170 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3171 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3175 const ALbufferlistitem
*BufferList
= Source
->queue
;
3176 while(BufferList
&& BufferList
!= Current
)
3178 ALsizei max_len
= 0;
3181 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3183 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3184 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3186 readPos
+= (ALuint64
)max_len
<< 32;
3187 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3188 almemory_order_relaxed
);
3190 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3193 return (ALint64
)readPos
;
3196 /* GetSourceSecOffset
3198 * Gets the current read offset for the given Source, in seconds. The offset is
3199 * relative to the start of the queue (not the start of the current buffer).
3201 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3203 ALCdevice
*device
= context
->Device
;
3204 const ALbufferlistitem
*Current
;
3213 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3215 *clocktime
= GetDeviceClockTime(device
);
3217 voice
= GetSourceVoice(Source
, context
);
3220 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3222 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3224 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3226 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3227 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3232 const ALbufferlistitem
*BufferList
= Source
->queue
;
3233 const ALbuffer
*BufferFmt
= NULL
;
3234 while(BufferList
&& BufferList
!= Current
)
3236 ALsizei max_len
= 0;
3239 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3241 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3244 if(!BufferFmt
) BufferFmt
= buffer
;
3245 max_len
= maxi(max_len
, buffer
->SampleLen
);
3248 readPos
+= (ALuint64
)max_len
<< FRACTIONBITS
;
3249 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3250 almemory_order_relaxed
);
3253 while(BufferList
&& !BufferFmt
)
3256 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3257 BufferFmt
= BufferList
->buffers
[i
];
3258 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3259 almemory_order_relaxed
);
3261 assert(BufferFmt
!= NULL
);
3263 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3264 (ALdouble
)BufferFmt
->Frequency
;
3272 * Gets the current read offset for the given Source, in the appropriate format
3273 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3274 * queue (not the start of the current buffer).
3276 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3278 ALCdevice
*device
= context
->Device
;
3279 const ALbufferlistitem
*Current
;
3281 ALsizei readPosFrac
;
3288 readPos
= readPosFrac
= 0;
3289 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3291 voice
= GetSourceVoice(Source
, context
);
3294 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3296 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3297 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3299 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3300 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3305 const ALbufferlistitem
*BufferList
= Source
->queue
;
3306 const ALbuffer
*BufferFmt
= NULL
;
3307 ALboolean readFin
= AL_FALSE
;
3308 ALuint totalBufferLen
= 0;
3310 while(BufferList
!= NULL
)
3312 ALsizei max_len
= 0;
3315 readFin
= readFin
|| (BufferList
== Current
);
3316 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3318 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3321 if(!BufferFmt
) BufferFmt
= buffer
;
3322 max_len
= maxi(max_len
, buffer
->SampleLen
);
3325 totalBufferLen
+= max_len
;
3326 if(!readFin
) readPos
+= max_len
;
3328 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3329 almemory_order_relaxed
);
3331 assert(BufferFmt
!= NULL
);
3334 readPos
%= totalBufferLen
;
3337 /* Wrap back to 0 */
3338 if(readPos
>= totalBufferLen
)
3339 readPos
= readPosFrac
= 0;
3346 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
3349 case AL_SAMPLE_OFFSET
:
3350 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3353 case AL_BYTE_OFFSET
:
3354 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3356 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3357 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3358 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3360 /* Round down to nearest ADPCM block */
3361 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3363 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3365 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3366 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3367 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
3369 /* Round down to nearest ADPCM block */
3370 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3374 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
3375 BufferFmt
->FmtType
);
3376 offset
= (ALdouble
)(readPos
* FrameSize
);
3388 * Apply the stored playback offset to the Source. This function will update
3389 * the number of buffers "played" given the stored offset.
3391 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3393 ALbufferlistitem
*BufferList
;
3394 ALuint bufferLen
, totalBufferLen
;
3398 /* Get sample frame offset */
3399 if(!GetSampleOffset(Source
, &offset
, &frac
))
3403 BufferList
= Source
->queue
;
3404 while(BufferList
&& totalBufferLen
<= offset
)
3406 ALsizei max_len
= 0;
3409 for(i
= 0;i
< BufferList
->num_buffers
;i
++)
3411 ALbuffer
*buffer
= BufferList
->buffers
[i
];
3412 if(buffer
) max_len
= maxi(max_len
, buffer
->SampleLen
);
3414 bufferLen
= max_len
;
3416 if(bufferLen
> offset
-totalBufferLen
)
3418 /* Offset is in this buffer */
3419 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3420 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_relaxed
);
3421 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_release
);
3425 totalBufferLen
+= bufferLen
;
3427 BufferList
= ATOMIC_LOAD(&BufferList
->next
, almemory_order_relaxed
);
3430 /* Offset is out of range of the queue */
3437 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3438 * or Second offset supplied by the application). This takes into account the
3439 * fact that the buffer format may have been modifed since.
3441 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3443 const ALbuffer
*BufferFmt
= NULL
;
3444 const ALbufferlistitem
*BufferList
;
3445 ALdouble dbloff
, dblfrac
;
3447 /* Find the first valid Buffer in the Queue */
3448 BufferList
= Source
->queue
;
3452 for(i
= 0;i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
3453 BufferFmt
= BufferList
->buffers
[i
];
3454 if(BufferFmt
) break;
3455 BufferList
= ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem
*,BufferList
)->next
,
3456 almemory_order_relaxed
);
3460 Source
->OffsetType
= AL_NONE
;
3461 Source
->Offset
= 0.0;
3465 switch(Source
->OffsetType
)
3467 case AL_BYTE_OFFSET
:
3468 /* Determine the ByteOffset (and ensure it is block aligned) */
3469 *offset
= (ALuint
)Source
->Offset
;
3470 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
3472 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
3473 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3474 *offset
*= BufferFmt
->OriginalAlign
;
3476 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
3478 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
3479 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
3480 *offset
*= BufferFmt
->OriginalAlign
;
3483 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
3487 case AL_SAMPLE_OFFSET
:
3488 dblfrac
= modf(Source
->Offset
, &dbloff
);
3489 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3490 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3494 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
3495 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3496 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3499 Source
->OffsetType
= AL_NONE
;
3500 Source
->Offset
= 0.0;
3506 static ALsource
*AllocSource(ALCcontext
*context
)
3508 ALCdevice
*device
= context
->Device
;
3509 SourceSubList
*sublist
, *subend
;
3510 ALsource
*source
= NULL
;
3514 almtx_lock(&context
->SourceLock
);
3515 if(context
->NumSources
>= device
->SourcesMax
)
3517 almtx_unlock(&context
->SourceLock
);
3518 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
3521 sublist
= VECTOR_BEGIN(context
->SourceList
);
3522 subend
= VECTOR_END(context
->SourceList
);
3523 for(;sublist
!= subend
;++sublist
)
3525 if(sublist
->FreeMask
)
3527 slidx
= CTZ64(sublist
->FreeMask
);
3528 source
= sublist
->Sources
+ slidx
;
3533 if(UNLIKELY(!source
))
3535 const SourceSubList empty_sublist
= { 0, NULL
};
3536 /* Don't allocate so many list entries that the 32-bit ID could
3539 if(UNLIKELY(VECTOR_SIZE(context
->SourceList
) >= 1<<25))
3541 almtx_unlock(&device
->BufferLock
);
3542 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
3545 lidx
= (ALsizei
)VECTOR_SIZE(context
->SourceList
);
3546 VECTOR_PUSH_BACK(context
->SourceList
, empty_sublist
);
3547 sublist
= &VECTOR_BACK(context
->SourceList
);
3548 sublist
->FreeMask
= ~U64(0);
3549 sublist
->Sources
= al_calloc(16, sizeof(ALsource
)*64);
3550 if(UNLIKELY(!sublist
->Sources
))
3552 VECTOR_POP_BACK(context
->SourceList
);
3553 almtx_unlock(&context
->SourceLock
);
3554 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
3559 source
= sublist
->Sources
+ slidx
;
3562 memset(source
, 0, sizeof(*source
));
3563 InitSourceParams(source
, device
->NumAuxSends
);
3565 /* Add 1 to avoid source ID 0. */
3566 source
->id
= ((lidx
<<6) | slidx
) + 1;
3568 context
->NumSources
++;
3569 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
3570 almtx_unlock(&context
->SourceLock
);
3575 static void FreeSource(ALCcontext
*context
, ALsource
*source
)
3577 ALCdevice
*device
= context
->Device
;
3578 ALuint id
= source
->id
- 1;
3579 ALsizei lidx
= id
>> 6;
3580 ALsizei slidx
= id
& 0x3f;
3583 ALCdevice_Lock(device
);
3584 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
3586 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
3587 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
3589 ALCdevice_Unlock(device
);
3591 DeinitSource(source
, device
->NumAuxSends
);
3592 memset(source
, 0, sizeof(*source
));
3594 VECTOR_ELEM(context
->SourceList
, lidx
).FreeMask
|= U64(1) << slidx
;
3595 context
->NumSources
--;
3600 * Destroys all sources in the source map.
3602 ALvoid
ReleaseALSources(ALCcontext
*context
)
3604 ALCdevice
*device
= context
->Device
;
3605 SourceSubList
*sublist
= VECTOR_BEGIN(context
->SourceList
);
3606 SourceSubList
*subend
= VECTOR_END(context
->SourceList
);
3607 size_t leftover
= 0;
3608 for(;sublist
!= subend
;++sublist
)
3610 ALuint64 usemask
= ~sublist
->FreeMask
;
3613 ALsizei idx
= CTZ64(usemask
);
3614 ALsource
*source
= sublist
->Sources
+ idx
;
3616 DeinitSource(source
, device
->NumAuxSends
);
3617 memset(source
, 0, sizeof(*source
));
3620 usemask
&= ~(U64(1) << idx
);
3622 sublist
->FreeMask
= ~usemask
;
3625 WARN("(%p) Deleted "SZFMT
" Source%s\n", device
, leftover
, (leftover
==1)?"":"s");