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"
35 static ALvoid
InitSourceParams(ALsource
*Source
);
36 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum eName
, ALdouble
*Offsets
, ALdouble updateLen
);
37 static ALboolean
ApplyOffset(ALsource
*Source
);
38 static ALint
GetByteOffset(ALsource
*Source
);
39 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
);
41 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
42 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
43 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
44 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
46 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
51 Context
= GetContextSuspended();
54 Device
= Context
->Device
;
55 if(n
< 0 || IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
56 alSetError(Context
, AL_INVALID_VALUE
);
57 else if((ALuint
)n
> Device
->MaxNoOfSources
- Context
->SourceMap
.size
)
58 alSetError(Context
, AL_INVALID_VALUE
);
64 // Add additional sources to the list
68 ALsource
*source
= calloc(1, sizeof(ALsource
));
71 alSetError(Context
, AL_OUT_OF_MEMORY
);
72 alDeleteSources(i
, sources
);
76 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
77 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
79 if(err
!= AL_NO_ERROR
)
81 ALTHUNK_REMOVEENTRY(source
->source
);
82 memset(source
, 0, sizeof(ALsource
));
85 alSetError(Context
, err
);
86 alDeleteSources(i
, sources
);
90 sources
[i
++] = source
->source
;
91 InitSourceParams(source
);
95 ProcessContext(Context
);
99 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
104 ALbufferlistitem
*BufferList
;
105 ALboolean SourcesValid
= AL_FALSE
;
107 Context
= GetContextSuspended();
111 alSetError(Context
, AL_INVALID_VALUE
);
114 SourcesValid
= AL_TRUE
;
115 // Check that all Sources are valid (and can therefore be deleted)
118 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
120 alSetError(Context
, AL_INVALID_NAME
);
121 SourcesValid
= AL_FALSE
;
129 // All Sources are valid, and can be deleted
132 // Recheck that the Source is valid, because there could be duplicated Source names
133 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) == NULL
)
136 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
138 if(Context
->ActiveSources
[j
] == Source
)
140 ALsizei end
= --(Context
->ActiveSourceCount
);
141 Context
->ActiveSources
[j
] = Context
->ActiveSources
[end
];
146 // For each buffer in the source's queue...
147 while(Source
->queue
!= NULL
)
149 BufferList
= Source
->queue
;
150 Source
->queue
= BufferList
->next
;
152 if(BufferList
->buffer
!= NULL
)
153 BufferList
->buffer
->refcount
--;
157 for(j
= 0;j
< MAX_SENDS
;++j
)
159 if(Source
->Send
[j
].Slot
)
160 Source
->Send
[j
].Slot
->refcount
--;
161 Source
->Send
[j
].Slot
= NULL
;
164 // Remove Source from list of Sources
165 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
166 ALTHUNK_REMOVEENTRY(Source
->source
);
168 memset(Source
,0,sizeof(ALsource
));
173 ProcessContext(Context
);
177 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
182 Context
= GetContextSuspended();
183 if(!Context
) return AL_FALSE
;
185 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
187 ProcessContext(Context
);
193 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
195 ALCcontext
*pContext
;
198 pContext
= GetContextSuspended();
199 if(!pContext
) return;
201 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
208 Source
->flPitch
= flValue
;
209 if(Source
->flPitch
< 0.001f
)
210 Source
->flPitch
= 0.001f
;
211 Source
->NeedsUpdate
= AL_TRUE
;
214 alSetError(pContext
, AL_INVALID_VALUE
);
217 case AL_CONE_INNER_ANGLE
:
218 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
220 Source
->flInnerAngle
= flValue
;
221 Source
->NeedsUpdate
= AL_TRUE
;
224 alSetError(pContext
, AL_INVALID_VALUE
);
227 case AL_CONE_OUTER_ANGLE
:
228 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
230 Source
->flOuterAngle
= flValue
;
231 Source
->NeedsUpdate
= AL_TRUE
;
234 alSetError(pContext
, AL_INVALID_VALUE
);
240 Source
->flGain
= flValue
;
241 Source
->NeedsUpdate
= AL_TRUE
;
244 alSetError(pContext
, AL_INVALID_VALUE
);
247 case AL_MAX_DISTANCE
:
250 Source
->flMaxDistance
= flValue
;
251 Source
->NeedsUpdate
= AL_TRUE
;
254 alSetError(pContext
, AL_INVALID_VALUE
);
257 case AL_ROLLOFF_FACTOR
:
260 Source
->flRollOffFactor
= flValue
;
261 Source
->NeedsUpdate
= AL_TRUE
;
264 alSetError(pContext
, AL_INVALID_VALUE
);
267 case AL_REFERENCE_DISTANCE
:
270 Source
->flRefDistance
= flValue
;
271 Source
->NeedsUpdate
= AL_TRUE
;
274 alSetError(pContext
, AL_INVALID_VALUE
);
278 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
280 Source
->flMinGain
= flValue
;
281 Source
->NeedsUpdate
= AL_TRUE
;
284 alSetError(pContext
, AL_INVALID_VALUE
);
288 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
290 Source
->flMaxGain
= flValue
;
291 Source
->NeedsUpdate
= AL_TRUE
;
294 alSetError(pContext
, AL_INVALID_VALUE
);
297 case AL_CONE_OUTER_GAIN
:
298 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
300 Source
->flOuterGain
= flValue
;
301 Source
->NeedsUpdate
= AL_TRUE
;
304 alSetError(pContext
, AL_INVALID_VALUE
);
307 case AL_CONE_OUTER_GAINHF
:
308 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
310 Source
->OuterGainHF
= flValue
;
311 Source
->NeedsUpdate
= AL_TRUE
;
314 alSetError(pContext
, AL_INVALID_VALUE
);
317 case AL_AIR_ABSORPTION_FACTOR
:
318 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
320 Source
->AirAbsorptionFactor
= flValue
;
321 Source
->NeedsUpdate
= AL_TRUE
;
324 alSetError(pContext
, AL_INVALID_VALUE
);
327 case AL_ROOM_ROLLOFF_FACTOR
:
328 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
330 Source
->RoomRolloffFactor
= flValue
;
331 Source
->NeedsUpdate
= AL_TRUE
;
334 alSetError(pContext
, AL_INVALID_VALUE
);
337 case AL_DOPPLER_FACTOR
:
338 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
340 Source
->DopplerFactor
= flValue
;
341 Source
->NeedsUpdate
= AL_TRUE
;
344 alSetError(pContext
, AL_INVALID_VALUE
);
348 case AL_SAMPLE_OFFSET
:
352 Source
->lOffsetType
= eParam
;
354 // Store Offset (convert Seconds into Milliseconds)
355 if(eParam
== AL_SEC_OFFSET
)
356 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
358 Source
->lOffset
= (ALint
)flValue
;
360 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
362 if(ApplyOffset(Source
) == AL_FALSE
)
363 alSetError(pContext
, AL_INVALID_VALUE
);
367 alSetError(pContext
, AL_INVALID_VALUE
);
371 alSetError(pContext
, AL_INVALID_ENUM
);
377 // Invalid Source Name
378 alSetError(pContext
, AL_INVALID_NAME
);
381 ProcessContext(pContext
);
385 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
387 ALCcontext
*pContext
;
390 pContext
= GetContextSuspended();
391 if(!pContext
) return;
393 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
398 Source
->vPosition
[0] = flValue1
;
399 Source
->vPosition
[1] = flValue2
;
400 Source
->vPosition
[2] = flValue3
;
401 Source
->NeedsUpdate
= AL_TRUE
;
405 Source
->vVelocity
[0] = flValue1
;
406 Source
->vVelocity
[1] = flValue2
;
407 Source
->vVelocity
[2] = flValue3
;
408 Source
->NeedsUpdate
= AL_TRUE
;
412 Source
->vOrientation
[0] = flValue1
;
413 Source
->vOrientation
[1] = flValue2
;
414 Source
->vOrientation
[2] = flValue3
;
415 Source
->NeedsUpdate
= AL_TRUE
;
419 alSetError(pContext
, AL_INVALID_ENUM
);
424 alSetError(pContext
, AL_INVALID_NAME
);
426 ProcessContext(pContext
);
430 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
432 ALCcontext
*pContext
;
434 pContext
= GetContextSuspended();
435 if(!pContext
) return;
439 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
444 case AL_CONE_INNER_ANGLE
:
445 case AL_CONE_OUTER_ANGLE
:
447 case AL_MAX_DISTANCE
:
448 case AL_ROLLOFF_FACTOR
:
449 case AL_REFERENCE_DISTANCE
:
452 case AL_CONE_OUTER_GAIN
:
453 case AL_CONE_OUTER_GAINHF
:
455 case AL_SAMPLE_OFFSET
:
457 case AL_AIR_ABSORPTION_FACTOR
:
458 case AL_ROOM_ROLLOFF_FACTOR
:
459 alSourcef(source
, eParam
, pflValues
[0]);
465 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
469 alSetError(pContext
, AL_INVALID_ENUM
);
474 alSetError(pContext
, AL_INVALID_NAME
);
477 alSetError(pContext
, AL_INVALID_VALUE
);
479 ProcessContext(pContext
);
483 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
485 ALCcontext
*pContext
;
487 ALbufferlistitem
*BufferListItem
;
489 pContext
= GetContextSuspended();
490 if(!pContext
) return;
492 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
494 ALCdevice
*device
= pContext
->Device
;
498 case AL_MAX_DISTANCE
:
499 case AL_ROLLOFF_FACTOR
:
500 case AL_CONE_INNER_ANGLE
:
501 case AL_CONE_OUTER_ANGLE
:
502 case AL_REFERENCE_DISTANCE
:
503 alSourcef(source
, eParam
, (ALfloat
)lValue
);
506 case AL_SOURCE_RELATIVE
:
507 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
509 Source
->bHeadRelative
= (ALboolean
)lValue
;
510 Source
->NeedsUpdate
= AL_TRUE
;
513 alSetError(pContext
, AL_INVALID_VALUE
);
517 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
518 Source
->bLooping
= (ALboolean
)lValue
;
520 alSetError(pContext
, AL_INVALID_VALUE
);
524 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
526 ALbuffer
*buffer
= NULL
;
529 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
531 // Remove all elements in the queue
532 while(Source
->queue
!= NULL
)
534 BufferListItem
= Source
->queue
;
535 Source
->queue
= BufferListItem
->next
;
537 if(BufferListItem
->buffer
)
538 BufferListItem
->buffer
->refcount
--;
539 free(BufferListItem
);
541 Source
->BuffersInQueue
= 0;
543 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
546 // Source is now in STATIC mode
547 Source
->lSourceType
= AL_STATIC
;
549 // Add the selected buffer to the queue
550 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
551 BufferListItem
->buffer
= buffer
;
552 BufferListItem
->next
= NULL
;
554 Source
->queue
= BufferListItem
;
555 Source
->BuffersInQueue
= 1;
557 if(aluChannelsFromFormat(buffer
->format
) == 1)
558 Source
->Update
= CalcSourceParams
;
560 Source
->Update
= CalcNonAttnSourceParams
;
562 Source
->Mix
= MixSource
;
564 // Increment reference counter for buffer
569 // Source is now in UNDETERMINED mode
570 Source
->lSourceType
= AL_UNDETERMINED
;
572 Source
->BuffersPlayed
= 0;
574 // Update AL_BUFFER parameter
575 Source
->Buffer
= buffer
;
576 Source
->NeedsUpdate
= AL_TRUE
;
579 alSetError(pContext
, AL_INVALID_VALUE
);
582 alSetError(pContext
, AL_INVALID_OPERATION
);
585 case AL_SOURCE_STATE
:
587 alSetError(pContext
, AL_INVALID_OPERATION
);
591 case AL_SAMPLE_OFFSET
:
595 Source
->lOffsetType
= eParam
;
597 // Store Offset (convert Seconds into Milliseconds)
598 if(eParam
== AL_SEC_OFFSET
)
599 Source
->lOffset
= lValue
* 1000;
601 Source
->lOffset
= lValue
;
603 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
605 if(ApplyOffset(Source
) == AL_FALSE
)
606 alSetError(pContext
, AL_INVALID_VALUE
);
610 alSetError(pContext
, AL_INVALID_VALUE
);
613 case AL_DIRECT_FILTER
: {
614 ALfilter
*filter
= NULL
;
617 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
621 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
622 Source
->DirectFilter
.filter
= 0;
625 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
626 Source
->NeedsUpdate
= AL_TRUE
;
629 alSetError(pContext
, AL_INVALID_VALUE
);
632 case AL_DIRECT_FILTER_GAINHF_AUTO
:
633 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
635 Source
->DryGainHFAuto
= lValue
;
636 Source
->NeedsUpdate
= AL_TRUE
;
639 alSetError(pContext
, AL_INVALID_VALUE
);
642 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
643 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
645 Source
->WetGainAuto
= lValue
;
646 Source
->NeedsUpdate
= AL_TRUE
;
649 alSetError(pContext
, AL_INVALID_VALUE
);
652 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
653 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
655 Source
->WetGainHFAuto
= lValue
;
656 Source
->NeedsUpdate
= AL_TRUE
;
659 alSetError(pContext
, AL_INVALID_VALUE
);
662 case AL_DISTANCE_MODEL
:
663 if(lValue
== AL_NONE
||
664 lValue
== AL_INVERSE_DISTANCE
||
665 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
666 lValue
== AL_LINEAR_DISTANCE
||
667 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
668 lValue
== AL_EXPONENT_DISTANCE
||
669 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
671 Source
->DistanceModel
= lValue
;
672 if(pContext
->SourceDistanceModel
)
673 Source
->NeedsUpdate
= AL_TRUE
;
676 alSetError(pContext
, AL_INVALID_VALUE
);
680 alSetError(pContext
, AL_INVALID_ENUM
);
685 alSetError(pContext
, AL_INVALID_NAME
);
687 ProcessContext(pContext
);
691 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
693 ALCcontext
*pContext
;
696 pContext
= GetContextSuspended();
697 if(!pContext
) return;
699 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
701 ALCdevice
*device
= pContext
->Device
;
708 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
711 case AL_AUXILIARY_SEND_FILTER
: {
712 ALeffectslot
*ALEffectSlot
= NULL
;
713 ALfilter
*ALFilter
= NULL
;
715 if((ALuint
)lValue2
< device
->NumAuxSends
&&
717 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
719 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
721 /* Release refcount on the previous slot, and add one for
723 if(Source
->Send
[lValue2
].Slot
)
724 Source
->Send
[lValue2
].Slot
->refcount
--;
725 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
726 if(Source
->Send
[lValue2
].Slot
)
727 Source
->Send
[lValue2
].Slot
->refcount
++;
732 Source
->Send
[lValue2
].WetFilter
.type
= 0;
733 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
736 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
737 Source
->NeedsUpdate
= AL_TRUE
;
740 alSetError(pContext
, AL_INVALID_VALUE
);
744 alSetError(pContext
, AL_INVALID_ENUM
);
749 alSetError(pContext
, AL_INVALID_NAME
);
751 ProcessContext(pContext
);
755 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
757 ALCcontext
*pContext
;
759 pContext
= GetContextSuspended();
760 if(!pContext
) return;
764 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
768 case AL_SOURCE_RELATIVE
:
769 case AL_CONE_INNER_ANGLE
:
770 case AL_CONE_OUTER_ANGLE
:
773 case AL_SOURCE_STATE
:
775 case AL_SAMPLE_OFFSET
:
777 case AL_MAX_DISTANCE
:
778 case AL_ROLLOFF_FACTOR
:
779 case AL_REFERENCE_DISTANCE
:
780 case AL_DIRECT_FILTER
:
781 case AL_DIRECT_FILTER_GAINHF_AUTO
:
782 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
783 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
784 case AL_DISTANCE_MODEL
:
785 alSourcei(source
, eParam
, plValues
[0]);
791 case AL_AUXILIARY_SEND_FILTER
:
792 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
796 alSetError(pContext
, AL_INVALID_ENUM
);
801 alSetError(pContext
, AL_INVALID_NAME
);
804 alSetError(pContext
, AL_INVALID_VALUE
);
806 ProcessContext(pContext
);
810 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
812 ALCcontext
*pContext
;
817 pContext
= GetContextSuspended();
818 if(!pContext
) return;
822 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
827 *pflValue
= Source
->flPitch
;
831 *pflValue
= Source
->flGain
;
835 *pflValue
= Source
->flMinGain
;
839 *pflValue
= Source
->flMaxGain
;
842 case AL_MAX_DISTANCE
:
843 *pflValue
= Source
->flMaxDistance
;
846 case AL_ROLLOFF_FACTOR
:
847 *pflValue
= Source
->flRollOffFactor
;
850 case AL_CONE_OUTER_GAIN
:
851 *pflValue
= Source
->flOuterGain
;
854 case AL_CONE_OUTER_GAINHF
:
855 *pflValue
= Source
->OuterGainHF
;
859 case AL_SAMPLE_OFFSET
:
861 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
862 pContext
->Device
->Frequency
;
863 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
864 *pflValue
= Offsets
[0];
867 case AL_CONE_INNER_ANGLE
:
868 *pflValue
= Source
->flInnerAngle
;
871 case AL_CONE_OUTER_ANGLE
:
872 *pflValue
= Source
->flOuterAngle
;
875 case AL_REFERENCE_DISTANCE
:
876 *pflValue
= Source
->flRefDistance
;
879 case AL_AIR_ABSORPTION_FACTOR
:
880 *pflValue
= Source
->AirAbsorptionFactor
;
883 case AL_ROOM_ROLLOFF_FACTOR
:
884 *pflValue
= Source
->RoomRolloffFactor
;
887 case AL_DOPPLER_FACTOR
:
888 *pflValue
= Source
->DopplerFactor
;
892 alSetError(pContext
, AL_INVALID_ENUM
);
897 alSetError(pContext
, AL_INVALID_NAME
);
900 alSetError(pContext
, AL_INVALID_VALUE
);
902 ProcessContext(pContext
);
906 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
908 ALCcontext
*pContext
;
911 pContext
= GetContextSuspended();
912 if(!pContext
) return;
914 if(pflValue1
&& pflValue2
&& pflValue3
)
916 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
921 *pflValue1
= Source
->vPosition
[0];
922 *pflValue2
= Source
->vPosition
[1];
923 *pflValue3
= Source
->vPosition
[2];
927 *pflValue1
= Source
->vVelocity
[0];
928 *pflValue2
= Source
->vVelocity
[1];
929 *pflValue3
= Source
->vVelocity
[2];
933 *pflValue1
= Source
->vOrientation
[0];
934 *pflValue2
= Source
->vOrientation
[1];
935 *pflValue3
= Source
->vOrientation
[2];
939 alSetError(pContext
, AL_INVALID_ENUM
);
944 alSetError(pContext
, AL_INVALID_NAME
);
947 alSetError(pContext
, AL_INVALID_VALUE
);
949 ProcessContext(pContext
);
953 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
955 ALCcontext
*pContext
;
960 pContext
= GetContextSuspended();
961 if(!pContext
) return;
965 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
973 case AL_MAX_DISTANCE
:
974 case AL_ROLLOFF_FACTOR
:
975 case AL_DOPPLER_FACTOR
:
976 case AL_CONE_OUTER_GAIN
:
978 case AL_SAMPLE_OFFSET
:
980 case AL_CONE_INNER_ANGLE
:
981 case AL_CONE_OUTER_ANGLE
:
982 case AL_REFERENCE_DISTANCE
:
983 case AL_CONE_OUTER_GAINHF
:
984 case AL_AIR_ABSORPTION_FACTOR
:
985 case AL_ROOM_ROLLOFF_FACTOR
:
986 alGetSourcef(source
, eParam
, pflValues
);
992 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
995 case AL_SAMPLE_RW_OFFSETS_SOFT
:
996 case AL_BYTE_RW_OFFSETS_SOFT
:
997 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
998 pContext
->Device
->Frequency
;
999 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1000 pflValues
[0] = Offsets
[0];
1001 pflValues
[1] = Offsets
[1];
1005 alSetError(pContext
, AL_INVALID_ENUM
);
1010 alSetError(pContext
, AL_INVALID_NAME
);
1013 alSetError(pContext
, AL_INVALID_VALUE
);
1015 ProcessContext(pContext
);
1019 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1021 ALCcontext
*pContext
;
1023 ALdouble Offsets
[2];
1026 pContext
= GetContextSuspended();
1027 if(!pContext
) return;
1031 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1035 case AL_MAX_DISTANCE
:
1036 *plValue
= (ALint
)Source
->flMaxDistance
;
1039 case AL_ROLLOFF_FACTOR
:
1040 *plValue
= (ALint
)Source
->flRollOffFactor
;
1043 case AL_REFERENCE_DISTANCE
:
1044 *plValue
= (ALint
)Source
->flRefDistance
;
1047 case AL_SOURCE_RELATIVE
:
1048 *plValue
= Source
->bHeadRelative
;
1051 case AL_CONE_INNER_ANGLE
:
1052 *plValue
= (ALint
)Source
->flInnerAngle
;
1055 case AL_CONE_OUTER_ANGLE
:
1056 *plValue
= (ALint
)Source
->flOuterAngle
;
1060 *plValue
= Source
->bLooping
;
1064 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1067 case AL_SOURCE_STATE
:
1068 *plValue
= Source
->state
;
1071 case AL_BUFFERS_QUEUED
:
1072 *plValue
= Source
->BuffersInQueue
;
1075 case AL_BUFFERS_PROCESSED
:
1076 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1078 /* Buffers on a looping source are in a perpetual state
1079 * of PENDING, so don't report any as PROCESSED */
1083 *plValue
= Source
->BuffersPlayed
;
1086 case AL_SOURCE_TYPE
:
1087 *plValue
= Source
->lSourceType
;
1091 case AL_SAMPLE_OFFSET
:
1092 case AL_BYTE_OFFSET
:
1093 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1094 pContext
->Device
->Frequency
;
1095 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1096 *plValue
= (ALint
)Offsets
[0];
1099 case AL_DIRECT_FILTER
:
1100 *plValue
= Source
->DirectFilter
.filter
;
1103 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1104 *plValue
= Source
->DryGainHFAuto
;
1107 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1108 *plValue
= Source
->WetGainAuto
;
1111 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1112 *plValue
= Source
->WetGainHFAuto
;
1115 case AL_DOPPLER_FACTOR
:
1116 *plValue
= (ALint
)Source
->DopplerFactor
;
1119 case AL_DISTANCE_MODEL
:
1120 *plValue
= Source
->DistanceModel
;
1124 alSetError(pContext
, AL_INVALID_ENUM
);
1129 alSetError(pContext
, AL_INVALID_NAME
);
1132 alSetError(pContext
, AL_INVALID_VALUE
);
1134 ProcessContext(pContext
);
1138 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1140 ALCcontext
*pContext
;
1143 pContext
= GetContextSuspended();
1144 if(!pContext
) return;
1146 if(plValue1
&& plValue2
&& plValue3
)
1148 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1153 *plValue1
= (ALint
)Source
->vPosition
[0];
1154 *plValue2
= (ALint
)Source
->vPosition
[1];
1155 *plValue3
= (ALint
)Source
->vPosition
[2];
1159 *plValue1
= (ALint
)Source
->vVelocity
[0];
1160 *plValue2
= (ALint
)Source
->vVelocity
[1];
1161 *plValue3
= (ALint
)Source
->vVelocity
[2];
1165 *plValue1
= (ALint
)Source
->vOrientation
[0];
1166 *plValue2
= (ALint
)Source
->vOrientation
[1];
1167 *plValue3
= (ALint
)Source
->vOrientation
[2];
1171 alSetError(pContext
, AL_INVALID_ENUM
);
1176 alSetError(pContext
, AL_INVALID_NAME
);
1179 alSetError(pContext
, AL_INVALID_VALUE
);
1181 ProcessContext(pContext
);
1185 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1187 ALCcontext
*pContext
;
1189 ALdouble Offsets
[2];
1192 pContext
= GetContextSuspended();
1193 if(!pContext
) return;
1197 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1201 case AL_SOURCE_RELATIVE
:
1202 case AL_CONE_INNER_ANGLE
:
1203 case AL_CONE_OUTER_ANGLE
:
1206 case AL_SOURCE_STATE
:
1207 case AL_BUFFERS_QUEUED
:
1208 case AL_BUFFERS_PROCESSED
:
1210 case AL_SAMPLE_OFFSET
:
1211 case AL_BYTE_OFFSET
:
1212 case AL_MAX_DISTANCE
:
1213 case AL_ROLLOFF_FACTOR
:
1214 case AL_DOPPLER_FACTOR
:
1215 case AL_REFERENCE_DISTANCE
:
1216 case AL_SOURCE_TYPE
:
1217 case AL_DIRECT_FILTER
:
1218 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1219 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1220 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1221 case AL_DISTANCE_MODEL
:
1222 alGetSourcei(source
, eParam
, plValues
);
1228 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1231 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1232 case AL_BYTE_RW_OFFSETS_SOFT
:
1233 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1234 pContext
->Device
->Frequency
;
1235 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1236 plValues
[0] = (ALint
)Offsets
[0];
1237 plValues
[1] = (ALint
)Offsets
[1];
1241 alSetError(pContext
, AL_INVALID_ENUM
);
1246 alSetError(pContext
, AL_INVALID_NAME
);
1249 alSetError(pContext
, AL_INVALID_VALUE
);
1251 ProcessContext(pContext
);
1255 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1257 alSourcePlayv(1, &source
);
1260 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1262 ALCcontext
*Context
;
1264 ALbufferlistitem
*BufferList
;
1267 Context
= GetContextSuspended();
1268 if(!Context
) return;
1272 alSetError(Context
, AL_INVALID_VALUE
);
1275 if(n
> 0 && !sources
)
1277 alSetError(Context
, AL_INVALID_VALUE
);
1281 // Check that all the Sources are valid
1282 for(i
= 0;i
< n
;i
++)
1284 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1286 alSetError(Context
, AL_INVALID_NAME
);
1291 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1296 newcount
= Context
->MaxActiveSources
<< 1;
1298 temp
= realloc(Context
->ActiveSources
,
1299 sizeof(*Context
->ActiveSources
) * newcount
);
1302 alSetError(Context
, AL_OUT_OF_MEMORY
);
1306 Context
->ActiveSources
= temp
;
1307 Context
->MaxActiveSources
= newcount
;
1310 for(i
= 0;i
< n
;i
++)
1312 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1314 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1315 BufferList
= Source
->queue
;
1318 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1320 BufferList
= BufferList
->next
;
1325 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1329 if(Source
->state
!= AL_PAUSED
)
1331 Source
->state
= AL_PLAYING
;
1332 Source
->position
= 0;
1333 Source
->position_fraction
= 0;
1334 Source
->BuffersPlayed
= 0;
1336 Source
->Buffer
= Source
->queue
->buffer
;
1339 Source
->state
= AL_PLAYING
;
1341 // Check if an Offset has been set
1343 ApplyOffset(Source
);
1345 // If device is disconnected, go right to stopped
1346 if(!Context
->Device
->Connected
)
1348 Source
->state
= AL_STOPPED
;
1349 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1350 Source
->position
= 0;
1351 Source
->position_fraction
= 0;
1355 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1357 if(Context
->ActiveSources
[j
] == Source
)
1360 if(j
== Context
->ActiveSourceCount
)
1361 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1366 ProcessContext(Context
);
1369 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1371 alSourcePausev(1, &source
);
1374 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1376 ALCcontext
*Context
;
1380 Context
= GetContextSuspended();
1381 if(!Context
) return;
1385 alSetError(Context
, AL_INVALID_VALUE
);
1388 if(n
> 0 && !sources
)
1390 alSetError(Context
, AL_INVALID_VALUE
);
1394 // Check all the Sources are valid
1395 for(i
= 0;i
< n
;i
++)
1397 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1399 alSetError(Context
, AL_INVALID_NAME
);
1404 for(i
= 0;i
< n
;i
++)
1406 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1407 if(Source
->state
== AL_PLAYING
)
1408 Source
->state
= AL_PAUSED
;
1412 ProcessContext(Context
);
1415 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1417 alSourceStopv(1, &source
);
1420 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1422 ALCcontext
*Context
;
1426 Context
= GetContextSuspended();
1427 if(!Context
) return;
1431 alSetError(Context
, AL_INVALID_VALUE
);
1434 if(n
> 0 && !sources
)
1436 alSetError(Context
, AL_INVALID_VALUE
);
1440 // Check all the Sources are valid
1441 for(i
= 0;i
< n
;i
++)
1443 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1445 alSetError(Context
, AL_INVALID_NAME
);
1450 for(i
= 0;i
< n
;i
++)
1452 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1453 if(Source
->state
!= AL_INITIAL
)
1455 Source
->state
= AL_STOPPED
;
1456 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1458 Source
->lOffset
= 0;
1462 ProcessContext(Context
);
1465 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1467 alSourceRewindv(1, &source
);
1470 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1472 ALCcontext
*Context
;
1476 Context
= GetContextSuspended();
1477 if(!Context
) return;
1481 alSetError(Context
, AL_INVALID_VALUE
);
1484 if(n
> 0 && !sources
)
1486 alSetError(Context
, AL_INVALID_VALUE
);
1490 // Check all the Sources are valid
1491 for(i
= 0;i
< n
;i
++)
1493 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1495 alSetError(Context
, AL_INVALID_NAME
);
1500 for(i
= 0;i
< n
;i
++)
1502 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1503 if(Source
->state
!= AL_INITIAL
)
1505 Source
->state
= AL_INITIAL
;
1506 Source
->position
= 0;
1507 Source
->position_fraction
= 0;
1508 Source
->BuffersPlayed
= 0;
1510 Source
->Buffer
= Source
->queue
->buffer
;
1512 Source
->lOffset
= 0;
1516 ProcessContext(Context
);
1520 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1522 ALCcontext
*Context
;
1527 ALbufferlistitem
*BufferListStart
;
1528 ALbufferlistitem
*BufferList
;
1535 Context
= GetContextSuspended();
1536 if(!Context
) return;
1540 alSetError(Context
, AL_INVALID_VALUE
);
1544 // Check that all buffers are valid or zero and that the source is valid
1546 // Check that this is a valid source
1547 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1549 alSetError(Context
, AL_INVALID_NAME
);
1553 // Check that this is not a STATIC Source
1554 if(Source
->lSourceType
== AL_STATIC
)
1556 // Invalid Source Type (can't queue on a Static Source)
1557 alSetError(Context
, AL_INVALID_OPERATION
);
1561 device
= Context
->Device
;
1566 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1567 BufferList
= Source
->queue
;
1570 if(BufferList
->buffer
)
1572 Frequency
= BufferList
->buffer
->frequency
;
1573 Format
= BufferList
->buffer
->eOriginalFormat
;
1576 BufferList
= BufferList
->next
;
1579 for(i
= 0;i
< n
;i
++)
1584 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1586 alSetError(Context
, AL_INVALID_NAME
);
1590 if(Frequency
== -1 && Format
== -1)
1592 Frequency
= buffer
->frequency
;
1593 Format
= buffer
->eOriginalFormat
;
1595 if(aluChannelsFromFormat(buffer
->format
) == 1)
1596 Source
->Update
= CalcSourceParams
;
1598 Source
->Update
= CalcNonAttnSourceParams
;
1600 Source
->Mix
= MixSource
;
1602 Source
->NeedsUpdate
= AL_TRUE
;
1604 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1606 alSetError(Context
, AL_INVALID_OPERATION
);
1611 // Change Source Type
1612 Source
->lSourceType
= AL_STREAMING
;
1614 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1616 // All buffers are valid - so add them to the list
1617 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1618 BufferListStart
->buffer
= buffer
;
1619 BufferListStart
->next
= NULL
;
1621 // Increment reference counter for buffer
1622 if(buffer
) buffer
->refcount
++;
1624 BufferList
= BufferListStart
;
1626 for(i
= 1;i
< n
;i
++)
1628 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1630 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1631 BufferList
->next
->buffer
= buffer
;
1632 BufferList
->next
->next
= NULL
;
1634 // Increment reference counter for buffer
1635 if(buffer
) buffer
->refcount
++;
1637 BufferList
= BufferList
->next
;
1640 if(Source
->queue
== NULL
)
1642 Source
->queue
= BufferListStart
;
1643 // Update Current Buffer
1644 Source
->Buffer
= BufferListStart
->buffer
;
1648 // Find end of queue
1649 BufferList
= Source
->queue
;
1650 while(BufferList
->next
!= NULL
)
1651 BufferList
= BufferList
->next
;
1653 BufferList
->next
= BufferListStart
;
1656 // Update number of buffers in queue
1657 Source
->BuffersInQueue
+= n
;
1660 ProcessContext(Context
);
1664 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1665 // an array of buffer IDs that are to be filled with the names of the buffers removed
1666 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1668 ALCcontext
*Context
;
1671 ALbufferlistitem
*BufferList
;
1676 Context
= GetContextSuspended();
1677 if(!Context
) return;
1681 alSetError(Context
, AL_INVALID_VALUE
);
1685 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1687 alSetError(Context
, AL_INVALID_NAME
);
1691 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1692 (ALuint
)n
> Source
->BuffersPlayed
)
1694 // Some buffers can't be unqueue because they have not been processed
1695 alSetError(Context
, AL_INVALID_VALUE
);
1699 for(i
= 0;i
< n
;i
++)
1701 BufferList
= Source
->queue
;
1702 Source
->queue
= BufferList
->next
;
1704 if(BufferList
->buffer
)
1706 // Record name of buffer
1707 buffers
[i
] = BufferList
->buffer
->buffer
;
1708 // Decrement buffer reference counter
1709 BufferList
->buffer
->refcount
--;
1714 // Release memory for buffer list item
1716 Source
->BuffersInQueue
--;
1719 if(Source
->state
!= AL_PLAYING
)
1722 Source
->Buffer
= Source
->queue
->buffer
;
1724 Source
->Buffer
= NULL
;
1726 Source
->BuffersPlayed
-= n
;
1729 ProcessContext(Context
);
1733 static ALvoid
InitSourceParams(ALsource
*Source
)
1735 Source
->flInnerAngle
= 360.0f
;
1736 Source
->flOuterAngle
= 360.0f
;
1737 Source
->flPitch
= 1.0f
;
1738 Source
->vPosition
[0] = 0.0f
;
1739 Source
->vPosition
[1] = 0.0f
;
1740 Source
->vPosition
[2] = 0.0f
;
1741 Source
->vOrientation
[0] = 0.0f
;
1742 Source
->vOrientation
[1] = 0.0f
;
1743 Source
->vOrientation
[2] = 0.0f
;
1744 Source
->vVelocity
[0] = 0.0f
;
1745 Source
->vVelocity
[1] = 0.0f
;
1746 Source
->vVelocity
[2] = 0.0f
;
1747 Source
->flRefDistance
= 1.0f
;
1748 Source
->flMaxDistance
= FLT_MAX
;
1749 Source
->flRollOffFactor
= 1.0f
;
1750 Source
->bLooping
= AL_FALSE
;
1751 Source
->flGain
= 1.0f
;
1752 Source
->flMinGain
= 0.0f
;
1753 Source
->flMaxGain
= 1.0f
;
1754 Source
->flOuterGain
= 0.0f
;
1755 Source
->OuterGainHF
= 1.0f
;
1757 Source
->DryGainHFAuto
= AL_TRUE
;
1758 Source
->WetGainAuto
= AL_TRUE
;
1759 Source
->WetGainHFAuto
= AL_TRUE
;
1760 Source
->AirAbsorptionFactor
= 0.0f
;
1761 Source
->RoomRolloffFactor
= 0.0f
;
1762 Source
->DopplerFactor
= 1.0f
;
1764 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1766 Source
->Resampler
= DefaultResampler
;
1768 Source
->state
= AL_INITIAL
;
1769 Source
->lSourceType
= AL_UNDETERMINED
;
1771 Source
->NeedsUpdate
= AL_TRUE
;
1773 Source
->Buffer
= NULL
;
1780 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1781 The offset is relative to the start of the queue (not the start of the current buffer)
1783 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1785 ALbufferlistitem
*BufferList
;
1786 ALbuffer
*Buffer
= NULL
;
1788 ALint Channels
, Bytes
;
1789 ALuint readPos
, writePos
;
1790 ALenum OriginalFormat
;
1791 ALuint TotalBufferDataSize
;
1794 // Find the first non-NULL Buffer in the Queue
1795 BufferList
= Source
->queue
;
1798 if(BufferList
->buffer
)
1800 Buffer
= BufferList
->buffer
;
1803 BufferList
= BufferList
->next
;
1806 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1813 // Get Current Buffer Size and frequency (in milliseconds)
1814 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1815 OriginalFormat
= Buffer
->eOriginalFormat
;
1816 Channels
= aluChannelsFromFormat(Buffer
->format
);
1817 Bytes
= aluBytesFromFormat(Buffer
->format
);
1819 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1820 readPos
= Source
->position
* Channels
* Bytes
;
1821 // Add byte length of any processed buffers in the queue
1822 TotalBufferDataSize
= 0;
1823 BufferList
= Source
->queue
;
1824 for(i
= 0;BufferList
;i
++)
1826 if(BufferList
->buffer
)
1828 if(i
< Source
->BuffersPlayed
)
1829 readPos
+= BufferList
->buffer
->size
;
1830 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1832 BufferList
= BufferList
->next
;
1834 if(Source
->state
== AL_PLAYING
)
1835 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1839 if(Source
->bLooping
)
1841 readPos
%= TotalBufferDataSize
;
1842 writePos
%= TotalBufferDataSize
;
1846 // Wrap positions back to 0
1847 if(readPos
>= TotalBufferDataSize
)
1849 if(writePos
>= TotalBufferDataSize
)
1856 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1857 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1859 case AL_SAMPLE_OFFSET
:
1860 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1861 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1862 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1864 case AL_BYTE_OFFSET
:
1865 case AL_BYTE_RW_OFFSETS_SOFT
:
1866 // Take into account the original format of the Buffer
1867 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1868 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1870 // Round down to nearest ADPCM block
1871 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1872 if(Source
->state
== AL_PLAYING
)
1874 // Round up to nearest ADPCM block
1875 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1878 offset
[1] = offset
[0];
1880 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1881 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1882 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1883 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1884 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1885 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1887 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1888 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1890 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1892 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1893 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1895 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1897 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1898 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1900 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1902 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1903 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1905 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1907 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1908 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1912 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1913 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1914 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1924 Apply a playback offset to the Source. This function will update the queue (to correctly
1925 mark buffers as 'pending' or 'processed' depending upon the new offset.
1927 static ALboolean
ApplyOffset(ALsource
*Source
)
1929 ALbufferlistitem
*BufferList
;
1931 ALint lBufferSize
, lTotalBufferSize
;
1932 ALint BuffersPlayed
;
1935 // Get true byte offset
1936 lByteOffset
= GetByteOffset(Source
);
1938 // If the offset is invalid, don't apply it
1939 if(lByteOffset
== -1)
1942 // Sort out the queue (pending and processed states)
1943 BufferList
= Source
->queue
;
1944 lTotalBufferSize
= 0;
1949 Buffer
= BufferList
->buffer
;
1950 lBufferSize
= Buffer
? Buffer
->size
: 0;
1952 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1954 // Offset is past this buffer so increment BuffersPlayed
1957 else if(lTotalBufferSize
<= lByteOffset
)
1959 // Offset is within this buffer
1960 // Set Current Buffer
1961 Source
->Buffer
= BufferList
->buffer
;
1962 Source
->BuffersPlayed
= BuffersPlayed
;
1964 // SW Mixer Positions are in Samples
1965 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1966 aluFrameSizeFromFormat(Buffer
->format
);
1970 // Increment the TotalBufferSize
1971 lTotalBufferSize
+= lBufferSize
;
1973 // Move on to next buffer in the Queue
1974 BufferList
= BufferList
->next
;
1976 // Offset is out of range of the buffer queue
1984 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1985 offset supplied by the application). This takes into account the fact that the buffer format
1986 may have been modifed by AL (e.g 8bit samples are converted to float)
1988 static ALint
GetByteOffset(ALsource
*Source
)
1990 ALbuffer
*Buffer
= NULL
;
1991 ALbufferlistitem
*BufferList
;
1992 ALdouble BufferFreq
;
1993 ALint Channels
, Bytes
;
1994 ALint ByteOffset
= -1;
1996 // Find the first non-NULL Buffer in the Queue
1997 BufferList
= Source
->queue
;
2000 if(BufferList
->buffer
)
2002 Buffer
= BufferList
->buffer
;
2005 BufferList
= BufferList
->next
;
2010 Source
->lOffset
= 0;
2014 BufferFreq
= ((ALdouble
)Buffer
->frequency
);
2015 Channels
= aluChannelsFromFormat(Buffer
->format
);
2016 Bytes
= aluBytesFromFormat(Buffer
->format
);
2018 // Determine the ByteOffset (and ensure it is block aligned)
2019 switch(Source
->lOffsetType
)
2021 case AL_BYTE_OFFSET
:
2022 // Take into consideration the original format
2023 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2025 ByteOffset
*= Channels
* Bytes
;
2028 case AL_SAMPLE_OFFSET
:
2029 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2033 // Note - lOffset is internally stored as Milliseconds
2034 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * BufferFreq
);
2035 ByteOffset
*= Channels
* Bytes
;
2039 Source
->lOffset
= 0;
2044 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2046 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2048 // Round down to nearest ADPCM block
2049 offset
/= 36 * channels
;
2050 // Multiply by compression rate (65 sample frames per block)
2053 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2054 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2055 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2057 /* muLaw has 1 byte per sample */
2058 offset
/= 1 * channels
;
2060 else if(format
== AL_FORMAT_REAR_MULAW
)
2062 /* Rear is 2 channels */
2065 else if(format
== AL_FORMAT_REAR8
)
2067 else if(format
== AL_FORMAT_REAR16
)
2069 else if(format
== AL_FORMAT_REAR32
)
2073 ALuint bytes
= aluBytesFromFormat(format
);
2074 offset
/= bytes
* channels
;
2080 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2084 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2086 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2087 Context
->SourceMap
.array
[pos
].value
= NULL
;
2089 // For each buffer in the source's queue, decrement its reference counter and remove it
2090 while(temp
->queue
!= NULL
)
2092 ALbufferlistitem
*BufferList
= temp
->queue
;
2093 temp
->queue
= BufferList
->next
;
2095 if(BufferList
->buffer
!= NULL
)
2096 BufferList
->buffer
->refcount
--;
2100 for(j
= 0;j
< MAX_SENDS
;++j
)
2102 if(temp
->Send
[j
].Slot
)
2103 temp
->Send
[j
].Slot
->refcount
--;
2104 temp
->Send
[j
].Slot
= NULL
;
2107 // Release source structure
2108 ALTHUNK_REMOVEENTRY(temp
->source
);
2109 memset(temp
, 0, sizeof(ALsource
));