2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
43 extern inline void LockSourcesRead(ALCcontext
*context
);
44 extern inline void UnlockSourcesRead(ALCcontext
*context
);
45 extern inline void LockSourcesWrite(ALCcontext
*context
);
46 extern inline void UnlockSourcesWrite(ALCcontext
*context
);
47 extern inline struct ALsource
*LookupSource(ALCcontext
*context
, ALuint id
);
48 extern inline struct ALsource
*RemoveSource(ALCcontext
*context
, ALuint id
);
50 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
51 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
52 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
);
53 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
54 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
);
56 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
);
57 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
);
59 typedef enum SourceProp
{
62 srcMinGain
= AL_MIN_GAIN
,
63 srcMaxGain
= AL_MAX_GAIN
,
64 srcMaxDistance
= AL_MAX_DISTANCE
,
65 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
66 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
67 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
68 srcSecOffset
= AL_SEC_OFFSET
,
69 srcSampleOffset
= AL_SAMPLE_OFFSET
,
70 srcByteOffset
= AL_BYTE_OFFSET
,
71 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
72 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
73 srcRefDistance
= AL_REFERENCE_DISTANCE
,
75 srcPosition
= AL_POSITION
,
76 srcVelocity
= AL_VELOCITY
,
77 srcDirection
= AL_DIRECTION
,
79 srcSourceRelative
= AL_SOURCE_RELATIVE
,
80 srcLooping
= AL_LOOPING
,
81 srcBuffer
= AL_BUFFER
,
82 srcSourceState
= AL_SOURCE_STATE
,
83 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
84 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
85 srcSourceType
= AL_SOURCE_TYPE
,
88 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
89 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
90 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
91 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
92 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
93 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
94 srcDirectFilter
= AL_DIRECT_FILTER
,
95 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel
= AL_DISTANCE_MODEL
,
103 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
104 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
105 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
109 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles
= AL_STEREO_ANGLES
,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius
= AL_SOURCE_RADIUS
,
118 srcOrientation
= AL_ORIENTATION
,
121 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
122 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
123 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
125 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
126 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
127 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
129 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
131 ALvoice
**voice
= context
->Voices
;
132 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
133 while(voice
!= voice_end
)
135 if(ATOMIC_LOAD(&(*voice
)->Source
, almemory_order_acquire
) == source
)
143 * Returns if the last known state for the source was playing or paused. Does
144 * not sync with the mixer voice.
146 static inline bool IsPlayingOrPaused(ALsource
*source
)
148 ALenum state
= ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
149 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
153 * Returns an updated source state using the matching voice's status (or lack
156 static inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
160 ALenum state
= AL_PLAYING
;
161 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source
->state
, &state
, AL_STOPPED
,
162 almemory_order_acq_rel
, almemory_order_acquire
))
166 return ATOMIC_LOAD(&source
->state
, almemory_order_acquire
);
170 * Returns if the source should specify an update, given the context's
171 * deferring state and the source's last known state.
173 static inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
175 return !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) &&
176 IsPlayingOrPaused(source
);
179 static ALint
FloatValsByProp(ALenum prop
)
181 if(prop
!= (ALenum
)((SourceProp
)prop
))
183 switch((SourceProp
)prop
)
189 case AL_MAX_DISTANCE
:
190 case AL_ROLLOFF_FACTOR
:
191 case AL_DOPPLER_FACTOR
:
192 case AL_CONE_OUTER_GAIN
:
194 case AL_SAMPLE_OFFSET
:
196 case AL_CONE_INNER_ANGLE
:
197 case AL_CONE_OUTER_ANGLE
:
198 case AL_REFERENCE_DISTANCE
:
199 case AL_CONE_OUTER_GAINHF
:
200 case AL_AIR_ABSORPTION_FACTOR
:
201 case AL_ROOM_ROLLOFF_FACTOR
:
202 case AL_DIRECT_FILTER_GAINHF_AUTO
:
203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
205 case AL_DIRECT_CHANNELS_SOFT
:
206 case AL_DISTANCE_MODEL
:
207 case AL_SOURCE_RELATIVE
:
209 case AL_SOURCE_STATE
:
210 case AL_BUFFERS_QUEUED
:
211 case AL_BUFFERS_PROCESSED
:
213 case AL_BYTE_LENGTH_SOFT
:
214 case AL_SAMPLE_LENGTH_SOFT
:
215 case AL_SEC_LENGTH_SOFT
:
216 case AL_SOURCE_RADIUS
:
219 case AL_STEREO_ANGLES
:
230 case AL_SEC_OFFSET_LATENCY_SOFT
:
231 break; /* Double only */
234 case AL_DIRECT_FILTER
:
235 case AL_AUXILIARY_SEND_FILTER
:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
238 break; /* i64 only */
242 static ALint
DoubleValsByProp(ALenum prop
)
244 if(prop
!= (ALenum
)((SourceProp
)prop
))
246 switch((SourceProp
)prop
)
252 case AL_MAX_DISTANCE
:
253 case AL_ROLLOFF_FACTOR
:
254 case AL_DOPPLER_FACTOR
:
255 case AL_CONE_OUTER_GAIN
:
257 case AL_SAMPLE_OFFSET
:
259 case AL_CONE_INNER_ANGLE
:
260 case AL_CONE_OUTER_ANGLE
:
261 case AL_REFERENCE_DISTANCE
:
262 case AL_CONE_OUTER_GAINHF
:
263 case AL_AIR_ABSORPTION_FACTOR
:
264 case AL_ROOM_ROLLOFF_FACTOR
:
265 case AL_DIRECT_FILTER_GAINHF_AUTO
:
266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
268 case AL_DIRECT_CHANNELS_SOFT
:
269 case AL_DISTANCE_MODEL
:
270 case AL_SOURCE_RELATIVE
:
272 case AL_SOURCE_STATE
:
273 case AL_BUFFERS_QUEUED
:
274 case AL_BUFFERS_PROCESSED
:
276 case AL_BYTE_LENGTH_SOFT
:
277 case AL_SAMPLE_LENGTH_SOFT
:
278 case AL_SEC_LENGTH_SOFT
:
279 case AL_SOURCE_RADIUS
:
282 case AL_SEC_OFFSET_LATENCY_SOFT
:
283 case AL_STEREO_ANGLES
:
295 case AL_DIRECT_FILTER
:
296 case AL_AUXILIARY_SEND_FILTER
:
297 break; /* i/i64 only */
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
299 break; /* i64 only */
304 static ALint
IntValsByProp(ALenum prop
)
306 if(prop
!= (ALenum
)((SourceProp
)prop
))
308 switch((SourceProp
)prop
)
314 case AL_MAX_DISTANCE
:
315 case AL_ROLLOFF_FACTOR
:
316 case AL_DOPPLER_FACTOR
:
317 case AL_CONE_OUTER_GAIN
:
319 case AL_SAMPLE_OFFSET
:
321 case AL_CONE_INNER_ANGLE
:
322 case AL_CONE_OUTER_ANGLE
:
323 case AL_REFERENCE_DISTANCE
:
324 case AL_CONE_OUTER_GAINHF
:
325 case AL_AIR_ABSORPTION_FACTOR
:
326 case AL_ROOM_ROLLOFF_FACTOR
:
327 case AL_DIRECT_FILTER_GAINHF_AUTO
:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
330 case AL_DIRECT_CHANNELS_SOFT
:
331 case AL_DISTANCE_MODEL
:
332 case AL_SOURCE_RELATIVE
:
335 case AL_SOURCE_STATE
:
336 case AL_BUFFERS_QUEUED
:
337 case AL_BUFFERS_PROCESSED
:
339 case AL_DIRECT_FILTER
:
340 case AL_BYTE_LENGTH_SOFT
:
341 case AL_SAMPLE_LENGTH_SOFT
:
342 case AL_SEC_LENGTH_SOFT
:
343 case AL_SOURCE_RADIUS
:
349 case AL_AUXILIARY_SEND_FILTER
:
355 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
356 break; /* i64 only */
357 case AL_SEC_OFFSET_LATENCY_SOFT
:
358 break; /* Double only */
359 case AL_STEREO_ANGLES
:
360 break; /* Float/double only */
364 static ALint
Int64ValsByProp(ALenum prop
)
366 if(prop
!= (ALenum
)((SourceProp
)prop
))
368 switch((SourceProp
)prop
)
374 case AL_MAX_DISTANCE
:
375 case AL_ROLLOFF_FACTOR
:
376 case AL_DOPPLER_FACTOR
:
377 case AL_CONE_OUTER_GAIN
:
379 case AL_SAMPLE_OFFSET
:
381 case AL_CONE_INNER_ANGLE
:
382 case AL_CONE_OUTER_ANGLE
:
383 case AL_REFERENCE_DISTANCE
:
384 case AL_CONE_OUTER_GAINHF
:
385 case AL_AIR_ABSORPTION_FACTOR
:
386 case AL_ROOM_ROLLOFF_FACTOR
:
387 case AL_DIRECT_FILTER_GAINHF_AUTO
:
388 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
389 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
390 case AL_DIRECT_CHANNELS_SOFT
:
391 case AL_DISTANCE_MODEL
:
392 case AL_SOURCE_RELATIVE
:
395 case AL_SOURCE_STATE
:
396 case AL_BUFFERS_QUEUED
:
397 case AL_BUFFERS_PROCESSED
:
399 case AL_DIRECT_FILTER
:
400 case AL_BYTE_LENGTH_SOFT
:
401 case AL_SAMPLE_LENGTH_SOFT
:
402 case AL_SEC_LENGTH_SOFT
:
403 case AL_SOURCE_RADIUS
:
406 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
412 case AL_AUXILIARY_SEND_FILTER
:
418 case AL_SEC_OFFSET_LATENCY_SOFT
:
419 break; /* Double only */
420 case AL_STEREO_ANGLES
:
421 break; /* Float/double only */
427 #define CHECKVAL(x) do { \
429 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
432 #define DO_UPDATEPROPS() do { \
433 if(SourceShouldUpdate(Source, Context)) \
434 UpdateSourceProps(Source, device->NumAuxSends); \
436 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
439 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
441 ALCdevice
*device
= Context
->Device
;
446 case AL_BYTE_LENGTH_SOFT
:
447 case AL_SAMPLE_LENGTH_SOFT
:
448 case AL_SEC_LENGTH_SOFT
:
449 case AL_SEC_OFFSET_LATENCY_SOFT
:
451 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
454 CHECKVAL(*values
>= 0.0f
);
456 Source
->Pitch
= *values
;
460 case AL_CONE_INNER_ANGLE
:
461 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
463 Source
->InnerAngle
= *values
;
467 case AL_CONE_OUTER_ANGLE
:
468 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
470 Source
->OuterAngle
= *values
;
475 CHECKVAL(*values
>= 0.0f
);
477 Source
->Gain
= *values
;
481 case AL_MAX_DISTANCE
:
482 CHECKVAL(*values
>= 0.0f
);
484 Source
->MaxDistance
= *values
;
488 case AL_ROLLOFF_FACTOR
:
489 CHECKVAL(*values
>= 0.0f
);
491 Source
->RollOffFactor
= *values
;
495 case AL_REFERENCE_DISTANCE
:
496 CHECKVAL(*values
>= 0.0f
);
498 Source
->RefDistance
= *values
;
503 CHECKVAL(*values
>= 0.0f
);
505 Source
->MinGain
= *values
;
510 CHECKVAL(*values
>= 0.0f
);
512 Source
->MaxGain
= *values
;
516 case AL_CONE_OUTER_GAIN
:
517 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
519 Source
->OuterGain
= *values
;
523 case AL_CONE_OUTER_GAINHF
:
524 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
526 Source
->OuterGainHF
= *values
;
530 case AL_AIR_ABSORPTION_FACTOR
:
531 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
533 Source
->AirAbsorptionFactor
= *values
;
537 case AL_ROOM_ROLLOFF_FACTOR
:
538 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
540 Source
->RoomRolloffFactor
= *values
;
544 case AL_DOPPLER_FACTOR
:
545 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
547 Source
->DopplerFactor
= *values
;
552 case AL_SAMPLE_OFFSET
:
554 CHECKVAL(*values
>= 0.0f
);
556 Source
->OffsetType
= prop
;
557 Source
->Offset
= *values
;
559 if(IsPlayingOrPaused(Source
))
563 ALCdevice_Lock(Context
->Device
);
564 /* Double-check that the source is still playing while we have
567 voice
= GetSourceVoice(Source
, Context
);
570 WriteLock(&Source
->queue_lock
);
571 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
573 WriteUnlock(&Source
->queue_lock
);
574 ALCdevice_Unlock(Context
->Device
);
575 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
577 WriteUnlock(&Source
->queue_lock
);
579 ALCdevice_Unlock(Context
->Device
);
583 case AL_SOURCE_RADIUS
:
584 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
586 Source
->Radius
= *values
;
590 case AL_STEREO_ANGLES
:
591 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
593 Source
->StereoPan
[0] = values
[0];
594 Source
->StereoPan
[1] = values
[1];
600 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
602 Source
->Position
[0] = values
[0];
603 Source
->Position
[1] = values
[1];
604 Source
->Position
[2] = values
[2];
609 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
611 Source
->Velocity
[0] = values
[0];
612 Source
->Velocity
[1] = values
[1];
613 Source
->Velocity
[2] = values
[2];
618 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
620 Source
->Direction
[0] = values
[0];
621 Source
->Direction
[1] = values
[1];
622 Source
->Direction
[2] = values
[2];
627 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
628 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
630 Source
->Orientation
[0][0] = values
[0];
631 Source
->Orientation
[0][1] = values
[1];
632 Source
->Orientation
[0][2] = values
[2];
633 Source
->Orientation
[1][0] = values
[3];
634 Source
->Orientation
[1][1] = values
[4];
635 Source
->Orientation
[1][2] = values
[5];
640 case AL_SOURCE_RELATIVE
:
642 case AL_SOURCE_STATE
:
644 case AL_DISTANCE_MODEL
:
645 case AL_DIRECT_FILTER_GAINHF_AUTO
:
646 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
647 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
648 case AL_DIRECT_CHANNELS_SOFT
:
649 ival
= (ALint
)values
[0];
650 return SetSourceiv(Source
, Context
, prop
, &ival
);
652 case AL_BUFFERS_QUEUED
:
653 case AL_BUFFERS_PROCESSED
:
654 ival
= (ALint
)((ALuint
)values
[0]);
655 return SetSourceiv(Source
, Context
, prop
, &ival
);
658 case AL_DIRECT_FILTER
:
659 case AL_AUXILIARY_SEND_FILTER
:
660 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
664 ERR("Unexpected property: 0x%04x\n", prop
);
665 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
668 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
670 ALCdevice
*device
= Context
->Device
;
671 ALbuffer
*buffer
= NULL
;
672 ALfilter
*filter
= NULL
;
673 ALeffectslot
*slot
= NULL
;
674 ALbufferlistitem
*oldlist
;
675 ALbufferlistitem
*newlist
;
680 case AL_SOURCE_STATE
:
682 case AL_BUFFERS_QUEUED
:
683 case AL_BUFFERS_PROCESSED
:
684 case AL_BYTE_LENGTH_SOFT
:
685 case AL_SAMPLE_LENGTH_SOFT
:
686 case AL_SEC_LENGTH_SOFT
:
688 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
690 case AL_SOURCE_RELATIVE
:
691 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
693 Source
->HeadRelative
= (ALboolean
)*values
;
698 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
700 WriteLock(&Source
->queue_lock
);
701 ATOMIC_STORE_SEQ(&Source
->looping
, *values
);
702 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) == AL_PLAYING
)
704 /* If the source is playing, wait for the current mix to finish
705 * to ensure it isn't currently looping back or reaching the
708 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
711 WriteUnlock(&Source
->queue_lock
);
715 LockBuffersRead(device
);
716 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
718 UnlockBuffersRead(device
);
719 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
722 WriteLock(&Source
->queue_lock
);
724 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
725 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
727 WriteUnlock(&Source
->queue_lock
);
728 UnlockBuffersRead(device
);
729 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
735 /* Add the selected buffer to a one-item queue */
736 newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
737 newlist
->buffer
= buffer
;
738 newlist
->next
= NULL
;
739 IncrementRef(&buffer
->ref
);
741 /* Source is now Static */
742 Source
->SourceType
= AL_STATIC
;
746 /* Source is now Undetermined */
747 Source
->SourceType
= AL_UNDETERMINED
;
750 oldlist
= ATOMIC_EXCHANGE_PTR_SEQ(&Source
->queue
, newlist
);
751 WriteUnlock(&Source
->queue_lock
);
752 UnlockBuffersRead(device
);
754 /* Delete all elements in the previous queue */
755 while(oldlist
!= NULL
)
757 ALbufferlistitem
*temp
= oldlist
;
758 oldlist
= temp
->next
;
761 DecrementRef(&temp
->buffer
->ref
);
767 case AL_SAMPLE_OFFSET
:
769 CHECKVAL(*values
>= 0);
771 Source
->OffsetType
= prop
;
772 Source
->Offset
= *values
;
774 if(IsPlayingOrPaused(Source
))
778 ALCdevice_Lock(Context
->Device
);
779 voice
= GetSourceVoice(Source
, Context
);
782 WriteLock(&Source
->queue_lock
);
783 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
785 WriteUnlock(&Source
->queue_lock
);
786 ALCdevice_Unlock(Context
->Device
);
787 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
789 WriteUnlock(&Source
->queue_lock
);
791 ALCdevice_Unlock(Context
->Device
);
795 case AL_DIRECT_FILTER
:
796 LockFiltersRead(device
);
797 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
799 UnlockFiltersRead(device
);
800 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
805 Source
->Direct
.Gain
= 1.0f
;
806 Source
->Direct
.GainHF
= 1.0f
;
807 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
808 Source
->Direct
.GainLF
= 1.0f
;
809 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
813 Source
->Direct
.Gain
= filter
->Gain
;
814 Source
->Direct
.GainHF
= filter
->GainHF
;
815 Source
->Direct
.HFReference
= filter
->HFReference
;
816 Source
->Direct
.GainLF
= filter
->GainLF
;
817 Source
->Direct
.LFReference
= filter
->LFReference
;
819 UnlockFiltersRead(device
);
823 case AL_DIRECT_FILTER_GAINHF_AUTO
:
824 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
826 Source
->DryGainHFAuto
= *values
;
830 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
831 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
833 Source
->WetGainAuto
= *values
;
837 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
838 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
840 Source
->WetGainHFAuto
= *values
;
844 case AL_DIRECT_CHANNELS_SOFT
:
845 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
847 Source
->DirectChannels
= *values
;
851 case AL_DISTANCE_MODEL
:
852 CHECKVAL(*values
== AL_NONE
||
853 *values
== AL_INVERSE_DISTANCE
||
854 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
855 *values
== AL_LINEAR_DISTANCE
||
856 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
857 *values
== AL_EXPONENT_DISTANCE
||
858 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
860 Source
->DistanceModel
= *values
;
861 if(Context
->SourceDistanceModel
)
866 case AL_AUXILIARY_SEND_FILTER
:
867 LockEffectSlotsRead(Context
);
868 LockFiltersRead(device
);
869 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
870 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
871 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
873 UnlockFiltersRead(device
);
874 UnlockEffectSlotsRead(Context
);
875 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
881 Source
->Send
[values
[1]].Gain
= 1.0f
;
882 Source
->Send
[values
[1]].GainHF
= 1.0f
;
883 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
884 Source
->Send
[values
[1]].GainLF
= 1.0f
;
885 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
889 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
890 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
891 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
892 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
893 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
895 UnlockFiltersRead(device
);
897 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
899 /* Add refcount on the new slot, and release the previous slot */
900 if(slot
) IncrementRef(&slot
->ref
);
901 if(Source
->Send
[values
[1]].Slot
)
902 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
903 Source
->Send
[values
[1]].Slot
= slot
;
905 /* We must force an update if the auxiliary slot changed on a
906 * playing source, in case the slot is about to be deleted.
908 UpdateSourceProps(Source
, device
->NumAuxSends
);
912 if(slot
) IncrementRef(&slot
->ref
);
913 if(Source
->Send
[values
[1]].Slot
)
914 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
915 Source
->Send
[values
[1]].Slot
= slot
;
918 UnlockEffectSlotsRead(Context
);
924 case AL_CONE_INNER_ANGLE
:
925 case AL_CONE_OUTER_ANGLE
:
930 case AL_REFERENCE_DISTANCE
:
931 case AL_ROLLOFF_FACTOR
:
932 case AL_CONE_OUTER_GAIN
:
933 case AL_MAX_DISTANCE
:
934 case AL_DOPPLER_FACTOR
:
935 case AL_CONE_OUTER_GAINHF
:
936 case AL_AIR_ABSORPTION_FACTOR
:
937 case AL_ROOM_ROLLOFF_FACTOR
:
938 case AL_SOURCE_RADIUS
:
939 fvals
[0] = (ALfloat
)*values
;
940 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
946 fvals
[0] = (ALfloat
)values
[0];
947 fvals
[1] = (ALfloat
)values
[1];
948 fvals
[2] = (ALfloat
)values
[2];
949 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
953 fvals
[0] = (ALfloat
)values
[0];
954 fvals
[1] = (ALfloat
)values
[1];
955 fvals
[2] = (ALfloat
)values
[2];
956 fvals
[3] = (ALfloat
)values
[3];
957 fvals
[4] = (ALfloat
)values
[4];
958 fvals
[5] = (ALfloat
)values
[5];
959 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
961 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
962 case AL_SEC_OFFSET_LATENCY_SOFT
:
963 case AL_STEREO_ANGLES
:
967 ERR("Unexpected property: 0x%04x\n", prop
);
968 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
971 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
979 case AL_BUFFERS_QUEUED
:
980 case AL_BUFFERS_PROCESSED
:
981 case AL_SOURCE_STATE
:
982 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
983 case AL_BYTE_LENGTH_SOFT
:
984 case AL_SAMPLE_LENGTH_SOFT
:
985 case AL_SEC_LENGTH_SOFT
:
987 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
991 case AL_SOURCE_RELATIVE
:
994 case AL_SAMPLE_OFFSET
:
996 case AL_DIRECT_FILTER_GAINHF_AUTO
:
997 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
998 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
999 case AL_DIRECT_CHANNELS_SOFT
:
1000 case AL_DISTANCE_MODEL
:
1001 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1003 ivals
[0] = (ALint
)*values
;
1004 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1008 case AL_DIRECT_FILTER
:
1009 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1011 ivals
[0] = (ALuint
)*values
;
1012 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1015 case AL_AUXILIARY_SEND_FILTER
:
1016 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1017 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1018 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1020 ivals
[0] = (ALuint
)values
[0];
1021 ivals
[1] = (ALuint
)values
[1];
1022 ivals
[2] = (ALuint
)values
[2];
1023 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1026 case AL_CONE_INNER_ANGLE
:
1027 case AL_CONE_OUTER_ANGLE
:
1032 case AL_REFERENCE_DISTANCE
:
1033 case AL_ROLLOFF_FACTOR
:
1034 case AL_CONE_OUTER_GAIN
:
1035 case AL_MAX_DISTANCE
:
1036 case AL_DOPPLER_FACTOR
:
1037 case AL_CONE_OUTER_GAINHF
:
1038 case AL_AIR_ABSORPTION_FACTOR
:
1039 case AL_ROOM_ROLLOFF_FACTOR
:
1040 case AL_SOURCE_RADIUS
:
1041 fvals
[0] = (ALfloat
)*values
;
1042 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1048 fvals
[0] = (ALfloat
)values
[0];
1049 fvals
[1] = (ALfloat
)values
[1];
1050 fvals
[2] = (ALfloat
)values
[2];
1051 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1054 case AL_ORIENTATION
:
1055 fvals
[0] = (ALfloat
)values
[0];
1056 fvals
[1] = (ALfloat
)values
[1];
1057 fvals
[2] = (ALfloat
)values
[2];
1058 fvals
[3] = (ALfloat
)values
[3];
1059 fvals
[4] = (ALfloat
)values
[4];
1060 fvals
[5] = (ALfloat
)values
[5];
1061 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1063 case AL_SEC_OFFSET_LATENCY_SOFT
:
1064 case AL_STEREO_ANGLES
:
1068 ERR("Unexpected property: 0x%04x\n", prop
);
1069 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1075 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1077 ALCdevice
*device
= Context
->Device
;
1078 ALbufferlistitem
*BufferList
;
1079 ClockLatency clocktime
;
1087 *values
= Source
->Gain
;
1091 *values
= Source
->Pitch
;
1094 case AL_MAX_DISTANCE
:
1095 *values
= Source
->MaxDistance
;
1098 case AL_ROLLOFF_FACTOR
:
1099 *values
= Source
->RollOffFactor
;
1102 case AL_REFERENCE_DISTANCE
:
1103 *values
= Source
->RefDistance
;
1106 case AL_CONE_INNER_ANGLE
:
1107 *values
= Source
->InnerAngle
;
1110 case AL_CONE_OUTER_ANGLE
:
1111 *values
= Source
->OuterAngle
;
1115 *values
= Source
->MinGain
;
1119 *values
= Source
->MaxGain
;
1122 case AL_CONE_OUTER_GAIN
:
1123 *values
= Source
->OuterGain
;
1127 case AL_SAMPLE_OFFSET
:
1128 case AL_BYTE_OFFSET
:
1129 *values
= GetSourceOffset(Source
, prop
, Context
);
1132 case AL_CONE_OUTER_GAINHF
:
1133 *values
= Source
->OuterGainHF
;
1136 case AL_AIR_ABSORPTION_FACTOR
:
1137 *values
= Source
->AirAbsorptionFactor
;
1140 case AL_ROOM_ROLLOFF_FACTOR
:
1141 *values
= Source
->RoomRolloffFactor
;
1144 case AL_DOPPLER_FACTOR
:
1145 *values
= Source
->DopplerFactor
;
1148 case AL_SEC_LENGTH_SOFT
:
1149 ReadLock(&Source
->queue_lock
);
1150 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1157 ALbuffer
*buffer
= BufferList
->buffer
;
1158 if(buffer
&& buffer
->SampleLen
> 0)
1160 freq
= buffer
->Frequency
;
1161 length
+= buffer
->SampleLen
;
1163 } while((BufferList
=BufferList
->next
) != NULL
);
1164 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1166 ReadUnlock(&Source
->queue_lock
);
1169 case AL_SOURCE_RADIUS
:
1170 *values
= Source
->Radius
;
1173 case AL_STEREO_ANGLES
:
1174 values
[0] = Source
->StereoPan
[0];
1175 values
[1] = Source
->StereoPan
[1];
1178 case AL_SEC_OFFSET_LATENCY_SOFT
:
1179 /* Get the source offset with the clock time first. Then get the
1180 * clock time with the device latency. Order is important.
1182 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1183 clocktime
= V0(device
->Backend
,getClockLatency
)();
1184 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1185 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1188 /* If the clock time incremented, reduce the latency by that
1189 * much since it's that much closer to the source offset it got
1192 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1193 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1199 values
[0] = Source
->Position
[0];
1200 values
[1] = Source
->Position
[1];
1201 values
[2] = Source
->Position
[2];
1205 values
[0] = Source
->Velocity
[0];
1206 values
[1] = Source
->Velocity
[1];
1207 values
[2] = Source
->Velocity
[2];
1211 values
[0] = Source
->Direction
[0];
1212 values
[1] = Source
->Direction
[1];
1213 values
[2] = Source
->Direction
[2];
1216 case AL_ORIENTATION
:
1217 values
[0] = Source
->Orientation
[0][0];
1218 values
[1] = Source
->Orientation
[0][1];
1219 values
[2] = Source
->Orientation
[0][2];
1220 values
[3] = Source
->Orientation
[1][0];
1221 values
[4] = Source
->Orientation
[1][1];
1222 values
[5] = Source
->Orientation
[1][2];
1226 case AL_SOURCE_RELATIVE
:
1228 case AL_SOURCE_STATE
:
1229 case AL_BUFFERS_QUEUED
:
1230 case AL_BUFFERS_PROCESSED
:
1231 case AL_SOURCE_TYPE
:
1232 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1233 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1234 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1235 case AL_DIRECT_CHANNELS_SOFT
:
1236 case AL_BYTE_LENGTH_SOFT
:
1237 case AL_SAMPLE_LENGTH_SOFT
:
1238 case AL_DISTANCE_MODEL
:
1239 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1240 *values
= (ALdouble
)ivals
[0];
1244 case AL_DIRECT_FILTER
:
1245 case AL_AUXILIARY_SEND_FILTER
:
1246 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1250 ERR("Unexpected property: 0x%04x\n", prop
);
1251 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1254 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1256 ALbufferlistitem
*BufferList
;
1262 case AL_SOURCE_RELATIVE
:
1263 *values
= Source
->HeadRelative
;
1267 *values
= ATOMIC_LOAD_SEQ(&Source
->looping
);
1271 ReadLock(&Source
->queue_lock
);
1272 BufferList
= (Source
->SourceType
== AL_STATIC
) ?
1273 ATOMIC_LOAD_SEQ(&Source
->queue
) : NULL
;
1274 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1275 ReadUnlock(&Source
->queue_lock
);
1278 case AL_SOURCE_STATE
:
1279 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1282 case AL_BYTE_LENGTH_SOFT
:
1283 ReadLock(&Source
->queue_lock
);
1284 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1290 ALbuffer
*buffer
= BufferList
->buffer
;
1291 if(buffer
&& buffer
->SampleLen
> 0)
1293 ALuint byte_align
, sample_align
;
1294 if(buffer
->OriginalType
== UserFmtIMA4
)
1296 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1297 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1298 sample_align
= buffer
->OriginalAlign
;
1300 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1302 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1303 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1304 sample_align
= buffer
->OriginalAlign
;
1308 ALsizei align
= buffer
->OriginalAlign
;
1309 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1310 sample_align
= buffer
->OriginalAlign
;
1313 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1315 } while((BufferList
=BufferList
->next
) != NULL
);
1318 ReadUnlock(&Source
->queue_lock
);
1321 case AL_SAMPLE_LENGTH_SOFT
:
1322 ReadLock(&Source
->queue_lock
);
1323 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1329 ALbuffer
*buffer
= BufferList
->buffer
;
1330 if(buffer
) length
+= buffer
->SampleLen
;
1331 } while((BufferList
=BufferList
->next
) != NULL
);
1334 ReadUnlock(&Source
->queue_lock
);
1337 case AL_BUFFERS_QUEUED
:
1338 ReadLock(&Source
->queue_lock
);
1339 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1346 } while((BufferList
=BufferList
->next
) != NULL
);
1349 ReadUnlock(&Source
->queue_lock
);
1352 case AL_BUFFERS_PROCESSED
:
1353 ReadLock(&Source
->queue_lock
);
1354 if(ATOMIC_LOAD_SEQ(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1356 /* Buffers on a looping source are in a perpetual state of
1357 * PENDING, so don't report any as PROCESSED */
1362 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
1363 const ALbufferlistitem
*Current
= NULL
;
1367 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1368 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1369 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1370 Current
= BufferList
;
1372 while(BufferList
&& BufferList
!= Current
)
1375 BufferList
= BufferList
->next
;
1379 ReadUnlock(&Source
->queue_lock
);
1382 case AL_SOURCE_TYPE
:
1383 *values
= Source
->SourceType
;
1386 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1387 *values
= Source
->DryGainHFAuto
;
1390 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1391 *values
= Source
->WetGainAuto
;
1394 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1395 *values
= Source
->WetGainHFAuto
;
1398 case AL_DIRECT_CHANNELS_SOFT
:
1399 *values
= Source
->DirectChannels
;
1402 case AL_DISTANCE_MODEL
:
1403 *values
= Source
->DistanceModel
;
1406 /* 1x float/double */
1407 case AL_CONE_INNER_ANGLE
:
1408 case AL_CONE_OUTER_ANGLE
:
1413 case AL_REFERENCE_DISTANCE
:
1414 case AL_ROLLOFF_FACTOR
:
1415 case AL_CONE_OUTER_GAIN
:
1416 case AL_MAX_DISTANCE
:
1418 case AL_SAMPLE_OFFSET
:
1419 case AL_BYTE_OFFSET
:
1420 case AL_DOPPLER_FACTOR
:
1421 case AL_AIR_ABSORPTION_FACTOR
:
1422 case AL_ROOM_ROLLOFF_FACTOR
:
1423 case AL_CONE_OUTER_GAINHF
:
1424 case AL_SEC_LENGTH_SOFT
:
1425 case AL_SOURCE_RADIUS
:
1426 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1427 *values
= (ALint
)dvals
[0];
1430 /* 3x float/double */
1434 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1436 values
[0] = (ALint
)dvals
[0];
1437 values
[1] = (ALint
)dvals
[1];
1438 values
[2] = (ALint
)dvals
[2];
1442 /* 6x float/double */
1443 case AL_ORIENTATION
:
1444 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1446 values
[0] = (ALint
)dvals
[0];
1447 values
[1] = (ALint
)dvals
[1];
1448 values
[2] = (ALint
)dvals
[2];
1449 values
[3] = (ALint
)dvals
[3];
1450 values
[4] = (ALint
)dvals
[4];
1451 values
[5] = (ALint
)dvals
[5];
1455 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1456 break; /* i64 only */
1457 case AL_SEC_OFFSET_LATENCY_SOFT
:
1458 break; /* Double only */
1459 case AL_STEREO_ANGLES
:
1460 break; /* Float/double only */
1462 case AL_DIRECT_FILTER
:
1463 case AL_AUXILIARY_SEND_FILTER
:
1467 ERR("Unexpected property: 0x%04x\n", prop
);
1468 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1471 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1473 ALCdevice
*device
= Context
->Device
;
1474 ClockLatency clocktime
;
1482 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1483 /* Get the source offset with the clock time first. Then get the
1484 * clock time with the device latency. Order is important.
1486 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1487 clocktime
= V0(device
->Backend
,getClockLatency
)();
1488 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1489 values
[1] = clocktime
.Latency
;
1492 /* If the clock time incremented, reduce the latency by that
1493 * much since it's that much closer to the source offset it got
1496 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1497 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1501 /* 1x float/double */
1502 case AL_CONE_INNER_ANGLE
:
1503 case AL_CONE_OUTER_ANGLE
:
1508 case AL_REFERENCE_DISTANCE
:
1509 case AL_ROLLOFF_FACTOR
:
1510 case AL_CONE_OUTER_GAIN
:
1511 case AL_MAX_DISTANCE
:
1513 case AL_SAMPLE_OFFSET
:
1514 case AL_BYTE_OFFSET
:
1515 case AL_DOPPLER_FACTOR
:
1516 case AL_AIR_ABSORPTION_FACTOR
:
1517 case AL_ROOM_ROLLOFF_FACTOR
:
1518 case AL_CONE_OUTER_GAINHF
:
1519 case AL_SEC_LENGTH_SOFT
:
1520 case AL_SOURCE_RADIUS
:
1521 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1522 *values
= (ALint64
)dvals
[0];
1525 /* 3x float/double */
1529 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1531 values
[0] = (ALint64
)dvals
[0];
1532 values
[1] = (ALint64
)dvals
[1];
1533 values
[2] = (ALint64
)dvals
[2];
1537 /* 6x float/double */
1538 case AL_ORIENTATION
:
1539 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1541 values
[0] = (ALint64
)dvals
[0];
1542 values
[1] = (ALint64
)dvals
[1];
1543 values
[2] = (ALint64
)dvals
[2];
1544 values
[3] = (ALint64
)dvals
[3];
1545 values
[4] = (ALint64
)dvals
[4];
1546 values
[5] = (ALint64
)dvals
[5];
1551 case AL_SOURCE_RELATIVE
:
1553 case AL_SOURCE_STATE
:
1554 case AL_BUFFERS_QUEUED
:
1555 case AL_BUFFERS_PROCESSED
:
1556 case AL_BYTE_LENGTH_SOFT
:
1557 case AL_SAMPLE_LENGTH_SOFT
:
1558 case AL_SOURCE_TYPE
:
1559 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1560 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1561 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1562 case AL_DIRECT_CHANNELS_SOFT
:
1563 case AL_DISTANCE_MODEL
:
1564 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1570 case AL_DIRECT_FILTER
:
1571 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1572 *values
= (ALuint
)ivals
[0];
1576 case AL_AUXILIARY_SEND_FILTER
:
1577 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1579 values
[0] = (ALuint
)ivals
[0];
1580 values
[1] = (ALuint
)ivals
[1];
1581 values
[2] = (ALuint
)ivals
[2];
1585 case AL_SEC_OFFSET_LATENCY_SOFT
:
1586 break; /* Double only */
1587 case AL_STEREO_ANGLES
:
1588 break; /* Float/double only */
1591 ERR("Unexpected property: 0x%04x\n", prop
);
1592 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1596 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1599 ALCcontext
*context
;
1603 context
= GetContextRef();
1604 if(!context
) return;
1607 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1608 device
= context
->Device
;
1609 for(cur
= 0;cur
< n
;cur
++)
1611 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1614 alDeleteSources(cur
, sources
);
1615 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1617 InitSourceParams(source
, device
->NumAuxSends
);
1619 err
= NewThunkEntry(&source
->id
);
1620 if(err
== AL_NO_ERROR
)
1621 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1622 if(err
!= AL_NO_ERROR
)
1624 FreeThunkEntry(source
->id
);
1625 memset(source
, 0, sizeof(ALsource
));
1628 alDeleteSources(cur
, sources
);
1629 SET_ERROR_AND_GOTO(context
, err
, done
);
1632 sources
[cur
] = source
->id
;
1636 ALCcontext_DecRef(context
);
1640 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1643 ALCcontext
*context
;
1647 context
= GetContextRef();
1648 if(!context
) return;
1650 LockSourcesWrite(context
);
1652 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1654 /* Check that all Sources are valid */
1655 for(i
= 0;i
< n
;i
++)
1657 if(LookupSource(context
, sources
[i
]) == NULL
)
1658 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1660 device
= context
->Device
;
1661 for(i
= 0;i
< n
;i
++)
1665 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1667 FreeThunkEntry(Source
->id
);
1669 ALCdevice_Lock(device
);
1670 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1672 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1673 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1675 ALCdevice_Unlock(device
);
1677 DeinitSource(Source
, device
->NumAuxSends
);
1679 memset(Source
, 0, sizeof(*Source
));
1684 UnlockSourcesWrite(context
);
1685 ALCcontext_DecRef(context
);
1689 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1691 ALCcontext
*context
;
1694 context
= GetContextRef();
1695 if(!context
) return AL_FALSE
;
1697 LockSourcesRead(context
);
1698 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1699 UnlockSourcesRead(context
);
1701 ALCcontext_DecRef(context
);
1707 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1709 ALCcontext
*Context
;
1712 Context
= GetContextRef();
1713 if(!Context
) return;
1715 WriteLock(&Context
->PropLock
);
1716 LockSourcesRead(Context
);
1717 if((Source
=LookupSource(Context
, source
)) == NULL
)
1718 alSetError(Context
, AL_INVALID_NAME
);
1719 else if(!(FloatValsByProp(param
) == 1))
1720 alSetError(Context
, AL_INVALID_ENUM
);
1722 SetSourcefv(Source
, Context
, param
, &value
);
1723 UnlockSourcesRead(Context
);
1724 WriteUnlock(&Context
->PropLock
);
1726 ALCcontext_DecRef(Context
);
1729 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1731 ALCcontext
*Context
;
1734 Context
= GetContextRef();
1735 if(!Context
) return;
1737 WriteLock(&Context
->PropLock
);
1738 LockSourcesRead(Context
);
1739 if((Source
=LookupSource(Context
, source
)) == NULL
)
1740 alSetError(Context
, AL_INVALID_NAME
);
1741 else if(!(FloatValsByProp(param
) == 3))
1742 alSetError(Context
, AL_INVALID_ENUM
);
1745 ALfloat fvals
[3] = { value1
, value2
, value3
};
1746 SetSourcefv(Source
, Context
, param
, fvals
);
1748 UnlockSourcesRead(Context
);
1749 WriteUnlock(&Context
->PropLock
);
1751 ALCcontext_DecRef(Context
);
1754 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1756 ALCcontext
*Context
;
1759 Context
= GetContextRef();
1760 if(!Context
) return;
1762 WriteLock(&Context
->PropLock
);
1763 LockSourcesRead(Context
);
1764 if((Source
=LookupSource(Context
, source
)) == NULL
)
1765 alSetError(Context
, AL_INVALID_NAME
);
1767 alSetError(Context
, AL_INVALID_VALUE
);
1768 else if(!(FloatValsByProp(param
) > 0))
1769 alSetError(Context
, AL_INVALID_ENUM
);
1771 SetSourcefv(Source
, Context
, param
, values
);
1772 UnlockSourcesRead(Context
);
1773 WriteUnlock(&Context
->PropLock
);
1775 ALCcontext_DecRef(Context
);
1779 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1781 ALCcontext
*Context
;
1784 Context
= GetContextRef();
1785 if(!Context
) return;
1787 WriteLock(&Context
->PropLock
);
1788 LockSourcesRead(Context
);
1789 if((Source
=LookupSource(Context
, source
)) == NULL
)
1790 alSetError(Context
, AL_INVALID_NAME
);
1791 else if(!(DoubleValsByProp(param
) == 1))
1792 alSetError(Context
, AL_INVALID_ENUM
);
1795 ALfloat fval
= (ALfloat
)value
;
1796 SetSourcefv(Source
, Context
, param
, &fval
);
1798 UnlockSourcesRead(Context
);
1799 WriteUnlock(&Context
->PropLock
);
1801 ALCcontext_DecRef(Context
);
1804 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1806 ALCcontext
*Context
;
1809 Context
= GetContextRef();
1810 if(!Context
) return;
1812 WriteLock(&Context
->PropLock
);
1813 LockSourcesRead(Context
);
1814 if((Source
=LookupSource(Context
, source
)) == NULL
)
1815 alSetError(Context
, AL_INVALID_NAME
);
1816 else if(!(DoubleValsByProp(param
) == 3))
1817 alSetError(Context
, AL_INVALID_ENUM
);
1820 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1821 SetSourcefv(Source
, Context
, param
, fvals
);
1823 UnlockSourcesRead(Context
);
1824 WriteUnlock(&Context
->PropLock
);
1826 ALCcontext_DecRef(Context
);
1829 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1831 ALCcontext
*Context
;
1835 Context
= GetContextRef();
1836 if(!Context
) return;
1838 WriteLock(&Context
->PropLock
);
1839 LockSourcesRead(Context
);
1840 if((Source
=LookupSource(Context
, source
)) == NULL
)
1841 alSetError(Context
, AL_INVALID_NAME
);
1843 alSetError(Context
, AL_INVALID_VALUE
);
1844 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1845 alSetError(Context
, AL_INVALID_ENUM
);
1851 for(i
= 0;i
< count
;i
++)
1852 fvals
[i
] = (ALfloat
)values
[i
];
1853 SetSourcefv(Source
, Context
, param
, fvals
);
1855 UnlockSourcesRead(Context
);
1856 WriteUnlock(&Context
->PropLock
);
1858 ALCcontext_DecRef(Context
);
1862 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1864 ALCcontext
*Context
;
1867 Context
= GetContextRef();
1868 if(!Context
) return;
1870 WriteLock(&Context
->PropLock
);
1871 LockSourcesRead(Context
);
1872 if((Source
=LookupSource(Context
, source
)) == NULL
)
1873 alSetError(Context
, AL_INVALID_NAME
);
1874 else if(!(IntValsByProp(param
) == 1))
1875 alSetError(Context
, AL_INVALID_ENUM
);
1877 SetSourceiv(Source
, Context
, param
, &value
);
1878 UnlockSourcesRead(Context
);
1879 WriteUnlock(&Context
->PropLock
);
1881 ALCcontext_DecRef(Context
);
1884 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1886 ALCcontext
*Context
;
1889 Context
= GetContextRef();
1890 if(!Context
) return;
1892 WriteLock(&Context
->PropLock
);
1893 LockSourcesRead(Context
);
1894 if((Source
=LookupSource(Context
, source
)) == NULL
)
1895 alSetError(Context
, AL_INVALID_NAME
);
1896 else if(!(IntValsByProp(param
) == 3))
1897 alSetError(Context
, AL_INVALID_ENUM
);
1900 ALint ivals
[3] = { value1
, value2
, value3
};
1901 SetSourceiv(Source
, Context
, param
, ivals
);
1903 UnlockSourcesRead(Context
);
1904 WriteUnlock(&Context
->PropLock
);
1906 ALCcontext_DecRef(Context
);
1909 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1911 ALCcontext
*Context
;
1914 Context
= GetContextRef();
1915 if(!Context
) return;
1917 WriteLock(&Context
->PropLock
);
1918 LockSourcesRead(Context
);
1919 if((Source
=LookupSource(Context
, source
)) == NULL
)
1920 alSetError(Context
, AL_INVALID_NAME
);
1922 alSetError(Context
, AL_INVALID_VALUE
);
1923 else if(!(IntValsByProp(param
) > 0))
1924 alSetError(Context
, AL_INVALID_ENUM
);
1926 SetSourceiv(Source
, Context
, param
, values
);
1927 UnlockSourcesRead(Context
);
1928 WriteUnlock(&Context
->PropLock
);
1930 ALCcontext_DecRef(Context
);
1934 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1936 ALCcontext
*Context
;
1939 Context
= GetContextRef();
1940 if(!Context
) return;
1942 WriteLock(&Context
->PropLock
);
1943 LockSourcesRead(Context
);
1944 if((Source
=LookupSource(Context
, source
)) == NULL
)
1945 alSetError(Context
, AL_INVALID_NAME
);
1946 else if(!(Int64ValsByProp(param
) == 1))
1947 alSetError(Context
, AL_INVALID_ENUM
);
1949 SetSourcei64v(Source
, Context
, param
, &value
);
1950 UnlockSourcesRead(Context
);
1951 WriteUnlock(&Context
->PropLock
);
1953 ALCcontext_DecRef(Context
);
1956 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1958 ALCcontext
*Context
;
1961 Context
= GetContextRef();
1962 if(!Context
) return;
1964 WriteLock(&Context
->PropLock
);
1965 LockSourcesRead(Context
);
1966 if((Source
=LookupSource(Context
, source
)) == NULL
)
1967 alSetError(Context
, AL_INVALID_NAME
);
1968 else if(!(Int64ValsByProp(param
) == 3))
1969 alSetError(Context
, AL_INVALID_ENUM
);
1972 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1973 SetSourcei64v(Source
, Context
, param
, i64vals
);
1975 UnlockSourcesRead(Context
);
1976 WriteUnlock(&Context
->PropLock
);
1978 ALCcontext_DecRef(Context
);
1981 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1983 ALCcontext
*Context
;
1986 Context
= GetContextRef();
1987 if(!Context
) return;
1989 WriteLock(&Context
->PropLock
);
1990 LockSourcesRead(Context
);
1991 if((Source
=LookupSource(Context
, source
)) == NULL
)
1992 alSetError(Context
, AL_INVALID_NAME
);
1994 alSetError(Context
, AL_INVALID_VALUE
);
1995 else if(!(Int64ValsByProp(param
) > 0))
1996 alSetError(Context
, AL_INVALID_ENUM
);
1998 SetSourcei64v(Source
, Context
, param
, values
);
1999 UnlockSourcesRead(Context
);
2000 WriteUnlock(&Context
->PropLock
);
2002 ALCcontext_DecRef(Context
);
2006 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2008 ALCcontext
*Context
;
2011 Context
= GetContextRef();
2012 if(!Context
) return;
2014 ReadLock(&Context
->PropLock
);
2015 LockSourcesRead(Context
);
2016 if((Source
=LookupSource(Context
, source
)) == NULL
)
2017 alSetError(Context
, AL_INVALID_NAME
);
2019 alSetError(Context
, AL_INVALID_VALUE
);
2020 else if(!(FloatValsByProp(param
) == 1))
2021 alSetError(Context
, AL_INVALID_ENUM
);
2025 if(GetSourcedv(Source
, Context
, param
, &dval
))
2026 *value
= (ALfloat
)dval
;
2028 UnlockSourcesRead(Context
);
2029 ReadUnlock(&Context
->PropLock
);
2031 ALCcontext_DecRef(Context
);
2035 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2037 ALCcontext
*Context
;
2040 Context
= GetContextRef();
2041 if(!Context
) return;
2043 ReadLock(&Context
->PropLock
);
2044 LockSourcesRead(Context
);
2045 if((Source
=LookupSource(Context
, source
)) == NULL
)
2046 alSetError(Context
, AL_INVALID_NAME
);
2047 else if(!(value1
&& value2
&& value3
))
2048 alSetError(Context
, AL_INVALID_VALUE
);
2049 else if(!(FloatValsByProp(param
) == 3))
2050 alSetError(Context
, AL_INVALID_ENUM
);
2054 if(GetSourcedv(Source
, Context
, param
, dvals
))
2056 *value1
= (ALfloat
)dvals
[0];
2057 *value2
= (ALfloat
)dvals
[1];
2058 *value3
= (ALfloat
)dvals
[2];
2061 UnlockSourcesRead(Context
);
2062 ReadUnlock(&Context
->PropLock
);
2064 ALCcontext_DecRef(Context
);
2068 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2070 ALCcontext
*Context
;
2074 Context
= GetContextRef();
2075 if(!Context
) return;
2077 ReadLock(&Context
->PropLock
);
2078 LockSourcesRead(Context
);
2079 if((Source
=LookupSource(Context
, source
)) == NULL
)
2080 alSetError(Context
, AL_INVALID_NAME
);
2082 alSetError(Context
, AL_INVALID_VALUE
);
2083 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2084 alSetError(Context
, AL_INVALID_ENUM
);
2088 if(GetSourcedv(Source
, Context
, param
, dvals
))
2091 for(i
= 0;i
< count
;i
++)
2092 values
[i
] = (ALfloat
)dvals
[i
];
2095 UnlockSourcesRead(Context
);
2096 ReadUnlock(&Context
->PropLock
);
2098 ALCcontext_DecRef(Context
);
2102 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2104 ALCcontext
*Context
;
2107 Context
= GetContextRef();
2108 if(!Context
) return;
2110 ReadLock(&Context
->PropLock
);
2111 LockSourcesRead(Context
);
2112 if((Source
=LookupSource(Context
, source
)) == NULL
)
2113 alSetError(Context
, AL_INVALID_NAME
);
2115 alSetError(Context
, AL_INVALID_VALUE
);
2116 else if(!(DoubleValsByProp(param
) == 1))
2117 alSetError(Context
, AL_INVALID_ENUM
);
2119 GetSourcedv(Source
, Context
, param
, value
);
2120 UnlockSourcesRead(Context
);
2121 ReadUnlock(&Context
->PropLock
);
2123 ALCcontext_DecRef(Context
);
2126 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2128 ALCcontext
*Context
;
2131 Context
= GetContextRef();
2132 if(!Context
) return;
2134 ReadLock(&Context
->PropLock
);
2135 LockSourcesRead(Context
);
2136 if((Source
=LookupSource(Context
, source
)) == NULL
)
2137 alSetError(Context
, AL_INVALID_NAME
);
2138 else if(!(value1
&& value2
&& value3
))
2139 alSetError(Context
, AL_INVALID_VALUE
);
2140 else if(!(DoubleValsByProp(param
) == 3))
2141 alSetError(Context
, AL_INVALID_ENUM
);
2145 if(GetSourcedv(Source
, Context
, param
, dvals
))
2152 UnlockSourcesRead(Context
);
2153 ReadUnlock(&Context
->PropLock
);
2155 ALCcontext_DecRef(Context
);
2158 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2160 ALCcontext
*Context
;
2163 Context
= GetContextRef();
2164 if(!Context
) return;
2166 ReadLock(&Context
->PropLock
);
2167 LockSourcesRead(Context
);
2168 if((Source
=LookupSource(Context
, source
)) == NULL
)
2169 alSetError(Context
, AL_INVALID_NAME
);
2171 alSetError(Context
, AL_INVALID_VALUE
);
2172 else if(!(DoubleValsByProp(param
) > 0))
2173 alSetError(Context
, AL_INVALID_ENUM
);
2175 GetSourcedv(Source
, Context
, param
, values
);
2176 UnlockSourcesRead(Context
);
2177 ReadUnlock(&Context
->PropLock
);
2179 ALCcontext_DecRef(Context
);
2183 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2185 ALCcontext
*Context
;
2188 Context
= GetContextRef();
2189 if(!Context
) return;
2191 ReadLock(&Context
->PropLock
);
2192 LockSourcesRead(Context
);
2193 if((Source
=LookupSource(Context
, source
)) == NULL
)
2194 alSetError(Context
, AL_INVALID_NAME
);
2196 alSetError(Context
, AL_INVALID_VALUE
);
2197 else if(!(IntValsByProp(param
) == 1))
2198 alSetError(Context
, AL_INVALID_ENUM
);
2200 GetSourceiv(Source
, Context
, param
, value
);
2201 UnlockSourcesRead(Context
);
2202 ReadUnlock(&Context
->PropLock
);
2204 ALCcontext_DecRef(Context
);
2208 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2210 ALCcontext
*Context
;
2213 Context
= GetContextRef();
2214 if(!Context
) return;
2216 ReadLock(&Context
->PropLock
);
2217 LockSourcesRead(Context
);
2218 if((Source
=LookupSource(Context
, source
)) == NULL
)
2219 alSetError(Context
, AL_INVALID_NAME
);
2220 else if(!(value1
&& value2
&& value3
))
2221 alSetError(Context
, AL_INVALID_VALUE
);
2222 else if(!(IntValsByProp(param
) == 3))
2223 alSetError(Context
, AL_INVALID_ENUM
);
2227 if(GetSourceiv(Source
, Context
, param
, ivals
))
2234 UnlockSourcesRead(Context
);
2235 ReadUnlock(&Context
->PropLock
);
2237 ALCcontext_DecRef(Context
);
2241 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2243 ALCcontext
*Context
;
2246 Context
= GetContextRef();
2247 if(!Context
) return;
2249 ReadLock(&Context
->PropLock
);
2250 LockSourcesRead(Context
);
2251 if((Source
=LookupSource(Context
, source
)) == NULL
)
2252 alSetError(Context
, AL_INVALID_NAME
);
2254 alSetError(Context
, AL_INVALID_VALUE
);
2255 else if(!(IntValsByProp(param
) > 0))
2256 alSetError(Context
, AL_INVALID_ENUM
);
2258 GetSourceiv(Source
, Context
, param
, values
);
2259 UnlockSourcesRead(Context
);
2260 ReadUnlock(&Context
->PropLock
);
2262 ALCcontext_DecRef(Context
);
2266 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2268 ALCcontext
*Context
;
2271 Context
= GetContextRef();
2272 if(!Context
) return;
2274 ReadLock(&Context
->PropLock
);
2275 LockSourcesRead(Context
);
2276 if((Source
=LookupSource(Context
, source
)) == NULL
)
2277 alSetError(Context
, AL_INVALID_NAME
);
2279 alSetError(Context
, AL_INVALID_VALUE
);
2280 else if(!(Int64ValsByProp(param
) == 1))
2281 alSetError(Context
, AL_INVALID_ENUM
);
2283 GetSourcei64v(Source
, Context
, param
, value
);
2284 UnlockSourcesRead(Context
);
2285 ReadUnlock(&Context
->PropLock
);
2287 ALCcontext_DecRef(Context
);
2290 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2292 ALCcontext
*Context
;
2295 Context
= GetContextRef();
2296 if(!Context
) return;
2298 ReadLock(&Context
->PropLock
);
2299 LockSourcesRead(Context
);
2300 if((Source
=LookupSource(Context
, source
)) == NULL
)
2301 alSetError(Context
, AL_INVALID_NAME
);
2302 else if(!(value1
&& value2
&& value3
))
2303 alSetError(Context
, AL_INVALID_VALUE
);
2304 else if(!(Int64ValsByProp(param
) == 3))
2305 alSetError(Context
, AL_INVALID_ENUM
);
2309 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2311 *value1
= i64vals
[0];
2312 *value2
= i64vals
[1];
2313 *value3
= i64vals
[2];
2316 UnlockSourcesRead(Context
);
2317 ReadUnlock(&Context
->PropLock
);
2319 ALCcontext_DecRef(Context
);
2322 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2324 ALCcontext
*Context
;
2327 Context
= GetContextRef();
2328 if(!Context
) return;
2330 ReadLock(&Context
->PropLock
);
2331 LockSourcesRead(Context
);
2332 if((Source
=LookupSource(Context
, source
)) == NULL
)
2333 alSetError(Context
, AL_INVALID_NAME
);
2335 alSetError(Context
, AL_INVALID_VALUE
);
2336 else if(!(Int64ValsByProp(param
) > 0))
2337 alSetError(Context
, AL_INVALID_ENUM
);
2339 GetSourcei64v(Source
, Context
, param
, values
);
2340 UnlockSourcesRead(Context
);
2341 ReadUnlock(&Context
->PropLock
);
2343 ALCcontext_DecRef(Context
);
2347 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2349 alSourcePlayv(1, &source
);
2351 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2353 ALCcontext
*context
;
2359 context
= GetContextRef();
2360 if(!context
) return;
2362 LockSourcesRead(context
);
2364 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2365 for(i
= 0;i
< n
;i
++)
2367 if(!LookupSource(context
, sources
[i
]))
2368 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2371 device
= context
->Device
;
2372 ALCdevice_Lock(device
);
2373 /* If the device is disconnected, go right to stopped. */
2374 if(!device
->Connected
)
2376 for(i
= 0;i
< n
;i
++)
2378 source
= LookupSource(context
, sources
[i
]);
2379 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2381 ALCdevice_Unlock(device
);
2385 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2387 ALsizei newcount
= context
->MaxVoices
<< 1;
2388 if(context
->MaxVoices
>= newcount
)
2390 ALCdevice_Unlock(device
);
2391 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2393 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2396 for(i
= 0;i
< n
;i
++)
2398 ALbufferlistitem
*BufferList
;
2399 ALbuffer
*buffer
= NULL
;
2401 source
= LookupSource(context
, sources
[i
]);
2402 WriteLock(&source
->queue_lock
);
2403 /* Check that there is a queue containing at least one valid, non zero
2406 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2409 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2411 BufferList
= BufferList
->next
;
2414 /* If there's nothing to play, go right to stopped. */
2417 /* NOTE: A source without any playable buffers should not have an
2418 * ALvoice since it shouldn't be in a playing or paused state. So
2419 * there's no need to look up its voice and clear the source.
2421 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2422 source
->OffsetType
= AL_NONE
;
2423 source
->Offset
= 0.0;
2427 voice
= GetSourceVoice(source
, context
);
2428 switch(GetSourceState(source
, voice
))
2431 assert(voice
!= NULL
);
2432 /* A source that's already playing is restarted from the beginning. */
2433 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2434 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2435 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2439 assert(voice
!= NULL
);
2440 /* A source that's paused simply resumes. Make sure it uses the
2441 * volume last specified; there's no reason to fade from where
2444 voice
->Flags
&= ~VOICE_IS_MOVING
;
2445 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2446 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2453 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2454 UpdateSourceProps(source
, device
->NumAuxSends
);
2456 /* Make sure this source isn't already active, and if not, look for an
2457 * unused voice to put it in.
2459 assert(voice
== NULL
);
2460 for(j
= 0;j
< context
->VoiceCount
;j
++)
2462 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2464 voice
= context
->Voices
[j
];
2469 voice
= context
->Voices
[context
->VoiceCount
++];
2470 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2471 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
2473 /* A source that's not playing or paused has any offset applied when it
2476 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2477 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2478 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2479 if(source
->OffsetType
!= AL_NONE
)
2480 ApplyOffset(source
, voice
);
2482 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2483 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2485 /* Clear previous samples. */
2486 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2488 /* Clear the stepping value so the mixer knows not to mix this until
2489 * the update gets applied.
2494 for(j
= 0;j
< voice
->NumChannels
;j
++)
2495 memset(&voice
->Direct
.Params
[j
].Hrtf
.State
, 0,
2496 sizeof(voice
->Direct
.Params
[j
].Hrtf
.State
));
2497 if(device
->AvgSpeakerDist
> 0.0f
)
2499 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2500 (device
->AvgSpeakerDist
* device
->Frequency
);
2501 for(j
= 0;j
< voice
->NumChannels
;j
++)
2503 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2504 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2505 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2509 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2510 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2511 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2513 WriteUnlock(&source
->queue_lock
);
2515 ALCdevice_Unlock(device
);
2518 UnlockSourcesRead(context
);
2519 ALCcontext_DecRef(context
);
2522 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2524 alSourcePausev(1, &source
);
2526 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2528 ALCcontext
*context
;
2534 context
= GetContextRef();
2535 if(!context
) return;
2537 LockSourcesRead(context
);
2539 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2540 for(i
= 0;i
< n
;i
++)
2542 if(!LookupSource(context
, sources
[i
]))
2543 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2546 device
= context
->Device
;
2547 ALCdevice_Lock(device
);
2548 for(i
= 0;i
< n
;i
++)
2550 source
= LookupSource(context
, sources
[i
]);
2551 WriteLock(&source
->queue_lock
);
2552 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2554 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2555 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2558 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2559 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2560 WriteUnlock(&source
->queue_lock
);
2562 ALCdevice_Unlock(device
);
2565 UnlockSourcesRead(context
);
2566 ALCcontext_DecRef(context
);
2569 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2571 alSourceStopv(1, &source
);
2573 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2575 ALCcontext
*context
;
2581 context
= GetContextRef();
2582 if(!context
) return;
2584 LockSourcesRead(context
);
2586 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2587 for(i
= 0;i
< n
;i
++)
2589 if(!LookupSource(context
, sources
[i
]))
2590 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2593 device
= context
->Device
;
2594 ALCdevice_Lock(device
);
2595 for(i
= 0;i
< n
;i
++)
2597 source
= LookupSource(context
, sources
[i
]);
2598 WriteLock(&source
->queue_lock
);
2599 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2601 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2602 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2603 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2606 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2607 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2608 source
->OffsetType
= AL_NONE
;
2609 source
->Offset
= 0.0;
2610 WriteUnlock(&source
->queue_lock
);
2612 ALCdevice_Unlock(device
);
2615 UnlockSourcesRead(context
);
2616 ALCcontext_DecRef(context
);
2619 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2621 alSourceRewindv(1, &source
);
2623 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2625 ALCcontext
*context
;
2631 context
= GetContextRef();
2632 if(!context
) return;
2634 LockSourcesRead(context
);
2636 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2637 for(i
= 0;i
< n
;i
++)
2639 if(!LookupSource(context
, sources
[i
]))
2640 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2643 device
= context
->Device
;
2644 ALCdevice_Lock(device
);
2645 for(i
= 0;i
< n
;i
++)
2647 source
= LookupSource(context
, sources
[i
]);
2648 WriteLock(&source
->queue_lock
);
2649 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2651 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2652 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2653 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2656 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2657 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2658 source
->OffsetType
= AL_NONE
;
2659 source
->Offset
= 0.0;
2660 WriteUnlock(&source
->queue_lock
);
2662 ALCdevice_Unlock(device
);
2665 UnlockSourcesRead(context
);
2666 ALCcontext_DecRef(context
);
2670 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2673 ALCcontext
*context
;
2676 ALbufferlistitem
*BufferListStart
;
2677 ALbufferlistitem
*BufferList
;
2678 ALbuffer
*BufferFmt
= NULL
;
2683 context
= GetContextRef();
2684 if(!context
) return;
2686 device
= context
->Device
;
2688 LockSourcesRead(context
);
2690 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2691 if((source
=LookupSource(context
, src
)) == NULL
)
2692 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2694 WriteLock(&source
->queue_lock
);
2695 if(source
->SourceType
== AL_STATIC
)
2697 WriteUnlock(&source
->queue_lock
);
2698 /* Can't queue on a Static Source */
2699 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2702 /* Check for a valid Buffer, for its frequency and format */
2703 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2706 if(BufferList
->buffer
)
2708 BufferFmt
= BufferList
->buffer
;
2711 BufferList
= BufferList
->next
;
2714 LockBuffersRead(device
);
2715 BufferListStart
= NULL
;
2717 for(i
= 0;i
< nb
;i
++)
2719 ALbuffer
*buffer
= NULL
;
2720 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2722 WriteUnlock(&source
->queue_lock
);
2723 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2726 if(!BufferListStart
)
2728 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2729 BufferList
= BufferListStart
;
2733 BufferList
->next
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2734 BufferList
= BufferList
->next
;
2736 BufferList
->buffer
= buffer
;
2737 BufferList
->next
= NULL
;
2738 if(!buffer
) continue;
2740 /* Hold a read lock on each buffer being queued while checking all
2741 * provided buffers. This is done so other threads don't see an extra
2742 * reference on some buffers if this operation ends up failing. */
2743 ReadLock(&buffer
->lock
);
2744 IncrementRef(&buffer
->ref
);
2746 if(BufferFmt
== NULL
)
2748 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2749 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2750 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2752 WriteUnlock(&source
->queue_lock
);
2753 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2756 /* A buffer failed (invalid ID or format), so unlock and release
2757 * each buffer we had. */
2758 while(BufferListStart
)
2760 ALbufferlistitem
*next
= BufferListStart
->next
;
2761 if((buffer
=BufferListStart
->buffer
) != NULL
)
2763 DecrementRef(&buffer
->ref
);
2764 ReadUnlock(&buffer
->lock
);
2766 al_free(BufferListStart
);
2767 BufferListStart
= next
;
2769 UnlockBuffersRead(device
);
2773 /* All buffers good, unlock them now. */
2774 BufferList
= BufferListStart
;
2775 while(BufferList
!= NULL
)
2777 ALbuffer
*buffer
= BufferList
->buffer
;
2778 if(buffer
) ReadUnlock(&buffer
->lock
);
2779 BufferList
= BufferList
->next
;
2781 UnlockBuffersRead(device
);
2783 /* Source is now streaming */
2784 source
->SourceType
= AL_STREAMING
;
2787 if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&source
->queue
, &BufferList
,
2790 /* Queue head is not NULL, append to the end of the queue */
2791 while(BufferList
->next
!= NULL
)
2792 BufferList
= BufferList
->next
;
2793 BufferList
->next
= BufferListStart
;
2795 WriteUnlock(&source
->queue_lock
);
2798 UnlockSourcesRead(context
);
2799 ALCcontext_DecRef(context
);
2802 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2804 ALCcontext
*context
;
2806 ALbufferlistitem
*OldHead
;
2807 ALbufferlistitem
*OldTail
;
2808 ALbufferlistitem
*Current
;
2812 context
= GetContextRef();
2813 if(!context
) return;
2815 LockSourcesRead(context
);
2817 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2819 if((source
=LookupSource(context
, src
)) == NULL
)
2820 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2822 /* Nothing to unqueue. */
2823 if(nb
== 0) goto done
;
2825 WriteLock(&source
->queue_lock
);
2826 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2828 WriteUnlock(&source
->queue_lock
);
2829 /* Trying to unqueue buffers on a looping or non-streaming source. */
2830 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2833 /* Find the new buffer queue head */
2834 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2836 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2837 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2838 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2840 if(OldTail
!= Current
)
2842 for(i
= 1;i
< nb
;i
++)
2844 ALbufferlistitem
*next
= OldTail
->next
;
2845 if(!next
|| next
== Current
) break;
2851 WriteUnlock(&source
->queue_lock
);
2852 /* Trying to unqueue pending buffers. */
2853 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2856 /* Swap it, and cut the new head from the old. */
2857 OldHead
= ATOMIC_EXCHANGE_PTR_SEQ(&source
->queue
, OldTail
->next
);
2860 ALCdevice
*device
= context
->Device
;
2863 /* Once the active mix (if any) is done, it's safe to cut the old tail
2864 * from the new head.
2866 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2868 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2871 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2872 OldTail
->next
= NULL
;
2874 WriteUnlock(&source
->queue_lock
);
2876 while(OldHead
!= NULL
)
2878 ALbufferlistitem
*next
= OldHead
->next
;
2879 ALbuffer
*buffer
= OldHead
->buffer
;
2885 *(buffers
++) = buffer
->id
;
2886 DecrementRef(&buffer
->ref
);
2894 UnlockSourcesRead(context
);
2895 ALCcontext_DecRef(context
);
2899 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2903 RWLockInit(&Source
->queue_lock
);
2905 Source
->InnerAngle
= 360.0f
;
2906 Source
->OuterAngle
= 360.0f
;
2907 Source
->Pitch
= 1.0f
;
2908 Source
->Position
[0] = 0.0f
;
2909 Source
->Position
[1] = 0.0f
;
2910 Source
->Position
[2] = 0.0f
;
2911 Source
->Velocity
[0] = 0.0f
;
2912 Source
->Velocity
[1] = 0.0f
;
2913 Source
->Velocity
[2] = 0.0f
;
2914 Source
->Direction
[0] = 0.0f
;
2915 Source
->Direction
[1] = 0.0f
;
2916 Source
->Direction
[2] = 0.0f
;
2917 Source
->Orientation
[0][0] = 0.0f
;
2918 Source
->Orientation
[0][1] = 0.0f
;
2919 Source
->Orientation
[0][2] = -1.0f
;
2920 Source
->Orientation
[1][0] = 0.0f
;
2921 Source
->Orientation
[1][1] = 1.0f
;
2922 Source
->Orientation
[1][2] = 0.0f
;
2923 Source
->RefDistance
= 1.0f
;
2924 Source
->MaxDistance
= FLT_MAX
;
2925 Source
->RollOffFactor
= 1.0f
;
2926 Source
->Gain
= 1.0f
;
2927 Source
->MinGain
= 0.0f
;
2928 Source
->MaxGain
= 1.0f
;
2929 Source
->OuterGain
= 0.0f
;
2930 Source
->OuterGainHF
= 1.0f
;
2932 Source
->DryGainHFAuto
= AL_TRUE
;
2933 Source
->WetGainAuto
= AL_TRUE
;
2934 Source
->WetGainHFAuto
= AL_TRUE
;
2935 Source
->AirAbsorptionFactor
= 0.0f
;
2936 Source
->RoomRolloffFactor
= 0.0f
;
2937 Source
->DopplerFactor
= 1.0f
;
2938 Source
->DirectChannels
= AL_FALSE
;
2940 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2941 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2943 Source
->Radius
= 0.0f
;
2945 Source
->DistanceModel
= DefaultDistanceModel
;
2947 Source
->Direct
.Gain
= 1.0f
;
2948 Source
->Direct
.GainHF
= 1.0f
;
2949 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2950 Source
->Direct
.GainLF
= 1.0f
;
2951 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2952 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2953 for(i
= 0;i
< num_sends
;i
++)
2955 Source
->Send
[i
].Slot
= NULL
;
2956 Source
->Send
[i
].Gain
= 1.0f
;
2957 Source
->Send
[i
].GainHF
= 1.0f
;
2958 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2959 Source
->Send
[i
].GainLF
= 1.0f
;
2960 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2963 Source
->Offset
= 0.0;
2964 Source
->OffsetType
= AL_NONE
;
2965 Source
->SourceType
= AL_UNDETERMINED
;
2966 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2968 ATOMIC_INIT(&Source
->queue
, NULL
);
2970 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2972 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2975 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
2977 ATOMIC_INIT(&Source
->Update
, NULL
);
2978 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2981 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2983 ALbufferlistitem
*BufferList
;
2984 struct ALsourceProps
*props
;
2988 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2989 if(props
) al_free(props
);
2991 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2994 struct ALsourceProps
*next
;
2995 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3000 /* This is excessively spammy if it traces every source destruction, so
3001 * just warn if it was unexpectedly large.
3004 WARN("Freed "SZFMT
" Source property objects\n", count
);
3006 BufferList
= ATOMIC_EXCHANGE_PTR_SEQ(&source
->queue
, NULL
);
3007 while(BufferList
!= NULL
)
3009 ALbufferlistitem
*next
= BufferList
->next
;
3010 if(BufferList
->buffer
!= NULL
)
3011 DecrementRef(&BufferList
->buffer
->ref
);
3012 al_free(BufferList
);
3018 for(i
= 0;i
< num_sends
;i
++)
3020 if(source
->Send
[i
].Slot
)
3021 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3022 source
->Send
[i
].Slot
= NULL
;
3024 al_free(source
->Send
);
3025 source
->Send
= NULL
;
3029 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
)
3031 struct ALsourceProps
*props
;
3034 /* Get an unused property container, or allocate a new one as needed. */
3035 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
3037 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
3040 struct ALsourceProps
*next
;
3042 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3043 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&source
->FreeList
, &props
, next
,
3044 almemory_order_acq_rel
, almemory_order_acquire
) == 0);
3047 /* Copy in current property values. */
3048 props
->Pitch
= source
->Pitch
;
3049 props
->Gain
= source
->Gain
;
3050 props
->OuterGain
= source
->OuterGain
;
3051 props
->MinGain
= source
->MinGain
;
3052 props
->MaxGain
= source
->MaxGain
;
3053 props
->InnerAngle
= source
->InnerAngle
;
3054 props
->OuterAngle
= source
->OuterAngle
;
3055 props
->RefDistance
= source
->RefDistance
;
3056 props
->MaxDistance
= source
->MaxDistance
;
3057 props
->RollOffFactor
= source
->RollOffFactor
;
3058 for(i
= 0;i
< 3;i
++)
3059 props
->Position
[i
] = source
->Position
[i
];
3060 for(i
= 0;i
< 3;i
++)
3061 props
->Velocity
[i
] = source
->Velocity
[i
];
3062 for(i
= 0;i
< 3;i
++)
3063 props
->Direction
[i
] = source
->Direction
[i
];
3064 for(i
= 0;i
< 2;i
++)
3067 for(j
= 0;j
< 3;j
++)
3068 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3070 props
->HeadRelative
= source
->HeadRelative
;
3071 props
->DistanceModel
= source
->DistanceModel
;
3072 props
->DirectChannels
= source
->DirectChannels
;
3074 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3075 props
->WetGainAuto
= source
->WetGainAuto
;
3076 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3077 props
->OuterGainHF
= source
->OuterGainHF
;
3079 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3080 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3081 props
->DopplerFactor
= source
->DopplerFactor
;
3083 props
->StereoPan
[0] = source
->StereoPan
[0];
3084 props
->StereoPan
[1] = source
->StereoPan
[1];
3086 props
->Radius
= source
->Radius
;
3088 props
->Direct
.Gain
= source
->Direct
.Gain
;
3089 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3090 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3091 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3092 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3094 for(i
= 0;i
< num_sends
;i
++)
3096 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3097 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3098 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3099 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3100 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3101 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3104 /* Set the new container for updating internal parameters. */
3105 props
= ATOMIC_EXCHANGE_PTR(&source
->Update
, props
, almemory_order_acq_rel
);
3108 /* If there was an unused update container, put it back in the
3111 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
3115 void UpdateAllSourceProps(ALCcontext
*context
)
3117 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3120 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3122 ALvoice
*voice
= context
->Voices
[pos
];
3123 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3124 if(source
!= NULL
&& !ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3125 UpdateSourceProps(source
, num_sends
);
3130 /* GetSourceSampleOffset
3132 * Gets the current read offset for the given Source, in 32.32 fixed-point
3133 * samples. The offset is relative to the start of the queue (not the start of
3134 * the current buffer).
3136 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3138 ALCdevice
*device
= context
->Device
;
3139 const ALbufferlistitem
*BufferList
;
3140 const ALbufferlistitem
*Current
;
3145 ReadLock(&Source
->queue_lock
);
3146 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3150 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3152 *clocktime
= GetDeviceClockTime(device
);
3154 voice
= GetSourceVoice(Source
, context
);
3157 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3159 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3160 readPos
|= (ALuint64
)ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3163 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3164 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3168 while(BufferList
&& BufferList
!= Current
)
3170 if(BufferList
->buffer
)
3171 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3172 BufferList
= BufferList
->next
;
3174 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3177 ReadUnlock(&Source
->queue_lock
);
3178 return (ALint64
)readPos
;
3181 /* GetSourceSecOffset
3183 * Gets the current read offset for the given Source, in seconds. The offset is
3184 * relative to the start of the queue (not the start of the current buffer).
3186 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3188 ALCdevice
*device
= context
->Device
;
3189 const ALbufferlistitem
*BufferList
;
3190 const ALbufferlistitem
*Current
;
3196 ReadLock(&Source
->queue_lock
);
3197 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3201 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3203 *clocktime
= GetDeviceClockTime(device
);
3205 voice
= GetSourceVoice(Source
, context
);
3208 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3210 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3212 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3214 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3215 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3220 const ALbuffer
*Buffer
= NULL
;
3221 while(BufferList
&& BufferList
!= Current
)
3223 const ALbuffer
*buffer
= BufferList
->buffer
;
3226 if(!Buffer
) Buffer
= buffer
;
3227 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3229 BufferList
= BufferList
->next
;
3232 while(BufferList
&& !Buffer
)
3234 Buffer
= BufferList
->buffer
;
3235 BufferList
= BufferList
->next
;
3237 assert(Buffer
!= NULL
);
3239 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3240 (ALdouble
)Buffer
->Frequency
;
3243 ReadUnlock(&Source
->queue_lock
);
3249 * Gets the current read offset for the given Source, in the appropriate format
3250 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3251 * queue (not the start of the current buffer).
3253 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3255 ALCdevice
*device
= context
->Device
;
3256 const ALbufferlistitem
*BufferList
;
3257 const ALbufferlistitem
*Current
;
3258 const ALbuffer
*Buffer
= NULL
;
3259 ALboolean readFin
= AL_FALSE
;
3261 ALsizei readPosFrac
;
3262 ALuint totalBufferLen
;
3268 ReadLock(&Source
->queue_lock
);
3269 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3270 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3273 readPos
= readPosFrac
= 0;
3274 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3276 voice
= GetSourceVoice(Source
, context
);
3279 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3281 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3282 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3284 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3285 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3289 ReadUnlock(&Source
->queue_lock
);
3294 while(BufferList
!= NULL
)
3296 const ALbuffer
*buffer
;
3297 readFin
= readFin
|| (BufferList
== Current
);
3298 if((buffer
=BufferList
->buffer
) != NULL
)
3300 if(!Buffer
) Buffer
= buffer
;
3301 totalBufferLen
+= buffer
->SampleLen
;
3302 if(!readFin
) readPos
+= buffer
->SampleLen
;
3304 BufferList
= BufferList
->next
;
3306 assert(Buffer
!= NULL
);
3309 readPos
%= totalBufferLen
;
3312 /* Wrap back to 0 */
3313 if(readPos
>= totalBufferLen
)
3314 readPos
= readPosFrac
= 0;
3321 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3324 case AL_SAMPLE_OFFSET
:
3325 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3328 case AL_BYTE_OFFSET
:
3329 if(Buffer
->OriginalType
== UserFmtIMA4
)
3331 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3332 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3333 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3335 /* Round down to nearest ADPCM block */
3336 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3338 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3340 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3341 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3342 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3344 /* Round down to nearest ADPCM block */
3345 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3349 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3350 offset
= (ALdouble
)(readPos
* FrameSize
);
3355 ReadUnlock(&Source
->queue_lock
);
3362 * Apply the stored playback offset to the Source. This function will update
3363 * the number of buffers "played" given the stored offset.
3365 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3367 ALbufferlistitem
*BufferList
;
3368 const ALbuffer
*Buffer
;
3369 ALuint bufferLen
, totalBufferLen
;
3373 /* Get sample frame offset */
3374 if(!GetSampleOffset(Source
, &offset
, &frac
))
3378 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3379 while(BufferList
&& totalBufferLen
<= offset
)
3381 Buffer
= BufferList
->buffer
;
3382 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3384 if(bufferLen
> offset
-totalBufferLen
)
3386 /* Offset is in this buffer */
3387 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
3388 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3389 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_release
);
3393 totalBufferLen
+= bufferLen
;
3395 BufferList
= BufferList
->next
;
3398 /* Offset is out of range of the queue */
3405 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3406 * or Second offset supplied by the application). This takes into account the
3407 * fact that the buffer format may have been modifed since.
3409 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
3411 const ALbuffer
*Buffer
= NULL
;
3412 const ALbufferlistitem
*BufferList
;
3413 ALdouble dbloff
, dblfrac
;
3415 /* Find the first valid Buffer in the Queue */
3416 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3419 if(BufferList
->buffer
)
3421 Buffer
= BufferList
->buffer
;
3424 BufferList
= BufferList
->next
;
3428 Source
->OffsetType
= AL_NONE
;
3429 Source
->Offset
= 0.0;
3433 switch(Source
->OffsetType
)
3435 case AL_BYTE_OFFSET
:
3436 /* Determine the ByteOffset (and ensure it is block aligned) */
3437 *offset
= (ALuint
)Source
->Offset
;
3438 if(Buffer
->OriginalType
== UserFmtIMA4
)
3440 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3441 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3442 *offset
*= Buffer
->OriginalAlign
;
3444 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3446 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3447 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3448 *offset
*= Buffer
->OriginalAlign
;
3451 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3455 case AL_SAMPLE_OFFSET
:
3456 dblfrac
= modf(Source
->Offset
, &dbloff
);
3457 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3458 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3462 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3463 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3464 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3467 Source
->OffsetType
= AL_NONE
;
3468 Source
->Offset
= 0.0;
3476 * Destroys all sources in the source map.
3478 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3480 ALCdevice
*device
= Context
->Device
;
3482 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3484 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3485 Context
->SourceMap
.values
[pos
] = NULL
;
3487 DeinitSource(temp
, device
->NumAuxSends
);
3489 FreeThunkEntry(temp
->id
);
3490 memset(temp
, 0, sizeof(*temp
));