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"
42 extern inline struct ALsource
*LookupSource(ALCcontext
*context
, ALuint id
);
43 extern inline struct ALsource
*RemoveSource(ALCcontext
*context
, ALuint id
);
45 static ALvoid
InitSourceParams(ALsource
*Source
);
46 static ALint64
GetSourceSampleOffset(ALsource
*Source
);
47 static ALdouble
GetSourceSecOffset(ALsource
*Source
);
48 static ALvoid
GetSourceOffsets(ALsource
*Source
, ALenum name
, ALdouble
*offsets
, ALdouble updateLen
);
49 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
);
51 typedef enum SourceProp
{
54 srcMinGain
= AL_MIN_GAIN
,
55 srcMaxGain
= AL_MAX_GAIN
,
56 srcMaxDistance
= AL_MAX_DISTANCE
,
57 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
58 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
59 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
60 srcSecOffset
= AL_SEC_OFFSET
,
61 srcSampleOffset
= AL_SAMPLE_OFFSET
,
62 srcByteOffset
= AL_BYTE_OFFSET
,
63 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
64 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
65 srcRefDistance
= AL_REFERENCE_DISTANCE
,
67 srcPosition
= AL_POSITION
,
68 srcVelocity
= AL_VELOCITY
,
69 srcDirection
= AL_DIRECTION
,
71 srcSourceRelative
= AL_SOURCE_RELATIVE
,
72 srcLooping
= AL_LOOPING
,
73 srcBuffer
= AL_BUFFER
,
74 srcSourceState
= AL_SOURCE_STATE
,
75 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
76 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
77 srcSourceType
= AL_SOURCE_TYPE
,
80 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
81 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
82 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
83 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
84 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
85 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
86 srcDirectFilter
= AL_DIRECT_FILTER
,
87 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
89 /* AL_SOFT_direct_channels */
90 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
92 /* AL_EXT_source_distance_model */
93 srcDistanceModel
= AL_DISTANCE_MODEL
,
95 srcByteLengthSOFT
= AL_BYTE_LENGTH_SOFT
,
96 srcSampleLengthSOFT
= AL_SAMPLE_LENGTH_SOFT
,
97 srcSecLengthSOFT
= AL_SEC_LENGTH_SOFT
,
99 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100 srcSampleRWOffsetsSOFT
= AL_SAMPLE_RW_OFFSETS_SOFT
,
101 srcByteRWOffsetsSOFT
= AL_BYTE_RW_OFFSETS_SOFT
,
103 /* AL_SOFT_source_latency */
104 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
105 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
108 srcOrientation
= AL_ORIENTATION
,
111 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
112 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
113 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
115 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
116 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
117 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
119 static ALint
FloatValsByProp(ALenum prop
)
121 if(prop
!= (ALenum
)((SourceProp
)prop
))
123 switch((SourceProp
)prop
)
129 case AL_MAX_DISTANCE
:
130 case AL_ROLLOFF_FACTOR
:
131 case AL_DOPPLER_FACTOR
:
132 case AL_CONE_OUTER_GAIN
:
134 case AL_SAMPLE_OFFSET
:
136 case AL_CONE_INNER_ANGLE
:
137 case AL_CONE_OUTER_ANGLE
:
138 case AL_REFERENCE_DISTANCE
:
139 case AL_CONE_OUTER_GAINHF
:
140 case AL_AIR_ABSORPTION_FACTOR
:
141 case AL_ROOM_ROLLOFF_FACTOR
:
142 case AL_DIRECT_FILTER_GAINHF_AUTO
:
143 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
144 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
145 case AL_DIRECT_CHANNELS_SOFT
:
146 case AL_DISTANCE_MODEL
:
147 case AL_SOURCE_RELATIVE
:
149 case AL_SOURCE_STATE
:
150 case AL_BUFFERS_QUEUED
:
151 case AL_BUFFERS_PROCESSED
:
153 case AL_BYTE_LENGTH_SOFT
:
154 case AL_SAMPLE_LENGTH_SOFT
:
155 case AL_SEC_LENGTH_SOFT
:
158 case AL_SAMPLE_RW_OFFSETS_SOFT
:
159 case AL_BYTE_RW_OFFSETS_SOFT
:
170 case AL_SEC_OFFSET_LATENCY_SOFT
:
171 break; /* Double only */
174 case AL_DIRECT_FILTER
:
175 case AL_AUXILIARY_SEND_FILTER
:
176 break; /* i/i64 only */
177 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
178 break; /* i64 only */
182 static ALint
DoubleValsByProp(ALenum prop
)
184 if(prop
!= (ALenum
)((SourceProp
)prop
))
186 switch((SourceProp
)prop
)
192 case AL_MAX_DISTANCE
:
193 case AL_ROLLOFF_FACTOR
:
194 case AL_DOPPLER_FACTOR
:
195 case AL_CONE_OUTER_GAIN
:
197 case AL_SAMPLE_OFFSET
:
199 case AL_CONE_INNER_ANGLE
:
200 case AL_CONE_OUTER_ANGLE
:
201 case AL_REFERENCE_DISTANCE
:
202 case AL_CONE_OUTER_GAINHF
:
203 case AL_AIR_ABSORPTION_FACTOR
:
204 case AL_ROOM_ROLLOFF_FACTOR
:
205 case AL_DIRECT_FILTER_GAINHF_AUTO
:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
208 case AL_DIRECT_CHANNELS_SOFT
:
209 case AL_DISTANCE_MODEL
:
210 case AL_SOURCE_RELATIVE
:
212 case AL_SOURCE_STATE
:
213 case AL_BUFFERS_QUEUED
:
214 case AL_BUFFERS_PROCESSED
:
216 case AL_BYTE_LENGTH_SOFT
:
217 case AL_SAMPLE_LENGTH_SOFT
:
218 case AL_SEC_LENGTH_SOFT
:
221 case AL_SAMPLE_RW_OFFSETS_SOFT
:
222 case AL_BYTE_RW_OFFSETS_SOFT
:
223 case AL_SEC_OFFSET_LATENCY_SOFT
:
235 case AL_DIRECT_FILTER
:
236 case AL_AUXILIARY_SEND_FILTER
:
237 break; /* i/i64 only */
238 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
239 break; /* i64 only */
244 static ALint
IntValsByProp(ALenum prop
)
246 if(prop
!= (ALenum
)((SourceProp
)prop
))
248 switch((SourceProp
)prop
)
254 case AL_MAX_DISTANCE
:
255 case AL_ROLLOFF_FACTOR
:
256 case AL_DOPPLER_FACTOR
:
257 case AL_CONE_OUTER_GAIN
:
259 case AL_SAMPLE_OFFSET
:
261 case AL_CONE_INNER_ANGLE
:
262 case AL_CONE_OUTER_ANGLE
:
263 case AL_REFERENCE_DISTANCE
:
264 case AL_CONE_OUTER_GAINHF
:
265 case AL_AIR_ABSORPTION_FACTOR
:
266 case AL_ROOM_ROLLOFF_FACTOR
:
267 case AL_DIRECT_FILTER_GAINHF_AUTO
:
268 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
269 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
270 case AL_DIRECT_CHANNELS_SOFT
:
271 case AL_DISTANCE_MODEL
:
272 case AL_SOURCE_RELATIVE
:
275 case AL_SOURCE_STATE
:
276 case AL_BUFFERS_QUEUED
:
277 case AL_BUFFERS_PROCESSED
:
279 case AL_DIRECT_FILTER
:
280 case AL_BYTE_LENGTH_SOFT
:
281 case AL_SAMPLE_LENGTH_SOFT
:
282 case AL_SEC_LENGTH_SOFT
:
285 case AL_SAMPLE_RW_OFFSETS_SOFT
:
286 case AL_BYTE_RW_OFFSETS_SOFT
:
292 case AL_AUXILIARY_SEND_FILTER
:
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
299 break; /* i64 only */
300 case AL_SEC_OFFSET_LATENCY_SOFT
:
301 break; /* Double only */
305 static ALint
Int64ValsByProp(ALenum prop
)
307 if(prop
!= (ALenum
)((SourceProp
)prop
))
309 switch((SourceProp
)prop
)
315 case AL_MAX_DISTANCE
:
316 case AL_ROLLOFF_FACTOR
:
317 case AL_DOPPLER_FACTOR
:
318 case AL_CONE_OUTER_GAIN
:
320 case AL_SAMPLE_OFFSET
:
322 case AL_CONE_INNER_ANGLE
:
323 case AL_CONE_OUTER_ANGLE
:
324 case AL_REFERENCE_DISTANCE
:
325 case AL_CONE_OUTER_GAINHF
:
326 case AL_AIR_ABSORPTION_FACTOR
:
327 case AL_ROOM_ROLLOFF_FACTOR
:
328 case AL_DIRECT_FILTER_GAINHF_AUTO
:
329 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
330 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
331 case AL_DIRECT_CHANNELS_SOFT
:
332 case AL_DISTANCE_MODEL
:
333 case AL_SOURCE_RELATIVE
:
336 case AL_SOURCE_STATE
:
337 case AL_BUFFERS_QUEUED
:
338 case AL_BUFFERS_PROCESSED
:
340 case AL_DIRECT_FILTER
:
341 case AL_BYTE_LENGTH_SOFT
:
342 case AL_SAMPLE_LENGTH_SOFT
:
343 case AL_SEC_LENGTH_SOFT
:
346 case AL_SAMPLE_RW_OFFSETS_SOFT
:
347 case AL_BYTE_RW_OFFSETS_SOFT
:
348 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
354 case AL_AUXILIARY_SEND_FILTER
:
360 case AL_SEC_OFFSET_LATENCY_SOFT
:
361 break; /* Double only */
367 #define CHECKVAL(x) do { \
369 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
372 static ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
378 case AL_BYTE_RW_OFFSETS_SOFT
:
379 case AL_SAMPLE_RW_OFFSETS_SOFT
:
380 case AL_BYTE_LENGTH_SOFT
:
381 case AL_SAMPLE_LENGTH_SOFT
:
382 case AL_SEC_LENGTH_SOFT
:
383 case AL_SEC_OFFSET_LATENCY_SOFT
:
385 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
388 CHECKVAL(*values
>= 0.0f
);
390 Source
->Pitch
= *values
;
391 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
394 case AL_CONE_INNER_ANGLE
:
395 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
397 Source
->InnerAngle
= *values
;
398 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
401 case AL_CONE_OUTER_ANGLE
:
402 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
404 Source
->OuterAngle
= *values
;
405 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
409 CHECKVAL(*values
>= 0.0f
);
411 Source
->Gain
= *values
;
412 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
415 case AL_MAX_DISTANCE
:
416 CHECKVAL(*values
>= 0.0f
);
418 Source
->MaxDistance
= *values
;
419 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
422 case AL_ROLLOFF_FACTOR
:
423 CHECKVAL(*values
>= 0.0f
);
425 Source
->RollOffFactor
= *values
;
426 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
429 case AL_REFERENCE_DISTANCE
:
430 CHECKVAL(*values
>= 0.0f
);
432 Source
->RefDistance
= *values
;
433 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
437 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
439 Source
->MinGain
= *values
;
440 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
444 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
446 Source
->MaxGain
= *values
;
447 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
450 case AL_CONE_OUTER_GAIN
:
451 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
453 Source
->OuterGain
= *values
;
454 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
457 case AL_CONE_OUTER_GAINHF
:
458 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
460 Source
->OuterGainHF
= *values
;
461 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
464 case AL_AIR_ABSORPTION_FACTOR
:
465 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
467 Source
->AirAbsorptionFactor
= *values
;
468 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
471 case AL_ROOM_ROLLOFF_FACTOR
:
472 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
474 Source
->RoomRolloffFactor
= *values
;
475 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
478 case AL_DOPPLER_FACTOR
:
479 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
481 Source
->DopplerFactor
= *values
;
482 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
486 case AL_SAMPLE_OFFSET
:
488 CHECKVAL(*values
>= 0.0f
);
490 LockContext(Context
);
491 Source
->OffsetType
= prop
;
492 Source
->Offset
= *values
;
494 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
495 !Context
->DeferUpdates
)
497 WriteLock(&Source
->queue_lock
);
498 if(ApplyOffset(Source
) == AL_FALSE
)
500 WriteUnlock(&Source
->queue_lock
);
501 UnlockContext(Context
);
502 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
504 WriteUnlock(&Source
->queue_lock
);
506 UnlockContext(Context
);
511 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
513 LockContext(Context
);
514 aluVectorSet(&Source
->Position
, values
[0], values
[1], values
[2], 1.0f
);
515 UnlockContext(Context
);
516 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
520 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
522 LockContext(Context
);
523 aluVectorSet(&Source
->Velocity
, values
[0], values
[1], values
[2], 0.0f
);
524 UnlockContext(Context
);
525 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
529 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]));
531 LockContext(Context
);
532 aluVectorSet(&Source
->Direction
, values
[0], values
[1], values
[2], 0.0f
);
533 UnlockContext(Context
);
534 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
538 CHECKVAL(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
539 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5]));
541 LockContext(Context
);
542 Source
->Orientation
[0][0] = values
[0];
543 Source
->Orientation
[0][1] = values
[1];
544 Source
->Orientation
[0][2] = values
[2];
545 Source
->Orientation
[1][0] = values
[3];
546 Source
->Orientation
[1][1] = values
[4];
547 Source
->Orientation
[1][2] = values
[5];
548 UnlockContext(Context
);
549 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
553 case AL_SOURCE_RELATIVE
:
555 case AL_SOURCE_STATE
:
557 case AL_DISTANCE_MODEL
:
558 case AL_DIRECT_FILTER_GAINHF_AUTO
:
559 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
560 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
561 case AL_DIRECT_CHANNELS_SOFT
:
562 ival
= (ALint
)values
[0];
563 return SetSourceiv(Source
, Context
, prop
, &ival
);
565 case AL_BUFFERS_QUEUED
:
566 case AL_BUFFERS_PROCESSED
:
567 ival
= (ALint
)((ALuint
)values
[0]);
568 return SetSourceiv(Source
, Context
, prop
, &ival
);
571 case AL_DIRECT_FILTER
:
572 case AL_AUXILIARY_SEND_FILTER
:
573 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
577 ERR("Unexpected property: 0x%04x\n", prop
);
578 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
581 static ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
583 ALCdevice
*device
= Context
->Device
;
584 ALbuffer
*buffer
= NULL
;
585 ALfilter
*filter
= NULL
;
586 ALeffectslot
*slot
= NULL
;
587 ALbufferlistitem
*oldlist
;
588 ALbufferlistitem
*newlist
;
593 case AL_SOURCE_STATE
:
595 case AL_BUFFERS_QUEUED
:
596 case AL_BUFFERS_PROCESSED
:
597 case AL_SAMPLE_RW_OFFSETS_SOFT
:
598 case AL_BYTE_RW_OFFSETS_SOFT
:
599 case AL_BYTE_LENGTH_SOFT
:
600 case AL_SAMPLE_LENGTH_SOFT
:
601 case AL_SEC_LENGTH_SOFT
:
603 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
605 case AL_SOURCE_RELATIVE
:
606 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
608 Source
->HeadRelative
= (ALboolean
)*values
;
609 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
613 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
615 Source
->Looping
= (ALboolean
)*values
;
619 CHECKVAL(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != NULL
);
621 WriteLock(&Source
->queue_lock
);
622 if(!(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
))
624 WriteUnlock(&Source
->queue_lock
);
625 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
630 /* Add the selected buffer to a one-item queue */
631 newlist
= malloc(sizeof(ALbufferlistitem
));
632 newlist
->buffer
= buffer
;
633 newlist
->next
= NULL
;
634 newlist
->prev
= NULL
;
635 IncrementRef(&buffer
->ref
);
637 /* Source is now Static */
638 Source
->SourceType
= AL_STATIC
;
640 ReadLock(&buffer
->lock
);
641 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
642 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
643 ReadUnlock(&buffer
->lock
);
647 /* Source is now Undetermined */
648 Source
->SourceType
= AL_UNDETERMINED
;
651 oldlist
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &Source
->queue
, newlist
);
652 ATOMIC_STORE(&Source
->current_buffer
, newlist
);
653 WriteUnlock(&Source
->queue_lock
);
655 /* Delete all elements in the previous queue */
656 while(oldlist
!= NULL
)
658 ALbufferlistitem
*temp
= oldlist
;
659 oldlist
= temp
->next
;
662 DecrementRef(&temp
->buffer
->ref
);
668 case AL_SAMPLE_OFFSET
:
670 CHECKVAL(*values
>= 0);
672 LockContext(Context
);
673 Source
->OffsetType
= prop
;
674 Source
->Offset
= *values
;
676 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
677 !Context
->DeferUpdates
)
679 WriteLock(&Source
->queue_lock
);
680 if(ApplyOffset(Source
) == AL_FALSE
)
682 WriteUnlock(&Source
->queue_lock
);
683 UnlockContext(Context
);
684 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
686 WriteUnlock(&Source
->queue_lock
);
688 UnlockContext(Context
);
691 case AL_DIRECT_FILTER
:
692 CHECKVAL(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != NULL
);
694 LockContext(Context
);
697 Source
->Direct
.Gain
= 1.0f
;
698 Source
->Direct
.GainHF
= 1.0f
;
699 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
700 Source
->Direct
.GainLF
= 1.0f
;
701 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
705 Source
->Direct
.Gain
= filter
->Gain
;
706 Source
->Direct
.GainHF
= filter
->GainHF
;
707 Source
->Direct
.HFReference
= filter
->HFReference
;
708 Source
->Direct
.GainLF
= filter
->GainLF
;
709 Source
->Direct
.LFReference
= filter
->LFReference
;
711 UnlockContext(Context
);
712 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
715 case AL_DIRECT_FILTER_GAINHF_AUTO
:
716 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
718 Source
->DryGainHFAuto
= *values
;
719 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
722 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
723 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
725 Source
->WetGainAuto
= *values
;
726 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
729 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
730 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
732 Source
->WetGainHFAuto
= *values
;
733 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
736 case AL_DIRECT_CHANNELS_SOFT
:
737 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
739 Source
->DirectChannels
= *values
;
740 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
743 case AL_DISTANCE_MODEL
:
744 CHECKVAL(*values
== AL_NONE
||
745 *values
== AL_INVERSE_DISTANCE
||
746 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
747 *values
== AL_LINEAR_DISTANCE
||
748 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
749 *values
== AL_EXPONENT_DISTANCE
||
750 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
752 Source
->DistanceModel
= *values
;
753 if(Context
->SourceDistanceModel
)
754 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
758 case AL_AUXILIARY_SEND_FILTER
:
759 LockContext(Context
);
760 if(!((ALuint
)values
[1] < device
->NumAuxSends
&&
761 (values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != NULL
) &&
762 (values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != NULL
)))
764 UnlockContext(Context
);
765 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_VALUE
, AL_FALSE
);
768 /* Add refcount on the new slot, and release the previous slot */
769 if(slot
) IncrementRef(&slot
->ref
);
770 slot
= ExchangePtr((XchgPtr
*)&Source
->Send
[values
[1]].Slot
, slot
);
771 if(slot
) DecrementRef(&slot
->ref
);
776 Source
->Send
[values
[1]].Gain
= 1.0f
;
777 Source
->Send
[values
[1]].GainHF
= 1.0f
;
778 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
779 Source
->Send
[values
[1]].GainLF
= 1.0f
;
780 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
784 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
785 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
786 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
787 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
788 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
790 UnlockContext(Context
);
791 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
796 case AL_CONE_INNER_ANGLE
:
797 case AL_CONE_OUTER_ANGLE
:
802 case AL_REFERENCE_DISTANCE
:
803 case AL_ROLLOFF_FACTOR
:
804 case AL_CONE_OUTER_GAIN
:
805 case AL_MAX_DISTANCE
:
806 case AL_DOPPLER_FACTOR
:
807 case AL_CONE_OUTER_GAINHF
:
808 case AL_AIR_ABSORPTION_FACTOR
:
809 case AL_ROOM_ROLLOFF_FACTOR
:
810 fvals
[0] = (ALfloat
)*values
;
811 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
817 fvals
[0] = (ALfloat
)values
[0];
818 fvals
[1] = (ALfloat
)values
[1];
819 fvals
[2] = (ALfloat
)values
[2];
820 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
824 fvals
[0] = (ALfloat
)values
[0];
825 fvals
[1] = (ALfloat
)values
[1];
826 fvals
[2] = (ALfloat
)values
[2];
827 fvals
[3] = (ALfloat
)values
[3];
828 fvals
[4] = (ALfloat
)values
[4];
829 fvals
[5] = (ALfloat
)values
[5];
830 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
832 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
833 case AL_SEC_OFFSET_LATENCY_SOFT
:
837 ERR("Unexpected property: 0x%04x\n", prop
);
838 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
841 static ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
849 case AL_BUFFERS_QUEUED
:
850 case AL_BUFFERS_PROCESSED
:
851 case AL_SOURCE_STATE
:
852 case AL_SAMPLE_RW_OFFSETS_SOFT
:
853 case AL_BYTE_RW_OFFSETS_SOFT
:
854 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
855 case AL_BYTE_LENGTH_SOFT
:
856 case AL_SAMPLE_LENGTH_SOFT
:
857 case AL_SEC_LENGTH_SOFT
:
859 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_OPERATION
, AL_FALSE
);
863 case AL_SOURCE_RELATIVE
:
866 case AL_SAMPLE_OFFSET
:
868 case AL_DIRECT_FILTER_GAINHF_AUTO
:
869 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
870 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
871 case AL_DIRECT_CHANNELS_SOFT
:
872 case AL_DISTANCE_MODEL
:
873 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
875 ivals
[0] = (ALint
)*values
;
876 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
880 case AL_DIRECT_FILTER
:
881 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
883 ivals
[0] = (ALuint
)*values
;
884 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
887 case AL_AUXILIARY_SEND_FILTER
:
888 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
889 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
890 values
[2] <= UINT_MAX
&& values
[2] >= 0);
892 ivals
[0] = (ALuint
)values
[0];
893 ivals
[1] = (ALuint
)values
[1];
894 ivals
[2] = (ALuint
)values
[2];
895 return SetSourceiv(Source
, Context
, (int)prop
, ivals
);
898 case AL_CONE_INNER_ANGLE
:
899 case AL_CONE_OUTER_ANGLE
:
904 case AL_REFERENCE_DISTANCE
:
905 case AL_ROLLOFF_FACTOR
:
906 case AL_CONE_OUTER_GAIN
:
907 case AL_MAX_DISTANCE
:
908 case AL_DOPPLER_FACTOR
:
909 case AL_CONE_OUTER_GAINHF
:
910 case AL_AIR_ABSORPTION_FACTOR
:
911 case AL_ROOM_ROLLOFF_FACTOR
:
912 fvals
[0] = (ALfloat
)*values
;
913 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
919 fvals
[0] = (ALfloat
)values
[0];
920 fvals
[1] = (ALfloat
)values
[1];
921 fvals
[2] = (ALfloat
)values
[2];
922 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
926 fvals
[0] = (ALfloat
)values
[0];
927 fvals
[1] = (ALfloat
)values
[1];
928 fvals
[2] = (ALfloat
)values
[2];
929 fvals
[3] = (ALfloat
)values
[3];
930 fvals
[4] = (ALfloat
)values
[4];
931 fvals
[5] = (ALfloat
)values
[5];
932 return SetSourcefv(Source
, Context
, (int)prop
, fvals
);
934 case AL_SEC_OFFSET_LATENCY_SOFT
:
938 ERR("Unexpected property: 0x%04x\n", prop
);
939 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
945 static ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
947 ALCdevice
*device
= Context
->Device
;
948 ALbufferlistitem
*BufferList
;
957 *values
= Source
->Gain
;
961 *values
= Source
->Pitch
;
964 case AL_MAX_DISTANCE
:
965 *values
= Source
->MaxDistance
;
968 case AL_ROLLOFF_FACTOR
:
969 *values
= Source
->RollOffFactor
;
972 case AL_REFERENCE_DISTANCE
:
973 *values
= Source
->RefDistance
;
976 case AL_CONE_INNER_ANGLE
:
977 *values
= Source
->InnerAngle
;
980 case AL_CONE_OUTER_ANGLE
:
981 *values
= Source
->OuterAngle
;
985 *values
= Source
->MinGain
;
989 *values
= Source
->MaxGain
;
992 case AL_CONE_OUTER_GAIN
:
993 *values
= Source
->OuterGain
;
997 case AL_SAMPLE_OFFSET
:
999 LockContext(Context
);
1000 GetSourceOffsets(Source
, prop
, offsets
, 0.0);
1001 UnlockContext(Context
);
1002 *values
= offsets
[0];
1005 case AL_CONE_OUTER_GAINHF
:
1006 *values
= Source
->OuterGainHF
;
1009 case AL_AIR_ABSORPTION_FACTOR
:
1010 *values
= Source
->AirAbsorptionFactor
;
1013 case AL_ROOM_ROLLOFF_FACTOR
:
1014 *values
= Source
->RoomRolloffFactor
;
1017 case AL_DOPPLER_FACTOR
:
1018 *values
= Source
->DopplerFactor
;
1021 case AL_SEC_LENGTH_SOFT
:
1022 ReadLock(&Source
->queue_lock
);
1023 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1030 ALbuffer
*buffer
= BufferList
->buffer
;
1031 if(buffer
&& buffer
->SampleLen
> 0)
1033 freq
= buffer
->Frequency
;
1034 length
+= buffer
->SampleLen
;
1036 } while((BufferList
=BufferList
->next
) != NULL
);
1037 *values
= (ALdouble
)length
/ (ALdouble
)freq
;
1039 ReadUnlock(&Source
->queue_lock
);
1042 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1043 case AL_BYTE_RW_OFFSETS_SOFT
:
1044 LockContext(Context
);
1045 updateLen
= (ALdouble
)device
->UpdateSize
/ device
->Frequency
;
1046 GetSourceOffsets(Source
, prop
, values
, updateLen
);
1047 UnlockContext(Context
);
1050 case AL_SEC_OFFSET_LATENCY_SOFT
:
1051 LockContext(Context
);
1052 values
[0] = GetSourceSecOffset(Source
);
1053 values
[1] = (ALdouble
)(V0(device
->Backend
,getLatency
)()) /
1055 UnlockContext(Context
);
1059 LockContext(Context
);
1060 values
[0] = Source
->Position
.v
[0];
1061 values
[1] = Source
->Position
.v
[1];
1062 values
[2] = Source
->Position
.v
[2];
1063 UnlockContext(Context
);
1067 LockContext(Context
);
1068 values
[0] = Source
->Velocity
.v
[0];
1069 values
[1] = Source
->Velocity
.v
[1];
1070 values
[2] = Source
->Velocity
.v
[2];
1071 UnlockContext(Context
);
1075 LockContext(Context
);
1076 values
[0] = Source
->Direction
.v
[0];
1077 values
[1] = Source
->Direction
.v
[1];
1078 values
[2] = Source
->Direction
.v
[2];
1079 UnlockContext(Context
);
1082 case AL_ORIENTATION
:
1083 LockContext(Context
);
1084 values
[0] = Source
->Orientation
[0][0];
1085 values
[1] = Source
->Orientation
[0][1];
1086 values
[2] = Source
->Orientation
[0][2];
1087 values
[3] = Source
->Orientation
[1][0];
1088 values
[4] = Source
->Orientation
[1][1];
1089 values
[5] = Source
->Orientation
[1][2];
1090 UnlockContext(Context
);
1094 case AL_SOURCE_RELATIVE
:
1096 case AL_SOURCE_STATE
:
1097 case AL_BUFFERS_QUEUED
:
1098 case AL_BUFFERS_PROCESSED
:
1099 case AL_SOURCE_TYPE
:
1100 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1101 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1102 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1103 case AL_DIRECT_CHANNELS_SOFT
:
1104 case AL_BYTE_LENGTH_SOFT
:
1105 case AL_SAMPLE_LENGTH_SOFT
:
1106 case AL_DISTANCE_MODEL
:
1107 if((err
=GetSourceiv(Source
, Context
, (int)prop
, ivals
)) != AL_FALSE
)
1108 *values
= (ALdouble
)ivals
[0];
1112 case AL_DIRECT_FILTER
:
1113 case AL_AUXILIARY_SEND_FILTER
:
1114 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1118 ERR("Unexpected property: 0x%04x\n", prop
);
1119 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1122 static ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1124 ALbufferlistitem
*BufferList
;
1130 case AL_SOURCE_RELATIVE
:
1131 *values
= Source
->HeadRelative
;
1135 *values
= Source
->Looping
;
1139 ReadLock(&Source
->queue_lock
);
1140 BufferList
= (Source
->SourceType
== AL_STATIC
) ? ATOMIC_LOAD(&Source
->queue
) :
1141 ATOMIC_LOAD(&Source
->current_buffer
);
1142 *values
= (BufferList
&& BufferList
->buffer
) ? BufferList
->buffer
->id
: 0;
1143 ReadUnlock(&Source
->queue_lock
);
1146 case AL_SOURCE_STATE
:
1147 *values
= Source
->state
;
1150 case AL_BYTE_LENGTH_SOFT
:
1151 ReadLock(&Source
->queue_lock
);
1152 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1158 ALbuffer
*buffer
= BufferList
->buffer
;
1159 if(buffer
&& buffer
->SampleLen
> 0)
1161 ALuint byte_align
, sample_align
;
1162 if(buffer
->OriginalType
== UserFmtIMA4
)
1164 ALsizei align
= (buffer
->OriginalAlign
-1)/2 + 4;
1165 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1166 sample_align
= buffer
->OriginalAlign
;
1168 else if(buffer
->OriginalType
== UserFmtMSADPCM
)
1170 ALsizei align
= (buffer
->OriginalAlign
-2)/2 + 7;
1171 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1172 sample_align
= buffer
->OriginalAlign
;
1176 ALsizei align
= buffer
->OriginalAlign
;
1177 byte_align
= align
* ChannelsFromFmt(buffer
->FmtChannels
);
1178 sample_align
= buffer
->OriginalAlign
;
1181 length
+= buffer
->SampleLen
/ sample_align
* byte_align
;
1183 } while((BufferList
=BufferList
->next
) != NULL
);
1186 ReadUnlock(&Source
->queue_lock
);
1189 case AL_SAMPLE_LENGTH_SOFT
:
1190 ReadLock(&Source
->queue_lock
);
1191 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1197 ALbuffer
*buffer
= BufferList
->buffer
;
1198 if(buffer
) length
+= buffer
->SampleLen
;
1199 } while((BufferList
=BufferList
->next
) != NULL
);
1202 ReadUnlock(&Source
->queue_lock
);
1205 case AL_BUFFERS_QUEUED
:
1206 ReadLock(&Source
->queue_lock
);
1207 if(!(BufferList
=ATOMIC_LOAD(&Source
->queue
)))
1214 } while((BufferList
=BufferList
->next
) != NULL
);
1217 ReadUnlock(&Source
->queue_lock
);
1220 case AL_BUFFERS_PROCESSED
:
1221 ReadLock(&Source
->queue_lock
);
1222 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1224 /* Buffers on a looping source are in a perpetual state of
1225 * PENDING, so don't report any as PROCESSED */
1230 const ALbufferlistitem
*BufferList
= ATOMIC_LOAD(&Source
->queue
);
1231 const ALbufferlistitem
*Current
= ATOMIC_LOAD(&Source
->current_buffer
);
1233 while(BufferList
&& BufferList
!= Current
)
1236 BufferList
= BufferList
->next
;
1240 ReadUnlock(&Source
->queue_lock
);
1243 case AL_SOURCE_TYPE
:
1244 *values
= Source
->SourceType
;
1247 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1248 *values
= Source
->DryGainHFAuto
;
1251 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1252 *values
= Source
->WetGainAuto
;
1255 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1256 *values
= Source
->WetGainHFAuto
;
1259 case AL_DIRECT_CHANNELS_SOFT
:
1260 *values
= Source
->DirectChannels
;
1263 case AL_DISTANCE_MODEL
:
1264 *values
= Source
->DistanceModel
;
1267 /* 1x float/double */
1268 case AL_CONE_INNER_ANGLE
:
1269 case AL_CONE_OUTER_ANGLE
:
1274 case AL_REFERENCE_DISTANCE
:
1275 case AL_ROLLOFF_FACTOR
:
1276 case AL_CONE_OUTER_GAIN
:
1277 case AL_MAX_DISTANCE
:
1279 case AL_SAMPLE_OFFSET
:
1280 case AL_BYTE_OFFSET
:
1281 case AL_DOPPLER_FACTOR
:
1282 case AL_AIR_ABSORPTION_FACTOR
:
1283 case AL_ROOM_ROLLOFF_FACTOR
:
1284 case AL_CONE_OUTER_GAINHF
:
1285 case AL_SEC_LENGTH_SOFT
:
1286 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1287 *values
= (ALint
)dvals
[0];
1290 /* 2x float/double */
1291 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1292 case AL_BYTE_RW_OFFSETS_SOFT
:
1293 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1295 values
[0] = (ALint
)dvals
[0];
1296 values
[1] = (ALint
)dvals
[1];
1300 /* 3x float/double */
1304 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1306 values
[0] = (ALint
)dvals
[0];
1307 values
[1] = (ALint
)dvals
[1];
1308 values
[2] = (ALint
)dvals
[2];
1312 /* 6x float/double */
1313 case AL_ORIENTATION
:
1314 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1316 values
[0] = (ALint
)dvals
[0];
1317 values
[1] = (ALint
)dvals
[1];
1318 values
[2] = (ALint
)dvals
[2];
1319 values
[3] = (ALint
)dvals
[3];
1320 values
[4] = (ALint
)dvals
[4];
1321 values
[5] = (ALint
)dvals
[5];
1325 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1326 break; /* i64 only */
1327 case AL_SEC_OFFSET_LATENCY_SOFT
:
1328 break; /* Double only */
1330 case AL_DIRECT_FILTER
:
1331 case AL_AUXILIARY_SEND_FILTER
:
1335 ERR("Unexpected property: 0x%04x\n", prop
);
1336 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1339 static ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1341 ALCdevice
*device
= Context
->Device
;
1348 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1349 LockContext(Context
);
1350 values
[0] = GetSourceSampleOffset(Source
);
1351 values
[1] = V0(device
->Backend
,getLatency
)();
1352 UnlockContext(Context
);
1355 /* 1x float/double */
1356 case AL_CONE_INNER_ANGLE
:
1357 case AL_CONE_OUTER_ANGLE
:
1362 case AL_REFERENCE_DISTANCE
:
1363 case AL_ROLLOFF_FACTOR
:
1364 case AL_CONE_OUTER_GAIN
:
1365 case AL_MAX_DISTANCE
:
1367 case AL_SAMPLE_OFFSET
:
1368 case AL_BYTE_OFFSET
:
1369 case AL_DOPPLER_FACTOR
:
1370 case AL_AIR_ABSORPTION_FACTOR
:
1371 case AL_ROOM_ROLLOFF_FACTOR
:
1372 case AL_CONE_OUTER_GAINHF
:
1373 case AL_SEC_LENGTH_SOFT
:
1374 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1375 *values
= (ALint64
)dvals
[0];
1378 /* 2x float/double */
1379 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1380 case AL_BYTE_RW_OFFSETS_SOFT
:
1381 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1383 values
[0] = (ALint64
)dvals
[0];
1384 values
[1] = (ALint64
)dvals
[1];
1388 /* 3x float/double */
1392 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1394 values
[0] = (ALint64
)dvals
[0];
1395 values
[1] = (ALint64
)dvals
[1];
1396 values
[2] = (ALint64
)dvals
[2];
1400 /* 6x float/double */
1401 case AL_ORIENTATION
:
1402 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1404 values
[0] = (ALint64
)dvals
[0];
1405 values
[1] = (ALint64
)dvals
[1];
1406 values
[2] = (ALint64
)dvals
[2];
1407 values
[3] = (ALint64
)dvals
[3];
1408 values
[4] = (ALint64
)dvals
[4];
1409 values
[5] = (ALint64
)dvals
[5];
1414 case AL_SOURCE_RELATIVE
:
1416 case AL_SOURCE_STATE
:
1417 case AL_BUFFERS_QUEUED
:
1418 case AL_BUFFERS_PROCESSED
:
1419 case AL_BYTE_LENGTH_SOFT
:
1420 case AL_SAMPLE_LENGTH_SOFT
:
1421 case AL_SOURCE_TYPE
:
1422 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1423 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1424 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1425 case AL_DIRECT_CHANNELS_SOFT
:
1426 case AL_DISTANCE_MODEL
:
1427 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1433 case AL_DIRECT_FILTER
:
1434 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1435 *values
= (ALuint
)ivals
[0];
1439 case AL_AUXILIARY_SEND_FILTER
:
1440 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1442 values
[0] = (ALuint
)ivals
[0];
1443 values
[1] = (ALuint
)ivals
[1];
1444 values
[2] = (ALuint
)ivals
[2];
1448 case AL_SEC_OFFSET_LATENCY_SOFT
:
1449 break; /* Double only */
1452 ERR("Unexpected property: 0x%04x\n", prop
);
1453 SET_ERROR_AND_RETURN_VALUE(Context
, AL_INVALID_ENUM
, AL_FALSE
);
1457 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
1459 ALCcontext
*context
;
1463 context
= GetContextRef();
1464 if(!context
) return;
1467 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1468 for(cur
= 0;cur
< n
;cur
++)
1470 ALsource
*source
= al_calloc(16, sizeof(ALsource
));
1473 alDeleteSources(cur
, sources
);
1474 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
1476 InitSourceParams(source
);
1478 err
= NewThunkEntry(&source
->id
);
1479 if(err
== AL_NO_ERROR
)
1480 err
= InsertUIntMapEntry(&context
->SourceMap
, source
->id
, source
);
1481 if(err
!= AL_NO_ERROR
)
1483 FreeThunkEntry(source
->id
);
1484 memset(source
, 0, sizeof(ALsource
));
1487 alDeleteSources(cur
, sources
);
1488 SET_ERROR_AND_GOTO(context
, err
, done
);
1491 sources
[cur
] = source
->id
;
1495 ALCcontext_DecRef(context
);
1499 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
1501 ALCcontext
*context
;
1502 ALbufferlistitem
*BufferList
;
1506 context
= GetContextRef();
1507 if(!context
) return;
1510 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
1512 /* Check that all Sources are valid */
1513 for(i
= 0;i
< n
;i
++)
1515 if(LookupSource(context
, sources
[i
]) == NULL
)
1516 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
1518 for(i
= 0;i
< n
;i
++)
1520 ALvoice
*voice
, *voice_end
;
1522 if((Source
=RemoveSource(context
, sources
[i
])) == NULL
)
1524 FreeThunkEntry(Source
->id
);
1526 LockContext(context
);
1527 voice
= context
->Voices
;
1528 voice_end
= voice
+ context
->VoiceCount
;
1529 while(voice
!= voice_end
)
1531 ALsource
*old
= Source
;
1532 if(COMPARE_EXCHANGE(&voice
->Source
, &old
, NULL
))
1536 UnlockContext(context
);
1538 BufferList
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &Source
->queue
, NULL
);
1539 while(BufferList
!= NULL
)
1541 ALbufferlistitem
*next
= BufferList
->next
;
1542 if(BufferList
->buffer
!= NULL
)
1543 DecrementRef(&BufferList
->buffer
->ref
);
1548 for(j
= 0;j
< MAX_SENDS
;++j
)
1550 if(Source
->Send
[j
].Slot
)
1551 DecrementRef(&Source
->Send
[j
].Slot
->ref
);
1552 Source
->Send
[j
].Slot
= NULL
;
1555 memset(Source
, 0, sizeof(*Source
));
1560 ALCcontext_DecRef(context
);
1564 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
1566 ALCcontext
*context
;
1569 context
= GetContextRef();
1570 if(!context
) return AL_FALSE
;
1572 ret
= (LookupSource(context
, source
) ? AL_TRUE
: AL_FALSE
);
1574 ALCcontext_DecRef(context
);
1580 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
1582 ALCcontext
*Context
;
1585 Context
= GetContextRef();
1586 if(!Context
) return;
1588 if((Source
=LookupSource(Context
, source
)) == NULL
)
1589 alSetError(Context
, AL_INVALID_NAME
);
1590 else if(!(FloatValsByProp(param
) == 1))
1591 alSetError(Context
, AL_INVALID_ENUM
);
1593 SetSourcefv(Source
, Context
, param
, &value
);
1595 ALCcontext_DecRef(Context
);
1598 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
1600 ALCcontext
*Context
;
1603 Context
= GetContextRef();
1604 if(!Context
) return;
1606 if((Source
=LookupSource(Context
, source
)) == NULL
)
1607 alSetError(Context
, AL_INVALID_NAME
);
1608 else if(!(FloatValsByProp(param
) == 3))
1609 alSetError(Context
, AL_INVALID_ENUM
);
1612 ALfloat fvals
[3] = { value1
, value2
, value3
};
1613 SetSourcefv(Source
, Context
, param
, fvals
);
1616 ALCcontext_DecRef(Context
);
1619 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
1621 ALCcontext
*Context
;
1624 Context
= GetContextRef();
1625 if(!Context
) return;
1627 if((Source
=LookupSource(Context
, source
)) == NULL
)
1628 alSetError(Context
, AL_INVALID_NAME
);
1630 alSetError(Context
, AL_INVALID_VALUE
);
1631 else if(!(FloatValsByProp(param
) > 0))
1632 alSetError(Context
, AL_INVALID_ENUM
);
1634 SetSourcefv(Source
, Context
, param
, values
);
1636 ALCcontext_DecRef(Context
);
1640 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
1642 ALCcontext
*Context
;
1645 Context
= GetContextRef();
1646 if(!Context
) return;
1648 if((Source
=LookupSource(Context
, source
)) == NULL
)
1649 alSetError(Context
, AL_INVALID_NAME
);
1650 else if(!(DoubleValsByProp(param
) == 1))
1651 alSetError(Context
, AL_INVALID_ENUM
);
1654 ALfloat fval
= (ALfloat
)value
;
1655 SetSourcefv(Source
, Context
, param
, &fval
);
1658 ALCcontext_DecRef(Context
);
1661 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
1663 ALCcontext
*Context
;
1666 Context
= GetContextRef();
1667 if(!Context
) return;
1669 if((Source
=LookupSource(Context
, source
)) == NULL
)
1670 alSetError(Context
, AL_INVALID_NAME
);
1671 else if(!(DoubleValsByProp(param
) == 3))
1672 alSetError(Context
, AL_INVALID_ENUM
);
1675 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
1676 SetSourcefv(Source
, Context
, param
, fvals
);
1679 ALCcontext_DecRef(Context
);
1682 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
1684 ALCcontext
*Context
;
1688 Context
= GetContextRef();
1689 if(!Context
) return;
1691 if((Source
=LookupSource(Context
, source
)) == NULL
)
1692 alSetError(Context
, AL_INVALID_NAME
);
1694 alSetError(Context
, AL_INVALID_VALUE
);
1695 else if(!((count
=DoubleValsByProp(param
)) > 0 && count
<= 6))
1696 alSetError(Context
, AL_INVALID_ENUM
);
1702 for(i
= 0;i
< count
;i
++)
1703 fvals
[i
] = (ALfloat
)values
[i
];
1704 SetSourcefv(Source
, Context
, param
, fvals
);
1707 ALCcontext_DecRef(Context
);
1711 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
1713 ALCcontext
*Context
;
1716 Context
= GetContextRef();
1717 if(!Context
) return;
1719 if((Source
=LookupSource(Context
, source
)) == NULL
)
1720 alSetError(Context
, AL_INVALID_NAME
);
1721 else if(!(IntValsByProp(param
) == 1))
1722 alSetError(Context
, AL_INVALID_ENUM
);
1724 SetSourceiv(Source
, Context
, param
, &value
);
1726 ALCcontext_DecRef(Context
);
1729 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
1731 ALCcontext
*Context
;
1734 Context
= GetContextRef();
1735 if(!Context
) return;
1737 if((Source
=LookupSource(Context
, source
)) == NULL
)
1738 alSetError(Context
, AL_INVALID_NAME
);
1739 else if(!(IntValsByProp(param
) == 3))
1740 alSetError(Context
, AL_INVALID_ENUM
);
1743 ALint ivals
[3] = { value1
, value2
, value3
};
1744 SetSourceiv(Source
, Context
, param
, ivals
);
1747 ALCcontext_DecRef(Context
);
1750 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
1752 ALCcontext
*Context
;
1755 Context
= GetContextRef();
1756 if(!Context
) return;
1758 if((Source
=LookupSource(Context
, source
)) == NULL
)
1759 alSetError(Context
, AL_INVALID_NAME
);
1761 alSetError(Context
, AL_INVALID_VALUE
);
1762 else if(!(IntValsByProp(param
) > 0))
1763 alSetError(Context
, AL_INVALID_ENUM
);
1765 SetSourceiv(Source
, Context
, param
, values
);
1767 ALCcontext_DecRef(Context
);
1771 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
1773 ALCcontext
*Context
;
1776 Context
= GetContextRef();
1777 if(!Context
) return;
1779 if((Source
=LookupSource(Context
, source
)) == NULL
)
1780 alSetError(Context
, AL_INVALID_NAME
);
1781 else if(!(Int64ValsByProp(param
) == 1))
1782 alSetError(Context
, AL_INVALID_ENUM
);
1784 SetSourcei64v(Source
, Context
, param
, &value
);
1786 ALCcontext_DecRef(Context
);
1789 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
1791 ALCcontext
*Context
;
1794 Context
= GetContextRef();
1795 if(!Context
) return;
1797 if((Source
=LookupSource(Context
, source
)) == NULL
)
1798 alSetError(Context
, AL_INVALID_NAME
);
1799 else if(!(Int64ValsByProp(param
) == 3))
1800 alSetError(Context
, AL_INVALID_ENUM
);
1803 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
1804 SetSourcei64v(Source
, Context
, param
, i64vals
);
1807 ALCcontext_DecRef(Context
);
1810 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
1812 ALCcontext
*Context
;
1815 Context
= GetContextRef();
1816 if(!Context
) return;
1818 if((Source
=LookupSource(Context
, source
)) == NULL
)
1819 alSetError(Context
, AL_INVALID_NAME
);
1821 alSetError(Context
, AL_INVALID_VALUE
);
1822 else if(!(Int64ValsByProp(param
) > 0))
1823 alSetError(Context
, AL_INVALID_ENUM
);
1825 SetSourcei64v(Source
, Context
, param
, values
);
1827 ALCcontext_DecRef(Context
);
1831 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
1833 ALCcontext
*Context
;
1836 Context
= GetContextRef();
1837 if(!Context
) return;
1839 if((Source
=LookupSource(Context
, source
)) == NULL
)
1840 alSetError(Context
, AL_INVALID_NAME
);
1842 alSetError(Context
, AL_INVALID_VALUE
);
1843 else if(!(FloatValsByProp(param
) == 1))
1844 alSetError(Context
, AL_INVALID_ENUM
);
1848 if(GetSourcedv(Source
, Context
, param
, &dval
))
1849 *value
= (ALfloat
)dval
;
1852 ALCcontext_DecRef(Context
);
1856 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
1858 ALCcontext
*Context
;
1861 Context
= GetContextRef();
1862 if(!Context
) return;
1864 if((Source
=LookupSource(Context
, source
)) == NULL
)
1865 alSetError(Context
, AL_INVALID_NAME
);
1866 else if(!(value1
&& value2
&& value3
))
1867 alSetError(Context
, AL_INVALID_VALUE
);
1868 else if(!(FloatValsByProp(param
) == 3))
1869 alSetError(Context
, AL_INVALID_ENUM
);
1873 if(GetSourcedv(Source
, Context
, param
, dvals
))
1875 *value1
= (ALfloat
)dvals
[0];
1876 *value2
= (ALfloat
)dvals
[1];
1877 *value3
= (ALfloat
)dvals
[2];
1881 ALCcontext_DecRef(Context
);
1885 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
1887 ALCcontext
*Context
;
1891 Context
= GetContextRef();
1892 if(!Context
) return;
1894 if((Source
=LookupSource(Context
, source
)) == NULL
)
1895 alSetError(Context
, AL_INVALID_NAME
);
1897 alSetError(Context
, AL_INVALID_VALUE
);
1898 else if(!((count
=FloatValsByProp(param
)) > 0 && count
<= 6))
1899 alSetError(Context
, AL_INVALID_ENUM
);
1903 if(GetSourcedv(Source
, Context
, param
, dvals
))
1906 for(i
= 0;i
< count
;i
++)
1907 values
[i
] = (ALfloat
)dvals
[i
];
1911 ALCcontext_DecRef(Context
);
1915 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
1917 ALCcontext
*Context
;
1920 Context
= GetContextRef();
1921 if(!Context
) return;
1923 if((Source
=LookupSource(Context
, source
)) == NULL
)
1924 alSetError(Context
, AL_INVALID_NAME
);
1926 alSetError(Context
, AL_INVALID_VALUE
);
1927 else if(!(DoubleValsByProp(param
) == 1))
1928 alSetError(Context
, AL_INVALID_ENUM
);
1930 GetSourcedv(Source
, Context
, param
, value
);
1932 ALCcontext_DecRef(Context
);
1935 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
1937 ALCcontext
*Context
;
1940 Context
= GetContextRef();
1941 if(!Context
) return;
1943 if((Source
=LookupSource(Context
, source
)) == NULL
)
1944 alSetError(Context
, AL_INVALID_NAME
);
1945 else if(!(value1
&& value2
&& value3
))
1946 alSetError(Context
, AL_INVALID_VALUE
);
1947 else if(!(DoubleValsByProp(param
) == 3))
1948 alSetError(Context
, AL_INVALID_ENUM
);
1952 if(GetSourcedv(Source
, Context
, param
, dvals
))
1960 ALCcontext_DecRef(Context
);
1963 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
1965 ALCcontext
*Context
;
1968 Context
= GetContextRef();
1969 if(!Context
) return;
1971 if((Source
=LookupSource(Context
, source
)) == NULL
)
1972 alSetError(Context
, AL_INVALID_NAME
);
1974 alSetError(Context
, AL_INVALID_VALUE
);
1975 else if(!(DoubleValsByProp(param
) > 0))
1976 alSetError(Context
, AL_INVALID_ENUM
);
1978 GetSourcedv(Source
, Context
, param
, values
);
1980 ALCcontext_DecRef(Context
);
1984 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
1986 ALCcontext
*Context
;
1989 Context
= GetContextRef();
1990 if(!Context
) return;
1992 if((Source
=LookupSource(Context
, source
)) == NULL
)
1993 alSetError(Context
, AL_INVALID_NAME
);
1995 alSetError(Context
, AL_INVALID_VALUE
);
1996 else if(!(IntValsByProp(param
) == 1))
1997 alSetError(Context
, AL_INVALID_ENUM
);
1999 GetSourceiv(Source
, Context
, param
, value
);
2001 ALCcontext_DecRef(Context
);
2005 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2007 ALCcontext
*Context
;
2010 Context
= GetContextRef();
2011 if(!Context
) return;
2013 if((Source
=LookupSource(Context
, source
)) == NULL
)
2014 alSetError(Context
, AL_INVALID_NAME
);
2015 else if(!(value1
&& value2
&& value3
))
2016 alSetError(Context
, AL_INVALID_VALUE
);
2017 else if(!(IntValsByProp(param
) == 3))
2018 alSetError(Context
, AL_INVALID_ENUM
);
2022 if(GetSourceiv(Source
, Context
, param
, ivals
))
2030 ALCcontext_DecRef(Context
);
2034 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2036 ALCcontext
*Context
;
2039 Context
= GetContextRef();
2040 if(!Context
) return;
2042 if((Source
=LookupSource(Context
, source
)) == NULL
)
2043 alSetError(Context
, AL_INVALID_NAME
);
2045 alSetError(Context
, AL_INVALID_VALUE
);
2046 else if(!(IntValsByProp(param
) > 0))
2047 alSetError(Context
, AL_INVALID_ENUM
);
2049 GetSourceiv(Source
, Context
, param
, values
);
2051 ALCcontext_DecRef(Context
);
2055 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2057 ALCcontext
*Context
;
2060 Context
= GetContextRef();
2061 if(!Context
) return;
2063 if((Source
=LookupSource(Context
, source
)) == NULL
)
2064 alSetError(Context
, AL_INVALID_NAME
);
2066 alSetError(Context
, AL_INVALID_VALUE
);
2067 else if(!(Int64ValsByProp(param
) == 1))
2068 alSetError(Context
, AL_INVALID_ENUM
);
2070 GetSourcei64v(Source
, Context
, param
, value
);
2072 ALCcontext_DecRef(Context
);
2075 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2077 ALCcontext
*Context
;
2080 Context
= GetContextRef();
2081 if(!Context
) return;
2083 if((Source
=LookupSource(Context
, source
)) == NULL
)
2084 alSetError(Context
, AL_INVALID_NAME
);
2085 else if(!(value1
&& value2
&& value3
))
2086 alSetError(Context
, AL_INVALID_VALUE
);
2087 else if(!(Int64ValsByProp(param
) == 3))
2088 alSetError(Context
, AL_INVALID_ENUM
);
2092 if(GetSourcei64v(Source
, Context
, param
, i64vals
))
2094 *value1
= i64vals
[0];
2095 *value2
= i64vals
[1];
2096 *value3
= i64vals
[2];
2100 ALCcontext_DecRef(Context
);
2103 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2105 ALCcontext
*Context
;
2108 Context
= GetContextRef();
2109 if(!Context
) return;
2111 if((Source
=LookupSource(Context
, source
)) == NULL
)
2112 alSetError(Context
, AL_INVALID_NAME
);
2114 alSetError(Context
, AL_INVALID_VALUE
);
2115 else if(!(Int64ValsByProp(param
) > 0))
2116 alSetError(Context
, AL_INVALID_ENUM
);
2118 GetSourcei64v(Source
, Context
, param
, values
);
2120 ALCcontext_DecRef(Context
);
2124 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2126 alSourcePlayv(1, &source
);
2128 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2130 ALCcontext
*context
;
2134 context
= GetContextRef();
2135 if(!context
) return;
2138 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2139 for(i
= 0;i
< n
;i
++)
2141 if(!LookupSource(context
, sources
[i
]))
2142 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2145 LockContext(context
);
2146 while(n
> context
->MaxVoices
-context
->VoiceCount
)
2148 ALvoice
*temp
= NULL
;
2151 newcount
= context
->MaxVoices
<< 1;
2153 temp
= realloc(context
->Voices
, newcount
* sizeof(context
->Voices
[0]));
2156 UnlockContext(context
);
2157 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
2159 memset(&temp
[context
->MaxVoices
], 0, (newcount
-context
->MaxVoices
) * sizeof(temp
[0]));
2161 context
->Voices
= temp
;
2162 context
->MaxVoices
= newcount
;
2165 for(i
= 0;i
< n
;i
++)
2167 source
= LookupSource(context
, sources
[i
]);
2168 if(context
->DeferUpdates
) source
->new_state
= AL_PLAYING
;
2169 else SetSourceState(source
, context
, AL_PLAYING
);
2171 UnlockContext(context
);
2174 ALCcontext_DecRef(context
);
2177 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2179 alSourcePausev(1, &source
);
2181 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2183 ALCcontext
*context
;
2187 context
= GetContextRef();
2188 if(!context
) return;
2191 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2192 for(i
= 0;i
< n
;i
++)
2194 if(!LookupSource(context
, sources
[i
]))
2195 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2198 LockContext(context
);
2199 for(i
= 0;i
< n
;i
++)
2201 source
= LookupSource(context
, sources
[i
]);
2202 if(context
->DeferUpdates
) source
->new_state
= AL_PAUSED
;
2203 else SetSourceState(source
, context
, AL_PAUSED
);
2205 UnlockContext(context
);
2208 ALCcontext_DecRef(context
);
2211 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2213 alSourceStopv(1, &source
);
2215 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2217 ALCcontext
*context
;
2221 context
= GetContextRef();
2222 if(!context
) return;
2225 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2226 for(i
= 0;i
< n
;i
++)
2228 if(!LookupSource(context
, sources
[i
]))
2229 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2232 LockContext(context
);
2233 for(i
= 0;i
< n
;i
++)
2235 source
= LookupSource(context
, sources
[i
]);
2236 source
->new_state
= AL_NONE
;
2237 SetSourceState(source
, context
, AL_STOPPED
);
2239 UnlockContext(context
);
2242 ALCcontext_DecRef(context
);
2245 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2247 alSourceRewindv(1, &source
);
2249 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2251 ALCcontext
*context
;
2255 context
= GetContextRef();
2256 if(!context
) return;
2259 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2260 for(i
= 0;i
< n
;i
++)
2262 if(!LookupSource(context
, sources
[i
]))
2263 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2266 LockContext(context
);
2267 for(i
= 0;i
< n
;i
++)
2269 source
= LookupSource(context
, sources
[i
]);
2270 source
->new_state
= AL_NONE
;
2271 SetSourceState(source
, context
, AL_INITIAL
);
2273 UnlockContext(context
);
2276 ALCcontext_DecRef(context
);
2280 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2283 ALCcontext
*context
;
2286 ALbufferlistitem
*BufferListStart
;
2287 ALbufferlistitem
*BufferList
;
2288 ALbuffer
*BufferFmt
= NULL
;
2293 context
= GetContextRef();
2294 if(!context
) return;
2296 device
= context
->Device
;
2299 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2300 if((source
=LookupSource(context
, src
)) == NULL
)
2301 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2303 WriteLock(&source
->queue_lock
);
2304 if(source
->SourceType
== AL_STATIC
)
2306 WriteUnlock(&source
->queue_lock
);
2307 /* Can't queue on a Static Source */
2308 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
2311 /* Check for a valid Buffer, for its frequency and format */
2312 BufferList
= ATOMIC_LOAD(&source
->queue
);
2315 if(BufferList
->buffer
)
2317 BufferFmt
= BufferList
->buffer
;
2320 BufferList
= BufferList
->next
;
2323 BufferListStart
= NULL
;
2325 for(i
= 0;i
< nb
;i
++)
2327 ALbuffer
*buffer
= NULL
;
2328 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
2330 WriteUnlock(&source
->queue_lock
);
2331 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, buffer_error
);
2334 if(!BufferListStart
)
2336 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
2337 BufferListStart
->buffer
= buffer
;
2338 BufferListStart
->next
= NULL
;
2339 BufferListStart
->prev
= NULL
;
2340 BufferList
= BufferListStart
;
2344 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
2345 BufferList
->next
->buffer
= buffer
;
2346 BufferList
->next
->next
= NULL
;
2347 BufferList
->next
->prev
= BufferList
;
2348 BufferList
= BufferList
->next
;
2350 if(!buffer
) continue;
2352 /* Hold a read lock on each buffer being queued while checking all
2353 * provided buffers. This is done so other threads don't see an extra
2354 * reference on some buffers if this operation ends up failing. */
2355 ReadLock(&buffer
->lock
);
2356 IncrementRef(&buffer
->ref
);
2358 if(BufferFmt
== NULL
)
2362 source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
2363 source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
2365 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
2366 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
2367 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
2369 WriteUnlock(&source
->queue_lock
);
2370 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, buffer_error
);
2373 /* A buffer failed (invalid ID or format), so unlock and release
2374 * each buffer we had. */
2375 while(BufferList
!= NULL
)
2377 ALbufferlistitem
*prev
= BufferList
->prev
;
2378 if((buffer
=BufferList
->buffer
) != NULL
)
2380 DecrementRef(&buffer
->ref
);
2381 ReadUnlock(&buffer
->lock
);
2389 /* All buffers good, unlock them now. */
2390 while(BufferList
!= NULL
)
2392 ALbuffer
*buffer
= BufferList
->buffer
;
2393 if(buffer
) ReadUnlock(&buffer
->lock
);
2394 BufferList
= BufferList
->prev
;
2397 /* Source is now streaming */
2398 source
->SourceType
= AL_STREAMING
;
2401 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->queue
, &BufferList
, BufferListStart
))
2403 /* Queue head is not NULL, append to the end of the queue */
2404 while(BufferList
->next
!= NULL
)
2405 BufferList
= BufferList
->next
;
2407 BufferListStart
->prev
= BufferList
;
2408 BufferList
->next
= BufferListStart
;
2411 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem
*, &source
->current_buffer
, &BufferList
, BufferListStart
);
2412 WriteUnlock(&source
->queue_lock
);
2415 ALCcontext_DecRef(context
);
2418 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
2420 ALCcontext
*context
;
2422 ALbufferlistitem
*NewHead
;
2423 ALbufferlistitem
*OldHead
;
2424 ALbufferlistitem
*Current
;
2430 context
= GetContextRef();
2431 if(!context
) return;
2434 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2436 if((source
=LookupSource(context
, src
)) == NULL
)
2437 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
2439 WriteLock(&source
->queue_lock
);
2440 /* Find the new buffer queue head */
2441 NewHead
= ATOMIC_LOAD(&source
->queue
);
2442 Current
= ATOMIC_LOAD(&source
->current_buffer
);
2443 for(i
= 0;i
< nb
&& NewHead
;i
++)
2445 if(NewHead
== Current
)
2447 NewHead
= NewHead
->next
;
2449 if(source
->Looping
|| source
->SourceType
!= AL_STREAMING
|| i
!= nb
)
2451 WriteUnlock(&source
->queue_lock
);
2452 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2453 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
2456 /* Swap it, and cut the new head from the old. */
2457 OldHead
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &source
->queue
, NewHead
);
2460 ALCdevice
*device
= context
->Device
;
2461 ALbufferlistitem
*OldTail
= NewHead
->prev
;
2464 /* Cut the new head's link back to the old body. The mixer is robust
2465 * enough to handle the link back going away. Once the active mix (if
2466 * any) is complete, it's safe to finish cutting the old tail from the
2468 NewHead
->prev
= NULL
;
2469 if(((count
=ReadRef(&device
->MixCount
))&1) != 0)
2471 while(count
== ReadRef(&device
->MixCount
))
2474 OldTail
->next
= NULL
;
2476 WriteUnlock(&source
->queue_lock
);
2478 while(OldHead
!= NULL
)
2480 ALbufferlistitem
*next
= OldHead
->next
;
2481 ALbuffer
*buffer
= OldHead
->buffer
;
2487 *(buffers
++) = buffer
->id
;
2488 DecrementRef(&buffer
->ref
);
2496 ALCcontext_DecRef(context
);
2500 static ALvoid
InitSourceParams(ALsource
*Source
)
2504 RWLockInit(&Source
->queue_lock
);
2506 Source
->InnerAngle
= 360.0f
;
2507 Source
->OuterAngle
= 360.0f
;
2508 Source
->Pitch
= 1.0f
;
2509 aluVectorSet(&Source
->Position
, 0.0f
, 0.0f
, 0.0f
, 1.0f
);
2510 aluVectorSet(&Source
->Velocity
, 0.0f
, 0.0f
, 0.0f
, 0.0f
);
2511 aluVectorSet(&Source
->Direction
, 0.0f
, 0.0f
, 0.0f
, 0.0f
);
2512 Source
->Orientation
[0][0] = 0.0f
;
2513 Source
->Orientation
[0][1] = 0.0f
;
2514 Source
->Orientation
[0][2] = -1.0f
;
2515 Source
->Orientation
[1][0] = 0.0f
;
2516 Source
->Orientation
[1][1] = 1.0f
;
2517 Source
->Orientation
[1][2] = 0.0f
;
2518 Source
->RefDistance
= 1.0f
;
2519 Source
->MaxDistance
= FLT_MAX
;
2520 Source
->RollOffFactor
= 1.0f
;
2521 Source
->Looping
= AL_FALSE
;
2522 Source
->Gain
= 1.0f
;
2523 Source
->MinGain
= 0.0f
;
2524 Source
->MaxGain
= 1.0f
;
2525 Source
->OuterGain
= 0.0f
;
2526 Source
->OuterGainHF
= 1.0f
;
2528 Source
->DryGainHFAuto
= AL_TRUE
;
2529 Source
->WetGainAuto
= AL_TRUE
;
2530 Source
->WetGainHFAuto
= AL_TRUE
;
2531 Source
->AirAbsorptionFactor
= 0.0f
;
2532 Source
->RoomRolloffFactor
= 0.0f
;
2533 Source
->DopplerFactor
= 1.0f
;
2534 Source
->DirectChannels
= AL_FALSE
;
2536 Source
->Radius
= 0.0f
;
2538 Source
->DistanceModel
= DefaultDistanceModel
;
2540 Source
->state
= AL_INITIAL
;
2541 Source
->new_state
= AL_NONE
;
2542 Source
->SourceType
= AL_UNDETERMINED
;
2543 Source
->Offset
= -1.0;
2545 ATOMIC_INIT(&Source
->queue
, NULL
);
2546 ATOMIC_INIT(&Source
->current_buffer
, NULL
);
2548 Source
->Direct
.Gain
= 1.0f
;
2549 Source
->Direct
.GainHF
= 1.0f
;
2550 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
2551 Source
->Direct
.GainLF
= 1.0f
;
2552 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
2553 for(i
= 0;i
< MAX_SENDS
;i
++)
2555 Source
->Send
[i
].Gain
= 1.0f
;
2556 Source
->Send
[i
].GainHF
= 1.0f
;
2557 Source
->Send
[i
].HFReference
= LOWPASSFREQREF
;
2558 Source
->Send
[i
].GainLF
= 1.0f
;
2559 Source
->Send
[i
].LFReference
= HIGHPASSFREQREF
;
2562 ATOMIC_INIT(&Source
->NeedsUpdate
, AL_TRUE
);
2568 * Sets the source's new play state given its current state.
2570 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
2572 WriteLock(&Source
->queue_lock
);
2573 if(state
== AL_PLAYING
)
2575 ALCdevice
*device
= Context
->Device
;
2576 ALbufferlistitem
*BufferList
;
2577 ALboolean discontinuity
;
2578 ALvoice
*voice
= NULL
;
2581 /* Check that there is a queue containing at least one valid, non zero
2583 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2587 if((buffer
=BufferList
->buffer
) != NULL
&& buffer
->SampleLen
> 0)
2589 BufferList
= BufferList
->next
;
2592 if(Source
->state
!= AL_PAUSED
)
2594 Source
->state
= AL_PLAYING
;
2595 Source
->position
= 0;
2596 Source
->position_fraction
= 0;
2597 ATOMIC_STORE(&Source
->current_buffer
, BufferList
);
2598 discontinuity
= AL_TRUE
;
2602 Source
->state
= AL_PLAYING
;
2603 discontinuity
= AL_FALSE
;
2606 // Check if an Offset has been set
2607 if(Source
->Offset
>= 0.0)
2609 ApplyOffset(Source
);
2610 /* discontinuity = AL_TRUE;??? */
2613 /* If there's nothing to play, or device is disconnected, go right to
2615 if(!BufferList
|| !device
->Connected
)
2618 /* Make sure this source isn't already active, while looking for an
2619 * unused active source slot to put it in. */
2620 for(i
= 0;i
< Context
->VoiceCount
;i
++)
2622 ALsource
*old
= Source
;
2623 if(COMPARE_EXCHANGE(&Context
->Voices
[i
].Source
, &old
, NULL
))
2627 voice
= &Context
->Voices
[i
];
2628 voice
->Source
= Source
;
2633 if(voice
== NULL
&& COMPARE_EXCHANGE(&Context
->Voices
[i
].Source
, &old
, Source
))
2634 voice
= &Context
->Voices
[i
];
2638 voice
= &Context
->Voices
[Context
->VoiceCount
++];
2639 voice
->Source
= Source
;
2642 /* Clear previous samples if playback is discontinuous. */
2644 memset(voice
->PrevSamples
, 0, sizeof(voice
->PrevSamples
));
2646 voice
->Direct
.Moving
= AL_FALSE
;
2647 voice
->Direct
.Counter
= 0;
2648 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
2651 for(j
= 0;j
< HRTF_HISTORY_LENGTH
;j
++)
2652 voice
->Direct
.Hrtf
[i
].State
.History
[j
] = 0.0f
;
2653 for(j
= 0;j
< HRIR_LENGTH
;j
++)
2655 voice
->Direct
.Hrtf
[i
].State
.Values
[j
][0] = 0.0f
;
2656 voice
->Direct
.Hrtf
[i
].State
.Values
[j
][1] = 0.0f
;
2659 for(i
= 0;i
< (ALsizei
)device
->NumAuxSends
;i
++)
2661 voice
->Send
[i
].Moving
= AL_FALSE
;
2662 voice
->Send
[i
].Counter
= 0;
2665 if(BufferList
->buffer
->FmtChannels
== FmtMono
)
2666 voice
->Update
= CalcSourceParams
;
2668 voice
->Update
= CalcNonAttnSourceParams
;
2670 ATOMIC_STORE(&Source
->NeedsUpdate
, AL_TRUE
);
2672 else if(state
== AL_PAUSED
)
2674 if(Source
->state
== AL_PLAYING
)
2675 Source
->state
= AL_PAUSED
;
2677 else if(state
== AL_STOPPED
)
2680 if(Source
->state
!= AL_INITIAL
)
2682 Source
->state
= AL_STOPPED
;
2683 ATOMIC_STORE(&Source
->current_buffer
, NULL
);
2685 Source
->Offset
= -1.0;
2687 else if(state
== AL_INITIAL
)
2689 if(Source
->state
!= AL_INITIAL
)
2691 Source
->state
= AL_INITIAL
;
2692 Source
->position
= 0;
2693 Source
->position_fraction
= 0;
2694 ATOMIC_STORE(&Source
->current_buffer
, ATOMIC_LOAD(&Source
->queue
));
2696 Source
->Offset
= -1.0;
2698 WriteUnlock(&Source
->queue_lock
);
2701 /* GetSourceSampleOffset
2703 * Gets the current read offset for the given Source, in 32.32 fixed-point
2704 * samples. The offset is relative to the start of the queue (not the start of
2705 * the current buffer).
2707 ALint64
GetSourceSampleOffset(ALsource
*Source
)
2709 const ALbufferlistitem
*BufferList
;
2710 const ALbufferlistitem
*Current
;
2713 ReadLock(&Source
->queue_lock
);
2714 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
2716 ReadUnlock(&Source
->queue_lock
);
2720 /* NOTE: This is the offset into the *current* buffer, so add the length of
2721 * any played buffers */
2722 readPos
= (ALuint64
)Source
->position
<< 32;
2723 readPos
|= (ALuint64
)Source
->position_fraction
<< (32-FRACTIONBITS
);
2724 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2725 Current
= ATOMIC_LOAD(&Source
->current_buffer
);
2726 while(BufferList
&& BufferList
!= Current
)
2728 if(BufferList
->buffer
)
2729 readPos
+= (ALuint64
)BufferList
->buffer
->SampleLen
<< 32;
2730 BufferList
= BufferList
->next
;
2733 ReadUnlock(&Source
->queue_lock
);
2734 return (ALint64
)minu64(readPos
, U64(0x7fffffffffffffff));
2737 /* GetSourceSecOffset
2739 * Gets the current read offset for the given Source, in seconds. The offset is
2740 * relative to the start of the queue (not the start of the current buffer).
2742 static ALdouble
GetSourceSecOffset(ALsource
*Source
)
2744 const ALbufferlistitem
*BufferList
;
2745 const ALbufferlistitem
*Current
;
2746 const ALbuffer
*Buffer
= NULL
;
2749 ReadLock(&Source
->queue_lock
);
2750 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
2752 ReadUnlock(&Source
->queue_lock
);
2756 /* NOTE: This is the offset into the *current* buffer, so add the length of
2757 * any played buffers */
2758 readPos
= (ALuint64
)Source
->position
<< FRACTIONBITS
;
2759 readPos
|= (ALuint64
)Source
->position_fraction
;
2760 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2761 Current
= ATOMIC_LOAD(&Source
->current_buffer
);
2762 while(BufferList
&& BufferList
!= Current
)
2764 const ALbuffer
*buffer
= BufferList
->buffer
;
2767 if(!Buffer
) Buffer
= buffer
;
2768 readPos
+= (ALuint64
)buffer
->SampleLen
<< FRACTIONBITS
;
2770 BufferList
= BufferList
->next
;
2773 while(BufferList
&& !Buffer
)
2775 Buffer
= BufferList
->buffer
;
2776 BufferList
= BufferList
->next
;
2778 assert(Buffer
!= NULL
);
2780 ReadUnlock(&Source
->queue_lock
);
2781 return (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/ (ALdouble
)Buffer
->Frequency
;
2786 * Gets the current read and write offsets for the given Source, in the
2787 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2788 * the start of the queue (not the start of the current buffer).
2790 static ALvoid
GetSourceOffsets(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
2792 const ALbufferlistitem
*BufferList
;
2793 const ALbufferlistitem
*Current
;
2794 const ALbuffer
*Buffer
= NULL
;
2795 ALboolean readFin
= AL_FALSE
;
2796 ALuint readPos
, readPosFrac
, writePos
;
2797 ALuint totalBufferLen
;
2799 ReadLock(&Source
->queue_lock
);
2800 if(Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
)
2804 ReadUnlock(&Source
->queue_lock
);
2808 if(updateLen
> 0.0 && updateLen
< 0.015)
2811 /* NOTE: This is the offset into the *current* buffer, so add the length of
2812 * any played buffers */
2814 readPos
= Source
->position
;
2815 readPosFrac
= Source
->position_fraction
;
2816 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2817 Current
= ATOMIC_LOAD(&Source
->current_buffer
);
2818 while(BufferList
!= NULL
)
2820 const ALbuffer
*buffer
;
2821 readFin
= readFin
|| (BufferList
== Current
);
2822 if((buffer
=BufferList
->buffer
) != NULL
)
2824 if(!Buffer
) Buffer
= buffer
;
2825 totalBufferLen
+= buffer
->SampleLen
;
2826 if(!readFin
) readPos
+= buffer
->SampleLen
;
2828 BufferList
= BufferList
->next
;
2830 assert(Buffer
!= NULL
);
2832 if(Source
->state
== AL_PLAYING
)
2833 writePos
= readPos
+ (ALuint
)(updateLen
*Buffer
->Frequency
+ 0.5f
);
2839 readPos
%= totalBufferLen
;
2840 writePos
%= totalBufferLen
;
2844 /* Wrap positions back to 0 */
2845 if(readPos
>= totalBufferLen
)
2846 readPos
= readPosFrac
= 0;
2847 if(writePos
>= totalBufferLen
)
2854 offset
[0] = (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
)/Buffer
->Frequency
;
2855 offset
[1] = (ALdouble
)writePos
/Buffer
->Frequency
;
2858 case AL_SAMPLE_OFFSET
:
2859 case AL_SAMPLE_RW_OFFSETS_SOFT
:
2860 offset
[0] = readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
2861 offset
[1] = (ALdouble
)writePos
;
2864 case AL_BYTE_OFFSET
:
2865 case AL_BYTE_RW_OFFSETS_SOFT
:
2866 if(Buffer
->OriginalType
== UserFmtIMA4
)
2868 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
2869 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
2870 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
2872 /* Round down to nearest ADPCM block */
2873 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
2874 if(Source
->state
!= AL_PLAYING
)
2875 offset
[1] = offset
[0];
2878 /* Round up to nearest ADPCM block */
2879 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
2880 FrameBlockSize
* BlockSize
);
2883 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
2885 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
2886 ALuint BlockSize
= align
* ChannelsFromFmt(Buffer
->FmtChannels
);
2887 ALuint FrameBlockSize
= Buffer
->OriginalAlign
;
2889 /* Round down to nearest ADPCM block */
2890 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
2891 if(Source
->state
!= AL_PLAYING
)
2892 offset
[1] = offset
[0];
2895 /* Round up to nearest ADPCM block */
2896 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
2897 FrameBlockSize
* BlockSize
);
2902 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
2903 offset
[0] = (ALdouble
)(readPos
* FrameSize
);
2904 offset
[1] = (ALdouble
)(writePos
* FrameSize
);
2909 ReadUnlock(&Source
->queue_lock
);
2915 * Apply the stored playback offset to the Source. This function will update
2916 * the number of buffers "played" given the stored offset.
2918 ALboolean
ApplyOffset(ALsource
*Source
)
2920 ALbufferlistitem
*BufferList
;
2921 const ALbuffer
*Buffer
;
2922 ALuint bufferLen
, totalBufferLen
;
2923 ALuint offset
=0, frac
=0;
2925 /* Get sample frame offset */
2926 if(!GetSampleOffset(Source
, &offset
, &frac
))
2930 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2931 while(BufferList
&& totalBufferLen
<= offset
)
2933 Buffer
= BufferList
->buffer
;
2934 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
2936 if(bufferLen
> offset
-totalBufferLen
)
2938 /* Offset is in this buffer */
2939 ATOMIC_STORE(&Source
->current_buffer
, BufferList
);
2941 Source
->position
= offset
- totalBufferLen
;
2942 Source
->position_fraction
= frac
;
2946 totalBufferLen
+= bufferLen
;
2948 BufferList
= BufferList
->next
;
2951 /* Offset is out of range of the queue */
2958 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
2959 * or Second offset supplied by the application). This takes into account the
2960 * fact that the buffer format may have been modifed since.
2962 static ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALuint
*frac
)
2964 const ALbuffer
*Buffer
= NULL
;
2965 const ALbufferlistitem
*BufferList
;
2966 ALdouble dbloff
, dblfrac
;
2968 /* Find the first valid Buffer in the Queue */
2969 BufferList
= ATOMIC_LOAD(&Source
->queue
);
2972 if(BufferList
->buffer
)
2974 Buffer
= BufferList
->buffer
;
2977 BufferList
= BufferList
->next
;
2981 Source
->Offset
= -1.0;
2985 switch(Source
->OffsetType
)
2987 case AL_BYTE_OFFSET
:
2988 /* Determine the ByteOffset (and ensure it is block aligned) */
2989 *offset
= (ALuint
)Source
->Offset
;
2990 if(Buffer
->OriginalType
== UserFmtIMA4
)
2992 ALsizei align
= (Buffer
->OriginalAlign
-1)/2 + 4;
2993 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
2994 *offset
*= Buffer
->OriginalAlign
;
2996 else if(Buffer
->OriginalType
== UserFmtMSADPCM
)
2998 ALsizei align
= (Buffer
->OriginalAlign
-2)/2 + 7;
2999 *offset
/= align
* ChannelsFromUserFmt(Buffer
->OriginalChannels
);
3000 *offset
*= Buffer
->OriginalAlign
;
3003 *offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
3007 case AL_SAMPLE_OFFSET
:
3008 dblfrac
= modf(Source
->Offset
, &dbloff
);
3009 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3010 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3014 dblfrac
= modf(Source
->Offset
*Buffer
->Frequency
, &dbloff
);
3015 *offset
= (ALuint
)mind(dbloff
, UINT_MAX
);
3016 *frac
= (ALuint
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
3019 Source
->Offset
= -1.0;
3027 * Destroys all sources in the source map.
3029 ALvoid
ReleaseALSources(ALCcontext
*Context
)
3031 ALbufferlistitem
*item
;
3034 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
3036 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
3037 Context
->SourceMap
.array
[pos
].value
= NULL
;
3039 item
= ATOMIC_EXCHANGE(ALbufferlistitem
*, &temp
->queue
, NULL
);
3042 ALbufferlistitem
*next
= item
->next
;
3043 if(item
->buffer
!= NULL
)
3044 DecrementRef(&item
->buffer
->ref
);
3049 for(j
= 0;j
< MAX_SENDS
;++j
)
3051 if(temp
->Send
[j
].Slot
)
3052 DecrementRef(&temp
->Send
[j
].Slot
->ref
);
3053 temp
->Send
[j
].Slot
= NULL
;
3056 FreeThunkEntry(temp
->id
);
3057 memset(temp
, 0, sizeof(*temp
));