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
);
52 static void DeinitSource(ALsource
*source
);
53 static void UpdateSourceProps(ALsource
*source
, ALuint 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] < 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
)
1542 ALCcontext
*context
;
1546 context
= GetContextRef();
1547 if(!context
) return;
1550 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1551 for(cur
= 0;cur
< n
;cur
++)
1553 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1556 alDeleteSources(cur
, sources
);
1557 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1559 InitSourceParams(source
);
1561 err
= NewThunkEntry(&source
->id
);
1562 if(err
== AL_NO_ERROR
)
1563 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1564 if(err
!= AL_NO_ERROR
)
1566 FreeThunkEntry(source
->id
);
1567 memset(source
, 0, sizeof(ALsource
));
1570 alDeleteSources(cur
, sources
);
1571 SET_ERROR_AND_GOTO(context
, err
, done
);
1574 sources
[cur
] = source
->id
;
1578 ALCcontext_DecRef(context
);
1582 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1584 ALCcontext
*context
;
1588 context
= GetContextRef();
1589 if(!context
) return;
1591 LockSourcesWrite(context
);
1593 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1595 /* Check that all Sources are valid */
1596 for(i
= 0;i
< n
;i
++)
1598 if(LookupSource(context
, sources
[i
]) == NULL
)
1599 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1601 for(i
= 0;i
< n
;i
++)
1605 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1607 FreeThunkEntry(Source
->id
);
1609 ALCdevice_Lock(context
->Device
);
1610 voice
= GetSourceVoice(Source
, context
);
1611 if(voice
) voice
->Source
= NULL
;
1612 ALCdevice_Unlock(context
->Device
);
1614 DeinitSource(Source
);
1616 memset(Source
, 0, sizeof(*Source
));
1621 UnlockSourcesWrite(context
);
1622 ALCcontext_DecRef(context
);
1626 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1628 ALCcontext
*context
;
1631 context
= GetContextRef();
1632 if(!context
) return AL_FALSE
;
1634 LockSourcesRead(context
);
1635 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1636 UnlockSourcesRead(context
);
1638 ALCcontext_DecRef(context
);
1644 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1646 ALCcontext
*Context
;
1649 Context
= GetContextRef();
1650 if(!Context
) return;
1652 WriteLock(&Context
->PropLock
);
1653 LockSourcesRead(Context
);
1654 if((Source
=LookupSource(Context
, source
)) == NULL
)
1655 alSetError(Context
, AL_INVALID_NAME
);
1656 else if(!(FloatValsByProp(param
) == 1))
1657 alSetError(Context
, AL_INVALID_ENUM
);
1659 SetSourcefv(Source
, Context
, param
, &value
);
1660 UnlockSourcesRead(Context
);
1661 WriteUnlock(&Context
->PropLock
);
1663 ALCcontext_DecRef(Context
);
1666 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1668 ALCcontext
*Context
;
1671 Context
= GetContextRef();
1672 if(!Context
) return;
1674 WriteLock(&Context
->PropLock
);
1675 LockSourcesRead(Context
);
1676 if((Source
=LookupSource(Context
, source
)) == NULL
)
1677 alSetError(Context
, AL_INVALID_NAME
);
1678 else if(!(FloatValsByProp(param
) == 3))
1679 alSetError(Context
, AL_INVALID_ENUM
);
1682 ALfloat fvals
[3] = { value1
, value2
, value3
};
1683 SetSourcefv(Source
, Context
, param
, fvals
);
1685 UnlockSourcesRead(Context
);
1686 WriteUnlock(&Context
->PropLock
);
1688 ALCcontext_DecRef(Context
);
1691 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1693 ALCcontext
*Context
;
1696 Context
= GetContextRef();
1697 if(!Context
) return;
1699 WriteLock(&Context
->PropLock
);
1700 LockSourcesRead(Context
);
1701 if((Source
=LookupSource(Context
, source
)) == NULL
)
1702 alSetError(Context
, AL_INVALID_NAME
);
1704 alSetError(Context
, AL_INVALID_VALUE
);
1705 else if(!(FloatValsByProp(param
) > 0))
1706 alSetError(Context
, AL_INVALID_ENUM
);
1708 SetSourcefv(Source
, Context
, param
, values
);
1709 UnlockSourcesRead(Context
);
1710 WriteUnlock(&Context
->PropLock
);
1712 ALCcontext_DecRef(Context
);
1716 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1718 ALCcontext
*Context
;
1721 Context
= GetContextRef();
1722 if(!Context
) return;
1724 WriteLock(&Context
->PropLock
);
1725 LockSourcesRead(Context
);
1726 if((Source
=LookupSource(Context
, source
)) == NULL
)
1727 alSetError(Context
, AL_INVALID_NAME
);
1728 else if(!(DoubleValsByProp(param
) == 1))
1729 alSetError(Context
, AL_INVALID_ENUM
);
1732 ALfloat fval
= (ALfloat
)value
;
1733 SetSourcefv(Source
, Context
, param
, &fval
);
1735 UnlockSourcesRead(Context
);
1736 WriteUnlock(&Context
->PropLock
);
1738 ALCcontext_DecRef(Context
);
1741 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1743 ALCcontext
*Context
;
1746 Context
= GetContextRef();
1747 if(!Context
) return;
1749 WriteLock(&Context
->PropLock
);
1750 LockSourcesRead(Context
);
1751 if((Source
=LookupSource(Context
, source
)) == NULL
)
1752 alSetError(Context
, AL_INVALID_NAME
);
1753 else if(!(DoubleValsByProp(param
) == 3))
1754 alSetError(Context
, AL_INVALID_ENUM
);
1757 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1758 SetSourcefv(Source
, Context
, param
, fvals
);
1760 UnlockSourcesRead(Context
);
1761 WriteUnlock(&Context
->PropLock
);
1763 ALCcontext_DecRef(Context
);
1766 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1768 ALCcontext
*Context
;
1772 Context
= GetContextRef();
1773 if(!Context
) return;
1775 WriteLock(&Context
->PropLock
);
1776 LockSourcesRead(Context
);
1777 if((Source
=LookupSource(Context
, source
)) == NULL
)
1778 alSetError(Context
, AL_INVALID_NAME
);
1780 alSetError(Context
, AL_INVALID_VALUE
);
1781 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1782 alSetError(Context
, AL_INVALID_ENUM
);
1788 for(i
= 0;i
< count
;i
++)
1789 fvals
[i
] = (ALfloat
)values
[i
];
1790 SetSourcefv(Source
, Context
, param
, fvals
);
1792 UnlockSourcesRead(Context
);
1793 WriteUnlock(&Context
->PropLock
);
1795 ALCcontext_DecRef(Context
);
1799 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1801 ALCcontext
*Context
;
1804 Context
= GetContextRef();
1805 if(!Context
) return;
1807 WriteLock(&Context
->PropLock
);
1808 LockSourcesRead(Context
);
1809 if((Source
=LookupSource(Context
, source
)) == NULL
)
1810 alSetError(Context
, AL_INVALID_NAME
);
1811 else if(!(IntValsByProp(param
) == 1))
1812 alSetError(Context
, AL_INVALID_ENUM
);
1814 SetSourceiv(Source
, Context
, param
, &value
);
1815 UnlockSourcesRead(Context
);
1816 WriteUnlock(&Context
->PropLock
);
1818 ALCcontext_DecRef(Context
);
1821 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1823 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
);
1833 else if(!(IntValsByProp(param
) == 3))
1834 alSetError(Context
, AL_INVALID_ENUM
);
1837 ALint ivals
[3] = { value1
, value2
, value3
};
1838 SetSourceiv(Source
, Context
, param
, ivals
);
1840 UnlockSourcesRead(Context
);
1841 WriteUnlock(&Context
->PropLock
);
1843 ALCcontext_DecRef(Context
);
1846 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1848 ALCcontext
*Context
;
1851 Context
= GetContextRef();
1852 if(!Context
) return;
1854 WriteLock(&Context
->PropLock
);
1855 LockSourcesRead(Context
);
1856 if((Source
=LookupSource(Context
, source
)) == NULL
)
1857 alSetError(Context
, AL_INVALID_NAME
);
1859 alSetError(Context
, AL_INVALID_VALUE
);
1860 else if(!(IntValsByProp(param
) > 0))
1861 alSetError(Context
, AL_INVALID_ENUM
);
1863 SetSourceiv(Source
, Context
, param
, values
);
1864 UnlockSourcesRead(Context
);
1865 WriteUnlock(&Context
->PropLock
);
1867 ALCcontext_DecRef(Context
);
1871 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1873 ALCcontext
*Context
;
1876 Context
= GetContextRef();
1877 if(!Context
) return;
1879 WriteLock(&Context
->PropLock
);
1880 LockSourcesRead(Context
);
1881 if((Source
=LookupSource(Context
, source
)) == NULL
)
1882 alSetError(Context
, AL_INVALID_NAME
);
1883 else if(!(Int64ValsByProp(param
) == 1))
1884 alSetError(Context
, AL_INVALID_ENUM
);
1886 SetSourcei64v(Source
, Context
, param
, &value
);
1887 UnlockSourcesRead(Context
);
1888 WriteUnlock(&Context
->PropLock
);
1890 ALCcontext_DecRef(Context
);
1893 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1895 ALCcontext
*Context
;
1898 Context
= GetContextRef();
1899 if(!Context
) return;
1901 WriteLock(&Context
->PropLock
);
1902 LockSourcesRead(Context
);
1903 if((Source
=LookupSource(Context
, source
)) == NULL
)
1904 alSetError(Context
, AL_INVALID_NAME
);
1905 else if(!(Int64ValsByProp(param
) == 3))
1906 alSetError(Context
, AL_INVALID_ENUM
);
1909 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1910 SetSourcei64v(Source
, Context
, param
, i64vals
);
1912 UnlockSourcesRead(Context
);
1913 WriteUnlock(&Context
->PropLock
);
1915 ALCcontext_DecRef(Context
);
1918 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1920 ALCcontext
*Context
;
1923 Context
= GetContextRef();
1924 if(!Context
) return;
1926 WriteLock(&Context
->PropLock
);
1927 LockSourcesRead(Context
);
1928 if((Source
=LookupSource(Context
, source
)) == NULL
)
1929 alSetError(Context
, AL_INVALID_NAME
);
1931 alSetError(Context
, AL_INVALID_VALUE
);
1932 else if(!(Int64ValsByProp(param
) > 0))
1933 alSetError(Context
, AL_INVALID_ENUM
);
1935 SetSourcei64v(Source
, Context
, param
, values
);
1936 UnlockSourcesRead(Context
);
1937 WriteUnlock(&Context
->PropLock
);
1939 ALCcontext_DecRef(Context
);
1943 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1945 ALCcontext
*Context
;
1948 Context
= GetContextRef();
1949 if(!Context
) return;
1951 ReadLock(&Context
->PropLock
);
1952 LockSourcesRead(Context
);
1953 if((Source
=LookupSource(Context
, source
)) == NULL
)
1954 alSetError(Context
, AL_INVALID_NAME
);
1956 alSetError(Context
, AL_INVALID_VALUE
);
1957 else if(!(FloatValsByProp(param
) == 1))
1958 alSetError(Context
, AL_INVALID_ENUM
);
1962 if(GetSourcedv(Source
, Context
, param
, &dval
))
1963 *value
= (ALfloat
)dval
;
1965 UnlockSourcesRead(Context
);
1966 ReadUnlock(&Context
->PropLock
);
1968 ALCcontext_DecRef(Context
);
1972 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1974 ALCcontext
*Context
;
1977 Context
= GetContextRef();
1978 if(!Context
) return;
1980 ReadLock(&Context
->PropLock
);
1981 LockSourcesRead(Context
);
1982 if((Source
=LookupSource(Context
, source
)) == NULL
)
1983 alSetError(Context
, AL_INVALID_NAME
);
1984 else if(!(value1
&& value2
&& value3
))
1985 alSetError(Context
, AL_INVALID_VALUE
);
1986 else if(!(FloatValsByProp(param
) == 3))
1987 alSetError(Context
, AL_INVALID_ENUM
);
1991 if(GetSourcedv(Source
, Context
, param
, dvals
))
1993 *value1
= (ALfloat
)dvals
[0];
1994 *value2
= (ALfloat
)dvals
[1];
1995 *value3
= (ALfloat
)dvals
[2];
1998 UnlockSourcesRead(Context
);
1999 ReadUnlock(&Context
->PropLock
);
2001 ALCcontext_DecRef(Context
);
2005 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2007 ALCcontext
*Context
;
2011 Context
= GetContextRef();
2012 if(!Context
) return;
2014 ReadLock(&Context
->PropLock
);
2015 LockSourcesRead(Context
);
2016 if((Source
=LookupSource(Context
, source
)) == NULL
)
2017 alSetError(Context
, AL_INVALID_NAME
);
2019 alSetError(Context
, AL_INVALID_VALUE
);
2020 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2021 alSetError(Context
, AL_INVALID_ENUM
);
2025 if(GetSourcedv(Source
, Context
, param
, dvals
))
2028 for(i
= 0;i
< count
;i
++)
2029 values
[i
] = (ALfloat
)dvals
[i
];
2032 UnlockSourcesRead(Context
);
2033 ReadUnlock(&Context
->PropLock
);
2035 ALCcontext_DecRef(Context
);
2039 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2041 ALCcontext
*Context
;
2044 Context
= GetContextRef();
2045 if(!Context
) return;
2047 ReadLock(&Context
->PropLock
);
2048 LockSourcesRead(Context
);
2049 if((Source
=LookupSource(Context
, source
)) == NULL
)
2050 alSetError(Context
, AL_INVALID_NAME
);
2052 alSetError(Context
, AL_INVALID_VALUE
);
2053 else if(!(DoubleValsByProp(param
) == 1))
2054 alSetError(Context
, AL_INVALID_ENUM
);
2056 GetSourcedv(Source
, Context
, param
, value
);
2057 UnlockSourcesRead(Context
);
2058 ReadUnlock(&Context
->PropLock
);
2060 ALCcontext_DecRef(Context
);
2063 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2065 ALCcontext
*Context
;
2068 Context
= GetContextRef();
2069 if(!Context
) return;
2071 ReadLock(&Context
->PropLock
);
2072 LockSourcesRead(Context
);
2073 if((Source
=LookupSource(Context
, source
)) == NULL
)
2074 alSetError(Context
, AL_INVALID_NAME
);
2075 else if(!(value1
&& value2
&& value3
))
2076 alSetError(Context
, AL_INVALID_VALUE
);
2077 else if(!(DoubleValsByProp(param
) == 3))
2078 alSetError(Context
, AL_INVALID_ENUM
);
2082 if(GetSourcedv(Source
, Context
, param
, dvals
))
2089 UnlockSourcesRead(Context
);
2090 ReadUnlock(&Context
->PropLock
);
2092 ALCcontext_DecRef(Context
);
2095 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2097 ALCcontext
*Context
;
2100 Context
= GetContextRef();
2101 if(!Context
) return;
2103 ReadLock(&Context
->PropLock
);
2104 LockSourcesRead(Context
);
2105 if((Source
=LookupSource(Context
, source
)) == NULL
)
2106 alSetError(Context
, AL_INVALID_NAME
);
2108 alSetError(Context
, AL_INVALID_VALUE
);
2109 else if(!(DoubleValsByProp(param
) > 0))
2110 alSetError(Context
, AL_INVALID_ENUM
);
2112 GetSourcedv(Source
, Context
, param
, values
);
2113 UnlockSourcesRead(Context
);
2114 ReadUnlock(&Context
->PropLock
);
2116 ALCcontext_DecRef(Context
);
2120 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2122 ALCcontext
*Context
;
2125 Context
= GetContextRef();
2126 if(!Context
) return;
2128 ReadLock(&Context
->PropLock
);
2129 LockSourcesRead(Context
);
2130 if((Source
=LookupSource(Context
, source
)) == NULL
)
2131 alSetError(Context
, AL_INVALID_NAME
);
2133 alSetError(Context
, AL_INVALID_VALUE
);
2134 else if(!(IntValsByProp(param
) == 1))
2135 alSetError(Context
, AL_INVALID_ENUM
);
2137 GetSourceiv(Source
, Context
, param
, value
);
2138 UnlockSourcesRead(Context
);
2139 ReadUnlock(&Context
->PropLock
);
2141 ALCcontext_DecRef(Context
);
2145 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2147 ALCcontext
*Context
;
2150 Context
= GetContextRef();
2151 if(!Context
) return;
2153 ReadLock(&Context
->PropLock
);
2154 LockSourcesRead(Context
);
2155 if((Source
=LookupSource(Context
, source
)) == NULL
)
2156 alSetError(Context
, AL_INVALID_NAME
);
2157 else if(!(value1
&& value2
&& value3
))
2158 alSetError(Context
, AL_INVALID_VALUE
);
2159 else if(!(IntValsByProp(param
) == 3))
2160 alSetError(Context
, AL_INVALID_ENUM
);
2164 if(GetSourceiv(Source
, Context
, param
, ivals
))
2171 UnlockSourcesRead(Context
);
2172 ReadUnlock(&Context
->PropLock
);
2174 ALCcontext_DecRef(Context
);
2178 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2180 ALCcontext
*Context
;
2183 Context
= GetContextRef();
2184 if(!Context
) return;
2186 ReadLock(&Context
->PropLock
);
2187 LockSourcesRead(Context
);
2188 if((Source
=LookupSource(Context
, source
)) == NULL
)
2189 alSetError(Context
, AL_INVALID_NAME
);
2191 alSetError(Context
, AL_INVALID_VALUE
);
2192 else if(!(IntValsByProp(param
) > 0))
2193 alSetError(Context
, AL_INVALID_ENUM
);
2195 GetSourceiv(Source
, Context
, param
, values
);
2196 UnlockSourcesRead(Context
);
2197 ReadUnlock(&Context
->PropLock
);
2199 ALCcontext_DecRef(Context
);
2203 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2205 ALCcontext
*Context
;
2208 Context
= GetContextRef();
2209 if(!Context
) return;
2211 ReadLock(&Context
->PropLock
);
2212 LockSourcesRead(Context
);
2213 if((Source
=LookupSource(Context
, source
)) == NULL
)
2214 alSetError(Context
, AL_INVALID_NAME
);
2216 alSetError(Context
, AL_INVALID_VALUE
);
2217 else if(!(Int64ValsByProp(param
) == 1))
2218 alSetError(Context
, AL_INVALID_ENUM
);
2220 GetSourcei64v(Source
, Context
, param
, value
);
2221 UnlockSourcesRead(Context
);
2222 ReadUnlock(&Context
->PropLock
);
2224 ALCcontext_DecRef(Context
);
2227 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2229 ALCcontext
*Context
;
2232 Context
= GetContextRef();
2233 if(!Context
) return;
2235 ReadLock(&Context
->PropLock
);
2236 LockSourcesRead(Context
);
2237 if((Source
=LookupSource(Context
, source
)) == NULL
)
2238 alSetError(Context
, AL_INVALID_NAME
);
2239 else if(!(value1
&& value2
&& value3
))
2240 alSetError(Context
, AL_INVALID_VALUE
);
2241 else if(!(Int64ValsByProp(param
) == 3))
2242 alSetError(Context
, AL_INVALID_ENUM
);
2246 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2248 *value1
= i64vals
[0];
2249 *value2
= i64vals
[1];
2250 *value3
= i64vals
[2];
2253 UnlockSourcesRead(Context
);
2254 ReadUnlock(&Context
->PropLock
);
2256 ALCcontext_DecRef(Context
);
2259 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2261 ALCcontext
*Context
;
2264 Context
= GetContextRef();
2265 if(!Context
) return;
2267 ReadLock(&Context
->PropLock
);
2268 LockSourcesRead(Context
);
2269 if((Source
=LookupSource(Context
, source
)) == NULL
)
2270 alSetError(Context
, AL_INVALID_NAME
);
2272 alSetError(Context
, AL_INVALID_VALUE
);
2273 else if(!(Int64ValsByProp(param
) > 0))
2274 alSetError(Context
, AL_INVALID_ENUM
);
2276 GetSourcei64v(Source
, Context
, param
, values
);
2277 UnlockSourcesRead(Context
);
2278 ReadUnlock(&Context
->PropLock
);
2280 ALCcontext_DecRef(Context
);
2284 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2286 alSourcePlayv(1, &source
);
2288 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2290 ALCcontext
*context
;
2294 context
= GetContextRef();
2295 if(!context
) return;
2297 LockSourcesRead(context
);
2299 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2300 for(i
= 0;i
< n
;i
++)
2302 if(!LookupSource(context
, sources
[i
]))
2303 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2306 ALCdevice_Lock(context
->Device
);
2307 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2309 ALsizei newcount
= context
->MaxVoices
<< 1;
2310 if(context
->MaxVoices
>= newcount
)
2312 ALCdevice_Unlock(context
->Device
);
2313 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2315 AllocateVoices(context
, newcount
, context
->Device
->NumAuxSends
);
2318 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) == DeferAll
)
2320 for(i
= 0;i
< n
;i
++)
2322 source
= LookupSource(context
, sources
[i
]);
2323 source
->new_state
= AL_PLAYING
;
2328 for(i
= 0;i
< n
;i
++)
2330 source
= LookupSource(context
, sources
[i
]);
2331 SetSourceState(source
, context
, AL_PLAYING
);
2334 ALCdevice_Unlock(context
->Device
);
2337 UnlockSourcesRead(context
);
2338 ALCcontext_DecRef(context
);
2341 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2343 alSourcePausev(1, &source
);
2345 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2347 ALCcontext
*context
;
2351 context
= GetContextRef();
2352 if(!context
) return;
2354 LockSourcesRead(context
);
2356 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2357 for(i
= 0;i
< n
;i
++)
2359 if(!LookupSource(context
, sources
[i
]))
2360 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2363 ALCdevice_Lock(context
->Device
);
2364 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2366 for(i
= 0;i
< n
;i
++)
2368 source
= LookupSource(context
, sources
[i
]);
2369 source
->new_state
= AL_PAUSED
;
2374 for(i
= 0;i
< n
;i
++)
2376 source
= LookupSource(context
, sources
[i
]);
2377 SetSourceState(source
, context
, AL_PAUSED
);
2380 ALCdevice_Unlock(context
->Device
);
2383 UnlockSourcesRead(context
);
2384 ALCcontext_DecRef(context
);
2387 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2389 alSourceStopv(1, &source
);
2391 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2393 ALCcontext
*context
;
2397 context
= GetContextRef();
2398 if(!context
) return;
2400 LockSourcesRead(context
);
2402 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2403 for(i
= 0;i
< n
;i
++)
2405 if(!LookupSource(context
, sources
[i
]))
2406 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2409 ALCdevice_Lock(context
->Device
);
2410 for(i
= 0;i
< n
;i
++)
2412 source
= LookupSource(context
, sources
[i
]);
2413 source
->new_state
= AL_NONE
;
2414 SetSourceState(source
, context
, AL_STOPPED
);
2416 ALCdevice_Unlock(context
->Device
);
2419 UnlockSourcesRead(context
);
2420 ALCcontext_DecRef(context
);
2423 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2425 alSourceRewindv(1, &source
);
2427 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2429 ALCcontext
*context
;
2433 context
= GetContextRef();
2434 if(!context
) return;
2436 LockSourcesRead(context
);
2438 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2439 for(i
= 0;i
< n
;i
++)
2441 if(!LookupSource(context
, sources
[i
]))
2442 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2445 ALCdevice_Lock(context
->Device
);
2446 for(i
= 0;i
< n
;i
++)
2448 source
= LookupSource(context
, sources
[i
]);
2449 source
->new_state
= AL_NONE
;
2450 SetSourceState(source
, context
, AL_INITIAL
);
2452 ALCdevice_Unlock(context
->Device
);
2455 UnlockSourcesRead(context
);
2456 ALCcontext_DecRef(context
);
2460 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2463 ALCcontext
*context
;
2466 ALbufferlistitem
*BufferListStart
;
2467 ALbufferlistitem
*BufferList
;
2468 ALbuffer
*BufferFmt
= NULL
;
2473 context
= GetContextRef();
2474 if(!context
) return;
2476 device
= context
->Device
;
2478 LockSourcesRead(context
);
2480 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2481 if((source
=LookupSource(context
, src
)) == NULL
)
2482 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2484 WriteLock(&source
->queue_lock
);
2485 if(source
->SourceType
== AL_STATIC
)
2487 WriteUnlock(&source
->queue_lock
);
2488 /* Can't queue on a Static Source */
2489 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2492 /* Check for a valid Buffer, for its frequency and format */
2493 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2496 if(BufferList
->buffer
)
2498 BufferFmt
= BufferList
->buffer
;
2501 BufferList
= BufferList
->next
;
2504 LockBuffersRead(device
);
2505 BufferListStart
= NULL
;
2507 for(i
= 0;i
< nb
;i
++)
2509 ALbuffer
*buffer
= NULL
;
2510 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2512 WriteUnlock(&source
->queue_lock
);
2513 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2516 if(!BufferListStart
)
2518 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2519 BufferList
= BufferListStart
;
2523 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2524 BufferList
= BufferList
->next
;
2526 BufferList
->buffer
= buffer
;
2527 BufferList
->next
= NULL
;
2528 if(!buffer
) continue;
2530 /* Hold a read lock on each buffer being queued while checking all
2531 * provided buffers. This is done so other threads don't see an extra
2532 * reference on some buffers if this operation ends up failing. */
2533 ReadLock(&buffer
->lock
);
2534 IncrementRef(&buffer
->ref
);
2536 if(BufferFmt
== NULL
)
2540 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2541 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2543 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2544 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2545 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2547 WriteUnlock(&source
->queue_lock
);
2548 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2551 /* A buffer failed (invalid ID or format), so unlock and release
2552 * each buffer we had. */
2553 while(BufferListStart
)
2555 ALbufferlistitem
*next
= BufferListStart
->next
;
2556 if((buffer
=BufferListStart
->buffer
) != NULL
)
2558 DecrementRef(&buffer
->ref
);
2559 ReadUnlock(&buffer
->lock
);
2561 free(BufferListStart
);
2562 BufferListStart
= next
;
2564 UnlockBuffersRead(device
);
2568 /* All buffers good, unlock them now. */
2569 BufferList
= BufferListStart
;
2570 while(BufferList
!= NULL
)
2572 ALbuffer
*buffer
= BufferList
->buffer
;
2573 if(buffer
) ReadUnlock(&buffer
->lock
);
2574 BufferList
= BufferList
->next
;
2576 UnlockBuffersRead(device
);
2578 /* Source is now streaming */
2579 source
->SourceType
= AL_STREAMING
;
2582 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->queue
,
2583 &BufferList
, BufferListStart
))
2585 /* Queue head is not NULL, append to the end of the queue */
2586 while(BufferList
->next
!= NULL
)
2587 BufferList
= BufferList
->next
;
2588 BufferList
->next
= BufferListStart
;
2590 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2594 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->current_buffer
,
2595 &BufferList
, BufferListStart
);
2596 WriteUnlock(&source
->queue_lock
);
2599 UnlockSourcesRead(context
);
2600 ALCcontext_DecRef(context
);
2603 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2605 ALCcontext
*context
;
2607 ALbufferlistitem
*OldHead
;
2608 ALbufferlistitem
*OldTail
;
2609 ALbufferlistitem
*Current
;
2615 context
= GetContextRef();
2616 if(!context
) return;
2618 LockSourcesRead(context
);
2620 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2622 if((source
=LookupSource(context
, src
)) == NULL
)
2623 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2625 WriteLock(&source
->queue_lock
);
2626 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2628 WriteUnlock(&source
->queue_lock
);
2629 /* Trying to unqueue buffers on a looping or non-streaming source. */
2630 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2633 /* Find the new buffer queue head */
2634 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2635 Current
= ATOMIC_LOAD_SEQ(&source
->current_buffer
);
2636 if(OldTail
!= Current
)
2638 for(i
= 1;i
< nb
;i
++)
2640 ALbufferlistitem
*next
= OldTail
->next
;
2641 if(!next
|| next
== Current
) break;
2647 WriteUnlock(&source
->queue_lock
);
2648 /* Trying to unqueue pending buffers. */
2649 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2652 /* Swap it, and cut the new head from the old. */
2653 OldHead
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2656 ALCdevice
*device
= context
->Device
;
2659 /* Once the active mix (if any) is done, it's safe to cut the old tail
2660 * from the new head.
2662 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2664 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2667 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2668 OldTail
->next
= NULL
;
2670 WriteUnlock(&source
->queue_lock
);
2672 while(OldHead
!= NULL
)
2674 ALbufferlistitem
*next
= OldHead
->next
;
2675 ALbuffer
*buffer
= OldHead
->buffer
;
2681 *(buffers
++) = buffer
->id
;
2682 DecrementRef(&buffer
->ref
);
2690 UnlockSourcesRead(context
);
2691 ALCcontext_DecRef(context
);
2695 static void InitSourceParams(ALsource
*Source
)
2699 RWLockInit(&Source
->queue_lock
);
2701 Source
->InnerAngle
= 360.0f
;
2702 Source
->OuterAngle
= 360.0f
;
2703 Source
->Pitch
= 1.0f
;
2704 Source
->Position
[0] = 0.0f
;
2705 Source
->Position
[1] = 0.0f
;
2706 Source
->Position
[2] = 0.0f
;
2707 Source
->Velocity
[0] = 0.0f
;
2708 Source
->Velocity
[1] = 0.0f
;
2709 Source
->Velocity
[2] = 0.0f
;
2710 Source
->Direction
[0] = 0.0f
;
2711 Source
->Direction
[1] = 0.0f
;
2712 Source
->Direction
[2] = 0.0f
;
2713 Source
->Orientation
[0][0] = 0.0f
;
2714 Source
->Orientation
[0][1] = 0.0f
;
2715 Source
->Orientation
[0][2] = -1.0f
;
2716 Source
->Orientation
[1][0] = 0.0f
;
2717 Source
->Orientation
[1][1] = 1.0f
;
2718 Source
->Orientation
[1][2] = 0.0f
;
2719 Source
->RefDistance
= 1.0f
;
2720 Source
->MaxDistance
= FLT_MAX
;
2721 Source
->RollOffFactor
= 1.0f
;
2722 Source
->Gain
= 1.0f
;
2723 Source
->MinGain
= 0.0f
;
2724 Source
->MaxGain
= 1.0f
;
2725 Source
->OuterGain
= 0.0f
;
2726 Source
->OuterGainHF
= 1.0f
;
2728 Source
->DryGainHFAuto
= AL_TRUE
;
2729 Source
->WetGainAuto
= AL_TRUE
;
2730 Source
->WetGainHFAuto
= AL_TRUE
;
2731 Source
->AirAbsorptionFactor
= 0.0f
;
2732 Source
->RoomRolloffFactor
= 0.0f
;
2733 Source
->DopplerFactor
= 1.0f
;
2734 Source
->DirectChannels
= AL_FALSE
;
2736 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2737 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2739 Source
->Radius
= 0.0f
;
2741 Source
->DistanceModel
= DefaultDistanceModel
;
2743 Source
->Direct
.Gain
= 1.0f
;
2744 Source
->Direct
.GainHF
= 1.0f
;
2745 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2746 Source
->Direct
.GainLF
= 1.0f
;
2747 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2748 for(i
= 0;i
< MAX_SENDS
;i
++)
2750 Source
->Send
[i
].Slot
= NULL
;
2751 Source
->Send
[i
].Gain
= 1.0f
;
2752 Source
->Send
[i
].GainHF
= 1.0f
;
2753 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2754 Source
->Send
[i
].GainLF
= 1.0f
;
2755 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2758 Source
->Offset
= 0.0;
2759 Source
->OffsetType
= AL_NONE
;
2760 Source
->SourceType
= AL_UNDETERMINED
;
2761 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2762 Source
->new_state
= AL_NONE
;
2764 ATOMIC_INIT(&Source
->queue
, NULL
);
2765 ATOMIC_INIT(&Source
->current_buffer
, NULL
);
2767 ATOMIC_INIT(&Source
->position
, 0);
2768 ATOMIC_INIT(&Source
->position_fraction
, 0);
2770 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2772 Source
->NeedsUpdate
= AL_TRUE
;
2774 ATOMIC_INIT(&Source
->Update
, NULL
);
2775 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2778 static void DeinitSource(ALsource
*source
)
2780 ALbufferlistitem
*BufferList
;
2781 struct ALsourceProps
*props
;
2785 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2786 if(props
) al_free(props
);
2788 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2791 struct ALsourceProps
*next
;
2792 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2797 /* This is excessively spammy if it traces every source destruction, so
2798 * just warn if it was unexpectedly large.
2801 WARN("Freed "SZFMT
" Source property objects\n", count
);
2803 BufferList
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, NULL
);
2804 while(BufferList
!= NULL
)
2806 ALbufferlistitem
*next
= BufferList
->next
;
2807 if(BufferList
->buffer
!= NULL
)
2808 DecrementRef(&BufferList
->buffer
->ref
);
2813 for(i
= 0;i
< MAX_SENDS
;i
++)
2815 if(source
->Send
[i
].Slot
)
2816 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2817 source
->Send
[i
].Slot
= NULL
;
2821 static void UpdateSourceProps(ALsource
*source
, ALuint num_sends
)
2823 struct ALsourceProps
*props
;
2826 /* Get an unused property container, or allocate a new one as needed. */
2827 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2829 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
2832 struct ALsourceProps
*next
;
2834 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2835 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2836 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
2837 almemory_order_acquire
) == 0);
2840 /* Copy in current property values. */
2841 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2842 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2843 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2844 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2845 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2846 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2847 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2848 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2849 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2850 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2851 for(i
= 0;i
< 3;i
++)
2852 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2853 for(i
= 0;i
< 3;i
++)
2854 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2855 for(i
= 0;i
< 3;i
++)
2856 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2857 for(i
= 0;i
< 2;i
++)
2860 for(j
= 0;j
< 3;j
++)
2861 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2862 almemory_order_relaxed
);
2864 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2865 ATOMIC_STORE(&props
->DistanceModel
, source
->DistanceModel
, almemory_order_relaxed
);
2866 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2868 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2869 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2870 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2871 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2873 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2874 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2875 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2877 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2878 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2880 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2882 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2883 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2884 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2885 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2886 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2888 for(i
= 0;i
< num_sends
;i
++)
2890 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2891 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2892 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2893 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2894 almemory_order_relaxed
);
2895 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2896 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2897 almemory_order_relaxed
);
2900 /* Set the new container for updating internal parameters. */
2901 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2904 /* If there was an unused update container, put it back in the
2907 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
2911 void UpdateAllSourceProps(ALCcontext
*context
)
2913 ALuint num_sends
= context
->Device
->NumAuxSends
;
2916 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
2918 ALvoice
*voice
= context
->Voices
[pos
];
2919 ALsource
*source
= voice
->Source
;
2920 if(source
!= NULL
&& source
->NeedsUpdate
&& IsPlayingOrPaused(source
))
2922 source
->NeedsUpdate
= AL_FALSE
;
2923 UpdateSourceProps(source
, num_sends
);
2931 * Sets the source's new play state given its current state.
2933 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2935 WriteLock(&Source
->queue_lock
);
2936 if(state
== AL_PLAYING
)
2938 ALCdevice
*device
= Context
->Device
;
2939 ALbufferlistitem
*BufferList
;
2940 ALboolean discontinuity
;
2941 ALvoice
*voice
= NULL
;
2944 /* Check that there is a queue containing at least one valid, non zero
2946 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
2950 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2952 BufferList
= BufferList
->next
;
2955 if(ATOMIC_EXCHANGE(ALenum
, &Source
->state
, AL_PLAYING
, almemory_order_acq_rel
) == AL_PAUSED
)
2956 discontinuity
= AL_FALSE
;
2959 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
2960 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
2961 ATOMIC_STORE(&Source
->position_fraction
, 0, almemory_order_release
);
2962 discontinuity
= AL_TRUE
;
2965 // Check if an Offset has been set
2966 if(Source
->OffsetType
!= AL_NONE
)
2968 ApplyOffset(Source
);
2969 /* discontinuity = AL_TRUE;??? */
2972 /* If there's nothing to play, or device is disconnected, go right to
2974 if(!BufferList
|| !device
->Connected
)
2977 /* Make sure this source isn't already active, and if not, look for an
2978 * unused voice to put it in.
2980 voice
= GetSourceVoice(Source
, Context
);
2983 for(i
= 0;i
< Context
->VoiceCount
;i
++)
2985 if(Context
->Voices
[i
]->Source
== NULL
)
2987 voice
= Context
->Voices
[i
];
2988 voice
->Source
= Source
;
2994 voice
= Context
->Voices
[Context
->VoiceCount
++];
2995 voice
->Source
= Source
;
2997 discontinuity
= AL_TRUE
;
3002 /* Clear previous samples if playback is discontinuous. */
3003 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
3005 /* Clear the stepping value so the mixer knows not to mix this
3006 * until the update gets applied.
3011 voice
->Moving
= AL_FALSE
;
3012 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
3015 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
3016 voice
->Direct
.Params
[i
].Hrtf
.State
.History
[j
] = 0.0f
;
3017 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3019 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][0] = 0.0f
;
3020 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][1] = 0.0f
;
3024 Source
->NeedsUpdate
= AL_FALSE
;
3025 UpdateSourceProps(Source
, device
->NumAuxSends
);
3027 else if(state
== AL_PAUSED
)
3029 ALenum playing
= AL_PLAYING
;
3030 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum
, &Source
->state
, &playing
, AL_PAUSED
);
3032 else if(state
== AL_STOPPED
)
3035 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3037 ATOMIC_STORE(&Source
->state
, AL_STOPPED
, almemory_order_relaxed
);
3038 ATOMIC_STORE_SEQ(&Source
->current_buffer
, NULL
);
3040 Source
->OffsetType
= AL_NONE
;
3041 Source
->Offset
= 0.0;
3043 else if(state
== AL_INITIAL
)
3045 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3047 ATOMIC_STORE(&Source
->state
, AL_INITIAL
, almemory_order_relaxed
);
3048 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD_SEQ(&Source
->queue
),
3049 almemory_order_relaxed
);
3050 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
3051 ATOMIC_STORE_SEQ(&Source
->position_fraction
, 0);
3053 Source
->OffsetType
= AL_NONE
;
3054 Source
->Offset
= 0.0;
3056 WriteUnlock(&Source
->queue_lock
);
3059 /* GetSourceSampleOffset
3061 * Gets the current read offset for the given Source, in 32.32 fixed-point
3062 * samples. The offset is relative to the start of the queue (not the start of
3063 * the current buffer).
3065 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3067 const ALbufferlistitem
*BufferList
;
3068 const ALbufferlistitem
*Current
;
3072 ReadLock(&Source
->queue_lock
);
3073 if(!IsPlayingOrPaused(Source
))
3075 ReadUnlock(&Source
->queue_lock
);
3077 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3079 *clocktime
= GetDeviceClockTime(device
);
3080 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3081 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3086 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3088 *clocktime
= GetDeviceClockTime(device
);
3090 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3091 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3093 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) << 32;
3094 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
) <<
3096 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3097 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3098 while(BufferList
&& BufferList
!= Current
)
3100 if(BufferList
->buffer
)
3101 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3102 BufferList
= BufferList
->next
;
3105 ReadUnlock(&Source
->queue_lock
);
3106 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
3109 /* GetSourceSecOffset
3111 * Gets the current read offset for the given Source, in seconds. The offset is
3112 * relative to the start of the queue (not the start of the current buffer).
3114 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3116 const ALbufferlistitem
*BufferList
;
3117 const ALbufferlistitem
*Current
;
3118 const ALbuffer
*Buffer
= NULL
;
3122 ReadLock(&Source
->queue_lock
);
3123 if(!IsPlayingOrPaused(Source
))
3125 ReadUnlock(&Source
->queue_lock
);
3127 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3129 *clocktime
= GetDeviceClockTime(device
);
3130 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3131 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3136 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3138 *clocktime
= GetDeviceClockTime(device
);
3140 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3141 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3143 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
)<<FRACTIONBITS
;
3144 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3145 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3146 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3147 while(BufferList
&& BufferList
!= Current
)
3149 const ALbuffer
*buffer
= BufferList
->buffer
;
3152 if(!Buffer
) Buffer
= buffer
;
3153 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3155 BufferList
= BufferList
->next
;
3158 while(BufferList
&& !Buffer
)
3160 Buffer
= BufferList
->buffer
;
3161 BufferList
= BufferList
->next
;
3163 assert(Buffer
!= NULL
);
3165 ReadUnlock(&Source
->queue_lock
);
3166 return (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/ (ALdouble
)Buffer
->Frequency
;
3171 * Gets the current read offset for the given Source, in the appropriate format
3172 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3173 * queue (not the start of the current buffer).
3175 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
)
3177 const ALbufferlistitem
*BufferList
;
3178 const ALbufferlistitem
*Current
;
3179 const ALbuffer
*Buffer
= NULL
;
3180 ALboolean readFin
= AL_FALSE
;
3181 ALuint readPos
, readPosFrac
;
3182 ALuint totalBufferLen
;
3183 ALdouble offset
= 0.0;
3187 ReadLock(&Source
->queue_lock
);
3188 if(!IsPlayingOrPaused(Source
))
3190 ReadUnlock(&Source
->queue_lock
);
3196 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3198 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3199 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3201 readPos
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
3202 readPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3204 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3205 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3206 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3208 while(BufferList
!= NULL
)
3210 const ALbuffer
*buffer
;
3211 readFin
= readFin
|| (BufferList
== Current
);
3212 if((buffer
=BufferList
->buffer
) != NULL
)
3214 if(!Buffer
) Buffer
= buffer
;
3215 totalBufferLen
+= buffer
->SampleLen
;
3216 if(!readFin
) readPos
+= buffer
->SampleLen
;
3218 BufferList
= BufferList
->next
;
3220 assert(Buffer
!= NULL
);
3223 readPos
%= totalBufferLen
;
3226 /* Wrap back to 0 */
3227 if(readPos
>= totalBufferLen
)
3228 readPos
= readPosFrac
= 0;
3234 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3237 case AL_SAMPLE_OFFSET
:
3238 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3241 case AL_BYTE_OFFSET
:
3242 if(Buffer
->OriginalType
== UserFmtIMA4
)
3244 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3245 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3246 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3248 /* Round down to nearest ADPCM block */
3249 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3251 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3253 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3254 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3255 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3257 /* Round down to nearest ADPCM block */
3258 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3262 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3263 offset
= (ALdouble
)(readPos
* FrameSize
);
3268 ReadUnlock(&Source
->queue_lock
);
3275 * Apply the stored playback offset to the Source. This function will update
3276 * the number of buffers "played" given the stored offset.
3278 ALboolean
ApplyOffset(ALsource
*Source
)
3280 ALbufferlistitem
*BufferList
;
3281 const ALbuffer
*Buffer
;
3282 ALuint bufferLen
, totalBufferLen
;
3283 ALuint offset
=0, frac
=0;
3285 /* Get sample frame offset */
3286 if(!GetSampleOffset(Source
, &offset
, &frac
))
3290 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3291 while(BufferList
&& totalBufferLen
<= offset
)
3293 Buffer
= BufferList
->buffer
;
3294 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3296 if(bufferLen
> offset
-totalBufferLen
)
3298 /* Offset is in this buffer */
3299 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
3301 ATOMIC_STORE(&Source
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3302 ATOMIC_STORE(&Source
->position_fraction
, frac
, almemory_order_release
);
3306 totalBufferLen
+= bufferLen
;
3308 BufferList
= BufferList
->next
;
3311 /* Offset is out of range of the queue */
3318 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3319 * or Second offset supplied by the application). This takes into account the
3320 * fact that the buffer format may have been modifed since.
3322 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3324 const ALbuffer
*Buffer
= NULL
;
3325 const ALbufferlistitem
*BufferList
;
3326 ALdouble dbloff
, dblfrac
;
3328 /* Find the first valid Buffer in the Queue */
3329 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3332 if(BufferList
->buffer
)
3334 Buffer
= BufferList
->buffer
;
3337 BufferList
= BufferList
->next
;
3341 Source
->OffsetType
= AL_NONE
;
3342 Source
->Offset
= 0.0;
3346 switch(Source
->OffsetType
)
3348 case AL_BYTE_OFFSET
:
3349 /* Determine the ByteOffset (and ensure it is block aligned) */
3350 *offset
= (ALuint
)Source
->Offset
;
3351 if(Buffer
->OriginalType
== UserFmtIMA4
)
3353 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3354 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3355 *offset
*= Buffer
->OriginalAlign
;
3357 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3359 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3360 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3361 *offset
*= Buffer
->OriginalAlign
;
3364 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3368 case AL_SAMPLE_OFFSET
:
3369 dblfrac
= modf(Source
->Offset
, &dbloff
);
3370 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3371 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3375 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3376 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3377 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3380 Source
->OffsetType
= AL_NONE
;
3381 Source
->Offset
= 0.0;
3389 * Destroys all sources in the source map.
3391 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3394 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3396 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3397 Context
->SourceMap
.values
[pos
] = NULL
;
3401 FreeThunkEntry(temp
->id
);
3402 memset(temp
, 0, sizeof(*temp
));