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
);
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
;
553 BufferListItem
->prev
= NULL
;
555 Source
->queue
= BufferListItem
;
556 Source
->BuffersInQueue
= 1;
558 if(buffer
->FmtChannels
== FmtMono
)
559 Source
->Update
= CalcSourceParams
;
561 Source
->Update
= CalcNonAttnSourceParams
;
563 // Increment reference counter for buffer
568 // Source is now in UNDETERMINED mode
569 Source
->lSourceType
= AL_UNDETERMINED
;
571 Source
->BuffersPlayed
= 0;
573 // Update AL_BUFFER parameter
574 Source
->Buffer
= buffer
;
575 Source
->NeedsUpdate
= AL_TRUE
;
578 alSetError(pContext
, AL_INVALID_VALUE
);
581 alSetError(pContext
, AL_INVALID_OPERATION
);
584 case AL_SOURCE_STATE
:
586 alSetError(pContext
, AL_INVALID_OPERATION
);
590 case AL_SAMPLE_OFFSET
:
594 Source
->lOffsetType
= eParam
;
596 // Store Offset (convert Seconds into Milliseconds)
597 if(eParam
== AL_SEC_OFFSET
)
598 Source
->lOffset
= lValue
* 1000;
600 Source
->lOffset
= lValue
;
602 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
604 if(ApplyOffset(Source
) == AL_FALSE
)
605 alSetError(pContext
, AL_INVALID_VALUE
);
609 alSetError(pContext
, AL_INVALID_VALUE
);
612 case AL_DIRECT_FILTER
: {
613 ALfilter
*filter
= NULL
;
616 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
620 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
621 Source
->DirectFilter
.filter
= 0;
624 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
625 Source
->NeedsUpdate
= AL_TRUE
;
628 alSetError(pContext
, AL_INVALID_VALUE
);
631 case AL_DIRECT_FILTER_GAINHF_AUTO
:
632 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
634 Source
->DryGainHFAuto
= lValue
;
635 Source
->NeedsUpdate
= AL_TRUE
;
638 alSetError(pContext
, AL_INVALID_VALUE
);
641 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
642 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
644 Source
->WetGainAuto
= lValue
;
645 Source
->NeedsUpdate
= AL_TRUE
;
648 alSetError(pContext
, AL_INVALID_VALUE
);
651 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
652 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
654 Source
->WetGainHFAuto
= lValue
;
655 Source
->NeedsUpdate
= AL_TRUE
;
658 alSetError(pContext
, AL_INVALID_VALUE
);
661 case AL_DISTANCE_MODEL
:
662 if(lValue
== AL_NONE
||
663 lValue
== AL_INVERSE_DISTANCE
||
664 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
665 lValue
== AL_LINEAR_DISTANCE
||
666 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
667 lValue
== AL_EXPONENT_DISTANCE
||
668 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
670 Source
->DistanceModel
= lValue
;
671 if(pContext
->SourceDistanceModel
)
672 Source
->NeedsUpdate
= AL_TRUE
;
675 alSetError(pContext
, AL_INVALID_VALUE
);
679 alSetError(pContext
, AL_INVALID_ENUM
);
684 alSetError(pContext
, AL_INVALID_NAME
);
686 ProcessContext(pContext
);
690 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
692 ALCcontext
*pContext
;
695 pContext
= GetContextSuspended();
696 if(!pContext
) return;
698 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
700 ALCdevice
*device
= pContext
->Device
;
707 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
710 case AL_AUXILIARY_SEND_FILTER
: {
711 ALeffectslot
*ALEffectSlot
= NULL
;
712 ALfilter
*ALFilter
= NULL
;
714 if((ALuint
)lValue2
< device
->NumAuxSends
&&
716 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
718 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
720 /* Release refcount on the previous slot, and add one for
722 if(Source
->Send
[lValue2
].Slot
)
723 Source
->Send
[lValue2
].Slot
->refcount
--;
724 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
725 if(Source
->Send
[lValue2
].Slot
)
726 Source
->Send
[lValue2
].Slot
->refcount
++;
731 Source
->Send
[lValue2
].WetFilter
.type
= 0;
732 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
735 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
736 Source
->NeedsUpdate
= AL_TRUE
;
739 alSetError(pContext
, AL_INVALID_VALUE
);
743 alSetError(pContext
, AL_INVALID_ENUM
);
748 alSetError(pContext
, AL_INVALID_NAME
);
750 ProcessContext(pContext
);
754 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
756 ALCcontext
*pContext
;
758 pContext
= GetContextSuspended();
759 if(!pContext
) return;
763 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
767 case AL_SOURCE_RELATIVE
:
768 case AL_CONE_INNER_ANGLE
:
769 case AL_CONE_OUTER_ANGLE
:
772 case AL_SOURCE_STATE
:
774 case AL_SAMPLE_OFFSET
:
776 case AL_MAX_DISTANCE
:
777 case AL_ROLLOFF_FACTOR
:
778 case AL_REFERENCE_DISTANCE
:
779 case AL_DIRECT_FILTER
:
780 case AL_DIRECT_FILTER_GAINHF_AUTO
:
781 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
782 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
783 case AL_DISTANCE_MODEL
:
784 alSourcei(source
, eParam
, plValues
[0]);
790 case AL_AUXILIARY_SEND_FILTER
:
791 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
795 alSetError(pContext
, AL_INVALID_ENUM
);
800 alSetError(pContext
, AL_INVALID_NAME
);
803 alSetError(pContext
, AL_INVALID_VALUE
);
805 ProcessContext(pContext
);
809 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
811 ALCcontext
*pContext
;
816 pContext
= GetContextSuspended();
817 if(!pContext
) return;
821 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
826 *pflValue
= Source
->flPitch
;
830 *pflValue
= Source
->flGain
;
834 *pflValue
= Source
->flMinGain
;
838 *pflValue
= Source
->flMaxGain
;
841 case AL_MAX_DISTANCE
:
842 *pflValue
= Source
->flMaxDistance
;
845 case AL_ROLLOFF_FACTOR
:
846 *pflValue
= Source
->flRollOffFactor
;
849 case AL_CONE_OUTER_GAIN
:
850 *pflValue
= Source
->flOuterGain
;
853 case AL_CONE_OUTER_GAINHF
:
854 *pflValue
= Source
->OuterGainHF
;
858 case AL_SAMPLE_OFFSET
:
860 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
861 pContext
->Device
->Frequency
;
862 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
863 *pflValue
= Offsets
[0];
866 case AL_CONE_INNER_ANGLE
:
867 *pflValue
= Source
->flInnerAngle
;
870 case AL_CONE_OUTER_ANGLE
:
871 *pflValue
= Source
->flOuterAngle
;
874 case AL_REFERENCE_DISTANCE
:
875 *pflValue
= Source
->flRefDistance
;
878 case AL_AIR_ABSORPTION_FACTOR
:
879 *pflValue
= Source
->AirAbsorptionFactor
;
882 case AL_ROOM_ROLLOFF_FACTOR
:
883 *pflValue
= Source
->RoomRolloffFactor
;
886 case AL_DOPPLER_FACTOR
:
887 *pflValue
= Source
->DopplerFactor
;
891 alSetError(pContext
, AL_INVALID_ENUM
);
896 alSetError(pContext
, AL_INVALID_NAME
);
899 alSetError(pContext
, AL_INVALID_VALUE
);
901 ProcessContext(pContext
);
905 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
907 ALCcontext
*pContext
;
910 pContext
= GetContextSuspended();
911 if(!pContext
) return;
913 if(pflValue1
&& pflValue2
&& pflValue3
)
915 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
920 *pflValue1
= Source
->vPosition
[0];
921 *pflValue2
= Source
->vPosition
[1];
922 *pflValue3
= Source
->vPosition
[2];
926 *pflValue1
= Source
->vVelocity
[0];
927 *pflValue2
= Source
->vVelocity
[1];
928 *pflValue3
= Source
->vVelocity
[2];
932 *pflValue1
= Source
->vOrientation
[0];
933 *pflValue2
= Source
->vOrientation
[1];
934 *pflValue3
= Source
->vOrientation
[2];
938 alSetError(pContext
, AL_INVALID_ENUM
);
943 alSetError(pContext
, AL_INVALID_NAME
);
946 alSetError(pContext
, AL_INVALID_VALUE
);
948 ProcessContext(pContext
);
952 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
954 ALCcontext
*pContext
;
959 pContext
= GetContextSuspended();
960 if(!pContext
) return;
964 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
972 case AL_MAX_DISTANCE
:
973 case AL_ROLLOFF_FACTOR
:
974 case AL_DOPPLER_FACTOR
:
975 case AL_CONE_OUTER_GAIN
:
977 case AL_SAMPLE_OFFSET
:
979 case AL_CONE_INNER_ANGLE
:
980 case AL_CONE_OUTER_ANGLE
:
981 case AL_REFERENCE_DISTANCE
:
982 case AL_CONE_OUTER_GAINHF
:
983 case AL_AIR_ABSORPTION_FACTOR
:
984 case AL_ROOM_ROLLOFF_FACTOR
:
985 alGetSourcef(source
, eParam
, pflValues
);
991 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
994 case AL_SAMPLE_RW_OFFSETS_SOFT
:
995 case AL_BYTE_RW_OFFSETS_SOFT
:
996 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
997 pContext
->Device
->Frequency
;
998 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
999 pflValues
[0] = Offsets
[0];
1000 pflValues
[1] = Offsets
[1];
1004 alSetError(pContext
, AL_INVALID_ENUM
);
1009 alSetError(pContext
, AL_INVALID_NAME
);
1012 alSetError(pContext
, AL_INVALID_VALUE
);
1014 ProcessContext(pContext
);
1018 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1020 ALCcontext
*pContext
;
1022 ALdouble Offsets
[2];
1025 pContext
= GetContextSuspended();
1026 if(!pContext
) return;
1030 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1034 case AL_MAX_DISTANCE
:
1035 *plValue
= (ALint
)Source
->flMaxDistance
;
1038 case AL_ROLLOFF_FACTOR
:
1039 *plValue
= (ALint
)Source
->flRollOffFactor
;
1042 case AL_REFERENCE_DISTANCE
:
1043 *plValue
= (ALint
)Source
->flRefDistance
;
1046 case AL_SOURCE_RELATIVE
:
1047 *plValue
= Source
->bHeadRelative
;
1050 case AL_CONE_INNER_ANGLE
:
1051 *plValue
= (ALint
)Source
->flInnerAngle
;
1054 case AL_CONE_OUTER_ANGLE
:
1055 *plValue
= (ALint
)Source
->flOuterAngle
;
1059 *plValue
= Source
->bLooping
;
1063 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1066 case AL_SOURCE_STATE
:
1067 *plValue
= Source
->state
;
1070 case AL_BUFFERS_QUEUED
:
1071 *plValue
= Source
->BuffersInQueue
;
1074 case AL_BUFFERS_PROCESSED
:
1075 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1077 /* Buffers on a looping source are in a perpetual state
1078 * of PENDING, so don't report any as PROCESSED */
1082 *plValue
= Source
->BuffersPlayed
;
1085 case AL_SOURCE_TYPE
:
1086 *plValue
= Source
->lSourceType
;
1090 case AL_SAMPLE_OFFSET
:
1091 case AL_BYTE_OFFSET
:
1092 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1093 pContext
->Device
->Frequency
;
1094 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1095 *plValue
= (ALint
)Offsets
[0];
1098 case AL_DIRECT_FILTER
:
1099 *plValue
= Source
->DirectFilter
.filter
;
1102 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1103 *plValue
= Source
->DryGainHFAuto
;
1106 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1107 *plValue
= Source
->WetGainAuto
;
1110 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1111 *plValue
= Source
->WetGainHFAuto
;
1114 case AL_DOPPLER_FACTOR
:
1115 *plValue
= (ALint
)Source
->DopplerFactor
;
1118 case AL_DISTANCE_MODEL
:
1119 *plValue
= Source
->DistanceModel
;
1123 alSetError(pContext
, AL_INVALID_ENUM
);
1128 alSetError(pContext
, AL_INVALID_NAME
);
1131 alSetError(pContext
, AL_INVALID_VALUE
);
1133 ProcessContext(pContext
);
1137 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1139 ALCcontext
*pContext
;
1142 pContext
= GetContextSuspended();
1143 if(!pContext
) return;
1145 if(plValue1
&& plValue2
&& plValue3
)
1147 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1152 *plValue1
= (ALint
)Source
->vPosition
[0];
1153 *plValue2
= (ALint
)Source
->vPosition
[1];
1154 *plValue3
= (ALint
)Source
->vPosition
[2];
1158 *plValue1
= (ALint
)Source
->vVelocity
[0];
1159 *plValue2
= (ALint
)Source
->vVelocity
[1];
1160 *plValue3
= (ALint
)Source
->vVelocity
[2];
1164 *plValue1
= (ALint
)Source
->vOrientation
[0];
1165 *plValue2
= (ALint
)Source
->vOrientation
[1];
1166 *plValue3
= (ALint
)Source
->vOrientation
[2];
1170 alSetError(pContext
, AL_INVALID_ENUM
);
1175 alSetError(pContext
, AL_INVALID_NAME
);
1178 alSetError(pContext
, AL_INVALID_VALUE
);
1180 ProcessContext(pContext
);
1184 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1186 ALCcontext
*pContext
;
1188 ALdouble Offsets
[2];
1191 pContext
= GetContextSuspended();
1192 if(!pContext
) return;
1196 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1200 case AL_SOURCE_RELATIVE
:
1201 case AL_CONE_INNER_ANGLE
:
1202 case AL_CONE_OUTER_ANGLE
:
1205 case AL_SOURCE_STATE
:
1206 case AL_BUFFERS_QUEUED
:
1207 case AL_BUFFERS_PROCESSED
:
1209 case AL_SAMPLE_OFFSET
:
1210 case AL_BYTE_OFFSET
:
1211 case AL_MAX_DISTANCE
:
1212 case AL_ROLLOFF_FACTOR
:
1213 case AL_DOPPLER_FACTOR
:
1214 case AL_REFERENCE_DISTANCE
:
1215 case AL_SOURCE_TYPE
:
1216 case AL_DIRECT_FILTER
:
1217 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1218 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1219 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1220 case AL_DISTANCE_MODEL
:
1221 alGetSourcei(source
, eParam
, plValues
);
1227 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1230 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1231 case AL_BYTE_RW_OFFSETS_SOFT
:
1232 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1233 pContext
->Device
->Frequency
;
1234 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1235 plValues
[0] = (ALint
)Offsets
[0];
1236 plValues
[1] = (ALint
)Offsets
[1];
1240 alSetError(pContext
, AL_INVALID_ENUM
);
1245 alSetError(pContext
, AL_INVALID_NAME
);
1248 alSetError(pContext
, AL_INVALID_VALUE
);
1250 ProcessContext(pContext
);
1254 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1256 alSourcePlayv(1, &source
);
1259 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1261 ALCcontext
*Context
;
1263 ALbufferlistitem
*BufferList
;
1266 Context
= GetContextSuspended();
1267 if(!Context
) return;
1271 alSetError(Context
, AL_INVALID_VALUE
);
1274 if(n
> 0 && !sources
)
1276 alSetError(Context
, AL_INVALID_VALUE
);
1280 // Check that all the Sources are valid
1281 for(i
= 0;i
< n
;i
++)
1283 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1285 alSetError(Context
, AL_INVALID_NAME
);
1290 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1295 newcount
= Context
->MaxActiveSources
<< 1;
1297 temp
= realloc(Context
->ActiveSources
,
1298 sizeof(*Context
->ActiveSources
) * newcount
);
1301 alSetError(Context
, AL_OUT_OF_MEMORY
);
1305 Context
->ActiveSources
= temp
;
1306 Context
->MaxActiveSources
= newcount
;
1309 for(i
= 0;i
< n
;i
++)
1311 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1313 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1314 BufferList
= Source
->queue
;
1317 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1319 BufferList
= BufferList
->next
;
1324 Source
->state
= AL_STOPPED
;
1325 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1326 Source
->position
= 0;
1327 Source
->position_fraction
= 0;
1328 Source
->lOffset
= 0;
1332 if(Source
->state
!= AL_PAUSED
)
1334 Source
->state
= AL_PLAYING
;
1335 Source
->position
= 0;
1336 Source
->position_fraction
= 0;
1337 Source
->BuffersPlayed
= 0;
1339 Source
->Buffer
= Source
->queue
->buffer
;
1342 Source
->state
= AL_PLAYING
;
1344 // Check if an Offset has been set
1346 ApplyOffset(Source
);
1348 // If device is disconnected, go right to stopped
1349 if(!Context
->Device
->Connected
)
1351 Source
->state
= AL_STOPPED
;
1352 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1353 Source
->position
= 0;
1354 Source
->position_fraction
= 0;
1358 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1360 if(Context
->ActiveSources
[j
] == Source
)
1363 if(j
== Context
->ActiveSourceCount
)
1364 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1369 ProcessContext(Context
);
1372 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1374 alSourcePausev(1, &source
);
1377 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1379 ALCcontext
*Context
;
1383 Context
= GetContextSuspended();
1384 if(!Context
) return;
1388 alSetError(Context
, AL_INVALID_VALUE
);
1391 if(n
> 0 && !sources
)
1393 alSetError(Context
, AL_INVALID_VALUE
);
1397 // Check all the Sources are valid
1398 for(i
= 0;i
< n
;i
++)
1400 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1402 alSetError(Context
, AL_INVALID_NAME
);
1407 for(i
= 0;i
< n
;i
++)
1409 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1410 if(Source
->state
== AL_PLAYING
)
1411 Source
->state
= AL_PAUSED
;
1415 ProcessContext(Context
);
1418 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1420 alSourceStopv(1, &source
);
1423 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1425 ALCcontext
*Context
;
1429 Context
= GetContextSuspended();
1430 if(!Context
) return;
1434 alSetError(Context
, AL_INVALID_VALUE
);
1437 if(n
> 0 && !sources
)
1439 alSetError(Context
, AL_INVALID_VALUE
);
1443 // Check all the Sources are valid
1444 for(i
= 0;i
< n
;i
++)
1446 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1448 alSetError(Context
, AL_INVALID_NAME
);
1453 for(i
= 0;i
< n
;i
++)
1455 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1456 if(Source
->state
!= AL_INITIAL
)
1458 Source
->state
= AL_STOPPED
;
1459 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1461 Source
->lOffset
= 0;
1465 ProcessContext(Context
);
1468 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1470 alSourceRewindv(1, &source
);
1473 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1475 ALCcontext
*Context
;
1479 Context
= GetContextSuspended();
1480 if(!Context
) return;
1484 alSetError(Context
, AL_INVALID_VALUE
);
1487 if(n
> 0 && !sources
)
1489 alSetError(Context
, AL_INVALID_VALUE
);
1493 // Check all the Sources are valid
1494 for(i
= 0;i
< n
;i
++)
1496 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1498 alSetError(Context
, AL_INVALID_NAME
);
1503 for(i
= 0;i
< n
;i
++)
1505 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1506 if(Source
->state
!= AL_INITIAL
)
1508 Source
->state
= AL_INITIAL
;
1509 Source
->position
= 0;
1510 Source
->position_fraction
= 0;
1511 Source
->BuffersPlayed
= 0;
1513 Source
->Buffer
= Source
->queue
->buffer
;
1515 Source
->lOffset
= 0;
1519 ProcessContext(Context
);
1523 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1525 ALCcontext
*Context
;
1530 ALbufferlistitem
*BufferListStart
;
1531 ALbufferlistitem
*BufferList
;
1538 Context
= GetContextSuspended();
1539 if(!Context
) return;
1543 alSetError(Context
, AL_INVALID_VALUE
);
1547 // Check that all buffers are valid or zero and that the source is valid
1549 // Check that this is a valid source
1550 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1552 alSetError(Context
, AL_INVALID_NAME
);
1556 // Check that this is not a STATIC Source
1557 if(Source
->lSourceType
== AL_STATIC
)
1559 // Invalid Source Type (can't queue on a Static Source)
1560 alSetError(Context
, AL_INVALID_OPERATION
);
1564 device
= Context
->Device
;
1569 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1570 BufferList
= Source
->queue
;
1573 if(BufferList
->buffer
)
1575 Frequency
= BufferList
->buffer
->Frequency
;
1576 Format
= BufferList
->buffer
->OriginalFormat
;
1579 BufferList
= BufferList
->next
;
1582 for(i
= 0;i
< n
;i
++)
1587 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1589 alSetError(Context
, AL_INVALID_NAME
);
1593 if(Frequency
== -1 && Format
== -1)
1595 Frequency
= buffer
->Frequency
;
1596 Format
= buffer
->OriginalFormat
;
1598 if(buffer
->FmtChannels
== FmtMono
)
1599 Source
->Update
= CalcSourceParams
;
1601 Source
->Update
= CalcNonAttnSourceParams
;
1603 Source
->NeedsUpdate
= AL_TRUE
;
1605 else if(Frequency
!= buffer
->Frequency
|| Format
!= buffer
->OriginalFormat
)
1607 alSetError(Context
, AL_INVALID_OPERATION
);
1612 // Change Source Type
1613 Source
->lSourceType
= AL_STREAMING
;
1615 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1617 // All buffers are valid - so add them to the list
1618 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1619 BufferListStart
->buffer
= buffer
;
1620 BufferListStart
->next
= NULL
;
1621 BufferListStart
->prev
= NULL
;
1623 // Increment reference counter for buffer
1624 if(buffer
) buffer
->refcount
++;
1626 BufferList
= BufferListStart
;
1628 for(i
= 1;i
< n
;i
++)
1630 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1632 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1633 BufferList
->next
->buffer
= buffer
;
1634 BufferList
->next
->next
= NULL
;
1635 BufferList
->next
->prev
= BufferList
;
1637 // Increment reference counter for buffer
1638 if(buffer
) buffer
->refcount
++;
1640 BufferList
= BufferList
->next
;
1643 if(Source
->queue
== NULL
)
1645 Source
->queue
= BufferListStart
;
1646 // Update Current Buffer
1647 Source
->Buffer
= BufferListStart
->buffer
;
1651 // Find end of queue
1652 BufferList
= Source
->queue
;
1653 while(BufferList
->next
!= NULL
)
1654 BufferList
= BufferList
->next
;
1656 BufferList
->next
= BufferListStart
;
1657 BufferList
->next
->prev
= BufferList
;
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 Source
->queue
->prev
= NULL
;
1725 if(Source
->state
!= AL_PLAYING
)
1728 Source
->Buffer
= Source
->queue
->buffer
;
1730 Source
->Buffer
= NULL
;
1732 Source
->BuffersPlayed
-= n
;
1735 ProcessContext(Context
);
1739 static ALvoid
InitSourceParams(ALsource
*Source
)
1741 Source
->flInnerAngle
= 360.0f
;
1742 Source
->flOuterAngle
= 360.0f
;
1743 Source
->flPitch
= 1.0f
;
1744 Source
->vPosition
[0] = 0.0f
;
1745 Source
->vPosition
[1] = 0.0f
;
1746 Source
->vPosition
[2] = 0.0f
;
1747 Source
->vOrientation
[0] = 0.0f
;
1748 Source
->vOrientation
[1] = 0.0f
;
1749 Source
->vOrientation
[2] = 0.0f
;
1750 Source
->vVelocity
[0] = 0.0f
;
1751 Source
->vVelocity
[1] = 0.0f
;
1752 Source
->vVelocity
[2] = 0.0f
;
1753 Source
->flRefDistance
= 1.0f
;
1754 Source
->flMaxDistance
= FLT_MAX
;
1755 Source
->flRollOffFactor
= 1.0f
;
1756 Source
->bLooping
= AL_FALSE
;
1757 Source
->flGain
= 1.0f
;
1758 Source
->flMinGain
= 0.0f
;
1759 Source
->flMaxGain
= 1.0f
;
1760 Source
->flOuterGain
= 0.0f
;
1761 Source
->OuterGainHF
= 1.0f
;
1763 Source
->DryGainHFAuto
= AL_TRUE
;
1764 Source
->WetGainAuto
= AL_TRUE
;
1765 Source
->WetGainHFAuto
= AL_TRUE
;
1766 Source
->AirAbsorptionFactor
= 0.0f
;
1767 Source
->RoomRolloffFactor
= 0.0f
;
1768 Source
->DopplerFactor
= 1.0f
;
1770 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1772 Source
->Resampler
= DefaultResampler
;
1774 Source
->state
= AL_INITIAL
;
1775 Source
->lSourceType
= AL_UNDETERMINED
;
1777 Source
->NeedsUpdate
= AL_TRUE
;
1779 Source
->Buffer
= NULL
;
1786 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1787 The offset is relative to the start of the queue (not the start of the current buffer)
1789 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1791 ALbufferlistitem
*BufferList
;
1792 ALbuffer
*Buffer
= NULL
;
1794 ALint Channels
, Bytes
;
1795 ALuint readPos
, writePos
;
1796 ALenum OriginalFormat
;
1797 ALuint TotalBufferDataSize
;
1800 // Find the first non-NULL Buffer in the Queue
1801 BufferList
= Source
->queue
;
1804 if(BufferList
->buffer
)
1806 Buffer
= BufferList
->buffer
;
1809 BufferList
= BufferList
->next
;
1812 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1819 // Get Current Buffer Size and frequency (in milliseconds)
1820 BufferFreq
= (ALfloat
)Buffer
->Frequency
;
1821 OriginalFormat
= Buffer
->OriginalFormat
;
1822 Channels
= ChannelsFromFmt(Buffer
->FmtChannels
);
1823 Bytes
= BytesFromFmt(Buffer
->FmtType
);
1825 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1826 readPos
= Source
->position
* Channels
* Bytes
;
1827 // Add byte length of any processed buffers in the queue
1828 TotalBufferDataSize
= 0;
1829 BufferList
= Source
->queue
;
1830 for(i
= 0;BufferList
;i
++)
1832 if(BufferList
->buffer
)
1834 if(i
< Source
->BuffersPlayed
)
1835 readPos
+= BufferList
->buffer
->size
;
1836 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1838 BufferList
= BufferList
->next
;
1840 if(Source
->state
== AL_PLAYING
)
1841 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1845 if(Source
->bLooping
)
1847 readPos
%= TotalBufferDataSize
;
1848 writePos
%= TotalBufferDataSize
;
1852 // Wrap positions back to 0
1853 if(readPos
>= TotalBufferDataSize
)
1855 if(writePos
>= TotalBufferDataSize
)
1862 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1863 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1865 case AL_SAMPLE_OFFSET
:
1866 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1867 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1868 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1870 case AL_BYTE_OFFSET
:
1871 case AL_BYTE_RW_OFFSETS_SOFT
:
1872 // Take into account the original format of the Buffer
1873 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1874 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1876 ALuint FrameBlockSize
= 65 * Bytes
* Channels
;
1877 ALuint BlockSize
= 36 * Channels
;
1879 // Round down to nearest ADPCM block
1880 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1881 if(Source
->state
!= AL_PLAYING
)
1882 offset
[1] = offset
[0];
1885 // Round up to nearest ADPCM block
1886 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1887 FrameBlockSize
* BlockSize
);
1892 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1893 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1894 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1904 Apply a playback offset to the Source. This function will update the queue (to correctly
1905 mark buffers as 'pending' or 'processed' depending upon the new offset.
1907 static ALboolean
ApplyOffset(ALsource
*Source
)
1909 ALbufferlistitem
*BufferList
;
1911 ALint lBufferSize
, lTotalBufferSize
;
1912 ALint BuffersPlayed
;
1915 // Get true byte offset
1916 lByteOffset
= GetByteOffset(Source
);
1918 // If the offset is invalid, don't apply it
1919 if(lByteOffset
== -1)
1922 // Sort out the queue (pending and processed states)
1923 BufferList
= Source
->queue
;
1924 lTotalBufferSize
= 0;
1929 Buffer
= BufferList
->buffer
;
1930 lBufferSize
= Buffer
? Buffer
->size
: 0;
1932 if(lBufferSize
<= lByteOffset
-lTotalBufferSize
)
1934 // Offset is past this buffer so increment BuffersPlayed
1937 else if(lTotalBufferSize
<= lByteOffset
)
1939 // Offset is within this buffer
1940 // Set Current Buffer
1941 Source
->Buffer
= BufferList
->buffer
;
1942 Source
->BuffersPlayed
= BuffersPlayed
;
1944 // SW Mixer Positions are in Samples
1945 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1946 FrameSizeFromFmt(Buffer
->FmtType
, Buffer
->FmtChannels
);
1950 // Increment the TotalBufferSize
1951 lTotalBufferSize
+= lBufferSize
;
1953 // Move on to next buffer in the Queue
1954 BufferList
= BufferList
->next
;
1956 // Offset is out of range of the buffer queue
1964 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1965 offset supplied by the application). This takes into account the fact that the buffer format
1966 may have been modifed by AL (e.g 8bit samples are converted to float)
1968 static ALint
GetByteOffset(ALsource
*Source
)
1970 ALbuffer
*Buffer
= NULL
;
1971 ALbufferlistitem
*BufferList
;
1972 ALint ByteOffset
= -1;
1974 // Find the first non-NULL Buffer in the Queue
1975 BufferList
= Source
->queue
;
1978 if(BufferList
->buffer
)
1980 Buffer
= BufferList
->buffer
;
1983 BufferList
= BufferList
->next
;
1988 Source
->lOffset
= 0;
1992 // Determine the ByteOffset (and ensure it is block aligned)
1993 switch(Source
->lOffsetType
)
1995 case AL_BYTE_OFFSET
:
1996 // Take into consideration the original format
1997 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->OriginalFormat
);
1998 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtType
, Buffer
->FmtChannels
);
2001 case AL_SAMPLE_OFFSET
:
2002 ByteOffset
= Source
->lOffset
* BytesFromFmt(Buffer
->FmtType
);
2006 // Note - lOffset is internally stored as Milliseconds
2007 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * Buffer
->Frequency
);
2008 ByteOffset
*= BytesFromFmt(Buffer
->FmtType
);
2012 Source
->lOffset
= 0;
2017 static ALint
FramesFromBytes(ALint offset
, ALenum format
)
2019 if(format
==AL_FORMAT_MONO_IMA4
)
2021 // Round down to nearest ADPCM block
2023 // Multiply by compression rate (65 sample frames per block)
2026 else if(format
==AL_FORMAT_STEREO_IMA4
)
2032 offset
/= aluFrameSizeFromFormat(format
);
2037 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2041 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2043 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2044 Context
->SourceMap
.array
[pos
].value
= NULL
;
2046 // For each buffer in the source's queue, decrement its reference counter and remove it
2047 while(temp
->queue
!= NULL
)
2049 ALbufferlistitem
*BufferList
= temp
->queue
;
2050 temp
->queue
= BufferList
->next
;
2052 if(BufferList
->buffer
!= NULL
)
2053 BufferList
->buffer
->refcount
--;
2057 for(j
= 0;j
< MAX_SENDS
;++j
)
2059 if(temp
->Send
[j
].Slot
)
2060 temp
->Send
[j
].Slot
->refcount
--;
2061 temp
->Send
[j
].Slot
= NULL
;
2064 // Release source structure
2065 ALTHUNK_REMOVEENTRY(temp
->source
);
2066 memset(temp
, 0, sizeof(ALsource
));