2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
43 extern inline void LockSourcesRead(ALCcontext
*context
);
44 extern inline void UnlockSourcesRead(ALCcontext
*context
);
45 extern inline void LockSourcesWrite(ALCcontext
*context
);
46 extern inline void UnlockSourcesWrite(ALCcontext
*context
);
47 extern inline struct ALsource
*LookupSource(ALCcontext
*context
, ALuint id
);
48 extern inline struct ALsource
*RemoveSource(ALCcontext
*context
, ALuint id
);
50 static void InitSourceParams(ALsource
*Source
);
51 static void DeinitSource(ALsource
*source
);
52 static void UpdateSourceProps(ALsource
*source
, ALuint num_sends
);
53 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
54 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
);
56 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
);
58 typedef enum SourceProp
{
61 srcMinGain
= AL_MIN_GAIN
,
62 srcMaxGain
= AL_MAX_GAIN
,
63 srcMaxDistance
= AL_MAX_DISTANCE
,
64 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
65 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
66 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
67 srcSecOffset
= AL_SEC_OFFSET
,
68 srcSampleOffset
= AL_SAMPLE_OFFSET
,
69 srcByteOffset
= AL_BYTE_OFFSET
,
70 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
71 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
72 srcRefDistance
= AL_REFERENCE_DISTANCE
,
74 srcPosition
= AL_POSITION
,
75 srcVelocity
= AL_VELOCITY
,
76 srcDirection
= AL_DIRECTION
,
78 srcSourceRelative
= AL_SOURCE_RELATIVE
,
79 srcLooping
= AL_LOOPING
,
80 srcBuffer
= AL_BUFFER
,
81 srcSourceState
= AL_SOURCE_STATE
,
82 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
83 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
84 srcSourceType
= AL_SOURCE_TYPE
,
87 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
88 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
89 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
90 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
91 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
92 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
93 srcDirectFilter
= AL_DIRECT_FILTER
,
94 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
96 /* AL_SOFT_direct_channels */
97 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
99 /* AL_EXT_source_distance_model */
100 srcDistanceModel
= AL_DISTANCE_MODEL
,
102 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
103 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
104 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
106 /* AL_SOFT_source_latency */
107 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
108 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
110 /* AL_EXT_STEREO_ANGLES */
111 srcAngles
= AL_STEREO_ANGLES
,
113 /* AL_EXT_SOURCE_RADIUS */
114 srcRadius
= AL_SOURCE_RADIUS
,
117 srcOrientation
= AL_ORIENTATION
,
120 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
121 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
122 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
124 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
125 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
126 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
128 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
130 ALvoice
*voice
= context
->Voices
;
131 ALvoice
*voice_end
= voice
+ context
->VoiceCount
;
132 while(voice
!= voice_end
)
134 if(voice
->Source
== source
)
140 static inline bool SourceShouldUpdate(const ALsource
*source
, const ALCcontext
*context
)
142 return (source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
) &&
143 !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
);
146 static ALint
FloatValsByProp(ALenum prop
)
148 if(prop
!= (ALenum
)((SourceProp
)prop
))
150 switch((SourceProp
)prop
)
156 case AL_MAX_DISTANCE
:
157 case AL_ROLLOFF_FACTOR
:
158 case AL_DOPPLER_FACTOR
:
159 case AL_CONE_OUTER_GAIN
:
161 case AL_SAMPLE_OFFSET
:
163 case AL_CONE_INNER_ANGLE
:
164 case AL_CONE_OUTER_ANGLE
:
165 case AL_REFERENCE_DISTANCE
:
166 case AL_CONE_OUTER_GAINHF
:
167 case AL_AIR_ABSORPTION_FACTOR
:
168 case AL_ROOM_ROLLOFF_FACTOR
:
169 case AL_DIRECT_FILTER_GAINHF_AUTO
:
170 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
171 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
172 case AL_DIRECT_CHANNELS_SOFT
:
173 case AL_DISTANCE_MODEL
:
174 case AL_SOURCE_RELATIVE
:
176 case AL_SOURCE_STATE
:
177 case AL_BUFFERS_QUEUED
:
178 case AL_BUFFERS_PROCESSED
:
180 case AL_BYTE_LENGTH_SOFT
:
181 case AL_SAMPLE_LENGTH_SOFT
:
182 case AL_SEC_LENGTH_SOFT
:
183 case AL_SOURCE_RADIUS
:
186 case AL_STEREO_ANGLES
:
197 case AL_SEC_OFFSET_LATENCY_SOFT
:
198 break; /* Double only */
201 case AL_DIRECT_FILTER
:
202 case AL_AUXILIARY_SEND_FILTER
:
203 break; /* i/i64 only */
204 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
205 break; /* i64 only */
209 static ALint
DoubleValsByProp(ALenum prop
)
211 if(prop
!= (ALenum
)((SourceProp
)prop
))
213 switch((SourceProp
)prop
)
219 case AL_MAX_DISTANCE
:
220 case AL_ROLLOFF_FACTOR
:
221 case AL_DOPPLER_FACTOR
:
222 case AL_CONE_OUTER_GAIN
:
224 case AL_SAMPLE_OFFSET
:
226 case AL_CONE_INNER_ANGLE
:
227 case AL_CONE_OUTER_ANGLE
:
228 case AL_REFERENCE_DISTANCE
:
229 case AL_CONE_OUTER_GAINHF
:
230 case AL_AIR_ABSORPTION_FACTOR
:
231 case AL_ROOM_ROLLOFF_FACTOR
:
232 case AL_DIRECT_FILTER_GAINHF_AUTO
:
233 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
234 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
235 case AL_DIRECT_CHANNELS_SOFT
:
236 case AL_DISTANCE_MODEL
:
237 case AL_SOURCE_RELATIVE
:
239 case AL_SOURCE_STATE
:
240 case AL_BUFFERS_QUEUED
:
241 case AL_BUFFERS_PROCESSED
:
243 case AL_BYTE_LENGTH_SOFT
:
244 case AL_SAMPLE_LENGTH_SOFT
:
245 case AL_SEC_LENGTH_SOFT
:
246 case AL_SOURCE_RADIUS
:
249 case AL_SEC_OFFSET_LATENCY_SOFT
:
250 case AL_STEREO_ANGLES
:
262 case AL_DIRECT_FILTER
:
263 case AL_AUXILIARY_SEND_FILTER
:
264 break; /* i/i64 only */
265 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
266 break; /* i64 only */
271 static ALint
IntValsByProp(ALenum prop
)
273 if(prop
!= (ALenum
)((SourceProp
)prop
))
275 switch((SourceProp
)prop
)
281 case AL_MAX_DISTANCE
:
282 case AL_ROLLOFF_FACTOR
:
283 case AL_DOPPLER_FACTOR
:
284 case AL_CONE_OUTER_GAIN
:
286 case AL_SAMPLE_OFFSET
:
288 case AL_CONE_INNER_ANGLE
:
289 case AL_CONE_OUTER_ANGLE
:
290 case AL_REFERENCE_DISTANCE
:
291 case AL_CONE_OUTER_GAINHF
:
292 case AL_AIR_ABSORPTION_FACTOR
:
293 case AL_ROOM_ROLLOFF_FACTOR
:
294 case AL_DIRECT_FILTER_GAINHF_AUTO
:
295 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
296 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
297 case AL_DIRECT_CHANNELS_SOFT
:
298 case AL_DISTANCE_MODEL
:
299 case AL_SOURCE_RELATIVE
:
302 case AL_SOURCE_STATE
:
303 case AL_BUFFERS_QUEUED
:
304 case AL_BUFFERS_PROCESSED
:
306 case AL_DIRECT_FILTER
:
307 case AL_BYTE_LENGTH_SOFT
:
308 case AL_SAMPLE_LENGTH_SOFT
:
309 case AL_SEC_LENGTH_SOFT
:
310 case AL_SOURCE_RADIUS
:
316 case AL_AUXILIARY_SEND_FILTER
:
322 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
323 break; /* i64 only */
324 case AL_SEC_OFFSET_LATENCY_SOFT
:
325 break; /* Double only */
326 case AL_STEREO_ANGLES
:
327 break; /* Float/double only */
331 static ALint
Int64ValsByProp(ALenum prop
)
333 if(prop
!= (ALenum
)((SourceProp
)prop
))
335 switch((SourceProp
)prop
)
341 case AL_MAX_DISTANCE
:
342 case AL_ROLLOFF_FACTOR
:
343 case AL_DOPPLER_FACTOR
:
344 case AL_CONE_OUTER_GAIN
:
346 case AL_SAMPLE_OFFSET
:
348 case AL_CONE_INNER_ANGLE
:
349 case AL_CONE_OUTER_ANGLE
:
350 case AL_REFERENCE_DISTANCE
:
351 case AL_CONE_OUTER_GAINHF
:
352 case AL_AIR_ABSORPTION_FACTOR
:
353 case AL_ROOM_ROLLOFF_FACTOR
:
354 case AL_DIRECT_FILTER_GAINHF_AUTO
:
355 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
356 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
357 case AL_DIRECT_CHANNELS_SOFT
:
358 case AL_DISTANCE_MODEL
:
359 case AL_SOURCE_RELATIVE
:
362 case AL_SOURCE_STATE
:
363 case AL_BUFFERS_QUEUED
:
364 case AL_BUFFERS_PROCESSED
:
366 case AL_DIRECT_FILTER
:
367 case AL_BYTE_LENGTH_SOFT
:
368 case AL_SAMPLE_LENGTH_SOFT
:
369 case AL_SEC_LENGTH_SOFT
:
370 case AL_SOURCE_RADIUS
:
373 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
379 case AL_AUXILIARY_SEND_FILTER
:
385 case AL_SEC_OFFSET_LATENCY_SOFT
:
386 break; /* Double only */
387 case AL_STEREO_ANGLES
:
388 break; /* Float/double only */
394 #define CHECKVAL(x) do { \
396 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
399 #define DO_UPDATEPROPS() do { \
400 if(SourceShouldUpdate(Source, Context)) \
401 UpdateSourceProps(Source, device->NumAuxSends); \
403 Source->NeedsUpdate = AL_TRUE; \
406 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
408 ALCdevice
*device
= Context
->Device
;
413 case AL_BYTE_LENGTH_SOFT
:
414 case AL_SAMPLE_LENGTH_SOFT
:
415 case AL_SEC_LENGTH_SOFT
:
416 case AL_SEC_OFFSET_LATENCY_SOFT
:
418 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
421 CHECKVAL(*values
>= 0.0f
);
423 Source
->Pitch
= *values
;
427 case AL_CONE_INNER_ANGLE
:
428 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
430 Source
->InnerAngle
= *values
;
434 case AL_CONE_OUTER_ANGLE
:
435 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
437 Source
->OuterAngle
= *values
;
442 CHECKVAL(*values
>= 0.0f
);
444 Source
->Gain
= *values
;
448 case AL_MAX_DISTANCE
:
449 CHECKVAL(*values
>= 0.0f
);
451 Source
->MaxDistance
= *values
;
455 case AL_ROLLOFF_FACTOR
:
456 CHECKVAL(*values
>= 0.0f
);
458 Source
->RollOffFactor
= *values
;
462 case AL_REFERENCE_DISTANCE
:
463 CHECKVAL(*values
>= 0.0f
);
465 Source
->RefDistance
= *values
;
470 CHECKVAL(*values
>= 0.0f
);
472 Source
->MinGain
= *values
;
477 CHECKVAL(*values
>= 0.0f
);
479 Source
->MaxGain
= *values
;
483 case AL_CONE_OUTER_GAIN
:
484 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
486 Source
->OuterGain
= *values
;
490 case AL_CONE_OUTER_GAINHF
:
491 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
493 Source
->OuterGainHF
= *values
;
497 case AL_AIR_ABSORPTION_FACTOR
:
498 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
500 Source
->AirAbsorptionFactor
= *values
;
504 case AL_ROOM_ROLLOFF_FACTOR
:
505 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
507 Source
->RoomRolloffFactor
= *values
;
511 case AL_DOPPLER_FACTOR
:
512 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
514 Source
->DopplerFactor
= *values
;
519 case AL_SAMPLE_OFFSET
:
521 CHECKVAL(*values
>= 0.0f
);
523 Source
->OffsetType
= prop
;
524 Source
->Offset
= *values
;
526 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
527 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
529 LockContext(Context
);
530 WriteLock(&Source
->queue_lock
);
531 if(ApplyOffset(Source
) == AL_FALSE
)
533 WriteUnlock(&Source
->queue_lock
);
534 UnlockContext(Context
);
535 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
537 WriteUnlock(&Source
->queue_lock
);
538 UnlockContext(Context
);
542 case AL_SOURCE_RADIUS
:
543 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
545 Source
->Radius
= *values
;
549 case AL_STEREO_ANGLES
:
550 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
552 Source
->StereoPan
[0] = values
[0];
553 Source
->StereoPan
[1] = values
[1];
559 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
561 Source
->Position
[0] = values
[0];
562 Source
->Position
[1] = values
[1];
563 Source
->Position
[2] = values
[2];
568 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
570 Source
->Velocity
[0] = values
[0];
571 Source
->Velocity
[1] = values
[1];
572 Source
->Velocity
[2] = values
[2];
577 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
579 Source
->Direction
[0] = values
[0];
580 Source
->Direction
[1] = values
[1];
581 Source
->Direction
[2] = values
[2];
586 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
587 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
589 Source
->Orientation
[0][0] = values
[0];
590 Source
->Orientation
[0][1] = values
[1];
591 Source
->Orientation
[0][2] = values
[2];
592 Source
->Orientation
[1][0] = values
[3];
593 Source
->Orientation
[1][1] = values
[4];
594 Source
->Orientation
[1][2] = values
[5];
599 case AL_SOURCE_RELATIVE
:
601 case AL_SOURCE_STATE
:
603 case AL_DISTANCE_MODEL
:
604 case AL_DIRECT_FILTER_GAINHF_AUTO
:
605 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
606 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
607 case AL_DIRECT_CHANNELS_SOFT
:
608 ival
= (ALint
)values
[0];
609 return SetSourceiv(Source
, Context
, prop
, &ival
);
611 case AL_BUFFERS_QUEUED
:
612 case AL_BUFFERS_PROCESSED
:
613 ival
= (ALint
)((ALuint
)values
[0]);
614 return SetSourceiv(Source
, Context
, prop
, &ival
);
617 case AL_DIRECT_FILTER
:
618 case AL_AUXILIARY_SEND_FILTER
:
619 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
623 ERR("Unexpected property: 0x%04x\n", prop
);
624 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
627 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
629 ALCdevice
*device
= Context
->Device
;
630 ALbuffer
*buffer
= NULL
;
631 ALfilter
*filter
= NULL
;
632 ALeffectslot
*slot
= NULL
;
633 ALbufferlistitem
*oldlist
;
634 ALbufferlistitem
*newlist
;
639 case AL_SOURCE_STATE
:
641 case AL_BUFFERS_QUEUED
:
642 case AL_BUFFERS_PROCESSED
:
643 case AL_BYTE_LENGTH_SOFT
:
644 case AL_SAMPLE_LENGTH_SOFT
:
645 case AL_SEC_LENGTH_SOFT
:
647 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
649 case AL_SOURCE_RELATIVE
:
650 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
652 Source
->HeadRelative
= (ALboolean
)*values
;
657 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
659 WriteLock(&Source
->queue_lock
);
660 ATOMIC_STORE(&Source
->looping
, *values
);
661 WriteUnlock(&Source
->queue_lock
);
665 LockBuffersRead(device
);
666 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
668 UnlockBuffersRead(device
);
669 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
672 WriteLock(&Source
->queue_lock
);
673 if(!(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
))
675 WriteUnlock(&Source
->queue_lock
);
676 UnlockBuffersRead(device
);
677 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
682 /* Add the selected buffer to a one-item queue */
683 newlist
= malloc(sizeof(ALbufferlistitem
));
684 newlist
->buffer
= buffer
;
685 newlist
->next
= NULL
;
686 IncrementRef(&buffer
->ref
);
688 /* Source is now Static */
689 Source
->SourceType
= AL_STATIC
;
691 ReadLock(&buffer
->lock
);
692 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
693 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
694 ReadUnlock(&buffer
->lock
);
698 /* Source is now Undetermined */
699 Source
->SourceType
= AL_UNDETERMINED
;
702 oldlist
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &Source
->queue
, newlist
);
703 ATOMIC_STORE(&Source
->current_buffer
, newlist
);
704 WriteUnlock(&Source
->queue_lock
);
705 UnlockBuffersRead(device
);
707 /* Delete all elements in the previous queue */
708 while(oldlist
!= NULL
)
710 ALbufferlistitem
*temp
= oldlist
;
711 oldlist
= temp
->next
;
714 DecrementRef(&temp
->buffer
->ref
);
720 case AL_SAMPLE_OFFSET
:
722 CHECKVAL(*values
>= 0);
724 Source
->OffsetType
= prop
;
725 Source
->Offset
= *values
;
727 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
728 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
730 LockContext(Context
);
731 WriteLock(&Source
->queue_lock
);
732 if(ApplyOffset(Source
) == AL_FALSE
)
734 WriteUnlock(&Source
->queue_lock
);
735 UnlockContext(Context
);
736 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
738 WriteUnlock(&Source
->queue_lock
);
739 UnlockContext(Context
);
743 case AL_DIRECT_FILTER
:
744 LockFiltersRead(device
);
745 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
747 UnlockFiltersRead(device
);
748 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
753 Source
->Direct
.Gain
= 1.0f
;
754 Source
->Direct
.GainHF
= 1.0f
;
755 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
756 Source
->Direct
.GainLF
= 1.0f
;
757 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
761 Source
->Direct
.Gain
= filter
->Gain
;
762 Source
->Direct
.GainHF
= filter
->GainHF
;
763 Source
->Direct
.HFReference
= filter
->HFReference
;
764 Source
->Direct
.GainLF
= filter
->GainLF
;
765 Source
->Direct
.LFReference
= filter
->LFReference
;
767 UnlockFiltersRead(device
);
771 case AL_DIRECT_FILTER_GAINHF_AUTO
:
772 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
774 Source
->DryGainHFAuto
= *values
;
778 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
779 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
781 Source
->WetGainAuto
= *values
;
785 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
786 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
788 Source
->WetGainHFAuto
= *values
;
792 case AL_DIRECT_CHANNELS_SOFT
:
793 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
795 Source
->DirectChannels
= *values
;
799 case AL_DISTANCE_MODEL
:
800 CHECKVAL(*values
== AL_NONE
||
801 *values
== AL_INVERSE_DISTANCE
||
802 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
803 *values
== AL_LINEAR_DISTANCE
||
804 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
805 *values
== AL_EXPONENT_DISTANCE
||
806 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
808 Source
->DistanceModel
= *values
;
809 if(Context
->SourceDistanceModel
)
814 case AL_AUXILIARY_SEND_FILTER
:
815 LockEffectSlotsRead(Context
);
816 LockFiltersRead(device
);
817 if(!((ALuint
)values
[1] < device
->NumAuxSends
&&
818 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
819 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
821 UnlockFiltersRead(device
);
822 UnlockEffectSlotsRead(Context
);
823 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
829 Source
->Send
[values
[1]].Gain
= 1.0f
;
830 Source
->Send
[values
[1]].GainHF
= 1.0f
;
831 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
832 Source
->Send
[values
[1]].GainLF
= 1.0f
;
833 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
837 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
838 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
839 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
840 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
841 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
843 UnlockFiltersRead(device
);
845 if(slot
!= Source
->Send
[values
[1]].Slot
&&
846 (Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
))
848 /* Add refcount on the new slot, and release the previous slot */
849 if(slot
) IncrementRef(&slot
->ref
);
850 if(Source
->Send
[values
[1]].Slot
)
851 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
852 Source
->Send
[values
[1]].Slot
= slot
;
854 /* We must force an update if the auxiliary slot changed on a
855 * playing source, in case the slot is about to be deleted.
857 UpdateSourceProps(Source
, device
->NumAuxSends
);
861 if(slot
) IncrementRef(&slot
->ref
);
862 if(Source
->Send
[values
[1]].Slot
)
863 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
864 Source
->Send
[values
[1]].Slot
= slot
;
867 UnlockEffectSlotsRead(Context
);
873 case AL_CONE_INNER_ANGLE
:
874 case AL_CONE_OUTER_ANGLE
:
879 case AL_REFERENCE_DISTANCE
:
880 case AL_ROLLOFF_FACTOR
:
881 case AL_CONE_OUTER_GAIN
:
882 case AL_MAX_DISTANCE
:
883 case AL_DOPPLER_FACTOR
:
884 case AL_CONE_OUTER_GAINHF
:
885 case AL_AIR_ABSORPTION_FACTOR
:
886 case AL_ROOM_ROLLOFF_FACTOR
:
887 case AL_SOURCE_RADIUS
:
888 fvals
[0] = (ALfloat
)*values
;
889 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
895 fvals
[0] = (ALfloat
)values
[0];
896 fvals
[1] = (ALfloat
)values
[1];
897 fvals
[2] = (ALfloat
)values
[2];
898 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
902 fvals
[0] = (ALfloat
)values
[0];
903 fvals
[1] = (ALfloat
)values
[1];
904 fvals
[2] = (ALfloat
)values
[2];
905 fvals
[3] = (ALfloat
)values
[3];
906 fvals
[4] = (ALfloat
)values
[4];
907 fvals
[5] = (ALfloat
)values
[5];
908 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
910 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
911 case AL_SEC_OFFSET_LATENCY_SOFT
:
912 case AL_STEREO_ANGLES
:
916 ERR("Unexpected property: 0x%04x\n", prop
);
917 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
920 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
928 case AL_BUFFERS_QUEUED
:
929 case AL_BUFFERS_PROCESSED
:
930 case AL_SOURCE_STATE
:
931 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
932 case AL_BYTE_LENGTH_SOFT
:
933 case AL_SAMPLE_LENGTH_SOFT
:
934 case AL_SEC_LENGTH_SOFT
:
936 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
940 case AL_SOURCE_RELATIVE
:
943 case AL_SAMPLE_OFFSET
:
945 case AL_DIRECT_FILTER_GAINHF_AUTO
:
946 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
947 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
948 case AL_DIRECT_CHANNELS_SOFT
:
949 case AL_DISTANCE_MODEL
:
950 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
952 ivals
[0] = (ALint
)*values
;
953 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
957 case AL_DIRECT_FILTER
:
958 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
960 ivals
[0] = (ALuint
)*values
;
961 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
964 case AL_AUXILIARY_SEND_FILTER
:
965 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
966 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
967 values
[2] <= UINT_MAX
&& values
[2] >= 0);
969 ivals
[0] = (ALuint
)values
[0];
970 ivals
[1] = (ALuint
)values
[1];
971 ivals
[2] = (ALuint
)values
[2];
972 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
975 case AL_CONE_INNER_ANGLE
:
976 case AL_CONE_OUTER_ANGLE
:
981 case AL_REFERENCE_DISTANCE
:
982 case AL_ROLLOFF_FACTOR
:
983 case AL_CONE_OUTER_GAIN
:
984 case AL_MAX_DISTANCE
:
985 case AL_DOPPLER_FACTOR
:
986 case AL_CONE_OUTER_GAINHF
:
987 case AL_AIR_ABSORPTION_FACTOR
:
988 case AL_ROOM_ROLLOFF_FACTOR
:
989 case AL_SOURCE_RADIUS
:
990 fvals
[0] = (ALfloat
)*values
;
991 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
997 fvals
[0] = (ALfloat
)values
[0];
998 fvals
[1] = (ALfloat
)values
[1];
999 fvals
[2] = (ALfloat
)values
[2];
1000 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1003 case AL_ORIENTATION
:
1004 fvals
[0] = (ALfloat
)values
[0];
1005 fvals
[1] = (ALfloat
)values
[1];
1006 fvals
[2] = (ALfloat
)values
[2];
1007 fvals
[3] = (ALfloat
)values
[3];
1008 fvals
[4] = (ALfloat
)values
[4];
1009 fvals
[5] = (ALfloat
)values
[5];
1010 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1012 case AL_SEC_OFFSET_LATENCY_SOFT
:
1013 case AL_STEREO_ANGLES
:
1017 ERR("Unexpected property: 0x%04x\n", prop
);
1018 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1024 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1026 ALCdevice
*device
= Context
->Device
;
1027 ALbufferlistitem
*BufferList
;
1028 ClockLatency clocktime
;
1036 *values
= Source
->Gain
;
1040 *values
= Source
->Pitch
;
1043 case AL_MAX_DISTANCE
:
1044 *values
= Source
->MaxDistance
;
1047 case AL_ROLLOFF_FACTOR
:
1048 *values
= Source
->RollOffFactor
;
1051 case AL_REFERENCE_DISTANCE
:
1052 *values
= Source
->RefDistance
;
1055 case AL_CONE_INNER_ANGLE
:
1056 *values
= Source
->InnerAngle
;
1059 case AL_CONE_OUTER_ANGLE
:
1060 *values
= Source
->OuterAngle
;
1064 *values
= Source
->MinGain
;
1068 *values
= Source
->MaxGain
;
1071 case AL_CONE_OUTER_GAIN
:
1072 *values
= Source
->OuterGain
;
1076 case AL_SAMPLE_OFFSET
:
1077 case AL_BYTE_OFFSET
:
1078 *values
= GetSourceOffset(Source
, prop
, device
);
1081 case AL_CONE_OUTER_GAINHF
:
1082 *values
= Source
->OuterGainHF
;
1085 case AL_AIR_ABSORPTION_FACTOR
:
1086 *values
= Source
->AirAbsorptionFactor
;
1089 case AL_ROOM_ROLLOFF_FACTOR
:
1090 *values
= Source
->RoomRolloffFactor
;
1093 case AL_DOPPLER_FACTOR
:
1094 *values
= Source
->DopplerFactor
;
1097 case AL_SEC_LENGTH_SOFT
:
1098 ReadLock(&Source
->queue_lock
);
1099 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1106 ALbuffer
*buffer
= BufferList
->buffer
;
1107 if(buffer
&& buffer
->SampleLen
> 0)
1109 freq
= buffer
->Frequency
;
1110 length
+= buffer
->SampleLen
;
1112 } while((BufferList
=BufferList
->next
) != NULL
);
1113 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1115 ReadUnlock(&Source
->queue_lock
);
1118 case AL_SOURCE_RADIUS
:
1119 *values
= Source
->Radius
;
1122 case AL_STEREO_ANGLES
:
1123 values
[0] = Source
->StereoPan
[0];
1124 values
[1] = Source
->StereoPan
[1];
1127 case AL_SEC_OFFSET_LATENCY_SOFT
:
1128 /* Get the source offset with the clock time first. Then get the
1129 * clock time with the device latency. Order is important.
1131 values
[0] = GetSourceSecOffset(Source
, device
, &srcclock
);
1132 clocktime
= V0(device
->Backend
,getClockLatency
)();
1133 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1134 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1137 /* If the clock time incremented, reduce the latency by that
1138 * much since it's that much closer to the source offset it got
1141 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1142 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1148 values
[0] = Source
->Position
[0];
1149 values
[1] = Source
->Position
[1];
1150 values
[2] = Source
->Position
[2];
1154 values
[0] = Source
->Velocity
[0];
1155 values
[1] = Source
->Velocity
[1];
1156 values
[2] = Source
->Velocity
[2];
1160 values
[0] = Source
->Direction
[0];
1161 values
[1] = Source
->Direction
[1];
1162 values
[2] = Source
->Direction
[2];
1165 case AL_ORIENTATION
:
1166 values
[0] = Source
->Orientation
[0][0];
1167 values
[1] = Source
->Orientation
[0][1];
1168 values
[2] = Source
->Orientation
[0][2];
1169 values
[3] = Source
->Orientation
[1][0];
1170 values
[4] = Source
->Orientation
[1][1];
1171 values
[5] = Source
->Orientation
[1][2];
1175 case AL_SOURCE_RELATIVE
:
1177 case AL_SOURCE_STATE
:
1178 case AL_BUFFERS_QUEUED
:
1179 case AL_BUFFERS_PROCESSED
:
1180 case AL_SOURCE_TYPE
:
1181 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1182 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1183 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1184 case AL_DIRECT_CHANNELS_SOFT
:
1185 case AL_BYTE_LENGTH_SOFT
:
1186 case AL_SAMPLE_LENGTH_SOFT
:
1187 case AL_DISTANCE_MODEL
:
1188 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1189 *values
= (ALdouble
)ivals
[0];
1193 case AL_DIRECT_FILTER
:
1194 case AL_AUXILIARY_SEND_FILTER
:
1195 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1199 ERR("Unexpected property: 0x%04x\n", prop
);
1200 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1203 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1205 ALbufferlistitem
*BufferList
;
1211 case AL_SOURCE_RELATIVE
:
1212 *values
= Source
->HeadRelative
;
1216 *values
= ATOMIC_LOAD(&Source
->looping
);
1220 ReadLock(&Source
->queue_lock
);
1221 BufferList
= (Source
->SourceType
== AL_STATIC
) ? ATOMIC_LOAD(&Source
->queue
) :
1222 ATOMIC_LOAD(&Source
->current_buffer
);
1223 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1224 ReadUnlock(&Source
->queue_lock
);
1227 case AL_SOURCE_STATE
:
1228 *values
= Source
->state
;
1231 case AL_BYTE_LENGTH_SOFT
:
1232 ReadLock(&Source
->queue_lock
);
1233 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1239 ALbuffer
*buffer
= BufferList
->buffer
;
1240 if(buffer
&& buffer
->SampleLen
> 0)
1242 ALuint byte_align
, sample_align
;
1243 if(buffer
->OriginalType
== UserFmtIMA4
)
1245 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1246 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1247 sample_align
= buffer
->OriginalAlign
;
1249 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1251 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1252 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1253 sample_align
= buffer
->OriginalAlign
;
1257 ALsizei align
= buffer
->OriginalAlign
;
1258 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1259 sample_align
= buffer
->OriginalAlign
;
1262 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1264 } while((BufferList
=BufferList
->next
) != NULL
);
1267 ReadUnlock(&Source
->queue_lock
);
1270 case AL_SAMPLE_LENGTH_SOFT
:
1271 ReadLock(&Source
->queue_lock
);
1272 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1278 ALbuffer
*buffer
= BufferList
->buffer
;
1279 if(buffer
) length
+= buffer
->SampleLen
;
1280 } while((BufferList
=BufferList
->next
) != NULL
);
1283 ReadUnlock(&Source
->queue_lock
);
1286 case AL_BUFFERS_QUEUED
:
1287 ReadLock(&Source
->queue_lock
);
1288 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1295 } while((BufferList
=BufferList
->next
) != NULL
);
1298 ReadUnlock(&Source
->queue_lock
);
1301 case AL_BUFFERS_PROCESSED
:
1302 ReadLock(&Source
->queue_lock
);
1303 if(ATOMIC_LOAD(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1305 /* Buffers on a looping source are in a perpetual state of
1306 * PENDING, so don't report any as PROCESSED */
1311 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD(&Source
->queue
);
1312 const ALbufferlistitem
*Current
= ATOMIC_LOAD(&Source
->current_buffer
);
1314 while(BufferList
&& BufferList
!= Current
)
1317 BufferList
= BufferList
->next
;
1321 ReadUnlock(&Source
->queue_lock
);
1324 case AL_SOURCE_TYPE
:
1325 *values
= Source
->SourceType
;
1328 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1329 *values
= Source
->DryGainHFAuto
;
1332 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1333 *values
= Source
->WetGainAuto
;
1336 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1337 *values
= Source
->WetGainHFAuto
;
1340 case AL_DIRECT_CHANNELS_SOFT
:
1341 *values
= Source
->DirectChannels
;
1344 case AL_DISTANCE_MODEL
:
1345 *values
= Source
->DistanceModel
;
1348 /* 1x float/double */
1349 case AL_CONE_INNER_ANGLE
:
1350 case AL_CONE_OUTER_ANGLE
:
1355 case AL_REFERENCE_DISTANCE
:
1356 case AL_ROLLOFF_FACTOR
:
1357 case AL_CONE_OUTER_GAIN
:
1358 case AL_MAX_DISTANCE
:
1360 case AL_SAMPLE_OFFSET
:
1361 case AL_BYTE_OFFSET
:
1362 case AL_DOPPLER_FACTOR
:
1363 case AL_AIR_ABSORPTION_FACTOR
:
1364 case AL_ROOM_ROLLOFF_FACTOR
:
1365 case AL_CONE_OUTER_GAINHF
:
1366 case AL_SEC_LENGTH_SOFT
:
1367 case AL_SOURCE_RADIUS
:
1368 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1369 *values
= (ALint
)dvals
[0];
1372 /* 3x float/double */
1376 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1378 values
[0] = (ALint
)dvals
[0];
1379 values
[1] = (ALint
)dvals
[1];
1380 values
[2] = (ALint
)dvals
[2];
1384 /* 6x float/double */
1385 case AL_ORIENTATION
:
1386 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1388 values
[0] = (ALint
)dvals
[0];
1389 values
[1] = (ALint
)dvals
[1];
1390 values
[2] = (ALint
)dvals
[2];
1391 values
[3] = (ALint
)dvals
[3];
1392 values
[4] = (ALint
)dvals
[4];
1393 values
[5] = (ALint
)dvals
[5];
1397 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1398 break; /* i64 only */
1399 case AL_SEC_OFFSET_LATENCY_SOFT
:
1400 break; /* Double only */
1401 case AL_STEREO_ANGLES
:
1402 break; /* Float/double only */
1404 case AL_DIRECT_FILTER
:
1405 case AL_AUXILIARY_SEND_FILTER
:
1409 ERR("Unexpected property: 0x%04x\n", prop
);
1410 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1413 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1415 ALCdevice
*device
= Context
->Device
;
1416 ClockLatency clocktime
;
1424 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1425 /* Get the source offset with the clock time first. Then get the
1426 * clock time with the device latency. Order is important.
1428 values
[0] = GetSourceSampleOffset(Source
, device
, &srcclock
);
1429 clocktime
= V0(device
->Backend
,getClockLatency
)();
1430 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1431 values
[1] = clocktime
.Latency
;
1434 /* If the clock time incremented, reduce the latency by that
1435 * much since it's that much closer to the source offset it got
1438 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1439 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1443 /* 1x float/double */
1444 case AL_CONE_INNER_ANGLE
:
1445 case AL_CONE_OUTER_ANGLE
:
1450 case AL_REFERENCE_DISTANCE
:
1451 case AL_ROLLOFF_FACTOR
:
1452 case AL_CONE_OUTER_GAIN
:
1453 case AL_MAX_DISTANCE
:
1455 case AL_SAMPLE_OFFSET
:
1456 case AL_BYTE_OFFSET
:
1457 case AL_DOPPLER_FACTOR
:
1458 case AL_AIR_ABSORPTION_FACTOR
:
1459 case AL_ROOM_ROLLOFF_FACTOR
:
1460 case AL_CONE_OUTER_GAINHF
:
1461 case AL_SEC_LENGTH_SOFT
:
1462 case AL_SOURCE_RADIUS
:
1463 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1464 *values
= (ALint64
)dvals
[0];
1467 /* 3x float/double */
1471 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1473 values
[0] = (ALint64
)dvals
[0];
1474 values
[1] = (ALint64
)dvals
[1];
1475 values
[2] = (ALint64
)dvals
[2];
1479 /* 6x float/double */
1480 case AL_ORIENTATION
:
1481 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1483 values
[0] = (ALint64
)dvals
[0];
1484 values
[1] = (ALint64
)dvals
[1];
1485 values
[2] = (ALint64
)dvals
[2];
1486 values
[3] = (ALint64
)dvals
[3];
1487 values
[4] = (ALint64
)dvals
[4];
1488 values
[5] = (ALint64
)dvals
[5];
1493 case AL_SOURCE_RELATIVE
:
1495 case AL_SOURCE_STATE
:
1496 case AL_BUFFERS_QUEUED
:
1497 case AL_BUFFERS_PROCESSED
:
1498 case AL_BYTE_LENGTH_SOFT
:
1499 case AL_SAMPLE_LENGTH_SOFT
:
1500 case AL_SOURCE_TYPE
:
1501 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1502 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1503 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1504 case AL_DIRECT_CHANNELS_SOFT
:
1505 case AL_DISTANCE_MODEL
:
1506 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1512 case AL_DIRECT_FILTER
:
1513 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1514 *values
= (ALuint
)ivals
[0];
1518 case AL_AUXILIARY_SEND_FILTER
:
1519 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1521 values
[0] = (ALuint
)ivals
[0];
1522 values
[1] = (ALuint
)ivals
[1];
1523 values
[2] = (ALuint
)ivals
[2];
1527 case AL_SEC_OFFSET_LATENCY_SOFT
:
1528 break; /* Double only */
1529 case AL_STEREO_ANGLES
:
1530 break; /* Float/double only */
1533 ERR("Unexpected property: 0x%04x\n", prop
);
1534 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1538 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1540 ALCcontext
*context
;
1544 context
= GetContextRef();
1545 if(!context
) return;
1548 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1549 for(cur
= 0;cur
< n
;cur
++)
1551 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1554 alDeleteSources(cur
, sources
);
1555 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1557 InitSourceParams(source
);
1559 err
= NewThunkEntry(&source
->id
);
1560 if(err
== AL_NO_ERROR
)
1561 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1562 if(err
!= AL_NO_ERROR
)
1564 FreeThunkEntry(source
->id
);
1565 memset(source
, 0, sizeof(ALsource
));
1568 alDeleteSources(cur
, sources
);
1569 SET_ERROR_AND_GOTO(context
, err
, done
);
1572 sources
[cur
] = source
->id
;
1576 ALCcontext_DecRef(context
);
1580 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1582 ALCcontext
*context
;
1586 context
= GetContextRef();
1587 if(!context
) return;
1589 LockSourcesWrite(context
);
1591 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1593 /* Check that all Sources are valid */
1594 for(i
= 0;i
< n
;i
++)
1596 if(LookupSource(context
, sources
[i
]) == NULL
)
1597 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1599 for(i
= 0;i
< n
;i
++)
1603 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1605 FreeThunkEntry(Source
->id
);
1607 LockContext(context
);
1608 voice
= GetSourceVoice(Source
, context
);
1609 if(voice
) voice
->Source
= NULL
;
1610 UnlockContext(context
);
1612 DeinitSource(Source
);
1614 memset(Source
, 0, sizeof(*Source
));
1619 UnlockSourcesWrite(context
);
1620 ALCcontext_DecRef(context
);
1624 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1626 ALCcontext
*context
;
1629 context
= GetContextRef();
1630 if(!context
) return AL_FALSE
;
1632 LockSourcesRead(context
);
1633 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1634 UnlockSourcesRead(context
);
1636 ALCcontext_DecRef(context
);
1642 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1644 ALCcontext
*Context
;
1647 Context
= GetContextRef();
1648 if(!Context
) return;
1650 WriteLock(&Context
->PropLock
);
1651 LockSourcesRead(Context
);
1652 if((Source
=LookupSource(Context
, source
)) == NULL
)
1653 alSetError(Context
, AL_INVALID_NAME
);
1654 else if(!(FloatValsByProp(param
) == 1))
1655 alSetError(Context
, AL_INVALID_ENUM
);
1657 SetSourcefv(Source
, Context
, param
, &value
);
1658 UnlockSourcesRead(Context
);
1659 WriteUnlock(&Context
->PropLock
);
1661 ALCcontext_DecRef(Context
);
1664 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1666 ALCcontext
*Context
;
1669 Context
= GetContextRef();
1670 if(!Context
) return;
1672 WriteLock(&Context
->PropLock
);
1673 LockSourcesRead(Context
);
1674 if((Source
=LookupSource(Context
, source
)) == NULL
)
1675 alSetError(Context
, AL_INVALID_NAME
);
1676 else if(!(FloatValsByProp(param
) == 3))
1677 alSetError(Context
, AL_INVALID_ENUM
);
1680 ALfloat fvals
[3] = { value1
, value2
, value3
};
1681 SetSourcefv(Source
, Context
, param
, fvals
);
1683 UnlockSourcesRead(Context
);
1684 WriteUnlock(&Context
->PropLock
);
1686 ALCcontext_DecRef(Context
);
1689 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1691 ALCcontext
*Context
;
1694 Context
= GetContextRef();
1695 if(!Context
) return;
1697 WriteLock(&Context
->PropLock
);
1698 LockSourcesRead(Context
);
1699 if((Source
=LookupSource(Context
, source
)) == NULL
)
1700 alSetError(Context
, AL_INVALID_NAME
);
1702 alSetError(Context
, AL_INVALID_VALUE
);
1703 else if(!(FloatValsByProp(param
) > 0))
1704 alSetError(Context
, AL_INVALID_ENUM
);
1706 SetSourcefv(Source
, Context
, param
, values
);
1707 UnlockSourcesRead(Context
);
1708 WriteUnlock(&Context
->PropLock
);
1710 ALCcontext_DecRef(Context
);
1714 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1716 ALCcontext
*Context
;
1719 Context
= GetContextRef();
1720 if(!Context
) return;
1722 WriteLock(&Context
->PropLock
);
1723 LockSourcesRead(Context
);
1724 if((Source
=LookupSource(Context
, source
)) == NULL
)
1725 alSetError(Context
, AL_INVALID_NAME
);
1726 else if(!(DoubleValsByProp(param
) == 1))
1727 alSetError(Context
, AL_INVALID_ENUM
);
1730 ALfloat fval
= (ALfloat
)value
;
1731 SetSourcefv(Source
, Context
, param
, &fval
);
1733 UnlockSourcesRead(Context
);
1734 WriteUnlock(&Context
->PropLock
);
1736 ALCcontext_DecRef(Context
);
1739 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1741 ALCcontext
*Context
;
1744 Context
= GetContextRef();
1745 if(!Context
) return;
1747 WriteLock(&Context
->PropLock
);
1748 LockSourcesRead(Context
);
1749 if((Source
=LookupSource(Context
, source
)) == NULL
)
1750 alSetError(Context
, AL_INVALID_NAME
);
1751 else if(!(DoubleValsByProp(param
) == 3))
1752 alSetError(Context
, AL_INVALID_ENUM
);
1755 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1756 SetSourcefv(Source
, Context
, param
, fvals
);
1758 UnlockSourcesRead(Context
);
1759 WriteUnlock(&Context
->PropLock
);
1761 ALCcontext_DecRef(Context
);
1764 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1766 ALCcontext
*Context
;
1770 Context
= GetContextRef();
1771 if(!Context
) return;
1773 WriteLock(&Context
->PropLock
);
1774 LockSourcesRead(Context
);
1775 if((Source
=LookupSource(Context
, source
)) == NULL
)
1776 alSetError(Context
, AL_INVALID_NAME
);
1778 alSetError(Context
, AL_INVALID_VALUE
);
1779 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1780 alSetError(Context
, AL_INVALID_ENUM
);
1786 for(i
= 0;i
< count
;i
++)
1787 fvals
[i
] = (ALfloat
)values
[i
];
1788 SetSourcefv(Source
, Context
, param
, fvals
);
1790 UnlockSourcesRead(Context
);
1791 WriteUnlock(&Context
->PropLock
);
1793 ALCcontext_DecRef(Context
);
1797 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1799 ALCcontext
*Context
;
1802 Context
= GetContextRef();
1803 if(!Context
) return;
1805 WriteLock(&Context
->PropLock
);
1806 LockSourcesRead(Context
);
1807 if((Source
=LookupSource(Context
, source
)) == NULL
)
1808 alSetError(Context
, AL_INVALID_NAME
);
1809 else if(!(IntValsByProp(param
) == 1))
1810 alSetError(Context
, AL_INVALID_ENUM
);
1812 SetSourceiv(Source
, Context
, param
, &value
);
1813 UnlockSourcesRead(Context
);
1814 WriteUnlock(&Context
->PropLock
);
1816 ALCcontext_DecRef(Context
);
1819 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1821 ALCcontext
*Context
;
1824 Context
= GetContextRef();
1825 if(!Context
) return;
1827 WriteLock(&Context
->PropLock
);
1828 LockSourcesRead(Context
);
1829 if((Source
=LookupSource(Context
, source
)) == NULL
)
1830 alSetError(Context
, AL_INVALID_NAME
);
1831 else if(!(IntValsByProp(param
) == 3))
1832 alSetError(Context
, AL_INVALID_ENUM
);
1835 ALint ivals
[3] = { value1
, value2
, value3
};
1836 SetSourceiv(Source
, Context
, param
, ivals
);
1838 UnlockSourcesRead(Context
);
1839 WriteUnlock(&Context
->PropLock
);
1841 ALCcontext_DecRef(Context
);
1844 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1846 ALCcontext
*Context
;
1849 Context
= GetContextRef();
1850 if(!Context
) return;
1852 WriteLock(&Context
->PropLock
);
1853 LockSourcesRead(Context
);
1854 if((Source
=LookupSource(Context
, source
)) == NULL
)
1855 alSetError(Context
, AL_INVALID_NAME
);
1857 alSetError(Context
, AL_INVALID_VALUE
);
1858 else if(!(IntValsByProp(param
) > 0))
1859 alSetError(Context
, AL_INVALID_ENUM
);
1861 SetSourceiv(Source
, Context
, param
, values
);
1862 UnlockSourcesRead(Context
);
1863 WriteUnlock(&Context
->PropLock
);
1865 ALCcontext_DecRef(Context
);
1869 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1871 ALCcontext
*Context
;
1874 Context
= GetContextRef();
1875 if(!Context
) return;
1877 WriteLock(&Context
->PropLock
);
1878 LockSourcesRead(Context
);
1879 if((Source
=LookupSource(Context
, source
)) == NULL
)
1880 alSetError(Context
, AL_INVALID_NAME
);
1881 else if(!(Int64ValsByProp(param
) == 1))
1882 alSetError(Context
, AL_INVALID_ENUM
);
1884 SetSourcei64v(Source
, Context
, param
, &value
);
1885 UnlockSourcesRead(Context
);
1886 WriteUnlock(&Context
->PropLock
);
1888 ALCcontext_DecRef(Context
);
1891 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1893 ALCcontext
*Context
;
1896 Context
= GetContextRef();
1897 if(!Context
) return;
1899 WriteLock(&Context
->PropLock
);
1900 LockSourcesRead(Context
);
1901 if((Source
=LookupSource(Context
, source
)) == NULL
)
1902 alSetError(Context
, AL_INVALID_NAME
);
1903 else if(!(Int64ValsByProp(param
) == 3))
1904 alSetError(Context
, AL_INVALID_ENUM
);
1907 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1908 SetSourcei64v(Source
, Context
, param
, i64vals
);
1910 UnlockSourcesRead(Context
);
1911 WriteUnlock(&Context
->PropLock
);
1913 ALCcontext_DecRef(Context
);
1916 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1918 ALCcontext
*Context
;
1921 Context
= GetContextRef();
1922 if(!Context
) return;
1924 WriteLock(&Context
->PropLock
);
1925 LockSourcesRead(Context
);
1926 if((Source
=LookupSource(Context
, source
)) == NULL
)
1927 alSetError(Context
, AL_INVALID_NAME
);
1929 alSetError(Context
, AL_INVALID_VALUE
);
1930 else if(!(Int64ValsByProp(param
) > 0))
1931 alSetError(Context
, AL_INVALID_ENUM
);
1933 SetSourcei64v(Source
, Context
, param
, values
);
1934 UnlockSourcesRead(Context
);
1935 WriteUnlock(&Context
->PropLock
);
1937 ALCcontext_DecRef(Context
);
1941 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1943 ALCcontext
*Context
;
1946 Context
= GetContextRef();
1947 if(!Context
) return;
1949 ReadLock(&Context
->PropLock
);
1950 LockSourcesRead(Context
);
1951 if((Source
=LookupSource(Context
, source
)) == NULL
)
1952 alSetError(Context
, AL_INVALID_NAME
);
1954 alSetError(Context
, AL_INVALID_VALUE
);
1955 else if(!(FloatValsByProp(param
) == 1))
1956 alSetError(Context
, AL_INVALID_ENUM
);
1960 if(GetSourcedv(Source
, Context
, param
, &dval
))
1961 *value
= (ALfloat
)dval
;
1963 UnlockSourcesRead(Context
);
1964 ReadUnlock(&Context
->PropLock
);
1966 ALCcontext_DecRef(Context
);
1970 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1972 ALCcontext
*Context
;
1975 Context
= GetContextRef();
1976 if(!Context
) return;
1978 ReadLock(&Context
->PropLock
);
1979 LockSourcesRead(Context
);
1980 if((Source
=LookupSource(Context
, source
)) == NULL
)
1981 alSetError(Context
, AL_INVALID_NAME
);
1982 else if(!(value1
&& value2
&& value3
))
1983 alSetError(Context
, AL_INVALID_VALUE
);
1984 else if(!(FloatValsByProp(param
) == 3))
1985 alSetError(Context
, AL_INVALID_ENUM
);
1989 if(GetSourcedv(Source
, Context
, param
, dvals
))
1991 *value1
= (ALfloat
)dvals
[0];
1992 *value2
= (ALfloat
)dvals
[1];
1993 *value3
= (ALfloat
)dvals
[2];
1996 UnlockSourcesRead(Context
);
1997 ReadUnlock(&Context
->PropLock
);
1999 ALCcontext_DecRef(Context
);
2003 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2005 ALCcontext
*Context
;
2009 Context
= GetContextRef();
2010 if(!Context
) return;
2012 ReadLock(&Context
->PropLock
);
2013 LockSourcesRead(Context
);
2014 if((Source
=LookupSource(Context
, source
)) == NULL
)
2015 alSetError(Context
, AL_INVALID_NAME
);
2017 alSetError(Context
, AL_INVALID_VALUE
);
2018 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2019 alSetError(Context
, AL_INVALID_ENUM
);
2023 if(GetSourcedv(Source
, Context
, param
, dvals
))
2026 for(i
= 0;i
< count
;i
++)
2027 values
[i
] = (ALfloat
)dvals
[i
];
2030 UnlockSourcesRead(Context
);
2031 ReadUnlock(&Context
->PropLock
);
2033 ALCcontext_DecRef(Context
);
2037 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2039 ALCcontext
*Context
;
2042 Context
= GetContextRef();
2043 if(!Context
) return;
2045 ReadLock(&Context
->PropLock
);
2046 LockSourcesRead(Context
);
2047 if((Source
=LookupSource(Context
, source
)) == NULL
)
2048 alSetError(Context
, AL_INVALID_NAME
);
2050 alSetError(Context
, AL_INVALID_VALUE
);
2051 else if(!(DoubleValsByProp(param
) == 1))
2052 alSetError(Context
, AL_INVALID_ENUM
);
2054 GetSourcedv(Source
, Context
, param
, value
);
2055 UnlockSourcesRead(Context
);
2056 ReadUnlock(&Context
->PropLock
);
2058 ALCcontext_DecRef(Context
);
2061 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2063 ALCcontext
*Context
;
2066 Context
= GetContextRef();
2067 if(!Context
) return;
2069 ReadLock(&Context
->PropLock
);
2070 LockSourcesRead(Context
);
2071 if((Source
=LookupSource(Context
, source
)) == NULL
)
2072 alSetError(Context
, AL_INVALID_NAME
);
2073 else if(!(value1
&& value2
&& value3
))
2074 alSetError(Context
, AL_INVALID_VALUE
);
2075 else if(!(DoubleValsByProp(param
) == 3))
2076 alSetError(Context
, AL_INVALID_ENUM
);
2080 if(GetSourcedv(Source
, Context
, param
, dvals
))
2087 UnlockSourcesRead(Context
);
2088 ReadUnlock(&Context
->PropLock
);
2090 ALCcontext_DecRef(Context
);
2093 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2095 ALCcontext
*Context
;
2098 Context
= GetContextRef();
2099 if(!Context
) return;
2101 ReadLock(&Context
->PropLock
);
2102 LockSourcesRead(Context
);
2103 if((Source
=LookupSource(Context
, source
)) == NULL
)
2104 alSetError(Context
, AL_INVALID_NAME
);
2106 alSetError(Context
, AL_INVALID_VALUE
);
2107 else if(!(DoubleValsByProp(param
) > 0))
2108 alSetError(Context
, AL_INVALID_ENUM
);
2110 GetSourcedv(Source
, Context
, param
, values
);
2111 UnlockSourcesRead(Context
);
2112 ReadUnlock(&Context
->PropLock
);
2114 ALCcontext_DecRef(Context
);
2118 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2120 ALCcontext
*Context
;
2123 Context
= GetContextRef();
2124 if(!Context
) return;
2126 ReadLock(&Context
->PropLock
);
2127 LockSourcesRead(Context
);
2128 if((Source
=LookupSource(Context
, source
)) == NULL
)
2129 alSetError(Context
, AL_INVALID_NAME
);
2131 alSetError(Context
, AL_INVALID_VALUE
);
2132 else if(!(IntValsByProp(param
) == 1))
2133 alSetError(Context
, AL_INVALID_ENUM
);
2135 GetSourceiv(Source
, Context
, param
, value
);
2136 UnlockSourcesRead(Context
);
2137 ReadUnlock(&Context
->PropLock
);
2139 ALCcontext_DecRef(Context
);
2143 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2145 ALCcontext
*Context
;
2148 Context
= GetContextRef();
2149 if(!Context
) return;
2151 ReadLock(&Context
->PropLock
);
2152 LockSourcesRead(Context
);
2153 if((Source
=LookupSource(Context
, source
)) == NULL
)
2154 alSetError(Context
, AL_INVALID_NAME
);
2155 else if(!(value1
&& value2
&& value3
))
2156 alSetError(Context
, AL_INVALID_VALUE
);
2157 else if(!(IntValsByProp(param
) == 3))
2158 alSetError(Context
, AL_INVALID_ENUM
);
2162 if(GetSourceiv(Source
, Context
, param
, ivals
))
2169 UnlockSourcesRead(Context
);
2170 ReadUnlock(&Context
->PropLock
);
2172 ALCcontext_DecRef(Context
);
2176 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2178 ALCcontext
*Context
;
2181 Context
= GetContextRef();
2182 if(!Context
) return;
2184 ReadLock(&Context
->PropLock
);
2185 LockSourcesRead(Context
);
2186 if((Source
=LookupSource(Context
, source
)) == NULL
)
2187 alSetError(Context
, AL_INVALID_NAME
);
2189 alSetError(Context
, AL_INVALID_VALUE
);
2190 else if(!(IntValsByProp(param
) > 0))
2191 alSetError(Context
, AL_INVALID_ENUM
);
2193 GetSourceiv(Source
, Context
, param
, values
);
2194 UnlockSourcesRead(Context
);
2195 ReadUnlock(&Context
->PropLock
);
2197 ALCcontext_DecRef(Context
);
2201 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2203 ALCcontext
*Context
;
2206 Context
= GetContextRef();
2207 if(!Context
) return;
2209 ReadLock(&Context
->PropLock
);
2210 LockSourcesRead(Context
);
2211 if((Source
=LookupSource(Context
, source
)) == NULL
)
2212 alSetError(Context
, AL_INVALID_NAME
);
2214 alSetError(Context
, AL_INVALID_VALUE
);
2215 else if(!(Int64ValsByProp(param
) == 1))
2216 alSetError(Context
, AL_INVALID_ENUM
);
2218 GetSourcei64v(Source
, Context
, param
, value
);
2219 UnlockSourcesRead(Context
);
2220 ReadUnlock(&Context
->PropLock
);
2222 ALCcontext_DecRef(Context
);
2225 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2227 ALCcontext
*Context
;
2230 Context
= GetContextRef();
2231 if(!Context
) return;
2233 ReadLock(&Context
->PropLock
);
2234 LockSourcesRead(Context
);
2235 if((Source
=LookupSource(Context
, source
)) == NULL
)
2236 alSetError(Context
, AL_INVALID_NAME
);
2237 else if(!(value1
&& value2
&& value3
))
2238 alSetError(Context
, AL_INVALID_VALUE
);
2239 else if(!(Int64ValsByProp(param
) == 3))
2240 alSetError(Context
, AL_INVALID_ENUM
);
2244 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2246 *value1
= i64vals
[0];
2247 *value2
= i64vals
[1];
2248 *value3
= i64vals
[2];
2251 UnlockSourcesRead(Context
);
2252 ReadUnlock(&Context
->PropLock
);
2254 ALCcontext_DecRef(Context
);
2257 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2259 ALCcontext
*Context
;
2262 Context
= GetContextRef();
2263 if(!Context
) return;
2265 ReadLock(&Context
->PropLock
);
2266 LockSourcesRead(Context
);
2267 if((Source
=LookupSource(Context
, source
)) == NULL
)
2268 alSetError(Context
, AL_INVALID_NAME
);
2270 alSetError(Context
, AL_INVALID_VALUE
);
2271 else if(!(Int64ValsByProp(param
) > 0))
2272 alSetError(Context
, AL_INVALID_ENUM
);
2274 GetSourcei64v(Source
, Context
, param
, values
);
2275 UnlockSourcesRead(Context
);
2276 ReadUnlock(&Context
->PropLock
);
2278 ALCcontext_DecRef(Context
);
2282 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2284 alSourcePlayv(1, &source
);
2286 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2288 ALCcontext
*context
;
2292 context
= GetContextRef();
2293 if(!context
) return;
2295 LockSourcesRead(context
);
2297 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2298 for(i
= 0;i
< n
;i
++)
2300 if(!LookupSource(context
, sources
[i
]))
2301 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2304 LockContext(context
);
2305 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2307 ALvoice
*temp
= NULL
;
2310 newcount
= context
->MaxVoices
<< 1;
2312 temp
= al_malloc(16, newcount
* sizeof(context
->Voices
[0]));
2315 UnlockContext(context
);
2316 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2318 memcpy(temp
, context
->Voices
, context
->MaxVoices
* sizeof(temp
[0]));
2319 memset(&temp
[context
->MaxVoices
], 0, (newcount
-context
->MaxVoices
) * sizeof(temp
[0]));
2321 al_free(context
->Voices
);
2322 context
->Voices
= temp
;
2323 context
->MaxVoices
= newcount
;
2326 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) == DeferAll
)
2328 for(i
= 0;i
< n
;i
++)
2330 source
= LookupSource(context
, sources
[i
]);
2331 source
->new_state
= AL_PLAYING
;
2336 for(i
= 0;i
< n
;i
++)
2338 source
= LookupSource(context
, sources
[i
]);
2339 SetSourceState(source
, context
, AL_PLAYING
);
2342 UnlockContext(context
);
2345 UnlockSourcesRead(context
);
2346 ALCcontext_DecRef(context
);
2349 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2351 alSourcePausev(1, &source
);
2353 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2355 ALCcontext
*context
;
2359 context
= GetContextRef();
2360 if(!context
) return;
2362 LockSourcesRead(context
);
2364 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2365 for(i
= 0;i
< n
;i
++)
2367 if(!LookupSource(context
, sources
[i
]))
2368 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2371 LockContext(context
);
2372 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2374 for(i
= 0;i
< n
;i
++)
2376 source
= LookupSource(context
, sources
[i
]);
2377 source
->new_state
= AL_PAUSED
;
2382 for(i
= 0;i
< n
;i
++)
2384 source
= LookupSource(context
, sources
[i
]);
2385 SetSourceState(source
, context
, AL_PAUSED
);
2388 UnlockContext(context
);
2391 UnlockSourcesRead(context
);
2392 ALCcontext_DecRef(context
);
2395 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2397 alSourceStopv(1, &source
);
2399 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2401 ALCcontext
*context
;
2405 context
= GetContextRef();
2406 if(!context
) return;
2408 LockSourcesRead(context
);
2410 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2411 for(i
= 0;i
< n
;i
++)
2413 if(!LookupSource(context
, sources
[i
]))
2414 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2417 LockContext(context
);
2418 for(i
= 0;i
< n
;i
++)
2420 source
= LookupSource(context
, sources
[i
]);
2421 source
->new_state
= AL_NONE
;
2422 SetSourceState(source
, context
, AL_STOPPED
);
2424 UnlockContext(context
);
2427 UnlockSourcesRead(context
);
2428 ALCcontext_DecRef(context
);
2431 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2433 alSourceRewindv(1, &source
);
2435 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2437 ALCcontext
*context
;
2441 context
= GetContextRef();
2442 if(!context
) return;
2444 LockSourcesRead(context
);
2446 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2447 for(i
= 0;i
< n
;i
++)
2449 if(!LookupSource(context
, sources
[i
]))
2450 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2453 LockContext(context
);
2454 for(i
= 0;i
< n
;i
++)
2456 source
= LookupSource(context
, sources
[i
]);
2457 source
->new_state
= AL_NONE
;
2458 SetSourceState(source
, context
, AL_INITIAL
);
2460 UnlockContext(context
);
2463 UnlockSourcesRead(context
);
2464 ALCcontext_DecRef(context
);
2468 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2471 ALCcontext
*context
;
2474 ALbufferlistitem
*BufferListStart
;
2475 ALbufferlistitem
*BufferList
;
2476 ALbuffer
*BufferFmt
= NULL
;
2481 context
= GetContextRef();
2482 if(!context
) return;
2484 device
= context
->Device
;
2486 LockSourcesRead(context
);
2488 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2489 if((source
=LookupSource(context
, src
)) == NULL
)
2490 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2492 WriteLock(&source
->queue_lock
);
2493 if(source
->SourceType
== AL_STATIC
)
2495 WriteUnlock(&source
->queue_lock
);
2496 /* Can't queue on a Static Source */
2497 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2500 /* Check for a valid Buffer, for its frequency and format */
2501 BufferList
= ATOMIC_LOAD(&source
->queue
);
2504 if(BufferList
->buffer
)
2506 BufferFmt
= BufferList
->buffer
;
2509 BufferList
= BufferList
->next
;
2512 LockBuffersRead(device
);
2513 BufferListStart
= NULL
;
2515 for(i
= 0;i
< nb
;i
++)
2517 ALbuffer
*buffer
= NULL
;
2518 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2520 WriteUnlock(&source
->queue_lock
);
2521 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2524 if(!BufferListStart
)
2526 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2527 BufferList
= BufferListStart
;
2531 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2532 BufferList
= BufferList
->next
;
2534 BufferList
->buffer
= buffer
;
2535 BufferList
->next
= NULL
;
2536 if(!buffer
) continue;
2538 /* Hold a read lock on each buffer being queued while checking all
2539 * provided buffers. This is done so other threads don't see an extra
2540 * reference on some buffers if this operation ends up failing. */
2541 ReadLock(&buffer
->lock
);
2542 IncrementRef(&buffer
->ref
);
2544 if(BufferFmt
== NULL
)
2548 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2549 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2551 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2552 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2553 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2555 WriteUnlock(&source
->queue_lock
);
2556 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2559 /* A buffer failed (invalid ID or format), so unlock and release
2560 * each buffer we had. */
2561 while(BufferListStart
)
2563 ALbufferlistitem
*next
= BufferListStart
->next
;
2564 if((buffer
=BufferListStart
->buffer
) != NULL
)
2566 DecrementRef(&buffer
->ref
);
2567 ReadUnlock(&buffer
->lock
);
2569 free(BufferListStart
);
2570 BufferListStart
= next
;
2572 UnlockBuffersRead(device
);
2576 /* All buffers good, unlock them now. */
2577 BufferList
= BufferListStart
;
2578 while(BufferList
!= NULL
)
2580 ALbuffer
*buffer
= BufferList
->buffer
;
2581 if(buffer
) ReadUnlock(&buffer
->lock
);
2582 BufferList
= BufferList
->next
;
2584 UnlockBuffersRead(device
);
2586 /* Source is now streaming */
2587 source
->SourceType
= AL_STREAMING
;
2590 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->queue
, &BufferList
, BufferListStart
))
2592 /* Queue head is not NULL, append to the end of the queue */
2593 while(BufferList
->next
!= NULL
)
2594 BufferList
= BufferList
->next
;
2595 BufferList
->next
= BufferListStart
;
2597 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2601 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->current_buffer
, &BufferList
, BufferListStart
);
2602 WriteUnlock(&source
->queue_lock
);
2605 UnlockSourcesRead(context
);
2606 ALCcontext_DecRef(context
);
2609 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2611 ALCcontext
*context
;
2613 ALbufferlistitem
*OldHead
;
2614 ALbufferlistitem
*OldTail
;
2615 ALbufferlistitem
*Current
;
2621 context
= GetContextRef();
2622 if(!context
) return;
2624 LockSourcesRead(context
);
2626 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2628 if((source
=LookupSource(context
, src
)) == NULL
)
2629 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2631 WriteLock(&source
->queue_lock
);
2632 if(ATOMIC_LOAD(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2634 WriteUnlock(&source
->queue_lock
);
2635 /* Trying to unqueue buffers on a looping or non-streaming source. */
2636 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2639 /* Find the new buffer queue head */
2640 OldTail
= ATOMIC_LOAD(&source
->queue
);
2641 Current
= ATOMIC_LOAD(&source
->current_buffer
);
2642 if(OldTail
!= Current
)
2644 for(i
= 1;i
< nb
;i
++)
2646 ALbufferlistitem
*next
= OldTail
->next
;
2647 if(!next
|| next
== Current
) break;
2653 WriteUnlock(&source
->queue_lock
);
2654 /* Trying to unqueue pending buffers. */
2655 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2658 /* Swap it, and cut the new head from the old. */
2659 OldHead
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2662 ALCdevice
*device
= context
->Device
;
2665 /* Once the active mix (if any) is done, it's safe to cut the old tail
2666 * from the new head.
2668 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2670 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2673 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2674 OldTail
->next
= NULL
;
2676 WriteUnlock(&source
->queue_lock
);
2678 while(OldHead
!= NULL
)
2680 ALbufferlistitem
*next
= OldHead
->next
;
2681 ALbuffer
*buffer
= OldHead
->buffer
;
2687 *(buffers
++) = buffer
->id
;
2688 DecrementRef(&buffer
->ref
);
2696 UnlockSourcesRead(context
);
2697 ALCcontext_DecRef(context
);
2701 static void InitSourceParams(ALsource
*Source
)
2705 RWLockInit(&Source
->queue_lock
);
2707 Source
->InnerAngle
= 360.0f
;
2708 Source
->OuterAngle
= 360.0f
;
2709 Source
->Pitch
= 1.0f
;
2710 Source
->Position
[0] = 0.0f
;
2711 Source
->Position
[1] = 0.0f
;
2712 Source
->Position
[2] = 0.0f
;
2713 Source
->Velocity
[0] = 0.0f
;
2714 Source
->Velocity
[1] = 0.0f
;
2715 Source
->Velocity
[2] = 0.0f
;
2716 Source
->Direction
[0] = 0.0f
;
2717 Source
->Direction
[1] = 0.0f
;
2718 Source
->Direction
[2] = 0.0f
;
2719 Source
->Orientation
[0][0] = 0.0f
;
2720 Source
->Orientation
[0][1] = 0.0f
;
2721 Source
->Orientation
[0][2] = -1.0f
;
2722 Source
->Orientation
[1][0] = 0.0f
;
2723 Source
->Orientation
[1][1] = 1.0f
;
2724 Source
->Orientation
[1][2] = 0.0f
;
2725 Source
->RefDistance
= 1.0f
;
2726 Source
->MaxDistance
= FLT_MAX
;
2727 Source
->RollOffFactor
= 1.0f
;
2728 Source
->Gain
= 1.0f
;
2729 Source
->MinGain
= 0.0f
;
2730 Source
->MaxGain
= 1.0f
;
2731 Source
->OuterGain
= 0.0f
;
2732 Source
->OuterGainHF
= 1.0f
;
2734 Source
->DryGainHFAuto
= AL_TRUE
;
2735 Source
->WetGainAuto
= AL_TRUE
;
2736 Source
->WetGainHFAuto
= AL_TRUE
;
2737 Source
->AirAbsorptionFactor
= 0.0f
;
2738 Source
->RoomRolloffFactor
= 0.0f
;
2739 Source
->DopplerFactor
= 1.0f
;
2740 Source
->DirectChannels
= AL_FALSE
;
2742 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2743 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2745 Source
->Radius
= 0.0f
;
2747 Source
->DistanceModel
= DefaultDistanceModel
;
2749 Source
->Direct
.Gain
= 1.0f
;
2750 Source
->Direct
.GainHF
= 1.0f
;
2751 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2752 Source
->Direct
.GainLF
= 1.0f
;
2753 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2754 for(i
= 0;i
< MAX_SENDS
;i
++)
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 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
)
2785 ALbufferlistitem
*BufferList
;
2786 struct ALsourceProps
*props
;
2790 props
= ATOMIC_LOAD(&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(ALbufferlistitem
*, &source
->queue
, NULL
);
2809 while(BufferList
!= NULL
)
2811 ALbufferlistitem
*next
= BufferList
->next
;
2812 if(BufferList
->buffer
!= NULL
)
2813 DecrementRef(&BufferList
->buffer
->ref
);
2818 for(i
= 0;i
< MAX_SENDS
;++i
)
2820 if(source
->Send
[i
].Slot
)
2821 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2822 source
->Send
[i
].Slot
= NULL
;
2826 static void UpdateSourceProps(ALsource
*source
, ALuint num_sends
)
2828 struct ALsourceProps
*props
;
2831 /* Get an unused property container, or allocate a new one as needed. */
2832 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2834 props
= al_calloc(16, sizeof(*props
));
2837 struct ALsourceProps
*next
;
2839 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2840 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2841 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
2842 almemory_order_acquire
) == 0);
2845 /* Copy in current property values. */
2846 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2847 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2848 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2849 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2850 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2851 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2852 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2853 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2854 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2855 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2856 for(i
= 0;i
< 3;i
++)
2857 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2858 for(i
= 0;i
< 3;i
++)
2859 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2860 for(i
= 0;i
< 3;i
++)
2861 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2862 for(i
= 0;i
< 2;i
++)
2865 for(j
= 0;j
< 3;j
++)
2866 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2867 almemory_order_relaxed
);
2869 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2870 ATOMIC_STORE(&props
->DistanceModel
, source
->DistanceModel
, almemory_order_relaxed
);
2871 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2873 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2874 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2875 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2876 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2878 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2879 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2880 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2882 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2883 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2885 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2887 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2888 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2889 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2890 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2891 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2893 for(i
= 0;i
< num_sends
;i
++)
2895 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2896 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2897 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2898 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2899 almemory_order_relaxed
);
2900 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2901 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2902 almemory_order_relaxed
);
2905 /* Set the new container for updating internal parameters. */
2906 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2909 /* If there was an unused update container, put it back in the
2912 struct ALsourceProps
*first
= ATOMIC_LOAD(&source
->FreeList
);
2914 ATOMIC_STORE(&props
->next
, first
, almemory_order_relaxed
);
2915 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2916 &source
->FreeList
, &first
, props
, almemory_order_acq_rel
,
2917 almemory_order_acquire
) == 0);
2921 void UpdateAllSourceProps(ALCcontext
*context
)
2923 ALuint 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
->state
== AL_PLAYING
||
2931 source
->state
== AL_PAUSED
) &&
2932 source
->NeedsUpdate
)
2934 source
->NeedsUpdate
= AL_FALSE
;
2935 UpdateSourceProps(source
, num_sends
);
2943 * Sets the source's new play state given its current state.
2945 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2947 WriteLock(&Source
->queue_lock
);
2948 if(state
== AL_PLAYING
)
2950 ALCdevice
*device
= Context
->Device
;
2951 ALbufferlistitem
*BufferList
;
2952 ALboolean discontinuity
;
2953 ALvoice
*voice
= NULL
;
2956 /* Check that there is a queue containing at least one valid, non zero
2958 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2962 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2964 BufferList
= BufferList
->next
;
2967 if(Source
->state
!= AL_PAUSED
)
2969 Source
->state
= AL_PLAYING
;
2970 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
2971 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
2972 ATOMIC_STORE(&Source
->position_fraction
, 0, almemory_order_release
);
2973 discontinuity
= AL_TRUE
;
2977 Source
->state
= AL_PLAYING
;
2978 discontinuity
= AL_FALSE
;
2981 // Check if an Offset has been set
2982 if(Source
->OffsetType
!= AL_NONE
)
2984 ApplyOffset(Source
);
2985 /* discontinuity = AL_TRUE;??? */
2988 /* If there's nothing to play, or device is disconnected, go right to
2990 if(!BufferList
|| !device
->Connected
)
2993 /* Make sure this source isn't already active, and if not, look for an
2994 * unused voice to put it in.
2996 voice
= GetSourceVoice(Source
, Context
);
2999 for(i
= 0;i
< Context
->VoiceCount
;i
++)
3001 if(Context
->Voices
[i
].Source
== NULL
)
3003 voice
= &Context
->Voices
[i
];
3004 voice
->Source
= Source
;
3010 voice
= &Context
->Voices
[Context
->VoiceCount
++];
3011 voice
->Source
= Source
;
3013 discontinuity
= AL_TRUE
;
3018 /* Clear previous samples if playback is discontinuous. */
3019 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
3021 /* Clear the stepping value so the mixer knows not to mix this
3022 * until the update gets applied.
3027 voice
->Moving
= AL_FALSE
;
3028 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
3031 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
3032 voice
->Chan
[i
].Direct
.Hrtf
.State
.History
[j
] = 0.0f
;
3033 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3035 voice
->Chan
[i
].Direct
.Hrtf
.State
.Values
[j
][0] = 0.0f
;
3036 voice
->Chan
[i
].Direct
.Hrtf
.State
.Values
[j
][1] = 0.0f
;
3040 Source
->NeedsUpdate
= AL_FALSE
;
3041 UpdateSourceProps(Source
, device
->NumAuxSends
);
3043 else if(state
== AL_PAUSED
)
3045 if(Source
->state
== AL_PLAYING
)
3046 Source
->state
= AL_PAUSED
;
3048 else if(state
== AL_STOPPED
)
3051 if(Source
->state
!= AL_INITIAL
)
3053 Source
->state
= AL_STOPPED
;
3054 ATOMIC_STORE(&Source
->current_buffer
, NULL
);
3056 Source
->OffsetType
= AL_NONE
;
3057 Source
->Offset
= 0.0;
3059 else if(state
== AL_INITIAL
)
3061 if(Source
->state
!= AL_INITIAL
)
3063 Source
->state
= AL_INITIAL
;
3064 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD(&Source
->queue
),
3065 almemory_order_relaxed
);
3066 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
3067 ATOMIC_STORE(&Source
->position_fraction
, 0);
3069 Source
->OffsetType
= AL_NONE
;
3070 Source
->Offset
= 0.0;
3072 WriteUnlock(&Source
->queue_lock
);
3075 /* GetSourceSampleOffset
3077 * Gets the current read offset for the given Source, in 32.32 fixed-point
3078 * samples. The offset is relative to the start of the queue (not the start of
3079 * the current buffer).
3081 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3083 const ALbufferlistitem
*BufferList
;
3084 const ALbufferlistitem
*Current
;
3088 ReadLock(&Source
->queue_lock
);
3089 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3091 ReadUnlock(&Source
->queue_lock
);
3093 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3095 *clocktime
= GetDeviceClockTime(device
);
3096 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3097 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3102 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3104 *clocktime
= GetDeviceClockTime(device
);
3106 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3107 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3109 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) << 32;
3110 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
) <<
3112 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3113 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3114 while(BufferList
&& BufferList
!= Current
)
3116 if(BufferList
->buffer
)
3117 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3118 BufferList
= BufferList
->next
;
3121 ReadUnlock(&Source
->queue_lock
);
3122 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
3125 /* GetSourceSecOffset
3127 * Gets the current read offset for the given Source, in seconds. The offset is
3128 * relative to the start of the queue (not the start of the current buffer).
3130 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3132 const ALbufferlistitem
*BufferList
;
3133 const ALbufferlistitem
*Current
;
3134 const ALbuffer
*Buffer
= NULL
;
3138 ReadLock(&Source
->queue_lock
);
3139 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3141 ReadUnlock(&Source
->queue_lock
);
3143 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3145 *clocktime
= GetDeviceClockTime(device
);
3146 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3147 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3152 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3154 *clocktime
= GetDeviceClockTime(device
);
3156 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3157 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3159 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
)<<FRACTIONBITS
;
3160 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3161 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3162 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3163 while(BufferList
&& BufferList
!= Current
)
3165 const ALbuffer
*buffer
= BufferList
->buffer
;
3168 if(!Buffer
) Buffer
= buffer
;
3169 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3171 BufferList
= BufferList
->next
;
3174 while(BufferList
&& !Buffer
)
3176 Buffer
= BufferList
->buffer
;
3177 BufferList
= BufferList
->next
;
3179 assert(Buffer
!= NULL
);
3181 ReadUnlock(&Source
->queue_lock
);
3182 return (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/ (ALdouble
)Buffer
->Frequency
;
3187 * Gets the current read offset for the given Source, in the appropriate format
3188 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3189 * queue (not the start of the current buffer).
3191 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
)
3193 const ALbufferlistitem
*BufferList
;
3194 const ALbufferlistitem
*Current
;
3195 const ALbuffer
*Buffer
= NULL
;
3196 ALboolean readFin
= AL_FALSE
;
3197 ALuint readPos
, readPosFrac
;
3198 ALuint totalBufferLen
;
3199 ALdouble offset
= 0.0;
3203 ReadLock(&Source
->queue_lock
);
3204 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3206 ReadUnlock(&Source
->queue_lock
);
3212 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3214 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3215 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3217 readPos
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
3218 readPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3220 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3221 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3222 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3224 while(BufferList
!= NULL
)
3226 const ALbuffer
*buffer
;
3227 readFin
= readFin
|| (BufferList
== Current
);
3228 if((buffer
=BufferList
->buffer
) != NULL
)
3230 if(!Buffer
) Buffer
= buffer
;
3231 totalBufferLen
+= buffer
->SampleLen
;
3232 if(!readFin
) readPos
+= buffer
->SampleLen
;
3234 BufferList
= BufferList
->next
;
3236 assert(Buffer
!= NULL
);
3239 readPos
%= totalBufferLen
;
3242 /* Wrap back to 0 */
3243 if(readPos
>= totalBufferLen
)
3244 readPos
= readPosFrac
= 0;
3250 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3253 case AL_SAMPLE_OFFSET
:
3254 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3257 case AL_BYTE_OFFSET
:
3258 if(Buffer
->OriginalType
== UserFmtIMA4
)
3260 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3261 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3262 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3264 /* Round down to nearest ADPCM block */
3265 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3267 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3269 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3270 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3271 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3273 /* Round down to nearest ADPCM block */
3274 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3278 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3279 offset
= (ALdouble
)(readPos
* FrameSize
);
3284 ReadUnlock(&Source
->queue_lock
);
3291 * Apply the stored playback offset to the Source. This function will update
3292 * the number of buffers "played" given the stored offset.
3294 ALboolean
ApplyOffset(ALsource
*Source
)
3296 ALbufferlistitem
*BufferList
;
3297 const ALbuffer
*Buffer
;
3298 ALuint bufferLen
, totalBufferLen
;
3299 ALuint offset
=0, frac
=0;
3301 /* Get sample frame offset */
3302 if(!GetSampleOffset(Source
, &offset
, &frac
))
3306 BufferList
= ATOMIC_LOAD(&Source
->queue
);
3307 while(BufferList
&& totalBufferLen
<= offset
)
3309 Buffer
= BufferList
->buffer
;
3310 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3312 if(bufferLen
> offset
-totalBufferLen
)
3314 /* Offset is in this buffer */
3315 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
3317 ATOMIC_STORE(&Source
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3318 ATOMIC_STORE(&Source
->position_fraction
, frac
, almemory_order_release
);
3322 totalBufferLen
+= bufferLen
;
3324 BufferList
= BufferList
->next
;
3327 /* Offset is out of range of the queue */
3334 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3335 * or Second offset supplied by the application). This takes into account the
3336 * fact that the buffer format may have been modifed since.
3338 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3340 const ALbuffer
*Buffer
= NULL
;
3341 const ALbufferlistitem
*BufferList
;
3342 ALdouble dbloff
, dblfrac
;
3344 /* Find the first valid Buffer in the Queue */
3345 BufferList
= ATOMIC_LOAD(&Source
->queue
);
3348 if(BufferList
->buffer
)
3350 Buffer
= BufferList
->buffer
;
3353 BufferList
= BufferList
->next
;
3357 Source
->OffsetType
= AL_NONE
;
3358 Source
->Offset
= 0.0;
3362 switch(Source
->OffsetType
)
3364 case AL_BYTE_OFFSET
:
3365 /* Determine the ByteOffset (and ensure it is block aligned) */
3366 *offset
= (ALuint
)Source
->Offset
;
3367 if(Buffer
->OriginalType
== UserFmtIMA4
)
3369 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3370 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3371 *offset
*= Buffer
->OriginalAlign
;
3373 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3375 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3376 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3377 *offset
*= Buffer
->OriginalAlign
;
3380 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3384 case AL_SAMPLE_OFFSET
:
3385 dblfrac
= modf(Source
->Offset
, &dbloff
);
3386 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3387 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3391 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3392 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3393 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3396 Source
->OffsetType
= AL_NONE
;
3397 Source
->Offset
= 0.0;
3405 * Destroys all sources in the source map.
3407 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3410 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3412 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3413 Context
->SourceMap
.values
[pos
] = NULL
;
3417 FreeThunkEntry(temp
->id
);
3418 memset(temp
, 0, sizeof(*temp
));