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
->state
= AL_STOPPED
;
1326 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1327 Source
->position
= 0;
1328 Source
->position_fraction
= 0;
1329 Source
->lOffset
= 0;
1333 if(Source
->state
!= AL_PAUSED
)
1335 Source
->state
= AL_PLAYING
;
1336 Source
->position
= 0;
1337 Source
->position_fraction
= 0;
1338 Source
->BuffersPlayed
= 0;
1340 Source
->Buffer
= Source
->queue
->buffer
;
1343 Source
->state
= AL_PLAYING
;
1345 // Check if an Offset has been set
1347 ApplyOffset(Source
);
1349 // If device is disconnected, go right to stopped
1350 if(!Context
->Device
->Connected
)
1352 Source
->state
= AL_STOPPED
;
1353 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1354 Source
->position
= 0;
1355 Source
->position_fraction
= 0;
1359 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1361 if(Context
->ActiveSources
[j
] == Source
)
1364 if(j
== Context
->ActiveSourceCount
)
1365 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1370 ProcessContext(Context
);
1373 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1375 alSourcePausev(1, &source
);
1378 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1380 ALCcontext
*Context
;
1384 Context
= GetContextSuspended();
1385 if(!Context
) return;
1389 alSetError(Context
, AL_INVALID_VALUE
);
1392 if(n
> 0 && !sources
)
1394 alSetError(Context
, AL_INVALID_VALUE
);
1398 // Check all the Sources are valid
1399 for(i
= 0;i
< n
;i
++)
1401 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1403 alSetError(Context
, AL_INVALID_NAME
);
1408 for(i
= 0;i
< n
;i
++)
1410 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1411 if(Source
->state
== AL_PLAYING
)
1412 Source
->state
= AL_PAUSED
;
1416 ProcessContext(Context
);
1419 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1421 alSourceStopv(1, &source
);
1424 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1426 ALCcontext
*Context
;
1430 Context
= GetContextSuspended();
1431 if(!Context
) return;
1435 alSetError(Context
, AL_INVALID_VALUE
);
1438 if(n
> 0 && !sources
)
1440 alSetError(Context
, AL_INVALID_VALUE
);
1444 // Check all the Sources are valid
1445 for(i
= 0;i
< n
;i
++)
1447 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1449 alSetError(Context
, AL_INVALID_NAME
);
1454 for(i
= 0;i
< n
;i
++)
1456 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1457 if(Source
->state
!= AL_INITIAL
)
1459 Source
->state
= AL_STOPPED
;
1460 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1462 Source
->lOffset
= 0;
1466 ProcessContext(Context
);
1469 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1471 alSourceRewindv(1, &source
);
1474 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1476 ALCcontext
*Context
;
1480 Context
= GetContextSuspended();
1481 if(!Context
) return;
1485 alSetError(Context
, AL_INVALID_VALUE
);
1488 if(n
> 0 && !sources
)
1490 alSetError(Context
, AL_INVALID_VALUE
);
1494 // Check all the Sources are valid
1495 for(i
= 0;i
< n
;i
++)
1497 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1499 alSetError(Context
, AL_INVALID_NAME
);
1504 for(i
= 0;i
< n
;i
++)
1506 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1507 if(Source
->state
!= AL_INITIAL
)
1509 Source
->state
= AL_INITIAL
;
1510 Source
->position
= 0;
1511 Source
->position_fraction
= 0;
1512 Source
->BuffersPlayed
= 0;
1514 Source
->Buffer
= Source
->queue
->buffer
;
1516 Source
->lOffset
= 0;
1520 ProcessContext(Context
);
1524 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1526 ALCcontext
*Context
;
1531 ALbufferlistitem
*BufferListStart
;
1532 ALbufferlistitem
*BufferList
;
1539 Context
= GetContextSuspended();
1540 if(!Context
) return;
1544 alSetError(Context
, AL_INVALID_VALUE
);
1548 // Check that all buffers are valid or zero and that the source is valid
1550 // Check that this is a valid source
1551 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1553 alSetError(Context
, AL_INVALID_NAME
);
1557 // Check that this is not a STATIC Source
1558 if(Source
->lSourceType
== AL_STATIC
)
1560 // Invalid Source Type (can't queue on a Static Source)
1561 alSetError(Context
, AL_INVALID_OPERATION
);
1565 device
= Context
->Device
;
1570 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1571 BufferList
= Source
->queue
;
1574 if(BufferList
->buffer
)
1576 Frequency
= BufferList
->buffer
->frequency
;
1577 Format
= BufferList
->buffer
->eOriginalFormat
;
1580 BufferList
= BufferList
->next
;
1583 for(i
= 0;i
< n
;i
++)
1588 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1590 alSetError(Context
, AL_INVALID_NAME
);
1594 if(Frequency
== -1 && Format
== -1)
1596 Frequency
= buffer
->frequency
;
1597 Format
= buffer
->eOriginalFormat
;
1599 if(aluChannelsFromFormat(buffer
->format
) == 1)
1600 Source
->Update
= CalcSourceParams
;
1602 Source
->Update
= CalcNonAttnSourceParams
;
1604 Source
->Mix
= MixSource
;
1606 Source
->NeedsUpdate
= AL_TRUE
;
1608 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1610 alSetError(Context
, AL_INVALID_OPERATION
);
1615 // Change Source Type
1616 Source
->lSourceType
= AL_STREAMING
;
1618 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1620 // All buffers are valid - so add them to the list
1621 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1622 BufferListStart
->buffer
= buffer
;
1623 BufferListStart
->next
= NULL
;
1625 // Increment reference counter for buffer
1626 if(buffer
) buffer
->refcount
++;
1628 BufferList
= BufferListStart
;
1630 for(i
= 1;i
< n
;i
++)
1632 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1634 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1635 BufferList
->next
->buffer
= buffer
;
1636 BufferList
->next
->next
= NULL
;
1638 // Increment reference counter for buffer
1639 if(buffer
) buffer
->refcount
++;
1641 BufferList
= BufferList
->next
;
1644 if(Source
->queue
== NULL
)
1646 Source
->queue
= BufferListStart
;
1647 // Update Current Buffer
1648 Source
->Buffer
= BufferListStart
->buffer
;
1652 // Find end of queue
1653 BufferList
= Source
->queue
;
1654 while(BufferList
->next
!= NULL
)
1655 BufferList
= BufferList
->next
;
1657 BufferList
->next
= BufferListStart
;
1660 // Update number of buffers in queue
1661 Source
->BuffersInQueue
+= n
;
1664 ProcessContext(Context
);
1668 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1669 // an array of buffer IDs that are to be filled with the names of the buffers removed
1670 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1672 ALCcontext
*Context
;
1675 ALbufferlistitem
*BufferList
;
1680 Context
= GetContextSuspended();
1681 if(!Context
) return;
1685 alSetError(Context
, AL_INVALID_VALUE
);
1689 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1691 alSetError(Context
, AL_INVALID_NAME
);
1695 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1696 (ALuint
)n
> Source
->BuffersPlayed
)
1698 // Some buffers can't be unqueue because they have not been processed
1699 alSetError(Context
, AL_INVALID_VALUE
);
1703 for(i
= 0;i
< n
;i
++)
1705 BufferList
= Source
->queue
;
1706 Source
->queue
= BufferList
->next
;
1708 if(BufferList
->buffer
)
1710 // Record name of buffer
1711 buffers
[i
] = BufferList
->buffer
->buffer
;
1712 // Decrement buffer reference counter
1713 BufferList
->buffer
->refcount
--;
1718 // Release memory for buffer list item
1720 Source
->BuffersInQueue
--;
1723 if(Source
->state
!= AL_PLAYING
)
1726 Source
->Buffer
= Source
->queue
->buffer
;
1728 Source
->Buffer
= NULL
;
1730 Source
->BuffersPlayed
-= n
;
1733 ProcessContext(Context
);
1737 static ALvoid
InitSourceParams(ALsource
*Source
)
1739 Source
->flInnerAngle
= 360.0f
;
1740 Source
->flOuterAngle
= 360.0f
;
1741 Source
->flPitch
= 1.0f
;
1742 Source
->vPosition
[0] = 0.0f
;
1743 Source
->vPosition
[1] = 0.0f
;
1744 Source
->vPosition
[2] = 0.0f
;
1745 Source
->vOrientation
[0] = 0.0f
;
1746 Source
->vOrientation
[1] = 0.0f
;
1747 Source
->vOrientation
[2] = 0.0f
;
1748 Source
->vVelocity
[0] = 0.0f
;
1749 Source
->vVelocity
[1] = 0.0f
;
1750 Source
->vVelocity
[2] = 0.0f
;
1751 Source
->flRefDistance
= 1.0f
;
1752 Source
->flMaxDistance
= FLT_MAX
;
1753 Source
->flRollOffFactor
= 1.0f
;
1754 Source
->bLooping
= AL_FALSE
;
1755 Source
->flGain
= 1.0f
;
1756 Source
->flMinGain
= 0.0f
;
1757 Source
->flMaxGain
= 1.0f
;
1758 Source
->flOuterGain
= 0.0f
;
1759 Source
->OuterGainHF
= 1.0f
;
1761 Source
->DryGainHFAuto
= AL_TRUE
;
1762 Source
->WetGainAuto
= AL_TRUE
;
1763 Source
->WetGainHFAuto
= AL_TRUE
;
1764 Source
->AirAbsorptionFactor
= 0.0f
;
1765 Source
->RoomRolloffFactor
= 0.0f
;
1766 Source
->DopplerFactor
= 1.0f
;
1768 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1770 Source
->Resampler
= DefaultResampler
;
1772 Source
->state
= AL_INITIAL
;
1773 Source
->lSourceType
= AL_UNDETERMINED
;
1775 Source
->NeedsUpdate
= AL_TRUE
;
1777 Source
->Buffer
= NULL
;
1784 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1785 The offset is relative to the start of the queue (not the start of the current buffer)
1787 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1789 ALbufferlistitem
*BufferList
;
1790 ALbuffer
*Buffer
= NULL
;
1792 ALint Channels
, Bytes
;
1793 ALuint readPos
, writePos
;
1794 ALenum OriginalFormat
;
1795 ALuint TotalBufferDataSize
;
1798 // Find the first non-NULL Buffer in the Queue
1799 BufferList
= Source
->queue
;
1802 if(BufferList
->buffer
)
1804 Buffer
= BufferList
->buffer
;
1807 BufferList
= BufferList
->next
;
1810 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1817 // Get Current Buffer Size and frequency (in milliseconds)
1818 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1819 OriginalFormat
= Buffer
->eOriginalFormat
;
1820 Channels
= aluChannelsFromFormat(Buffer
->format
);
1821 Bytes
= aluBytesFromFormat(Buffer
->format
);
1823 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1824 readPos
= Source
->position
* Channels
* Bytes
;
1825 // Add byte length of any processed buffers in the queue
1826 TotalBufferDataSize
= 0;
1827 BufferList
= Source
->queue
;
1828 for(i
= 0;BufferList
;i
++)
1830 if(BufferList
->buffer
)
1832 if(i
< Source
->BuffersPlayed
)
1833 readPos
+= BufferList
->buffer
->size
;
1834 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1836 BufferList
= BufferList
->next
;
1838 if(Source
->state
== AL_PLAYING
)
1839 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1843 if(Source
->bLooping
)
1845 readPos
%= TotalBufferDataSize
;
1846 writePos
%= TotalBufferDataSize
;
1850 // Wrap positions back to 0
1851 if(readPos
>= TotalBufferDataSize
)
1853 if(writePos
>= TotalBufferDataSize
)
1860 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1861 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1863 case AL_SAMPLE_OFFSET
:
1864 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1865 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1866 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1868 case AL_BYTE_OFFSET
:
1869 case AL_BYTE_RW_OFFSETS_SOFT
:
1870 // Take into account the original format of the Buffer
1871 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1872 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1874 // Round down to nearest ADPCM block
1875 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1876 if(Source
->state
== AL_PLAYING
)
1878 // Round up to nearest ADPCM block
1879 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1882 offset
[1] = offset
[0];
1884 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1885 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1886 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1887 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1888 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1889 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1891 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1892 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1894 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1896 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1897 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1899 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1901 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1902 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1904 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1906 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1907 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1909 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1911 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1912 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1916 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1917 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1918 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1928 Apply a playback offset to the Source. This function will update the queue (to correctly
1929 mark buffers as 'pending' or 'processed' depending upon the new offset.
1931 static ALboolean
ApplyOffset(ALsource
*Source
)
1933 ALbufferlistitem
*BufferList
;
1935 ALint lBufferSize
, lTotalBufferSize
;
1936 ALint BuffersPlayed
;
1939 // Get true byte offset
1940 lByteOffset
= GetByteOffset(Source
);
1942 // If the offset is invalid, don't apply it
1943 if(lByteOffset
== -1)
1946 // Sort out the queue (pending and processed states)
1947 BufferList
= Source
->queue
;
1948 lTotalBufferSize
= 0;
1953 Buffer
= BufferList
->buffer
;
1954 lBufferSize
= Buffer
? Buffer
->size
: 0;
1956 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1958 // Offset is past this buffer so increment BuffersPlayed
1961 else if(lTotalBufferSize
<= lByteOffset
)
1963 // Offset is within this buffer
1964 // Set Current Buffer
1965 Source
->Buffer
= BufferList
->buffer
;
1966 Source
->BuffersPlayed
= BuffersPlayed
;
1968 // SW Mixer Positions are in Samples
1969 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1970 aluFrameSizeFromFormat(Buffer
->format
);
1974 // Increment the TotalBufferSize
1975 lTotalBufferSize
+= lBufferSize
;
1977 // Move on to next buffer in the Queue
1978 BufferList
= BufferList
->next
;
1980 // Offset is out of range of the buffer queue
1988 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1989 offset supplied by the application). This takes into account the fact that the buffer format
1990 may have been modifed by AL (e.g 8bit samples are converted to float)
1992 static ALint
GetByteOffset(ALsource
*Source
)
1994 ALbuffer
*Buffer
= NULL
;
1995 ALbufferlistitem
*BufferList
;
1996 ALdouble BufferFreq
;
1997 ALint Channels
, Bytes
;
1998 ALint ByteOffset
= -1;
2000 // Find the first non-NULL Buffer in the Queue
2001 BufferList
= Source
->queue
;
2004 if(BufferList
->buffer
)
2006 Buffer
= BufferList
->buffer
;
2009 BufferList
= BufferList
->next
;
2014 Source
->lOffset
= 0;
2018 BufferFreq
= ((ALdouble
)Buffer
->frequency
);
2019 Channels
= aluChannelsFromFormat(Buffer
->format
);
2020 Bytes
= aluBytesFromFormat(Buffer
->format
);
2022 // Determine the ByteOffset (and ensure it is block aligned)
2023 switch(Source
->lOffsetType
)
2025 case AL_BYTE_OFFSET
:
2026 // Take into consideration the original format
2027 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2029 ByteOffset
*= Channels
* Bytes
;
2032 case AL_SAMPLE_OFFSET
:
2033 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2037 // Note - lOffset is internally stored as Milliseconds
2038 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * BufferFreq
);
2039 ByteOffset
*= Channels
* Bytes
;
2043 Source
->lOffset
= 0;
2048 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2050 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2052 // Round down to nearest ADPCM block
2053 offset
/= 36 * channels
;
2054 // Multiply by compression rate (65 sample frames per block)
2057 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2058 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2059 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2061 /* muLaw has 1 byte per sample */
2062 offset
/= 1 * channels
;
2064 else if(format
== AL_FORMAT_REAR_MULAW
)
2066 /* Rear is 2 channels */
2069 else if(format
== AL_FORMAT_REAR8
)
2071 else if(format
== AL_FORMAT_REAR16
)
2073 else if(format
== AL_FORMAT_REAR32
)
2077 ALuint bytes
= aluBytesFromFormat(format
);
2078 offset
/= bytes
* channels
;
2084 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2088 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2090 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2091 Context
->SourceMap
.array
[pos
].value
= NULL
;
2093 // For each buffer in the source's queue, decrement its reference counter and remove it
2094 while(temp
->queue
!= NULL
)
2096 ALbufferlistitem
*BufferList
= temp
->queue
;
2097 temp
->queue
= BufferList
->next
;
2099 if(BufferList
->buffer
!= NULL
)
2100 BufferList
->buffer
->refcount
--;
2104 for(j
= 0;j
< MAX_SENDS
;++j
)
2106 if(temp
->Send
[j
].Slot
)
2107 temp
->Send
[j
].Slot
->refcount
--;
2108 temp
->Send
[j
].Slot
= NULL
;
2111 // Release source structure
2112 ALTHUNK_REMOVEENTRY(temp
->source
);
2113 memset(temp
, 0, sizeof(ALsource
));