2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
43 extern inline void LockSourcesRead(ALCcontext
*context
);
44 extern inline void UnlockSourcesRead(ALCcontext
*context
);
45 extern inline void LockSourcesWrite(ALCcontext
*context
);
46 extern inline void UnlockSourcesWrite(ALCcontext
*context
);
47 extern inline struct ALsource
*LookupSource(ALCcontext
*context
, ALuint id
);
48 extern inline struct ALsource
*RemoveSource(ALCcontext
*context
, ALuint id
);
49 extern inline ALboolean
IsPlayingOrPaused(const ALsource
*source
);
51 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
);
52 static void DeinitSource(ALsource
*source
, ALsizei num_sends
);
53 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
);
54 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
55 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
);
56 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
);
57 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
);
59 typedef enum SourceProp
{
62 srcMinGain
= AL_MIN_GAIN
,
63 srcMaxGain
= AL_MAX_GAIN
,
64 srcMaxDistance
= AL_MAX_DISTANCE
,
65 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
66 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
67 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
68 srcSecOffset
= AL_SEC_OFFSET
,
69 srcSampleOffset
= AL_SAMPLE_OFFSET
,
70 srcByteOffset
= AL_BYTE_OFFSET
,
71 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
72 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
73 srcRefDistance
= AL_REFERENCE_DISTANCE
,
75 srcPosition
= AL_POSITION
,
76 srcVelocity
= AL_VELOCITY
,
77 srcDirection
= AL_DIRECTION
,
79 srcSourceRelative
= AL_SOURCE_RELATIVE
,
80 srcLooping
= AL_LOOPING
,
81 srcBuffer
= AL_BUFFER
,
82 srcSourceState
= AL_SOURCE_STATE
,
83 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
84 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
85 srcSourceType
= AL_SOURCE_TYPE
,
88 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
89 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
90 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
91 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
92 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
93 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
94 srcDirectFilter
= AL_DIRECT_FILTER
,
95 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel
= AL_DISTANCE_MODEL
,
103 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
104 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
105 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
109 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles
= AL_STEREO_ANGLES
,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius
= AL_SOURCE_RADIUS
,
118 srcOrientation
= AL_ORIENTATION
,
121 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
122 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
123 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
125 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
126 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
127 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
129 static inline ALvoice
*GetSourceVoice(const ALsource
*source
, const ALCcontext
*context
)
131 ALvoice
**voice
= context
->Voices
;
132 ALvoice
**voice_end
= voice
+ context
->VoiceCount
;
133 while(voice
!= voice_end
)
135 if((*voice
)->Source
== source
)
142 static inline bool IsPlayingOrPausedSeq(const ALsource
*source
)
144 ALenum state
= ATOMIC_LOAD_SEQ(&source
->state
);
145 return state
== AL_PLAYING
|| state
== AL_PAUSED
;
148 static inline bool SourceShouldUpdate(const ALsource
*source
, const ALCcontext
*context
)
150 return IsPlayingOrPausedSeq(source
) &&
151 !ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
);
154 static ALint
FloatValsByProp(ALenum prop
)
156 if(prop
!= (ALenum
)((SourceProp
)prop
))
158 switch((SourceProp
)prop
)
164 case AL_MAX_DISTANCE
:
165 case AL_ROLLOFF_FACTOR
:
166 case AL_DOPPLER_FACTOR
:
167 case AL_CONE_OUTER_GAIN
:
169 case AL_SAMPLE_OFFSET
:
171 case AL_CONE_INNER_ANGLE
:
172 case AL_CONE_OUTER_ANGLE
:
173 case AL_REFERENCE_DISTANCE
:
174 case AL_CONE_OUTER_GAINHF
:
175 case AL_AIR_ABSORPTION_FACTOR
:
176 case AL_ROOM_ROLLOFF_FACTOR
:
177 case AL_DIRECT_FILTER_GAINHF_AUTO
:
178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
179 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
180 case AL_DIRECT_CHANNELS_SOFT
:
181 case AL_DISTANCE_MODEL
:
182 case AL_SOURCE_RELATIVE
:
184 case AL_SOURCE_STATE
:
185 case AL_BUFFERS_QUEUED
:
186 case AL_BUFFERS_PROCESSED
:
188 case AL_BYTE_LENGTH_SOFT
:
189 case AL_SAMPLE_LENGTH_SOFT
:
190 case AL_SEC_LENGTH_SOFT
:
191 case AL_SOURCE_RADIUS
:
194 case AL_STEREO_ANGLES
:
205 case AL_SEC_OFFSET_LATENCY_SOFT
:
206 break; /* Double only */
209 case AL_DIRECT_FILTER
:
210 case AL_AUXILIARY_SEND_FILTER
:
211 break; /* i/i64 only */
212 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
213 break; /* i64 only */
217 static ALint
DoubleValsByProp(ALenum prop
)
219 if(prop
!= (ALenum
)((SourceProp
)prop
))
221 switch((SourceProp
)prop
)
227 case AL_MAX_DISTANCE
:
228 case AL_ROLLOFF_FACTOR
:
229 case AL_DOPPLER_FACTOR
:
230 case AL_CONE_OUTER_GAIN
:
232 case AL_SAMPLE_OFFSET
:
234 case AL_CONE_INNER_ANGLE
:
235 case AL_CONE_OUTER_ANGLE
:
236 case AL_REFERENCE_DISTANCE
:
237 case AL_CONE_OUTER_GAINHF
:
238 case AL_AIR_ABSORPTION_FACTOR
:
239 case AL_ROOM_ROLLOFF_FACTOR
:
240 case AL_DIRECT_FILTER_GAINHF_AUTO
:
241 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
242 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
243 case AL_DIRECT_CHANNELS_SOFT
:
244 case AL_DISTANCE_MODEL
:
245 case AL_SOURCE_RELATIVE
:
247 case AL_SOURCE_STATE
:
248 case AL_BUFFERS_QUEUED
:
249 case AL_BUFFERS_PROCESSED
:
251 case AL_BYTE_LENGTH_SOFT
:
252 case AL_SAMPLE_LENGTH_SOFT
:
253 case AL_SEC_LENGTH_SOFT
:
254 case AL_SOURCE_RADIUS
:
257 case AL_SEC_OFFSET_LATENCY_SOFT
:
258 case AL_STEREO_ANGLES
:
270 case AL_DIRECT_FILTER
:
271 case AL_AUXILIARY_SEND_FILTER
:
272 break; /* i/i64 only */
273 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
274 break; /* i64 only */
279 static ALint
IntValsByProp(ALenum prop
)
281 if(prop
!= (ALenum
)((SourceProp
)prop
))
283 switch((SourceProp
)prop
)
289 case AL_MAX_DISTANCE
:
290 case AL_ROLLOFF_FACTOR
:
291 case AL_DOPPLER_FACTOR
:
292 case AL_CONE_OUTER_GAIN
:
294 case AL_SAMPLE_OFFSET
:
296 case AL_CONE_INNER_ANGLE
:
297 case AL_CONE_OUTER_ANGLE
:
298 case AL_REFERENCE_DISTANCE
:
299 case AL_CONE_OUTER_GAINHF
:
300 case AL_AIR_ABSORPTION_FACTOR
:
301 case AL_ROOM_ROLLOFF_FACTOR
:
302 case AL_DIRECT_FILTER_GAINHF_AUTO
:
303 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
304 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
305 case AL_DIRECT_CHANNELS_SOFT
:
306 case AL_DISTANCE_MODEL
:
307 case AL_SOURCE_RELATIVE
:
310 case AL_SOURCE_STATE
:
311 case AL_BUFFERS_QUEUED
:
312 case AL_BUFFERS_PROCESSED
:
314 case AL_DIRECT_FILTER
:
315 case AL_BYTE_LENGTH_SOFT
:
316 case AL_SAMPLE_LENGTH_SOFT
:
317 case AL_SEC_LENGTH_SOFT
:
318 case AL_SOURCE_RADIUS
:
324 case AL_AUXILIARY_SEND_FILTER
:
330 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
331 break; /* i64 only */
332 case AL_SEC_OFFSET_LATENCY_SOFT
:
333 break; /* Double only */
334 case AL_STEREO_ANGLES
:
335 break; /* Float/double only */
339 static ALint
Int64ValsByProp(ALenum prop
)
341 if(prop
!= (ALenum
)((SourceProp
)prop
))
343 switch((SourceProp
)prop
)
349 case AL_MAX_DISTANCE
:
350 case AL_ROLLOFF_FACTOR
:
351 case AL_DOPPLER_FACTOR
:
352 case AL_CONE_OUTER_GAIN
:
354 case AL_SAMPLE_OFFSET
:
356 case AL_CONE_INNER_ANGLE
:
357 case AL_CONE_OUTER_ANGLE
:
358 case AL_REFERENCE_DISTANCE
:
359 case AL_CONE_OUTER_GAINHF
:
360 case AL_AIR_ABSORPTION_FACTOR
:
361 case AL_ROOM_ROLLOFF_FACTOR
:
362 case AL_DIRECT_FILTER_GAINHF_AUTO
:
363 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
364 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
365 case AL_DIRECT_CHANNELS_SOFT
:
366 case AL_DISTANCE_MODEL
:
367 case AL_SOURCE_RELATIVE
:
370 case AL_SOURCE_STATE
:
371 case AL_BUFFERS_QUEUED
:
372 case AL_BUFFERS_PROCESSED
:
374 case AL_DIRECT_FILTER
:
375 case AL_BYTE_LENGTH_SOFT
:
376 case AL_SAMPLE_LENGTH_SOFT
:
377 case AL_SEC_LENGTH_SOFT
:
378 case AL_SOURCE_RADIUS
:
381 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
387 case AL_AUXILIARY_SEND_FILTER
:
393 case AL_SEC_OFFSET_LATENCY_SOFT
:
394 break; /* Double only */
395 case AL_STEREO_ANGLES
:
396 break; /* Float/double only */
402 #define CHECKVAL(x) do { \
404 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
407 #define DO_UPDATEPROPS() do { \
408 if(SourceShouldUpdate(Source, Context)) \
409 UpdateSourceProps(Source, device->NumAuxSends); \
411 Source->NeedsUpdate = AL_TRUE; \
414 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
416 ALCdevice
*device
= Context
->Device
;
421 case AL_BYTE_LENGTH_SOFT
:
422 case AL_SAMPLE_LENGTH_SOFT
:
423 case AL_SEC_LENGTH_SOFT
:
424 case AL_SEC_OFFSET_LATENCY_SOFT
:
426 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
429 CHECKVAL(*values
>= 0.0f
);
431 Source
->Pitch
= *values
;
435 case AL_CONE_INNER_ANGLE
:
436 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
438 Source
->InnerAngle
= *values
;
442 case AL_CONE_OUTER_ANGLE
:
443 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
445 Source
->OuterAngle
= *values
;
450 CHECKVAL(*values
>= 0.0f
);
452 Source
->Gain
= *values
;
456 case AL_MAX_DISTANCE
:
457 CHECKVAL(*values
>= 0.0f
);
459 Source
->MaxDistance
= *values
;
463 case AL_ROLLOFF_FACTOR
:
464 CHECKVAL(*values
>= 0.0f
);
466 Source
->RollOffFactor
= *values
;
470 case AL_REFERENCE_DISTANCE
:
471 CHECKVAL(*values
>= 0.0f
);
473 Source
->RefDistance
= *values
;
478 CHECKVAL(*values
>= 0.0f
);
480 Source
->MinGain
= *values
;
485 CHECKVAL(*values
>= 0.0f
);
487 Source
->MaxGain
= *values
;
491 case AL_CONE_OUTER_GAIN
:
492 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
494 Source
->OuterGain
= *values
;
498 case AL_CONE_OUTER_GAINHF
:
499 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
501 Source
->OuterGainHF
= *values
;
505 case AL_AIR_ABSORPTION_FACTOR
:
506 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
508 Source
->AirAbsorptionFactor
= *values
;
512 case AL_ROOM_ROLLOFF_FACTOR
:
513 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
515 Source
->RoomRolloffFactor
= *values
;
519 case AL_DOPPLER_FACTOR
:
520 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
522 Source
->DopplerFactor
= *values
;
527 case AL_SAMPLE_OFFSET
:
529 CHECKVAL(*values
>= 0.0f
);
531 Source
->OffsetType
= prop
;
532 Source
->Offset
= *values
;
534 if(IsPlayingOrPausedSeq(Source
) &&
535 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
537 ALCdevice_Lock(Context
->Device
);
538 /* Double-check that the source is still playing while we have
541 if(IsPlayingOrPaused(Source
))
543 WriteLock(&Source
->queue_lock
);
544 if(ApplyOffset(Source
) == AL_FALSE
)
546 WriteUnlock(&Source
->queue_lock
);
547 ALCdevice_Unlock(Context
->Device
);
548 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
550 WriteUnlock(&Source
->queue_lock
);
552 ALCdevice_Unlock(Context
->Device
);
556 case AL_SOURCE_RADIUS
:
557 CHECKVAL(*values
>= 0.0f
&& isfinite(*values
));
559 Source
->Radius
= *values
;
563 case AL_STEREO_ANGLES
:
564 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]));
566 Source
->StereoPan
[0] = values
[0];
567 Source
->StereoPan
[1] = values
[1];
573 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
575 Source
->Position
[0] = values
[0];
576 Source
->Position
[1] = values
[1];
577 Source
->Position
[2] = values
[2];
582 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
584 Source
->Velocity
[0] = values
[0];
585 Source
->Velocity
[1] = values
[1];
586 Source
->Velocity
[2] = values
[2];
591 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
593 Source
->Direction
[0] = values
[0];
594 Source
->Direction
[1] = values
[1];
595 Source
->Direction
[2] = values
[2];
600 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
601 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
603 Source
->Orientation
[0][0] = values
[0];
604 Source
->Orientation
[0][1] = values
[1];
605 Source
->Orientation
[0][2] = values
[2];
606 Source
->Orientation
[1][0] = values
[3];
607 Source
->Orientation
[1][1] = values
[4];
608 Source
->Orientation
[1][2] = values
[5];
613 case AL_SOURCE_RELATIVE
:
615 case AL_SOURCE_STATE
:
617 case AL_DISTANCE_MODEL
:
618 case AL_DIRECT_FILTER_GAINHF_AUTO
:
619 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
620 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
621 case AL_DIRECT_CHANNELS_SOFT
:
622 ival
= (ALint
)values
[0];
623 return SetSourceiv(Source
, Context
, prop
, &ival
);
625 case AL_BUFFERS_QUEUED
:
626 case AL_BUFFERS_PROCESSED
:
627 ival
= (ALint
)((ALuint
)values
[0]);
628 return SetSourceiv(Source
, Context
, prop
, &ival
);
631 case AL_DIRECT_FILTER
:
632 case AL_AUXILIARY_SEND_FILTER
:
633 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
637 ERR("Unexpected property: 0x%04x\n", prop
);
638 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
641 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
643 ALCdevice
*device
= Context
->Device
;
644 ALbuffer
*buffer
= NULL
;
645 ALfilter
*filter
= NULL
;
646 ALeffectslot
*slot
= NULL
;
647 ALbufferlistitem
*oldlist
;
648 ALbufferlistitem
*newlist
;
653 case AL_SOURCE_STATE
:
655 case AL_BUFFERS_QUEUED
:
656 case AL_BUFFERS_PROCESSED
:
657 case AL_BYTE_LENGTH_SOFT
:
658 case AL_SAMPLE_LENGTH_SOFT
:
659 case AL_SEC_LENGTH_SOFT
:
661 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
663 case AL_SOURCE_RELATIVE
:
664 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
666 Source
->HeadRelative
= (ALboolean
)*values
;
671 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
673 WriteLock(&Source
->queue_lock
);
674 ATOMIC_STORE_SEQ(&Source
->looping
, *values
);
675 WriteUnlock(&Source
->queue_lock
);
679 LockBuffersRead(device
);
680 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
))
682 UnlockBuffersRead(device
);
683 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
686 WriteLock(&Source
->queue_lock
);
687 if(IsPlayingOrPausedSeq(Source
))
689 WriteUnlock(&Source
->queue_lock
);
690 UnlockBuffersRead(device
);
691 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
696 /* Add the selected buffer to a one-item queue */
697 newlist
= malloc(sizeof(ALbufferlistitem
));
698 newlist
->buffer
= buffer
;
699 newlist
->next
= NULL
;
700 IncrementRef(&buffer
->ref
);
702 /* Source is now Static */
703 Source
->SourceType
= AL_STATIC
;
705 ReadLock(&buffer
->lock
);
706 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
707 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
708 ReadUnlock(&buffer
->lock
);
712 /* Source is now Undetermined */
713 Source
->SourceType
= AL_UNDETERMINED
;
716 oldlist
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &Source
->queue
, newlist
);
717 ATOMIC_STORE_SEQ(&Source
->current_buffer
, newlist
);
718 WriteUnlock(&Source
->queue_lock
);
719 UnlockBuffersRead(device
);
721 /* Delete all elements in the previous queue */
722 while(oldlist
!= NULL
)
724 ALbufferlistitem
*temp
= oldlist
;
725 oldlist
= temp
->next
;
728 DecrementRef(&temp
->buffer
->ref
);
734 case AL_SAMPLE_OFFSET
:
736 CHECKVAL(*values
>= 0);
738 Source
->OffsetType
= prop
;
739 Source
->Offset
= *values
;
741 if(IsPlayingOrPausedSeq(Source
) &&
742 !ATOMIC_LOAD(&Context
->DeferUpdates
, almemory_order_acquire
))
744 ALCdevice_Lock(Context
->Device
);
745 if(IsPlayingOrPaused(Source
))
747 WriteLock(&Source
->queue_lock
);
748 if(ApplyOffset(Source
) == AL_FALSE
)
750 WriteUnlock(&Source
->queue_lock
);
751 ALCdevice_Unlock(Context
->Device
);
752 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
754 WriteUnlock(&Source
->queue_lock
);
756 ALCdevice_Unlock(Context
->Device
);
760 case AL_DIRECT_FILTER
:
761 LockFiltersRead(device
);
762 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
))
764 UnlockFiltersRead(device
);
765 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
770 Source
->Direct
.Gain
= 1.0f
;
771 Source
->Direct
.GainHF
= 1.0f
;
772 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
773 Source
->Direct
.GainLF
= 1.0f
;
774 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
778 Source
->Direct
.Gain
= filter
->Gain
;
779 Source
->Direct
.GainHF
= filter
->GainHF
;
780 Source
->Direct
.HFReference
= filter
->HFReference
;
781 Source
->Direct
.GainLF
= filter
->GainLF
;
782 Source
->Direct
.LFReference
= filter
->LFReference
;
784 UnlockFiltersRead(device
);
788 case AL_DIRECT_FILTER_GAINHF_AUTO
:
789 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
791 Source
->DryGainHFAuto
= *values
;
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
796 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
798 Source
->WetGainAuto
= *values
;
802 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
803 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
805 Source
->WetGainHFAuto
= *values
;
809 case AL_DIRECT_CHANNELS_SOFT
:
810 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
812 Source
->DirectChannels
= *values
;
816 case AL_DISTANCE_MODEL
:
817 CHECKVAL(*values
== AL_NONE
||
818 *values
== AL_INVERSE_DISTANCE
||
819 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
820 *values
== AL_LINEAR_DISTANCE
||
821 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
822 *values
== AL_EXPONENT_DISTANCE
||
823 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
825 Source
->DistanceModel
= *values
;
826 if(Context
->SourceDistanceModel
)
831 case AL_AUXILIARY_SEND_FILTER
:
832 LockEffectSlotsRead(Context
);
833 LockFiltersRead(device
);
834 if(!((ALuint
)values
[1] < (ALuint
)device
->NumAuxSends
&&
835 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
836 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
838 UnlockFiltersRead(device
);
839 UnlockEffectSlotsRead(Context
);
840 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
846 Source
->Send
[values
[1]].Gain
= 1.0f
;
847 Source
->Send
[values
[1]].GainHF
= 1.0f
;
848 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
849 Source
->Send
[values
[1]].GainLF
= 1.0f
;
850 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
854 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
855 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
856 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
857 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
858 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
860 UnlockFiltersRead(device
);
862 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPausedSeq(Source
))
864 /* Add refcount on the new slot, and release the previous slot */
865 if(slot
) IncrementRef(&slot
->ref
);
866 if(Source
->Send
[values
[1]].Slot
)
867 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
868 Source
->Send
[values
[1]].Slot
= slot
;
870 /* We must force an update if the auxiliary slot changed on a
871 * playing source, in case the slot is about to be deleted.
873 UpdateSourceProps(Source
, device
->NumAuxSends
);
877 if(slot
) IncrementRef(&slot
->ref
);
878 if(Source
->Send
[values
[1]].Slot
)
879 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
880 Source
->Send
[values
[1]].Slot
= slot
;
883 UnlockEffectSlotsRead(Context
);
889 case AL_CONE_INNER_ANGLE
:
890 case AL_CONE_OUTER_ANGLE
:
895 case AL_REFERENCE_DISTANCE
:
896 case AL_ROLLOFF_FACTOR
:
897 case AL_CONE_OUTER_GAIN
:
898 case AL_MAX_DISTANCE
:
899 case AL_DOPPLER_FACTOR
:
900 case AL_CONE_OUTER_GAINHF
:
901 case AL_AIR_ABSORPTION_FACTOR
:
902 case AL_ROOM_ROLLOFF_FACTOR
:
903 case AL_SOURCE_RADIUS
:
904 fvals
[0] = (ALfloat
)*values
;
905 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
911 fvals
[0] = (ALfloat
)values
[0];
912 fvals
[1] = (ALfloat
)values
[1];
913 fvals
[2] = (ALfloat
)values
[2];
914 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
918 fvals
[0] = (ALfloat
)values
[0];
919 fvals
[1] = (ALfloat
)values
[1];
920 fvals
[2] = (ALfloat
)values
[2];
921 fvals
[3] = (ALfloat
)values
[3];
922 fvals
[4] = (ALfloat
)values
[4];
923 fvals
[5] = (ALfloat
)values
[5];
924 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
926 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
927 case AL_SEC_OFFSET_LATENCY_SOFT
:
928 case AL_STEREO_ANGLES
:
932 ERR("Unexpected property: 0x%04x\n", prop
);
933 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
936 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
944 case AL_BUFFERS_QUEUED
:
945 case AL_BUFFERS_PROCESSED
:
946 case AL_SOURCE_STATE
:
947 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
948 case AL_BYTE_LENGTH_SOFT
:
949 case AL_SAMPLE_LENGTH_SOFT
:
950 case AL_SEC_LENGTH_SOFT
:
952 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
956 case AL_SOURCE_RELATIVE
:
959 case AL_SAMPLE_OFFSET
:
961 case AL_DIRECT_FILTER_GAINHF_AUTO
:
962 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
963 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
964 case AL_DIRECT_CHANNELS_SOFT
:
965 case AL_DISTANCE_MODEL
:
966 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
968 ivals
[0] = (ALint
)*values
;
969 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
973 case AL_DIRECT_FILTER
:
974 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
976 ivals
[0] = (ALuint
)*values
;
977 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
980 case AL_AUXILIARY_SEND_FILTER
:
981 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
982 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
983 values
[2] <= UINT_MAX
&& values
[2] >= 0);
985 ivals
[0] = (ALuint
)values
[0];
986 ivals
[1] = (ALuint
)values
[1];
987 ivals
[2] = (ALuint
)values
[2];
988 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
991 case AL_CONE_INNER_ANGLE
:
992 case AL_CONE_OUTER_ANGLE
:
997 case AL_REFERENCE_DISTANCE
:
998 case AL_ROLLOFF_FACTOR
:
999 case AL_CONE_OUTER_GAIN
:
1000 case AL_MAX_DISTANCE
:
1001 case AL_DOPPLER_FACTOR
:
1002 case AL_CONE_OUTER_GAINHF
:
1003 case AL_AIR_ABSORPTION_FACTOR
:
1004 case AL_ROOM_ROLLOFF_FACTOR
:
1005 case AL_SOURCE_RADIUS
:
1006 fvals
[0] = (ALfloat
)*values
;
1007 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1013 fvals
[0] = (ALfloat
)values
[0];
1014 fvals
[1] = (ALfloat
)values
[1];
1015 fvals
[2] = (ALfloat
)values
[2];
1016 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1019 case AL_ORIENTATION
:
1020 fvals
[0] = (ALfloat
)values
[0];
1021 fvals
[1] = (ALfloat
)values
[1];
1022 fvals
[2] = (ALfloat
)values
[2];
1023 fvals
[3] = (ALfloat
)values
[3];
1024 fvals
[4] = (ALfloat
)values
[4];
1025 fvals
[5] = (ALfloat
)values
[5];
1026 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
1028 case AL_SEC_OFFSET_LATENCY_SOFT
:
1029 case AL_STEREO_ANGLES
:
1033 ERR("Unexpected property: 0x%04x\n", prop
);
1034 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1040 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1042 ALCdevice
*device
= Context
->Device
;
1043 ALbufferlistitem
*BufferList
;
1044 ClockLatency clocktime
;
1052 *values
= Source
->Gain
;
1056 *values
= Source
->Pitch
;
1059 case AL_MAX_DISTANCE
:
1060 *values
= Source
->MaxDistance
;
1063 case AL_ROLLOFF_FACTOR
:
1064 *values
= Source
->RollOffFactor
;
1067 case AL_REFERENCE_DISTANCE
:
1068 *values
= Source
->RefDistance
;
1071 case AL_CONE_INNER_ANGLE
:
1072 *values
= Source
->InnerAngle
;
1075 case AL_CONE_OUTER_ANGLE
:
1076 *values
= Source
->OuterAngle
;
1080 *values
= Source
->MinGain
;
1084 *values
= Source
->MaxGain
;
1087 case AL_CONE_OUTER_GAIN
:
1088 *values
= Source
->OuterGain
;
1092 case AL_SAMPLE_OFFSET
:
1093 case AL_BYTE_OFFSET
:
1094 *values
= GetSourceOffset(Source
, prop
, device
);
1097 case AL_CONE_OUTER_GAINHF
:
1098 *values
= Source
->OuterGainHF
;
1101 case AL_AIR_ABSORPTION_FACTOR
:
1102 *values
= Source
->AirAbsorptionFactor
;
1105 case AL_ROOM_ROLLOFF_FACTOR
:
1106 *values
= Source
->RoomRolloffFactor
;
1109 case AL_DOPPLER_FACTOR
:
1110 *values
= Source
->DopplerFactor
;
1113 case AL_SEC_LENGTH_SOFT
:
1114 ReadLock(&Source
->queue_lock
);
1115 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1122 ALbuffer
*buffer
= BufferList
->buffer
;
1123 if(buffer
&& buffer
->SampleLen
> 0)
1125 freq
= buffer
->Frequency
;
1126 length
+= buffer
->SampleLen
;
1128 } while((BufferList
=BufferList
->next
) != NULL
);
1129 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1131 ReadUnlock(&Source
->queue_lock
);
1134 case AL_SOURCE_RADIUS
:
1135 *values
= Source
->Radius
;
1138 case AL_STEREO_ANGLES
:
1139 values
[0] = Source
->StereoPan
[0];
1140 values
[1] = Source
->StereoPan
[1];
1143 case AL_SEC_OFFSET_LATENCY_SOFT
:
1144 /* Get the source offset with the clock time first. Then get the
1145 * clock time with the device latency. Order is important.
1147 values
[0] = GetSourceSecOffset(Source
, device
, &srcclock
);
1148 clocktime
= V0(device
->Backend
,getClockLatency
)();
1149 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1150 values
[1] = (ALdouble
)clocktime
.Latency
/ 1000000000.0;
1153 /* If the clock time incremented, reduce the latency by that
1154 * much since it's that much closer to the source offset it got
1157 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1158 values
[1] = (ALdouble
)(clocktime
.Latency
- minu64(clocktime
.Latency
, diff
)) /
1164 values
[0] = Source
->Position
[0];
1165 values
[1] = Source
->Position
[1];
1166 values
[2] = Source
->Position
[2];
1170 values
[0] = Source
->Velocity
[0];
1171 values
[1] = Source
->Velocity
[1];
1172 values
[2] = Source
->Velocity
[2];
1176 values
[0] = Source
->Direction
[0];
1177 values
[1] = Source
->Direction
[1];
1178 values
[2] = Source
->Direction
[2];
1181 case AL_ORIENTATION
:
1182 values
[0] = Source
->Orientation
[0][0];
1183 values
[1] = Source
->Orientation
[0][1];
1184 values
[2] = Source
->Orientation
[0][2];
1185 values
[3] = Source
->Orientation
[1][0];
1186 values
[4] = Source
->Orientation
[1][1];
1187 values
[5] = Source
->Orientation
[1][2];
1191 case AL_SOURCE_RELATIVE
:
1193 case AL_SOURCE_STATE
:
1194 case AL_BUFFERS_QUEUED
:
1195 case AL_BUFFERS_PROCESSED
:
1196 case AL_SOURCE_TYPE
:
1197 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1198 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1199 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1200 case AL_DIRECT_CHANNELS_SOFT
:
1201 case AL_BYTE_LENGTH_SOFT
:
1202 case AL_SAMPLE_LENGTH_SOFT
:
1203 case AL_DISTANCE_MODEL
:
1204 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1205 *values
= (ALdouble
)ivals
[0];
1209 case AL_DIRECT_FILTER
:
1210 case AL_AUXILIARY_SEND_FILTER
:
1211 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1215 ERR("Unexpected property: 0x%04x\n", prop
);
1216 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1219 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1221 ALbufferlistitem
*BufferList
;
1227 case AL_SOURCE_RELATIVE
:
1228 *values
= Source
->HeadRelative
;
1232 *values
= ATOMIC_LOAD_SEQ(&Source
->looping
);
1236 ReadLock(&Source
->queue_lock
);
1237 BufferList
= (Source
->SourceType
== AL_STATIC
) ?
1238 ATOMIC_LOAD_SEQ(&Source
->queue
) :
1239 ATOMIC_LOAD_SEQ(&Source
->current_buffer
);
1240 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1241 ReadUnlock(&Source
->queue_lock
);
1244 case AL_SOURCE_STATE
:
1245 *values
= ATOMIC_LOAD_SEQ(&Source
->state
);
1248 case AL_BYTE_LENGTH_SOFT
:
1249 ReadLock(&Source
->queue_lock
);
1250 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1256 ALbuffer
*buffer
= BufferList
->buffer
;
1257 if(buffer
&& buffer
->SampleLen
> 0)
1259 ALuint byte_align
, sample_align
;
1260 if(buffer
->OriginalType
== UserFmtIMA4
)
1262 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1263 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1264 sample_align
= buffer
->OriginalAlign
;
1266 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1268 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1269 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1270 sample_align
= buffer
->OriginalAlign
;
1274 ALsizei align
= buffer
->OriginalAlign
;
1275 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1276 sample_align
= buffer
->OriginalAlign
;
1279 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1281 } while((BufferList
=BufferList
->next
) != NULL
);
1284 ReadUnlock(&Source
->queue_lock
);
1287 case AL_SAMPLE_LENGTH_SOFT
:
1288 ReadLock(&Source
->queue_lock
);
1289 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1295 ALbuffer
*buffer
= BufferList
->buffer
;
1296 if(buffer
) length
+= buffer
->SampleLen
;
1297 } while((BufferList
=BufferList
->next
) != NULL
);
1300 ReadUnlock(&Source
->queue_lock
);
1303 case AL_BUFFERS_QUEUED
:
1304 ReadLock(&Source
->queue_lock
);
1305 if(!(BufferList
=ATOMIC_LOAD_SEQ(&Source
->queue
)))
1312 } while((BufferList
=BufferList
->next
) != NULL
);
1315 ReadUnlock(&Source
->queue_lock
);
1318 case AL_BUFFERS_PROCESSED
:
1319 ReadLock(&Source
->queue_lock
);
1320 if(ATOMIC_LOAD_SEQ(&Source
->looping
) || Source
->SourceType
!= AL_STREAMING
)
1322 /* Buffers on a looping source are in a perpetual state of
1323 * PENDING, so don't report any as PROCESSED */
1328 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
1329 const ALbufferlistitem
*Current
= ATOMIC_LOAD_SEQ(&Source
->current_buffer
);
1331 while(BufferList
&& BufferList
!= Current
)
1334 BufferList
= BufferList
->next
;
1338 ReadUnlock(&Source
->queue_lock
);
1341 case AL_SOURCE_TYPE
:
1342 *values
= Source
->SourceType
;
1345 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1346 *values
= Source
->DryGainHFAuto
;
1349 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1350 *values
= Source
->WetGainAuto
;
1353 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1354 *values
= Source
->WetGainHFAuto
;
1357 case AL_DIRECT_CHANNELS_SOFT
:
1358 *values
= Source
->DirectChannels
;
1361 case AL_DISTANCE_MODEL
:
1362 *values
= Source
->DistanceModel
;
1365 /* 1x float/double */
1366 case AL_CONE_INNER_ANGLE
:
1367 case AL_CONE_OUTER_ANGLE
:
1372 case AL_REFERENCE_DISTANCE
:
1373 case AL_ROLLOFF_FACTOR
:
1374 case AL_CONE_OUTER_GAIN
:
1375 case AL_MAX_DISTANCE
:
1377 case AL_SAMPLE_OFFSET
:
1378 case AL_BYTE_OFFSET
:
1379 case AL_DOPPLER_FACTOR
:
1380 case AL_AIR_ABSORPTION_FACTOR
:
1381 case AL_ROOM_ROLLOFF_FACTOR
:
1382 case AL_CONE_OUTER_GAINHF
:
1383 case AL_SEC_LENGTH_SOFT
:
1384 case AL_SOURCE_RADIUS
:
1385 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1386 *values
= (ALint
)dvals
[0];
1389 /* 3x float/double */
1393 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1395 values
[0] = (ALint
)dvals
[0];
1396 values
[1] = (ALint
)dvals
[1];
1397 values
[2] = (ALint
)dvals
[2];
1401 /* 6x float/double */
1402 case AL_ORIENTATION
:
1403 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1405 values
[0] = (ALint
)dvals
[0];
1406 values
[1] = (ALint
)dvals
[1];
1407 values
[2] = (ALint
)dvals
[2];
1408 values
[3] = (ALint
)dvals
[3];
1409 values
[4] = (ALint
)dvals
[4];
1410 values
[5] = (ALint
)dvals
[5];
1414 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1415 break; /* i64 only */
1416 case AL_SEC_OFFSET_LATENCY_SOFT
:
1417 break; /* Double only */
1418 case AL_STEREO_ANGLES
:
1419 break; /* Float/double only */
1421 case AL_DIRECT_FILTER
:
1422 case AL_AUXILIARY_SEND_FILTER
:
1426 ERR("Unexpected property: 0x%04x\n", prop
);
1427 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1430 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1432 ALCdevice
*device
= Context
->Device
;
1433 ClockLatency clocktime
;
1441 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1442 /* Get the source offset with the clock time first. Then get the
1443 * clock time with the device latency. Order is important.
1445 values
[0] = GetSourceSampleOffset(Source
, device
, &srcclock
);
1446 clocktime
= V0(device
->Backend
,getClockLatency
)();
1447 if(srcclock
== (ALuint64
)clocktime
.ClockTime
)
1448 values
[1] = clocktime
.Latency
;
1451 /* If the clock time incremented, reduce the latency by that
1452 * much since it's that much closer to the source offset it got
1455 ALuint64 diff
= clocktime
.ClockTime
- srcclock
;
1456 values
[1] = clocktime
.Latency
- minu64(clocktime
.Latency
, diff
);
1460 /* 1x float/double */
1461 case AL_CONE_INNER_ANGLE
:
1462 case AL_CONE_OUTER_ANGLE
:
1467 case AL_REFERENCE_DISTANCE
:
1468 case AL_ROLLOFF_FACTOR
:
1469 case AL_CONE_OUTER_GAIN
:
1470 case AL_MAX_DISTANCE
:
1472 case AL_SAMPLE_OFFSET
:
1473 case AL_BYTE_OFFSET
:
1474 case AL_DOPPLER_FACTOR
:
1475 case AL_AIR_ABSORPTION_FACTOR
:
1476 case AL_ROOM_ROLLOFF_FACTOR
:
1477 case AL_CONE_OUTER_GAINHF
:
1478 case AL_SEC_LENGTH_SOFT
:
1479 case AL_SOURCE_RADIUS
:
1480 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1481 *values
= (ALint64
)dvals
[0];
1484 /* 3x float/double */
1488 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1490 values
[0] = (ALint64
)dvals
[0];
1491 values
[1] = (ALint64
)dvals
[1];
1492 values
[2] = (ALint64
)dvals
[2];
1496 /* 6x float/double */
1497 case AL_ORIENTATION
:
1498 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1500 values
[0] = (ALint64
)dvals
[0];
1501 values
[1] = (ALint64
)dvals
[1];
1502 values
[2] = (ALint64
)dvals
[2];
1503 values
[3] = (ALint64
)dvals
[3];
1504 values
[4] = (ALint64
)dvals
[4];
1505 values
[5] = (ALint64
)dvals
[5];
1510 case AL_SOURCE_RELATIVE
:
1512 case AL_SOURCE_STATE
:
1513 case AL_BUFFERS_QUEUED
:
1514 case AL_BUFFERS_PROCESSED
:
1515 case AL_BYTE_LENGTH_SOFT
:
1516 case AL_SAMPLE_LENGTH_SOFT
:
1517 case AL_SOURCE_TYPE
:
1518 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1519 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1520 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1521 case AL_DIRECT_CHANNELS_SOFT
:
1522 case AL_DISTANCE_MODEL
:
1523 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1529 case AL_DIRECT_FILTER
:
1530 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1531 *values
= (ALuint
)ivals
[0];
1535 case AL_AUXILIARY_SEND_FILTER
:
1536 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1538 values
[0] = (ALuint
)ivals
[0];
1539 values
[1] = (ALuint
)ivals
[1];
1540 values
[2] = (ALuint
)ivals
[2];
1544 case AL_SEC_OFFSET_LATENCY_SOFT
:
1545 break; /* Double only */
1546 case AL_STEREO_ANGLES
:
1547 break; /* Float/double only */
1550 ERR("Unexpected property: 0x%04x\n", prop
);
1551 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1555 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1558 ALCcontext
*context
;
1562 context
= GetContextRef();
1563 if(!context
) return;
1566 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1567 device
= context
->Device
;
1568 for(cur
= 0;cur
< n
;cur
++)
1570 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1573 alDeleteSources(cur
, sources
);
1574 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1576 InitSourceParams(source
, device
->NumAuxSends
);
1578 err
= NewThunkEntry(&source
->id
);
1579 if(err
== AL_NO_ERROR
)
1580 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1581 if(err
!= AL_NO_ERROR
)
1583 FreeThunkEntry(source
->id
);
1584 memset(source
, 0, sizeof(ALsource
));
1587 alDeleteSources(cur
, sources
);
1588 SET_ERROR_AND_GOTO(context
, err
, done
);
1591 sources
[cur
] = source
->id
;
1595 ALCcontext_DecRef(context
);
1599 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1602 ALCcontext
*context
;
1606 context
= GetContextRef();
1607 if(!context
) return;
1609 LockSourcesWrite(context
);
1611 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1613 /* Check that all Sources are valid */
1614 for(i
= 0;i
< n
;i
++)
1616 if(LookupSource(context
, sources
[i
]) == NULL
)
1617 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1619 device
= context
->Device
;
1620 for(i
= 0;i
< n
;i
++)
1624 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1626 FreeThunkEntry(Source
->id
);
1628 ALCdevice_Lock(device
);
1629 voice
= GetSourceVoice(Source
, context
);
1630 if(voice
) voice
->Source
= NULL
;
1631 ALCdevice_Unlock(device
);
1633 DeinitSource(Source
, device
->NumAuxSends
);
1635 memset(Source
, 0, sizeof(*Source
));
1640 UnlockSourcesWrite(context
);
1641 ALCcontext_DecRef(context
);
1645 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1647 ALCcontext
*context
;
1650 context
= GetContextRef();
1651 if(!context
) return AL_FALSE
;
1653 LockSourcesRead(context
);
1654 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1655 UnlockSourcesRead(context
);
1657 ALCcontext_DecRef(context
);
1663 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1665 ALCcontext
*Context
;
1668 Context
= GetContextRef();
1669 if(!Context
) return;
1671 WriteLock(&Context
->PropLock
);
1672 LockSourcesRead(Context
);
1673 if((Source
=LookupSource(Context
, source
)) == NULL
)
1674 alSetError(Context
, AL_INVALID_NAME
);
1675 else if(!(FloatValsByProp(param
) == 1))
1676 alSetError(Context
, AL_INVALID_ENUM
);
1678 SetSourcefv(Source
, Context
, param
, &value
);
1679 UnlockSourcesRead(Context
);
1680 WriteUnlock(&Context
->PropLock
);
1682 ALCcontext_DecRef(Context
);
1685 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1687 ALCcontext
*Context
;
1690 Context
= GetContextRef();
1691 if(!Context
) return;
1693 WriteLock(&Context
->PropLock
);
1694 LockSourcesRead(Context
);
1695 if((Source
=LookupSource(Context
, source
)) == NULL
)
1696 alSetError(Context
, AL_INVALID_NAME
);
1697 else if(!(FloatValsByProp(param
) == 3))
1698 alSetError(Context
, AL_INVALID_ENUM
);
1701 ALfloat fvals
[3] = { value1
, value2
, value3
};
1702 SetSourcefv(Source
, Context
, param
, fvals
);
1704 UnlockSourcesRead(Context
);
1705 WriteUnlock(&Context
->PropLock
);
1707 ALCcontext_DecRef(Context
);
1710 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1712 ALCcontext
*Context
;
1715 Context
= GetContextRef();
1716 if(!Context
) return;
1718 WriteLock(&Context
->PropLock
);
1719 LockSourcesRead(Context
);
1720 if((Source
=LookupSource(Context
, source
)) == NULL
)
1721 alSetError(Context
, AL_INVALID_NAME
);
1723 alSetError(Context
, AL_INVALID_VALUE
);
1724 else if(!(FloatValsByProp(param
) > 0))
1725 alSetError(Context
, AL_INVALID_ENUM
);
1727 SetSourcefv(Source
, Context
, param
, values
);
1728 UnlockSourcesRead(Context
);
1729 WriteUnlock(&Context
->PropLock
);
1731 ALCcontext_DecRef(Context
);
1735 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1737 ALCcontext
*Context
;
1740 Context
= GetContextRef();
1741 if(!Context
) return;
1743 WriteLock(&Context
->PropLock
);
1744 LockSourcesRead(Context
);
1745 if((Source
=LookupSource(Context
, source
)) == NULL
)
1746 alSetError(Context
, AL_INVALID_NAME
);
1747 else if(!(DoubleValsByProp(param
) == 1))
1748 alSetError(Context
, AL_INVALID_ENUM
);
1751 ALfloat fval
= (ALfloat
)value
;
1752 SetSourcefv(Source
, Context
, param
, &fval
);
1754 UnlockSourcesRead(Context
);
1755 WriteUnlock(&Context
->PropLock
);
1757 ALCcontext_DecRef(Context
);
1760 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1762 ALCcontext
*Context
;
1765 Context
= GetContextRef();
1766 if(!Context
) return;
1768 WriteLock(&Context
->PropLock
);
1769 LockSourcesRead(Context
);
1770 if((Source
=LookupSource(Context
, source
)) == NULL
)
1771 alSetError(Context
, AL_INVALID_NAME
);
1772 else if(!(DoubleValsByProp(param
) == 3))
1773 alSetError(Context
, AL_INVALID_ENUM
);
1776 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1777 SetSourcefv(Source
, Context
, param
, fvals
);
1779 UnlockSourcesRead(Context
);
1780 WriteUnlock(&Context
->PropLock
);
1782 ALCcontext_DecRef(Context
);
1785 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1787 ALCcontext
*Context
;
1791 Context
= GetContextRef();
1792 if(!Context
) return;
1794 WriteLock(&Context
->PropLock
);
1795 LockSourcesRead(Context
);
1796 if((Source
=LookupSource(Context
, source
)) == NULL
)
1797 alSetError(Context
, AL_INVALID_NAME
);
1799 alSetError(Context
, AL_INVALID_VALUE
);
1800 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1801 alSetError(Context
, AL_INVALID_ENUM
);
1807 for(i
= 0;i
< count
;i
++)
1808 fvals
[i
] = (ALfloat
)values
[i
];
1809 SetSourcefv(Source
, Context
, param
, fvals
);
1811 UnlockSourcesRead(Context
);
1812 WriteUnlock(&Context
->PropLock
);
1814 ALCcontext_DecRef(Context
);
1818 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1820 ALCcontext
*Context
;
1823 Context
= GetContextRef();
1824 if(!Context
) return;
1826 WriteLock(&Context
->PropLock
);
1827 LockSourcesRead(Context
);
1828 if((Source
=LookupSource(Context
, source
)) == NULL
)
1829 alSetError(Context
, AL_INVALID_NAME
);
1830 else if(!(IntValsByProp(param
) == 1))
1831 alSetError(Context
, AL_INVALID_ENUM
);
1833 SetSourceiv(Source
, Context
, param
, &value
);
1834 UnlockSourcesRead(Context
);
1835 WriteUnlock(&Context
->PropLock
);
1837 ALCcontext_DecRef(Context
);
1840 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1842 ALCcontext
*Context
;
1845 Context
= GetContextRef();
1846 if(!Context
) return;
1848 WriteLock(&Context
->PropLock
);
1849 LockSourcesRead(Context
);
1850 if((Source
=LookupSource(Context
, source
)) == NULL
)
1851 alSetError(Context
, AL_INVALID_NAME
);
1852 else if(!(IntValsByProp(param
) == 3))
1853 alSetError(Context
, AL_INVALID_ENUM
);
1856 ALint ivals
[3] = { value1
, value2
, value3
};
1857 SetSourceiv(Source
, Context
, param
, ivals
);
1859 UnlockSourcesRead(Context
);
1860 WriteUnlock(&Context
->PropLock
);
1862 ALCcontext_DecRef(Context
);
1865 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1867 ALCcontext
*Context
;
1870 Context
= GetContextRef();
1871 if(!Context
) return;
1873 WriteLock(&Context
->PropLock
);
1874 LockSourcesRead(Context
);
1875 if((Source
=LookupSource(Context
, source
)) == NULL
)
1876 alSetError(Context
, AL_INVALID_NAME
);
1878 alSetError(Context
, AL_INVALID_VALUE
);
1879 else if(!(IntValsByProp(param
) > 0))
1880 alSetError(Context
, AL_INVALID_ENUM
);
1882 SetSourceiv(Source
, Context
, param
, values
);
1883 UnlockSourcesRead(Context
);
1884 WriteUnlock(&Context
->PropLock
);
1886 ALCcontext_DecRef(Context
);
1890 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1892 ALCcontext
*Context
;
1895 Context
= GetContextRef();
1896 if(!Context
) return;
1898 WriteLock(&Context
->PropLock
);
1899 LockSourcesRead(Context
);
1900 if((Source
=LookupSource(Context
, source
)) == NULL
)
1901 alSetError(Context
, AL_INVALID_NAME
);
1902 else if(!(Int64ValsByProp(param
) == 1))
1903 alSetError(Context
, AL_INVALID_ENUM
);
1905 SetSourcei64v(Source
, Context
, param
, &value
);
1906 UnlockSourcesRead(Context
);
1907 WriteUnlock(&Context
->PropLock
);
1909 ALCcontext_DecRef(Context
);
1912 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1914 ALCcontext
*Context
;
1917 Context
= GetContextRef();
1918 if(!Context
) return;
1920 WriteLock(&Context
->PropLock
);
1921 LockSourcesRead(Context
);
1922 if((Source
=LookupSource(Context
, source
)) == NULL
)
1923 alSetError(Context
, AL_INVALID_NAME
);
1924 else if(!(Int64ValsByProp(param
) == 3))
1925 alSetError(Context
, AL_INVALID_ENUM
);
1928 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1929 SetSourcei64v(Source
, Context
, param
, i64vals
);
1931 UnlockSourcesRead(Context
);
1932 WriteUnlock(&Context
->PropLock
);
1934 ALCcontext_DecRef(Context
);
1937 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1939 ALCcontext
*Context
;
1942 Context
= GetContextRef();
1943 if(!Context
) return;
1945 WriteLock(&Context
->PropLock
);
1946 LockSourcesRead(Context
);
1947 if((Source
=LookupSource(Context
, source
)) == NULL
)
1948 alSetError(Context
, AL_INVALID_NAME
);
1950 alSetError(Context
, AL_INVALID_VALUE
);
1951 else if(!(Int64ValsByProp(param
) > 0))
1952 alSetError(Context
, AL_INVALID_ENUM
);
1954 SetSourcei64v(Source
, Context
, param
, values
);
1955 UnlockSourcesRead(Context
);
1956 WriteUnlock(&Context
->PropLock
);
1958 ALCcontext_DecRef(Context
);
1962 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1964 ALCcontext
*Context
;
1967 Context
= GetContextRef();
1968 if(!Context
) return;
1970 ReadLock(&Context
->PropLock
);
1971 LockSourcesRead(Context
);
1972 if((Source
=LookupSource(Context
, source
)) == NULL
)
1973 alSetError(Context
, AL_INVALID_NAME
);
1975 alSetError(Context
, AL_INVALID_VALUE
);
1976 else if(!(FloatValsByProp(param
) == 1))
1977 alSetError(Context
, AL_INVALID_ENUM
);
1981 if(GetSourcedv(Source
, Context
, param
, &dval
))
1982 *value
= (ALfloat
)dval
;
1984 UnlockSourcesRead(Context
);
1985 ReadUnlock(&Context
->PropLock
);
1987 ALCcontext_DecRef(Context
);
1991 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1993 ALCcontext
*Context
;
1996 Context
= GetContextRef();
1997 if(!Context
) return;
1999 ReadLock(&Context
->PropLock
);
2000 LockSourcesRead(Context
);
2001 if((Source
=LookupSource(Context
, source
)) == NULL
)
2002 alSetError(Context
, AL_INVALID_NAME
);
2003 else if(!(value1
&& value2
&& value3
))
2004 alSetError(Context
, AL_INVALID_VALUE
);
2005 else if(!(FloatValsByProp(param
) == 3))
2006 alSetError(Context
, AL_INVALID_ENUM
);
2010 if(GetSourcedv(Source
, Context
, param
, dvals
))
2012 *value1
= (ALfloat
)dvals
[0];
2013 *value2
= (ALfloat
)dvals
[1];
2014 *value3
= (ALfloat
)dvals
[2];
2017 UnlockSourcesRead(Context
);
2018 ReadUnlock(&Context
->PropLock
);
2020 ALCcontext_DecRef(Context
);
2024 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2026 ALCcontext
*Context
;
2030 Context
= GetContextRef();
2031 if(!Context
) return;
2033 ReadLock(&Context
->PropLock
);
2034 LockSourcesRead(Context
);
2035 if((Source
=LookupSource(Context
, source
)) == NULL
)
2036 alSetError(Context
, AL_INVALID_NAME
);
2038 alSetError(Context
, AL_INVALID_VALUE
);
2039 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
2040 alSetError(Context
, AL_INVALID_ENUM
);
2044 if(GetSourcedv(Source
, Context
, param
, dvals
))
2047 for(i
= 0;i
< count
;i
++)
2048 values
[i
] = (ALfloat
)dvals
[i
];
2051 UnlockSourcesRead(Context
);
2052 ReadUnlock(&Context
->PropLock
);
2054 ALCcontext_DecRef(Context
);
2058 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2060 ALCcontext
*Context
;
2063 Context
= GetContextRef();
2064 if(!Context
) return;
2066 ReadLock(&Context
->PropLock
);
2067 LockSourcesRead(Context
);
2068 if((Source
=LookupSource(Context
, source
)) == NULL
)
2069 alSetError(Context
, AL_INVALID_NAME
);
2071 alSetError(Context
, AL_INVALID_VALUE
);
2072 else if(!(DoubleValsByProp(param
) == 1))
2073 alSetError(Context
, AL_INVALID_ENUM
);
2075 GetSourcedv(Source
, Context
, param
, value
);
2076 UnlockSourcesRead(Context
);
2077 ReadUnlock(&Context
->PropLock
);
2079 ALCcontext_DecRef(Context
);
2082 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2084 ALCcontext
*Context
;
2087 Context
= GetContextRef();
2088 if(!Context
) return;
2090 ReadLock(&Context
->PropLock
);
2091 LockSourcesRead(Context
);
2092 if((Source
=LookupSource(Context
, source
)) == NULL
)
2093 alSetError(Context
, AL_INVALID_NAME
);
2094 else if(!(value1
&& value2
&& value3
))
2095 alSetError(Context
, AL_INVALID_VALUE
);
2096 else if(!(DoubleValsByProp(param
) == 3))
2097 alSetError(Context
, AL_INVALID_ENUM
);
2101 if(GetSourcedv(Source
, Context
, param
, dvals
))
2108 UnlockSourcesRead(Context
);
2109 ReadUnlock(&Context
->PropLock
);
2111 ALCcontext_DecRef(Context
);
2114 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2116 ALCcontext
*Context
;
2119 Context
= GetContextRef();
2120 if(!Context
) return;
2122 ReadLock(&Context
->PropLock
);
2123 LockSourcesRead(Context
);
2124 if((Source
=LookupSource(Context
, source
)) == NULL
)
2125 alSetError(Context
, AL_INVALID_NAME
);
2127 alSetError(Context
, AL_INVALID_VALUE
);
2128 else if(!(DoubleValsByProp(param
) > 0))
2129 alSetError(Context
, AL_INVALID_ENUM
);
2131 GetSourcedv(Source
, Context
, param
, values
);
2132 UnlockSourcesRead(Context
);
2133 ReadUnlock(&Context
->PropLock
);
2135 ALCcontext_DecRef(Context
);
2139 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2141 ALCcontext
*Context
;
2144 Context
= GetContextRef();
2145 if(!Context
) return;
2147 ReadLock(&Context
->PropLock
);
2148 LockSourcesRead(Context
);
2149 if((Source
=LookupSource(Context
, source
)) == NULL
)
2150 alSetError(Context
, AL_INVALID_NAME
);
2152 alSetError(Context
, AL_INVALID_VALUE
);
2153 else if(!(IntValsByProp(param
) == 1))
2154 alSetError(Context
, AL_INVALID_ENUM
);
2156 GetSourceiv(Source
, Context
, param
, value
);
2157 UnlockSourcesRead(Context
);
2158 ReadUnlock(&Context
->PropLock
);
2160 ALCcontext_DecRef(Context
);
2164 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2166 ALCcontext
*Context
;
2169 Context
= GetContextRef();
2170 if(!Context
) return;
2172 ReadLock(&Context
->PropLock
);
2173 LockSourcesRead(Context
);
2174 if((Source
=LookupSource(Context
, source
)) == NULL
)
2175 alSetError(Context
, AL_INVALID_NAME
);
2176 else if(!(value1
&& value2
&& value3
))
2177 alSetError(Context
, AL_INVALID_VALUE
);
2178 else if(!(IntValsByProp(param
) == 3))
2179 alSetError(Context
, AL_INVALID_ENUM
);
2183 if(GetSourceiv(Source
, Context
, param
, ivals
))
2190 UnlockSourcesRead(Context
);
2191 ReadUnlock(&Context
->PropLock
);
2193 ALCcontext_DecRef(Context
);
2197 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2199 ALCcontext
*Context
;
2202 Context
= GetContextRef();
2203 if(!Context
) return;
2205 ReadLock(&Context
->PropLock
);
2206 LockSourcesRead(Context
);
2207 if((Source
=LookupSource(Context
, source
)) == NULL
)
2208 alSetError(Context
, AL_INVALID_NAME
);
2210 alSetError(Context
, AL_INVALID_VALUE
);
2211 else if(!(IntValsByProp(param
) > 0))
2212 alSetError(Context
, AL_INVALID_ENUM
);
2214 GetSourceiv(Source
, Context
, param
, values
);
2215 UnlockSourcesRead(Context
);
2216 ReadUnlock(&Context
->PropLock
);
2218 ALCcontext_DecRef(Context
);
2222 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2224 ALCcontext
*Context
;
2227 Context
= GetContextRef();
2228 if(!Context
) return;
2230 ReadLock(&Context
->PropLock
);
2231 LockSourcesRead(Context
);
2232 if((Source
=LookupSource(Context
, source
)) == NULL
)
2233 alSetError(Context
, AL_INVALID_NAME
);
2235 alSetError(Context
, AL_INVALID_VALUE
);
2236 else if(!(Int64ValsByProp(param
) == 1))
2237 alSetError(Context
, AL_INVALID_ENUM
);
2239 GetSourcei64v(Source
, Context
, param
, value
);
2240 UnlockSourcesRead(Context
);
2241 ReadUnlock(&Context
->PropLock
);
2243 ALCcontext_DecRef(Context
);
2246 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2248 ALCcontext
*Context
;
2251 Context
= GetContextRef();
2252 if(!Context
) return;
2254 ReadLock(&Context
->PropLock
);
2255 LockSourcesRead(Context
);
2256 if((Source
=LookupSource(Context
, source
)) == NULL
)
2257 alSetError(Context
, AL_INVALID_NAME
);
2258 else if(!(value1
&& value2
&& value3
))
2259 alSetError(Context
, AL_INVALID_VALUE
);
2260 else if(!(Int64ValsByProp(param
) == 3))
2261 alSetError(Context
, AL_INVALID_ENUM
);
2265 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2267 *value1
= i64vals
[0];
2268 *value2
= i64vals
[1];
2269 *value3
= i64vals
[2];
2272 UnlockSourcesRead(Context
);
2273 ReadUnlock(&Context
->PropLock
);
2275 ALCcontext_DecRef(Context
);
2278 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2280 ALCcontext
*Context
;
2283 Context
= GetContextRef();
2284 if(!Context
) return;
2286 ReadLock(&Context
->PropLock
);
2287 LockSourcesRead(Context
);
2288 if((Source
=LookupSource(Context
, source
)) == NULL
)
2289 alSetError(Context
, AL_INVALID_NAME
);
2291 alSetError(Context
, AL_INVALID_VALUE
);
2292 else if(!(Int64ValsByProp(param
) > 0))
2293 alSetError(Context
, AL_INVALID_ENUM
);
2295 GetSourcei64v(Source
, Context
, param
, values
);
2296 UnlockSourcesRead(Context
);
2297 ReadUnlock(&Context
->PropLock
);
2299 ALCcontext_DecRef(Context
);
2303 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2305 alSourcePlayv(1, &source
);
2307 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2309 ALCcontext
*context
;
2313 context
= GetContextRef();
2314 if(!context
) return;
2316 LockSourcesRead(context
);
2318 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2319 for(i
= 0;i
< n
;i
++)
2321 if(!LookupSource(context
, sources
[i
]))
2322 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2325 ALCdevice_Lock(context
->Device
);
2326 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2328 ALsizei newcount
= context
->MaxVoices
<< 1;
2329 if(context
->MaxVoices
>= newcount
)
2331 ALCdevice_Unlock(context
->Device
);
2332 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2334 AllocateVoices(context
, newcount
, context
->Device
->NumAuxSends
);
2337 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
) == DeferAll
)
2339 for(i
= 0;i
< n
;i
++)
2341 source
= LookupSource(context
, sources
[i
]);
2342 source
->new_state
= AL_PLAYING
;
2347 for(i
= 0;i
< n
;i
++)
2349 source
= LookupSource(context
, sources
[i
]);
2350 SetSourceState(source
, context
, AL_PLAYING
);
2353 ALCdevice_Unlock(context
->Device
);
2356 UnlockSourcesRead(context
);
2357 ALCcontext_DecRef(context
);
2360 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2362 alSourcePausev(1, &source
);
2364 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2366 ALCcontext
*context
;
2370 context
= GetContextRef();
2371 if(!context
) return;
2373 LockSourcesRead(context
);
2375 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2376 for(i
= 0;i
< n
;i
++)
2378 if(!LookupSource(context
, sources
[i
]))
2379 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2382 ALCdevice_Lock(context
->Device
);
2383 if(ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
2385 for(i
= 0;i
< n
;i
++)
2387 source
= LookupSource(context
, sources
[i
]);
2388 source
->new_state
= AL_PAUSED
;
2393 for(i
= 0;i
< n
;i
++)
2395 source
= LookupSource(context
, sources
[i
]);
2396 SetSourceState(source
, context
, AL_PAUSED
);
2399 ALCdevice_Unlock(context
->Device
);
2402 UnlockSourcesRead(context
);
2403 ALCcontext_DecRef(context
);
2406 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2408 alSourceStopv(1, &source
);
2410 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2412 ALCcontext
*context
;
2416 context
= GetContextRef();
2417 if(!context
) return;
2419 LockSourcesRead(context
);
2421 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2422 for(i
= 0;i
< n
;i
++)
2424 if(!LookupSource(context
, sources
[i
]))
2425 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2428 ALCdevice_Lock(context
->Device
);
2429 for(i
= 0;i
< n
;i
++)
2431 source
= LookupSource(context
, sources
[i
]);
2432 source
->new_state
= AL_NONE
;
2433 SetSourceState(source
, context
, AL_STOPPED
);
2435 ALCdevice_Unlock(context
->Device
);
2438 UnlockSourcesRead(context
);
2439 ALCcontext_DecRef(context
);
2442 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2444 alSourceRewindv(1, &source
);
2446 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2448 ALCcontext
*context
;
2452 context
= GetContextRef();
2453 if(!context
) return;
2455 LockSourcesRead(context
);
2457 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2458 for(i
= 0;i
< n
;i
++)
2460 if(!LookupSource(context
, sources
[i
]))
2461 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2464 ALCdevice_Lock(context
->Device
);
2465 for(i
= 0;i
< n
;i
++)
2467 source
= LookupSource(context
, sources
[i
]);
2468 source
->new_state
= AL_NONE
;
2469 SetSourceState(source
, context
, AL_INITIAL
);
2471 ALCdevice_Unlock(context
->Device
);
2474 UnlockSourcesRead(context
);
2475 ALCcontext_DecRef(context
);
2479 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2482 ALCcontext
*context
;
2485 ALbufferlistitem
*BufferListStart
;
2486 ALbufferlistitem
*BufferList
;
2487 ALbuffer
*BufferFmt
= NULL
;
2492 context
= GetContextRef();
2493 if(!context
) return;
2495 device
= context
->Device
;
2497 LockSourcesRead(context
);
2499 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2500 if((source
=LookupSource(context
, src
)) == NULL
)
2501 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2503 WriteLock(&source
->queue_lock
);
2504 if(source
->SourceType
== AL_STATIC
)
2506 WriteUnlock(&source
->queue_lock
);
2507 /* Can't queue on a Static Source */
2508 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2511 /* Check for a valid Buffer, for its frequency and format */
2512 BufferList
= ATOMIC_LOAD_SEQ(&source
->queue
);
2515 if(BufferList
->buffer
)
2517 BufferFmt
= BufferList
->buffer
;
2520 BufferList
= BufferList
->next
;
2523 LockBuffersRead(device
);
2524 BufferListStart
= NULL
;
2526 for(i
= 0;i
< nb
;i
++)
2528 ALbuffer
*buffer
= NULL
;
2529 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2531 WriteUnlock(&source
->queue_lock
);
2532 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2535 if(!BufferListStart
)
2537 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2538 BufferList
= BufferListStart
;
2542 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2543 BufferList
= BufferList
->next
;
2545 BufferList
->buffer
= buffer
;
2546 BufferList
->next
= NULL
;
2547 if(!buffer
) continue;
2549 /* Hold a read lock on each buffer being queued while checking all
2550 * provided buffers. This is done so other threads don't see an extra
2551 * reference on some buffers if this operation ends up failing. */
2552 ReadLock(&buffer
->lock
);
2553 IncrementRef(&buffer
->ref
);
2555 if(BufferFmt
== NULL
)
2559 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2560 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2562 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2563 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2564 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2566 WriteUnlock(&source
->queue_lock
);
2567 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2570 /* A buffer failed (invalid ID or format), so unlock and release
2571 * each buffer we had. */
2572 while(BufferListStart
)
2574 ALbufferlistitem
*next
= BufferListStart
->next
;
2575 if((buffer
=BufferListStart
->buffer
) != NULL
)
2577 DecrementRef(&buffer
->ref
);
2578 ReadUnlock(&buffer
->lock
);
2580 free(BufferListStart
);
2581 BufferListStart
= next
;
2583 UnlockBuffersRead(device
);
2587 /* All buffers good, unlock them now. */
2588 BufferList
= BufferListStart
;
2589 while(BufferList
!= NULL
)
2591 ALbuffer
*buffer
= BufferList
->buffer
;
2592 if(buffer
) ReadUnlock(&buffer
->lock
);
2593 BufferList
= BufferList
->next
;
2595 UnlockBuffersRead(device
);
2597 /* Source is now streaming */
2598 source
->SourceType
= AL_STREAMING
;
2601 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->queue
,
2602 &BufferList
, BufferListStart
))
2604 /* Queue head is not NULL, append to the end of the queue */
2605 while(BufferList
->next
!= NULL
)
2606 BufferList
= BufferList
->next
;
2607 BufferList
->next
= BufferListStart
;
2609 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2613 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem
*, &source
->current_buffer
,
2614 &BufferList
, BufferListStart
);
2615 WriteUnlock(&source
->queue_lock
);
2618 UnlockSourcesRead(context
);
2619 ALCcontext_DecRef(context
);
2622 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2624 ALCcontext
*context
;
2626 ALbufferlistitem
*OldHead
;
2627 ALbufferlistitem
*OldTail
;
2628 ALbufferlistitem
*Current
;
2634 context
= GetContextRef();
2635 if(!context
) return;
2637 LockSourcesRead(context
);
2639 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2641 if((source
=LookupSource(context
, src
)) == NULL
)
2642 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2644 WriteLock(&source
->queue_lock
);
2645 if(ATOMIC_LOAD_SEQ(&source
->looping
) || source
->SourceType
!= AL_STREAMING
)
2647 WriteUnlock(&source
->queue_lock
);
2648 /* Trying to unqueue buffers on a looping or non-streaming source. */
2649 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2652 /* Find the new buffer queue head */
2653 OldTail
= ATOMIC_LOAD_SEQ(&source
->queue
);
2654 Current
= ATOMIC_LOAD_SEQ(&source
->current_buffer
);
2655 if(OldTail
!= Current
)
2657 for(i
= 1;i
< nb
;i
++)
2659 ALbufferlistitem
*next
= OldTail
->next
;
2660 if(!next
|| next
== Current
) break;
2666 WriteUnlock(&source
->queue_lock
);
2667 /* Trying to unqueue pending buffers. */
2668 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2671 /* Swap it, and cut the new head from the old. */
2672 OldHead
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, OldTail
->next
);
2675 ALCdevice
*device
= context
->Device
;
2678 /* Once the active mix (if any) is done, it's safe to cut the old tail
2679 * from the new head.
2681 if(((count
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
2683 while(count
== ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))
2686 ATOMIC_THREAD_FENCE(almemory_order_acq_rel
);
2687 OldTail
->next
= NULL
;
2689 WriteUnlock(&source
->queue_lock
);
2691 while(OldHead
!= NULL
)
2693 ALbufferlistitem
*next
= OldHead
->next
;
2694 ALbuffer
*buffer
= OldHead
->buffer
;
2700 *(buffers
++) = buffer
->id
;
2701 DecrementRef(&buffer
->ref
);
2709 UnlockSourcesRead(context
);
2710 ALCcontext_DecRef(context
);
2714 static void InitSourceParams(ALsource
*Source
, ALsizei num_sends
)
2718 RWLockInit(&Source
->queue_lock
);
2720 Source
->InnerAngle
= 360.0f
;
2721 Source
->OuterAngle
= 360.0f
;
2722 Source
->Pitch
= 1.0f
;
2723 Source
->Position
[0] = 0.0f
;
2724 Source
->Position
[1] = 0.0f
;
2725 Source
->Position
[2] = 0.0f
;
2726 Source
->Velocity
[0] = 0.0f
;
2727 Source
->Velocity
[1] = 0.0f
;
2728 Source
->Velocity
[2] = 0.0f
;
2729 Source
->Direction
[0] = 0.0f
;
2730 Source
->Direction
[1] = 0.0f
;
2731 Source
->Direction
[2] = 0.0f
;
2732 Source
->Orientation
[0][0] = 0.0f
;
2733 Source
->Orientation
[0][1] = 0.0f
;
2734 Source
->Orientation
[0][2] = -1.0f
;
2735 Source
->Orientation
[1][0] = 0.0f
;
2736 Source
->Orientation
[1][1] = 1.0f
;
2737 Source
->Orientation
[1][2] = 0.0f
;
2738 Source
->RefDistance
= 1.0f
;
2739 Source
->MaxDistance
= FLT_MAX
;
2740 Source
->RollOffFactor
= 1.0f
;
2741 Source
->Gain
= 1.0f
;
2742 Source
->MinGain
= 0.0f
;
2743 Source
->MaxGain
= 1.0f
;
2744 Source
->OuterGain
= 0.0f
;
2745 Source
->OuterGainHF
= 1.0f
;
2747 Source
->DryGainHFAuto
= AL_TRUE
;
2748 Source
->WetGainAuto
= AL_TRUE
;
2749 Source
->WetGainHFAuto
= AL_TRUE
;
2750 Source
->AirAbsorptionFactor
= 0.0f
;
2751 Source
->RoomRolloffFactor
= 0.0f
;
2752 Source
->DopplerFactor
= 1.0f
;
2753 Source
->DirectChannels
= AL_FALSE
;
2755 Source
->StereoPan
[0] = DEG2RAD( 30.0f
);
2756 Source
->StereoPan
[1] = DEG2RAD(-30.0f
);
2758 Source
->Radius
= 0.0f
;
2760 Source
->DistanceModel
= DefaultDistanceModel
;
2762 Source
->Direct
.Gain
= 1.0f
;
2763 Source
->Direct
.GainHF
= 1.0f
;
2764 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2765 Source
->Direct
.GainLF
= 1.0f
;
2766 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2767 Source
->Send
= al_calloc(16, num_sends
*sizeof(Source
->Send
[0]));
2768 for(i
= 0;i
< num_sends
;i
++)
2770 Source
->Send
[i
].Slot
= NULL
;
2771 Source
->Send
[i
].Gain
= 1.0f
;
2772 Source
->Send
[i
].GainHF
= 1.0f
;
2773 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2774 Source
->Send
[i
].GainLF
= 1.0f
;
2775 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2778 Source
->Offset
= 0.0;
2779 Source
->OffsetType
= AL_NONE
;
2780 Source
->SourceType
= AL_UNDETERMINED
;
2781 ATOMIC_INIT(&Source
->state
, AL_INITIAL
);
2782 Source
->new_state
= AL_NONE
;
2784 ATOMIC_INIT(&Source
->queue
, NULL
);
2785 ATOMIC_INIT(&Source
->current_buffer
, NULL
);
2787 ATOMIC_INIT(&Source
->position
, 0);
2788 ATOMIC_INIT(&Source
->position_fraction
, 0);
2790 ATOMIC_INIT(&Source
->looping
, AL_FALSE
);
2792 Source
->NeedsUpdate
= AL_TRUE
;
2794 ATOMIC_INIT(&Source
->Update
, NULL
);
2795 ATOMIC_INIT(&Source
->FreeList
, NULL
);
2798 static void DeinitSource(ALsource
*source
, ALsizei num_sends
)
2800 ALbufferlistitem
*BufferList
;
2801 struct ALsourceProps
*props
;
2805 props
= ATOMIC_LOAD_SEQ(&source
->Update
);
2806 if(props
) al_free(props
);
2808 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_relaxed
);
2811 struct ALsourceProps
*next
;
2812 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2817 /* This is excessively spammy if it traces every source destruction, so
2818 * just warn if it was unexpectedly large.
2821 WARN("Freed "SZFMT
" Source property objects\n", count
);
2823 BufferList
= ATOMIC_EXCHANGE_SEQ(ALbufferlistitem
*, &source
->queue
, NULL
);
2824 while(BufferList
!= NULL
)
2826 ALbufferlistitem
*next
= BufferList
->next
;
2827 if(BufferList
->buffer
!= NULL
)
2828 DecrementRef(&BufferList
->buffer
->ref
);
2835 for(i
= 0;i
< num_sends
;i
++)
2837 if(source
->Send
[i
].Slot
)
2838 DecrementRef(&source
->Send
[i
].Slot
->ref
);
2839 source
->Send
[i
].Slot
= NULL
;
2841 al_free(source
->Send
);
2842 source
->Send
= NULL
;
2846 static void UpdateSourceProps(ALsource
*source
, ALsizei num_sends
)
2848 struct ALsourceProps
*props
;
2851 /* Get an unused property container, or allocate a new one as needed. */
2852 props
= ATOMIC_LOAD(&source
->FreeList
, almemory_order_acquire
);
2854 props
= al_calloc(16, offsetof(struct ALsourceProps
, Send
[num_sends
]));
2857 struct ALsourceProps
*next
;
2859 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
2860 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps
*,
2861 &source
->FreeList
, &props
, next
, almemory_order_acq_rel
,
2862 almemory_order_acquire
) == 0);
2865 /* Copy in current property values. */
2866 ATOMIC_STORE(&props
->Pitch
, source
->Pitch
, almemory_order_relaxed
);
2867 ATOMIC_STORE(&props
->Gain
, source
->Gain
, almemory_order_relaxed
);
2868 ATOMIC_STORE(&props
->OuterGain
, source
->OuterGain
, almemory_order_relaxed
);
2869 ATOMIC_STORE(&props
->MinGain
, source
->MinGain
, almemory_order_relaxed
);
2870 ATOMIC_STORE(&props
->MaxGain
, source
->MaxGain
, almemory_order_relaxed
);
2871 ATOMIC_STORE(&props
->InnerAngle
, source
->InnerAngle
, almemory_order_relaxed
);
2872 ATOMIC_STORE(&props
->OuterAngle
, source
->OuterAngle
, almemory_order_relaxed
);
2873 ATOMIC_STORE(&props
->RefDistance
, source
->RefDistance
, almemory_order_relaxed
);
2874 ATOMIC_STORE(&props
->MaxDistance
, source
->MaxDistance
, almemory_order_relaxed
);
2875 ATOMIC_STORE(&props
->RollOffFactor
, source
->RollOffFactor
, almemory_order_relaxed
);
2876 for(i
= 0;i
< 3;i
++)
2877 ATOMIC_STORE(&props
->Position
[i
], source
->Position
[i
], almemory_order_relaxed
);
2878 for(i
= 0;i
< 3;i
++)
2879 ATOMIC_STORE(&props
->Velocity
[i
], source
->Velocity
[i
], almemory_order_relaxed
);
2880 for(i
= 0;i
< 3;i
++)
2881 ATOMIC_STORE(&props
->Direction
[i
], source
->Direction
[i
], almemory_order_relaxed
);
2882 for(i
= 0;i
< 2;i
++)
2885 for(j
= 0;j
< 3;j
++)
2886 ATOMIC_STORE(&props
->Orientation
[i
][j
], source
->Orientation
[i
][j
],
2887 almemory_order_relaxed
);
2889 ATOMIC_STORE(&props
->HeadRelative
, source
->HeadRelative
, almemory_order_relaxed
);
2890 ATOMIC_STORE(&props
->DistanceModel
, source
->DistanceModel
, almemory_order_relaxed
);
2891 ATOMIC_STORE(&props
->DirectChannels
, source
->DirectChannels
, almemory_order_relaxed
);
2893 ATOMIC_STORE(&props
->DryGainHFAuto
, source
->DryGainHFAuto
, almemory_order_relaxed
);
2894 ATOMIC_STORE(&props
->WetGainAuto
, source
->WetGainAuto
, almemory_order_relaxed
);
2895 ATOMIC_STORE(&props
->WetGainHFAuto
, source
->WetGainHFAuto
, almemory_order_relaxed
);
2896 ATOMIC_STORE(&props
->OuterGainHF
, source
->OuterGainHF
, almemory_order_relaxed
);
2898 ATOMIC_STORE(&props
->AirAbsorptionFactor
, source
->AirAbsorptionFactor
, almemory_order_relaxed
);
2899 ATOMIC_STORE(&props
->RoomRolloffFactor
, source
->RoomRolloffFactor
, almemory_order_relaxed
);
2900 ATOMIC_STORE(&props
->DopplerFactor
, source
->DopplerFactor
, almemory_order_relaxed
);
2902 ATOMIC_STORE(&props
->StereoPan
[0], source
->StereoPan
[0], almemory_order_relaxed
);
2903 ATOMIC_STORE(&props
->StereoPan
[1], source
->StereoPan
[1], almemory_order_relaxed
);
2905 ATOMIC_STORE(&props
->Radius
, source
->Radius
, almemory_order_relaxed
);
2907 ATOMIC_STORE(&props
->Direct
.Gain
, source
->Direct
.Gain
, almemory_order_relaxed
);
2908 ATOMIC_STORE(&props
->Direct
.GainHF
, source
->Direct
.GainHF
, almemory_order_relaxed
);
2909 ATOMIC_STORE(&props
->Direct
.HFReference
, source
->Direct
.HFReference
, almemory_order_relaxed
);
2910 ATOMIC_STORE(&props
->Direct
.GainLF
, source
->Direct
.GainLF
, almemory_order_relaxed
);
2911 ATOMIC_STORE(&props
->Direct
.LFReference
, source
->Direct
.LFReference
, almemory_order_relaxed
);
2913 for(i
= 0;i
< num_sends
;i
++)
2915 ATOMIC_STORE(&props
->Send
[i
].Slot
, source
->Send
[i
].Slot
, almemory_order_relaxed
);
2916 ATOMIC_STORE(&props
->Send
[i
].Gain
, source
->Send
[i
].Gain
, almemory_order_relaxed
);
2917 ATOMIC_STORE(&props
->Send
[i
].GainHF
, source
->Send
[i
].GainHF
, almemory_order_relaxed
);
2918 ATOMIC_STORE(&props
->Send
[i
].HFReference
, source
->Send
[i
].HFReference
,
2919 almemory_order_relaxed
);
2920 ATOMIC_STORE(&props
->Send
[i
].GainLF
, source
->Send
[i
].GainLF
, almemory_order_relaxed
);
2921 ATOMIC_STORE(&props
->Send
[i
].LFReference
, source
->Send
[i
].LFReference
,
2922 almemory_order_relaxed
);
2925 /* Set the new container for updating internal parameters. */
2926 props
= ATOMIC_EXCHANGE(struct ALsourceProps
*, &source
->Update
, props
, almemory_order_acq_rel
);
2929 /* If there was an unused update container, put it back in the
2932 ATOMIC_REPLACE_HEAD(struct ALsourceProps
*, &source
->FreeList
, props
);
2936 void UpdateAllSourceProps(ALCcontext
*context
)
2938 ALsizei num_sends
= context
->Device
->NumAuxSends
;
2941 for(pos
= 0;pos
< context
->VoiceCount
;pos
++)
2943 ALvoice
*voice
= context
->Voices
[pos
];
2944 ALsource
*source
= voice
->Source
;
2945 if(source
!= NULL
&& source
->NeedsUpdate
&& IsPlayingOrPausedSeq(source
))
2947 source
->NeedsUpdate
= AL_FALSE
;
2948 UpdateSourceProps(source
, num_sends
);
2956 * Sets the source's new play state given its current state.
2958 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2960 WriteLock(&Source
->queue_lock
);
2961 if(state
== AL_PLAYING
)
2963 ALCdevice
*device
= Context
->Device
;
2964 ALbufferlistitem
*BufferList
;
2965 ALboolean discontinuity
;
2966 ALvoice
*voice
= NULL
;
2969 /* Check that there is a queue containing at least one valid, non zero
2971 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
2975 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2977 BufferList
= BufferList
->next
;
2980 if(ATOMIC_EXCHANGE(ALenum
, &Source
->state
, AL_PLAYING
, almemory_order_acq_rel
) == AL_PAUSED
)
2981 discontinuity
= AL_FALSE
;
2984 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
2985 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
2986 ATOMIC_STORE(&Source
->position_fraction
, 0, almemory_order_release
);
2987 discontinuity
= AL_TRUE
;
2990 // Check if an Offset has been set
2991 if(Source
->OffsetType
!= AL_NONE
)
2993 ApplyOffset(Source
);
2994 /* discontinuity = AL_TRUE;??? */
2997 /* If there's nothing to play, or device is disconnected, go right to
2999 if(!BufferList
|| !device
->Connected
)
3002 /* Make sure this source isn't already active, and if not, look for an
3003 * unused voice to put it in.
3005 voice
= GetSourceVoice(Source
, Context
);
3008 for(i
= 0;i
< Context
->VoiceCount
;i
++)
3010 if(Context
->Voices
[i
]->Source
== NULL
)
3012 voice
= Context
->Voices
[i
];
3013 voice
->Source
= Source
;
3019 voice
= Context
->Voices
[Context
->VoiceCount
++];
3020 voice
->Source
= Source
;
3022 discontinuity
= AL_TRUE
;
3027 /* Clear previous samples if playback is discontinuous. */
3028 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
3030 /* Clear the stepping value so the mixer knows not to mix this
3031 * until the update gets applied.
3036 voice
->Moving
= AL_FALSE
;
3037 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
3040 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
3041 voice
->Direct
.Params
[i
].Hrtf
.State
.History
[j
] = 0.0f
;
3042 for(j
= 0;j
< HRIR_LENGTH
;j
++)
3044 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][0] = 0.0f
;
3045 voice
->Direct
.Params
[i
].Hrtf
.State
.Values
[j
][1] = 0.0f
;
3049 Source
->NeedsUpdate
= AL_FALSE
;
3050 UpdateSourceProps(Source
, device
->NumAuxSends
);
3052 else if(state
== AL_PAUSED
)
3054 ALenum playing
= AL_PLAYING
;
3055 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum
, &Source
->state
, &playing
, AL_PAUSED
);
3057 else if(state
== AL_STOPPED
)
3060 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3062 ATOMIC_STORE(&Source
->state
, AL_STOPPED
, almemory_order_relaxed
);
3063 ATOMIC_STORE_SEQ(&Source
->current_buffer
, NULL
);
3065 Source
->OffsetType
= AL_NONE
;
3066 Source
->Offset
= 0.0;
3068 else if(state
== AL_INITIAL
)
3070 if(ATOMIC_LOAD(&Source
->state
, almemory_order_acquire
) != AL_INITIAL
)
3072 ATOMIC_STORE(&Source
->state
, AL_INITIAL
, almemory_order_relaxed
);
3073 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD_SEQ(&Source
->queue
),
3074 almemory_order_relaxed
);
3075 ATOMIC_STORE(&Source
->position
, 0, almemory_order_relaxed
);
3076 ATOMIC_STORE_SEQ(&Source
->position_fraction
, 0);
3078 Source
->OffsetType
= AL_NONE
;
3079 Source
->Offset
= 0.0;
3081 WriteUnlock(&Source
->queue_lock
);
3084 /* GetSourceSampleOffset
3086 * Gets the current read offset for the given Source, in 32.32 fixed-point
3087 * samples. The offset is relative to the start of the queue (not the start of
3088 * the current buffer).
3090 static ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3092 const ALbufferlistitem
*BufferList
;
3093 const ALbufferlistitem
*Current
;
3097 ReadLock(&Source
->queue_lock
);
3099 BufferList
= Current
= NULL
;
3101 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3103 *clocktime
= GetDeviceClockTime(device
);
3105 if(IsPlayingOrPaused(Source
))
3107 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3108 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3110 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) << 32;
3111 readPos
|= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
) <<
3114 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3115 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3117 while(BufferList
&& BufferList
!= Current
)
3119 if(BufferList
->buffer
)
3120 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
3121 BufferList
= BufferList
->next
;
3124 ReadUnlock(&Source
->queue_lock
);
3125 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
3128 /* GetSourceSecOffset
3130 * Gets the current read offset for the given Source, in seconds. The offset is
3131 * relative to the start of the queue (not the start of the current buffer).
3133 static ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCdevice
*device
, ALuint64
*clocktime
)
3135 const ALbufferlistitem
*BufferList
;
3136 const ALbufferlistitem
*Current
;
3141 ReadLock(&Source
->queue_lock
);
3143 BufferList
= Current
= NULL
;
3145 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3147 *clocktime
= GetDeviceClockTime(device
);
3149 if(IsPlayingOrPaused(Source
))
3151 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3152 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3154 readPos
= (ALuint64
)ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
) <<
3156 readPos
|= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3158 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3159 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3165 const ALbuffer
*Buffer
= NULL
;
3166 while(BufferList
&& BufferList
!= Current
)
3168 const ALbuffer
*buffer
= BufferList
->buffer
;
3171 if(!Buffer
) Buffer
= buffer
;
3172 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
3174 BufferList
= BufferList
->next
;
3177 while(BufferList
&& !Buffer
)
3179 Buffer
= BufferList
->buffer
;
3180 BufferList
= BufferList
->next
;
3182 assert(Buffer
!= NULL
);
3184 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
3185 (ALdouble
)Buffer
->Frequency
;
3188 ReadUnlock(&Source
->queue_lock
);
3194 * Gets the current read offset for the given Source, in the appropriate format
3195 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3196 * queue (not the start of the current buffer).
3198 static ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCdevice
*device
)
3200 const ALbufferlistitem
*BufferList
;
3201 const ALbufferlistitem
*Current
;
3202 const ALbuffer
*Buffer
= NULL
;
3203 ALboolean readFin
= AL_FALSE
;
3204 ALuint readPos
, readPosFrac
;
3205 ALuint totalBufferLen
;
3211 ReadLock(&Source
->queue_lock
);
3213 while(((refcount
=ATOMIC_LOAD(&device
->MixCount
, almemory_order_acquire
))&1))
3215 state
= ATOMIC_LOAD(&Source
->state
, almemory_order_relaxed
);
3217 BufferList
= ATOMIC_LOAD(&Source
->queue
, almemory_order_relaxed
);
3218 Current
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_relaxed
);
3220 readPos
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
3221 readPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
3223 looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
3224 ATOMIC_THREAD_FENCE(almemory_order_acquire
);
3225 } while(refcount
!= ATOMIC_LOAD(&device
->MixCount
, almemory_order_relaxed
));
3227 if(state
!= AL_PLAYING
&& state
!= AL_PAUSED
)
3229 ReadUnlock(&Source
->queue_lock
);
3234 while(BufferList
!= NULL
)
3236 const ALbuffer
*buffer
;
3237 readFin
= readFin
|| (BufferList
== Current
);
3238 if((buffer
=BufferList
->buffer
) != NULL
)
3240 if(!Buffer
) Buffer
= buffer
;
3241 totalBufferLen
+= buffer
->SampleLen
;
3242 if(!readFin
) readPos
+= buffer
->SampleLen
;
3244 BufferList
= BufferList
->next
;
3246 assert(Buffer
!= NULL
);
3249 readPos
%= totalBufferLen
;
3252 /* Wrap back to 0 */
3253 if(readPos
>= totalBufferLen
)
3254 readPos
= readPosFrac
= 0;
3261 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
3264 case AL_SAMPLE_OFFSET
:
3265 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
3268 case AL_BYTE_OFFSET
:
3269 if(Buffer
->OriginalType
== UserFmtIMA4
)
3271 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3272 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3273 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3275 /* Round down to nearest ADPCM block */
3276 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3278 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3280 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3281 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
3282 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
3284 /* Round down to nearest ADPCM block */
3285 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
3289 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3290 offset
= (ALdouble
)(readPos
* FrameSize
);
3295 ReadUnlock(&Source
->queue_lock
);
3302 * Apply the stored playback offset to the Source. This function will update
3303 * the number of buffers "played" given the stored offset.
3305 ALboolean
ApplyOffset(ALsource
*Source
)
3307 ALbufferlistitem
*BufferList
;
3308 const ALbuffer
*Buffer
;
3309 ALuint bufferLen
, totalBufferLen
;
3310 ALuint offset
=0, frac
=0;
3312 /* Get sample frame offset */
3313 if(!GetSampleOffset(Source
, &offset
, &frac
))
3317 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3318 while(BufferList
&& totalBufferLen
<= offset
)
3320 Buffer
= BufferList
->buffer
;
3321 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
3323 if(bufferLen
> offset
-totalBufferLen
)
3325 /* Offset is in this buffer */
3326 ATOMIC_STORE(&Source
->current_buffer
, BufferList
, almemory_order_relaxed
);
3328 ATOMIC_STORE(&Source
->position
, offset
- totalBufferLen
, almemory_order_relaxed
);
3329 ATOMIC_STORE(&Source
->position_fraction
, frac
, almemory_order_release
);
3333 totalBufferLen
+= bufferLen
;
3335 BufferList
= BufferList
->next
;
3338 /* Offset is out of range of the queue */
3345 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3346 * or Second offset supplied by the application). This takes into account the
3347 * fact that the buffer format may have been modifed since.
3349 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
3351 const ALbuffer
*Buffer
= NULL
;
3352 const ALbufferlistitem
*BufferList
;
3353 ALdouble dbloff
, dblfrac
;
3355 /* Find the first valid Buffer in the Queue */
3356 BufferList
= ATOMIC_LOAD_SEQ(&Source
->queue
);
3359 if(BufferList
->buffer
)
3361 Buffer
= BufferList
->buffer
;
3364 BufferList
= BufferList
->next
;
3368 Source
->OffsetType
= AL_NONE
;
3369 Source
->Offset
= 0.0;
3373 switch(Source
->OffsetType
)
3375 case AL_BYTE_OFFSET
:
3376 /* Determine the ByteOffset (and ensure it is block aligned) */
3377 *offset
= (ALuint
)Source
->Offset
;
3378 if(Buffer
->OriginalType
== UserFmtIMA4
)
3380 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
3381 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3382 *offset
*= Buffer
->OriginalAlign
;
3384 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
3386 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
3387 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3388 *offset
*= Buffer
->OriginalAlign
;
3391 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3395 case AL_SAMPLE_OFFSET
:
3396 dblfrac
= modf(Source
->Offset
, &dbloff
);
3397 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3398 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3402 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3403 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3404 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3407 Source
->OffsetType
= AL_NONE
;
3408 Source
->Offset
= 0.0;
3416 * Destroys all sources in the source map.
3418 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3420 ALCdevice
*device
= Context
->Device
;
3422 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3424 ALsource
*temp
= Context
->SourceMap
.values
[pos
];
3425 Context
->SourceMap
.values
[pos
] = NULL
;
3427 DeinitSource(temp
, device
->NumAuxSends
);
3429 FreeThunkEntry(temp
->id
);
3430 memset(temp
, 0, sizeof(*temp
));