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
, ALuint
*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(ALenum
, &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 WriteUnlock(&Source
->queue_lock
);
706 LockBuffersRead(device
);
707 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
709 UnlockBuffersRead(device
);
710 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
713 WriteLock(&Source
->queue_lock
);
715 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
716 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
718 WriteUnlock(&Source
->queue_lock
);
719 UnlockBuffersRead(device
);
720 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
726 /* Add the selected buffer to a one-item queue */
727 newlist
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
728 newlist
->buffer
= buffer
;
729 newlist
->next
= NULL
;
730 IncrementRef(&buffer
->ref
);
732 /* Source is now Static */
733 Source
->SourceType
= AL_STATIC
;
737 /* Source is now Undetermined */
738 Source
->SourceType
= AL_UNDETERMINED
;
741 oldlist
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &Source
->queue
, newlist
);
742 WriteUnlock(&Source
->queue_lock
);
743 UnlockBuffersRead(device
);
745 /* Delete all elements in the previous queue */
746 while(oldlist
!= NULL
)
748 ALbufferlistitem
*temp
= oldlist
;
749 oldlist
= temp
->next
;
752 DecrementRef(&temp
->buffer
->ref
);
758 case AL_SAMPLE_OFFSET
:
760 CHECKVAL(*values
>= 0);
762 Source
->OffsetType
= prop
;
763 Source
->Offset
= *values
;
765 if(IsPlayingOrPaused(Source
))
769 ALCdevice_Lock(Context
->Device
);
770 voice
= GetSourceVoice(Source
, Context
);
773 WriteLock(&Source
->queue_lock
);
774 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
776 WriteUnlock(&Source
->queue_lock
);
777 ALCdevice_Unlock(Context
->Device
);
778 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
780 WriteUnlock(&Source
->queue_lock
);
782 ALCdevice_Unlock(Context
->Device
);
786 case AL_DIRECT_FILTER
:
787 LockFiltersRead(device
);
788 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
790 UnlockFiltersRead(device
);
791 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
796 Source
->Direct
.Gain
= 1.0f
;
797 Source
->Direct
.GainHF
= 1.0f
;
798 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
799 Source
->Direct
.GainLF
= 1.0f
;
800 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
804 Source
->Direct
.Gain
= filter
->Gain
;
805 Source
->Direct
.GainHF
= filter
->GainHF
;
806 Source
->Direct
.HFReference
= filter
->HFReference
;
807 Source
->Direct
.GainLF
= filter
->GainLF
;
808 Source
->Direct
.LFReference
= filter
->LFReference
;
810 UnlockFiltersRead(device
);
814 case AL_DIRECT_FILTER_GAINHF_AUTO
:
815 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
817 Source
->DryGainHFAuto
= *values
;
821 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
822 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
824 Source
->WetGainAuto
= *values
;
828 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
829 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
831 Source
->WetGainHFAuto
= *values
;
835 case AL_DIRECT_CHANNELS_SOFT
:
836 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
838 Source
->DirectChannels
= *values
;
842 case AL_DISTANCE_MODEL
:
843 CHECKVAL(*values
== AL_NONE
||
844 *values
== AL_INVERSE_DISTANCE
||
845 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
846 *values
== AL_LINEAR_DISTANCE
||
847 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
848 *values
== AL_EXPONENT_DISTANCE
||
849 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
851 Source
->DistanceModel
= *values
;
852 if(Context
->SourceDistanceModel
)
857 case AL_AUXILIARY_SEND_FILTER
:
858 LockEffectSlotsRead(Context
);
859 LockFiltersRead(device
);
860 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
861 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
862 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
864 UnlockFiltersRead(device
);
865 UnlockEffectSlotsRead(Context
);
866 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
872 Source
->Send
[values
[1]].Gain
= 1.0f
;
873 Source
->Send
[values
[1]].GainHF
= 1.0f
;
874 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
875 Source
->Send
[values
[1]].GainLF
= 1.0f
;
876 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
880 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
881 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
882 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
883 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
884 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
886 UnlockFiltersRead(device
);
888 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
890 /* Add refcount on the new slot, and release the previous slot */
891 if(slot
) IncrementRef(&slot
->ref
);
892 if(Source
->Send
[values
[1]].Slot
)
893 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
894 Source
->Send
[values
[1]].Slot
= slot
;
896 /* We must force an update if the auxiliary slot changed on a
897 * playing source, in case the slot is about to be deleted.
899 UpdateSourceProps(Source
, device
->NumAuxSends
);
903 if(slot
) IncrementRef(&slot
->ref
);
904 if(Source
->Send
[values
[1]].Slot
)
905 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
906 Source
->Send
[values
[1]].Slot
= slot
;
909 UnlockEffectSlotsRead(Context
);
915 case AL_CONE_INNER_ANGLE
:
916 case AL_CONE_OUTER_ANGLE
:
921 case AL_REFERENCE_DISTANCE
:
922 case AL_ROLLOFF_FACTOR
:
923 case AL_CONE_OUTER_GAIN
:
924 case AL_MAX_DISTANCE
:
925 case AL_DOPPLER_FACTOR
:
926 case AL_CONE_OUTER_GAINHF
:
927 case AL_AIR_ABSORPTION_FACTOR
:
928 case AL_ROOM_ROLLOFF_FACTOR
:
929 case AL_SOURCE_RADIUS
:
930 fvals
[0] = (ALfloat
)*values
;
931 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
937 fvals
[0] = (ALfloat
)values
[0];
938 fvals
[1] = (ALfloat
)values
[1];
939 fvals
[2] = (ALfloat
)values
[2];
940 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
944 fvals
[0] = (ALfloat
)values
[0];
945 fvals
[1] = (ALfloat
)values
[1];
946 fvals
[2] = (ALfloat
)values
[2];
947 fvals
[3] = (ALfloat
)values
[3];
948 fvals
[4] = (ALfloat
)values
[4];
949 fvals
[5] = (ALfloat
)values
[5];
950 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
952 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
953 case AL_SEC_OFFSET_LATENCY_SOFT
:
954 case AL_STEREO_ANGLES
:
958 ERR("Unexpected property: 0x%04x\n", prop
);
959 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
962 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
970 case AL_BUFFERS_QUEUED
:
971 case AL_BUFFERS_PROCESSED
:
972 case AL_SOURCE_STATE
:
973 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
974 case AL_BYTE_LENGTH_SOFT
:
975 case AL_SAMPLE_LENGTH_SOFT
:
976 case AL_SEC_LENGTH_SOFT
:
978 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
982 case AL_SOURCE_RELATIVE
:
985 case AL_SAMPLE_OFFSET
:
987 case AL_DIRECT_FILTER_GAINHF_AUTO
:
988 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
989 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
990 case AL_DIRECT_CHANNELS_SOFT
:
991 case AL_DISTANCE_MODEL
:
992 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
994 ivals
[0] = (ALint
)*values
;
995 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
999 case AL_DIRECT_FILTER
:
1000 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1002 ivals
[0] = (ALuint
)*values
;
1003 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1006 case AL_AUXILIARY_SEND_FILTER
:
1007 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1008 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1009 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1011 ivals
[0] = (ALuint
)values
[0];
1012 ivals
[1] = (ALuint
)values
[1];
1013 ivals
[2] = (ALuint
)values
[2];
1014 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
1017 case AL_CONE_INNER_ANGLE
:
1018 case AL_CONE_OUTER_ANGLE
:
1023 case AL_REFERENCE_DISTANCE
:
1024 case AL_ROLLOFF_FACTOR
:
1025 case AL_CONE_OUTER_GAIN
:
1026 case AL_MAX_DISTANCE
:
1027 case AL_DOPPLER_FACTOR
:
1028 case AL_CONE_OUTER_GAINHF
:
1029 case AL_AIR_ABSORPTION_FACTOR
:
1030 case AL_ROOM_ROLLOFF_FACTOR
:
1031 case AL_SOURCE_RADIUS
:
1032 fvals
[0] = (ALfloat
)*values
;
1033 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1039 fvals
[0] = (ALfloat
)values
[0];
1040 fvals
[1] = (ALfloat
)values
[1];
1041 fvals
[2] = (ALfloat
)values
[2];
1042 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1045 case AL_ORIENTATION
:
1046 fvals
[0] = (ALfloat
)values
[0];
1047 fvals
[1] = (ALfloat
)values
[1];
1048 fvals
[2] = (ALfloat
)values
[2];
1049 fvals
[3] = (ALfloat
)values
[3];
1050 fvals
[4] = (ALfloat
)values
[4];
1051 fvals
[5] = (ALfloat
)values
[5];
1052 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1054 case AL_SEC_OFFSET_LATENCY_SOFT
:
1055 case AL_STEREO_ANGLES
:
1059 ERR("Unexpected property: 0x%04x\n", prop
);
1060 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1066 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1068 ALCdevice
*device
= Context
->Device
;
1069 ALbufferlistitem
*BufferList
;
1070 ClockLatency clocktime
;
1078 *values
= Source
->Gain
;
1082 *values
= Source
->Pitch
;
1085 case AL_MAX_DISTANCE
:
1086 *values
= Source
->MaxDistance
;
1089 case AL_ROLLOFF_FACTOR
:
1090 *values
= Source
->RollOffFactor
;
1093 case AL_REFERENCE_DISTANCE
:
1094 *values
= Source
->RefDistance
;
1097 case AL_CONE_INNER_ANGLE
:
1098 *values
= Source
->InnerAngle
;
1101 case AL_CONE_OUTER_ANGLE
:
1102 *values
= Source
->OuterAngle
;
1106 *values
= Source
->MinGain
;
1110 *values
= Source
->MaxGain
;
1113 case AL_CONE_OUTER_GAIN
:
1114 *values
= Source
->OuterGain
;
1118 case AL_SAMPLE_OFFSET
:
1119 case AL_BYTE_OFFSET
:
1120 *values
= GetSourceOffset(Source
, prop
, Context
);
1123 case AL_CONE_OUTER_GAINHF
:
1124 *values
= Source
->OuterGainHF
;
1127 case AL_AIR_ABSORPTION_FACTOR
:
1128 *values
= Source
->AirAbsorptionFactor
;
1131 case AL_ROOM_ROLLOFF_FACTOR
:
1132 *values
= Source
->RoomRolloffFactor
;
1135 case AL_DOPPLER_FACTOR
:
1136 *values
= Source
->DopplerFactor
;
1139 case AL_SEC_LENGTH_SOFT
:
1140 ReadLock(&Source
->queue_lock
);
1141 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1148 ALbuffer
*buffer
= BufferList
->buffer
;
1149 if(buffer
&& buffer
->SampleLen
> 0)
1151 freq
= buffer
->Frequency
;
1152 length
+= buffer
->SampleLen
;
1154 } while((BufferList
=BufferList
->next
) != NULL
);
1155 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1157 ReadUnlock(&Source
->queue_lock
);
1160 case AL_SOURCE_RADIUS
:
1161 *values
= Source
->Radius
;
1164 case AL_STEREO_ANGLES
:
1165 values
[0] = Source
->StereoPan
[0];
1166 values
[1] = Source
->StereoPan
[1];
1169 case AL_SEC_OFFSET_LATENCY_SOFT
:
1170 /* Get the source offset with the clock time first. Then get the
1171 * clock time with the device latency. Order is important.
1173 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1174 clocktime
= V0(device
->Backend
,getClockLatency
)();
1175 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1176 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1179 /* If the clock time incremented, reduce the latency by that
1180 * much since it's that much closer to the source offset it got
1183 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1184 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1190 values
[0] = Source
->Position
[0];
1191 values
[1] = Source
->Position
[1];
1192 values
[2] = Source
->Position
[2];
1196 values
[0] = Source
->Velocity
[0];
1197 values
[1] = Source
->Velocity
[1];
1198 values
[2] = Source
->Velocity
[2];
1202 values
[0] = Source
->Direction
[0];
1203 values
[1] = Source
->Direction
[1];
1204 values
[2] = Source
->Direction
[2];
1207 case AL_ORIENTATION
:
1208 values
[0] = Source
->Orientation
[0][0];
1209 values
[1] = Source
->Orientation
[0][1];
1210 values
[2] = Source
->Orientation
[0][2];
1211 values
[3] = Source
->Orientation
[1][0];
1212 values
[4] = Source
->Orientation
[1][1];
1213 values
[5] = Source
->Orientation
[1][2];
1217 case AL_SOURCE_RELATIVE
:
1219 case AL_SOURCE_STATE
:
1220 case AL_BUFFERS_QUEUED
:
1221 case AL_BUFFERS_PROCESSED
:
1222 case AL_SOURCE_TYPE
:
1223 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1224 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1225 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1226 case AL_DIRECT_CHANNELS_SOFT
:
1227 case AL_BYTE_LENGTH_SOFT
:
1228 case AL_SAMPLE_LENGTH_SOFT
:
1229 case AL_DISTANCE_MODEL
:
1230 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1231 *values
= (ALdouble
)ivals
[0];
1235 case AL_DIRECT_FILTER
:
1236 case AL_AUXILIARY_SEND_FILTER
:
1237 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1241 ERR("Unexpected property: 0x%04x\n", prop
);
1242 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1245 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1247 ALbufferlistitem
*BufferList
;
1253 case AL_SOURCE_RELATIVE
:
1254 *values
= Source
->HeadRelative
;
1258 *values
= ATOMIC_LOAD_SEQ(&Source
->looping
);
1262 ReadLock(&Source
->queue_lock
);
1263 BufferList
= (Source
->SourceType
== AL_STATIC
) ?
1264 ATOMIC_LOAD_SEQ(&Source
->queue
) : NULL
;
1265 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1266 ReadUnlock(&Source
->queue_lock
);
1269 case AL_SOURCE_STATE
:
1270 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1273 case AL_BYTE_LENGTH_SOFT
:
1274 ReadLock(&Source
->queue_lock
);
1275 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1281 ALbuffer
*buffer
= BufferList
->buffer
;
1282 if(buffer
&& buffer
->SampleLen
> 0)
1284 ALuint byte_align
, sample_align
;
1285 if(buffer
->OriginalType
== UserFmtIMA4
)
1287 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1288 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1289 sample_align
= buffer
->OriginalAlign
;
1291 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1293 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1294 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1295 sample_align
= buffer
->OriginalAlign
;
1299 ALsizei align
= buffer
->OriginalAlign
;
1300 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1301 sample_align
= buffer
->OriginalAlign
;
1304 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1306 } while((BufferList
=BufferList
->next
) != NULL
);
1309 ReadUnlock(&Source
->queue_lock
);
1312 case AL_SAMPLE_LENGTH_SOFT
:
1313 ReadLock(&Source
->queue_lock
);
1314 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1320 ALbuffer
*buffer
= BufferList
->buffer
;
1321 if(buffer
) length
+= buffer
->SampleLen
;
1322 } while((BufferList
=BufferList
->next
) != NULL
);
1325 ReadUnlock(&Source
->queue_lock
);
1328 case AL_BUFFERS_QUEUED
:
1329 ReadLock(&Source
->queue_lock
);
1330 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1337 } while((BufferList
=BufferList
->next
) != NULL
);
1340 ReadUnlock(&Source
->queue_lock
);
1343 case AL_BUFFERS_PROCESSED
:
1344 ReadLock(&Source
->queue_lock
);
1345 if(ATOMIC_LOAD_SEQ(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1347 /* Buffers on a looping source are in a perpetual state of
1348 * PENDING, so don't report any as PROCESSED */
1353 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
1354 const ALbufferlistitem
*Current
= NULL
;
1358 if((voice
=GetSourceVoice(Source
, Context
)) != NULL
)
1359 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
1360 else if(ATOMIC_LOAD_SEQ(&Source
->state
) == AL_INITIAL
)
1361 Current
= BufferList
;
1363 while(BufferList
&& BufferList
!= Current
)
1366 BufferList
= BufferList
->next
;
1370 ReadUnlock(&Source
->queue_lock
);
1373 case AL_SOURCE_TYPE
:
1374 *values
= Source
->SourceType
;
1377 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1378 *values
= Source
->DryGainHFAuto
;
1381 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1382 *values
= Source
->WetGainAuto
;
1385 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1386 *values
= Source
->WetGainHFAuto
;
1389 case AL_DIRECT_CHANNELS_SOFT
:
1390 *values
= Source
->DirectChannels
;
1393 case AL_DISTANCE_MODEL
:
1394 *values
= Source
->DistanceModel
;
1397 /* 1x float/double */
1398 case AL_CONE_INNER_ANGLE
:
1399 case AL_CONE_OUTER_ANGLE
:
1404 case AL_REFERENCE_DISTANCE
:
1405 case AL_ROLLOFF_FACTOR
:
1406 case AL_CONE_OUTER_GAIN
:
1407 case AL_MAX_DISTANCE
:
1409 case AL_SAMPLE_OFFSET
:
1410 case AL_BYTE_OFFSET
:
1411 case AL_DOPPLER_FACTOR
:
1412 case AL_AIR_ABSORPTION_FACTOR
:
1413 case AL_ROOM_ROLLOFF_FACTOR
:
1414 case AL_CONE_OUTER_GAINHF
:
1415 case AL_SEC_LENGTH_SOFT
:
1416 case AL_SOURCE_RADIUS
:
1417 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1418 *values
= (ALint
)dvals
[0];
1421 /* 3x float/double */
1425 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1427 values
[0] = (ALint
)dvals
[0];
1428 values
[1] = (ALint
)dvals
[1];
1429 values
[2] = (ALint
)dvals
[2];
1433 /* 6x float/double */
1434 case AL_ORIENTATION
:
1435 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1437 values
[0] = (ALint
)dvals
[0];
1438 values
[1] = (ALint
)dvals
[1];
1439 values
[2] = (ALint
)dvals
[2];
1440 values
[3] = (ALint
)dvals
[3];
1441 values
[4] = (ALint
)dvals
[4];
1442 values
[5] = (ALint
)dvals
[5];
1446 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1447 break; /* i64 only */
1448 case AL_SEC_OFFSET_LATENCY_SOFT
:
1449 break; /* Double only */
1450 case AL_STEREO_ANGLES
:
1451 break; /* Float/double only */
1453 case AL_DIRECT_FILTER
:
1454 case AL_AUXILIARY_SEND_FILTER
:
1458 ERR("Unexpected property: 0x%04x\n", prop
);
1459 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1462 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1464 ALCdevice
*device
= Context
->Device
;
1465 ClockLatency clocktime
;
1473 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1474 /* Get the source offset with the clock time first. Then get the
1475 * clock time with the device latency. Order is important.
1477 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1478 clocktime
= V0(device
->Backend
,getClockLatency
)();
1479 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1480 values
[1] = clocktime
.Latency
;
1483 /* If the clock time incremented, reduce the latency by that
1484 * much since it's that much closer to the source offset it got
1487 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1488 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1492 /* 1x float/double */
1493 case AL_CONE_INNER_ANGLE
:
1494 case AL_CONE_OUTER_ANGLE
:
1499 case AL_REFERENCE_DISTANCE
:
1500 case AL_ROLLOFF_FACTOR
:
1501 case AL_CONE_OUTER_GAIN
:
1502 case AL_MAX_DISTANCE
:
1504 case AL_SAMPLE_OFFSET
:
1505 case AL_BYTE_OFFSET
:
1506 case AL_DOPPLER_FACTOR
:
1507 case AL_AIR_ABSORPTION_FACTOR
:
1508 case AL_ROOM_ROLLOFF_FACTOR
:
1509 case AL_CONE_OUTER_GAINHF
:
1510 case AL_SEC_LENGTH_SOFT
:
1511 case AL_SOURCE_RADIUS
:
1512 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1513 *values
= (ALint64
)dvals
[0];
1516 /* 3x float/double */
1520 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1522 values
[0] = (ALint64
)dvals
[0];
1523 values
[1] = (ALint64
)dvals
[1];
1524 values
[2] = (ALint64
)dvals
[2];
1528 /* 6x float/double */
1529 case AL_ORIENTATION
:
1530 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1532 values
[0] = (ALint64
)dvals
[0];
1533 values
[1] = (ALint64
)dvals
[1];
1534 values
[2] = (ALint64
)dvals
[2];
1535 values
[3] = (ALint64
)dvals
[3];
1536 values
[4] = (ALint64
)dvals
[4];
1537 values
[5] = (ALint64
)dvals
[5];
1542 case AL_SOURCE_RELATIVE
:
1544 case AL_SOURCE_STATE
:
1545 case AL_BUFFERS_QUEUED
:
1546 case AL_BUFFERS_PROCESSED
:
1547 case AL_BYTE_LENGTH_SOFT
:
1548 case AL_SAMPLE_LENGTH_SOFT
:
1549 case AL_SOURCE_TYPE
:
1550 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1551 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1552 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1553 case AL_DIRECT_CHANNELS_SOFT
:
1554 case AL_DISTANCE_MODEL
:
1555 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1561 case AL_DIRECT_FILTER
:
1562 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1563 *values
= (ALuint
)ivals
[0];
1567 case AL_AUXILIARY_SEND_FILTER
:
1568 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1570 values
[0] = (ALuint
)ivals
[0];
1571 values
[1] = (ALuint
)ivals
[1];
1572 values
[2] = (ALuint
)ivals
[2];
1576 case AL_SEC_OFFSET_LATENCY_SOFT
:
1577 break; /* Double only */
1578 case AL_STEREO_ANGLES
:
1579 break; /* Float/double only */
1582 ERR("Unexpected property: 0x%04x\n", prop
);
1583 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1587 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1590 ALCcontext
*context
;
1594 context
= GetContextRef();
1595 if(!context
) return;
1598 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1599 device
= context
->Device
;
1600 for(cur
= 0;cur
< n
;cur
++)
1602 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1605 alDeleteSources(cur
, sources
);
1606 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1608 InitSourceParams(source
, device
->NumAuxSends
);
1610 err
= NewThunkEntry(&source
->id
);
1611 if(err
== AL_NO_ERROR
)
1612 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1613 if(err
!= AL_NO_ERROR
)
1615 FreeThunkEntry(source
->id
);
1616 memset(source
, 0, sizeof(ALsource
));
1619 alDeleteSources(cur
, sources
);
1620 SET_ERROR_AND_GOTO(context
, err
, done
);
1623 sources
[cur
] = source
->id
;
1627 ALCcontext_DecRef(context
);
1631 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1634 ALCcontext
*context
;
1638 context
= GetContextRef();
1639 if(!context
) return;
1641 LockSourcesWrite(context
);
1643 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1645 /* Check that all Sources are valid */
1646 for(i
= 0;i
< n
;i
++)
1648 if(LookupSource(context
, sources
[i
]) == NULL
)
1649 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1651 device
= context
->Device
;
1652 for(i
= 0;i
< n
;i
++)
1656 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1658 FreeThunkEntry(Source
->id
);
1660 ALCdevice_Lock(device
);
1661 if((voice
=GetSourceVoice(Source
, context
)) != NULL
)
1663 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
1664 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
1666 ALCdevice_Unlock(device
);
1668 DeinitSource(Source
, device
->NumAuxSends
);
1670 memset(Source
, 0, sizeof(*Source
));
1675 UnlockSourcesWrite(context
);
1676 ALCcontext_DecRef(context
);
1680 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1682 ALCcontext
*context
;
1685 context
= GetContextRef();
1686 if(!context
) return AL_FALSE
;
1688 LockSourcesRead(context
);
1689 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1690 UnlockSourcesRead(context
);
1692 ALCcontext_DecRef(context
);
1698 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1700 ALCcontext
*Context
;
1703 Context
= GetContextRef();
1704 if(!Context
) return;
1706 WriteLock(&Context
->PropLock
);
1707 LockSourcesRead(Context
);
1708 if((Source
=LookupSource(Context
, source
)) == NULL
)
1709 alSetError(Context
, AL_INVALID_NAME
);
1710 else if(!(FloatValsByProp(param
) == 1))
1711 alSetError(Context
, AL_INVALID_ENUM
);
1713 SetSourcefv(Source
, Context
, param
, &value
);
1714 UnlockSourcesRead(Context
);
1715 WriteUnlock(&Context
->PropLock
);
1717 ALCcontext_DecRef(Context
);
1720 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1722 ALCcontext
*Context
;
1725 Context
= GetContextRef();
1726 if(!Context
) return;
1728 WriteLock(&Context
->PropLock
);
1729 LockSourcesRead(Context
);
1730 if((Source
=LookupSource(Context
, source
)) == NULL
)
1731 alSetError(Context
, AL_INVALID_NAME
);
1732 else if(!(FloatValsByProp(param
) == 3))
1733 alSetError(Context
, AL_INVALID_ENUM
);
1736 ALfloat fvals
[3] = { value1
, value2
, value3
};
1737 SetSourcefv(Source
, Context
, param
, fvals
);
1739 UnlockSourcesRead(Context
);
1740 WriteUnlock(&Context
->PropLock
);
1742 ALCcontext_DecRef(Context
);
1745 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1747 ALCcontext
*Context
;
1750 Context
= GetContextRef();
1751 if(!Context
) return;
1753 WriteLock(&Context
->PropLock
);
1754 LockSourcesRead(Context
);
1755 if((Source
=LookupSource(Context
, source
)) == NULL
)
1756 alSetError(Context
, AL_INVALID_NAME
);
1758 alSetError(Context
, AL_INVALID_VALUE
);
1759 else if(!(FloatValsByProp(param
) > 0))
1760 alSetError(Context
, AL_INVALID_ENUM
);
1762 SetSourcefv(Source
, Context
, param
, values
);
1763 UnlockSourcesRead(Context
);
1764 WriteUnlock(&Context
->PropLock
);
1766 ALCcontext_DecRef(Context
);
1770 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1772 ALCcontext
*Context
;
1775 Context
= GetContextRef();
1776 if(!Context
) return;
1778 WriteLock(&Context
->PropLock
);
1779 LockSourcesRead(Context
);
1780 if((Source
=LookupSource(Context
, source
)) == NULL
)
1781 alSetError(Context
, AL_INVALID_NAME
);
1782 else if(!(DoubleValsByProp(param
) == 1))
1783 alSetError(Context
, AL_INVALID_ENUM
);
1786 ALfloat fval
= (ALfloat
)value
;
1787 SetSourcefv(Source
, Context
, param
, &fval
);
1789 UnlockSourcesRead(Context
);
1790 WriteUnlock(&Context
->PropLock
);
1792 ALCcontext_DecRef(Context
);
1795 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1797 ALCcontext
*Context
;
1800 Context
= GetContextRef();
1801 if(!Context
) return;
1803 WriteLock(&Context
->PropLock
);
1804 LockSourcesRead(Context
);
1805 if((Source
=LookupSource(Context
, source
)) == NULL
)
1806 alSetError(Context
, AL_INVALID_NAME
);
1807 else if(!(DoubleValsByProp(param
) == 3))
1808 alSetError(Context
, AL_INVALID_ENUM
);
1811 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1812 SetSourcefv(Source
, Context
, param
, fvals
);
1814 UnlockSourcesRead(Context
);
1815 WriteUnlock(&Context
->PropLock
);
1817 ALCcontext_DecRef(Context
);
1820 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1822 ALCcontext
*Context
;
1826 Context
= GetContextRef();
1827 if(!Context
) return;
1829 WriteLock(&Context
->PropLock
);
1830 LockSourcesRead(Context
);
1831 if((Source
=LookupSource(Context
, source
)) == NULL
)
1832 alSetError(Context
, AL_INVALID_NAME
);
1834 alSetError(Context
, AL_INVALID_VALUE
);
1835 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1836 alSetError(Context
, AL_INVALID_ENUM
);
1842 for(i
= 0;i
< count
;i
++)
1843 fvals
[i
] = (ALfloat
)values
[i
];
1844 SetSourcefv(Source
, Context
, param
, fvals
);
1846 UnlockSourcesRead(Context
);
1847 WriteUnlock(&Context
->PropLock
);
1849 ALCcontext_DecRef(Context
);
1853 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1855 ALCcontext
*Context
;
1858 Context
= GetContextRef();
1859 if(!Context
) return;
1861 WriteLock(&Context
->PropLock
);
1862 LockSourcesRead(Context
);
1863 if((Source
=LookupSource(Context
, source
)) == NULL
)
1864 alSetError(Context
, AL_INVALID_NAME
);
1865 else if(!(IntValsByProp(param
) == 1))
1866 alSetError(Context
, AL_INVALID_ENUM
);
1868 SetSourceiv(Source
, Context
, param
, &value
);
1869 UnlockSourcesRead(Context
);
1870 WriteUnlock(&Context
->PropLock
);
1872 ALCcontext_DecRef(Context
);
1875 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1877 ALCcontext
*Context
;
1880 Context
= GetContextRef();
1881 if(!Context
) return;
1883 WriteLock(&Context
->PropLock
);
1884 LockSourcesRead(Context
);
1885 if((Source
=LookupSource(Context
, source
)) == NULL
)
1886 alSetError(Context
, AL_INVALID_NAME
);
1887 else if(!(IntValsByProp(param
) == 3))
1888 alSetError(Context
, AL_INVALID_ENUM
);
1891 ALint ivals
[3] = { value1
, value2
, value3
};
1892 SetSourceiv(Source
, Context
, param
, ivals
);
1894 UnlockSourcesRead(Context
);
1895 WriteUnlock(&Context
->PropLock
);
1897 ALCcontext_DecRef(Context
);
1900 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1902 ALCcontext
*Context
;
1905 Context
= GetContextRef();
1906 if(!Context
) return;
1908 WriteLock(&Context
->PropLock
);
1909 LockSourcesRead(Context
);
1910 if((Source
=LookupSource(Context
, source
)) == NULL
)
1911 alSetError(Context
, AL_INVALID_NAME
);
1913 alSetError(Context
, AL_INVALID_VALUE
);
1914 else if(!(IntValsByProp(param
) > 0))
1915 alSetError(Context
, AL_INVALID_ENUM
);
1917 SetSourceiv(Source
, Context
, param
, values
);
1918 UnlockSourcesRead(Context
);
1919 WriteUnlock(&Context
->PropLock
);
1921 ALCcontext_DecRef(Context
);
1925 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1927 ALCcontext
*Context
;
1930 Context
= GetContextRef();
1931 if(!Context
) return;
1933 WriteLock(&Context
->PropLock
);
1934 LockSourcesRead(Context
);
1935 if((Source
=LookupSource(Context
, source
)) == NULL
)
1936 alSetError(Context
, AL_INVALID_NAME
);
1937 else if(!(Int64ValsByProp(param
) == 1))
1938 alSetError(Context
, AL_INVALID_ENUM
);
1940 SetSourcei64v(Source
, Context
, param
, &value
);
1941 UnlockSourcesRead(Context
);
1942 WriteUnlock(&Context
->PropLock
);
1944 ALCcontext_DecRef(Context
);
1947 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1949 ALCcontext
*Context
;
1952 Context
= GetContextRef();
1953 if(!Context
) return;
1955 WriteLock(&Context
->PropLock
);
1956 LockSourcesRead(Context
);
1957 if((Source
=LookupSource(Context
, source
)) == NULL
)
1958 alSetError(Context
, AL_INVALID_NAME
);
1959 else if(!(Int64ValsByProp(param
) == 3))
1960 alSetError(Context
, AL_INVALID_ENUM
);
1963 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1964 SetSourcei64v(Source
, Context
, param
, i64vals
);
1966 UnlockSourcesRead(Context
);
1967 WriteUnlock(&Context
->PropLock
);
1969 ALCcontext_DecRef(Context
);
1972 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1974 ALCcontext
*Context
;
1977 Context
= GetContextRef();
1978 if(!Context
) return;
1980 WriteLock(&Context
->PropLock
);
1981 LockSourcesRead(Context
);
1982 if((Source
=LookupSource(Context
, source
)) == NULL
)
1983 alSetError(Context
, AL_INVALID_NAME
);
1985 alSetError(Context
, AL_INVALID_VALUE
);
1986 else if(!(Int64ValsByProp(param
) > 0))
1987 alSetError(Context
, AL_INVALID_ENUM
);
1989 SetSourcei64v(Source
, Context
, param
, values
);
1990 UnlockSourcesRead(Context
);
1991 WriteUnlock(&Context
->PropLock
);
1993 ALCcontext_DecRef(Context
);
1997 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1999 ALCcontext
*Context
;
2002 Context
= GetContextRef();
2003 if(!Context
) return;
2005 ReadLock(&Context
->PropLock
);
2006 LockSourcesRead(Context
);
2007 if((Source
=LookupSource(Context
, source
)) == NULL
)
2008 alSetError(Context
, AL_INVALID_NAME
);
2010 alSetError(Context
, AL_INVALID_VALUE
);
2011 else if(!(FloatValsByProp(param
) == 1))
2012 alSetError(Context
, AL_INVALID_ENUM
);
2016 if(GetSourcedv(Source
, Context
, param
, &dval
))
2017 *value
= (ALfloat
)dval
;
2019 UnlockSourcesRead(Context
);
2020 ReadUnlock(&Context
->PropLock
);
2022 ALCcontext_DecRef(Context
);
2026 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2028 ALCcontext
*Context
;
2031 Context
= GetContextRef();
2032 if(!Context
) return;
2034 ReadLock(&Context
->PropLock
);
2035 LockSourcesRead(Context
);
2036 if((Source
=LookupSource(Context
, source
)) == NULL
)
2037 alSetError(Context
, AL_INVALID_NAME
);
2038 else if(!(value1
&& value2
&& value3
))
2039 alSetError(Context
, AL_INVALID_VALUE
);
2040 else if(!(FloatValsByProp(param
) == 3))
2041 alSetError(Context
, AL_INVALID_ENUM
);
2045 if(GetSourcedv(Source
, Context
, param
, dvals
))
2047 *value1
= (ALfloat
)dvals
[0];
2048 *value2
= (ALfloat
)dvals
[1];
2049 *value3
= (ALfloat
)dvals
[2];
2052 UnlockSourcesRead(Context
);
2053 ReadUnlock(&Context
->PropLock
);
2055 ALCcontext_DecRef(Context
);
2059 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2061 ALCcontext
*Context
;
2065 Context
= GetContextRef();
2066 if(!Context
) return;
2068 ReadLock(&Context
->PropLock
);
2069 LockSourcesRead(Context
);
2070 if((Source
=LookupSource(Context
, source
)) == NULL
)
2071 alSetError(Context
, AL_INVALID_NAME
);
2073 alSetError(Context
, AL_INVALID_VALUE
);
2074 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2075 alSetError(Context
, AL_INVALID_ENUM
);
2079 if(GetSourcedv(Source
, Context
, param
, dvals
))
2082 for(i
= 0;i
< count
;i
++)
2083 values
[i
] = (ALfloat
)dvals
[i
];
2086 UnlockSourcesRead(Context
);
2087 ReadUnlock(&Context
->PropLock
);
2089 ALCcontext_DecRef(Context
);
2093 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2095 ALCcontext
*Context
;
2098 Context
= GetContextRef();
2099 if(!Context
) return;
2101 ReadLock(&Context
->PropLock
);
2102 LockSourcesRead(Context
);
2103 if((Source
=LookupSource(Context
, source
)) == NULL
)
2104 alSetError(Context
, AL_INVALID_NAME
);
2106 alSetError(Context
, AL_INVALID_VALUE
);
2107 else if(!(DoubleValsByProp(param
) == 1))
2108 alSetError(Context
, AL_INVALID_ENUM
);
2110 GetSourcedv(Source
, Context
, param
, value
);
2111 UnlockSourcesRead(Context
);
2112 ReadUnlock(&Context
->PropLock
);
2114 ALCcontext_DecRef(Context
);
2117 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2119 ALCcontext
*Context
;
2122 Context
= GetContextRef();
2123 if(!Context
) return;
2125 ReadLock(&Context
->PropLock
);
2126 LockSourcesRead(Context
);
2127 if((Source
=LookupSource(Context
, source
)) == NULL
)
2128 alSetError(Context
, AL_INVALID_NAME
);
2129 else if(!(value1
&& value2
&& value3
))
2130 alSetError(Context
, AL_INVALID_VALUE
);
2131 else if(!(DoubleValsByProp(param
) == 3))
2132 alSetError(Context
, AL_INVALID_ENUM
);
2136 if(GetSourcedv(Source
, Context
, param
, dvals
))
2143 UnlockSourcesRead(Context
);
2144 ReadUnlock(&Context
->PropLock
);
2146 ALCcontext_DecRef(Context
);
2149 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2151 ALCcontext
*Context
;
2154 Context
= GetContextRef();
2155 if(!Context
) return;
2157 ReadLock(&Context
->PropLock
);
2158 LockSourcesRead(Context
);
2159 if((Source
=LookupSource(Context
, source
)) == NULL
)
2160 alSetError(Context
, AL_INVALID_NAME
);
2162 alSetError(Context
, AL_INVALID_VALUE
);
2163 else if(!(DoubleValsByProp(param
) > 0))
2164 alSetError(Context
, AL_INVALID_ENUM
);
2166 GetSourcedv(Source
, Context
, param
, values
);
2167 UnlockSourcesRead(Context
);
2168 ReadUnlock(&Context
->PropLock
);
2170 ALCcontext_DecRef(Context
);
2174 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2176 ALCcontext
*Context
;
2179 Context
= GetContextRef();
2180 if(!Context
) return;
2182 ReadLock(&Context
->PropLock
);
2183 LockSourcesRead(Context
);
2184 if((Source
=LookupSource(Context
, source
)) == NULL
)
2185 alSetError(Context
, AL_INVALID_NAME
);
2187 alSetError(Context
, AL_INVALID_VALUE
);
2188 else if(!(IntValsByProp(param
) == 1))
2189 alSetError(Context
, AL_INVALID_ENUM
);
2191 GetSourceiv(Source
, Context
, param
, value
);
2192 UnlockSourcesRead(Context
);
2193 ReadUnlock(&Context
->PropLock
);
2195 ALCcontext_DecRef(Context
);
2199 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2201 ALCcontext
*Context
;
2204 Context
= GetContextRef();
2205 if(!Context
) return;
2207 ReadLock(&Context
->PropLock
);
2208 LockSourcesRead(Context
);
2209 if((Source
=LookupSource(Context
, source
)) == NULL
)
2210 alSetError(Context
, AL_INVALID_NAME
);
2211 else if(!(value1
&& value2
&& value3
))
2212 alSetError(Context
, AL_INVALID_VALUE
);
2213 else if(!(IntValsByProp(param
) == 3))
2214 alSetError(Context
, AL_INVALID_ENUM
);
2218 if(GetSourceiv(Source
, Context
, param
, ivals
))
2225 UnlockSourcesRead(Context
);
2226 ReadUnlock(&Context
->PropLock
);
2228 ALCcontext_DecRef(Context
);
2232 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2234 ALCcontext
*Context
;
2237 Context
= GetContextRef();
2238 if(!Context
) return;
2240 ReadLock(&Context
->PropLock
);
2241 LockSourcesRead(Context
);
2242 if((Source
=LookupSource(Context
, source
)) == NULL
)
2243 alSetError(Context
, AL_INVALID_NAME
);
2245 alSetError(Context
, AL_INVALID_VALUE
);
2246 else if(!(IntValsByProp(param
) > 0))
2247 alSetError(Context
, AL_INVALID_ENUM
);
2249 GetSourceiv(Source
, Context
, param
, values
);
2250 UnlockSourcesRead(Context
);
2251 ReadUnlock(&Context
->PropLock
);
2253 ALCcontext_DecRef(Context
);
2257 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2259 ALCcontext
*Context
;
2262 Context
= GetContextRef();
2263 if(!Context
) return;
2265 ReadLock(&Context
->PropLock
);
2266 LockSourcesRead(Context
);
2267 if((Source
=LookupSource(Context
, source
)) == NULL
)
2268 alSetError(Context
, AL_INVALID_NAME
);
2270 alSetError(Context
, AL_INVALID_VALUE
);
2271 else if(!(Int64ValsByProp(param
) == 1))
2272 alSetError(Context
, AL_INVALID_ENUM
);
2274 GetSourcei64v(Source
, Context
, param
, value
);
2275 UnlockSourcesRead(Context
);
2276 ReadUnlock(&Context
->PropLock
);
2278 ALCcontext_DecRef(Context
);
2281 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2283 ALCcontext
*Context
;
2286 Context
= GetContextRef();
2287 if(!Context
) return;
2289 ReadLock(&Context
->PropLock
);
2290 LockSourcesRead(Context
);
2291 if((Source
=LookupSource(Context
, source
)) == NULL
)
2292 alSetError(Context
, AL_INVALID_NAME
);
2293 else if(!(value1
&& value2
&& value3
))
2294 alSetError(Context
, AL_INVALID_VALUE
);
2295 else if(!(Int64ValsByProp(param
) == 3))
2296 alSetError(Context
, AL_INVALID_ENUM
);
2300 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2302 *value1
= i64vals
[0];
2303 *value2
= i64vals
[1];
2304 *value3
= i64vals
[2];
2307 UnlockSourcesRead(Context
);
2308 ReadUnlock(&Context
->PropLock
);
2310 ALCcontext_DecRef(Context
);
2313 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2315 ALCcontext
*Context
;
2318 Context
= GetContextRef();
2319 if(!Context
) return;
2321 ReadLock(&Context
->PropLock
);
2322 LockSourcesRead(Context
);
2323 if((Source
=LookupSource(Context
, source
)) == NULL
)
2324 alSetError(Context
, AL_INVALID_NAME
);
2326 alSetError(Context
, AL_INVALID_VALUE
);
2327 else if(!(Int64ValsByProp(param
) > 0))
2328 alSetError(Context
, AL_INVALID_ENUM
);
2330 GetSourcei64v(Source
, Context
, param
, values
);
2331 UnlockSourcesRead(Context
);
2332 ReadUnlock(&Context
->PropLock
);
2334 ALCcontext_DecRef(Context
);
2338 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2340 alSourcePlayv(1, &source
);
2342 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2344 ALCcontext
*context
;
2350 context
= GetContextRef();
2351 if(!context
) return;
2353 LockSourcesRead(context
);
2355 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2356 for(i
= 0;i
< n
;i
++)
2358 if(!LookupSource(context
, sources
[i
]))
2359 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2362 device
= context
->Device
;
2363 ALCdevice_Lock(device
);
2364 /* If the device is disconnected, go right to stopped. */
2365 if(!device
->Connected
)
2367 for(i
= 0;i
< n
;i
++)
2369 source
= LookupSource(context
, sources
[i
]);
2370 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2372 ALCdevice_Unlock(device
);
2376 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2378 ALsizei newcount
= context
->MaxVoices
<< 1;
2379 if(context
->MaxVoices
>= newcount
)
2381 ALCdevice_Unlock(device
);
2382 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2384 AllocateVoices(context
, newcount
, device
->NumAuxSends
);
2387 for(i
= 0;i
< n
;i
++)
2389 ALbufferlistitem
*BufferList
;
2390 ALbuffer
*buffer
= NULL
;
2392 source
= LookupSource(context
, sources
[i
]);
2393 WriteLock(&source
->queue_lock
);
2394 /* Check that there is a queue containing at least one valid, non zero
2397 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2400 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2402 BufferList
= BufferList
->next
;
2405 /* If there's nothing to play, go right to stopped. */
2408 /* NOTE: A source without any playable buffers should not have an
2409 * ALvoice since it shouldn't be in a playing or paused state. So
2410 * there's no need to look up its voice and clear the source.
2412 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2413 source
->OffsetType
= AL_NONE
;
2414 source
->Offset
= 0.0;
2418 voice
= GetSourceVoice(source
, context
);
2419 switch(GetSourceState(source
, voice
))
2422 assert(voice
!= NULL
);
2423 /* A source that's already playing is restarted from the beginning. */
2424 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2425 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2426 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_release
);
2430 assert(voice
!= NULL
);
2431 /* A source that's paused simply resumes. Make sure it uses the
2432 * volume last specified; there's no reason to fade from where
2435 voice
->Flags
&= ~VOICE_IS_MOVING
;
2436 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2437 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2444 ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acquire
);
2445 UpdateSourceProps(source
, device
->NumAuxSends
);
2447 /* Make sure this source isn't already active, and if not, look for an
2448 * unused voice to put it in.
2450 assert(voice
== NULL
);
2451 for(j
= 0;j
< context
->VoiceCount
;j
++)
2453 if(ATOMIC_LOAD(&context
->Voices
[j
]->Source
, almemory_order_acquire
) == NULL
)
2455 voice
= context
->Voices
[j
];
2460 voice
= context
->Voices
[context
->VoiceCount
++];
2461 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2462 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
2464 /* A source that's not playing or paused has any offset applied when it
2467 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
2468 ATOMIC_STORE(&voice
->position
, 0, almemory_order_relaxed
);
2469 ATOMIC_STORE(&voice
->position_fraction
, 0, almemory_order_relaxed
);
2470 if(source
->OffsetType
!= AL_NONE
)
2471 ApplyOffset(source
, voice
);
2473 voice
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2474 voice
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2476 /* Clear previous samples. */
2477 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2479 /* Clear the stepping value so the mixer knows not to mix this until
2480 * the update gets applied.
2485 for(j
= 0;j
< voice
->NumChannels
;j
++)
2486 memset(&voice
->Direct
.Params
[j
].Hrtf
.State
, 0,
2487 sizeof(voice
->Direct
.Params
[j
].Hrtf
.State
));
2488 if(device
->AvgSpeakerDist
> 0.0f
)
2490 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2491 (device
->AvgSpeakerDist
* device
->Frequency
);
2492 for(j
= 0;j
< voice
->NumChannels
;j
++)
2494 NfcFilterCreate1(&voice
->Direct
.Params
[j
].NFCtrlFilter
[0], 0.0f
, w1
);
2495 NfcFilterCreate2(&voice
->Direct
.Params
[j
].NFCtrlFilter
[1], 0.0f
, w1
);
2496 NfcFilterCreate3(&voice
->Direct
.Params
[j
].NFCtrlFilter
[2], 0.0f
, w1
);
2500 ATOMIC_STORE(&voice
->Source
, source
, almemory_order_relaxed
);
2501 ATOMIC_STORE(&voice
->Playing
, true, almemory_order_release
);
2502 ATOMIC_STORE(&source
->state
, AL_PLAYING
, almemory_order_release
);
2504 WriteUnlock(&source
->queue_lock
);
2506 ALCdevice_Unlock(device
);
2509 UnlockSourcesRead(context
);
2510 ALCcontext_DecRef(context
);
2513 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2515 alSourcePausev(1, &source
);
2517 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2519 ALCcontext
*context
;
2525 context
= GetContextRef();
2526 if(!context
) return;
2528 LockSourcesRead(context
);
2530 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2531 for(i
= 0;i
< n
;i
++)
2533 if(!LookupSource(context
, sources
[i
]))
2534 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2537 device
= context
->Device
;
2538 ALCdevice_Lock(device
);
2539 for(i
= 0;i
< n
;i
++)
2541 source
= LookupSource(context
, sources
[i
]);
2542 WriteLock(&source
->queue_lock
);
2543 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2545 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2546 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2549 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2550 ATOMIC_STORE(&source
->state
, AL_PAUSED
, almemory_order_release
);
2551 WriteUnlock(&source
->queue_lock
);
2553 ALCdevice_Unlock(device
);
2556 UnlockSourcesRead(context
);
2557 ALCcontext_DecRef(context
);
2560 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2562 alSourceStopv(1, &source
);
2564 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2566 ALCcontext
*context
;
2572 context
= GetContextRef();
2573 if(!context
) return;
2575 LockSourcesRead(context
);
2577 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2578 for(i
= 0;i
< n
;i
++)
2580 if(!LookupSource(context
, sources
[i
]))
2581 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2584 device
= context
->Device
;
2585 ALCdevice_Lock(device
);
2586 for(i
= 0;i
< n
;i
++)
2588 source
= LookupSource(context
, sources
[i
]);
2589 WriteLock(&source
->queue_lock
);
2590 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2592 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2593 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2594 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2597 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2598 ATOMIC_STORE(&source
->state
, AL_STOPPED
, almemory_order_relaxed
);
2599 source
->OffsetType
= AL_NONE
;
2600 source
->Offset
= 0.0;
2601 WriteUnlock(&source
->queue_lock
);
2603 ALCdevice_Unlock(device
);
2606 UnlockSourcesRead(context
);
2607 ALCcontext_DecRef(context
);
2610 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2612 alSourceRewindv(1, &source
);
2614 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2616 ALCcontext
*context
;
2622 context
= GetContextRef();
2623 if(!context
) return;
2625 LockSourcesRead(context
);
2627 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2628 for(i
= 0;i
< n
;i
++)
2630 if(!LookupSource(context
, sources
[i
]))
2631 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2634 device
= context
->Device
;
2635 ALCdevice_Lock(device
);
2636 for(i
= 0;i
< n
;i
++)
2638 source
= LookupSource(context
, sources
[i
]);
2639 WriteLock(&source
->queue_lock
);
2640 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2642 ATOMIC_STORE(&voice
->Source
, NULL
, almemory_order_relaxed
);
2643 ATOMIC_STORE(&voice
->Playing
, false, almemory_order_release
);
2644 while((ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
)&1))
2647 if(ATOMIC_LOAD(&source
->state
, almemory_order_acquire
) != AL_INITIAL
)
2648 ATOMIC_STORE(&source
->state
, AL_INITIAL
, almemory_order_relaxed
);
2649 source
->OffsetType
= AL_NONE
;
2650 source
->Offset
= 0.0;
2651 WriteUnlock(&source
->queue_lock
);
2653 ALCdevice_Unlock(device
);
2656 UnlockSourcesRead(context
);
2657 ALCcontext_DecRef(context
);
2661 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2664 ALCcontext
*context
;
2667 ALbufferlistitem
*BufferListStart
;
2668 ALbufferlistitem
*BufferList
;
2669 ALbuffer
*BufferFmt
= NULL
;
2674 context
= GetContextRef();
2675 if(!context
) return;
2677 device
= context
->Device
;
2679 LockSourcesRead(context
);
2681 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2682 if((source
=LookupSource(context
, src
)) == NULL
)
2683 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2685 WriteLock(&source
->queue_lock
);
2686 if(source
->SourceType
== AL_STATIC
)
2688 WriteUnlock(&source
->queue_lock
);
2689 /* Can't queue on a Static Source */
2690 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2693 /* Check for a valid Buffer, for its frequency and format */
2694 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2697 if(BufferList
->buffer
)
2699 BufferFmt
= BufferList
->buffer
;
2702 BufferList
= BufferList
->next
;
2705 LockBuffersRead(device
);
2706 BufferListStart
= NULL
;
2708 for(i
= 0;i
< nb
;i
++)
2710 ALbuffer
*buffer
= NULL
;
2711 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2713 WriteUnlock(&source
->queue_lock
);
2714 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2717 if(!BufferListStart
)
2719 BufferListStart
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2720 BufferList
= BufferListStart
;
2724 BufferList
->next
= al_calloc(DEF_ALIGN
, sizeof(ALbufferlistitem
));
2725 BufferList
= BufferList
->next
;
2727 BufferList
->buffer
= buffer
;
2728 BufferList
->next
= NULL
;
2729 if(!buffer
) continue;
2731 /* Hold a read lock on each buffer being queued while checking all
2732 * provided buffers. This is done so other threads don't see an extra
2733 * reference on some buffers if this operation ends up failing. */
2734 ReadLock(&buffer
->lock
);
2735 IncrementRef(&buffer
->ref
);
2737 if(BufferFmt
== NULL
)
2739 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2740 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2741 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2743 WriteUnlock(&source
->queue_lock
);
2744 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2747 /* A buffer failed (invalid ID or format), so unlock and release
2748 * each buffer we had. */
2749 while(BufferListStart
)
2751 ALbufferlistitem
*next
= BufferListStart
->next
;
2752 if((buffer
=BufferListStart
->buffer
) != NULL
)
2754 DecrementRef(&buffer
->ref
);
2755 ReadUnlock(&buffer
->lock
);
2757 al_free(BufferListStart
);
2758 BufferListStart
= next
;
2760 UnlockBuffersRead(device
);
2764 /* All buffers good, unlock them now. */
2765 BufferList
= BufferListStart
;
2766 while(BufferList
!= NULL
)
2768 ALbuffer
*buffer
= BufferList
->buffer
;
2769 if(buffer
) ReadUnlock(&buffer
->lock
);
2770 BufferList
= BufferList
->next
;
2772 UnlockBuffersRead(device
);
2774 /* Source is now streaming */
2775 source
->SourceType
= AL_STREAMING
;
2778 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->queue
,
2779 &BufferList
, BufferListStart
))
2781 /* Queue head is not NULL, append to the end of the queue */
2782 while(BufferList
->next
!= NULL
)
2783 BufferList
= BufferList
->next
;
2784 BufferList
->next
= BufferListStart
;
2786 WriteUnlock(&source
->queue_lock
);
2789 UnlockSourcesRead(context
);
2790 ALCcontext_DecRef(context
);
2793 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2795 ALCcontext
*context
;
2797 ALbufferlistitem
*OldHead
;
2798 ALbufferlistitem
*OldTail
;
2799 ALbufferlistitem
*Current
;
2803 context
= GetContextRef();
2804 if(!context
) return;
2806 LockSourcesRead(context
);
2808 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2810 if((source
=LookupSource(context
, src
)) == NULL
)
2811 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2813 /* Nothing to unqueue. */
2814 if(nb
== 0) goto done
;
2816 WriteLock(&source
->queue_lock
);
2817 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2819 WriteUnlock(&source
->queue_lock
);
2820 /* Trying to unqueue buffers on a looping or non-streaming source. */
2821 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2824 /* Find the new buffer queue head */
2825 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2827 if((voice
=GetSourceVoice(source
, context
)) != NULL
)
2828 Current
= ATOMIC_LOAD_SEQ(&voice
->current_buffer
);
2829 else if(ATOMIC_LOAD_SEQ(&source
->state
) == AL_INITIAL
)
2831 if(OldTail
!= Current
)
2833 for(i
= 1;i
< nb
;i
++)
2835 ALbufferlistitem
*next
= OldTail
->next
;
2836 if(!next
|| next
== Current
) break;
2842 WriteUnlock(&source
->queue_lock
);
2843 /* Trying to unqueue pending buffers. */
2844 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2847 /* Swap it, and cut the new head from the old. */
2848 OldHead
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2851 ALCdevice
*device
= context
->Device
;
2854 /* Once the active mix (if any) is done, it's safe to cut the old tail
2855 * from the new head.
2857 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2859 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2862 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2863 OldTail
->next
= NULL
;
2865 WriteUnlock(&source
->queue_lock
);
2867 while(OldHead
!= NULL
)
2869 ALbufferlistitem
*next
= OldHead
->next
;
2870 ALbuffer
*buffer
= OldHead
->buffer
;
2876 *(buffers
++) = buffer
->id
;
2877 DecrementRef(&buffer
->ref
);
2885 UnlockSourcesRead(context
);
2886 ALCcontext_DecRef(context
);
2890 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2894 RWLockInit(&Source
->queue_lock
);
2896 Source
->InnerAngle
= 360.0f
;
2897 Source
->OuterAngle
= 360.0f
;
2898 Source
->Pitch
= 1.0f
;
2899 Source
->Position
[0] = 0.0f
;
2900 Source
->Position
[1] = 0.0f
;
2901 Source
->Position
[2] = 0.0f
;
2902 Source
->Velocity
[0] = 0.0f
;
2903 Source
->Velocity
[1] = 0.0f
;
2904 Source
->Velocity
[2] = 0.0f
;
2905 Source
->Direction
[0] = 0.0f
;
2906 Source
->Direction
[1] = 0.0f
;
2907 Source
->Direction
[2] = 0.0f
;
2908 Source
->Orientation
[0][0] = 0.0f
;
2909 Source
->Orientation
[0][1] = 0.0f
;
2910 Source
->Orientation
[0][2] = -1.0f
;
2911 Source
->Orientation
[1][0] = 0.0f
;
2912 Source
->Orientation
[1][1] = 1.0f
;
2913 Source
->Orientation
[1][2] = 0.0f
;
2914 Source
->RefDistance
= 1.0f
;
2915 Source
->MaxDistance
= FLT_MAX
;
2916 Source
->RollOffFactor
= 1.0f
;
2917 Source
->Gain
= 1.0f
;
2918 Source
->MinGain
= 0.0f
;
2919 Source
->MaxGain
= 1.0f
;
2920 Source
->OuterGain
= 0.0f
;
2921 Source
->OuterGainHF
= 1.0f
;
2923 Source
->DryGainHFAuto
= AL_TRUE
;
2924 Source
->WetGainAuto
= AL_TRUE
;
2925 Source
->WetGainHFAuto
= AL_TRUE
;
2926 Source
->AirAbsorptionFactor
= 0.0f
;
2927 Source
->RoomRolloffFactor
= 0.0f
;
2928 Source
->DopplerFactor
= 1.0f
;
2929 Source
->DirectChannels
= AL_FALSE
;
2931 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2932 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2934 Source
->Radius
= 0.0f
;
2936 Source
->DistanceModel
= DefaultDistanceModel
;
2938 Source
->Direct
.Gain
= 1.0f
;
2939 Source
->Direct
.GainHF
= 1.0f
;
2940 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2941 Source
->Direct
.GainLF
= 1.0f
;
2942 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2943 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2944 for(i
= 0;i
< num_sends
;i
++)
2946 Source
->Send
[i
].Slot
= NULL
;
2947 Source
->Send
[i
].Gain
= 1.0f
;
2948 Source
->Send
[i
].GainHF
= 1.0f
;
2949 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2950 Source
->Send
[i
].GainLF
= 1.0f
;
2951 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2954 Source
->Offset
= 0.0;
2955 Source
->OffsetType
= AL_NONE
;
2956 Source
->SourceType
= AL_UNDETERMINED
;
2957 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2959 ATOMIC_INIT(&Source
->queue
, NULL
);
2961 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2963 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2966 ATOMIC_FLAG_TEST_AND_SET(&Source
->PropsClean
, almemory_order_relaxed
);
2968 ATOMIC_INIT(&Source
->Update
, NULL
);
2969 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2972 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2974 ALbufferlistitem
*BufferList
;
2975 struct ALsourceProps
*props
;
2979 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2980 if(props
) al_free(props
);
2982 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2985 struct ALsourceProps
*next
;
2986 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2991 /* This is excessively spammy if it traces every source destruction, so
2992 * just warn if it was unexpectedly large.
2995 WARN("Freed "SZFMT
" Source property objects\n", count
);
2997 BufferList
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, NULL
);
2998 while(BufferList
!= NULL
)
3000 ALbufferlistitem
*next
= BufferList
->next
;
3001 if(BufferList
->buffer
!= NULL
)
3002 DecrementRef(&BufferList
->buffer
->ref
);
3003 al_free(BufferList
);
3009 for(i
= 0;i
< num_sends
;i
++)
3011 if(source
->Send
[i
].Slot
)
3012 DecrementRef(&source
->Send
[i
].Slot
->ref
);
3013 source
->Send
[i
].Slot
= NULL
;
3015 al_free(source
->Send
);
3016 source
->Send
= NULL
;
3020 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
)
3022 struct ALsourceProps
*props
;
3025 /* Get an unused property container, or allocate a new one as needed. */
3026 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
3028 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
3031 struct ALsourceProps
*next
;
3033 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
3034 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
3035 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
3036 almemory_order_acquire
) == 0);
3039 /* Copy in current property values. */
3040 props
->Pitch
= source
->Pitch
;
3041 props
->Gain
= source
->Gain
;
3042 props
->OuterGain
= source
->OuterGain
;
3043 props
->MinGain
= source
->MinGain
;
3044 props
->MaxGain
= source
->MaxGain
;
3045 props
->InnerAngle
= source
->InnerAngle
;
3046 props
->OuterAngle
= source
->OuterAngle
;
3047 props
->RefDistance
= source
->RefDistance
;
3048 props
->MaxDistance
= source
->MaxDistance
;
3049 props
->RollOffFactor
= source
->RollOffFactor
;
3050 for(i
= 0;i
< 3;i
++)
3051 props
->Position
[i
] = source
->Position
[i
];
3052 for(i
= 0;i
< 3;i
++)
3053 props
->Velocity
[i
] = source
->Velocity
[i
];
3054 for(i
= 0;i
< 3;i
++)
3055 props
->Direction
[i
] = source
->Direction
[i
];
3056 for(i
= 0;i
< 2;i
++)
3059 for(j
= 0;j
< 3;j
++)
3060 props
->Orientation
[i
][j
] = source
->Orientation
[i
][j
];
3062 props
->HeadRelative
= source
->HeadRelative
;
3063 props
->DistanceModel
= source
->DistanceModel
;
3064 props
->DirectChannels
= source
->DirectChannels
;
3066 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
3067 props
->WetGainAuto
= source
->WetGainAuto
;
3068 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
3069 props
->OuterGainHF
= source
->OuterGainHF
;
3071 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
3072 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
3073 props
->DopplerFactor
= source
->DopplerFactor
;
3075 props
->StereoPan
[0] = source
->StereoPan
[0];
3076 props
->StereoPan
[1] = source
->StereoPan
[1];
3078 props
->Radius
= source
->Radius
;
3080 props
->Direct
.Gain
= source
->Direct
.Gain
;
3081 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
3082 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
3083 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
3084 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
3086 for(i
= 0;i
< num_sends
;i
++)
3088 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
3089 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
3090 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
3091 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
3092 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
3093 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
3096 /* Set the new container for updating internal parameters. */
3097 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
3100 /* If there was an unused update container, put it back in the
3103 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
3107 void UpdateAllSourceProps(ALCcontext
*context
)
3109 ALsizei num_sends
= context
->Device
->NumAuxSends
;
3112 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
3114 ALvoice
*voice
= context
->Voices
[pos
];
3115 ALsource
*source
= ATOMIC_LOAD(&voice
->Source
, almemory_order_acquire
);
3116 if(source
!= NULL
&& ATOMIC_FLAG_TEST_AND_SET(&source
->PropsClean
, almemory_order_acq_rel
))
3117 UpdateSourceProps(source
, num_sends
);
3122 /* GetSourceSampleOffset
3124 * Gets the current read offset for the given Source, in 32.32 fixed-point
3125 * samples. The offset is relative to the start of the queue (not the start of
3126 * the current buffer).
3128 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3130 ALCdevice
*device
= context
->Device
;
3131 const ALbufferlistitem
*BufferList
;
3132 const ALbufferlistitem
*Current
;
3137 ReadLock(&Source
->queue_lock
);
3138 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3142 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3144 *clocktime
= GetDeviceClockTime(device
);
3146 voice
= GetSourceVoice(Source
, context
);
3149 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3151 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) << 32;
3152 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
) <<
3155 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3156 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3160 while(BufferList
&& BufferList
!= Current
)
3162 if(BufferList
->buffer
)
3163 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3164 BufferList
= BufferList
->next
;
3166 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
3169 ReadUnlock(&Source
->queue_lock
);
3170 return (ALint64
)readPos
;
3173 /* GetSourceSecOffset
3175 * Gets the current read offset for the given Source, in seconds. The offset is
3176 * relative to the start of the queue (not the start of the current buffer).
3178 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, ALuint64
*clocktime
)
3180 ALCdevice
*device
= context
->Device
;
3181 const ALbufferlistitem
*BufferList
;
3182 const ALbufferlistitem
*Current
;
3188 ReadLock(&Source
->queue_lock
);
3189 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3193 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3195 *clocktime
= GetDeviceClockTime(device
);
3197 voice
= GetSourceVoice(Source
, context
);
3200 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3202 readPos
= (ALuint64
)ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
) <<
3204 readPos
|= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3206 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3207 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3212 const ALbuffer
*Buffer
= NULL
;
3213 while(BufferList
&& BufferList
!= Current
)
3215 const ALbuffer
*buffer
= BufferList
->buffer
;
3218 if(!Buffer
) Buffer
= buffer
;
3219 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3221 BufferList
= BufferList
->next
;
3224 while(BufferList
&& !Buffer
)
3226 Buffer
= BufferList
->buffer
;
3227 BufferList
= BufferList
->next
;
3229 assert(Buffer
!= NULL
);
3231 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3232 (ALdouble
)Buffer
->Frequency
;
3235 ReadUnlock(&Source
->queue_lock
);
3241 * Gets the current read offset for the given Source, in the appropriate format
3242 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3243 * queue (not the start of the current buffer).
3245 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
3247 ALCdevice
*device
= context
->Device
;
3248 const ALbufferlistitem
*BufferList
;
3249 const ALbufferlistitem
*Current
;
3250 const ALbuffer
*Buffer
= NULL
;
3251 ALboolean readFin
= AL_FALSE
;
3252 ALuint readPos
, readPosFrac
;
3253 ALuint totalBufferLen
;
3259 ReadLock(&Source
->queue_lock
);
3260 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3261 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3264 readPos
= readPosFrac
= 0;
3265 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3267 voice
= GetSourceVoice(Source
, context
);
3270 Current
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
3272 readPos
= ATOMIC_LOAD(&voice
->position
, almemory_order_relaxed
);
3273 readPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
3275 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3276 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3280 ReadUnlock(&Source
->queue_lock
);
3285 while(BufferList
!= NULL
)
3287 const ALbuffer
*buffer
;
3288 readFin
= readFin
|| (BufferList
== Current
);
3289 if((buffer
=BufferList
->buffer
) != NULL
)
3291 if(!Buffer
) Buffer
= buffer
;
3292 totalBufferLen
+= buffer
->SampleLen
;
3293 if(!readFin
) readPos
+= buffer
->SampleLen
;
3295 BufferList
= BufferList
->next
;
3297 assert(Buffer
!= NULL
);
3300 readPos
%= totalBufferLen
;
3303 /* Wrap back to 0 */
3304 if(readPos
>= totalBufferLen
)
3305 readPos
= readPosFrac
= 0;
3312 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3315 case AL_SAMPLE_OFFSET
:
3316 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3319 case AL_BYTE_OFFSET
:
3320 if(Buffer
->OriginalType
== UserFmtIMA4
)
3322 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3323 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3324 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3326 /* Round down to nearest ADPCM block */
3327 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3329 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3331 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
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
);
3340 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3341 offset
= (ALdouble
)(readPos
* FrameSize
);
3346 ReadUnlock(&Source
->queue_lock
);
3353 * Apply the stored playback offset to the Source. This function will update
3354 * the number of buffers "played" given the stored offset.
3356 static ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
3358 ALbufferlistitem
*BufferList
;
3359 const ALbuffer
*Buffer
;
3360 ALuint bufferLen
, totalBufferLen
;
3361 ALuint offset
=0, frac
=0;
3363 /* Get sample frame offset */
3364 if(!GetSampleOffset(Source
, &offset
, &frac
))
3368 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3369 while(BufferList
&& totalBufferLen
<= offset
)
3371 Buffer
= BufferList
->buffer
;
3372 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3374 if(bufferLen
> offset
-totalBufferLen
)
3376 /* Offset is in this buffer */
3377 ATOMIC_STORE(&voice
->current_buffer
, BufferList
, almemory_order_relaxed
);
3378 ATOMIC_STORE(&voice
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3379 ATOMIC_STORE(&voice
->position_fraction
, frac
, almemory_order_release
);
3383 totalBufferLen
+= bufferLen
;
3385 BufferList
= BufferList
->next
;
3388 /* Offset is out of range of the queue */
3395 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3396 * or Second offset supplied by the application). This takes into account the
3397 * fact that the buffer format may have been modifed since.
3399 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3401 const ALbuffer
*Buffer
= NULL
;
3402 const ALbufferlistitem
*BufferList
;
3403 ALdouble dbloff
, dblfrac
;
3405 /* Find the first valid Buffer in the Queue */
3406 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3409 if(BufferList
->buffer
)
3411 Buffer
= BufferList
->buffer
;
3414 BufferList
= BufferList
->next
;
3418 Source
->OffsetType
= AL_NONE
;
3419 Source
->Offset
= 0.0;
3423 switch(Source
->OffsetType
)
3425 case AL_BYTE_OFFSET
:
3426 /* Determine the ByteOffset (and ensure it is block aligned) */
3427 *offset
= (ALuint
)Source
->Offset
;
3428 if(Buffer
->OriginalType
== UserFmtIMA4
)
3430 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3431 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3432 *offset
*= Buffer
->OriginalAlign
;
3434 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3436 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3437 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3438 *offset
*= Buffer
->OriginalAlign
;
3441 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3445 case AL_SAMPLE_OFFSET
:
3446 dblfrac
= modf(Source
->Offset
, &dbloff
);
3447 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3448 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3452 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3453 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3454 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3457 Source
->OffsetType
= AL_NONE
;
3458 Source
->Offset
= 0.0;
3466 * Destroys all sources in the source map.
3468 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3470 ALCdevice
*device
= Context
->Device
;
3472 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3474 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3475 Context
->SourceMap
.values
[pos
] = NULL
;
3477 DeinitSource(temp
, device
->NumAuxSends
);
3479 FreeThunkEntry(temp
->id
);
3480 memset(temp
, 0, sizeof(*temp
));