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
);
49 extern inline ALboolean
IsPlayingOrPaused(const ALsource
*source
);
51 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
52 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
53 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
);
54 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
56 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
);
57 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
);
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((*voice
)->Source
== source
)
142 static inline bool SourceShouldUpdate(const ALsource
*source
, const ALCcontext
*context
)
144 return IsPlayingOrPaused(source
) &&
145 !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
);
148 static ALint
FloatValsByProp(ALenum prop
)
150 if(prop
!= (ALenum
)((SourceProp
)prop
))
152 switch((SourceProp
)prop
)
158 case AL_MAX_DISTANCE
:
159 case AL_ROLLOFF_FACTOR
:
160 case AL_DOPPLER_FACTOR
:
161 case AL_CONE_OUTER_GAIN
:
163 case AL_SAMPLE_OFFSET
:
165 case AL_CONE_INNER_ANGLE
:
166 case AL_CONE_OUTER_ANGLE
:
167 case AL_REFERENCE_DISTANCE
:
168 case AL_CONE_OUTER_GAINHF
:
169 case AL_AIR_ABSORPTION_FACTOR
:
170 case AL_ROOM_ROLLOFF_FACTOR
:
171 case AL_DIRECT_FILTER_GAINHF_AUTO
:
172 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
173 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
174 case AL_DIRECT_CHANNELS_SOFT
:
175 case AL_DISTANCE_MODEL
:
176 case AL_SOURCE_RELATIVE
:
178 case AL_SOURCE_STATE
:
179 case AL_BUFFERS_QUEUED
:
180 case AL_BUFFERS_PROCESSED
:
182 case AL_BYTE_LENGTH_SOFT
:
183 case AL_SAMPLE_LENGTH_SOFT
:
184 case AL_SEC_LENGTH_SOFT
:
185 case AL_SOURCE_RADIUS
:
188 case AL_STEREO_ANGLES
:
199 case AL_SEC_OFFSET_LATENCY_SOFT
:
200 break; /* Double only */
203 case AL_DIRECT_FILTER
:
204 case AL_AUXILIARY_SEND_FILTER
:
205 break; /* i/i64 only */
206 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
207 break; /* i64 only */
211 static ALint
DoubleValsByProp(ALenum prop
)
213 if(prop
!= (ALenum
)((SourceProp
)prop
))
215 switch((SourceProp
)prop
)
221 case AL_MAX_DISTANCE
:
222 case AL_ROLLOFF_FACTOR
:
223 case AL_DOPPLER_FACTOR
:
224 case AL_CONE_OUTER_GAIN
:
226 case AL_SAMPLE_OFFSET
:
228 case AL_CONE_INNER_ANGLE
:
229 case AL_CONE_OUTER_ANGLE
:
230 case AL_REFERENCE_DISTANCE
:
231 case AL_CONE_OUTER_GAINHF
:
232 case AL_AIR_ABSORPTION_FACTOR
:
233 case AL_ROOM_ROLLOFF_FACTOR
:
234 case AL_DIRECT_FILTER_GAINHF_AUTO
:
235 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
236 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
237 case AL_DIRECT_CHANNELS_SOFT
:
238 case AL_DISTANCE_MODEL
:
239 case AL_SOURCE_RELATIVE
:
241 case AL_SOURCE_STATE
:
242 case AL_BUFFERS_QUEUED
:
243 case AL_BUFFERS_PROCESSED
:
245 case AL_BYTE_LENGTH_SOFT
:
246 case AL_SAMPLE_LENGTH_SOFT
:
247 case AL_SEC_LENGTH_SOFT
:
248 case AL_SOURCE_RADIUS
:
251 case AL_SEC_OFFSET_LATENCY_SOFT
:
252 case AL_STEREO_ANGLES
:
264 case AL_DIRECT_FILTER
:
265 case AL_AUXILIARY_SEND_FILTER
:
266 break; /* i/i64 only */
267 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
268 break; /* i64 only */
273 static ALint
IntValsByProp(ALenum prop
)
275 if(prop
!= (ALenum
)((SourceProp
)prop
))
277 switch((SourceProp
)prop
)
283 case AL_MAX_DISTANCE
:
284 case AL_ROLLOFF_FACTOR
:
285 case AL_DOPPLER_FACTOR
:
286 case AL_CONE_OUTER_GAIN
:
288 case AL_SAMPLE_OFFSET
:
290 case AL_CONE_INNER_ANGLE
:
291 case AL_CONE_OUTER_ANGLE
:
292 case AL_REFERENCE_DISTANCE
:
293 case AL_CONE_OUTER_GAINHF
:
294 case AL_AIR_ABSORPTION_FACTOR
:
295 case AL_ROOM_ROLLOFF_FACTOR
:
296 case AL_DIRECT_FILTER_GAINHF_AUTO
:
297 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
298 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
299 case AL_DIRECT_CHANNELS_SOFT
:
300 case AL_DISTANCE_MODEL
:
301 case AL_SOURCE_RELATIVE
:
304 case AL_SOURCE_STATE
:
305 case AL_BUFFERS_QUEUED
:
306 case AL_BUFFERS_PROCESSED
:
308 case AL_DIRECT_FILTER
:
309 case AL_BYTE_LENGTH_SOFT
:
310 case AL_SAMPLE_LENGTH_SOFT
:
311 case AL_SEC_LENGTH_SOFT
:
312 case AL_SOURCE_RADIUS
:
318 case AL_AUXILIARY_SEND_FILTER
:
324 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
325 break; /* i64 only */
326 case AL_SEC_OFFSET_LATENCY_SOFT
:
327 break; /* Double only */
328 case AL_STEREO_ANGLES
:
329 break; /* Float/double only */
333 static ALint
Int64ValsByProp(ALenum prop
)
335 if(prop
!= (ALenum
)((SourceProp
)prop
))
337 switch((SourceProp
)prop
)
343 case AL_MAX_DISTANCE
:
344 case AL_ROLLOFF_FACTOR
:
345 case AL_DOPPLER_FACTOR
:
346 case AL_CONE_OUTER_GAIN
:
348 case AL_SAMPLE_OFFSET
:
350 case AL_CONE_INNER_ANGLE
:
351 case AL_CONE_OUTER_ANGLE
:
352 case AL_REFERENCE_DISTANCE
:
353 case AL_CONE_OUTER_GAINHF
:
354 case AL_AIR_ABSORPTION_FACTOR
:
355 case AL_ROOM_ROLLOFF_FACTOR
:
356 case AL_DIRECT_FILTER_GAINHF_AUTO
:
357 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
358 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
359 case AL_DIRECT_CHANNELS_SOFT
:
360 case AL_DISTANCE_MODEL
:
361 case AL_SOURCE_RELATIVE
:
364 case AL_SOURCE_STATE
:
365 case AL_BUFFERS_QUEUED
:
366 case AL_BUFFERS_PROCESSED
:
368 case AL_DIRECT_FILTER
:
369 case AL_BYTE_LENGTH_SOFT
:
370 case AL_SAMPLE_LENGTH_SOFT
:
371 case AL_SEC_LENGTH_SOFT
:
372 case AL_SOURCE_RADIUS
:
375 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
381 case AL_AUXILIARY_SEND_FILTER
:
387 case AL_SEC_OFFSET_LATENCY_SOFT
:
388 break; /* Double only */
389 case AL_STEREO_ANGLES
:
390 break; /* Float/double only */
396 #define CHECKVAL(x) do { \
398 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
401 #define DO_UPDATEPROPS() do { \
402 if(SourceShouldUpdate(Source, Context)) \
403 UpdateSourceProps(Source, device->NumAuxSends); \
405 Source->NeedsUpdate = AL_TRUE; \
408 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
410 ALCdevice
*device
= Context
->Device
;
415 case AL_BYTE_LENGTH_SOFT
:
416 case AL_SAMPLE_LENGTH_SOFT
:
417 case AL_SEC_LENGTH_SOFT
:
418 case AL_SEC_OFFSET_LATENCY_SOFT
:
420 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
423 CHECKVAL(*values
>= 0.0f
);
425 Source
->Pitch
= *values
;
429 case AL_CONE_INNER_ANGLE
:
430 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
432 Source
->InnerAngle
= *values
;
436 case AL_CONE_OUTER_ANGLE
:
437 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
439 Source
->OuterAngle
= *values
;
444 CHECKVAL(*values
>= 0.0f
);
446 Source
->Gain
= *values
;
450 case AL_MAX_DISTANCE
:
451 CHECKVAL(*values
>= 0.0f
);
453 Source
->MaxDistance
= *values
;
457 case AL_ROLLOFF_FACTOR
:
458 CHECKVAL(*values
>= 0.0f
);
460 Source
->RollOffFactor
= *values
;
464 case AL_REFERENCE_DISTANCE
:
465 CHECKVAL(*values
>= 0.0f
);
467 Source
->RefDistance
= *values
;
472 CHECKVAL(*values
>= 0.0f
);
474 Source
->MinGain
= *values
;
479 CHECKVAL(*values
>= 0.0f
);
481 Source
->MaxGain
= *values
;
485 case AL_CONE_OUTER_GAIN
:
486 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
488 Source
->OuterGain
= *values
;
492 case AL_CONE_OUTER_GAINHF
:
493 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
495 Source
->OuterGainHF
= *values
;
499 case AL_AIR_ABSORPTION_FACTOR
:
500 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
502 Source
->AirAbsorptionFactor
= *values
;
506 case AL_ROOM_ROLLOFF_FACTOR
:
507 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
509 Source
->RoomRolloffFactor
= *values
;
513 case AL_DOPPLER_FACTOR
:
514 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
516 Source
->DopplerFactor
= *values
;
521 case AL_SAMPLE_OFFSET
:
523 CHECKVAL(*values
>= 0.0f
);
525 Source
->OffsetType
= prop
;
526 Source
->Offset
= *values
;
528 if(IsPlayingOrPaused(Source
) &&
529 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
531 ALCdevice_Lock(Context
->Device
);
532 WriteLock(&Source
->queue_lock
);
533 if(ApplyOffset(Source
) == AL_FALSE
)
535 WriteUnlock(&Source
->queue_lock
);
536 ALCdevice_Unlock(Context
->Device
);
537 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
539 WriteUnlock(&Source
->queue_lock
);
540 ALCdevice_Unlock(Context
->Device
);
544 case AL_SOURCE_RADIUS
:
545 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
547 Source
->Radius
= *values
;
551 case AL_STEREO_ANGLES
:
552 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
554 Source
->StereoPan
[0] = values
[0];
555 Source
->StereoPan
[1] = values
[1];
561 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
563 Source
->Position
[0] = values
[0];
564 Source
->Position
[1] = values
[1];
565 Source
->Position
[2] = values
[2];
570 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
572 Source
->Velocity
[0] = values
[0];
573 Source
->Velocity
[1] = values
[1];
574 Source
->Velocity
[2] = values
[2];
579 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
581 Source
->Direction
[0] = values
[0];
582 Source
->Direction
[1] = values
[1];
583 Source
->Direction
[2] = values
[2];
588 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
589 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
591 Source
->Orientation
[0][0] = values
[0];
592 Source
->Orientation
[0][1] = values
[1];
593 Source
->Orientation
[0][2] = values
[2];
594 Source
->Orientation
[1][0] = values
[3];
595 Source
->Orientation
[1][1] = values
[4];
596 Source
->Orientation
[1][2] = values
[5];
601 case AL_SOURCE_RELATIVE
:
603 case AL_SOURCE_STATE
:
605 case AL_DISTANCE_MODEL
:
606 case AL_DIRECT_FILTER_GAINHF_AUTO
:
607 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
608 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
609 case AL_DIRECT_CHANNELS_SOFT
:
610 ival
= (ALint
)values
[0];
611 return SetSourceiv(Source
, Context
, prop
, &ival
);
613 case AL_BUFFERS_QUEUED
:
614 case AL_BUFFERS_PROCESSED
:
615 ival
= (ALint
)((ALuint
)values
[0]);
616 return SetSourceiv(Source
, Context
, prop
, &ival
);
619 case AL_DIRECT_FILTER
:
620 case AL_AUXILIARY_SEND_FILTER
:
621 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
625 ERR("Unexpected property: 0x%04x\n", prop
);
626 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
629 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
631 ALCdevice
*device
= Context
->Device
;
632 ALbuffer
*buffer
= NULL
;
633 ALfilter
*filter
= NULL
;
634 ALeffectslot
*slot
= NULL
;
635 ALbufferlistitem
*oldlist
;
636 ALbufferlistitem
*newlist
;
641 case AL_SOURCE_STATE
:
643 case AL_BUFFERS_QUEUED
:
644 case AL_BUFFERS_PROCESSED
:
645 case AL_BYTE_LENGTH_SOFT
:
646 case AL_SAMPLE_LENGTH_SOFT
:
647 case AL_SEC_LENGTH_SOFT
:
649 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
651 case AL_SOURCE_RELATIVE
:
652 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
654 Source
->HeadRelative
= (ALboolean
)*values
;
659 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
661 WriteLock(&Source
->queue_lock
);
662 ATOMIC_STORE_SEQ(&Source
->looping
, *values
);
663 WriteUnlock(&Source
->queue_lock
);
667 LockBuffersRead(device
);
668 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
670 UnlockBuffersRead(device
);
671 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
674 WriteLock(&Source
->queue_lock
);
675 if(IsPlayingOrPaused(Source
))
677 WriteUnlock(&Source
->queue_lock
);
678 UnlockBuffersRead(device
);
679 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
684 /* Add the selected buffer to a one-item queue */
685 newlist
= malloc(sizeof(ALbufferlistitem
));
686 newlist
->buffer
= buffer
;
687 newlist
->next
= NULL
;
688 IncrementRef(&buffer
->ref
);
690 /* Source is now Static */
691 Source
->SourceType
= AL_STATIC
;
693 ReadLock(&buffer
->lock
);
694 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
695 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
696 ReadUnlock(&buffer
->lock
);
700 /* Source is now Undetermined */
701 Source
->SourceType
= AL_UNDETERMINED
;
704 oldlist
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &Source
->queue
, newlist
);
705 ATOMIC_STORE_SEQ(&Source
->current_buffer
, newlist
);
706 WriteUnlock(&Source
->queue_lock
);
707 UnlockBuffersRead(device
);
709 /* Delete all elements in the previous queue */
710 while(oldlist
!= NULL
)
712 ALbufferlistitem
*temp
= oldlist
;
713 oldlist
= temp
->next
;
716 DecrementRef(&temp
->buffer
->ref
);
722 case AL_SAMPLE_OFFSET
:
724 CHECKVAL(*values
>= 0);
726 Source
->OffsetType
= prop
;
727 Source
->Offset
= *values
;
729 if(IsPlayingOrPaused(Source
) &&
730 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
732 ALCdevice_Lock(Context
->Device
);
733 WriteLock(&Source
->queue_lock
);
734 if(ApplyOffset(Source
) == AL_FALSE
)
736 WriteUnlock(&Source
->queue_lock
);
737 ALCdevice_Unlock(Context
->Device
);
738 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
740 WriteUnlock(&Source
->queue_lock
);
741 ALCdevice_Unlock(Context
->Device
);
745 case AL_DIRECT_FILTER
:
746 LockFiltersRead(device
);
747 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
749 UnlockFiltersRead(device
);
750 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
755 Source
->Direct
.Gain
= 1.0f
;
756 Source
->Direct
.GainHF
= 1.0f
;
757 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
758 Source
->Direct
.GainLF
= 1.0f
;
759 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
763 Source
->Direct
.Gain
= filter
->Gain
;
764 Source
->Direct
.GainHF
= filter
->GainHF
;
765 Source
->Direct
.HFReference
= filter
->HFReference
;
766 Source
->Direct
.GainLF
= filter
->GainLF
;
767 Source
->Direct
.LFReference
= filter
->LFReference
;
769 UnlockFiltersRead(device
);
773 case AL_DIRECT_FILTER_GAINHF_AUTO
:
774 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
776 Source
->DryGainHFAuto
= *values
;
780 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
781 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
783 Source
->WetGainAuto
= *values
;
787 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
788 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
790 Source
->WetGainHFAuto
= *values
;
794 case AL_DIRECT_CHANNELS_SOFT
:
795 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
797 Source
->DirectChannels
= *values
;
801 case AL_DISTANCE_MODEL
:
802 CHECKVAL(*values
== AL_NONE
||
803 *values
== AL_INVERSE_DISTANCE
||
804 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
805 *values
== AL_LINEAR_DISTANCE
||
806 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
807 *values
== AL_EXPONENT_DISTANCE
||
808 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
810 Source
->DistanceModel
= *values
;
811 if(Context
->SourceDistanceModel
)
816 case AL_AUXILIARY_SEND_FILTER
:
817 LockEffectSlotsRead(Context
);
818 LockFiltersRead(device
);
819 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
820 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
821 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
823 UnlockFiltersRead(device
);
824 UnlockEffectSlotsRead(Context
);
825 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
831 Source
->Send
[values
[1]].Gain
= 1.0f
;
832 Source
->Send
[values
[1]].GainHF
= 1.0f
;
833 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
834 Source
->Send
[values
[1]].GainLF
= 1.0f
;
835 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
839 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
840 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
841 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
842 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
843 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
845 UnlockFiltersRead(device
);
847 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
849 /* Add refcount on the new slot, and release the previous slot */
850 if(slot
) IncrementRef(&slot
->ref
);
851 if(Source
->Send
[values
[1]].Slot
)
852 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
853 Source
->Send
[values
[1]].Slot
= slot
;
855 /* We must force an update if the auxiliary slot changed on a
856 * playing source, in case the slot is about to be deleted.
858 UpdateSourceProps(Source
, device
->NumAuxSends
);
862 if(slot
) IncrementRef(&slot
->ref
);
863 if(Source
->Send
[values
[1]].Slot
)
864 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
865 Source
->Send
[values
[1]].Slot
= slot
;
868 UnlockEffectSlotsRead(Context
);
874 case AL_CONE_INNER_ANGLE
:
875 case AL_CONE_OUTER_ANGLE
:
880 case AL_REFERENCE_DISTANCE
:
881 case AL_ROLLOFF_FACTOR
:
882 case AL_CONE_OUTER_GAIN
:
883 case AL_MAX_DISTANCE
:
884 case AL_DOPPLER_FACTOR
:
885 case AL_CONE_OUTER_GAINHF
:
886 case AL_AIR_ABSORPTION_FACTOR
:
887 case AL_ROOM_ROLLOFF_FACTOR
:
888 case AL_SOURCE_RADIUS
:
889 fvals
[0] = (ALfloat
)*values
;
890 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
896 fvals
[0] = (ALfloat
)values
[0];
897 fvals
[1] = (ALfloat
)values
[1];
898 fvals
[2] = (ALfloat
)values
[2];
899 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
903 fvals
[0] = (ALfloat
)values
[0];
904 fvals
[1] = (ALfloat
)values
[1];
905 fvals
[2] = (ALfloat
)values
[2];
906 fvals
[3] = (ALfloat
)values
[3];
907 fvals
[4] = (ALfloat
)values
[4];
908 fvals
[5] = (ALfloat
)values
[5];
909 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
911 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
912 case AL_SEC_OFFSET_LATENCY_SOFT
:
913 case AL_STEREO_ANGLES
:
917 ERR("Unexpected property: 0x%04x\n", prop
);
918 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
921 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
929 case AL_BUFFERS_QUEUED
:
930 case AL_BUFFERS_PROCESSED
:
931 case AL_SOURCE_STATE
:
932 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
933 case AL_BYTE_LENGTH_SOFT
:
934 case AL_SAMPLE_LENGTH_SOFT
:
935 case AL_SEC_LENGTH_SOFT
:
937 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
941 case AL_SOURCE_RELATIVE
:
944 case AL_SAMPLE_OFFSET
:
946 case AL_DIRECT_FILTER_GAINHF_AUTO
:
947 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
948 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
949 case AL_DIRECT_CHANNELS_SOFT
:
950 case AL_DISTANCE_MODEL
:
951 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
953 ivals
[0] = (ALint
)*values
;
954 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
958 case AL_DIRECT_FILTER
:
959 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
961 ivals
[0] = (ALuint
)*values
;
962 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
965 case AL_AUXILIARY_SEND_FILTER
:
966 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
967 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
968 values
[2] <= UINT_MAX
&& values
[2] >= 0);
970 ivals
[0] = (ALuint
)values
[0];
971 ivals
[1] = (ALuint
)values
[1];
972 ivals
[2] = (ALuint
)values
[2];
973 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
976 case AL_CONE_INNER_ANGLE
:
977 case AL_CONE_OUTER_ANGLE
:
982 case AL_REFERENCE_DISTANCE
:
983 case AL_ROLLOFF_FACTOR
:
984 case AL_CONE_OUTER_GAIN
:
985 case AL_MAX_DISTANCE
:
986 case AL_DOPPLER_FACTOR
:
987 case AL_CONE_OUTER_GAINHF
:
988 case AL_AIR_ABSORPTION_FACTOR
:
989 case AL_ROOM_ROLLOFF_FACTOR
:
990 case AL_SOURCE_RADIUS
:
991 fvals
[0] = (ALfloat
)*values
;
992 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
998 fvals
[0] = (ALfloat
)values
[0];
999 fvals
[1] = (ALfloat
)values
[1];
1000 fvals
[2] = (ALfloat
)values
[2];
1001 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1004 case AL_ORIENTATION
:
1005 fvals
[0] = (ALfloat
)values
[0];
1006 fvals
[1] = (ALfloat
)values
[1];
1007 fvals
[2] = (ALfloat
)values
[2];
1008 fvals
[3] = (ALfloat
)values
[3];
1009 fvals
[4] = (ALfloat
)values
[4];
1010 fvals
[5] = (ALfloat
)values
[5];
1011 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1013 case AL_SEC_OFFSET_LATENCY_SOFT
:
1014 case AL_STEREO_ANGLES
:
1018 ERR("Unexpected property: 0x%04x\n", prop
);
1019 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1025 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1027 ALCdevice
*device
= Context
->Device
;
1028 ALbufferlistitem
*BufferList
;
1029 ClockLatency clocktime
;
1037 *values
= Source
->Gain
;
1041 *values
= Source
->Pitch
;
1044 case AL_MAX_DISTANCE
:
1045 *values
= Source
->MaxDistance
;
1048 case AL_ROLLOFF_FACTOR
:
1049 *values
= Source
->RollOffFactor
;
1052 case AL_REFERENCE_DISTANCE
:
1053 *values
= Source
->RefDistance
;
1056 case AL_CONE_INNER_ANGLE
:
1057 *values
= Source
->InnerAngle
;
1060 case AL_CONE_OUTER_ANGLE
:
1061 *values
= Source
->OuterAngle
;
1065 *values
= Source
->MinGain
;
1069 *values
= Source
->MaxGain
;
1072 case AL_CONE_OUTER_GAIN
:
1073 *values
= Source
->OuterGain
;
1077 case AL_SAMPLE_OFFSET
:
1078 case AL_BYTE_OFFSET
:
1079 *values
= GetSourceOffset(Source
, prop
, device
);
1082 case AL_CONE_OUTER_GAINHF
:
1083 *values
= Source
->OuterGainHF
;
1086 case AL_AIR_ABSORPTION_FACTOR
:
1087 *values
= Source
->AirAbsorptionFactor
;
1090 case AL_ROOM_ROLLOFF_FACTOR
:
1091 *values
= Source
->RoomRolloffFactor
;
1094 case AL_DOPPLER_FACTOR
:
1095 *values
= Source
->DopplerFactor
;
1098 case AL_SEC_LENGTH_SOFT
:
1099 ReadLock(&Source
->queue_lock
);
1100 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1107 ALbuffer
*buffer
= BufferList
->buffer
;
1108 if(buffer
&& buffer
->SampleLen
> 0)
1110 freq
= buffer
->Frequency
;
1111 length
+= buffer
->SampleLen
;
1113 } while((BufferList
=BufferList
->next
) != NULL
);
1114 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1116 ReadUnlock(&Source
->queue_lock
);
1119 case AL_SOURCE_RADIUS
:
1120 *values
= Source
->Radius
;
1123 case AL_STEREO_ANGLES
:
1124 values
[0] = Source
->StereoPan
[0];
1125 values
[1] = Source
->StereoPan
[1];
1128 case AL_SEC_OFFSET_LATENCY_SOFT
:
1129 /* Get the source offset with the clock time first. Then get the
1130 * clock time with the device latency. Order is important.
1132 values
[0] = GetSourceSecOffset(Source
, device
, &srcclock
);
1133 clocktime
= V0(device
->Backend
,getClockLatency
)();
1134 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1135 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1138 /* If the clock time incremented, reduce the latency by that
1139 * much since it's that much closer to the source offset it got
1142 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1143 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1149 values
[0] = Source
->Position
[0];
1150 values
[1] = Source
->Position
[1];
1151 values
[2] = Source
->Position
[2];
1155 values
[0] = Source
->Velocity
[0];
1156 values
[1] = Source
->Velocity
[1];
1157 values
[2] = Source
->Velocity
[2];
1161 values
[0] = Source
->Direction
[0];
1162 values
[1] = Source
->Direction
[1];
1163 values
[2] = Source
->Direction
[2];
1166 case AL_ORIENTATION
:
1167 values
[0] = Source
->Orientation
[0][0];
1168 values
[1] = Source
->Orientation
[0][1];
1169 values
[2] = Source
->Orientation
[0][2];
1170 values
[3] = Source
->Orientation
[1][0];
1171 values
[4] = Source
->Orientation
[1][1];
1172 values
[5] = Source
->Orientation
[1][2];
1176 case AL_SOURCE_RELATIVE
:
1178 case AL_SOURCE_STATE
:
1179 case AL_BUFFERS_QUEUED
:
1180 case AL_BUFFERS_PROCESSED
:
1181 case AL_SOURCE_TYPE
:
1182 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1183 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1184 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1185 case AL_DIRECT_CHANNELS_SOFT
:
1186 case AL_BYTE_LENGTH_SOFT
:
1187 case AL_SAMPLE_LENGTH_SOFT
:
1188 case AL_DISTANCE_MODEL
:
1189 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1190 *values
= (ALdouble
)ivals
[0];
1194 case AL_DIRECT_FILTER
:
1195 case AL_AUXILIARY_SEND_FILTER
:
1196 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1200 ERR("Unexpected property: 0x%04x\n", prop
);
1201 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1204 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1206 ALbufferlistitem
*BufferList
;
1212 case AL_SOURCE_RELATIVE
:
1213 *values
= Source
->HeadRelative
;
1217 *values
= ATOMIC_LOAD_SEQ(&Source
->looping
);
1221 ReadLock(&Source
->queue_lock
);
1222 BufferList
= (Source
->SourceType
== AL_STATIC
) ?
1223 ATOMIC_LOAD_SEQ(&Source
->queue
) :
1224 ATOMIC_LOAD_SEQ(&Source
->current_buffer
);
1225 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1226 ReadUnlock(&Source
->queue_lock
);
1229 case AL_SOURCE_STATE
:
1230 *values
= ATOMIC_LOAD_SEQ(&Source
->state
);
1233 case AL_BYTE_LENGTH_SOFT
:
1234 ReadLock(&Source
->queue_lock
);
1235 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1241 ALbuffer
*buffer
= BufferList
->buffer
;
1242 if(buffer
&& buffer
->SampleLen
> 0)
1244 ALuint byte_align
, sample_align
;
1245 if(buffer
->OriginalType
== UserFmtIMA4
)
1247 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1248 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1249 sample_align
= buffer
->OriginalAlign
;
1251 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1253 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1254 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1255 sample_align
= buffer
->OriginalAlign
;
1259 ALsizei align
= buffer
->OriginalAlign
;
1260 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1261 sample_align
= buffer
->OriginalAlign
;
1264 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1266 } while((BufferList
=BufferList
->next
) != NULL
);
1269 ReadUnlock(&Source
->queue_lock
);
1272 case AL_SAMPLE_LENGTH_SOFT
:
1273 ReadLock(&Source
->queue_lock
);
1274 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1280 ALbuffer
*buffer
= BufferList
->buffer
;
1281 if(buffer
) length
+= buffer
->SampleLen
;
1282 } while((BufferList
=BufferList
->next
) != NULL
);
1285 ReadUnlock(&Source
->queue_lock
);
1288 case AL_BUFFERS_QUEUED
:
1289 ReadLock(&Source
->queue_lock
);
1290 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1297 } while((BufferList
=BufferList
->next
) != NULL
);
1300 ReadUnlock(&Source
->queue_lock
);
1303 case AL_BUFFERS_PROCESSED
:
1304 ReadLock(&Source
->queue_lock
);
1305 if(ATOMIC_LOAD_SEQ(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1307 /* Buffers on a looping source are in a perpetual state of
1308 * PENDING, so don't report any as PROCESSED */
1313 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
1314 const ALbufferlistitem
*Current
= ATOMIC_LOAD_SEQ(&Source
->current_buffer
);
1316 while(BufferList
&& BufferList
!= Current
)
1319 BufferList
= BufferList
->next
;
1323 ReadUnlock(&Source
->queue_lock
);
1326 case AL_SOURCE_TYPE
:
1327 *values
= Source
->SourceType
;
1330 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1331 *values
= Source
->DryGainHFAuto
;
1334 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1335 *values
= Source
->WetGainAuto
;
1338 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1339 *values
= Source
->WetGainHFAuto
;
1342 case AL_DIRECT_CHANNELS_SOFT
:
1343 *values
= Source
->DirectChannels
;
1346 case AL_DISTANCE_MODEL
:
1347 *values
= Source
->DistanceModel
;
1350 /* 1x float/double */
1351 case AL_CONE_INNER_ANGLE
:
1352 case AL_CONE_OUTER_ANGLE
:
1357 case AL_REFERENCE_DISTANCE
:
1358 case AL_ROLLOFF_FACTOR
:
1359 case AL_CONE_OUTER_GAIN
:
1360 case AL_MAX_DISTANCE
:
1362 case AL_SAMPLE_OFFSET
:
1363 case AL_BYTE_OFFSET
:
1364 case AL_DOPPLER_FACTOR
:
1365 case AL_AIR_ABSORPTION_FACTOR
:
1366 case AL_ROOM_ROLLOFF_FACTOR
:
1367 case AL_CONE_OUTER_GAINHF
:
1368 case AL_SEC_LENGTH_SOFT
:
1369 case AL_SOURCE_RADIUS
:
1370 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1371 *values
= (ALint
)dvals
[0];
1374 /* 3x float/double */
1378 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1380 values
[0] = (ALint
)dvals
[0];
1381 values
[1] = (ALint
)dvals
[1];
1382 values
[2] = (ALint
)dvals
[2];
1386 /* 6x float/double */
1387 case AL_ORIENTATION
:
1388 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1390 values
[0] = (ALint
)dvals
[0];
1391 values
[1] = (ALint
)dvals
[1];
1392 values
[2] = (ALint
)dvals
[2];
1393 values
[3] = (ALint
)dvals
[3];
1394 values
[4] = (ALint
)dvals
[4];
1395 values
[5] = (ALint
)dvals
[5];
1399 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1400 break; /* i64 only */
1401 case AL_SEC_OFFSET_LATENCY_SOFT
:
1402 break; /* Double only */
1403 case AL_STEREO_ANGLES
:
1404 break; /* Float/double only */
1406 case AL_DIRECT_FILTER
:
1407 case AL_AUXILIARY_SEND_FILTER
:
1411 ERR("Unexpected property: 0x%04x\n", prop
);
1412 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1415 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1417 ALCdevice
*device
= Context
->Device
;
1418 ClockLatency clocktime
;
1426 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1427 /* Get the source offset with the clock time first. Then get the
1428 * clock time with the device latency. Order is important.
1430 values
[0] = GetSourceSampleOffset(Source
, device
, &srcclock
);
1431 clocktime
= V0(device
->Backend
,getClockLatency
)();
1432 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1433 values
[1] = clocktime
.Latency
;
1436 /* If the clock time incremented, reduce the latency by that
1437 * much since it's that much closer to the source offset it got
1440 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1441 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1445 /* 1x float/double */
1446 case AL_CONE_INNER_ANGLE
:
1447 case AL_CONE_OUTER_ANGLE
:
1452 case AL_REFERENCE_DISTANCE
:
1453 case AL_ROLLOFF_FACTOR
:
1454 case AL_CONE_OUTER_GAIN
:
1455 case AL_MAX_DISTANCE
:
1457 case AL_SAMPLE_OFFSET
:
1458 case AL_BYTE_OFFSET
:
1459 case AL_DOPPLER_FACTOR
:
1460 case AL_AIR_ABSORPTION_FACTOR
:
1461 case AL_ROOM_ROLLOFF_FACTOR
:
1462 case AL_CONE_OUTER_GAINHF
:
1463 case AL_SEC_LENGTH_SOFT
:
1464 case AL_SOURCE_RADIUS
:
1465 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1466 *values
= (ALint64
)dvals
[0];
1469 /* 3x float/double */
1473 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1475 values
[0] = (ALint64
)dvals
[0];
1476 values
[1] = (ALint64
)dvals
[1];
1477 values
[2] = (ALint64
)dvals
[2];
1481 /* 6x float/double */
1482 case AL_ORIENTATION
:
1483 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1485 values
[0] = (ALint64
)dvals
[0];
1486 values
[1] = (ALint64
)dvals
[1];
1487 values
[2] = (ALint64
)dvals
[2];
1488 values
[3] = (ALint64
)dvals
[3];
1489 values
[4] = (ALint64
)dvals
[4];
1490 values
[5] = (ALint64
)dvals
[5];
1495 case AL_SOURCE_RELATIVE
:
1497 case AL_SOURCE_STATE
:
1498 case AL_BUFFERS_QUEUED
:
1499 case AL_BUFFERS_PROCESSED
:
1500 case AL_BYTE_LENGTH_SOFT
:
1501 case AL_SAMPLE_LENGTH_SOFT
:
1502 case AL_SOURCE_TYPE
:
1503 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1504 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1505 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1506 case AL_DIRECT_CHANNELS_SOFT
:
1507 case AL_DISTANCE_MODEL
:
1508 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1514 case AL_DIRECT_FILTER
:
1515 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1516 *values
= (ALuint
)ivals
[0];
1520 case AL_AUXILIARY_SEND_FILTER
:
1521 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1523 values
[0] = (ALuint
)ivals
[0];
1524 values
[1] = (ALuint
)ivals
[1];
1525 values
[2] = (ALuint
)ivals
[2];
1529 case AL_SEC_OFFSET_LATENCY_SOFT
:
1530 break; /* Double only */
1531 case AL_STEREO_ANGLES
:
1532 break; /* Float/double only */
1535 ERR("Unexpected property: 0x%04x\n", prop
);
1536 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1540 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1543 ALCcontext
*context
;
1547 context
= GetContextRef();
1548 if(!context
) return;
1551 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1552 device
= context
->Device
;
1553 for(cur
= 0;cur
< n
;cur
++)
1555 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1558 alDeleteSources(cur
, sources
);
1559 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1561 InitSourceParams(source
, device
->NumAuxSends
);
1563 err
= NewThunkEntry(&source
->id
);
1564 if(err
== AL_NO_ERROR
)
1565 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1566 if(err
!= AL_NO_ERROR
)
1568 FreeThunkEntry(source
->id
);
1569 memset(source
, 0, sizeof(ALsource
));
1572 alDeleteSources(cur
, sources
);
1573 SET_ERROR_AND_GOTO(context
, err
, done
);
1576 sources
[cur
] = source
->id
;
1580 ALCcontext_DecRef(context
);
1584 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1587 ALCcontext
*context
;
1591 context
= GetContextRef();
1592 if(!context
) return;
1594 LockSourcesWrite(context
);
1596 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1598 /* Check that all Sources are valid */
1599 for(i
= 0;i
< n
;i
++)
1601 if(LookupSource(context
, sources
[i
]) == NULL
)
1602 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1604 device
= context
->Device
;
1605 for(i
= 0;i
< n
;i
++)
1609 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1611 FreeThunkEntry(Source
->id
);
1613 ALCdevice_Lock(device
);
1614 voice
= GetSourceVoice(Source
, context
);
1615 if(voice
) voice
->Source
= NULL
;
1616 ALCdevice_Unlock(device
);
1618 DeinitSource(Source
, device
->NumAuxSends
);
1620 memset(Source
, 0, sizeof(*Source
));
1625 UnlockSourcesWrite(context
);
1626 ALCcontext_DecRef(context
);
1630 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1632 ALCcontext
*context
;
1635 context
= GetContextRef();
1636 if(!context
) return AL_FALSE
;
1638 LockSourcesRead(context
);
1639 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1640 UnlockSourcesRead(context
);
1642 ALCcontext_DecRef(context
);
1648 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1650 ALCcontext
*Context
;
1653 Context
= GetContextRef();
1654 if(!Context
) return;
1656 WriteLock(&Context
->PropLock
);
1657 LockSourcesRead(Context
);
1658 if((Source
=LookupSource(Context
, source
)) == NULL
)
1659 alSetError(Context
, AL_INVALID_NAME
);
1660 else if(!(FloatValsByProp(param
) == 1))
1661 alSetError(Context
, AL_INVALID_ENUM
);
1663 SetSourcefv(Source
, Context
, param
, &value
);
1664 UnlockSourcesRead(Context
);
1665 WriteUnlock(&Context
->PropLock
);
1667 ALCcontext_DecRef(Context
);
1670 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1672 ALCcontext
*Context
;
1675 Context
= GetContextRef();
1676 if(!Context
) return;
1678 WriteLock(&Context
->PropLock
);
1679 LockSourcesRead(Context
);
1680 if((Source
=LookupSource(Context
, source
)) == NULL
)
1681 alSetError(Context
, AL_INVALID_NAME
);
1682 else if(!(FloatValsByProp(param
) == 3))
1683 alSetError(Context
, AL_INVALID_ENUM
);
1686 ALfloat fvals
[3] = { value1
, value2
, value3
};
1687 SetSourcefv(Source
, Context
, param
, fvals
);
1689 UnlockSourcesRead(Context
);
1690 WriteUnlock(&Context
->PropLock
);
1692 ALCcontext_DecRef(Context
);
1695 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1697 ALCcontext
*Context
;
1700 Context
= GetContextRef();
1701 if(!Context
) return;
1703 WriteLock(&Context
->PropLock
);
1704 LockSourcesRead(Context
);
1705 if((Source
=LookupSource(Context
, source
)) == NULL
)
1706 alSetError(Context
, AL_INVALID_NAME
);
1708 alSetError(Context
, AL_INVALID_VALUE
);
1709 else if(!(FloatValsByProp(param
) > 0))
1710 alSetError(Context
, AL_INVALID_ENUM
);
1712 SetSourcefv(Source
, Context
, param
, values
);
1713 UnlockSourcesRead(Context
);
1714 WriteUnlock(&Context
->PropLock
);
1716 ALCcontext_DecRef(Context
);
1720 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
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(!(DoubleValsByProp(param
) == 1))
1733 alSetError(Context
, AL_INVALID_ENUM
);
1736 ALfloat fval
= (ALfloat
)value
;
1737 SetSourcefv(Source
, Context
, param
, &fval
);
1739 UnlockSourcesRead(Context
);
1740 WriteUnlock(&Context
->PropLock
);
1742 ALCcontext_DecRef(Context
);
1745 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
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
);
1757 else if(!(DoubleValsByProp(param
) == 3))
1758 alSetError(Context
, AL_INVALID_ENUM
);
1761 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1762 SetSourcefv(Source
, Context
, param
, fvals
);
1764 UnlockSourcesRead(Context
);
1765 WriteUnlock(&Context
->PropLock
);
1767 ALCcontext_DecRef(Context
);
1770 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1772 ALCcontext
*Context
;
1776 Context
= GetContextRef();
1777 if(!Context
) return;
1779 WriteLock(&Context
->PropLock
);
1780 LockSourcesRead(Context
);
1781 if((Source
=LookupSource(Context
, source
)) == NULL
)
1782 alSetError(Context
, AL_INVALID_NAME
);
1784 alSetError(Context
, AL_INVALID_VALUE
);
1785 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1786 alSetError(Context
, AL_INVALID_ENUM
);
1792 for(i
= 0;i
< count
;i
++)
1793 fvals
[i
] = (ALfloat
)values
[i
];
1794 SetSourcefv(Source
, Context
, param
, fvals
);
1796 UnlockSourcesRead(Context
);
1797 WriteUnlock(&Context
->PropLock
);
1799 ALCcontext_DecRef(Context
);
1803 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1805 ALCcontext
*Context
;
1808 Context
= GetContextRef();
1809 if(!Context
) return;
1811 WriteLock(&Context
->PropLock
);
1812 LockSourcesRead(Context
);
1813 if((Source
=LookupSource(Context
, source
)) == NULL
)
1814 alSetError(Context
, AL_INVALID_NAME
);
1815 else if(!(IntValsByProp(param
) == 1))
1816 alSetError(Context
, AL_INVALID_ENUM
);
1818 SetSourceiv(Source
, Context
, param
, &value
);
1819 UnlockSourcesRead(Context
);
1820 WriteUnlock(&Context
->PropLock
);
1822 ALCcontext_DecRef(Context
);
1825 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1827 ALCcontext
*Context
;
1830 Context
= GetContextRef();
1831 if(!Context
) return;
1833 WriteLock(&Context
->PropLock
);
1834 LockSourcesRead(Context
);
1835 if((Source
=LookupSource(Context
, source
)) == NULL
)
1836 alSetError(Context
, AL_INVALID_NAME
);
1837 else if(!(IntValsByProp(param
) == 3))
1838 alSetError(Context
, AL_INVALID_ENUM
);
1841 ALint ivals
[3] = { value1
, value2
, value3
};
1842 SetSourceiv(Source
, Context
, param
, ivals
);
1844 UnlockSourcesRead(Context
);
1845 WriteUnlock(&Context
->PropLock
);
1847 ALCcontext_DecRef(Context
);
1850 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1852 ALCcontext
*Context
;
1855 Context
= GetContextRef();
1856 if(!Context
) return;
1858 WriteLock(&Context
->PropLock
);
1859 LockSourcesRead(Context
);
1860 if((Source
=LookupSource(Context
, source
)) == NULL
)
1861 alSetError(Context
, AL_INVALID_NAME
);
1863 alSetError(Context
, AL_INVALID_VALUE
);
1864 else if(!(IntValsByProp(param
) > 0))
1865 alSetError(Context
, AL_INVALID_ENUM
);
1867 SetSourceiv(Source
, Context
, param
, values
);
1868 UnlockSourcesRead(Context
);
1869 WriteUnlock(&Context
->PropLock
);
1871 ALCcontext_DecRef(Context
);
1875 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
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(!(Int64ValsByProp(param
) == 1))
1888 alSetError(Context
, AL_INVALID_ENUM
);
1890 SetSourcei64v(Source
, Context
, param
, &value
);
1891 UnlockSourcesRead(Context
);
1892 WriteUnlock(&Context
->PropLock
);
1894 ALCcontext_DecRef(Context
);
1897 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1899 ALCcontext
*Context
;
1902 Context
= GetContextRef();
1903 if(!Context
) return;
1905 WriteLock(&Context
->PropLock
);
1906 LockSourcesRead(Context
);
1907 if((Source
=LookupSource(Context
, source
)) == NULL
)
1908 alSetError(Context
, AL_INVALID_NAME
);
1909 else if(!(Int64ValsByProp(param
) == 3))
1910 alSetError(Context
, AL_INVALID_ENUM
);
1913 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1914 SetSourcei64v(Source
, Context
, param
, i64vals
);
1916 UnlockSourcesRead(Context
);
1917 WriteUnlock(&Context
->PropLock
);
1919 ALCcontext_DecRef(Context
);
1922 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1924 ALCcontext
*Context
;
1927 Context
= GetContextRef();
1928 if(!Context
) return;
1930 WriteLock(&Context
->PropLock
);
1931 LockSourcesRead(Context
);
1932 if((Source
=LookupSource(Context
, source
)) == NULL
)
1933 alSetError(Context
, AL_INVALID_NAME
);
1935 alSetError(Context
, AL_INVALID_VALUE
);
1936 else if(!(Int64ValsByProp(param
) > 0))
1937 alSetError(Context
, AL_INVALID_ENUM
);
1939 SetSourcei64v(Source
, Context
, param
, values
);
1940 UnlockSourcesRead(Context
);
1941 WriteUnlock(&Context
->PropLock
);
1943 ALCcontext_DecRef(Context
);
1947 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1949 ALCcontext
*Context
;
1952 Context
= GetContextRef();
1953 if(!Context
) return;
1955 ReadLock(&Context
->PropLock
);
1956 LockSourcesRead(Context
);
1957 if((Source
=LookupSource(Context
, source
)) == NULL
)
1958 alSetError(Context
, AL_INVALID_NAME
);
1960 alSetError(Context
, AL_INVALID_VALUE
);
1961 else if(!(FloatValsByProp(param
) == 1))
1962 alSetError(Context
, AL_INVALID_ENUM
);
1966 if(GetSourcedv(Source
, Context
, param
, &dval
))
1967 *value
= (ALfloat
)dval
;
1969 UnlockSourcesRead(Context
);
1970 ReadUnlock(&Context
->PropLock
);
1972 ALCcontext_DecRef(Context
);
1976 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1978 ALCcontext
*Context
;
1981 Context
= GetContextRef();
1982 if(!Context
) return;
1984 ReadLock(&Context
->PropLock
);
1985 LockSourcesRead(Context
);
1986 if((Source
=LookupSource(Context
, source
)) == NULL
)
1987 alSetError(Context
, AL_INVALID_NAME
);
1988 else if(!(value1
&& value2
&& value3
))
1989 alSetError(Context
, AL_INVALID_VALUE
);
1990 else if(!(FloatValsByProp(param
) == 3))
1991 alSetError(Context
, AL_INVALID_ENUM
);
1995 if(GetSourcedv(Source
, Context
, param
, dvals
))
1997 *value1
= (ALfloat
)dvals
[0];
1998 *value2
= (ALfloat
)dvals
[1];
1999 *value3
= (ALfloat
)dvals
[2];
2002 UnlockSourcesRead(Context
);
2003 ReadUnlock(&Context
->PropLock
);
2005 ALCcontext_DecRef(Context
);
2009 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2011 ALCcontext
*Context
;
2015 Context
= GetContextRef();
2016 if(!Context
) return;
2018 ReadLock(&Context
->PropLock
);
2019 LockSourcesRead(Context
);
2020 if((Source
=LookupSource(Context
, source
)) == NULL
)
2021 alSetError(Context
, AL_INVALID_NAME
);
2023 alSetError(Context
, AL_INVALID_VALUE
);
2024 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2025 alSetError(Context
, AL_INVALID_ENUM
);
2029 if(GetSourcedv(Source
, Context
, param
, dvals
))
2032 for(i
= 0;i
< count
;i
++)
2033 values
[i
] = (ALfloat
)dvals
[i
];
2036 UnlockSourcesRead(Context
);
2037 ReadUnlock(&Context
->PropLock
);
2039 ALCcontext_DecRef(Context
);
2043 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2045 ALCcontext
*Context
;
2048 Context
= GetContextRef();
2049 if(!Context
) return;
2051 ReadLock(&Context
->PropLock
);
2052 LockSourcesRead(Context
);
2053 if((Source
=LookupSource(Context
, source
)) == NULL
)
2054 alSetError(Context
, AL_INVALID_NAME
);
2056 alSetError(Context
, AL_INVALID_VALUE
);
2057 else if(!(DoubleValsByProp(param
) == 1))
2058 alSetError(Context
, AL_INVALID_ENUM
);
2060 GetSourcedv(Source
, Context
, param
, value
);
2061 UnlockSourcesRead(Context
);
2062 ReadUnlock(&Context
->PropLock
);
2064 ALCcontext_DecRef(Context
);
2067 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2069 ALCcontext
*Context
;
2072 Context
= GetContextRef();
2073 if(!Context
) return;
2075 ReadLock(&Context
->PropLock
);
2076 LockSourcesRead(Context
);
2077 if((Source
=LookupSource(Context
, source
)) == NULL
)
2078 alSetError(Context
, AL_INVALID_NAME
);
2079 else if(!(value1
&& value2
&& value3
))
2080 alSetError(Context
, AL_INVALID_VALUE
);
2081 else if(!(DoubleValsByProp(param
) == 3))
2082 alSetError(Context
, AL_INVALID_ENUM
);
2086 if(GetSourcedv(Source
, Context
, param
, dvals
))
2093 UnlockSourcesRead(Context
);
2094 ReadUnlock(&Context
->PropLock
);
2096 ALCcontext_DecRef(Context
);
2099 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2101 ALCcontext
*Context
;
2104 Context
= GetContextRef();
2105 if(!Context
) return;
2107 ReadLock(&Context
->PropLock
);
2108 LockSourcesRead(Context
);
2109 if((Source
=LookupSource(Context
, source
)) == NULL
)
2110 alSetError(Context
, AL_INVALID_NAME
);
2112 alSetError(Context
, AL_INVALID_VALUE
);
2113 else if(!(DoubleValsByProp(param
) > 0))
2114 alSetError(Context
, AL_INVALID_ENUM
);
2116 GetSourcedv(Source
, Context
, param
, values
);
2117 UnlockSourcesRead(Context
);
2118 ReadUnlock(&Context
->PropLock
);
2120 ALCcontext_DecRef(Context
);
2124 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2126 ALCcontext
*Context
;
2129 Context
= GetContextRef();
2130 if(!Context
) return;
2132 ReadLock(&Context
->PropLock
);
2133 LockSourcesRead(Context
);
2134 if((Source
=LookupSource(Context
, source
)) == NULL
)
2135 alSetError(Context
, AL_INVALID_NAME
);
2137 alSetError(Context
, AL_INVALID_VALUE
);
2138 else if(!(IntValsByProp(param
) == 1))
2139 alSetError(Context
, AL_INVALID_ENUM
);
2141 GetSourceiv(Source
, Context
, param
, value
);
2142 UnlockSourcesRead(Context
);
2143 ReadUnlock(&Context
->PropLock
);
2145 ALCcontext_DecRef(Context
);
2149 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
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
);
2161 else if(!(value1
&& value2
&& value3
))
2162 alSetError(Context
, AL_INVALID_VALUE
);
2163 else if(!(IntValsByProp(param
) == 3))
2164 alSetError(Context
, AL_INVALID_ENUM
);
2168 if(GetSourceiv(Source
, Context
, param
, ivals
))
2175 UnlockSourcesRead(Context
);
2176 ReadUnlock(&Context
->PropLock
);
2178 ALCcontext_DecRef(Context
);
2182 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2184 ALCcontext
*Context
;
2187 Context
= GetContextRef();
2188 if(!Context
) return;
2190 ReadLock(&Context
->PropLock
);
2191 LockSourcesRead(Context
);
2192 if((Source
=LookupSource(Context
, source
)) == NULL
)
2193 alSetError(Context
, AL_INVALID_NAME
);
2195 alSetError(Context
, AL_INVALID_VALUE
);
2196 else if(!(IntValsByProp(param
) > 0))
2197 alSetError(Context
, AL_INVALID_ENUM
);
2199 GetSourceiv(Source
, Context
, param
, values
);
2200 UnlockSourcesRead(Context
);
2201 ReadUnlock(&Context
->PropLock
);
2203 ALCcontext_DecRef(Context
);
2207 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2209 ALCcontext
*Context
;
2212 Context
= GetContextRef();
2213 if(!Context
) return;
2215 ReadLock(&Context
->PropLock
);
2216 LockSourcesRead(Context
);
2217 if((Source
=LookupSource(Context
, source
)) == NULL
)
2218 alSetError(Context
, AL_INVALID_NAME
);
2220 alSetError(Context
, AL_INVALID_VALUE
);
2221 else if(!(Int64ValsByProp(param
) == 1))
2222 alSetError(Context
, AL_INVALID_ENUM
);
2224 GetSourcei64v(Source
, Context
, param
, value
);
2225 UnlockSourcesRead(Context
);
2226 ReadUnlock(&Context
->PropLock
);
2228 ALCcontext_DecRef(Context
);
2231 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2233 ALCcontext
*Context
;
2236 Context
= GetContextRef();
2237 if(!Context
) return;
2239 ReadLock(&Context
->PropLock
);
2240 LockSourcesRead(Context
);
2241 if((Source
=LookupSource(Context
, source
)) == NULL
)
2242 alSetError(Context
, AL_INVALID_NAME
);
2243 else if(!(value1
&& value2
&& value3
))
2244 alSetError(Context
, AL_INVALID_VALUE
);
2245 else if(!(Int64ValsByProp(param
) == 3))
2246 alSetError(Context
, AL_INVALID_ENUM
);
2250 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2252 *value1
= i64vals
[0];
2253 *value2
= i64vals
[1];
2254 *value3
= i64vals
[2];
2257 UnlockSourcesRead(Context
);
2258 ReadUnlock(&Context
->PropLock
);
2260 ALCcontext_DecRef(Context
);
2263 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2265 ALCcontext
*Context
;
2268 Context
= GetContextRef();
2269 if(!Context
) return;
2271 ReadLock(&Context
->PropLock
);
2272 LockSourcesRead(Context
);
2273 if((Source
=LookupSource(Context
, source
)) == NULL
)
2274 alSetError(Context
, AL_INVALID_NAME
);
2276 alSetError(Context
, AL_INVALID_VALUE
);
2277 else if(!(Int64ValsByProp(param
) > 0))
2278 alSetError(Context
, AL_INVALID_ENUM
);
2280 GetSourcei64v(Source
, Context
, param
, values
);
2281 UnlockSourcesRead(Context
);
2282 ReadUnlock(&Context
->PropLock
);
2284 ALCcontext_DecRef(Context
);
2288 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2290 alSourcePlayv(1, &source
);
2292 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2294 ALCcontext
*context
;
2298 context
= GetContextRef();
2299 if(!context
) return;
2301 LockSourcesRead(context
);
2303 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2304 for(i
= 0;i
< n
;i
++)
2306 if(!LookupSource(context
, sources
[i
]))
2307 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2310 ALCdevice_Lock(context
->Device
);
2311 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2313 ALsizei newcount
= context
->MaxVoices
<< 1;
2314 if(context
->MaxVoices
>= newcount
)
2316 ALCdevice_Unlock(context
->Device
);
2317 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2319 AllocateVoices(context
, newcount
, context
->Device
->NumAuxSends
);
2322 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) == DeferAll
)
2324 for(i
= 0;i
< n
;i
++)
2326 source
= LookupSource(context
, sources
[i
]);
2327 source
->new_state
= AL_PLAYING
;
2332 for(i
= 0;i
< n
;i
++)
2334 source
= LookupSource(context
, sources
[i
]);
2335 SetSourceState(source
, context
, AL_PLAYING
);
2338 ALCdevice_Unlock(context
->Device
);
2341 UnlockSourcesRead(context
);
2342 ALCcontext_DecRef(context
);
2345 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2347 alSourcePausev(1, &source
);
2349 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2351 ALCcontext
*context
;
2355 context
= GetContextRef();
2356 if(!context
) return;
2358 LockSourcesRead(context
);
2360 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2361 for(i
= 0;i
< n
;i
++)
2363 if(!LookupSource(context
, sources
[i
]))
2364 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2367 ALCdevice_Lock(context
->Device
);
2368 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2370 for(i
= 0;i
< n
;i
++)
2372 source
= LookupSource(context
, sources
[i
]);
2373 source
->new_state
= AL_PAUSED
;
2378 for(i
= 0;i
< n
;i
++)
2380 source
= LookupSource(context
, sources
[i
]);
2381 SetSourceState(source
, context
, AL_PAUSED
);
2384 ALCdevice_Unlock(context
->Device
);
2387 UnlockSourcesRead(context
);
2388 ALCcontext_DecRef(context
);
2391 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2393 alSourceStopv(1, &source
);
2395 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2397 ALCcontext
*context
;
2401 context
= GetContextRef();
2402 if(!context
) return;
2404 LockSourcesRead(context
);
2406 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2407 for(i
= 0;i
< n
;i
++)
2409 if(!LookupSource(context
, sources
[i
]))
2410 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2413 ALCdevice_Lock(context
->Device
);
2414 for(i
= 0;i
< n
;i
++)
2416 source
= LookupSource(context
, sources
[i
]);
2417 source
->new_state
= AL_NONE
;
2418 SetSourceState(source
, context
, AL_STOPPED
);
2420 ALCdevice_Unlock(context
->Device
);
2423 UnlockSourcesRead(context
);
2424 ALCcontext_DecRef(context
);
2427 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2429 alSourceRewindv(1, &source
);
2431 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2433 ALCcontext
*context
;
2437 context
= GetContextRef();
2438 if(!context
) return;
2440 LockSourcesRead(context
);
2442 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2443 for(i
= 0;i
< n
;i
++)
2445 if(!LookupSource(context
, sources
[i
]))
2446 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2449 ALCdevice_Lock(context
->Device
);
2450 for(i
= 0;i
< n
;i
++)
2452 source
= LookupSource(context
, sources
[i
]);
2453 source
->new_state
= AL_NONE
;
2454 SetSourceState(source
, context
, AL_INITIAL
);
2456 ALCdevice_Unlock(context
->Device
);
2459 UnlockSourcesRead(context
);
2460 ALCcontext_DecRef(context
);
2464 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2467 ALCcontext
*context
;
2470 ALbufferlistitem
*BufferListStart
;
2471 ALbufferlistitem
*BufferList
;
2472 ALbuffer
*BufferFmt
= NULL
;
2477 context
= GetContextRef();
2478 if(!context
) return;
2480 device
= context
->Device
;
2482 LockSourcesRead(context
);
2484 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2485 if((source
=LookupSource(context
, src
)) == NULL
)
2486 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2488 WriteLock(&source
->queue_lock
);
2489 if(source
->SourceType
== AL_STATIC
)
2491 WriteUnlock(&source
->queue_lock
);
2492 /* Can't queue on a Static Source */
2493 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2496 /* Check for a valid Buffer, for its frequency and format */
2497 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2500 if(BufferList
->buffer
)
2502 BufferFmt
= BufferList
->buffer
;
2505 BufferList
= BufferList
->next
;
2508 LockBuffersRead(device
);
2509 BufferListStart
= NULL
;
2511 for(i
= 0;i
< nb
;i
++)
2513 ALbuffer
*buffer
= NULL
;
2514 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2516 WriteUnlock(&source
->queue_lock
);
2517 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2520 if(!BufferListStart
)
2522 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2523 BufferList
= BufferListStart
;
2527 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2528 BufferList
= BufferList
->next
;
2530 BufferList
->buffer
= buffer
;
2531 BufferList
->next
= NULL
;
2532 if(!buffer
) continue;
2534 /* Hold a read lock on each buffer being queued while checking all
2535 * provided buffers. This is done so other threads don't see an extra
2536 * reference on some buffers if this operation ends up failing. */
2537 ReadLock(&buffer
->lock
);
2538 IncrementRef(&buffer
->ref
);
2540 if(BufferFmt
== NULL
)
2544 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2545 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2547 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2548 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2549 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2551 WriteUnlock(&source
->queue_lock
);
2552 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2555 /* A buffer failed (invalid ID or format), so unlock and release
2556 * each buffer we had. */
2557 while(BufferListStart
)
2559 ALbufferlistitem
*next
= BufferListStart
->next
;
2560 if((buffer
=BufferListStart
->buffer
) != NULL
)
2562 DecrementRef(&buffer
->ref
);
2563 ReadUnlock(&buffer
->lock
);
2565 free(BufferListStart
);
2566 BufferListStart
= next
;
2568 UnlockBuffersRead(device
);
2572 /* All buffers good, unlock them now. */
2573 BufferList
= BufferListStart
;
2574 while(BufferList
!= NULL
)
2576 ALbuffer
*buffer
= BufferList
->buffer
;
2577 if(buffer
) ReadUnlock(&buffer
->lock
);
2578 BufferList
= BufferList
->next
;
2580 UnlockBuffersRead(device
);
2582 /* Source is now streaming */
2583 source
->SourceType
= AL_STREAMING
;
2586 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->queue
,
2587 &BufferList
, BufferListStart
))
2589 /* Queue head is not NULL, append to the end of the queue */
2590 while(BufferList
->next
!= NULL
)
2591 BufferList
= BufferList
->next
;
2592 BufferList
->next
= BufferListStart
;
2594 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2598 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->current_buffer
,
2599 &BufferList
, BufferListStart
);
2600 WriteUnlock(&source
->queue_lock
);
2603 UnlockSourcesRead(context
);
2604 ALCcontext_DecRef(context
);
2607 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2609 ALCcontext
*context
;
2611 ALbufferlistitem
*OldHead
;
2612 ALbufferlistitem
*OldTail
;
2613 ALbufferlistitem
*Current
;
2619 context
= GetContextRef();
2620 if(!context
) return;
2622 LockSourcesRead(context
);
2624 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2626 if((source
=LookupSource(context
, src
)) == NULL
)
2627 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2629 WriteLock(&source
->queue_lock
);
2630 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2632 WriteUnlock(&source
->queue_lock
);
2633 /* Trying to unqueue buffers on a looping or non-streaming source. */
2634 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2637 /* Find the new buffer queue head */
2638 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2639 Current
= ATOMIC_LOAD_SEQ(&source
->current_buffer
);
2640 if(OldTail
!= Current
)
2642 for(i
= 1;i
< nb
;i
++)
2644 ALbufferlistitem
*next
= OldTail
->next
;
2645 if(!next
|| next
== Current
) break;
2651 WriteUnlock(&source
->queue_lock
);
2652 /* Trying to unqueue pending buffers. */
2653 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2656 /* Swap it, and cut the new head from the old. */
2657 OldHead
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2660 ALCdevice
*device
= context
->Device
;
2663 /* Once the active mix (if any) is done, it's safe to cut the old tail
2664 * from the new head.
2666 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2668 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2671 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2672 OldTail
->next
= NULL
;
2674 WriteUnlock(&source
->queue_lock
);
2676 while(OldHead
!= NULL
)
2678 ALbufferlistitem
*next
= OldHead
->next
;
2679 ALbuffer
*buffer
= OldHead
->buffer
;
2685 *(buffers
++) = buffer
->id
;
2686 DecrementRef(&buffer
->ref
);
2694 UnlockSourcesRead(context
);
2695 ALCcontext_DecRef(context
);
2699 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2703 RWLockInit(&Source
->queue_lock
);
2705 Source
->InnerAngle
= 360.0f
;
2706 Source
->OuterAngle
= 360.0f
;
2707 Source
->Pitch
= 1.0f
;
2708 Source
->Position
[0] = 0.0f
;
2709 Source
->Position
[1] = 0.0f
;
2710 Source
->Position
[2] = 0.0f
;
2711 Source
->Velocity
[0] = 0.0f
;
2712 Source
->Velocity
[1] = 0.0f
;
2713 Source
->Velocity
[2] = 0.0f
;
2714 Source
->Direction
[0] = 0.0f
;
2715 Source
->Direction
[1] = 0.0f
;
2716 Source
->Direction
[2] = 0.0f
;
2717 Source
->Orientation
[0][0] = 0.0f
;
2718 Source
->Orientation
[0][1] = 0.0f
;
2719 Source
->Orientation
[0][2] = -1.0f
;
2720 Source
->Orientation
[1][0] = 0.0f
;
2721 Source
->Orientation
[1][1] = 1.0f
;
2722 Source
->Orientation
[1][2] = 0.0f
;
2723 Source
->RefDistance
= 1.0f
;
2724 Source
->MaxDistance
= FLT_MAX
;
2725 Source
->RollOffFactor
= 1.0f
;
2726 Source
->Gain
= 1.0f
;
2727 Source
->MinGain
= 0.0f
;
2728 Source
->MaxGain
= 1.0f
;
2729 Source
->OuterGain
= 0.0f
;
2730 Source
->OuterGainHF
= 1.0f
;
2732 Source
->DryGainHFAuto
= AL_TRUE
;
2733 Source
->WetGainAuto
= AL_TRUE
;
2734 Source
->WetGainHFAuto
= AL_TRUE
;
2735 Source
->AirAbsorptionFactor
= 0.0f
;
2736 Source
->RoomRolloffFactor
= 0.0f
;
2737 Source
->DopplerFactor
= 1.0f
;
2738 Source
->DirectChannels
= AL_FALSE
;
2740 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2741 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2743 Source
->Radius
= 0.0f
;
2745 Source
->DistanceModel
= DefaultDistanceModel
;
2747 Source
->Direct
.Gain
= 1.0f
;
2748 Source
->Direct
.GainHF
= 1.0f
;
2749 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2750 Source
->Direct
.GainLF
= 1.0f
;
2751 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2752 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2753 for(i
= 0;i
< num_sends
;i
++)
2755 Source
->Send
[i
].Slot
= NULL
;
2756 Source
->Send
[i
].Gain
= 1.0f
;
2757 Source
->Send
[i
].GainHF
= 1.0f
;
2758 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2759 Source
->Send
[i
].GainLF
= 1.0f
;
2760 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2763 Source
->Offset
= 0.0;
2764 Source
->OffsetType
= AL_NONE
;
2765 Source
->SourceType
= AL_UNDETERMINED
;
2766 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2767 Source
->new_state
= AL_NONE
;
2769 ATOMIC_INIT(&Source
->queue
, NULL
);
2770 ATOMIC_INIT(&Source
->current_buffer
, NULL
);
2772 ATOMIC_INIT(&Source
->position
, 0);
2773 ATOMIC_INIT(&Source
->position_fraction
, 0);
2775 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2777 Source
->NeedsUpdate
= AL_TRUE
;
2779 ATOMIC_INIT(&Source
->Update
, NULL
);
2780 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2783 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2785 ALbufferlistitem
*BufferList
;
2786 struct ALsourceProps
*props
;
2790 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2791 if(props
) al_free(props
);
2793 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2796 struct ALsourceProps
*next
;
2797 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2802 /* This is excessively spammy if it traces every source destruction, so
2803 * just warn if it was unexpectedly large.
2806 WARN("Freed "SZFMT
" Source property objects\n", count
);
2808 BufferList
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, NULL
);
2809 while(BufferList
!= NULL
)
2811 ALbufferlistitem
*next
= BufferList
->next
;
2812 if(BufferList
->buffer
!= NULL
)
2813 DecrementRef(&BufferList
->buffer
->ref
);
2820 for(i
= 0;i
< num_sends
;i
++)
2822 if(source
->Send
[i
].Slot
)
2823 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2824 source
->Send
[i
].Slot
= NULL
;
2826 al_free(source
->Send
);
2827 source
->Send
= NULL
;
2831 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
)
2833 struct ALsourceProps
*props
;
2836 /* Get an unused property container, or allocate a new one as needed. */
2837 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2839 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
2842 struct ALsourceProps
*next
;
2844 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2845 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2846 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
2847 almemory_order_acquire
) == 0);
2850 /* Copy in current property values. */
2851 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2852 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2853 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2854 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2855 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2856 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2857 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2858 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2859 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2860 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2861 for(i
= 0;i
< 3;i
++)
2862 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2863 for(i
= 0;i
< 3;i
++)
2864 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2865 for(i
= 0;i
< 3;i
++)
2866 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2867 for(i
= 0;i
< 2;i
++)
2870 for(j
= 0;j
< 3;j
++)
2871 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2872 almemory_order_relaxed
);
2874 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2875 ATOMIC_STORE(&props
->DistanceModel
, source
->DistanceModel
, almemory_order_relaxed
);
2876 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2878 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2879 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2880 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2881 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2883 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2884 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2885 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2887 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2888 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2890 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2892 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2893 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2894 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2895 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2896 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2898 for(i
= 0;i
< num_sends
;i
++)
2900 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2901 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2902 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2903 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2904 almemory_order_relaxed
);
2905 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2906 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2907 almemory_order_relaxed
);
2910 /* Set the new container for updating internal parameters. */
2911 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2914 /* If there was an unused update container, put it back in the
2917 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
2921 void UpdateAllSourceProps(ALCcontext
*context
)
2923 ALsizei num_sends
= context
->Device
->NumAuxSends
;
2926 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
2928 ALvoice
*voice
= context
->Voices
[pos
];
2929 ALsource
*source
= voice
->Source
;
2930 if(source
!= NULL
&& source
->NeedsUpdate
&& IsPlayingOrPaused(source
))
2932 source
->NeedsUpdate
= AL_FALSE
;
2933 UpdateSourceProps(source
, num_sends
);
2941 * Sets the source's new play state given its current state.
2943 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2945 WriteLock(&Source
->queue_lock
);
2946 if(state
== AL_PLAYING
)
2948 ALCdevice
*device
= Context
->Device
;
2949 ALbufferlistitem
*BufferList
;
2950 ALboolean discontinuity
;
2951 ALvoice
*voice
= NULL
;
2954 /* Check that there is a queue containing at least one valid, non zero
2956 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
2960 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2962 BufferList
= BufferList
->next
;
2965 if(ATOMIC_EXCHANGE(ALenum
, &Source
->state
, AL_PLAYING
, almemory_order_acq_rel
) == AL_PAUSED
)
2966 discontinuity
= AL_FALSE
;
2969 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
2970 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
2971 ATOMIC_STORE(&Source
->position_fraction
, 0, almemory_order_release
);
2972 discontinuity
= AL_TRUE
;
2975 // Check if an Offset has been set
2976 if(Source
->OffsetType
!= AL_NONE
)
2978 ApplyOffset(Source
);
2979 /* discontinuity = AL_TRUE;??? */
2982 /* If there's nothing to play, or device is disconnected, go right to
2984 if(!BufferList
|| !device
->Connected
)
2987 /* Make sure this source isn't already active, and if not, look for an
2988 * unused voice to put it in.
2990 voice
= GetSourceVoice(Source
, Context
);
2993 for(i
= 0;i
< Context
->VoiceCount
;i
++)
2995 if(Context
->Voices
[i
]->Source
== NULL
)
2997 voice
= Context
->Voices
[i
];
2998 voice
->Source
= Source
;
3004 voice
= Context
->Voices
[Context
->VoiceCount
++];
3005 voice
->Source
= Source
;
3007 discontinuity
= AL_TRUE
;
3012 /* Clear previous samples if playback is discontinuous. */
3013 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
3015 /* Clear the stepping value so the mixer knows not to mix this
3016 * until the update gets applied.
3021 voice
->Moving
= AL_FALSE
;
3022 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
3025 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
3026 voice
->Direct
.Params
[i
].Hrtf
.State
.History
[j
] = 0.0f
;
3027 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3029 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][0] = 0.0f
;
3030 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][1] = 0.0f
;
3034 Source
->NeedsUpdate
= AL_FALSE
;
3035 UpdateSourceProps(Source
, device
->NumAuxSends
);
3037 else if(state
== AL_PAUSED
)
3039 ALenum playing
= AL_PLAYING
;
3040 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum
, &Source
->state
, &playing
, AL_PAUSED
);
3042 else if(state
== AL_STOPPED
)
3045 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3047 ATOMIC_STORE(&Source
->state
, AL_STOPPED
, almemory_order_relaxed
);
3048 ATOMIC_STORE_SEQ(&Source
->current_buffer
, NULL
);
3050 Source
->OffsetType
= AL_NONE
;
3051 Source
->Offset
= 0.0;
3053 else if(state
== AL_INITIAL
)
3055 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3057 ATOMIC_STORE(&Source
->state
, AL_INITIAL
, almemory_order_relaxed
);
3058 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD_SEQ(&Source
->queue
),
3059 almemory_order_relaxed
);
3060 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
3061 ATOMIC_STORE_SEQ(&Source
->position_fraction
, 0);
3063 Source
->OffsetType
= AL_NONE
;
3064 Source
->Offset
= 0.0;
3066 WriteUnlock(&Source
->queue_lock
);
3069 /* GetSourceSampleOffset
3071 * Gets the current read offset for the given Source, in 32.32 fixed-point
3072 * samples. The offset is relative to the start of the queue (not the start of
3073 * the current buffer).
3075 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3077 const ALbufferlistitem
*BufferList
;
3078 const ALbufferlistitem
*Current
;
3082 ReadLock(&Source
->queue_lock
);
3083 if(!IsPlayingOrPaused(Source
))
3085 ReadUnlock(&Source
->queue_lock
);
3087 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3089 *clocktime
= GetDeviceClockTime(device
);
3090 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3091 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3096 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3098 *clocktime
= GetDeviceClockTime(device
);
3100 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3101 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3103 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) << 32;
3104 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
) <<
3106 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3107 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3108 while(BufferList
&& BufferList
!= Current
)
3110 if(BufferList
->buffer
)
3111 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3112 BufferList
= BufferList
->next
;
3115 ReadUnlock(&Source
->queue_lock
);
3116 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
3119 /* GetSourceSecOffset
3121 * Gets the current read offset for the given Source, in seconds. The offset is
3122 * relative to the start of the queue (not the start of the current buffer).
3124 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3126 const ALbufferlistitem
*BufferList
;
3127 const ALbufferlistitem
*Current
;
3128 const ALbuffer
*Buffer
= NULL
;
3132 ReadLock(&Source
->queue_lock
);
3133 if(!IsPlayingOrPaused(Source
))
3135 ReadUnlock(&Source
->queue_lock
);
3137 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3139 *clocktime
= GetDeviceClockTime(device
);
3140 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3141 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3146 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3148 *clocktime
= GetDeviceClockTime(device
);
3150 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3151 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3153 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
)<<FRACTIONBITS
;
3154 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3155 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3156 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3157 while(BufferList
&& BufferList
!= Current
)
3159 const ALbuffer
*buffer
= BufferList
->buffer
;
3162 if(!Buffer
) Buffer
= buffer
;
3163 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3165 BufferList
= BufferList
->next
;
3168 while(BufferList
&& !Buffer
)
3170 Buffer
= BufferList
->buffer
;
3171 BufferList
= BufferList
->next
;
3173 assert(Buffer
!= NULL
);
3175 ReadUnlock(&Source
->queue_lock
);
3176 return (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/ (ALdouble
)Buffer
->Frequency
;
3181 * Gets the current read offset for the given Source, in the appropriate format
3182 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3183 * queue (not the start of the current buffer).
3185 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
)
3187 const ALbufferlistitem
*BufferList
;
3188 const ALbufferlistitem
*Current
;
3189 const ALbuffer
*Buffer
= NULL
;
3190 ALboolean readFin
= AL_FALSE
;
3191 ALuint readPos
, readPosFrac
;
3192 ALuint totalBufferLen
;
3193 ALdouble offset
= 0.0;
3197 ReadLock(&Source
->queue_lock
);
3198 if(!IsPlayingOrPaused(Source
))
3200 ReadUnlock(&Source
->queue_lock
);
3206 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3208 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3209 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3211 readPos
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
3212 readPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3214 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3215 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3216 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3218 while(BufferList
!= NULL
)
3220 const ALbuffer
*buffer
;
3221 readFin
= readFin
|| (BufferList
== Current
);
3222 if((buffer
=BufferList
->buffer
) != NULL
)
3224 if(!Buffer
) Buffer
= buffer
;
3225 totalBufferLen
+= buffer
->SampleLen
;
3226 if(!readFin
) readPos
+= buffer
->SampleLen
;
3228 BufferList
= BufferList
->next
;
3230 assert(Buffer
!= NULL
);
3233 readPos
%= totalBufferLen
;
3236 /* Wrap back to 0 */
3237 if(readPos
>= totalBufferLen
)
3238 readPos
= readPosFrac
= 0;
3244 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3247 case AL_SAMPLE_OFFSET
:
3248 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3251 case AL_BYTE_OFFSET
:
3252 if(Buffer
->OriginalType
== UserFmtIMA4
)
3254 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3255 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3256 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3258 /* Round down to nearest ADPCM block */
3259 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3261 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3263 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3264 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3265 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3267 /* Round down to nearest ADPCM block */
3268 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3272 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3273 offset
= (ALdouble
)(readPos
* FrameSize
);
3278 ReadUnlock(&Source
->queue_lock
);
3285 * Apply the stored playback offset to the Source. This function will update
3286 * the number of buffers "played" given the stored offset.
3288 ALboolean
ApplyOffset(ALsource
*Source
)
3290 ALbufferlistitem
*BufferList
;
3291 const ALbuffer
*Buffer
;
3292 ALuint bufferLen
, totalBufferLen
;
3293 ALuint offset
=0, frac
=0;
3295 /* Get sample frame offset */
3296 if(!GetSampleOffset(Source
, &offset
, &frac
))
3300 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3301 while(BufferList
&& totalBufferLen
<= offset
)
3303 Buffer
= BufferList
->buffer
;
3304 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3306 if(bufferLen
> offset
-totalBufferLen
)
3308 /* Offset is in this buffer */
3309 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
3311 ATOMIC_STORE(&Source
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3312 ATOMIC_STORE(&Source
->position_fraction
, frac
, almemory_order_release
);
3316 totalBufferLen
+= bufferLen
;
3318 BufferList
= BufferList
->next
;
3321 /* Offset is out of range of the queue */
3328 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3329 * or Second offset supplied by the application). This takes into account the
3330 * fact that the buffer format may have been modifed since.
3332 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3334 const ALbuffer
*Buffer
= NULL
;
3335 const ALbufferlistitem
*BufferList
;
3336 ALdouble dbloff
, dblfrac
;
3338 /* Find the first valid Buffer in the Queue */
3339 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3342 if(BufferList
->buffer
)
3344 Buffer
= BufferList
->buffer
;
3347 BufferList
= BufferList
->next
;
3351 Source
->OffsetType
= AL_NONE
;
3352 Source
->Offset
= 0.0;
3356 switch(Source
->OffsetType
)
3358 case AL_BYTE_OFFSET
:
3359 /* Determine the ByteOffset (and ensure it is block aligned) */
3360 *offset
= (ALuint
)Source
->Offset
;
3361 if(Buffer
->OriginalType
== UserFmtIMA4
)
3363 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3364 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3365 *offset
*= Buffer
->OriginalAlign
;
3367 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3369 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3370 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3371 *offset
*= Buffer
->OriginalAlign
;
3374 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3378 case AL_SAMPLE_OFFSET
:
3379 dblfrac
= modf(Source
->Offset
, &dbloff
);
3380 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3381 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3385 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3386 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3387 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3390 Source
->OffsetType
= AL_NONE
;
3391 Source
->Offset
= 0.0;
3399 * Destroys all sources in the source map.
3401 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3403 ALCdevice
*device
= Context
->Device
;
3405 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3407 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3408 Context
->SourceMap
.values
[pos
] = NULL
;
3410 DeinitSource(temp
, device
->NumAuxSends
);
3412 FreeThunkEntry(temp
->id
);
3413 memset(temp
, 0, sizeof(*temp
));