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
].WetGain
= 1.0f
;
690 Source
->Send
[value2
].WetGainHF
= 1.0f
;
694 Source
->Send
[value2
].WetGain
= filter
->Gain
;
695 Source
->Send
[value2
].WetGainHF
= filter
->GainHF
;
697 Source
->NeedsUpdate
= AL_TRUE
;
698 UnlockContext(Context
);
702 alSetError(Context
, AL_INVALID_ENUM
);
708 ALCcontext_DecRef(Context
);
712 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
720 case AL_SOURCE_RELATIVE
:
721 case AL_CONE_INNER_ANGLE
:
722 case AL_CONE_OUTER_ANGLE
:
725 case AL_SOURCE_STATE
:
727 case AL_SAMPLE_OFFSET
:
729 case AL_MAX_DISTANCE
:
730 case AL_ROLLOFF_FACTOR
:
731 case AL_REFERENCE_DISTANCE
:
732 case AL_DIRECT_FILTER
:
733 case AL_DIRECT_FILTER_GAINHF_AUTO
:
734 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
735 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
736 case AL_DISTANCE_MODEL
:
737 case AL_DIRECT_CHANNELS_SOFT
:
738 alSourcei(source
, param
, values
[0]);
744 case AL_AUXILIARY_SEND_FILTER
:
745 alSource3i(source
, param
, values
[0], values
[1], values
[2]);
750 Context
= GetContextRef();
755 if(LookupSource(Context
, source
) == NULL
)
756 al_throwerr(Context
, AL_INVALID_NAME
);
757 CHECK_VALUE(Context
, values
);
761 al_throwerr(Context
, AL_INVALID_ENUM
);
766 ALCcontext_DecRef(Context
);
770 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
777 Context
= GetContextRef();
782 if((Source
=LookupSource(Context
, source
)) == NULL
)
783 al_throwerr(Context
, AL_INVALID_NAME
);
784 CHECK_VALUE(Context
, value
);
788 *value
= Source
->Pitch
;
792 *value
= Source
->Gain
;
796 *value
= Source
->MinGain
;
800 *value
= Source
->MaxGain
;
803 case AL_MAX_DISTANCE
:
804 *value
= Source
->MaxDistance
;
807 case AL_ROLLOFF_FACTOR
:
808 *value
= Source
->RollOffFactor
;
811 case AL_CONE_OUTER_GAIN
:
812 *value
= Source
->OuterGain
;
815 case AL_CONE_OUTER_GAINHF
:
816 *value
= Source
->OuterGainHF
;
820 case AL_SAMPLE_OFFSET
:
822 LockContext(Context
);
823 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
824 Context
->Device
->Frequency
;
825 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
826 UnlockContext(Context
);
827 *value
= (ALfloat
)offsets
[0];
830 case AL_CONE_INNER_ANGLE
:
831 *value
= Source
->InnerAngle
;
834 case AL_CONE_OUTER_ANGLE
:
835 *value
= Source
->OuterAngle
;
838 case AL_REFERENCE_DISTANCE
:
839 *value
= Source
->RefDistance
;
842 case AL_AIR_ABSORPTION_FACTOR
:
843 *value
= Source
->AirAbsorptionFactor
;
846 case AL_ROOM_ROLLOFF_FACTOR
:
847 *value
= Source
->RoomRolloffFactor
;
850 case AL_DOPPLER_FACTOR
:
851 *value
= Source
->DopplerFactor
;
855 al_throwerr(Context
, AL_INVALID_ENUM
);
860 ALCcontext_DecRef(Context
);
864 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
869 Context
= GetContextRef();
874 if((Source
=LookupSource(Context
, source
)) == NULL
)
875 al_throwerr(Context
, AL_INVALID_NAME
);
876 CHECK_VALUE(Context
, value1
&& value2
&& value3
);
880 LockContext(Context
);
881 *value1
= Source
->Position
[0];
882 *value2
= Source
->Position
[1];
883 *value3
= Source
->Position
[2];
884 UnlockContext(Context
);
888 LockContext(Context
);
889 *value1
= Source
->Velocity
[0];
890 *value2
= Source
->Velocity
[1];
891 *value3
= Source
->Velocity
[2];
892 UnlockContext(Context
);
896 LockContext(Context
);
897 *value1
= Source
->Orientation
[0];
898 *value2
= Source
->Orientation
[1];
899 *value3
= Source
->Orientation
[2];
900 UnlockContext(Context
);
904 al_throwerr(Context
, AL_INVALID_ENUM
);
909 ALCcontext_DecRef(Context
);
913 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
926 case AL_MAX_DISTANCE
:
927 case AL_ROLLOFF_FACTOR
:
928 case AL_DOPPLER_FACTOR
:
929 case AL_CONE_OUTER_GAIN
:
931 case AL_SAMPLE_OFFSET
:
933 case AL_CONE_INNER_ANGLE
:
934 case AL_CONE_OUTER_ANGLE
:
935 case AL_REFERENCE_DISTANCE
:
936 case AL_CONE_OUTER_GAINHF
:
937 case AL_AIR_ABSORPTION_FACTOR
:
938 case AL_ROOM_ROLLOFF_FACTOR
:
939 alGetSourcef(source
, param
, values
);
945 alGetSource3f(source
, param
, values
+0, values
+1, values
+2);
949 Context
= GetContextRef();
954 if((Source
=LookupSource(Context
, source
)) == NULL
)
955 al_throwerr(Context
, AL_INVALID_NAME
);
956 CHECK_VALUE(Context
, values
);
959 case AL_SAMPLE_RW_OFFSETS_SOFT
:
960 case AL_BYTE_RW_OFFSETS_SOFT
:
961 LockContext(Context
);
962 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
963 Context
->Device
->Frequency
;
964 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
965 UnlockContext(Context
);
966 values
[0] = (ALfloat
)offsets
[0];
967 values
[1] = (ALfloat
)offsets
[1];
971 al_throwerr(Context
, AL_INVALID_ENUM
);
976 ALCcontext_DecRef(Context
);
980 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
982 ALbufferlistitem
*BufferList
;
988 Context
= GetContextRef();
993 if((Source
=LookupSource(Context
, source
)) == NULL
)
994 al_throwerr(Context
, AL_INVALID_NAME
);
995 CHECK_VALUE(Context
, value
);
998 case AL_MAX_DISTANCE
:
999 *value
= (ALint
)Source
->MaxDistance
;
1002 case AL_ROLLOFF_FACTOR
:
1003 *value
= (ALint
)Source
->RollOffFactor
;
1006 case AL_REFERENCE_DISTANCE
:
1007 *value
= (ALint
)Source
->RefDistance
;
1010 case AL_SOURCE_RELATIVE
:
1011 *value
= Source
->HeadRelative
;
1014 case AL_CONE_INNER_ANGLE
:
1015 *value
= (ALint
)Source
->InnerAngle
;
1018 case AL_CONE_OUTER_ANGLE
:
1019 *value
= (ALint
)Source
->OuterAngle
;
1023 *value
= Source
->Looping
;
1027 LockContext(Context
);
1028 BufferList
= Source
->queue
;
1029 if(Source
->SourceType
!= AL_STATIC
)
1031 ALuint i
= Source
->BuffersPlayed
;
1034 BufferList
= BufferList
->next
;
1038 *value
= ((BufferList
&& BufferList
->buffer
) ?
1039 BufferList
->buffer
->id
: 0);
1040 UnlockContext(Context
);
1043 case AL_SOURCE_STATE
:
1044 *value
= Source
->state
;
1047 case AL_BUFFERS_QUEUED
:
1048 *value
= Source
->BuffersInQueue
;
1051 case AL_BUFFERS_PROCESSED
:
1052 LockContext(Context
);
1053 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1055 /* Buffers on a looping source are in a perpetual state of
1056 * PENDING, so don't report any as PROCESSED */
1060 *value
= Source
->BuffersPlayed
;
1061 UnlockContext(Context
);
1064 case AL_SOURCE_TYPE
:
1065 *value
= Source
->SourceType
;
1069 case AL_SAMPLE_OFFSET
:
1070 case AL_BYTE_OFFSET
:
1071 LockContext(Context
);
1072 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
1073 Context
->Device
->Frequency
;
1074 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
1075 UnlockContext(Context
);
1076 *value
= (ALint
)offsets
[0];
1079 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1080 *value
= Source
->DryGainHFAuto
;
1083 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1084 *value
= Source
->WetGainAuto
;
1087 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1088 *value
= Source
->WetGainHFAuto
;
1091 case AL_DOPPLER_FACTOR
:
1092 *value
= (ALint
)Source
->DopplerFactor
;
1095 case AL_DIRECT_CHANNELS_SOFT
:
1096 *value
= Source
->DirectChannels
;
1099 case AL_DISTANCE_MODEL
:
1100 *value
= Source
->DistanceModel
;
1104 al_throwerr(Context
, AL_INVALID_ENUM
);
1109 ALCcontext_DecRef(Context
);
1113 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
1115 ALCcontext
*Context
;
1118 Context
= GetContextRef();
1119 if(!Context
) return;
1123 if((Source
=LookupSource(Context
, source
)) == NULL
)
1124 al_throwerr(Context
, AL_INVALID_NAME
);
1125 CHECK_VALUE(Context
, value1
&& value2
&& value3
);
1129 LockContext(Context
);
1130 *value1
= (ALint
)Source
->Position
[0];
1131 *value2
= (ALint
)Source
->Position
[1];
1132 *value3
= (ALint
)Source
->Position
[2];
1133 UnlockContext(Context
);
1137 LockContext(Context
);
1138 *value1
= (ALint
)Source
->Velocity
[0];
1139 *value2
= (ALint
)Source
->Velocity
[1];
1140 *value3
= (ALint
)Source
->Velocity
[2];
1141 UnlockContext(Context
);
1145 LockContext(Context
);
1146 *value1
= (ALint
)Source
->Orientation
[0];
1147 *value2
= (ALint
)Source
->Orientation
[1];
1148 *value3
= (ALint
)Source
->Orientation
[2];
1149 UnlockContext(Context
);
1153 al_throwerr(Context
, AL_INVALID_ENUM
);
1158 ALCcontext_DecRef(Context
);
1162 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
1164 ALCcontext
*Context
;
1166 ALdouble offsets
[2];
1171 case AL_SOURCE_RELATIVE
:
1172 case AL_CONE_INNER_ANGLE
:
1173 case AL_CONE_OUTER_ANGLE
:
1176 case AL_SOURCE_STATE
:
1177 case AL_BUFFERS_QUEUED
:
1178 case AL_BUFFERS_PROCESSED
:
1180 case AL_SAMPLE_OFFSET
:
1181 case AL_BYTE_OFFSET
:
1182 case AL_MAX_DISTANCE
:
1183 case AL_ROLLOFF_FACTOR
:
1184 case AL_DOPPLER_FACTOR
:
1185 case AL_REFERENCE_DISTANCE
:
1186 case AL_SOURCE_TYPE
:
1187 case AL_DIRECT_FILTER
:
1188 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1189 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1190 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1191 case AL_DISTANCE_MODEL
:
1192 case AL_DIRECT_CHANNELS_SOFT
:
1193 alGetSourcei(source
, param
, values
);
1199 alGetSource3i(source
, param
, values
+0, values
+1, values
+2);
1203 Context
= GetContextRef();
1204 if(!Context
) return;
1208 if((Source
=LookupSource(Context
, source
)) == NULL
)
1209 al_throwerr(Context
, AL_INVALID_NAME
);
1210 CHECK_VALUE(Context
, values
);
1213 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1214 case AL_BYTE_RW_OFFSETS_SOFT
:
1215 LockContext(Context
);
1216 updateLen
= (ALdouble
)Context
->Device
->UpdateSize
/
1217 Context
->Device
->Frequency
;
1218 GetSourceOffsets(Source
, param
, offsets
, updateLen
);
1219 UnlockContext(Context
);
1220 values
[0] = (ALint
)offsets
[0];
1221 values
[1] = (ALint
)offsets
[1];
1225 al_throwerr(Context
, AL_INVALID_ENUM
);
1230 ALCcontext_DecRef(Context
);
1234 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1236 alSourcePlayv(1, &source
);
1238 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1240 ALCcontext
*Context
;
1244 Context
= GetContextRef();
1245 if(!Context
) return;
1249 CHECK_VALUE(Context
, n
>= 0);
1250 for(i
= 0;i
< n
;i
++)
1252 if(!LookupSource(Context
, sources
[i
]))
1253 al_throwerr(Context
, AL_INVALID_NAME
);
1256 LockContext(Context
);
1257 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1262 newcount
= Context
->MaxActiveSources
<< 1;
1264 temp
= realloc(Context
->ActiveSources
,
1265 sizeof(*Context
->ActiveSources
) * newcount
);
1268 UnlockContext(Context
);
1269 al_throwerr(Context
, AL_OUT_OF_MEMORY
);
1272 Context
->ActiveSources
= temp
;
1273 Context
->MaxActiveSources
= newcount
;
1276 for(i
= 0;i
< n
;i
++)
1278 Source
= LookupSource(Context
, sources
[i
]);
1279 if(Context
->DeferUpdates
) Source
->new_state
= AL_PLAYING
;
1280 else SetSourceState(Source
, Context
, AL_PLAYING
);
1282 UnlockContext(Context
);
1286 ALCcontext_DecRef(Context
);
1289 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1291 alSourcePausev(1, &source
);
1293 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1295 ALCcontext
*Context
;
1299 Context
= GetContextRef();
1300 if(!Context
) return;
1304 CHECK_VALUE(Context
, n
>= 0);
1305 for(i
= 0;i
< n
;i
++)
1307 if(!LookupSource(Context
, sources
[i
]))
1308 al_throwerr(Context
, AL_INVALID_NAME
);
1311 LockContext(Context
);
1312 for(i
= 0;i
< n
;i
++)
1314 Source
= LookupSource(Context
, sources
[i
]);
1315 if(Context
->DeferUpdates
) Source
->new_state
= AL_PAUSED
;
1316 else SetSourceState(Source
, Context
, AL_PAUSED
);
1318 UnlockContext(Context
);
1322 ALCcontext_DecRef(Context
);
1325 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1327 alSourceStopv(1, &source
);
1329 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1331 ALCcontext
*Context
;
1335 Context
= GetContextRef();
1336 if(!Context
) return;
1340 CHECK_VALUE(Context
, n
>= 0);
1341 for(i
= 0;i
< n
;i
++)
1343 if(!LookupSource(Context
, sources
[i
]))
1344 al_throwerr(Context
, AL_INVALID_NAME
);
1347 LockContext(Context
);
1348 for(i
= 0;i
< n
;i
++)
1350 Source
= LookupSource(Context
, sources
[i
]);
1351 Source
->new_state
= AL_NONE
;
1352 SetSourceState(Source
, Context
, AL_STOPPED
);
1354 UnlockContext(Context
);
1358 ALCcontext_DecRef(Context
);
1361 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1363 alSourceRewindv(1, &source
);
1365 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1367 ALCcontext
*Context
;
1371 Context
= GetContextRef();
1372 if(!Context
) return;
1376 CHECK_VALUE(Context
, n
>= 0);
1377 for(i
= 0;i
< n
;i
++)
1379 if(!LookupSource(Context
, sources
[i
]))
1380 al_throwerr(Context
, AL_INVALID_NAME
);
1383 LockContext(Context
);
1384 for(i
= 0;i
< n
;i
++)
1386 Source
= LookupSource(Context
, sources
[i
]);
1387 Source
->new_state
= AL_NONE
;
1388 SetSourceState(Source
, Context
, AL_INITIAL
);
1390 UnlockContext(Context
);
1394 ALCcontext_DecRef(Context
);
1398 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei nb
, const ALuint
*buffers
)
1400 ALCcontext
*Context
;
1403 ALbufferlistitem
*BufferListStart
= NULL
;
1404 ALbufferlistitem
*BufferList
;
1405 ALbuffer
*BufferFmt
;
1410 Context
= GetContextRef();
1411 if(!Context
) return;
1415 ALCdevice
*device
= Context
->Device
;
1417 CHECK_VALUE(Context
, nb
>= 0);
1419 if((Source
=LookupSource(Context
, source
)) == NULL
)
1420 al_throwerr(Context
, AL_INVALID_NAME
);
1422 LockContext(Context
);
1423 if(Source
->SourceType
== AL_STATIC
)
1425 UnlockContext(Context
);
1426 /* Can't queue on a Static Source */
1427 al_throwerr(Context
, AL_INVALID_OPERATION
);
1432 /* Check for a valid Buffer, for its frequency and format */
1433 BufferList
= Source
->queue
;
1436 if(BufferList
->buffer
)
1438 BufferFmt
= BufferList
->buffer
;
1441 BufferList
= BufferList
->next
;
1444 for(i
= 0;i
< nb
;i
++)
1446 ALbuffer
*buffer
= NULL
;
1447 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == NULL
)
1449 UnlockContext(Context
);
1450 al_throwerr(Context
, AL_INVALID_NAME
);
1453 if(!BufferListStart
)
1455 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1456 BufferListStart
->buffer
= buffer
;
1457 BufferListStart
->next
= NULL
;
1458 BufferListStart
->prev
= NULL
;
1459 BufferList
= BufferListStart
;
1463 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1464 BufferList
->next
->buffer
= buffer
;
1465 BufferList
->next
->next
= NULL
;
1466 BufferList
->next
->prev
= BufferList
;
1467 BufferList
= BufferList
->next
;
1469 if(!buffer
) continue;
1470 IncrementRef(&buffer
->ref
);
1472 ReadLock(&buffer
->lock
);
1473 if(BufferFmt
== NULL
)
1477 Source
->NumChannels
= ChannelsFromFmt(buffer
->FmtChannels
);
1478 Source
->SampleSize
= BytesFromFmt(buffer
->FmtType
);
1479 if(buffer
->FmtChannels
== FmtMono
)
1480 Source
->Update
= CalcSourceParams
;
1482 Source
->Update
= CalcNonAttnSourceParams
;
1484 Source
->NeedsUpdate
= AL_TRUE
;
1486 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
1487 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
1488 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
1490 ReadUnlock(&buffer
->lock
);
1491 UnlockContext(Context
);
1492 al_throwerr(Context
, AL_INVALID_OPERATION
);
1494 ReadUnlock(&buffer
->lock
);
1497 /* Source is now streaming */
1498 Source
->SourceType
= AL_STREAMING
;
1500 if(Source
->queue
== NULL
)
1501 Source
->queue
= BufferListStart
;
1504 /* Append to the end of the queue */
1505 BufferList
= Source
->queue
;
1506 while(BufferList
->next
!= NULL
)
1507 BufferList
= BufferList
->next
;
1509 BufferListStart
->prev
= BufferList
;
1510 BufferList
->next
= BufferListStart
;
1513 Source
->BuffersInQueue
+= nb
;
1515 UnlockContext(Context
);
1519 while(BufferListStart
)
1521 BufferList
= BufferListStart
;
1522 BufferListStart
= BufferList
->next
;
1524 if(BufferList
->buffer
)
1525 DecrementRef(&BufferList
->buffer
->ref
);
1531 ALCcontext_DecRef(Context
);
1534 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint source
, ALsizei nb
, ALuint
*buffers
)
1536 ALCcontext
*Context
;
1539 ALbufferlistitem
*BufferList
;
1544 Context
= GetContextRef();
1545 if(!Context
) return;
1549 CHECK_VALUE(Context
, nb
>= 0);
1551 if((Source
=LookupSource(Context
, source
)) == NULL
)
1552 al_throwerr(Context
, AL_INVALID_NAME
);
1554 LockContext(Context
);
1555 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
||
1556 (ALuint
)nb
> Source
->BuffersPlayed
)
1558 UnlockContext(Context
);
1559 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1560 al_throwerr(Context
, AL_INVALID_VALUE
);
1563 for(i
= 0;i
< nb
;i
++)
1565 BufferList
= Source
->queue
;
1566 Source
->queue
= BufferList
->next
;
1567 Source
->BuffersInQueue
--;
1568 Source
->BuffersPlayed
--;
1570 if(BufferList
->buffer
)
1572 buffers
[i
] = BufferList
->buffer
->id
;
1573 DecrementRef(&BufferList
->buffer
->ref
);
1581 Source
->queue
->prev
= NULL
;
1582 UnlockContext(Context
);
1586 ALCcontext_DecRef(Context
);
1590 static ALvoid
InitSourceParams(ALsource
*Source
)
1594 Source
->InnerAngle
= 360.0f
;
1595 Source
->OuterAngle
= 360.0f
;
1596 Source
->Pitch
= 1.0f
;
1597 Source
->Position
[0] = 0.0f
;
1598 Source
->Position
[1] = 0.0f
;
1599 Source
->Position
[2] = 0.0f
;
1600 Source
->Orientation
[0] = 0.0f
;
1601 Source
->Orientation
[1] = 0.0f
;
1602 Source
->Orientation
[2] = 0.0f
;
1603 Source
->Velocity
[0] = 0.0f
;
1604 Source
->Velocity
[1] = 0.0f
;
1605 Source
->Velocity
[2] = 0.0f
;
1606 Source
->RefDistance
= 1.0f
;
1607 Source
->MaxDistance
= FLT_MAX
;
1608 Source
->RollOffFactor
= 1.0f
;
1609 Source
->Looping
= AL_FALSE
;
1610 Source
->Gain
= 1.0f
;
1611 Source
->MinGain
= 0.0f
;
1612 Source
->MaxGain
= 1.0f
;
1613 Source
->OuterGain
= 0.0f
;
1614 Source
->OuterGainHF
= 1.0f
;
1616 Source
->DryGainHFAuto
= AL_TRUE
;
1617 Source
->WetGainAuto
= AL_TRUE
;
1618 Source
->WetGainHFAuto
= AL_TRUE
;
1619 Source
->AirAbsorptionFactor
= 0.0f
;
1620 Source
->RoomRolloffFactor
= 0.0f
;
1621 Source
->DopplerFactor
= 1.0f
;
1622 Source
->DirectChannels
= AL_FALSE
;
1624 Source
->DistanceModel
= DefaultDistanceModel
;
1626 Source
->Resampler
= DefaultResampler
;
1628 Source
->state
= AL_INITIAL
;
1629 Source
->new_state
= AL_NONE
;
1630 Source
->SourceType
= AL_UNDETERMINED
;
1631 Source
->Offset
= -1.0;
1633 Source
->DirectGain
= 1.0f
;
1634 Source
->DirectGainHF
= 1.0f
;
1635 for(i
= 0;i
< MAX_SENDS
;i
++)
1637 Source
->Send
[i
].WetGain
= 1.0f
;
1638 Source
->Send
[i
].WetGainHF
= 1.0f
;
1641 Source
->NeedsUpdate
= AL_TRUE
;
1643 Source
->HrtfMoving
= AL_FALSE
;
1644 Source
->HrtfCounter
= 0;
1650 * Sets the source's new play state given its current state.
1652 ALvoid
SetSourceState(ALsource
*Source
, ALCcontext
*Context
, ALenum state
)
1654 if(state
== AL_PLAYING
)
1656 ALbufferlistitem
*BufferList
;
1659 /* Check that there is a queue containing at least one valid, non zero
1661 BufferList
= Source
->queue
;
1664 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->SampleLen
)
1666 BufferList
= BufferList
->next
;
1669 if(Source
->state
!= AL_PLAYING
)
1671 for(j
= 0;j
< MAXCHANNELS
;j
++)
1673 for(k
= 0;k
< SRC_HISTORY_LENGTH
;k
++)
1674 Source
->HrtfHistory
[j
][k
] = 0.0f
;
1675 for(k
= 0;k
< HRIR_LENGTH
;k
++)
1677 Source
->HrtfValues
[j
][k
][0] = 0.0f
;
1678 Source
->HrtfValues
[j
][k
][1] = 0.0f
;
1683 if(Source
->state
!= AL_PAUSED
)
1685 Source
->state
= AL_PLAYING
;
1686 Source
->position
= 0;
1687 Source
->position_fraction
= 0;
1688 Source
->BuffersPlayed
= 0;
1691 Source
->state
= AL_PLAYING
;
1693 // Check if an Offset has been set
1694 if(Source
->Offset
>= 0.0)
1695 ApplyOffset(Source
);
1697 /* If there's nothing to play, or device is disconnected, go right to
1699 if(!BufferList
|| !Context
->Device
->Connected
)
1701 SetSourceState(Source
, Context
, AL_STOPPED
);
1705 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1707 if(Context
->ActiveSources
[j
] == Source
)
1710 if(j
== Context
->ActiveSourceCount
)
1711 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1713 else if(state
== AL_PAUSED
)
1715 if(Source
->state
== AL_PLAYING
)
1717 Source
->state
= AL_PAUSED
;
1718 Source
->HrtfMoving
= AL_FALSE
;
1719 Source
->HrtfCounter
= 0;
1722 else if(state
== AL_STOPPED
)
1724 if(Source
->state
!= AL_INITIAL
)
1726 Source
->state
= AL_STOPPED
;
1727 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1728 Source
->HrtfMoving
= AL_FALSE
;
1729 Source
->HrtfCounter
= 0;
1731 Source
->Offset
= -1.0;
1733 else if(state
== AL_INITIAL
)
1735 if(Source
->state
!= AL_INITIAL
)
1737 Source
->state
= AL_INITIAL
;
1738 Source
->position
= 0;
1739 Source
->position_fraction
= 0;
1740 Source
->BuffersPlayed
= 0;
1741 Source
->HrtfMoving
= AL_FALSE
;
1742 Source
->HrtfCounter
= 0;
1744 Source
->Offset
= -1.0;
1750 * Gets the current read and write offsets for the given Source, in the
1751 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
1752 * the start of the queue (not the start of the current buffer).
1754 static ALvoid
GetSourceOffsets(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1756 const ALbufferlistitem
*BufferList
;
1757 const ALbuffer
*Buffer
= NULL
;
1758 ALuint readPos
, writePos
;
1759 ALuint totalBufferLen
;
1762 // Find the first valid Buffer in the Queue
1763 BufferList
= Source
->queue
;
1766 if(BufferList
->buffer
)
1768 Buffer
= BufferList
->buffer
;
1771 BufferList
= BufferList
->next
;
1774 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1781 if(updateLen
> 0.0 && updateLen
< 0.015)
1784 /* NOTE: This is the offset into the *current* buffer, so add the length of
1785 * any played buffers */
1786 readPos
= Source
->position
;
1788 BufferList
= Source
->queue
;
1789 for(i
= 0;BufferList
;i
++)
1791 if(BufferList
->buffer
)
1793 if(i
< Source
->BuffersPlayed
)
1794 readPos
+= BufferList
->buffer
->SampleLen
;
1795 totalBufferLen
+= BufferList
->buffer
->SampleLen
;
1797 BufferList
= BufferList
->next
;
1799 if(Source
->state
== AL_PLAYING
)
1800 writePos
= readPos
+ (ALuint
)(updateLen
*Buffer
->Frequency
);
1806 readPos
%= totalBufferLen
;
1807 writePos
%= totalBufferLen
;
1811 /* Wrap positions back to 0 */
1812 if(readPos
>= totalBufferLen
)
1814 if(writePos
>= totalBufferLen
)
1821 offset
[0] = (ALdouble
)readPos
/ Buffer
->Frequency
;
1822 offset
[1] = (ALdouble
)writePos
/ Buffer
->Frequency
;
1825 case AL_SAMPLE_OFFSET
:
1826 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1827 offset
[0] = (ALdouble
)readPos
;
1828 offset
[1] = (ALdouble
)writePos
;
1831 case AL_BYTE_OFFSET
:
1832 case AL_BYTE_RW_OFFSETS_SOFT
:
1833 if(Buffer
->OriginalType
== UserFmtIMA4
)
1835 ALuint BlockSize
= 36 * ChannelsFromFmt(Buffer
->FmtChannels
);
1836 ALuint FrameBlockSize
= 65;
1838 /* Round down to nearest ADPCM block */
1839 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1840 if(Source
->state
!= AL_PLAYING
)
1841 offset
[1] = offset
[0];
1844 /* Round up to nearest ADPCM block */
1845 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1846 FrameBlockSize
* BlockSize
);
1851 ALuint FrameSize
= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
1852 offset
[0] = (ALdouble
)(readPos
* FrameSize
);
1853 offset
[1] = (ALdouble
)(writePos
* FrameSize
);
1862 * Apply the stored playback offset to the Source. This function will update
1863 * the number of buffers "played" given the stored offset.
1865 ALboolean
ApplyOffset(ALsource
*Source
)
1867 const ALbufferlistitem
*BufferList
;
1868 const ALbuffer
*Buffer
;
1869 ALint bufferLen
, totalBufferLen
;
1870 ALint buffersPlayed
;
1873 /* Get sample frame offset */
1874 offset
= GetSampleOffset(Source
);
1881 BufferList
= Source
->queue
;
1884 Buffer
= BufferList
->buffer
;
1885 bufferLen
= Buffer
? Buffer
->SampleLen
: 0;
1887 if(bufferLen
<= offset
-totalBufferLen
)
1889 /* Offset is past this buffer so increment to the next buffer */
1892 else if(totalBufferLen
<= offset
)
1894 /* Offset is in this buffer */
1895 Source
->BuffersPlayed
= buffersPlayed
;
1897 Source
->position
= offset
- totalBufferLen
;
1898 Source
->position_fraction
= 0;
1902 totalBufferLen
+= bufferLen
;
1904 BufferList
= BufferList
->next
;
1907 /* Offset is out of range of the queue */
1914 * Returns the sample offset into the Source's queue (from the Sample, Byte or
1915 * Second offset supplied by the application). This takes into account the fact
1916 * that the buffer format may have been modifed since.
1918 static ALint
GetSampleOffset(ALsource
*Source
)
1920 const ALbuffer
*Buffer
= NULL
;
1921 const ALbufferlistitem
*BufferList
;
1924 /* Find the first valid Buffer in the Queue */
1925 BufferList
= Source
->queue
;
1928 if(BufferList
->buffer
)
1930 Buffer
= BufferList
->buffer
;
1933 BufferList
= BufferList
->next
;
1938 Source
->Offset
= -1.0;
1942 switch(Source
->OffsetType
)
1944 case AL_BYTE_OFFSET
:
1945 /* Determine the ByteOffset (and ensure it is block aligned) */
1946 Offset
= (ALint
)Source
->Offset
;
1947 if(Buffer
->OriginalType
== UserFmtIMA4
)
1949 Offset
/= 36 * ChannelsFromUserFmt(Buffer
->OriginalChannels
);
1953 Offset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
1956 case AL_SAMPLE_OFFSET
:
1957 Offset
= (ALint
)Source
->Offset
;
1961 Offset
= (ALint
)(Source
->Offset
* Buffer
->Frequency
);
1964 Source
->Offset
= -1.0;
1972 * Destroys all sources in the source map.
1974 ALvoid
ReleaseALSources(ALCcontext
*Context
)
1978 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
1980 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
1981 Context
->SourceMap
.array
[pos
].value
= NULL
;
1983 while(temp
->queue
!= NULL
)
1985 ALbufferlistitem
*BufferList
= temp
->queue
;
1986 temp
->queue
= BufferList
->next
;
1988 if(BufferList
->buffer
!= NULL
)
1989 DecrementRef(&BufferList
->buffer
->ref
);
1993 for(j
= 0;j
< MAX_SENDS
;++j
)
1995 if(temp
->Send
[j
].Slot
)
1996 DecrementRef(&temp
->Send
[j
].Slot
->ref
);
1997 temp
->Send
[j
].Slot
= NULL
;
2000 FreeThunkEntry(temp
->id
);
2001 memset(temp
, 0, sizeof(*temp
));