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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
33 #include "alAuxEffectSlot.h"
36 enum Resampler DefaultResampler
= LinearResampler
;
37 const ALsizei ResamplerPadding
[ResamplerMax
] = {
42 const ALsizei ResamplerPrePadding
[ResamplerMax
] = {
49 static ALvoid
InitSourceParams(ALsource
*Source
);
50 static ALvoid
GetSourceOffsets(ALsource
*Source
, ALenum name
, ALdouble
*offsets
, ALdouble updateLen
);
51 static ALint
GetSampleOffset(ALsource
*Source
);
54 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
59 Context
= GetContextRef();
66 CHECK_VALUE(Context
, n
>= 0);
67 for(cur
= 0;cur
< n
;cur
++)
69 ALsource
*source
= calloc(1, sizeof(ALsource
));
71 al_throwerr(Context
, AL_OUT_OF_MEMORY
);
72 InitSourceParams(source
);
74 err
= NewThunkEntry(&source
->id
);
75 if(err
== AL_NO_ERROR
)
76 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->id
, source
);
77 if(err
!= AL_NO_ERROR
)
79 FreeThunkEntry(source
->id
);
80 memset(source
, 0, sizeof(ALsource
));
83 al_throwerr(Context
, err
);
86 sources
[cur
] = source
->id
;
92 alDeleteSources(cur
, sources
);
96 ALCcontext_DecRef(Context
);
100 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
104 Context
= GetContextRef();
109 ALbufferlistitem
*BufferList
;
113 CHECK_VALUE(Context
, n
>= 0);
115 /* Check that all Sources are valid */
118 if(LookupSource(Context
, sources
[i
]) == NULL
)
119 al_throwerr(Context
, AL_INVALID_NAME
);
124 ALsource
**srclist
, **srclistend
;
126 if((Source
=RemoveSource(Context
, sources
[i
])) == NULL
)
128 FreeThunkEntry(Source
->id
);
130 LockContext(Context
);
131 srclist
= Context
->ActiveSources
;
132 srclistend
= srclist
+ Context
->ActiveSourceCount
;
133 while(srclist
!= srclistend
)
135 if(*srclist
== Source
)
137 Context
->ActiveSourceCount
--;
138 *srclist
= *(--srclistend
);
143 UnlockContext(Context
);
145 while(Source
->queue
!= NULL
)
147 BufferList
= Source
->queue
;
148 Source
->queue
= BufferList
->next
;
150 if(BufferList
->buffer
!= NULL
)
151 DecrementRef(&BufferList
->buffer
->ref
);
155 for(j
= 0;j
< MAX_SENDS
;++j
)
157 if(Source
->Send
[j
].Slot
)
158 DecrementRef(&Source
->Send
[j
].Slot
->ref
);
159 Source
->Send
[j
].Slot
= NULL
;
162 memset(Source
, 0, sizeof(*Source
));
168 ALCcontext_DecRef(Context
);
172 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
177 Context
= GetContextRef();
178 if(!Context
) return AL_FALSE
;
180 result
= (LookupSource(Context
, source
) ? AL_TRUE
: AL_FALSE
);
182 ALCcontext_DecRef(Context
);
188 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
193 Context
= GetContextRef();
198 if((Source
=LookupSource(Context
, source
)) == NULL
)
199 al_throwerr(Context
, AL_INVALID_NAME
);
203 CHECK_VALUE(Context
, value
>= 0.0f
);
205 Source
->Pitch
= value
;
206 Source
->NeedsUpdate
= AL_TRUE
;
209 case AL_CONE_INNER_ANGLE
:
210 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 360.0f
);
212 Source
->InnerAngle
= value
;
213 Source
->NeedsUpdate
= AL_TRUE
;
216 case AL_CONE_OUTER_ANGLE
:
217 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 360.0f
);
219 Source
->OuterAngle
= value
;
220 Source
->NeedsUpdate
= AL_TRUE
;
224 CHECK_VALUE(Context
, value
>= 0.0f
);
226 Source
->Gain
= value
;
227 Source
->NeedsUpdate
= AL_TRUE
;
230 case AL_MAX_DISTANCE
:
231 CHECK_VALUE(Context
, value
>= 0.0f
);
233 Source
->MaxDistance
= value
;
234 Source
->NeedsUpdate
= AL_TRUE
;
237 case AL_ROLLOFF_FACTOR
:
238 CHECK_VALUE(Context
, value
>= 0.0f
);
240 Source
->RollOffFactor
= value
;
241 Source
->NeedsUpdate
= AL_TRUE
;
244 case AL_REFERENCE_DISTANCE
:
245 CHECK_VALUE(Context
, value
>= 0.0f
);
247 Source
->RefDistance
= value
;
248 Source
->NeedsUpdate
= AL_TRUE
;
252 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
254 Source
->MinGain
= value
;
255 Source
->NeedsUpdate
= AL_TRUE
;
259 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
261 Source
->MaxGain
= value
;
262 Source
->NeedsUpdate
= AL_TRUE
;
265 case AL_CONE_OUTER_GAIN
:
266 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
268 Source
->OuterGain
= value
;
269 Source
->NeedsUpdate
= AL_TRUE
;
272 case AL_CONE_OUTER_GAINHF
:
273 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
275 Source
->OuterGainHF
= value
;
276 Source
->NeedsUpdate
= AL_TRUE
;
279 case AL_AIR_ABSORPTION_FACTOR
:
280 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 10.0f
);
282 Source
->AirAbsorptionFactor
= value
;
283 Source
->NeedsUpdate
= AL_TRUE
;
286 case AL_ROOM_ROLLOFF_FACTOR
:
287 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 10.0f
);
289 Source
->RoomRolloffFactor
= value
;
290 Source
->NeedsUpdate
= AL_TRUE
;
293 case AL_DOPPLER_FACTOR
:
294 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
296 Source
->DopplerFactor
= value
;
297 Source
->NeedsUpdate
= AL_TRUE
;
301 case AL_SAMPLE_OFFSET
:
303 CHECK_VALUE(Context
, value
>= 0.0f
);
305 LockContext(Context
);
306 Source
->OffsetType
= param
;
307 Source
->Offset
= value
;
309 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
310 !Context
->DeferUpdates
)
312 if(ApplyOffset(Source
) == AL_FALSE
)
314 UnlockContext(Context
);
315 al_throwerr(Context
, AL_INVALID_VALUE
);
318 UnlockContext(Context
);
322 al_throwerr(Context
, AL_INVALID_ENUM
);
327 ALCcontext_DecRef(Context
);
331 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
336 Context
= GetContextRef();
341 if((Source
=LookupSource(Context
, source
)) == NULL
)
342 al_throwerr(Context
, AL_INVALID_NAME
);
346 CHECK_VALUE(Context
, isfinite(value1
) && isfinite(value2
) && isfinite(value3
));
348 LockContext(Context
);
349 Source
->Position
[0] = value1
;
350 Source
->Position
[1] = value2
;
351 Source
->Position
[2] = value3
;
352 UnlockContext(Context
);
353 Source
->NeedsUpdate
= AL_TRUE
;
357 CHECK_VALUE(Context
, isfinite(value1
) && isfinite(value2
) && isfinite(value3
));
359 LockContext(Context
);
360 Source
->Velocity
[0] = value1
;
361 Source
->Velocity
[1] = value2
;
362 Source
->Velocity
[2] = value3
;
363 UnlockContext(Context
);
364 Source
->NeedsUpdate
= AL_TRUE
;
368 CHECK_VALUE(Context
, isfinite(value1
) && isfinite(value2
) && isfinite(value3
));
370 LockContext(Context
);
371 Source
->Orientation
[0] = value1
;
372 Source
->Orientation
[1] = value2
;
373 Source
->Orientation
[2] = value3
;
374 UnlockContext(Context
);
375 Source
->NeedsUpdate
= AL_TRUE
;
379 al_throwerr(Context
, AL_INVALID_ENUM
);
384 ALCcontext_DecRef(Context
);
388 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
397 case AL_CONE_INNER_ANGLE
:
398 case AL_CONE_OUTER_ANGLE
:
400 case AL_MAX_DISTANCE
:
401 case AL_ROLLOFF_FACTOR
:
402 case AL_REFERENCE_DISTANCE
:
405 case AL_CONE_OUTER_GAIN
:
406 case AL_CONE_OUTER_GAINHF
:
408 case AL_SAMPLE_OFFSET
:
410 case AL_AIR_ABSORPTION_FACTOR
:
411 case AL_ROOM_ROLLOFF_FACTOR
:
412 alSourcef(source
, param
, values
[0]);
418 alSource3f(source
, param
, values
[0], values
[1], values
[2]);
423 Context
= GetContextRef();
428 if(LookupSource(Context
, source
) == NULL
)
429 al_throwerr(Context
, AL_INVALID_NAME
);
430 CHECK_VALUE(Context
, values
);
435 al_throwerr(Context
, AL_INVALID_ENUM
);
440 ALCcontext_DecRef(Context
);
444 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
451 case AL_MAX_DISTANCE
:
452 case AL_ROLLOFF_FACTOR
:
453 case AL_CONE_INNER_ANGLE
:
454 case AL_CONE_OUTER_ANGLE
:
455 case AL_REFERENCE_DISTANCE
:
456 alSourcef(source
, param
, (ALfloat
)value
);
460 Context
= GetContextRef();
465 ALCdevice
*device
= Context
->Device
;
466 ALbuffer
*buffer
= NULL
;
467 ALfilter
*filter
= NULL
;
468 ALbufferlistitem
*oldlist
;
470 if((Source
=LookupSource(Context
, source
)) == NULL
)
471 al_throwerr(Context
, AL_INVALID_NAME
);
474 case AL_SOURCE_RELATIVE
:
475 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
477 Source
->HeadRelative
= (ALboolean
)value
;
478 Source
->NeedsUpdate
= AL_TRUE
;
482 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
484 Source
->Looping
= (ALboolean
)value
;
488 CHECK_VALUE(Context
, value
== 0 ||
489 (buffer
=LookupBuffer(device
, value
)) != NULL
);
491 LockContext(Context
);
492 if(!(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
))
494 UnlockContext(Context
);
495 al_throwerr(Context
, AL_INVALID_OPERATION
);
498 Source
->BuffersInQueue
= 0;
499 Source
->BuffersPlayed
= 0;
503 ALbufferlistitem
*BufferListItem
;
505 /* Source is now Static */
506 Source
->SourceType
= AL_STATIC
;
508 /* Add the selected buffer to a one-item queue */
509 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
510 BufferListItem
->buffer
= buffer
;
511 BufferListItem
->next
= NULL
;
512 BufferListItem
->prev
= NULL
;
513 IncrementRef(&buffer
->ref
);
515 oldlist
= ExchangePtr((XchgPtr
*)&Source
->queue
, BufferListItem
);
516 Source
->BuffersInQueue
= 1;
518 ReadLock(&buffer
->lock
);
519 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
520 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
521 ReadUnlock(&buffer
->lock
);
522 if(buffer
->FmtChannels
== FmtMono
)
523 Source
->Update
= CalcSourceParams
;
525 Source
->Update
= CalcNonAttnSourceParams
;
526 Source
->NeedsUpdate
= AL_TRUE
;
530 /* Source is now Undetermined */
531 Source
->SourceType
= AL_UNDETERMINED
;
532 oldlist
= ExchangePtr((XchgPtr
*)&Source
->queue
, NULL
);
535 /* Delete all elements in the previous queue */
536 while(oldlist
!= NULL
)
538 ALbufferlistitem
*temp
= oldlist
;
539 oldlist
= temp
->next
;
542 DecrementRef(&temp
->buffer
->ref
);
545 UnlockContext(Context
);
548 case AL_SOURCE_STATE
:
550 al_throwerr(Context
, AL_INVALID_OPERATION
);
553 case AL_SAMPLE_OFFSET
:
555 CHECK_VALUE(Context
, value
>= 0);
557 LockContext(Context
);
558 Source
->OffsetType
= param
;
559 Source
->Offset
= value
;
561 if((Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
) &&
562 !Context
->DeferUpdates
)
564 if(ApplyOffset(Source
) == AL_FALSE
)
566 UnlockContext(Context
);
567 al_throwerr(Context
, AL_INVALID_VALUE
);
570 UnlockContext(Context
);
573 case AL_DIRECT_FILTER
:
574 CHECK_VALUE(Context
, value
== 0 ||
575 (filter
=LookupFilter(device
, value
)) != NULL
);
577 LockContext(Context
);
580 Source
->DirectGain
= 1.0f
;
581 Source
->DirectGainHF
= 1.0f
;
585 Source
->DirectGain
= filter
->Gain
;
586 Source
->DirectGainHF
= filter
->GainHF
;
588 UnlockContext(Context
);
589 Source
->NeedsUpdate
= AL_TRUE
;
592 case AL_DIRECT_FILTER_GAINHF_AUTO
:
593 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
595 Source
->DryGainHFAuto
= value
;
596 Source
->NeedsUpdate
= AL_TRUE
;
599 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
600 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
602 Source
->WetGainAuto
= value
;
603 Source
->NeedsUpdate
= AL_TRUE
;
606 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
607 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
609 Source
->WetGainHFAuto
= value
;
610 Source
->NeedsUpdate
= AL_TRUE
;
613 case AL_DIRECT_CHANNELS_SOFT
:
614 CHECK_VALUE(Context
, value
== AL_FALSE
|| value
== AL_TRUE
);
616 Source
->DirectChannels
= value
;
617 Source
->NeedsUpdate
= AL_TRUE
;
620 case AL_DISTANCE_MODEL
:
621 CHECK_VALUE(Context
, value
== AL_NONE
||
622 value
== AL_INVERSE_DISTANCE
||
623 value
== AL_INVERSE_DISTANCE_CLAMPED
||
624 value
== AL_LINEAR_DISTANCE
||
625 value
== AL_LINEAR_DISTANCE_CLAMPED
||
626 value
== AL_EXPONENT_DISTANCE
||
627 value
== AL_EXPONENT_DISTANCE_CLAMPED
);
629 Source
->DistanceModel
= value
;
630 if(Context
->SourceDistanceModel
)
631 Source
->NeedsUpdate
= AL_TRUE
;
635 al_throwerr(Context
, AL_INVALID_ENUM
);
640 ALCcontext_DecRef(Context
);
644 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
654 alSource3f(source
, param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
658 Context
= GetContextRef();
663 ALCdevice
*device
= Context
->Device
;
664 ALeffectslot
*slot
= NULL
;
665 ALfilter
*filter
= NULL
;
667 if((Source
=LookupSource(Context
, source
)) == NULL
)
668 al_throwerr(Context
, AL_INVALID_NAME
);
671 case AL_AUXILIARY_SEND_FILTER
:
672 LockContext(Context
);
673 if(!((ALuint
)value2
< device
->NumAuxSends
&&
674 (value1
== 0 || (slot
=LookupEffectSlot(Context
, value1
)) != NULL
) &&
675 (value3
== 0 || (filter
=LookupFilter(device
, value3
)) != NULL
)))
677 UnlockContext(Context
);
678 al_throwerr(Context
, AL_INVALID_VALUE
);
681 /* Add refcount on the new slot, and release the previous slot */
682 if(slot
) IncrementRef(&slot
->ref
);
683 slot
= ExchangePtr((XchgPtr
*)&Source
->Send
[value2
].Slot
, slot
);
684 if(slot
) DecrementRef(&slot
->ref
);
689 Source
->Send
[value2
].Gain
= 1.0f
;
690 Source
->Send
[value2
].GainHF
= 1.0f
;
694 Source
->Send
[value2
].Gain
= filter
->Gain
;
695 Source
->Send
[value2
].GainHF
= filter
->GainHF
;
697 Source
->NeedsUpdate
= AL_TRUE
;
698 UnlockContext(Context
);
702 al_throwerr(Context
, AL_INVALID_ENUM
);
707 ALCcontext_DecRef(Context
);
711 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
719 case AL_SOURCE_RELATIVE
:
720 case AL_CONE_INNER_ANGLE
:
721 case AL_CONE_OUTER_ANGLE
:
724 case AL_SOURCE_STATE
:
726 case AL_SAMPLE_OFFSET
:
728 case AL_MAX_DISTANCE
:
729 case AL_ROLLOFF_FACTOR
:
730 case AL_REFERENCE_DISTANCE
:
731 case AL_DIRECT_FILTER
:
732 case AL_DIRECT_FILTER_GAINHF_AUTO
:
733 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
734 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
735 case AL_DISTANCE_MODEL
:
736 case AL_DIRECT_CHANNELS_SOFT
:
737 alSourcei(source
, param
, values
[0]);
743 case AL_AUXILIARY_SEND_FILTER
:
744 alSource3i(source
, param
, values
[0], values
[1], values
[2]);
749 Context
= GetContextRef();
754 if(LookupSource(Context
, source
) == NULL
)
755 al_throwerr(Context
, AL_INVALID_NAME
);
756 CHECK_VALUE(Context
, values
);
760 al_throwerr(Context
, AL_INVALID_ENUM
);
765 ALCcontext_DecRef(Context
);
769 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
776 Context
= GetContextRef();
781 if((Source
=LookupSource(Context
, source
)) == NULL
)
782 al_throwerr(Context
, AL_INVALID_NAME
);
783 CHECK_VALUE(Context
, value
);
787 *value
= Source
->Pitch
;
791 *value
= Source
->Gain
;
795 *value
= Source
->MinGain
;
799 *value
= Source
->MaxGain
;
802 case AL_MAX_DISTANCE
:
803 *value
= Source
->MaxDistance
;
806 case AL_ROLLOFF_FACTOR
:
807 *value
= Source
->RollOffFactor
;
810 case AL_CONE_OUTER_GAIN
:
811 *value
= Source
->OuterGain
;
814 case AL_CONE_OUTER_GAINHF
:
815 *value
= Source
->OuterGainHF
;
819 case AL_SAMPLE_OFFSET
:
821 LockContext(Context
);
822 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
823 Context
->Device
->Frequency
;
824 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
825 UnlockContext(Context
);
826 *value
= (ALfloat
)offsets
[0];
829 case AL_CONE_INNER_ANGLE
:
830 *value
= Source
->InnerAngle
;
833 case AL_CONE_OUTER_ANGLE
:
834 *value
= Source
->OuterAngle
;
837 case AL_REFERENCE_DISTANCE
:
838 *value
= Source
->RefDistance
;
841 case AL_AIR_ABSORPTION_FACTOR
:
842 *value
= Source
->AirAbsorptionFactor
;
845 case AL_ROOM_ROLLOFF_FACTOR
:
846 *value
= Source
->RoomRolloffFactor
;
849 case AL_DOPPLER_FACTOR
:
850 *value
= Source
->DopplerFactor
;
854 al_throwerr(Context
, AL_INVALID_ENUM
);
859 ALCcontext_DecRef(Context
);
863 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
868 Context
= GetContextRef();
873 if((Source
=LookupSource(Context
, source
)) == NULL
)
874 al_throwerr(Context
, AL_INVALID_NAME
);
875 CHECK_VALUE(Context
, value1
&& value2
&& value3
);
879 LockContext(Context
);
880 *value1
= Source
->Position
[0];
881 *value2
= Source
->Position
[1];
882 *value3
= Source
->Position
[2];
883 UnlockContext(Context
);
887 LockContext(Context
);
888 *value1
= Source
->Velocity
[0];
889 *value2
= Source
->Velocity
[1];
890 *value3
= Source
->Velocity
[2];
891 UnlockContext(Context
);
895 LockContext(Context
);
896 *value1
= Source
->Orientation
[0];
897 *value2
= Source
->Orientation
[1];
898 *value3
= Source
->Orientation
[2];
899 UnlockContext(Context
);
903 al_throwerr(Context
, AL_INVALID_ENUM
);
908 ALCcontext_DecRef(Context
);
912 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
925 case AL_MAX_DISTANCE
:
926 case AL_ROLLOFF_FACTOR
:
927 case AL_DOPPLER_FACTOR
:
928 case AL_CONE_OUTER_GAIN
:
930 case AL_SAMPLE_OFFSET
:
932 case AL_CONE_INNER_ANGLE
:
933 case AL_CONE_OUTER_ANGLE
:
934 case AL_REFERENCE_DISTANCE
:
935 case AL_CONE_OUTER_GAINHF
:
936 case AL_AIR_ABSORPTION_FACTOR
:
937 case AL_ROOM_ROLLOFF_FACTOR
:
938 alGetSourcef(source
, param
, values
);
944 alGetSource3f(source
, param
, values
+0, values
+1, values
+2);
948 Context
= GetContextRef();
953 if((Source
=LookupSource(Context
, source
)) == NULL
)
954 al_throwerr(Context
, AL_INVALID_NAME
);
955 CHECK_VALUE(Context
, values
);
958 case AL_SAMPLE_RW_OFFSETS_SOFT
:
959 case AL_BYTE_RW_OFFSETS_SOFT
:
960 LockContext(Context
);
961 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
962 Context
->Device
->Frequency
;
963 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
964 UnlockContext(Context
);
965 values
[0] = (ALfloat
)offsets
[0];
966 values
[1] = (ALfloat
)offsets
[1];
970 al_throwerr(Context
, AL_INVALID_ENUM
);
975 ALCcontext_DecRef(Context
);
979 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
981 ALbufferlistitem
*BufferList
;
987 Context
= GetContextRef();
992 if((Source
=LookupSource(Context
, source
)) == NULL
)
993 al_throwerr(Context
, AL_INVALID_NAME
);
994 CHECK_VALUE(Context
, value
);
997 case AL_MAX_DISTANCE
:
998 *value
= (ALint
)Source
->MaxDistance
;
1001 case AL_ROLLOFF_FACTOR
:
1002 *value
= (ALint
)Source
->RollOffFactor
;
1005 case AL_REFERENCE_DISTANCE
:
1006 *value
= (ALint
)Source
->RefDistance
;
1009 case AL_SOURCE_RELATIVE
:
1010 *value
= Source
->HeadRelative
;
1013 case AL_CONE_INNER_ANGLE
:
1014 *value
= (ALint
)Source
->InnerAngle
;
1017 case AL_CONE_OUTER_ANGLE
:
1018 *value
= (ALint
)Source
->OuterAngle
;
1022 *value
= Source
->Looping
;
1026 LockContext(Context
);
1027 BufferList
= Source
->queue
;
1028 if(Source
->SourceType
!= AL_STATIC
)
1030 ALuint i
= Source
->BuffersPlayed
;
1033 BufferList
= BufferList
->next
;
1037 *value
= ((BufferList
&& BufferList
->buffer
) ?
1038 BufferList
->buffer
->id
: 0);
1039 UnlockContext(Context
);
1042 case AL_SOURCE_STATE
:
1043 *value
= Source
->state
;
1046 case AL_BUFFERS_QUEUED
:
1047 *value
= Source
->BuffersInQueue
;
1050 case AL_BUFFERS_PROCESSED
:
1051 LockContext(Context
);
1052 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1054 /* Buffers on a looping source are in a perpetual state of
1055 * PENDING, so don't report any as PROCESSED */
1059 *value
= Source
->BuffersPlayed
;
1060 UnlockContext(Context
);
1063 case AL_SOURCE_TYPE
:
1064 *value
= Source
->SourceType
;
1068 case AL_SAMPLE_OFFSET
:
1069 case AL_BYTE_OFFSET
:
1070 LockContext(Context
);
1071 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
1072 Context
->Device
->Frequency
;
1073 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
1074 UnlockContext(Context
);
1075 *value
= (ALint
)offsets
[0];
1078 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1079 *value
= Source
->DryGainHFAuto
;
1082 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1083 *value
= Source
->WetGainAuto
;
1086 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1087 *value
= Source
->WetGainHFAuto
;
1090 case AL_DOPPLER_FACTOR
:
1091 *value
= (ALint
)Source
->DopplerFactor
;
1094 case AL_DIRECT_CHANNELS_SOFT
:
1095 *value
= Source
->DirectChannels
;
1098 case AL_DISTANCE_MODEL
:
1099 *value
= Source
->DistanceModel
;
1103 al_throwerr(Context
, AL_INVALID_ENUM
);
1108 ALCcontext_DecRef(Context
);
1112 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
1114 ALCcontext
*Context
;
1117 Context
= GetContextRef();
1118 if(!Context
) return;
1122 if((Source
=LookupSource(Context
, source
)) == NULL
)
1123 al_throwerr(Context
, AL_INVALID_NAME
);
1124 CHECK_VALUE(Context
, value1
&& value2
&& value3
);
1128 LockContext(Context
);
1129 *value1
= (ALint
)Source
->Position
[0];
1130 *value2
= (ALint
)Source
->Position
[1];
1131 *value3
= (ALint
)Source
->Position
[2];
1132 UnlockContext(Context
);
1136 LockContext(Context
);
1137 *value1
= (ALint
)Source
->Velocity
[0];
1138 *value2
= (ALint
)Source
->Velocity
[1];
1139 *value3
= (ALint
)Source
->Velocity
[2];
1140 UnlockContext(Context
);
1144 LockContext(Context
);
1145 *value1
= (ALint
)Source
->Orientation
[0];
1146 *value2
= (ALint
)Source
->Orientation
[1];
1147 *value3
= (ALint
)Source
->Orientation
[2];
1148 UnlockContext(Context
);
1152 al_throwerr(Context
, AL_INVALID_ENUM
);
1157 ALCcontext_DecRef(Context
);
1161 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
1163 ALCcontext
*Context
;
1165 ALdouble offsets
[2];
1170 case AL_SOURCE_RELATIVE
:
1171 case AL_CONE_INNER_ANGLE
:
1172 case AL_CONE_OUTER_ANGLE
:
1175 case AL_SOURCE_STATE
:
1176 case AL_BUFFERS_QUEUED
:
1177 case AL_BUFFERS_PROCESSED
:
1179 case AL_SAMPLE_OFFSET
:
1180 case AL_BYTE_OFFSET
:
1181 case AL_MAX_DISTANCE
:
1182 case AL_ROLLOFF_FACTOR
:
1183 case AL_DOPPLER_FACTOR
:
1184 case AL_REFERENCE_DISTANCE
:
1185 case AL_SOURCE_TYPE
:
1186 case AL_DIRECT_FILTER
:
1187 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1188 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1189 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1190 case AL_DISTANCE_MODEL
:
1191 case AL_DIRECT_CHANNELS_SOFT
:
1192 alGetSourcei(source
, param
, values
);
1198 alGetSource3i(source
, param
, values
+0, values
+1, values
+2);
1202 Context
= GetContextRef();
1203 if(!Context
) return;
1207 if((Source
=LookupSource(Context
, source
)) == NULL
)
1208 al_throwerr(Context
, AL_INVALID_NAME
);
1209 CHECK_VALUE(Context
, values
);
1212 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1213 case AL_BYTE_RW_OFFSETS_SOFT
:
1214 LockContext(Context
);
1215 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
1216 Context
->Device
->Frequency
;
1217 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
1218 UnlockContext(Context
);
1219 values
[0] = (ALint
)offsets
[0];
1220 values
[1] = (ALint
)offsets
[1];
1224 al_throwerr(Context
, AL_INVALID_ENUM
);
1229 ALCcontext_DecRef(Context
);
1233 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1235 alSourcePlayv(1, &source
);
1237 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1239 ALCcontext
*Context
;
1243 Context
= GetContextRef();
1244 if(!Context
) return;
1248 CHECK_VALUE(Context
, n
>= 0);
1249 for(i
= 0;i
< n
;i
++)
1251 if(!LookupSource(Context
, sources
[i
]))
1252 al_throwerr(Context
, AL_INVALID_NAME
);
1255 LockContext(Context
);
1256 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1261 newcount
= Context
->MaxActiveSources
<< 1;
1263 temp
= realloc(Context
->ActiveSources
,
1264 sizeof(*Context
->ActiveSources
) * newcount
);
1267 UnlockContext(Context
);
1268 al_throwerr(Context
, AL_OUT_OF_MEMORY
);
1271 Context
->ActiveSources
= temp
;
1272 Context
->MaxActiveSources
= newcount
;
1275 for(i
= 0;i
< n
;i
++)
1277 Source
= LookupSource(Context
, sources
[i
]);
1278 if(Context
->DeferUpdates
) Source
->new_state
= AL_PLAYING
;
1279 else SetSourceState(Source
, Context
, AL_PLAYING
);
1281 UnlockContext(Context
);
1285 ALCcontext_DecRef(Context
);
1288 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1290 alSourcePausev(1, &source
);
1292 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1294 ALCcontext
*Context
;
1298 Context
= GetContextRef();
1299 if(!Context
) return;
1303 CHECK_VALUE(Context
, n
>= 0);
1304 for(i
= 0;i
< n
;i
++)
1306 if(!LookupSource(Context
, sources
[i
]))
1307 al_throwerr(Context
, AL_INVALID_NAME
);
1310 LockContext(Context
);
1311 for(i
= 0;i
< n
;i
++)
1313 Source
= LookupSource(Context
, sources
[i
]);
1314 if(Context
->DeferUpdates
) Source
->new_state
= AL_PAUSED
;
1315 else SetSourceState(Source
, Context
, AL_PAUSED
);
1317 UnlockContext(Context
);
1321 ALCcontext_DecRef(Context
);
1324 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1326 alSourceStopv(1, &source
);
1328 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1330 ALCcontext
*Context
;
1334 Context
= GetContextRef();
1335 if(!Context
) return;
1339 CHECK_VALUE(Context
, n
>= 0);
1340 for(i
= 0;i
< n
;i
++)
1342 if(!LookupSource(Context
, sources
[i
]))
1343 al_throwerr(Context
, AL_INVALID_NAME
);
1346 LockContext(Context
);
1347 for(i
= 0;i
< n
;i
++)
1349 Source
= LookupSource(Context
, sources
[i
]);
1350 Source
->new_state
= AL_NONE
;
1351 SetSourceState(Source
, Context
, AL_STOPPED
);
1353 UnlockContext(Context
);
1357 ALCcontext_DecRef(Context
);
1360 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1362 alSourceRewindv(1, &source
);
1364 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1366 ALCcontext
*Context
;
1370 Context
= GetContextRef();
1371 if(!Context
) return;
1375 CHECK_VALUE(Context
, n
>= 0);
1376 for(i
= 0;i
< n
;i
++)
1378 if(!LookupSource(Context
, sources
[i
]))
1379 al_throwerr(Context
, AL_INVALID_NAME
);
1382 LockContext(Context
);
1383 for(i
= 0;i
< n
;i
++)
1385 Source
= LookupSource(Context
, sources
[i
]);
1386 Source
->new_state
= AL_NONE
;
1387 SetSourceState(Source
, Context
, AL_INITIAL
);
1389 UnlockContext(Context
);
1393 ALCcontext_DecRef(Context
);
1397 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei nb
, const ALuint
*buffers
)
1399 ALCcontext
*Context
;
1402 ALbufferlistitem
*BufferListStart
= NULL
;
1403 ALbufferlistitem
*BufferList
;
1404 ALbuffer
*BufferFmt
;
1409 Context
= GetContextRef();
1410 if(!Context
) return;
1414 ALCdevice
*device
= Context
->Device
;
1416 CHECK_VALUE(Context
, nb
>= 0);
1418 if((Source
=LookupSource(Context
, source
)) == NULL
)
1419 al_throwerr(Context
, AL_INVALID_NAME
);
1421 LockContext(Context
);
1422 if(Source
->SourceType
== AL_STATIC
)
1424 UnlockContext(Context
);
1425 /* Can't queue on a Static Source */
1426 al_throwerr(Context
, AL_INVALID_OPERATION
);
1431 /* Check for a valid Buffer, for its frequency and format */
1432 BufferList
= Source
->queue
;
1435 if(BufferList
->buffer
)
1437 BufferFmt
= BufferList
->buffer
;
1440 BufferList
= BufferList
->next
;
1443 for(i
= 0;i
< nb
;i
++)
1445 ALbuffer
*buffer
= NULL
;
1446 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
1448 UnlockContext(Context
);
1449 al_throwerr(Context
, AL_INVALID_NAME
);
1452 if(!BufferListStart
)
1454 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1455 BufferListStart
->buffer
= buffer
;
1456 BufferListStart
->next
= NULL
;
1457 BufferListStart
->prev
= NULL
;
1458 BufferList
= BufferListStart
;
1462 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1463 BufferList
->next
->buffer
= buffer
;
1464 BufferList
->next
->next
= NULL
;
1465 BufferList
->next
->prev
= BufferList
;
1466 BufferList
= BufferList
->next
;
1468 if(!buffer
) continue;
1469 IncrementRef(&buffer
->ref
);
1471 ReadLock(&buffer
->lock
);
1472 if(BufferFmt
== NULL
)
1476 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
1477 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
1478 if(buffer
->FmtChannels
== FmtMono
)
1479 Source
->Update
= CalcSourceParams
;
1481 Source
->Update
= CalcNonAttnSourceParams
;
1483 Source
->NeedsUpdate
= AL_TRUE
;
1485 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
1486 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
1487 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
1489 ReadUnlock(&buffer
->lock
);
1490 UnlockContext(Context
);
1491 al_throwerr(Context
, AL_INVALID_OPERATION
);
1493 ReadUnlock(&buffer
->lock
);
1496 /* Source is now streaming */
1497 Source
->SourceType
= AL_STREAMING
;
1499 if(Source
->queue
== NULL
)
1500 Source
->queue
= BufferListStart
;
1503 /* Append to the end of the queue */
1504 BufferList
= Source
->queue
;
1505 while(BufferList
->next
!= NULL
)
1506 BufferList
= BufferList
->next
;
1508 BufferListStart
->prev
= BufferList
;
1509 BufferList
->next
= BufferListStart
;
1512 Source
->BuffersInQueue
+= nb
;
1514 UnlockContext(Context
);
1518 while(BufferListStart
)
1520 BufferList
= BufferListStart
;
1521 BufferListStart
= BufferList
->next
;
1523 if(BufferList
->buffer
)
1524 DecrementRef(&BufferList
->buffer
->ref
);
1530 ALCcontext_DecRef(Context
);
1533 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint source
, ALsizei nb
, ALuint
*buffers
)
1535 ALCcontext
*Context
;
1538 ALbufferlistitem
*BufferList
;
1543 Context
= GetContextRef();
1544 if(!Context
) return;
1548 CHECK_VALUE(Context
, nb
>= 0);
1550 if((Source
=LookupSource(Context
, source
)) == NULL
)
1551 al_throwerr(Context
, AL_INVALID_NAME
);
1553 LockContext(Context
);
1554 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
||
1555 (ALuint
)nb
> Source
->BuffersPlayed
)
1557 UnlockContext(Context
);
1558 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1559 al_throwerr(Context
, AL_INVALID_VALUE
);
1562 for(i
= 0;i
< nb
;i
++)
1564 BufferList
= Source
->queue
;
1565 Source
->queue
= BufferList
->next
;
1566 Source
->BuffersInQueue
--;
1567 Source
->BuffersPlayed
--;
1569 if(BufferList
->buffer
)
1571 buffers
[i
] = BufferList
->buffer
->id
;
1572 DecrementRef(&BufferList
->buffer
->ref
);
1580 Source
->queue
->prev
= NULL
;
1581 UnlockContext(Context
);
1585 ALCcontext_DecRef(Context
);
1589 static ALvoid
InitSourceParams(ALsource
*Source
)
1593 Source
->InnerAngle
= 360.0f
;
1594 Source
->OuterAngle
= 360.0f
;
1595 Source
->Pitch
= 1.0f
;
1596 Source
->Position
[0] = 0.0f
;
1597 Source
->Position
[1] = 0.0f
;
1598 Source
->Position
[2] = 0.0f
;
1599 Source
->Orientation
[0] = 0.0f
;
1600 Source
->Orientation
[1] = 0.0f
;
1601 Source
->Orientation
[2] = 0.0f
;
1602 Source
->Velocity
[0] = 0.0f
;
1603 Source
->Velocity
[1] = 0.0f
;
1604 Source
->Velocity
[2] = 0.0f
;
1605 Source
->RefDistance
= 1.0f
;
1606 Source
->MaxDistance
= FLT_MAX
;
1607 Source
->RollOffFactor
= 1.0f
;
1608 Source
->Looping
= AL_FALSE
;
1609 Source
->Gain
= 1.0f
;
1610 Source
->MinGain
= 0.0f
;
1611 Source
->MaxGain
= 1.0f
;
1612 Source
->OuterGain
= 0.0f
;
1613 Source
->OuterGainHF
= 1.0f
;
1615 Source
->DryGainHFAuto
= AL_TRUE
;
1616 Source
->WetGainAuto
= AL_TRUE
;
1617 Source
->WetGainHFAuto
= AL_TRUE
;
1618 Source
->AirAbsorptionFactor
= 0.0f
;
1619 Source
->RoomRolloffFactor
= 0.0f
;
1620 Source
->DopplerFactor
= 1.0f
;
1621 Source
->DirectChannels
= AL_FALSE
;
1623 Source
->DistanceModel
= DefaultDistanceModel
;
1625 Source
->Resampler
= DefaultResampler
;
1627 Source
->state
= AL_INITIAL
;
1628 Source
->new_state
= AL_NONE
;
1629 Source
->SourceType
= AL_UNDETERMINED
;
1630 Source
->Offset
= -1.0;
1632 Source
->DirectGain
= 1.0f
;
1633 Source
->DirectGainHF
= 1.0f
;
1634 for(i
= 0;i
< MAX_SENDS
;i
++)
1636 Source
->Send
[i
].Gain
= 1.0f
;
1637 Source
->Send
[i
].GainHF
= 1.0f
;
1640 Source
->NeedsUpdate
= AL_TRUE
;
1642 Source
->Hrtf
.Moving
= AL_FALSE
;
1643 Source
->Hrtf
.Counter
= 0;
1649 * Sets the source's new play state given its current state.
1651 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
1653 if(state
== AL_PLAYING
)
1655 ALbufferlistitem
*BufferList
;
1658 /* Check that there is a queue containing at least one valid, non zero
1660 BufferList
= Source
->queue
;
1663 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->SampleLen
)
1665 BufferList
= BufferList
->next
;
1668 if(Source
->state
!= AL_PLAYING
)
1670 for(j
= 0;j
< MAXCHANNELS
;j
++)
1672 for(k
= 0;k
< SRC_HISTORY_LENGTH
;k
++)
1673 Source
->Hrtf
.History
[j
][k
] = 0.0f
;
1674 for(k
= 0;k
< HRIR_LENGTH
;k
++)
1676 Source
->Hrtf
.Values
[j
][k
][0] = 0.0f
;
1677 Source
->Hrtf
.Values
[j
][k
][1] = 0.0f
;
1682 if(Source
->state
!= AL_PAUSED
)
1684 Source
->state
= AL_PLAYING
;
1685 Source
->position
= 0;
1686 Source
->position_fraction
= 0;
1687 Source
->BuffersPlayed
= 0;
1690 Source
->state
= AL_PLAYING
;
1692 // Check if an Offset has been set
1693 if(Source
->Offset
>= 0.0)
1694 ApplyOffset(Source
);
1696 /* If there's nothing to play, or device is disconnected, go right to
1698 if(!BufferList
|| !Context
->Device
->Connected
)
1700 SetSourceState(Source
, Context
, AL_STOPPED
);
1704 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1706 if(Context
->ActiveSources
[j
] == Source
)
1709 if(j
== Context
->ActiveSourceCount
)
1710 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1712 else if(state
== AL_PAUSED
)
1714 if(Source
->state
== AL_PLAYING
)
1716 Source
->state
= AL_PAUSED
;
1717 Source
->Hrtf
.Moving
= AL_FALSE
;
1718 Source
->Hrtf
.Counter
= 0;
1721 else if(state
== AL_STOPPED
)
1723 if(Source
->state
!= AL_INITIAL
)
1725 Source
->state
= AL_STOPPED
;
1726 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1727 Source
->Hrtf
.Moving
= AL_FALSE
;
1728 Source
->Hrtf
.Counter
= 0;
1730 Source
->Offset
= -1.0;
1732 else if(state
== AL_INITIAL
)
1734 if(Source
->state
!= AL_INITIAL
)
1736 Source
->state
= AL_INITIAL
;
1737 Source
->position
= 0;
1738 Source
->position_fraction
= 0;
1739 Source
->BuffersPlayed
= 0;
1740 Source
->Hrtf
.Moving
= AL_FALSE
;
1741 Source
->Hrtf
.Counter
= 0;
1743 Source
->Offset
= -1.0;
1749 * Gets the current read and write offsets for the given Source, in the
1750 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
1751 * the start of the queue (not the start of the current buffer).
1753 static ALvoid
GetSourceOffsets(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1755 const ALbufferlistitem
*BufferList
;
1756 const ALbuffer
*Buffer
= NULL
;
1757 ALuint readPos
, writePos
;
1758 ALuint totalBufferLen
;
1761 // Find the first valid Buffer in the Queue
1762 BufferList
= Source
->queue
;
1765 if(BufferList
->buffer
)
1767 Buffer
= BufferList
->buffer
;
1770 BufferList
= BufferList
->next
;
1773 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1780 if(updateLen
> 0.0 && updateLen
< 0.015)
1783 /* NOTE: This is the offset into the *current* buffer, so add the length of
1784 * any played buffers */
1785 readPos
= Source
->position
;
1787 BufferList
= Source
->queue
;
1788 for(i
= 0;BufferList
;i
++)
1790 if(BufferList
->buffer
)
1792 if(i
< Source
->BuffersPlayed
)
1793 readPos
+= BufferList
->buffer
->SampleLen
;
1794 totalBufferLen
+= BufferList
->buffer
->SampleLen
;
1796 BufferList
= BufferList
->next
;
1798 if(Source
->state
== AL_PLAYING
)
1799 writePos
= readPos
+ (ALuint
)(updateLen
*Buffer
->Frequency
);
1805 readPos
%= totalBufferLen
;
1806 writePos
%= totalBufferLen
;
1810 /* Wrap positions back to 0 */
1811 if(readPos
>= totalBufferLen
)
1813 if(writePos
>= totalBufferLen
)
1820 offset
[0] = (ALdouble
)readPos
/ Buffer
->Frequency
;
1821 offset
[1] = (ALdouble
)writePos
/ Buffer
->Frequency
;
1824 case AL_SAMPLE_OFFSET
:
1825 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1826 offset
[0] = (ALdouble
)readPos
;
1827 offset
[1] = (ALdouble
)writePos
;
1830 case AL_BYTE_OFFSET
:
1831 case AL_BYTE_RW_OFFSETS_SOFT
:
1832 if(Buffer
->OriginalType
== UserFmtIMA4
)
1834 ALuint BlockSize
= 36 * ChannelsFromFmt(Buffer
->FmtChannels
);
1835 ALuint FrameBlockSize
= 65;
1837 /* Round down to nearest ADPCM block */
1838 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1839 if(Source
->state
!= AL_PLAYING
)
1840 offset
[1] = offset
[0];
1843 /* Round up to nearest ADPCM block */
1844 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1845 FrameBlockSize
* BlockSize
);
1850 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
1851 offset
[0] = (ALdouble
)(readPos
* FrameSize
);
1852 offset
[1] = (ALdouble
)(writePos
* FrameSize
);
1861 * Apply the stored playback offset to the Source. This function will update
1862 * the number of buffers "played" given the stored offset.
1864 ALboolean
ApplyOffset(ALsource
*Source
)
1866 const ALbufferlistitem
*BufferList
;
1867 const ALbuffer
*Buffer
;
1868 ALint bufferLen
, totalBufferLen
;
1869 ALint buffersPlayed
;
1872 /* Get sample frame offset */
1873 offset
= GetSampleOffset(Source
);
1880 BufferList
= Source
->queue
;
1883 Buffer
= BufferList
->buffer
;
1884 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
1886 if(bufferLen
<= offset
-totalBufferLen
)
1888 /* Offset is past this buffer so increment to the next buffer */
1891 else if(totalBufferLen
<= offset
)
1893 /* Offset is in this buffer */
1894 Source
->BuffersPlayed
= buffersPlayed
;
1896 Source
->position
= offset
- totalBufferLen
;
1897 Source
->position_fraction
= 0;
1901 totalBufferLen
+= bufferLen
;
1903 BufferList
= BufferList
->next
;
1906 /* Offset is out of range of the queue */
1913 * Returns the sample offset into the Source's queue (from the Sample, Byte or
1914 * Second offset supplied by the application). This takes into account the fact
1915 * that the buffer format may have been modifed since.
1917 static ALint
GetSampleOffset(ALsource
*Source
)
1919 const ALbuffer
*Buffer
= NULL
;
1920 const ALbufferlistitem
*BufferList
;
1923 /* Find the first valid Buffer in the Queue */
1924 BufferList
= Source
->queue
;
1927 if(BufferList
->buffer
)
1929 Buffer
= BufferList
->buffer
;
1932 BufferList
= BufferList
->next
;
1937 Source
->Offset
= -1.0;
1941 switch(Source
->OffsetType
)
1943 case AL_BYTE_OFFSET
:
1944 /* Determine the ByteOffset (and ensure it is block aligned) */
1945 Offset
= (ALint
)Source
->Offset
;
1946 if(Buffer
->OriginalType
== UserFmtIMA4
)
1948 Offset
/= 36 * ChannelsFromUserFmt(Buffer
->OriginalChannels
);
1952 Offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
1955 case AL_SAMPLE_OFFSET
:
1956 Offset
= (ALint
)Source
->Offset
;
1960 Offset
= (ALint
)(Source
->Offset
* Buffer
->Frequency
);
1963 Source
->Offset
= -1.0;
1971 * Destroys all sources in the source map.
1973 ALvoid
ReleaseALSources(ALCcontext
*Context
)
1977 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
1979 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
1980 Context
->SourceMap
.array
[pos
].value
= NULL
;
1982 while(temp
->queue
!= NULL
)
1984 ALbufferlistitem
*BufferList
= temp
->queue
;
1985 temp
->queue
= BufferList
->next
;
1987 if(BufferList
->buffer
!= NULL
)
1988 DecrementRef(&BufferList
->buffer
->ref
);
1992 for(j
= 0;j
< MAX_SENDS
;++j
)
1994 if(temp
->Send
[j
].Slot
)
1995 DecrementRef(&temp
->Send
[j
].Slot
->ref
);
1996 temp
->Send
[j
].Slot
= NULL
;
1999 FreeThunkEntry(temp
->id
);
2000 memset(temp
, 0, sizeof(*temp
));