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
, ALCcontext
*context
);
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 bool SourceShouldUpdate(const ALsource
*source
, const ALCcontext
*context
)
130 return (source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
) &&
131 !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
);
134 static ALint
FloatValsByProp(ALenum prop
)
136 if(prop
!= (ALenum
)((SourceProp
)prop
))
138 switch((SourceProp
)prop
)
144 case AL_MAX_DISTANCE
:
145 case AL_ROLLOFF_FACTOR
:
146 case AL_DOPPLER_FACTOR
:
147 case AL_CONE_OUTER_GAIN
:
149 case AL_SAMPLE_OFFSET
:
151 case AL_CONE_INNER_ANGLE
:
152 case AL_CONE_OUTER_ANGLE
:
153 case AL_REFERENCE_DISTANCE
:
154 case AL_CONE_OUTER_GAINHF
:
155 case AL_AIR_ABSORPTION_FACTOR
:
156 case AL_ROOM_ROLLOFF_FACTOR
:
157 case AL_DIRECT_FILTER_GAINHF_AUTO
:
158 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
159 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
160 case AL_DIRECT_CHANNELS_SOFT
:
161 case AL_DISTANCE_MODEL
:
162 case AL_SOURCE_RELATIVE
:
164 case AL_SOURCE_STATE
:
165 case AL_BUFFERS_QUEUED
:
166 case AL_BUFFERS_PROCESSED
:
168 case AL_BYTE_LENGTH_SOFT
:
169 case AL_SAMPLE_LENGTH_SOFT
:
170 case AL_SEC_LENGTH_SOFT
:
171 case AL_SOURCE_RADIUS
:
174 case AL_STEREO_ANGLES
:
185 case AL_SEC_OFFSET_LATENCY_SOFT
:
186 break; /* Double only */
189 case AL_DIRECT_FILTER
:
190 case AL_AUXILIARY_SEND_FILTER
:
191 break; /* i/i64 only */
192 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
193 break; /* i64 only */
197 static ALint
DoubleValsByProp(ALenum prop
)
199 if(prop
!= (ALenum
)((SourceProp
)prop
))
201 switch((SourceProp
)prop
)
207 case AL_MAX_DISTANCE
:
208 case AL_ROLLOFF_FACTOR
:
209 case AL_DOPPLER_FACTOR
:
210 case AL_CONE_OUTER_GAIN
:
212 case AL_SAMPLE_OFFSET
:
214 case AL_CONE_INNER_ANGLE
:
215 case AL_CONE_OUTER_ANGLE
:
216 case AL_REFERENCE_DISTANCE
:
217 case AL_CONE_OUTER_GAINHF
:
218 case AL_AIR_ABSORPTION_FACTOR
:
219 case AL_ROOM_ROLLOFF_FACTOR
:
220 case AL_DIRECT_FILTER_GAINHF_AUTO
:
221 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
222 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
223 case AL_DIRECT_CHANNELS_SOFT
:
224 case AL_DISTANCE_MODEL
:
225 case AL_SOURCE_RELATIVE
:
227 case AL_SOURCE_STATE
:
228 case AL_BUFFERS_QUEUED
:
229 case AL_BUFFERS_PROCESSED
:
231 case AL_BYTE_LENGTH_SOFT
:
232 case AL_SAMPLE_LENGTH_SOFT
:
233 case AL_SEC_LENGTH_SOFT
:
234 case AL_SOURCE_RADIUS
:
237 case AL_SEC_OFFSET_LATENCY_SOFT
:
238 case AL_STEREO_ANGLES
:
250 case AL_DIRECT_FILTER
:
251 case AL_AUXILIARY_SEND_FILTER
:
252 break; /* i/i64 only */
253 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
254 break; /* i64 only */
259 static ALint
IntValsByProp(ALenum prop
)
261 if(prop
!= (ALenum
)((SourceProp
)prop
))
263 switch((SourceProp
)prop
)
269 case AL_MAX_DISTANCE
:
270 case AL_ROLLOFF_FACTOR
:
271 case AL_DOPPLER_FACTOR
:
272 case AL_CONE_OUTER_GAIN
:
274 case AL_SAMPLE_OFFSET
:
276 case AL_CONE_INNER_ANGLE
:
277 case AL_CONE_OUTER_ANGLE
:
278 case AL_REFERENCE_DISTANCE
:
279 case AL_CONE_OUTER_GAINHF
:
280 case AL_AIR_ABSORPTION_FACTOR
:
281 case AL_ROOM_ROLLOFF_FACTOR
:
282 case AL_DIRECT_FILTER_GAINHF_AUTO
:
283 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
284 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
285 case AL_DIRECT_CHANNELS_SOFT
:
286 case AL_DISTANCE_MODEL
:
287 case AL_SOURCE_RELATIVE
:
290 case AL_SOURCE_STATE
:
291 case AL_BUFFERS_QUEUED
:
292 case AL_BUFFERS_PROCESSED
:
294 case AL_DIRECT_FILTER
:
295 case AL_BYTE_LENGTH_SOFT
:
296 case AL_SAMPLE_LENGTH_SOFT
:
297 case AL_SEC_LENGTH_SOFT
:
298 case AL_SOURCE_RADIUS
:
304 case AL_AUXILIARY_SEND_FILTER
:
310 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
311 break; /* i64 only */
312 case AL_SEC_OFFSET_LATENCY_SOFT
:
313 break; /* Double only */
314 case AL_STEREO_ANGLES
:
315 break; /* Float/double only */
319 static ALint
Int64ValsByProp(ALenum prop
)
321 if(prop
!= (ALenum
)((SourceProp
)prop
))
323 switch((SourceProp
)prop
)
329 case AL_MAX_DISTANCE
:
330 case AL_ROLLOFF_FACTOR
:
331 case AL_DOPPLER_FACTOR
:
332 case AL_CONE_OUTER_GAIN
:
334 case AL_SAMPLE_OFFSET
:
336 case AL_CONE_INNER_ANGLE
:
337 case AL_CONE_OUTER_ANGLE
:
338 case AL_REFERENCE_DISTANCE
:
339 case AL_CONE_OUTER_GAINHF
:
340 case AL_AIR_ABSORPTION_FACTOR
:
341 case AL_ROOM_ROLLOFF_FACTOR
:
342 case AL_DIRECT_FILTER_GAINHF_AUTO
:
343 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
344 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
345 case AL_DIRECT_CHANNELS_SOFT
:
346 case AL_DISTANCE_MODEL
:
347 case AL_SOURCE_RELATIVE
:
350 case AL_SOURCE_STATE
:
351 case AL_BUFFERS_QUEUED
:
352 case AL_BUFFERS_PROCESSED
:
354 case AL_DIRECT_FILTER
:
355 case AL_BYTE_LENGTH_SOFT
:
356 case AL_SAMPLE_LENGTH_SOFT
:
357 case AL_SEC_LENGTH_SOFT
:
358 case AL_SOURCE_RADIUS
:
361 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
367 case AL_AUXILIARY_SEND_FILTER
:
373 case AL_SEC_OFFSET_LATENCY_SOFT
:
374 break; /* Double only */
375 case AL_STEREO_ANGLES
:
376 break; /* Float/double only */
382 #define CHECKVAL(x) do { \
384 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
387 #define DO_UPDATEPROPS() do { \
388 if(SourceShouldUpdate(Source, Context)) \
389 UpdateSourceProps(Source, device->NumAuxSends, Context); \
392 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
394 ALCdevice
*device
= Context
->Device
;
399 case AL_BYTE_LENGTH_SOFT
:
400 case AL_SAMPLE_LENGTH_SOFT
:
401 case AL_SEC_LENGTH_SOFT
:
402 case AL_SEC_OFFSET_LATENCY_SOFT
:
404 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
407 CHECKVAL(*values
>= 0.0f
);
409 Source
->Pitch
= *values
;
413 case AL_CONE_INNER_ANGLE
:
414 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
416 Source
->InnerAngle
= *values
;
420 case AL_CONE_OUTER_ANGLE
:
421 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
423 Source
->OuterAngle
= *values
;
428 CHECKVAL(*values
>= 0.0f
);
430 Source
->Gain
= *values
;
434 case AL_MAX_DISTANCE
:
435 CHECKVAL(*values
>= 0.0f
);
437 Source
->MaxDistance
= *values
;
441 case AL_ROLLOFF_FACTOR
:
442 CHECKVAL(*values
>= 0.0f
);
444 Source
->RollOffFactor
= *values
;
448 case AL_REFERENCE_DISTANCE
:
449 CHECKVAL(*values
>= 0.0f
);
451 Source
->RefDistance
= *values
;
456 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
458 Source
->MinGain
= *values
;
463 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
465 Source
->MaxGain
= *values
;
469 case AL_CONE_OUTER_GAIN
:
470 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
472 Source
->OuterGain
= *values
;
476 case AL_CONE_OUTER_GAINHF
:
477 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
479 Source
->OuterGainHF
= *values
;
483 case AL_AIR_ABSORPTION_FACTOR
:
484 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
486 Source
->AirAbsorptionFactor
= *values
;
490 case AL_ROOM_ROLLOFF_FACTOR
:
491 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
493 Source
->RoomRolloffFactor
= *values
;
497 case AL_DOPPLER_FACTOR
:
498 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
500 Source
->DopplerFactor
= *values
;
505 case AL_SAMPLE_OFFSET
:
507 CHECKVAL(*values
>= 0.0f
);
509 Source
->OffsetType
= prop
;
510 Source
->Offset
= *values
;
512 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
513 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
515 LockContext(Context
);
516 WriteLock(&Source
->queue_lock
);
517 if(ApplyOffset(Source
) == AL_FALSE
)
519 WriteUnlock(&Source
->queue_lock
);
520 UnlockContext(Context
);
521 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
523 WriteUnlock(&Source
->queue_lock
);
524 UnlockContext(Context
);
528 case AL_SOURCE_RADIUS
:
529 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
531 Source
->Radius
= *values
;
535 case AL_STEREO_ANGLES
:
536 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
538 Source
->StereoPan
[0] = values
[0];
539 Source
->StereoPan
[1] = values
[1];
545 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
547 Source
->Position
[0] = values
[0];
548 Source
->Position
[1] = values
[1];
549 Source
->Position
[2] = values
[2];
554 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
556 Source
->Velocity
[0] = values
[0];
557 Source
->Velocity
[1] = values
[1];
558 Source
->Velocity
[2] = values
[2];
563 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
565 Source
->Direction
[0] = values
[0];
566 Source
->Direction
[1] = values
[1];
567 Source
->Direction
[2] = values
[2];
572 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
573 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
575 Source
->Orientation
[0][0] = values
[0];
576 Source
->Orientation
[0][1] = values
[1];
577 Source
->Orientation
[0][2] = values
[2];
578 Source
->Orientation
[1][0] = values
[3];
579 Source
->Orientation
[1][1] = values
[4];
580 Source
->Orientation
[1][2] = values
[5];
585 case AL_SOURCE_RELATIVE
:
587 case AL_SOURCE_STATE
:
589 case AL_DISTANCE_MODEL
:
590 case AL_DIRECT_FILTER_GAINHF_AUTO
:
591 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
592 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
593 case AL_DIRECT_CHANNELS_SOFT
:
594 ival
= (ALint
)values
[0];
595 return SetSourceiv(Source
, Context
, prop
, &ival
);
597 case AL_BUFFERS_QUEUED
:
598 case AL_BUFFERS_PROCESSED
:
599 ival
= (ALint
)((ALuint
)values
[0]);
600 return SetSourceiv(Source
, Context
, prop
, &ival
);
603 case AL_DIRECT_FILTER
:
604 case AL_AUXILIARY_SEND_FILTER
:
605 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
609 ERR("Unexpected property: 0x%04x\n", prop
);
610 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
613 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
615 ALCdevice
*device
= Context
->Device
;
616 ALbuffer
*buffer
= NULL
;
617 ALfilter
*filter
= NULL
;
618 ALeffectslot
*slot
= NULL
;
619 ALbufferlistitem
*oldlist
;
620 ALbufferlistitem
*newlist
;
625 case AL_SOURCE_STATE
:
627 case AL_BUFFERS_QUEUED
:
628 case AL_BUFFERS_PROCESSED
:
629 case AL_BYTE_LENGTH_SOFT
:
630 case AL_SAMPLE_LENGTH_SOFT
:
631 case AL_SEC_LENGTH_SOFT
:
633 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
635 case AL_SOURCE_RELATIVE
:
636 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
638 Source
->HeadRelative
= (ALboolean
)*values
;
643 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
645 WriteLock(&Source
->queue_lock
);
646 ATOMIC_STORE(&Source
->looping
, *values
);
647 WriteUnlock(&Source
->queue_lock
);
651 LockBuffersRead(device
);
652 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
654 UnlockBuffersRead(device
);
655 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
658 WriteLock(&Source
->queue_lock
);
659 if(!(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
))
661 WriteUnlock(&Source
->queue_lock
);
662 UnlockBuffersRead(device
);
663 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
668 /* Add the selected buffer to a one-item queue */
669 newlist
= malloc(sizeof(ALbufferlistitem
));
670 newlist
->buffer
= buffer
;
671 newlist
->next
= NULL
;
672 IncrementRef(&buffer
->ref
);
674 /* Source is now Static */
675 Source
->SourceType
= AL_STATIC
;
677 ReadLock(&buffer
->lock
);
678 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
679 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
680 ReadUnlock(&buffer
->lock
);
684 /* Source is now Undetermined */
685 Source
->SourceType
= AL_UNDETERMINED
;
688 oldlist
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &Source
->queue
, newlist
);
689 ATOMIC_STORE(&Source
->current_buffer
, newlist
);
690 WriteUnlock(&Source
->queue_lock
);
691 UnlockBuffersRead(device
);
693 /* Delete all elements in the previous queue */
694 while(oldlist
!= NULL
)
696 ALbufferlistitem
*temp
= oldlist
;
697 oldlist
= temp
->next
;
700 DecrementRef(&temp
->buffer
->ref
);
706 case AL_SAMPLE_OFFSET
:
708 CHECKVAL(*values
>= 0);
710 Source
->OffsetType
= prop
;
711 Source
->Offset
= *values
;
713 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
714 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
716 LockContext(Context
);
717 WriteLock(&Source
->queue_lock
);
718 if(ApplyOffset(Source
) == AL_FALSE
)
720 WriteUnlock(&Source
->queue_lock
);
721 UnlockContext(Context
);
722 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
724 WriteUnlock(&Source
->queue_lock
);
725 UnlockContext(Context
);
729 case AL_DIRECT_FILTER
:
730 LockFiltersRead(device
);
731 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
733 UnlockFiltersRead(device
);
734 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
739 Source
->Direct
.Gain
= 1.0f
;
740 Source
->Direct
.GainHF
= 1.0f
;
741 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
742 Source
->Direct
.GainLF
= 1.0f
;
743 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
747 Source
->Direct
.Gain
= filter
->Gain
;
748 Source
->Direct
.GainHF
= filter
->GainHF
;
749 Source
->Direct
.HFReference
= filter
->HFReference
;
750 Source
->Direct
.GainLF
= filter
->GainLF
;
751 Source
->Direct
.LFReference
= filter
->LFReference
;
753 UnlockFiltersRead(device
);
757 case AL_DIRECT_FILTER_GAINHF_AUTO
:
758 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
760 Source
->DryGainHFAuto
= *values
;
764 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
765 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
767 Source
->WetGainAuto
= *values
;
771 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
772 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
774 Source
->WetGainHFAuto
= *values
;
778 case AL_DIRECT_CHANNELS_SOFT
:
779 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
781 Source
->DirectChannels
= *values
;
785 case AL_DISTANCE_MODEL
:
786 CHECKVAL(*values
== AL_NONE
||
787 *values
== AL_INVERSE_DISTANCE
||
788 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
789 *values
== AL_LINEAR_DISTANCE
||
790 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
791 *values
== AL_EXPONENT_DISTANCE
||
792 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
794 Source
->DistanceModel
= *values
;
795 if(Context
->SourceDistanceModel
)
800 case AL_AUXILIARY_SEND_FILTER
:
801 LockEffectSlotsRead(Context
);
802 LockFiltersRead(device
);
803 if(!((ALuint
)values
[1] < device
->NumAuxSends
&&
804 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
805 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
807 UnlockFiltersRead(device
);
808 UnlockEffectSlotsRead(Context
);
809 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
815 Source
->Send
[values
[1]].Gain
= 1.0f
;
816 Source
->Send
[values
[1]].GainHF
= 1.0f
;
817 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
818 Source
->Send
[values
[1]].GainLF
= 1.0f
;
819 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
823 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
824 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
825 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
826 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
827 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
829 UnlockFiltersRead(device
);
831 if(slot
!= Source
->Send
[values
[1]].Slot
&&
832 (Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
))
834 /* Add refcount on the new slot, and release the previous slot */
835 if(slot
) IncrementRef(&slot
->ref
);
836 if(Source
->Send
[values
[1]].Slot
)
837 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
838 Source
->Send
[values
[1]].Slot
= slot
;
840 /* We must force an update if the auxiliary slot changed on a
841 * playing source, in case the slot is about to be deleted.
843 UpdateSourceProps(Source
, device
->NumAuxSends
, Context
);
847 if(slot
) IncrementRef(&slot
->ref
);
848 if(Source
->Send
[values
[1]].Slot
)
849 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
850 Source
->Send
[values
[1]].Slot
= slot
;
853 UnlockEffectSlotsRead(Context
);
859 case AL_CONE_INNER_ANGLE
:
860 case AL_CONE_OUTER_ANGLE
:
865 case AL_REFERENCE_DISTANCE
:
866 case AL_ROLLOFF_FACTOR
:
867 case AL_CONE_OUTER_GAIN
:
868 case AL_MAX_DISTANCE
:
869 case AL_DOPPLER_FACTOR
:
870 case AL_CONE_OUTER_GAINHF
:
871 case AL_AIR_ABSORPTION_FACTOR
:
872 case AL_ROOM_ROLLOFF_FACTOR
:
873 case AL_SOURCE_RADIUS
:
874 fvals
[0] = (ALfloat
)*values
;
875 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
881 fvals
[0] = (ALfloat
)values
[0];
882 fvals
[1] = (ALfloat
)values
[1];
883 fvals
[2] = (ALfloat
)values
[2];
884 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
888 fvals
[0] = (ALfloat
)values
[0];
889 fvals
[1] = (ALfloat
)values
[1];
890 fvals
[2] = (ALfloat
)values
[2];
891 fvals
[3] = (ALfloat
)values
[3];
892 fvals
[4] = (ALfloat
)values
[4];
893 fvals
[5] = (ALfloat
)values
[5];
894 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
896 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
897 case AL_SEC_OFFSET_LATENCY_SOFT
:
898 case AL_STEREO_ANGLES
:
902 ERR("Unexpected property: 0x%04x\n", prop
);
903 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
906 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
914 case AL_BUFFERS_QUEUED
:
915 case AL_BUFFERS_PROCESSED
:
916 case AL_SOURCE_STATE
:
917 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
918 case AL_BYTE_LENGTH_SOFT
:
919 case AL_SAMPLE_LENGTH_SOFT
:
920 case AL_SEC_LENGTH_SOFT
:
922 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
926 case AL_SOURCE_RELATIVE
:
929 case AL_SAMPLE_OFFSET
:
931 case AL_DIRECT_FILTER_GAINHF_AUTO
:
932 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
933 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
934 case AL_DIRECT_CHANNELS_SOFT
:
935 case AL_DISTANCE_MODEL
:
936 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
938 ivals
[0] = (ALint
)*values
;
939 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
943 case AL_DIRECT_FILTER
:
944 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
946 ivals
[0] = (ALuint
)*values
;
947 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
950 case AL_AUXILIARY_SEND_FILTER
:
951 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
952 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
953 values
[2] <= UINT_MAX
&& values
[2] >= 0);
955 ivals
[0] = (ALuint
)values
[0];
956 ivals
[1] = (ALuint
)values
[1];
957 ivals
[2] = (ALuint
)values
[2];
958 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
961 case AL_CONE_INNER_ANGLE
:
962 case AL_CONE_OUTER_ANGLE
:
967 case AL_REFERENCE_DISTANCE
:
968 case AL_ROLLOFF_FACTOR
:
969 case AL_CONE_OUTER_GAIN
:
970 case AL_MAX_DISTANCE
:
971 case AL_DOPPLER_FACTOR
:
972 case AL_CONE_OUTER_GAINHF
:
973 case AL_AIR_ABSORPTION_FACTOR
:
974 case AL_ROOM_ROLLOFF_FACTOR
:
975 case AL_SOURCE_RADIUS
:
976 fvals
[0] = (ALfloat
)*values
;
977 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
983 fvals
[0] = (ALfloat
)values
[0];
984 fvals
[1] = (ALfloat
)values
[1];
985 fvals
[2] = (ALfloat
)values
[2];
986 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
990 fvals
[0] = (ALfloat
)values
[0];
991 fvals
[1] = (ALfloat
)values
[1];
992 fvals
[2] = (ALfloat
)values
[2];
993 fvals
[3] = (ALfloat
)values
[3];
994 fvals
[4] = (ALfloat
)values
[4];
995 fvals
[5] = (ALfloat
)values
[5];
996 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
998 case AL_SEC_OFFSET_LATENCY_SOFT
:
999 case AL_STEREO_ANGLES
:
1003 ERR("Unexpected property: 0x%04x\n", prop
);
1004 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1010 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1012 ALCdevice
*device
= Context
->Device
;
1013 ALbufferlistitem
*BufferList
;
1014 ClockLatency clocktime
;
1022 *values
= Source
->Gain
;
1026 *values
= Source
->Pitch
;
1029 case AL_MAX_DISTANCE
:
1030 *values
= Source
->MaxDistance
;
1033 case AL_ROLLOFF_FACTOR
:
1034 *values
= Source
->RollOffFactor
;
1037 case AL_REFERENCE_DISTANCE
:
1038 *values
= Source
->RefDistance
;
1041 case AL_CONE_INNER_ANGLE
:
1042 *values
= Source
->InnerAngle
;
1045 case AL_CONE_OUTER_ANGLE
:
1046 *values
= Source
->OuterAngle
;
1050 *values
= Source
->MinGain
;
1054 *values
= Source
->MaxGain
;
1057 case AL_CONE_OUTER_GAIN
:
1058 *values
= Source
->OuterGain
;
1062 case AL_SAMPLE_OFFSET
:
1063 case AL_BYTE_OFFSET
:
1064 *values
= GetSourceOffset(Source
, prop
, device
);
1067 case AL_CONE_OUTER_GAINHF
:
1068 *values
= Source
->OuterGainHF
;
1071 case AL_AIR_ABSORPTION_FACTOR
:
1072 *values
= Source
->AirAbsorptionFactor
;
1075 case AL_ROOM_ROLLOFF_FACTOR
:
1076 *values
= Source
->RoomRolloffFactor
;
1079 case AL_DOPPLER_FACTOR
:
1080 *values
= Source
->DopplerFactor
;
1083 case AL_SEC_LENGTH_SOFT
:
1084 ReadLock(&Source
->queue_lock
);
1085 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1092 ALbuffer
*buffer
= BufferList
->buffer
;
1093 if(buffer
&& buffer
->SampleLen
> 0)
1095 freq
= buffer
->Frequency
;
1096 length
+= buffer
->SampleLen
;
1098 } while((BufferList
=BufferList
->next
) != NULL
);
1099 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1101 ReadUnlock(&Source
->queue_lock
);
1104 case AL_SOURCE_RADIUS
:
1105 *values
= Source
->Radius
;
1108 case AL_STEREO_ANGLES
:
1109 values
[0] = Source
->StereoPan
[0];
1110 values
[1] = Source
->StereoPan
[1];
1113 case AL_SEC_OFFSET_LATENCY_SOFT
:
1114 /* Get the source offset with the clock time first. Then get the
1115 * clock time with the device latency. Order is important.
1117 values
[0] = GetSourceSecOffset(Source
, device
, &srcclock
);
1118 clocktime
= V0(device
->Backend
,getClockLatency
)();
1119 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1120 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1123 /* If the clock time incremented, reduce the latency by that
1124 * much since it's that much closer to the source offset it got
1127 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1128 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1134 values
[0] = Source
->Position
[0];
1135 values
[1] = Source
->Position
[1];
1136 values
[2] = Source
->Position
[2];
1140 values
[0] = Source
->Velocity
[0];
1141 values
[1] = Source
->Velocity
[1];
1142 values
[2] = Source
->Velocity
[2];
1146 values
[0] = Source
->Direction
[0];
1147 values
[1] = Source
->Direction
[1];
1148 values
[2] = Source
->Direction
[2];
1151 case AL_ORIENTATION
:
1152 values
[0] = Source
->Orientation
[0][0];
1153 values
[1] = Source
->Orientation
[0][1];
1154 values
[2] = Source
->Orientation
[0][2];
1155 values
[3] = Source
->Orientation
[1][0];
1156 values
[4] = Source
->Orientation
[1][1];
1157 values
[5] = Source
->Orientation
[1][2];
1161 case AL_SOURCE_RELATIVE
:
1163 case AL_SOURCE_STATE
:
1164 case AL_BUFFERS_QUEUED
:
1165 case AL_BUFFERS_PROCESSED
:
1166 case AL_SOURCE_TYPE
:
1167 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1168 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1169 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1170 case AL_DIRECT_CHANNELS_SOFT
:
1171 case AL_BYTE_LENGTH_SOFT
:
1172 case AL_SAMPLE_LENGTH_SOFT
:
1173 case AL_DISTANCE_MODEL
:
1174 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1175 *values
= (ALdouble
)ivals
[0];
1179 case AL_DIRECT_FILTER
:
1180 case AL_AUXILIARY_SEND_FILTER
:
1181 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1185 ERR("Unexpected property: 0x%04x\n", prop
);
1186 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1189 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1191 ALbufferlistitem
*BufferList
;
1197 case AL_SOURCE_RELATIVE
:
1198 *values
= Source
->HeadRelative
;
1202 *values
= ATOMIC_LOAD(&Source
->looping
);
1206 ReadLock(&Source
->queue_lock
);
1207 BufferList
= (Source
->SourceType
== AL_STATIC
) ? ATOMIC_LOAD(&Source
->queue
) :
1208 ATOMIC_LOAD(&Source
->current_buffer
);
1209 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1210 ReadUnlock(&Source
->queue_lock
);
1213 case AL_SOURCE_STATE
:
1214 *values
= Source
->state
;
1217 case AL_BYTE_LENGTH_SOFT
:
1218 ReadLock(&Source
->queue_lock
);
1219 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1225 ALbuffer
*buffer
= BufferList
->buffer
;
1226 if(buffer
&& buffer
->SampleLen
> 0)
1228 ALuint byte_align
, sample_align
;
1229 if(buffer
->OriginalType
== UserFmtIMA4
)
1231 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1232 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1233 sample_align
= buffer
->OriginalAlign
;
1235 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1237 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1238 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1239 sample_align
= buffer
->OriginalAlign
;
1243 ALsizei align
= buffer
->OriginalAlign
;
1244 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1245 sample_align
= buffer
->OriginalAlign
;
1248 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1250 } while((BufferList
=BufferList
->next
) != NULL
);
1253 ReadUnlock(&Source
->queue_lock
);
1256 case AL_SAMPLE_LENGTH_SOFT
:
1257 ReadLock(&Source
->queue_lock
);
1258 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1264 ALbuffer
*buffer
= BufferList
->buffer
;
1265 if(buffer
) length
+= buffer
->SampleLen
;
1266 } while((BufferList
=BufferList
->next
) != NULL
);
1269 ReadUnlock(&Source
->queue_lock
);
1272 case AL_BUFFERS_QUEUED
:
1273 ReadLock(&Source
->queue_lock
);
1274 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1281 } while((BufferList
=BufferList
->next
) != NULL
);
1284 ReadUnlock(&Source
->queue_lock
);
1287 case AL_BUFFERS_PROCESSED
:
1288 ReadLock(&Source
->queue_lock
);
1289 if(ATOMIC_LOAD(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1291 /* Buffers on a looping source are in a perpetual state of
1292 * PENDING, so don't report any as PROCESSED */
1297 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD(&Source
->queue
);
1298 const ALbufferlistitem
*Current
= ATOMIC_LOAD(&Source
->current_buffer
);
1300 while(BufferList
&& BufferList
!= Current
)
1303 BufferList
= BufferList
->next
;
1307 ReadUnlock(&Source
->queue_lock
);
1310 case AL_SOURCE_TYPE
:
1311 *values
= Source
->SourceType
;
1314 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1315 *values
= Source
->DryGainHFAuto
;
1318 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1319 *values
= Source
->WetGainAuto
;
1322 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1323 *values
= Source
->WetGainHFAuto
;
1326 case AL_DIRECT_CHANNELS_SOFT
:
1327 *values
= Source
->DirectChannels
;
1330 case AL_DISTANCE_MODEL
:
1331 *values
= Source
->DistanceModel
;
1334 /* 1x float/double */
1335 case AL_CONE_INNER_ANGLE
:
1336 case AL_CONE_OUTER_ANGLE
:
1341 case AL_REFERENCE_DISTANCE
:
1342 case AL_ROLLOFF_FACTOR
:
1343 case AL_CONE_OUTER_GAIN
:
1344 case AL_MAX_DISTANCE
:
1346 case AL_SAMPLE_OFFSET
:
1347 case AL_BYTE_OFFSET
:
1348 case AL_DOPPLER_FACTOR
:
1349 case AL_AIR_ABSORPTION_FACTOR
:
1350 case AL_ROOM_ROLLOFF_FACTOR
:
1351 case AL_CONE_OUTER_GAINHF
:
1352 case AL_SEC_LENGTH_SOFT
:
1353 case AL_SOURCE_RADIUS
:
1354 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1355 *values
= (ALint
)dvals
[0];
1358 /* 3x float/double */
1362 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1364 values
[0] = (ALint
)dvals
[0];
1365 values
[1] = (ALint
)dvals
[1];
1366 values
[2] = (ALint
)dvals
[2];
1370 /* 6x float/double */
1371 case AL_ORIENTATION
:
1372 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1374 values
[0] = (ALint
)dvals
[0];
1375 values
[1] = (ALint
)dvals
[1];
1376 values
[2] = (ALint
)dvals
[2];
1377 values
[3] = (ALint
)dvals
[3];
1378 values
[4] = (ALint
)dvals
[4];
1379 values
[5] = (ALint
)dvals
[5];
1383 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1384 break; /* i64 only */
1385 case AL_SEC_OFFSET_LATENCY_SOFT
:
1386 break; /* Double only */
1387 case AL_STEREO_ANGLES
:
1388 break; /* Float/double only */
1390 case AL_DIRECT_FILTER
:
1391 case AL_AUXILIARY_SEND_FILTER
:
1395 ERR("Unexpected property: 0x%04x\n", prop
);
1396 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1399 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1401 ALCdevice
*device
= Context
->Device
;
1402 ClockLatency clocktime
;
1410 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1411 /* Get the source offset with the clock time first. Then get the
1412 * clock time with the device latency. Order is important.
1414 values
[0] = GetSourceSampleOffset(Source
, device
, &srcclock
);
1415 clocktime
= V0(device
->Backend
,getClockLatency
)();
1416 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1417 values
[1] = clocktime
.Latency
;
1420 /* If the clock time incremented, reduce the latency by that
1421 * much since it's that much closer to the source offset it got
1424 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1425 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1429 /* 1x float/double */
1430 case AL_CONE_INNER_ANGLE
:
1431 case AL_CONE_OUTER_ANGLE
:
1436 case AL_REFERENCE_DISTANCE
:
1437 case AL_ROLLOFF_FACTOR
:
1438 case AL_CONE_OUTER_GAIN
:
1439 case AL_MAX_DISTANCE
:
1441 case AL_SAMPLE_OFFSET
:
1442 case AL_BYTE_OFFSET
:
1443 case AL_DOPPLER_FACTOR
:
1444 case AL_AIR_ABSORPTION_FACTOR
:
1445 case AL_ROOM_ROLLOFF_FACTOR
:
1446 case AL_CONE_OUTER_GAINHF
:
1447 case AL_SEC_LENGTH_SOFT
:
1448 case AL_SOURCE_RADIUS
:
1449 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1450 *values
= (ALint64
)dvals
[0];
1453 /* 3x float/double */
1457 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1459 values
[0] = (ALint64
)dvals
[0];
1460 values
[1] = (ALint64
)dvals
[1];
1461 values
[2] = (ALint64
)dvals
[2];
1465 /* 6x float/double */
1466 case AL_ORIENTATION
:
1467 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1469 values
[0] = (ALint64
)dvals
[0];
1470 values
[1] = (ALint64
)dvals
[1];
1471 values
[2] = (ALint64
)dvals
[2];
1472 values
[3] = (ALint64
)dvals
[3];
1473 values
[4] = (ALint64
)dvals
[4];
1474 values
[5] = (ALint64
)dvals
[5];
1479 case AL_SOURCE_RELATIVE
:
1481 case AL_SOURCE_STATE
:
1482 case AL_BUFFERS_QUEUED
:
1483 case AL_BUFFERS_PROCESSED
:
1484 case AL_BYTE_LENGTH_SOFT
:
1485 case AL_SAMPLE_LENGTH_SOFT
:
1486 case AL_SOURCE_TYPE
:
1487 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1488 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1489 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1490 case AL_DIRECT_CHANNELS_SOFT
:
1491 case AL_DISTANCE_MODEL
:
1492 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1498 case AL_DIRECT_FILTER
:
1499 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1500 *values
= (ALuint
)ivals
[0];
1504 case AL_AUXILIARY_SEND_FILTER
:
1505 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1507 values
[0] = (ALuint
)ivals
[0];
1508 values
[1] = (ALuint
)ivals
[1];
1509 values
[2] = (ALuint
)ivals
[2];
1513 case AL_SEC_OFFSET_LATENCY_SOFT
:
1514 break; /* Double only */
1515 case AL_STEREO_ANGLES
:
1516 break; /* Float/double only */
1519 ERR("Unexpected property: 0x%04x\n", prop
);
1520 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1524 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1526 ALCcontext
*context
;
1530 context
= GetContextRef();
1531 if(!context
) return;
1534 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1535 for(cur
= 0;cur
< n
;cur
++)
1537 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1540 alDeleteSources(cur
, sources
);
1541 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1543 InitSourceParams(source
);
1545 err
= NewThunkEntry(&source
->id
);
1546 if(err
== AL_NO_ERROR
)
1547 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1548 if(err
!= AL_NO_ERROR
)
1550 FreeThunkEntry(source
->id
);
1551 memset(source
, 0, sizeof(ALsource
));
1554 alDeleteSources(cur
, sources
);
1555 SET_ERROR_AND_GOTO(context
, err
, done
);
1558 sources
[cur
] = source
->id
;
1562 ALCcontext_DecRef(context
);
1566 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1568 ALCcontext
*context
;
1572 context
= GetContextRef();
1573 if(!context
) return;
1575 LockSourcesWrite(context
);
1577 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1579 /* Check that all Sources are valid */
1580 for(i
= 0;i
< n
;i
++)
1582 if(LookupSource(context
, sources
[i
]) == NULL
)
1583 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1585 for(i
= 0;i
< n
;i
++)
1587 ALvoice
*voice
, *voice_end
;
1589 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1591 FreeThunkEntry(Source
->id
);
1593 LockContext(context
);
1594 voice
= context
->Voices
;
1595 voice_end
= voice
+ context
->VoiceCount
;
1596 while(voice
!= voice_end
)
1598 ALsource
*old
= Source
;
1599 if(COMPARE_EXCHANGE(&voice
->Source
, &old
, NULL
))
1603 UnlockContext(context
);
1605 DeinitSource(Source
);
1607 memset(Source
, 0, sizeof(*Source
));
1612 UnlockSourcesWrite(context
);
1613 ALCcontext_DecRef(context
);
1617 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1619 ALCcontext
*context
;
1622 context
= GetContextRef();
1623 if(!context
) return AL_FALSE
;
1625 LockSourcesRead(context
);
1626 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1627 UnlockSourcesRead(context
);
1629 ALCcontext_DecRef(context
);
1635 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1637 ALCcontext
*Context
;
1640 Context
= GetContextRef();
1641 if(!Context
) return;
1643 WriteLock(&Context
->PropLock
);
1644 LockSourcesRead(Context
);
1645 if((Source
=LookupSource(Context
, source
)) == NULL
)
1646 alSetError(Context
, AL_INVALID_NAME
);
1647 else if(!(FloatValsByProp(param
) == 1))
1648 alSetError(Context
, AL_INVALID_ENUM
);
1650 SetSourcefv(Source
, Context
, param
, &value
);
1651 UnlockSourcesRead(Context
);
1652 WriteUnlock(&Context
->PropLock
);
1654 ALCcontext_DecRef(Context
);
1657 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1659 ALCcontext
*Context
;
1662 Context
= GetContextRef();
1663 if(!Context
) return;
1665 WriteLock(&Context
->PropLock
);
1666 LockSourcesRead(Context
);
1667 if((Source
=LookupSource(Context
, source
)) == NULL
)
1668 alSetError(Context
, AL_INVALID_NAME
);
1669 else if(!(FloatValsByProp(param
) == 3))
1670 alSetError(Context
, AL_INVALID_ENUM
);
1673 ALfloat fvals
[3] = { value1
, value2
, value3
};
1674 SetSourcefv(Source
, Context
, param
, fvals
);
1676 UnlockSourcesRead(Context
);
1677 WriteUnlock(&Context
->PropLock
);
1679 ALCcontext_DecRef(Context
);
1682 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1684 ALCcontext
*Context
;
1687 Context
= GetContextRef();
1688 if(!Context
) return;
1690 WriteLock(&Context
->PropLock
);
1691 LockSourcesRead(Context
);
1692 if((Source
=LookupSource(Context
, source
)) == NULL
)
1693 alSetError(Context
, AL_INVALID_NAME
);
1695 alSetError(Context
, AL_INVALID_VALUE
);
1696 else if(!(FloatValsByProp(param
) > 0))
1697 alSetError(Context
, AL_INVALID_ENUM
);
1699 SetSourcefv(Source
, Context
, param
, values
);
1700 UnlockSourcesRead(Context
);
1701 WriteUnlock(&Context
->PropLock
);
1703 ALCcontext_DecRef(Context
);
1707 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1709 ALCcontext
*Context
;
1712 Context
= GetContextRef();
1713 if(!Context
) return;
1715 WriteLock(&Context
->PropLock
);
1716 LockSourcesRead(Context
);
1717 if((Source
=LookupSource(Context
, source
)) == NULL
)
1718 alSetError(Context
, AL_INVALID_NAME
);
1719 else if(!(DoubleValsByProp(param
) == 1))
1720 alSetError(Context
, AL_INVALID_ENUM
);
1723 ALfloat fval
= (ALfloat
)value
;
1724 SetSourcefv(Source
, Context
, param
, &fval
);
1726 UnlockSourcesRead(Context
);
1727 WriteUnlock(&Context
->PropLock
);
1729 ALCcontext_DecRef(Context
);
1732 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1734 ALCcontext
*Context
;
1737 Context
= GetContextRef();
1738 if(!Context
) return;
1740 WriteLock(&Context
->PropLock
);
1741 LockSourcesRead(Context
);
1742 if((Source
=LookupSource(Context
, source
)) == NULL
)
1743 alSetError(Context
, AL_INVALID_NAME
);
1744 else if(!(DoubleValsByProp(param
) == 3))
1745 alSetError(Context
, AL_INVALID_ENUM
);
1748 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1749 SetSourcefv(Source
, Context
, param
, fvals
);
1751 UnlockSourcesRead(Context
);
1752 WriteUnlock(&Context
->PropLock
);
1754 ALCcontext_DecRef(Context
);
1757 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1759 ALCcontext
*Context
;
1763 Context
= GetContextRef();
1764 if(!Context
) return;
1766 WriteLock(&Context
->PropLock
);
1767 LockSourcesRead(Context
);
1768 if((Source
=LookupSource(Context
, source
)) == NULL
)
1769 alSetError(Context
, AL_INVALID_NAME
);
1771 alSetError(Context
, AL_INVALID_VALUE
);
1772 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1773 alSetError(Context
, AL_INVALID_ENUM
);
1779 for(i
= 0;i
< count
;i
++)
1780 fvals
[i
] = (ALfloat
)values
[i
];
1781 SetSourcefv(Source
, Context
, param
, fvals
);
1783 UnlockSourcesRead(Context
);
1784 WriteUnlock(&Context
->PropLock
);
1786 ALCcontext_DecRef(Context
);
1790 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1792 ALCcontext
*Context
;
1795 Context
= GetContextRef();
1796 if(!Context
) return;
1798 WriteLock(&Context
->PropLock
);
1799 LockSourcesRead(Context
);
1800 if((Source
=LookupSource(Context
, source
)) == NULL
)
1801 alSetError(Context
, AL_INVALID_NAME
);
1802 else if(!(IntValsByProp(param
) == 1))
1803 alSetError(Context
, AL_INVALID_ENUM
);
1805 SetSourceiv(Source
, Context
, param
, &value
);
1806 UnlockSourcesRead(Context
);
1807 WriteUnlock(&Context
->PropLock
);
1809 ALCcontext_DecRef(Context
);
1812 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1814 ALCcontext
*Context
;
1817 Context
= GetContextRef();
1818 if(!Context
) return;
1820 WriteLock(&Context
->PropLock
);
1821 LockSourcesRead(Context
);
1822 if((Source
=LookupSource(Context
, source
)) == NULL
)
1823 alSetError(Context
, AL_INVALID_NAME
);
1824 else if(!(IntValsByProp(param
) == 3))
1825 alSetError(Context
, AL_INVALID_ENUM
);
1828 ALint ivals
[3] = { value1
, value2
, value3
};
1829 SetSourceiv(Source
, Context
, param
, ivals
);
1831 UnlockSourcesRead(Context
);
1832 WriteUnlock(&Context
->PropLock
);
1834 ALCcontext_DecRef(Context
);
1837 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1839 ALCcontext
*Context
;
1842 Context
= GetContextRef();
1843 if(!Context
) return;
1845 WriteLock(&Context
->PropLock
);
1846 LockSourcesRead(Context
);
1847 if((Source
=LookupSource(Context
, source
)) == NULL
)
1848 alSetError(Context
, AL_INVALID_NAME
);
1850 alSetError(Context
, AL_INVALID_VALUE
);
1851 else if(!(IntValsByProp(param
) > 0))
1852 alSetError(Context
, AL_INVALID_ENUM
);
1854 SetSourceiv(Source
, Context
, param
, values
);
1855 UnlockSourcesRead(Context
);
1856 WriteUnlock(&Context
->PropLock
);
1858 ALCcontext_DecRef(Context
);
1862 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1864 ALCcontext
*Context
;
1867 Context
= GetContextRef();
1868 if(!Context
) return;
1870 WriteLock(&Context
->PropLock
);
1871 LockSourcesRead(Context
);
1872 if((Source
=LookupSource(Context
, source
)) == NULL
)
1873 alSetError(Context
, AL_INVALID_NAME
);
1874 else if(!(Int64ValsByProp(param
) == 1))
1875 alSetError(Context
, AL_INVALID_ENUM
);
1877 SetSourcei64v(Source
, Context
, param
, &value
);
1878 UnlockSourcesRead(Context
);
1879 WriteUnlock(&Context
->PropLock
);
1881 ALCcontext_DecRef(Context
);
1884 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1886 ALCcontext
*Context
;
1889 Context
= GetContextRef();
1890 if(!Context
) return;
1892 WriteLock(&Context
->PropLock
);
1893 LockSourcesRead(Context
);
1894 if((Source
=LookupSource(Context
, source
)) == NULL
)
1895 alSetError(Context
, AL_INVALID_NAME
);
1896 else if(!(Int64ValsByProp(param
) == 3))
1897 alSetError(Context
, AL_INVALID_ENUM
);
1900 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1901 SetSourcei64v(Source
, Context
, param
, i64vals
);
1903 UnlockSourcesRead(Context
);
1904 WriteUnlock(&Context
->PropLock
);
1906 ALCcontext_DecRef(Context
);
1909 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1911 ALCcontext
*Context
;
1914 Context
= GetContextRef();
1915 if(!Context
) return;
1917 WriteLock(&Context
->PropLock
);
1918 LockSourcesRead(Context
);
1919 if((Source
=LookupSource(Context
, source
)) == NULL
)
1920 alSetError(Context
, AL_INVALID_NAME
);
1922 alSetError(Context
, AL_INVALID_VALUE
);
1923 else if(!(Int64ValsByProp(param
) > 0))
1924 alSetError(Context
, AL_INVALID_ENUM
);
1926 SetSourcei64v(Source
, Context
, param
, values
);
1927 UnlockSourcesRead(Context
);
1928 WriteUnlock(&Context
->PropLock
);
1930 ALCcontext_DecRef(Context
);
1934 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1936 ALCcontext
*Context
;
1939 Context
= GetContextRef();
1940 if(!Context
) return;
1942 ReadLock(&Context
->PropLock
);
1943 LockSourcesRead(Context
);
1944 if((Source
=LookupSource(Context
, source
)) == NULL
)
1945 alSetError(Context
, AL_INVALID_NAME
);
1947 alSetError(Context
, AL_INVALID_VALUE
);
1948 else if(!(FloatValsByProp(param
) == 1))
1949 alSetError(Context
, AL_INVALID_ENUM
);
1953 if(GetSourcedv(Source
, Context
, param
, &dval
))
1954 *value
= (ALfloat
)dval
;
1956 UnlockSourcesRead(Context
);
1957 ReadUnlock(&Context
->PropLock
);
1959 ALCcontext_DecRef(Context
);
1963 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1965 ALCcontext
*Context
;
1968 Context
= GetContextRef();
1969 if(!Context
) return;
1971 ReadLock(&Context
->PropLock
);
1972 LockSourcesRead(Context
);
1973 if((Source
=LookupSource(Context
, source
)) == NULL
)
1974 alSetError(Context
, AL_INVALID_NAME
);
1975 else if(!(value1
&& value2
&& value3
))
1976 alSetError(Context
, AL_INVALID_VALUE
);
1977 else if(!(FloatValsByProp(param
) == 3))
1978 alSetError(Context
, AL_INVALID_ENUM
);
1982 if(GetSourcedv(Source
, Context
, param
, dvals
))
1984 *value1
= (ALfloat
)dvals
[0];
1985 *value2
= (ALfloat
)dvals
[1];
1986 *value3
= (ALfloat
)dvals
[2];
1989 UnlockSourcesRead(Context
);
1990 ReadUnlock(&Context
->PropLock
);
1992 ALCcontext_DecRef(Context
);
1996 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
1998 ALCcontext
*Context
;
2002 Context
= GetContextRef();
2003 if(!Context
) return;
2005 ReadLock(&Context
->PropLock
);
2006 LockSourcesRead(Context
);
2007 if((Source
=LookupSource(Context
, source
)) == NULL
)
2008 alSetError(Context
, AL_INVALID_NAME
);
2010 alSetError(Context
, AL_INVALID_VALUE
);
2011 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2012 alSetError(Context
, AL_INVALID_ENUM
);
2016 if(GetSourcedv(Source
, Context
, param
, dvals
))
2019 for(i
= 0;i
< count
;i
++)
2020 values
[i
] = (ALfloat
)dvals
[i
];
2023 UnlockSourcesRead(Context
);
2024 ReadUnlock(&Context
->PropLock
);
2026 ALCcontext_DecRef(Context
);
2030 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2032 ALCcontext
*Context
;
2035 Context
= GetContextRef();
2036 if(!Context
) return;
2038 ReadLock(&Context
->PropLock
);
2039 LockSourcesRead(Context
);
2040 if((Source
=LookupSource(Context
, source
)) == NULL
)
2041 alSetError(Context
, AL_INVALID_NAME
);
2043 alSetError(Context
, AL_INVALID_VALUE
);
2044 else if(!(DoubleValsByProp(param
) == 1))
2045 alSetError(Context
, AL_INVALID_ENUM
);
2047 GetSourcedv(Source
, Context
, param
, value
);
2048 UnlockSourcesRead(Context
);
2049 ReadUnlock(&Context
->PropLock
);
2051 ALCcontext_DecRef(Context
);
2054 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2056 ALCcontext
*Context
;
2059 Context
= GetContextRef();
2060 if(!Context
) return;
2062 ReadLock(&Context
->PropLock
);
2063 LockSourcesRead(Context
);
2064 if((Source
=LookupSource(Context
, source
)) == NULL
)
2065 alSetError(Context
, AL_INVALID_NAME
);
2066 else if(!(value1
&& value2
&& value3
))
2067 alSetError(Context
, AL_INVALID_VALUE
);
2068 else if(!(DoubleValsByProp(param
) == 3))
2069 alSetError(Context
, AL_INVALID_ENUM
);
2073 if(GetSourcedv(Source
, Context
, param
, dvals
))
2080 UnlockSourcesRead(Context
);
2081 ReadUnlock(&Context
->PropLock
);
2083 ALCcontext_DecRef(Context
);
2086 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2088 ALCcontext
*Context
;
2091 Context
= GetContextRef();
2092 if(!Context
) return;
2094 ReadLock(&Context
->PropLock
);
2095 LockSourcesRead(Context
);
2096 if((Source
=LookupSource(Context
, source
)) == NULL
)
2097 alSetError(Context
, AL_INVALID_NAME
);
2099 alSetError(Context
, AL_INVALID_VALUE
);
2100 else if(!(DoubleValsByProp(param
) > 0))
2101 alSetError(Context
, AL_INVALID_ENUM
);
2103 GetSourcedv(Source
, Context
, param
, values
);
2104 UnlockSourcesRead(Context
);
2105 ReadUnlock(&Context
->PropLock
);
2107 ALCcontext_DecRef(Context
);
2111 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2113 ALCcontext
*Context
;
2116 Context
= GetContextRef();
2117 if(!Context
) return;
2119 ReadLock(&Context
->PropLock
);
2120 LockSourcesRead(Context
);
2121 if((Source
=LookupSource(Context
, source
)) == NULL
)
2122 alSetError(Context
, AL_INVALID_NAME
);
2124 alSetError(Context
, AL_INVALID_VALUE
);
2125 else if(!(IntValsByProp(param
) == 1))
2126 alSetError(Context
, AL_INVALID_ENUM
);
2128 GetSourceiv(Source
, Context
, param
, value
);
2129 UnlockSourcesRead(Context
);
2130 ReadUnlock(&Context
->PropLock
);
2132 ALCcontext_DecRef(Context
);
2136 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2138 ALCcontext
*Context
;
2141 Context
= GetContextRef();
2142 if(!Context
) return;
2144 ReadLock(&Context
->PropLock
);
2145 LockSourcesRead(Context
);
2146 if((Source
=LookupSource(Context
, source
)) == NULL
)
2147 alSetError(Context
, AL_INVALID_NAME
);
2148 else if(!(value1
&& value2
&& value3
))
2149 alSetError(Context
, AL_INVALID_VALUE
);
2150 else if(!(IntValsByProp(param
) == 3))
2151 alSetError(Context
, AL_INVALID_ENUM
);
2155 if(GetSourceiv(Source
, Context
, param
, ivals
))
2162 UnlockSourcesRead(Context
);
2163 ReadUnlock(&Context
->PropLock
);
2165 ALCcontext_DecRef(Context
);
2169 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2171 ALCcontext
*Context
;
2174 Context
= GetContextRef();
2175 if(!Context
) return;
2177 ReadLock(&Context
->PropLock
);
2178 LockSourcesRead(Context
);
2179 if((Source
=LookupSource(Context
, source
)) == NULL
)
2180 alSetError(Context
, AL_INVALID_NAME
);
2182 alSetError(Context
, AL_INVALID_VALUE
);
2183 else if(!(IntValsByProp(param
) > 0))
2184 alSetError(Context
, AL_INVALID_ENUM
);
2186 GetSourceiv(Source
, Context
, param
, values
);
2187 UnlockSourcesRead(Context
);
2188 ReadUnlock(&Context
->PropLock
);
2190 ALCcontext_DecRef(Context
);
2194 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2196 ALCcontext
*Context
;
2199 Context
= GetContextRef();
2200 if(!Context
) return;
2202 ReadLock(&Context
->PropLock
);
2203 LockSourcesRead(Context
);
2204 if((Source
=LookupSource(Context
, source
)) == NULL
)
2205 alSetError(Context
, AL_INVALID_NAME
);
2207 alSetError(Context
, AL_INVALID_VALUE
);
2208 else if(!(Int64ValsByProp(param
) == 1))
2209 alSetError(Context
, AL_INVALID_ENUM
);
2211 GetSourcei64v(Source
, Context
, param
, value
);
2212 UnlockSourcesRead(Context
);
2213 ReadUnlock(&Context
->PropLock
);
2215 ALCcontext_DecRef(Context
);
2218 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2220 ALCcontext
*Context
;
2223 Context
= GetContextRef();
2224 if(!Context
) return;
2226 ReadLock(&Context
->PropLock
);
2227 LockSourcesRead(Context
);
2228 if((Source
=LookupSource(Context
, source
)) == NULL
)
2229 alSetError(Context
, AL_INVALID_NAME
);
2230 else if(!(value1
&& value2
&& value3
))
2231 alSetError(Context
, AL_INVALID_VALUE
);
2232 else if(!(Int64ValsByProp(param
) == 3))
2233 alSetError(Context
, AL_INVALID_ENUM
);
2237 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2239 *value1
= i64vals
[0];
2240 *value2
= i64vals
[1];
2241 *value3
= i64vals
[2];
2244 UnlockSourcesRead(Context
);
2245 ReadUnlock(&Context
->PropLock
);
2247 ALCcontext_DecRef(Context
);
2250 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2252 ALCcontext
*Context
;
2255 Context
= GetContextRef();
2256 if(!Context
) return;
2258 ReadLock(&Context
->PropLock
);
2259 LockSourcesRead(Context
);
2260 if((Source
=LookupSource(Context
, source
)) == NULL
)
2261 alSetError(Context
, AL_INVALID_NAME
);
2263 alSetError(Context
, AL_INVALID_VALUE
);
2264 else if(!(Int64ValsByProp(param
) > 0))
2265 alSetError(Context
, AL_INVALID_ENUM
);
2267 GetSourcei64v(Source
, Context
, param
, values
);
2268 UnlockSourcesRead(Context
);
2269 ReadUnlock(&Context
->PropLock
);
2271 ALCcontext_DecRef(Context
);
2275 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2277 alSourcePlayv(1, &source
);
2279 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2281 ALCcontext
*context
;
2285 context
= GetContextRef();
2286 if(!context
) return;
2288 LockSourcesRead(context
);
2290 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2291 for(i
= 0;i
< n
;i
++)
2293 if(!LookupSource(context
, sources
[i
]))
2294 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2297 LockContext(context
);
2298 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2300 ALvoice
*temp
= NULL
;
2303 newcount
= context
->MaxVoices
<< 1;
2305 temp
= al_malloc(16, newcount
* sizeof(context
->Voices
[0]));
2308 UnlockContext(context
);
2309 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2311 memcpy(temp
, context
->Voices
, context
->MaxVoices
* sizeof(temp
[0]));
2312 memset(&temp
[context
->MaxVoices
], 0, (newcount
-context
->MaxVoices
) * sizeof(temp
[0]));
2314 al_free(context
->Voices
);
2315 context
->Voices
= temp
;
2316 context
->MaxVoices
= newcount
;
2319 for(i
= 0;i
< n
;i
++)
2321 source
= LookupSource(context
, sources
[i
]);
2322 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2323 source
->new_state
= AL_PLAYING
;
2325 SetSourceState(source
, context
, AL_PLAYING
);
2327 UnlockContext(context
);
2330 UnlockSourcesRead(context
);
2331 ALCcontext_DecRef(context
);
2334 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2336 alSourcePausev(1, &source
);
2338 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2340 ALCcontext
*context
;
2344 context
= GetContextRef();
2345 if(!context
) return;
2347 LockSourcesRead(context
);
2349 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2350 for(i
= 0;i
< n
;i
++)
2352 if(!LookupSource(context
, sources
[i
]))
2353 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2356 LockContext(context
);
2357 for(i
= 0;i
< n
;i
++)
2359 source
= LookupSource(context
, sources
[i
]);
2360 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2361 source
->new_state
= AL_PAUSED
;
2363 SetSourceState(source
, context
, AL_PAUSED
);
2365 UnlockContext(context
);
2368 UnlockSourcesRead(context
);
2369 ALCcontext_DecRef(context
);
2372 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2374 alSourceStopv(1, &source
);
2376 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2378 ALCcontext
*context
;
2382 context
= GetContextRef();
2383 if(!context
) return;
2385 LockSourcesRead(context
);
2387 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2388 for(i
= 0;i
< n
;i
++)
2390 if(!LookupSource(context
, sources
[i
]))
2391 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2394 LockContext(context
);
2395 for(i
= 0;i
< n
;i
++)
2397 source
= LookupSource(context
, sources
[i
]);
2398 source
->new_state
= AL_NONE
;
2399 SetSourceState(source
, context
, AL_STOPPED
);
2401 UnlockContext(context
);
2404 UnlockSourcesRead(context
);
2405 ALCcontext_DecRef(context
);
2408 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2410 alSourceRewindv(1, &source
);
2412 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2414 ALCcontext
*context
;
2418 context
= GetContextRef();
2419 if(!context
) return;
2421 LockSourcesRead(context
);
2423 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2424 for(i
= 0;i
< n
;i
++)
2426 if(!LookupSource(context
, sources
[i
]))
2427 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2430 LockContext(context
);
2431 for(i
= 0;i
< n
;i
++)
2433 source
= LookupSource(context
, sources
[i
]);
2434 source
->new_state
= AL_NONE
;
2435 SetSourceState(source
, context
, AL_INITIAL
);
2437 UnlockContext(context
);
2440 UnlockSourcesRead(context
);
2441 ALCcontext_DecRef(context
);
2445 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2448 ALCcontext
*context
;
2451 ALbufferlistitem
*BufferListStart
;
2452 ALbufferlistitem
*BufferList
;
2453 ALbuffer
*BufferFmt
= NULL
;
2458 context
= GetContextRef();
2459 if(!context
) return;
2461 device
= context
->Device
;
2463 LockSourcesRead(context
);
2465 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2466 if((source
=LookupSource(context
, src
)) == NULL
)
2467 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2469 WriteLock(&source
->queue_lock
);
2470 if(source
->SourceType
== AL_STATIC
)
2472 WriteUnlock(&source
->queue_lock
);
2473 /* Can't queue on a Static Source */
2474 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2477 /* Check for a valid Buffer, for its frequency and format */
2478 BufferList
= ATOMIC_LOAD(&source
->queue
);
2481 if(BufferList
->buffer
)
2483 BufferFmt
= BufferList
->buffer
;
2486 BufferList
= BufferList
->next
;
2489 LockBuffersRead(device
);
2490 BufferListStart
= NULL
;
2492 for(i
= 0;i
< nb
;i
++)
2494 ALbuffer
*buffer
= NULL
;
2495 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2497 WriteUnlock(&source
->queue_lock
);
2498 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2501 if(!BufferListStart
)
2503 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2504 BufferList
= BufferListStart
;
2508 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2509 BufferList
= BufferList
->next
;
2511 BufferList
->buffer
= buffer
;
2512 BufferList
->next
= NULL
;
2513 if(!buffer
) continue;
2515 /* Hold a read lock on each buffer being queued while checking all
2516 * provided buffers. This is done so other threads don't see an extra
2517 * reference on some buffers if this operation ends up failing. */
2518 ReadLock(&buffer
->lock
);
2519 IncrementRef(&buffer
->ref
);
2521 if(BufferFmt
== NULL
)
2525 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2526 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2528 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2529 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2530 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2532 WriteUnlock(&source
->queue_lock
);
2533 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2536 /* A buffer failed (invalid ID or format), so unlock and release
2537 * each buffer we had. */
2538 while(BufferListStart
)
2540 ALbufferlistitem
*next
= BufferListStart
->next
;
2541 if((buffer
=BufferListStart
->buffer
) != NULL
)
2543 DecrementRef(&buffer
->ref
);
2544 ReadUnlock(&buffer
->lock
);
2546 free(BufferListStart
);
2547 BufferListStart
= next
;
2549 UnlockBuffersRead(device
);
2553 /* All buffers good, unlock them now. */
2554 BufferList
= BufferListStart
;
2555 while(BufferList
!= NULL
)
2557 ALbuffer
*buffer
= BufferList
->buffer
;
2558 if(buffer
) ReadUnlock(&buffer
->lock
);
2559 BufferList
= BufferList
->next
;
2561 UnlockBuffersRead(device
);
2563 /* Source is now streaming */
2564 source
->SourceType
= AL_STREAMING
;
2567 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->queue
, &BufferList
, BufferListStart
))
2569 /* Queue head is not NULL, append to the end of the queue */
2570 while(BufferList
->next
!= NULL
)
2571 BufferList
= BufferList
->next
;
2572 BufferList
->next
= BufferListStart
;
2574 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2578 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->current_buffer
, &BufferList
, BufferListStart
);
2579 WriteUnlock(&source
->queue_lock
);
2582 UnlockSourcesRead(context
);
2583 ALCcontext_DecRef(context
);
2586 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2588 ALCcontext
*context
;
2590 ALbufferlistitem
*OldHead
;
2591 ALbufferlistitem
*OldTail
;
2592 ALbufferlistitem
*Current
;
2598 context
= GetContextRef();
2599 if(!context
) return;
2601 LockSourcesRead(context
);
2603 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2605 if((source
=LookupSource(context
, src
)) == NULL
)
2606 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2608 WriteLock(&source
->queue_lock
);
2609 if(ATOMIC_LOAD(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2611 WriteUnlock(&source
->queue_lock
);
2612 /* Trying to unqueue buffers on a looping or non-streaming source. */
2613 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2616 /* Find the new buffer queue head */
2617 OldTail
= ATOMIC_LOAD(&source
->queue
);
2618 Current
= ATOMIC_LOAD(&source
->current_buffer
);
2619 if(OldTail
!= Current
)
2621 for(i
= 1;i
< nb
;i
++)
2623 ALbufferlistitem
*next
= OldTail
->next
;
2624 if(!next
|| next
== Current
) break;
2630 WriteUnlock(&source
->queue_lock
);
2631 /* Trying to unqueue pending buffers. */
2632 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2635 /* Swap it, and cut the new head from the old. */
2636 OldHead
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2639 ALCdevice
*device
= context
->Device
;
2642 /* Once the active mix (if any) is done, it's safe to cut the old tail
2643 * from the new head.
2645 if(((count
=ReadRef(&device
->MixCount
))&1) != 0)
2647 while(count
== ReadRef(&device
->MixCount
))
2650 OldTail
->next
= NULL
;
2652 WriteUnlock(&source
->queue_lock
);
2654 while(OldHead
!= NULL
)
2656 ALbufferlistitem
*next
= OldHead
->next
;
2657 ALbuffer
*buffer
= OldHead
->buffer
;
2663 *(buffers
++) = buffer
->id
;
2664 DecrementRef(&buffer
->ref
);
2672 UnlockSourcesRead(context
);
2673 ALCcontext_DecRef(context
);
2677 static void InitSourceParams(ALsource
*Source
)
2681 RWLockInit(&Source
->queue_lock
);
2683 Source
->InnerAngle
= 360.0f
;
2684 Source
->OuterAngle
= 360.0f
;
2685 Source
->Pitch
= 1.0f
;
2686 Source
->Position
[0] = 0.0f
;
2687 Source
->Position
[1] = 0.0f
;
2688 Source
->Position
[2] = 0.0f
;
2689 Source
->Velocity
[0] = 0.0f
;
2690 Source
->Velocity
[1] = 0.0f
;
2691 Source
->Velocity
[2] = 0.0f
;
2692 Source
->Direction
[0] = 0.0f
;
2693 Source
->Direction
[1] = 0.0f
;
2694 Source
->Direction
[2] = 0.0f
;
2695 Source
->Orientation
[0][0] = 0.0f
;
2696 Source
->Orientation
[0][1] = 0.0f
;
2697 Source
->Orientation
[0][2] = -1.0f
;
2698 Source
->Orientation
[1][0] = 0.0f
;
2699 Source
->Orientation
[1][1] = 1.0f
;
2700 Source
->Orientation
[1][2] = 0.0f
;
2701 Source
->RefDistance
= 1.0f
;
2702 Source
->MaxDistance
= FLT_MAX
;
2703 Source
->RollOffFactor
= 1.0f
;
2704 Source
->Gain
= 1.0f
;
2705 Source
->MinGain
= 0.0f
;
2706 Source
->MaxGain
= 1.0f
;
2707 Source
->OuterGain
= 0.0f
;
2708 Source
->OuterGainHF
= 1.0f
;
2710 Source
->DryGainHFAuto
= AL_TRUE
;
2711 Source
->WetGainAuto
= AL_TRUE
;
2712 Source
->WetGainHFAuto
= AL_TRUE
;
2713 Source
->AirAbsorptionFactor
= 0.0f
;
2714 Source
->RoomRolloffFactor
= 0.0f
;
2715 Source
->DopplerFactor
= 1.0f
;
2716 Source
->DirectChannels
= AL_FALSE
;
2718 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2719 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2721 Source
->Radius
= 0.0f
;
2723 Source
->DistanceModel
= DefaultDistanceModel
;
2725 Source
->Direct
.Gain
= 1.0f
;
2726 Source
->Direct
.GainHF
= 1.0f
;
2727 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2728 Source
->Direct
.GainLF
= 1.0f
;
2729 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2730 for(i
= 0;i
< MAX_SENDS
;i
++)
2732 Source
->Send
[i
].Gain
= 1.0f
;
2733 Source
->Send
[i
].GainHF
= 1.0f
;
2734 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2735 Source
->Send
[i
].GainLF
= 1.0f
;
2736 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2739 Source
->Offset
= 0.0;
2740 Source
->OffsetType
= AL_NONE
;
2741 Source
->SourceType
= AL_UNDETERMINED
;
2742 Source
->state
= AL_INITIAL
;
2743 Source
->new_state
= AL_NONE
;
2745 ATOMIC_INIT(&Source
->queue
, NULL
);
2746 ATOMIC_INIT(&Source
->current_buffer
, NULL
);
2748 ATOMIC_INIT(&Source
->position
, 0);
2749 ATOMIC_INIT(&Source
->position_fraction
, 0);
2751 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2753 ATOMIC_INIT(&Source
->Update
, NULL
);
2754 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2757 static void DeinitSource(ALsource
*source
)
2759 ALbufferlistitem
*BufferList
;
2760 struct ALsourceProps
*props
;
2764 props
= ATOMIC_LOAD(&source
->Update
);
2765 if(props
) al_free(props
);
2767 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2770 struct ALsourceProps
*next
;
2771 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2776 /* This is excessively spammy if it traces every source destruction, so
2777 * just warn if it was unexpectedly large.
2780 WARN("Freed "SZFMT
" Source property objects\n", count
);
2782 BufferList
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &source
->queue
, NULL
);
2783 while(BufferList
!= NULL
)
2785 ALbufferlistitem
*next
= BufferList
->next
;
2786 if(BufferList
->buffer
!= NULL
)
2787 DecrementRef(&BufferList
->buffer
->ref
);
2792 for(i
= 0;i
< MAX_SENDS
;++i
)
2794 if(source
->Send
[i
].Slot
)
2795 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2796 source
->Send
[i
].Slot
= NULL
;
2800 static void UpdateSourceProps(ALsource
*source
, ALuint num_sends
, ALCcontext
*context
)
2802 struct ALsourceProps
*props
;
2805 /* Get an unused property container, or allocate a new one as needed. */
2806 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2808 props
= al_calloc(16, sizeof(*props
));
2811 struct ALsourceProps
*next
;
2813 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2814 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2815 &source
->FreeList
, &props
, next
, almemory_order_seq_cst
,
2816 almemory_order_consume
) == 0);
2819 /* Copy in current property values. */
2820 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2821 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2822 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2823 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2824 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2825 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2826 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2827 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2828 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2829 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2830 for(i
= 0;i
< 3;i
++)
2831 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2832 for(i
= 0;i
< 3;i
++)
2833 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2834 for(i
= 0;i
< 3;i
++)
2835 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2836 for(i
= 0;i
< 2;i
++)
2839 for(j
= 0;j
< 3;j
++)
2840 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2841 almemory_order_relaxed
);
2843 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2844 ATOMIC_STORE(&props
->DistanceModel
,
2845 context
->SourceDistanceModel
? source
->DistanceModel
: context
->DistanceModel
,
2846 almemory_order_relaxed
2848 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2850 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2851 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2852 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2853 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2855 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2856 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2857 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2859 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2860 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2862 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2864 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2865 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2866 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2867 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2868 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2870 for(i
= 0;i
< num_sends
;i
++)
2872 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2873 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2874 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2875 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2876 almemory_order_relaxed
);
2877 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2878 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2879 almemory_order_relaxed
);
2882 /* Set the new container for updating internal parameters. */
2883 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2886 /* If there was an unused update container, put it back in the
2889 struct ALsourceProps
*first
= ATOMIC_LOAD(&source
->FreeList
);
2891 ATOMIC_STORE(&props
->next
, first
, almemory_order_relaxed
);
2892 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2893 &source
->FreeList
, &first
, props
) == 0);
2897 void UpdateAllSourceProps(ALCcontext
*context
)
2899 ALuint num_sends
= context
->Device
->NumAuxSends
;
2903 /* Tell the mixer to stop applying updates, then wait for any active
2904 * updating to finish, before providing source updates.
2906 ATOMIC_STORE(&context
->HoldUpdates
, AL_TRUE
);
2907 while(((updates
=ReadRef(&context
->UpdateCount
))&1) != 0)
2909 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
2911 ALvoice
*voice
= &context
->Voices
[pos
];
2912 ALsource
*source
= voice
->Source
;
2913 if(source
!= NULL
&& (source
->state
== AL_PLAYING
||
2914 source
->state
== AL_PAUSED
))
2915 UpdateSourceProps(source
, num_sends
, context
);
2917 /* Now with all updates declared, let the mixer continue applying them so
2918 * they all happen at once.
2920 ATOMIC_STORE(&context
->HoldUpdates
, AL_FALSE
);
2926 * Sets the source's new play state given its current state.
2928 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2930 WriteLock(&Source
->queue_lock
);
2931 if(state
== AL_PLAYING
)
2933 ALCdevice
*device
= Context
->Device
;
2934 ALbufferlistitem
*BufferList
;
2935 ALboolean discontinuity
;
2936 ALvoice
*voice
= NULL
;
2939 /* Check that there is a queue containing at least one valid, non zero
2941 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2945 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2947 BufferList
= BufferList
->next
;
2950 if(Source
->state
!= AL_PAUSED
)
2952 Source
->state
= AL_PLAYING
;
2953 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
2954 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
2955 ATOMIC_STORE(&Source
->position_fraction
, 0);
2956 discontinuity
= AL_TRUE
;
2960 Source
->state
= AL_PLAYING
;
2961 discontinuity
= AL_FALSE
;
2964 // Check if an Offset has been set
2965 if(Source
->OffsetType
!= AL_NONE
)
2967 ApplyOffset(Source
);
2968 /* discontinuity = AL_TRUE;??? */
2971 /* If there's nothing to play, or device is disconnected, go right to
2973 if(!BufferList
|| !device
->Connected
)
2976 /* Make sure this source isn't already active, while looking for an
2977 * unused active source slot to put it in. */
2978 for(i
= 0;i
< Context
->VoiceCount
;i
++)
2980 ALsource
*old
= Source
;
2981 if(COMPARE_EXCHANGE(&Context
->Voices
[i
].Source
, &old
, NULL
))
2985 voice
= &Context
->Voices
[i
];
2986 voice
->Source
= Source
;
2991 if(voice
== NULL
&& COMPARE_EXCHANGE(&Context
->Voices
[i
].Source
, &old
, Source
))
2992 voice
= &Context
->Voices
[i
];
2996 voice
= &Context
->Voices
[Context
->VoiceCount
++];
2997 voice
->Source
= Source
;
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
->Chan
[i
].Direct
.Hrtf
.State
.History
[j
] = 0.0f
;
3017 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3019 voice
->Chan
[i
].Direct
.Hrtf
.State
.Values
[j
][0] = 0.0f
;
3020 voice
->Chan
[i
].Direct
.Hrtf
.State
.Values
[j
][1] = 0.0f
;
3024 UpdateSourceProps(Source
, device
->NumAuxSends
, Context
);
3026 else if(state
== AL_PAUSED
)
3028 if(Source
->state
== AL_PLAYING
)
3029 Source
->state
= AL_PAUSED
;
3031 else if(state
== AL_STOPPED
)
3034 if(Source
->state
!= AL_INITIAL
)
3036 Source
->state
= AL_STOPPED
;
3037 ATOMIC_STORE(&Source
->current_buffer
, NULL
);
3039 Source
->OffsetType
= AL_NONE
;
3040 Source
->Offset
= 0.0;
3042 else if(state
== AL_INITIAL
)
3044 if(Source
->state
!= AL_INITIAL
)
3046 Source
->state
= AL_INITIAL
;
3047 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD(&Source
->queue
),
3048 almemory_order_relaxed
);
3049 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
3050 ATOMIC_STORE(&Source
->position_fraction
, 0);
3052 Source
->OffsetType
= AL_NONE
;
3053 Source
->Offset
= 0.0;
3055 WriteUnlock(&Source
->queue_lock
);
3058 /* GetSourceSampleOffset
3060 * Gets the current read offset for the given Source, in 32.32 fixed-point
3061 * samples. The offset is relative to the start of the queue (not the start of
3062 * the current buffer).
3064 ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3066 const ALbufferlistitem
*BufferList
;
3067 const ALbufferlistitem
*Current
;
3071 ReadLock(&Source
->queue_lock
);
3072 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3074 ReadUnlock(&Source
->queue_lock
);
3076 while(((refcount
=ReadRef(&device
->MixCount
))&1))
3078 *clocktime
= GetDeviceClockTime(device
);
3079 } while(refcount
!= ReadRef(&device
->MixCount
));
3084 while(((refcount
=ReadRef(&device
->MixCount
))&1))
3086 *clocktime
= GetDeviceClockTime(device
);
3088 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3089 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3091 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) << 32;
3092 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
) <<
3094 } while(refcount
!= ReadRef(&device
->MixCount
));
3095 while(BufferList
&& BufferList
!= Current
)
3097 if(BufferList
->buffer
)
3098 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3099 BufferList
= BufferList
->next
;
3102 ReadUnlock(&Source
->queue_lock
);
3103 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
3106 /* GetSourceSecOffset
3108 * Gets the current read offset for the given Source, in seconds. The offset is
3109 * relative to the start of the queue (not the start of the current buffer).
3111 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3113 const ALbufferlistitem
*BufferList
;
3114 const ALbufferlistitem
*Current
;
3115 const ALbuffer
*Buffer
= NULL
;
3119 ReadLock(&Source
->queue_lock
);
3120 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3122 ReadUnlock(&Source
->queue_lock
);
3124 while(((refcount
=ReadRef(&device
->MixCount
))&1))
3126 *clocktime
= GetDeviceClockTime(device
);
3127 } while(refcount
!= ReadRef(&device
->MixCount
));
3132 while(((refcount
=ReadRef(&device
->MixCount
))&1))
3134 *clocktime
= GetDeviceClockTime(device
);
3136 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3137 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3139 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
)<<FRACTIONBITS
;
3140 readPos
|= (ALuint64
)ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3141 } while(refcount
!= ReadRef(&device
->MixCount
));
3142 while(BufferList
&& BufferList
!= Current
)
3144 const ALbuffer
*buffer
= BufferList
->buffer
;
3147 if(!Buffer
) Buffer
= buffer
;
3148 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3150 BufferList
= BufferList
->next
;
3153 while(BufferList
&& !Buffer
)
3155 Buffer
= BufferList
->buffer
;
3156 BufferList
= BufferList
->next
;
3158 assert(Buffer
!= NULL
);
3160 ReadUnlock(&Source
->queue_lock
);
3161 return (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/ (ALdouble
)Buffer
->Frequency
;
3166 * Gets the current read offset for the given Source, in the appropriate format
3167 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3168 * queue (not the start of the current buffer).
3170 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
)
3172 const ALbufferlistitem
*BufferList
;
3173 const ALbufferlistitem
*Current
;
3174 const ALbuffer
*Buffer
= NULL
;
3175 ALboolean readFin
= AL_FALSE
;
3176 ALuint readPos
, readPosFrac
;
3177 ALuint totalBufferLen
;
3178 ALdouble offset
= 0.0;
3182 ReadLock(&Source
->queue_lock
);
3183 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
3185 ReadUnlock(&Source
->queue_lock
);
3191 while(((refcount
=ReadRef(&device
->MixCount
))&1))
3193 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3194 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3196 readPos
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
3197 readPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3199 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3200 } while(refcount
!= ReadRef(&device
->MixCount
));
3202 while(BufferList
!= NULL
)
3204 const ALbuffer
*buffer
;
3205 readFin
= readFin
|| (BufferList
== Current
);
3206 if((buffer
=BufferList
->buffer
) != NULL
)
3208 if(!Buffer
) Buffer
= buffer
;
3209 totalBufferLen
+= buffer
->SampleLen
;
3210 if(!readFin
) readPos
+= buffer
->SampleLen
;
3212 BufferList
= BufferList
->next
;
3214 assert(Buffer
!= NULL
);
3217 readPos
%= totalBufferLen
;
3220 /* Wrap back to 0 */
3221 if(readPos
>= totalBufferLen
)
3222 readPos
= readPosFrac
= 0;
3228 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3231 case AL_SAMPLE_OFFSET
:
3232 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3235 case AL_BYTE_OFFSET
:
3236 if(Buffer
->OriginalType
== UserFmtIMA4
)
3238 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3239 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3240 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3242 /* Round down to nearest ADPCM block */
3243 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3245 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3247 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3248 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3249 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3251 /* Round down to nearest ADPCM block */
3252 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3256 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3257 offset
= (ALdouble
)(readPos
* FrameSize
);
3262 ReadUnlock(&Source
->queue_lock
);
3269 * Apply the stored playback offset to the Source. This function will update
3270 * the number of buffers "played" given the stored offset.
3272 ALboolean
ApplyOffset(ALsource
*Source
)
3274 ALbufferlistitem
*BufferList
;
3275 const ALbuffer
*Buffer
;
3276 ALuint bufferLen
, totalBufferLen
;
3277 ALuint offset
=0, frac
=0;
3279 /* Get sample frame offset */
3280 if(!GetSampleOffset(Source
, &offset
, &frac
))
3284 BufferList
= ATOMIC_LOAD(&Source
->queue
);
3285 while(BufferList
&& totalBufferLen
<= offset
)
3287 Buffer
= BufferList
->buffer
;
3288 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3290 if(bufferLen
> offset
-totalBufferLen
)
3292 /* Offset is in this buffer */
3293 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
3295 ATOMIC_STORE(&Source
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3296 ATOMIC_STORE(&Source
->position_fraction
, frac
);
3300 totalBufferLen
+= bufferLen
;
3302 BufferList
= BufferList
->next
;
3305 /* Offset is out of range of the queue */
3312 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3313 * or Second offset supplied by the application). This takes into account the
3314 * fact that the buffer format may have been modifed since.
3316 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3318 const ALbuffer
*Buffer
= NULL
;
3319 const ALbufferlistitem
*BufferList
;
3320 ALdouble dbloff
, dblfrac
;
3322 /* Find the first valid Buffer in the Queue */
3323 BufferList
= ATOMIC_LOAD(&Source
->queue
);
3326 if(BufferList
->buffer
)
3328 Buffer
= BufferList
->buffer
;
3331 BufferList
= BufferList
->next
;
3335 Source
->OffsetType
= AL_NONE
;
3336 Source
->Offset
= 0.0;
3340 switch(Source
->OffsetType
)
3342 case AL_BYTE_OFFSET
:
3343 /* Determine the ByteOffset (and ensure it is block aligned) */
3344 *offset
= (ALuint
)Source
->Offset
;
3345 if(Buffer
->OriginalType
== UserFmtIMA4
)
3347 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3348 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3349 *offset
*= Buffer
->OriginalAlign
;
3351 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3353 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3354 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3355 *offset
*= Buffer
->OriginalAlign
;
3358 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3362 case AL_SAMPLE_OFFSET
:
3363 dblfrac
= modf(Source
->Offset
, &dbloff
);
3364 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3365 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3369 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3370 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3371 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3374 Source
->OffsetType
= AL_NONE
;
3375 Source
->Offset
= 0.0;
3383 * Destroys all sources in the source map.
3385 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3388 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3390 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3391 Context
->SourceMap
.values
[pos
] = NULL
;
3395 FreeThunkEntry(temp
->id
);
3396 memset(temp
, 0, sizeof(*temp
));