2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
33 #include "alAuxEffectSlot.h"
36 resampler_t DefaultResampler
;
37 const ALsizei ResamplerPadding
[RESAMPLER_MAX
] = {
42 const ALsizei ResamplerPrePadding
[RESAMPLER_MAX
] = {
49 static ALvoid
InitSourceParams(ALsource
*Source
);
50 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum eName
, ALdouble
*Offsets
, ALdouble updateLen
);
51 static ALboolean
ApplyOffset(ALsource
*Source
);
52 static ALint
GetByteOffset(ALsource
*Source
);
53 static ALint
FramesFromBytes(ALint offset
, ALenum format
);
55 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
56 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
57 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
58 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
60 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
65 Context
= GetContextSuspended();
68 Device
= Context
->Device
;
69 if(n
< 0 || IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
70 alSetError(Context
, AL_INVALID_VALUE
);
71 else if((ALuint
)n
> Device
->MaxNoOfSources
- Context
->SourceMap
.size
)
72 alSetError(Context
, AL_INVALID_VALUE
);
78 // Add additional sources to the list
82 ALsource
*source
= calloc(1, sizeof(ALsource
));
85 alSetError(Context
, AL_OUT_OF_MEMORY
);
86 alDeleteSources(i
, sources
);
90 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
91 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
93 if(err
!= AL_NO_ERROR
)
95 ALTHUNK_REMOVEENTRY(source
->source
);
96 memset(source
, 0, sizeof(ALsource
));
99 alSetError(Context
, err
);
100 alDeleteSources(i
, sources
);
104 sources
[i
++] = source
->source
;
105 InitSourceParams(source
);
109 ProcessContext(Context
);
113 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
118 ALbufferlistitem
*BufferList
;
119 ALboolean SourcesValid
= AL_FALSE
;
121 Context
= GetContextSuspended();
125 alSetError(Context
, AL_INVALID_VALUE
);
128 SourcesValid
= AL_TRUE
;
129 // Check that all Sources are valid (and can therefore be deleted)
132 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
134 alSetError(Context
, AL_INVALID_NAME
);
135 SourcesValid
= AL_FALSE
;
143 // All Sources are valid, and can be deleted
146 // Recheck that the Source is valid, because there could be duplicated Source names
147 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) == NULL
)
150 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
152 if(Context
->ActiveSources
[j
] == Source
)
154 ALsizei end
= --(Context
->ActiveSourceCount
);
155 Context
->ActiveSources
[j
] = Context
->ActiveSources
[end
];
160 // For each buffer in the source's queue...
161 while(Source
->queue
!= NULL
)
163 BufferList
= Source
->queue
;
164 Source
->queue
= BufferList
->next
;
166 if(BufferList
->buffer
!= NULL
)
167 BufferList
->buffer
->refcount
--;
171 for(j
= 0;j
< MAX_SENDS
;++j
)
173 if(Source
->Send
[j
].Slot
)
174 Source
->Send
[j
].Slot
->refcount
--;
175 Source
->Send
[j
].Slot
= NULL
;
178 // Remove Source from list of Sources
179 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
180 ALTHUNK_REMOVEENTRY(Source
->source
);
182 memset(Source
,0,sizeof(ALsource
));
187 ProcessContext(Context
);
191 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
196 Context
= GetContextSuspended();
197 if(!Context
) return AL_FALSE
;
199 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
201 ProcessContext(Context
);
207 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
209 ALCcontext
*pContext
;
212 pContext
= GetContextSuspended();
213 if(!pContext
) return;
215 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
222 Source
->flPitch
= flValue
;
223 if(Source
->flPitch
< 0.001f
)
224 Source
->flPitch
= 0.001f
;
225 Source
->NeedsUpdate
= AL_TRUE
;
228 alSetError(pContext
, AL_INVALID_VALUE
);
231 case AL_CONE_INNER_ANGLE
:
232 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
234 Source
->flInnerAngle
= flValue
;
235 Source
->NeedsUpdate
= AL_TRUE
;
238 alSetError(pContext
, AL_INVALID_VALUE
);
241 case AL_CONE_OUTER_ANGLE
:
242 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
244 Source
->flOuterAngle
= flValue
;
245 Source
->NeedsUpdate
= AL_TRUE
;
248 alSetError(pContext
, AL_INVALID_VALUE
);
254 Source
->flGain
= flValue
;
255 Source
->NeedsUpdate
= AL_TRUE
;
258 alSetError(pContext
, AL_INVALID_VALUE
);
261 case AL_MAX_DISTANCE
:
264 Source
->flMaxDistance
= flValue
;
265 Source
->NeedsUpdate
= AL_TRUE
;
268 alSetError(pContext
, AL_INVALID_VALUE
);
271 case AL_ROLLOFF_FACTOR
:
274 Source
->flRollOffFactor
= flValue
;
275 Source
->NeedsUpdate
= AL_TRUE
;
278 alSetError(pContext
, AL_INVALID_VALUE
);
281 case AL_REFERENCE_DISTANCE
:
284 Source
->flRefDistance
= flValue
;
285 Source
->NeedsUpdate
= AL_TRUE
;
288 alSetError(pContext
, AL_INVALID_VALUE
);
292 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
294 Source
->flMinGain
= flValue
;
295 Source
->NeedsUpdate
= AL_TRUE
;
298 alSetError(pContext
, AL_INVALID_VALUE
);
302 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
304 Source
->flMaxGain
= flValue
;
305 Source
->NeedsUpdate
= AL_TRUE
;
308 alSetError(pContext
, AL_INVALID_VALUE
);
311 case AL_CONE_OUTER_GAIN
:
312 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
314 Source
->flOuterGain
= flValue
;
315 Source
->NeedsUpdate
= AL_TRUE
;
318 alSetError(pContext
, AL_INVALID_VALUE
);
321 case AL_CONE_OUTER_GAINHF
:
322 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
324 Source
->OuterGainHF
= flValue
;
325 Source
->NeedsUpdate
= AL_TRUE
;
328 alSetError(pContext
, AL_INVALID_VALUE
);
331 case AL_AIR_ABSORPTION_FACTOR
:
332 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
334 Source
->AirAbsorptionFactor
= flValue
;
335 Source
->NeedsUpdate
= AL_TRUE
;
338 alSetError(pContext
, AL_INVALID_VALUE
);
341 case AL_ROOM_ROLLOFF_FACTOR
:
342 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
344 Source
->RoomRolloffFactor
= flValue
;
345 Source
->NeedsUpdate
= AL_TRUE
;
348 alSetError(pContext
, AL_INVALID_VALUE
);
351 case AL_DOPPLER_FACTOR
:
352 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
354 Source
->DopplerFactor
= flValue
;
355 Source
->NeedsUpdate
= AL_TRUE
;
358 alSetError(pContext
, AL_INVALID_VALUE
);
362 case AL_SAMPLE_OFFSET
:
366 Source
->lOffsetType
= eParam
;
368 // Store Offset (convert Seconds into Milliseconds)
369 if(eParam
== AL_SEC_OFFSET
)
370 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
372 Source
->lOffset
= (ALint
)flValue
;
374 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
376 if(ApplyOffset(Source
) == AL_FALSE
)
377 alSetError(pContext
, AL_INVALID_VALUE
);
381 alSetError(pContext
, AL_INVALID_VALUE
);
385 alSetError(pContext
, AL_INVALID_ENUM
);
391 // Invalid Source Name
392 alSetError(pContext
, AL_INVALID_NAME
);
395 ProcessContext(pContext
);
399 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
401 ALCcontext
*pContext
;
404 pContext
= GetContextSuspended();
405 if(!pContext
) return;
407 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
412 Source
->vPosition
[0] = flValue1
;
413 Source
->vPosition
[1] = flValue2
;
414 Source
->vPosition
[2] = flValue3
;
415 Source
->NeedsUpdate
= AL_TRUE
;
419 Source
->vVelocity
[0] = flValue1
;
420 Source
->vVelocity
[1] = flValue2
;
421 Source
->vVelocity
[2] = flValue3
;
422 Source
->NeedsUpdate
= AL_TRUE
;
426 Source
->vOrientation
[0] = flValue1
;
427 Source
->vOrientation
[1] = flValue2
;
428 Source
->vOrientation
[2] = flValue3
;
429 Source
->NeedsUpdate
= AL_TRUE
;
433 alSetError(pContext
, AL_INVALID_ENUM
);
438 alSetError(pContext
, AL_INVALID_NAME
);
440 ProcessContext(pContext
);
444 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
446 ALCcontext
*pContext
;
448 pContext
= GetContextSuspended();
449 if(!pContext
) return;
453 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
458 case AL_CONE_INNER_ANGLE
:
459 case AL_CONE_OUTER_ANGLE
:
461 case AL_MAX_DISTANCE
:
462 case AL_ROLLOFF_FACTOR
:
463 case AL_REFERENCE_DISTANCE
:
466 case AL_CONE_OUTER_GAIN
:
467 case AL_CONE_OUTER_GAINHF
:
469 case AL_SAMPLE_OFFSET
:
471 case AL_AIR_ABSORPTION_FACTOR
:
472 case AL_ROOM_ROLLOFF_FACTOR
:
473 alSourcef(source
, eParam
, pflValues
[0]);
479 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
483 alSetError(pContext
, AL_INVALID_ENUM
);
488 alSetError(pContext
, AL_INVALID_NAME
);
491 alSetError(pContext
, AL_INVALID_VALUE
);
493 ProcessContext(pContext
);
497 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
499 ALCcontext
*pContext
;
501 ALbufferlistitem
*BufferListItem
;
503 pContext
= GetContextSuspended();
504 if(!pContext
) return;
506 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
508 ALCdevice
*device
= pContext
->Device
;
512 case AL_MAX_DISTANCE
:
513 case AL_ROLLOFF_FACTOR
:
514 case AL_CONE_INNER_ANGLE
:
515 case AL_CONE_OUTER_ANGLE
:
516 case AL_REFERENCE_DISTANCE
:
517 alSourcef(source
, eParam
, (ALfloat
)lValue
);
520 case AL_SOURCE_RELATIVE
:
521 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
523 Source
->bHeadRelative
= (ALboolean
)lValue
;
524 Source
->NeedsUpdate
= AL_TRUE
;
527 alSetError(pContext
, AL_INVALID_VALUE
);
531 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
532 Source
->bLooping
= (ALboolean
)lValue
;
534 alSetError(pContext
, AL_INVALID_VALUE
);
538 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
540 ALbuffer
*buffer
= NULL
;
543 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
545 // Remove all elements in the queue
546 while(Source
->queue
!= NULL
)
548 BufferListItem
= Source
->queue
;
549 Source
->queue
= BufferListItem
->next
;
551 if(BufferListItem
->buffer
)
552 BufferListItem
->buffer
->refcount
--;
553 free(BufferListItem
);
555 Source
->BuffersInQueue
= 0;
557 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
560 // Source is now in STATIC mode
561 Source
->lSourceType
= AL_STATIC
;
563 // Add the selected buffer to the queue
564 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
565 BufferListItem
->buffer
= buffer
;
566 BufferListItem
->next
= NULL
;
567 BufferListItem
->prev
= NULL
;
569 Source
->queue
= BufferListItem
;
570 Source
->BuffersInQueue
= 1;
572 if(buffer
->FmtChannels
== FmtMono
)
573 Source
->Update
= CalcSourceParams
;
575 Source
->Update
= CalcNonAttnSourceParams
;
577 // Increment reference counter for buffer
582 // Source is now in UNDETERMINED mode
583 Source
->lSourceType
= AL_UNDETERMINED
;
585 Source
->BuffersPlayed
= 0;
587 // Update AL_BUFFER parameter
588 Source
->Buffer
= buffer
;
589 Source
->NeedsUpdate
= AL_TRUE
;
592 alSetError(pContext
, AL_INVALID_VALUE
);
595 alSetError(pContext
, AL_INVALID_OPERATION
);
598 case AL_SOURCE_STATE
:
600 alSetError(pContext
, AL_INVALID_OPERATION
);
604 case AL_SAMPLE_OFFSET
:
608 Source
->lOffsetType
= eParam
;
610 // Store Offset (convert Seconds into Milliseconds)
611 if(eParam
== AL_SEC_OFFSET
)
612 Source
->lOffset
= lValue
* 1000;
614 Source
->lOffset
= lValue
;
616 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
618 if(ApplyOffset(Source
) == AL_FALSE
)
619 alSetError(pContext
, AL_INVALID_VALUE
);
623 alSetError(pContext
, AL_INVALID_VALUE
);
626 case AL_DIRECT_FILTER
: {
627 ALfilter
*filter
= NULL
;
630 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
634 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
635 Source
->DirectFilter
.filter
= 0;
638 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
639 Source
->NeedsUpdate
= AL_TRUE
;
642 alSetError(pContext
, AL_INVALID_VALUE
);
645 case AL_DIRECT_FILTER_GAINHF_AUTO
:
646 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
648 Source
->DryGainHFAuto
= lValue
;
649 Source
->NeedsUpdate
= AL_TRUE
;
652 alSetError(pContext
, AL_INVALID_VALUE
);
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
656 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
658 Source
->WetGainAuto
= lValue
;
659 Source
->NeedsUpdate
= AL_TRUE
;
662 alSetError(pContext
, AL_INVALID_VALUE
);
665 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
666 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
668 Source
->WetGainHFAuto
= lValue
;
669 Source
->NeedsUpdate
= AL_TRUE
;
672 alSetError(pContext
, AL_INVALID_VALUE
);
675 case AL_DISTANCE_MODEL
:
676 if(lValue
== AL_NONE
||
677 lValue
== AL_INVERSE_DISTANCE
||
678 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
679 lValue
== AL_LINEAR_DISTANCE
||
680 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
681 lValue
== AL_EXPONENT_DISTANCE
||
682 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
684 Source
->DistanceModel
= lValue
;
685 if(pContext
->SourceDistanceModel
)
686 Source
->NeedsUpdate
= AL_TRUE
;
689 alSetError(pContext
, AL_INVALID_VALUE
);
693 alSetError(pContext
, AL_INVALID_ENUM
);
698 alSetError(pContext
, AL_INVALID_NAME
);
700 ProcessContext(pContext
);
704 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
706 ALCcontext
*pContext
;
709 pContext
= GetContextSuspended();
710 if(!pContext
) return;
712 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
714 ALCdevice
*device
= pContext
->Device
;
721 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
724 case AL_AUXILIARY_SEND_FILTER
: {
725 ALeffectslot
*ALEffectSlot
= NULL
;
726 ALfilter
*ALFilter
= NULL
;
728 if((ALuint
)lValue2
< device
->NumAuxSends
&&
730 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
732 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
734 /* Release refcount on the previous slot, and add one for
736 if(Source
->Send
[lValue2
].Slot
)
737 Source
->Send
[lValue2
].Slot
->refcount
--;
738 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
739 if(Source
->Send
[lValue2
].Slot
)
740 Source
->Send
[lValue2
].Slot
->refcount
++;
745 Source
->Send
[lValue2
].WetFilter
.type
= 0;
746 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
749 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
750 Source
->NeedsUpdate
= AL_TRUE
;
753 alSetError(pContext
, AL_INVALID_VALUE
);
757 alSetError(pContext
, AL_INVALID_ENUM
);
762 alSetError(pContext
, AL_INVALID_NAME
);
764 ProcessContext(pContext
);
768 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
770 ALCcontext
*pContext
;
772 pContext
= GetContextSuspended();
773 if(!pContext
) return;
777 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
781 case AL_SOURCE_RELATIVE
:
782 case AL_CONE_INNER_ANGLE
:
783 case AL_CONE_OUTER_ANGLE
:
786 case AL_SOURCE_STATE
:
788 case AL_SAMPLE_OFFSET
:
790 case AL_MAX_DISTANCE
:
791 case AL_ROLLOFF_FACTOR
:
792 case AL_REFERENCE_DISTANCE
:
793 case AL_DIRECT_FILTER
:
794 case AL_DIRECT_FILTER_GAINHF_AUTO
:
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
796 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
797 case AL_DISTANCE_MODEL
:
798 alSourcei(source
, eParam
, plValues
[0]);
804 case AL_AUXILIARY_SEND_FILTER
:
805 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
809 alSetError(pContext
, AL_INVALID_ENUM
);
814 alSetError(pContext
, AL_INVALID_NAME
);
817 alSetError(pContext
, AL_INVALID_VALUE
);
819 ProcessContext(pContext
);
823 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
825 ALCcontext
*pContext
;
830 pContext
= GetContextSuspended();
831 if(!pContext
) return;
835 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
840 *pflValue
= Source
->flPitch
;
844 *pflValue
= Source
->flGain
;
848 *pflValue
= Source
->flMinGain
;
852 *pflValue
= Source
->flMaxGain
;
855 case AL_MAX_DISTANCE
:
856 *pflValue
= Source
->flMaxDistance
;
859 case AL_ROLLOFF_FACTOR
:
860 *pflValue
= Source
->flRollOffFactor
;
863 case AL_CONE_OUTER_GAIN
:
864 *pflValue
= Source
->flOuterGain
;
867 case AL_CONE_OUTER_GAINHF
:
868 *pflValue
= Source
->OuterGainHF
;
872 case AL_SAMPLE_OFFSET
:
874 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
875 pContext
->Device
->Frequency
;
876 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
877 *pflValue
= Offsets
[0];
880 case AL_CONE_INNER_ANGLE
:
881 *pflValue
= Source
->flInnerAngle
;
884 case AL_CONE_OUTER_ANGLE
:
885 *pflValue
= Source
->flOuterAngle
;
888 case AL_REFERENCE_DISTANCE
:
889 *pflValue
= Source
->flRefDistance
;
892 case AL_AIR_ABSORPTION_FACTOR
:
893 *pflValue
= Source
->AirAbsorptionFactor
;
896 case AL_ROOM_ROLLOFF_FACTOR
:
897 *pflValue
= Source
->RoomRolloffFactor
;
900 case AL_DOPPLER_FACTOR
:
901 *pflValue
= Source
->DopplerFactor
;
905 alSetError(pContext
, AL_INVALID_ENUM
);
910 alSetError(pContext
, AL_INVALID_NAME
);
913 alSetError(pContext
, AL_INVALID_VALUE
);
915 ProcessContext(pContext
);
919 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
921 ALCcontext
*pContext
;
924 pContext
= GetContextSuspended();
925 if(!pContext
) return;
927 if(pflValue1
&& pflValue2
&& pflValue3
)
929 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
934 *pflValue1
= Source
->vPosition
[0];
935 *pflValue2
= Source
->vPosition
[1];
936 *pflValue3
= Source
->vPosition
[2];
940 *pflValue1
= Source
->vVelocity
[0];
941 *pflValue2
= Source
->vVelocity
[1];
942 *pflValue3
= Source
->vVelocity
[2];
946 *pflValue1
= Source
->vOrientation
[0];
947 *pflValue2
= Source
->vOrientation
[1];
948 *pflValue3
= Source
->vOrientation
[2];
952 alSetError(pContext
, AL_INVALID_ENUM
);
957 alSetError(pContext
, AL_INVALID_NAME
);
960 alSetError(pContext
, AL_INVALID_VALUE
);
962 ProcessContext(pContext
);
966 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
968 ALCcontext
*pContext
;
973 pContext
= GetContextSuspended();
974 if(!pContext
) return;
978 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
986 case AL_MAX_DISTANCE
:
987 case AL_ROLLOFF_FACTOR
:
988 case AL_DOPPLER_FACTOR
:
989 case AL_CONE_OUTER_GAIN
:
991 case AL_SAMPLE_OFFSET
:
993 case AL_CONE_INNER_ANGLE
:
994 case AL_CONE_OUTER_ANGLE
:
995 case AL_REFERENCE_DISTANCE
:
996 case AL_CONE_OUTER_GAINHF
:
997 case AL_AIR_ABSORPTION_FACTOR
:
998 case AL_ROOM_ROLLOFF_FACTOR
:
999 alGetSourcef(source
, eParam
, pflValues
);
1005 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
1008 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1009 case AL_BYTE_RW_OFFSETS_SOFT
:
1010 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1011 pContext
->Device
->Frequency
;
1012 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1013 pflValues
[0] = Offsets
[0];
1014 pflValues
[1] = Offsets
[1];
1018 alSetError(pContext
, AL_INVALID_ENUM
);
1023 alSetError(pContext
, AL_INVALID_NAME
);
1026 alSetError(pContext
, AL_INVALID_VALUE
);
1028 ProcessContext(pContext
);
1032 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1034 ALCcontext
*pContext
;
1036 ALdouble Offsets
[2];
1039 pContext
= GetContextSuspended();
1040 if(!pContext
) return;
1044 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1048 case AL_MAX_DISTANCE
:
1049 *plValue
= (ALint
)Source
->flMaxDistance
;
1052 case AL_ROLLOFF_FACTOR
:
1053 *plValue
= (ALint
)Source
->flRollOffFactor
;
1056 case AL_REFERENCE_DISTANCE
:
1057 *plValue
= (ALint
)Source
->flRefDistance
;
1060 case AL_SOURCE_RELATIVE
:
1061 *plValue
= Source
->bHeadRelative
;
1064 case AL_CONE_INNER_ANGLE
:
1065 *plValue
= (ALint
)Source
->flInnerAngle
;
1068 case AL_CONE_OUTER_ANGLE
:
1069 *plValue
= (ALint
)Source
->flOuterAngle
;
1073 *plValue
= Source
->bLooping
;
1077 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1080 case AL_SOURCE_STATE
:
1081 *plValue
= Source
->state
;
1084 case AL_BUFFERS_QUEUED
:
1085 *plValue
= Source
->BuffersInQueue
;
1088 case AL_BUFFERS_PROCESSED
:
1089 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1091 /* Buffers on a looping source are in a perpetual state
1092 * of PENDING, so don't report any as PROCESSED */
1096 *plValue
= Source
->BuffersPlayed
;
1099 case AL_SOURCE_TYPE
:
1100 *plValue
= Source
->lSourceType
;
1104 case AL_SAMPLE_OFFSET
:
1105 case AL_BYTE_OFFSET
:
1106 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1107 pContext
->Device
->Frequency
;
1108 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1109 *plValue
= (ALint
)Offsets
[0];
1112 case AL_DIRECT_FILTER
:
1113 *plValue
= Source
->DirectFilter
.filter
;
1116 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1117 *plValue
= Source
->DryGainHFAuto
;
1120 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1121 *plValue
= Source
->WetGainAuto
;
1124 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1125 *plValue
= Source
->WetGainHFAuto
;
1128 case AL_DOPPLER_FACTOR
:
1129 *plValue
= (ALint
)Source
->DopplerFactor
;
1132 case AL_DISTANCE_MODEL
:
1133 *plValue
= Source
->DistanceModel
;
1137 alSetError(pContext
, AL_INVALID_ENUM
);
1142 alSetError(pContext
, AL_INVALID_NAME
);
1145 alSetError(pContext
, AL_INVALID_VALUE
);
1147 ProcessContext(pContext
);
1151 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1153 ALCcontext
*pContext
;
1156 pContext
= GetContextSuspended();
1157 if(!pContext
) return;
1159 if(plValue1
&& plValue2
&& plValue3
)
1161 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1166 *plValue1
= (ALint
)Source
->vPosition
[0];
1167 *plValue2
= (ALint
)Source
->vPosition
[1];
1168 *plValue3
= (ALint
)Source
->vPosition
[2];
1172 *plValue1
= (ALint
)Source
->vVelocity
[0];
1173 *plValue2
= (ALint
)Source
->vVelocity
[1];
1174 *plValue3
= (ALint
)Source
->vVelocity
[2];
1178 *plValue1
= (ALint
)Source
->vOrientation
[0];
1179 *plValue2
= (ALint
)Source
->vOrientation
[1];
1180 *plValue3
= (ALint
)Source
->vOrientation
[2];
1184 alSetError(pContext
, AL_INVALID_ENUM
);
1189 alSetError(pContext
, AL_INVALID_NAME
);
1192 alSetError(pContext
, AL_INVALID_VALUE
);
1194 ProcessContext(pContext
);
1198 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1200 ALCcontext
*pContext
;
1202 ALdouble Offsets
[2];
1205 pContext
= GetContextSuspended();
1206 if(!pContext
) return;
1210 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1214 case AL_SOURCE_RELATIVE
:
1215 case AL_CONE_INNER_ANGLE
:
1216 case AL_CONE_OUTER_ANGLE
:
1219 case AL_SOURCE_STATE
:
1220 case AL_BUFFERS_QUEUED
:
1221 case AL_BUFFERS_PROCESSED
:
1223 case AL_SAMPLE_OFFSET
:
1224 case AL_BYTE_OFFSET
:
1225 case AL_MAX_DISTANCE
:
1226 case AL_ROLLOFF_FACTOR
:
1227 case AL_DOPPLER_FACTOR
:
1228 case AL_REFERENCE_DISTANCE
:
1229 case AL_SOURCE_TYPE
:
1230 case AL_DIRECT_FILTER
:
1231 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1232 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1233 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1234 case AL_DISTANCE_MODEL
:
1235 alGetSourcei(source
, eParam
, plValues
);
1241 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1244 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1245 case AL_BYTE_RW_OFFSETS_SOFT
:
1246 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1247 pContext
->Device
->Frequency
;
1248 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1249 plValues
[0] = (ALint
)Offsets
[0];
1250 plValues
[1] = (ALint
)Offsets
[1];
1254 alSetError(pContext
, AL_INVALID_ENUM
);
1259 alSetError(pContext
, AL_INVALID_NAME
);
1262 alSetError(pContext
, AL_INVALID_VALUE
);
1264 ProcessContext(pContext
);
1268 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1270 alSourcePlayv(1, &source
);
1273 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1275 ALCcontext
*Context
;
1277 ALbufferlistitem
*BufferList
;
1280 Context
= GetContextSuspended();
1281 if(!Context
) return;
1285 alSetError(Context
, AL_INVALID_VALUE
);
1288 if(n
> 0 && !sources
)
1290 alSetError(Context
, AL_INVALID_VALUE
);
1294 // Check that all the Sources are valid
1295 for(i
= 0;i
< n
;i
++)
1297 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1299 alSetError(Context
, AL_INVALID_NAME
);
1304 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1309 newcount
= Context
->MaxActiveSources
<< 1;
1311 temp
= realloc(Context
->ActiveSources
,
1312 sizeof(*Context
->ActiveSources
) * newcount
);
1315 alSetError(Context
, AL_OUT_OF_MEMORY
);
1319 Context
->ActiveSources
= temp
;
1320 Context
->MaxActiveSources
= newcount
;
1323 for(i
= 0;i
< n
;i
++)
1325 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1327 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1328 BufferList
= Source
->queue
;
1331 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1333 BufferList
= BufferList
->next
;
1338 Source
->state
= AL_STOPPED
;
1339 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1340 Source
->position
= 0;
1341 Source
->position_fraction
= 0;
1342 Source
->lOffset
= 0;
1346 if(Source
->state
!= AL_PAUSED
)
1348 Source
->state
= AL_PLAYING
;
1349 Source
->position
= 0;
1350 Source
->position_fraction
= 0;
1351 Source
->BuffersPlayed
= 0;
1353 Source
->Buffer
= Source
->queue
->buffer
;
1356 Source
->state
= AL_PLAYING
;
1358 // Check if an Offset has been set
1360 ApplyOffset(Source
);
1362 // If device is disconnected, go right to stopped
1363 if(!Context
->Device
->Connected
)
1365 Source
->state
= AL_STOPPED
;
1366 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1367 Source
->position
= 0;
1368 Source
->position_fraction
= 0;
1372 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1374 if(Context
->ActiveSources
[j
] == Source
)
1377 if(j
== Context
->ActiveSourceCount
)
1378 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1383 ProcessContext(Context
);
1386 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1388 alSourcePausev(1, &source
);
1391 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1393 ALCcontext
*Context
;
1397 Context
= GetContextSuspended();
1398 if(!Context
) return;
1402 alSetError(Context
, AL_INVALID_VALUE
);
1405 if(n
> 0 && !sources
)
1407 alSetError(Context
, AL_INVALID_VALUE
);
1411 // Check all the Sources are valid
1412 for(i
= 0;i
< n
;i
++)
1414 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1416 alSetError(Context
, AL_INVALID_NAME
);
1421 for(i
= 0;i
< n
;i
++)
1423 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1424 if(Source
->state
== AL_PLAYING
)
1425 Source
->state
= AL_PAUSED
;
1429 ProcessContext(Context
);
1432 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1434 alSourceStopv(1, &source
);
1437 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1439 ALCcontext
*Context
;
1443 Context
= GetContextSuspended();
1444 if(!Context
) return;
1448 alSetError(Context
, AL_INVALID_VALUE
);
1451 if(n
> 0 && !sources
)
1453 alSetError(Context
, AL_INVALID_VALUE
);
1457 // Check all the Sources are valid
1458 for(i
= 0;i
< n
;i
++)
1460 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1462 alSetError(Context
, AL_INVALID_NAME
);
1467 for(i
= 0;i
< n
;i
++)
1469 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1470 if(Source
->state
!= AL_INITIAL
)
1472 Source
->state
= AL_STOPPED
;
1473 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1475 Source
->lOffset
= 0;
1479 ProcessContext(Context
);
1482 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1484 alSourceRewindv(1, &source
);
1487 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1489 ALCcontext
*Context
;
1493 Context
= GetContextSuspended();
1494 if(!Context
) return;
1498 alSetError(Context
, AL_INVALID_VALUE
);
1501 if(n
> 0 && !sources
)
1503 alSetError(Context
, AL_INVALID_VALUE
);
1507 // Check all the Sources are valid
1508 for(i
= 0;i
< n
;i
++)
1510 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1512 alSetError(Context
, AL_INVALID_NAME
);
1517 for(i
= 0;i
< n
;i
++)
1519 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1520 if(Source
->state
!= AL_INITIAL
)
1522 Source
->state
= AL_INITIAL
;
1523 Source
->position
= 0;
1524 Source
->position_fraction
= 0;
1525 Source
->BuffersPlayed
= 0;
1527 Source
->Buffer
= Source
->queue
->buffer
;
1529 Source
->lOffset
= 0;
1533 ProcessContext(Context
);
1537 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1539 ALCcontext
*Context
;
1544 ALbufferlistitem
*BufferListStart
;
1545 ALbufferlistitem
*BufferList
;
1546 ALbuffer
*BufferFmt
;
1551 Context
= GetContextSuspended();
1552 if(!Context
) return;
1556 alSetError(Context
, AL_INVALID_VALUE
);
1560 // Check that all buffers are valid or zero and that the source is valid
1562 // Check that this is a valid source
1563 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1565 alSetError(Context
, AL_INVALID_NAME
);
1569 // Check that this is not a STATIC Source
1570 if(Source
->lSourceType
== AL_STATIC
)
1572 // Invalid Source Type (can't queue on a Static Source)
1573 alSetError(Context
, AL_INVALID_OPERATION
);
1577 device
= Context
->Device
;
1581 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1582 BufferList
= Source
->queue
;
1585 if(BufferList
->buffer
)
1587 BufferFmt
= BufferList
->buffer
;
1590 BufferList
= BufferList
->next
;
1593 for(i
= 0;i
< n
;i
++)
1598 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1600 alSetError(Context
, AL_INVALID_NAME
);
1604 if(BufferFmt
== NULL
)
1608 if(buffer
->FmtChannels
== FmtMono
)
1609 Source
->Update
= CalcSourceParams
;
1611 Source
->Update
= CalcNonAttnSourceParams
;
1613 Source
->NeedsUpdate
= AL_TRUE
;
1615 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
1616 BufferFmt
->OriginalFormat
!= buffer
->OriginalFormat
)
1618 alSetError(Context
, AL_INVALID_OPERATION
);
1623 // Change Source Type
1624 Source
->lSourceType
= AL_STREAMING
;
1626 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1628 // All buffers are valid - so add them to the list
1629 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1630 BufferListStart
->buffer
= buffer
;
1631 BufferListStart
->next
= NULL
;
1632 BufferListStart
->prev
= NULL
;
1634 // Increment reference counter for buffer
1635 if(buffer
) buffer
->refcount
++;
1637 BufferList
= BufferListStart
;
1639 for(i
= 1;i
< n
;i
++)
1641 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1643 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1644 BufferList
->next
->buffer
= buffer
;
1645 BufferList
->next
->next
= NULL
;
1646 BufferList
->next
->prev
= BufferList
;
1648 // Increment reference counter for buffer
1649 if(buffer
) buffer
->refcount
++;
1651 BufferList
= BufferList
->next
;
1654 if(Source
->queue
== NULL
)
1656 Source
->queue
= BufferListStart
;
1657 // Update Current Buffer
1658 Source
->Buffer
= BufferListStart
->buffer
;
1662 // Find end of queue
1663 BufferList
= Source
->queue
;
1664 while(BufferList
->next
!= NULL
)
1665 BufferList
= BufferList
->next
;
1667 BufferList
->next
= BufferListStart
;
1668 BufferList
->next
->prev
= BufferList
;
1671 // Update number of buffers in queue
1672 Source
->BuffersInQueue
+= n
;
1675 ProcessContext(Context
);
1679 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1680 // an array of buffer IDs that are to be filled with the names of the buffers removed
1681 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1683 ALCcontext
*Context
;
1686 ALbufferlistitem
*BufferList
;
1691 Context
= GetContextSuspended();
1692 if(!Context
) return;
1696 alSetError(Context
, AL_INVALID_VALUE
);
1700 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1702 alSetError(Context
, AL_INVALID_NAME
);
1706 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1707 (ALuint
)n
> Source
->BuffersPlayed
)
1709 // Some buffers can't be unqueue because they have not been processed
1710 alSetError(Context
, AL_INVALID_VALUE
);
1714 for(i
= 0;i
< n
;i
++)
1716 BufferList
= Source
->queue
;
1717 Source
->queue
= BufferList
->next
;
1719 if(BufferList
->buffer
)
1721 // Record name of buffer
1722 buffers
[i
] = BufferList
->buffer
->buffer
;
1723 // Decrement buffer reference counter
1724 BufferList
->buffer
->refcount
--;
1729 // Release memory for buffer list item
1731 Source
->BuffersInQueue
--;
1734 Source
->queue
->prev
= NULL
;
1736 if(Source
->state
!= AL_PLAYING
)
1739 Source
->Buffer
= Source
->queue
->buffer
;
1741 Source
->Buffer
= NULL
;
1743 Source
->BuffersPlayed
-= n
;
1746 ProcessContext(Context
);
1750 static ALvoid
InitSourceParams(ALsource
*Source
)
1752 Source
->flInnerAngle
= 360.0f
;
1753 Source
->flOuterAngle
= 360.0f
;
1754 Source
->flPitch
= 1.0f
;
1755 Source
->vPosition
[0] = 0.0f
;
1756 Source
->vPosition
[1] = 0.0f
;
1757 Source
->vPosition
[2] = 0.0f
;
1758 Source
->vOrientation
[0] = 0.0f
;
1759 Source
->vOrientation
[1] = 0.0f
;
1760 Source
->vOrientation
[2] = 0.0f
;
1761 Source
->vVelocity
[0] = 0.0f
;
1762 Source
->vVelocity
[1] = 0.0f
;
1763 Source
->vVelocity
[2] = 0.0f
;
1764 Source
->flRefDistance
= 1.0f
;
1765 Source
->flMaxDistance
= FLT_MAX
;
1766 Source
->flRollOffFactor
= 1.0f
;
1767 Source
->bLooping
= AL_FALSE
;
1768 Source
->flGain
= 1.0f
;
1769 Source
->flMinGain
= 0.0f
;
1770 Source
->flMaxGain
= 1.0f
;
1771 Source
->flOuterGain
= 0.0f
;
1772 Source
->OuterGainHF
= 1.0f
;
1774 Source
->DryGainHFAuto
= AL_TRUE
;
1775 Source
->WetGainAuto
= AL_TRUE
;
1776 Source
->WetGainHFAuto
= AL_TRUE
;
1777 Source
->AirAbsorptionFactor
= 0.0f
;
1778 Source
->RoomRolloffFactor
= 0.0f
;
1779 Source
->DopplerFactor
= 1.0f
;
1781 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1783 Source
->Resampler
= DefaultResampler
;
1785 Source
->state
= AL_INITIAL
;
1786 Source
->lSourceType
= AL_UNDETERMINED
;
1788 Source
->NeedsUpdate
= AL_TRUE
;
1790 Source
->Buffer
= NULL
;
1797 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1798 The offset is relative to the start of the queue (not the start of the current buffer)
1800 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1802 ALbufferlistitem
*BufferList
;
1803 ALbuffer
*Buffer
= NULL
;
1805 ALint Channels
, Bytes
;
1806 ALuint readPos
, writePos
;
1807 ALenum OriginalFormat
;
1808 ALuint TotalBufferDataSize
;
1811 // Find the first non-NULL Buffer in the Queue
1812 BufferList
= Source
->queue
;
1815 if(BufferList
->buffer
)
1817 Buffer
= BufferList
->buffer
;
1820 BufferList
= BufferList
->next
;
1823 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1830 // Get Current Buffer Size and frequency (in milliseconds)
1831 BufferFreq
= (ALfloat
)Buffer
->Frequency
;
1832 OriginalFormat
= Buffer
->OriginalFormat
;
1833 Channels
= ChannelsFromFmt(Buffer
->FmtChannels
);
1834 Bytes
= BytesFromFmt(Buffer
->FmtType
);
1836 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1837 readPos
= Source
->position
* Channels
* Bytes
;
1838 // Add byte length of any processed buffers in the queue
1839 TotalBufferDataSize
= 0;
1840 BufferList
= Source
->queue
;
1841 for(i
= 0;BufferList
;i
++)
1843 if(BufferList
->buffer
)
1845 if(i
< Source
->BuffersPlayed
)
1846 readPos
+= BufferList
->buffer
->size
;
1847 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1849 BufferList
= BufferList
->next
;
1851 if(Source
->state
== AL_PLAYING
)
1852 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1856 if(Source
->bLooping
)
1858 readPos
%= TotalBufferDataSize
;
1859 writePos
%= TotalBufferDataSize
;
1863 // Wrap positions back to 0
1864 if(readPos
>= TotalBufferDataSize
)
1866 if(writePos
>= TotalBufferDataSize
)
1873 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1874 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1876 case AL_SAMPLE_OFFSET
:
1877 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1878 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1879 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1881 case AL_BYTE_OFFSET
:
1882 case AL_BYTE_RW_OFFSETS_SOFT
:
1883 // Take into account the original format of the Buffer
1884 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1885 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1887 ALuint FrameBlockSize
= 65 * Bytes
* Channels
;
1888 ALuint BlockSize
= 36 * Channels
;
1890 // Round down to nearest ADPCM block
1891 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1892 if(Source
->state
!= AL_PLAYING
)
1893 offset
[1] = offset
[0];
1896 // Round up to nearest ADPCM block
1897 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1898 FrameBlockSize
* BlockSize
);
1903 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1904 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1905 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1915 Apply a playback offset to the Source. This function will update the queue (to correctly
1916 mark buffers as 'pending' or 'processed' depending upon the new offset.
1918 static ALboolean
ApplyOffset(ALsource
*Source
)
1920 ALbufferlistitem
*BufferList
;
1922 ALint lBufferSize
, lTotalBufferSize
;
1923 ALint BuffersPlayed
;
1926 // Get true byte offset
1927 lByteOffset
= GetByteOffset(Source
);
1929 // If the offset is invalid, don't apply it
1930 if(lByteOffset
== -1)
1933 // Sort out the queue (pending and processed states)
1934 BufferList
= Source
->queue
;
1935 lTotalBufferSize
= 0;
1940 Buffer
= BufferList
->buffer
;
1941 lBufferSize
= Buffer
? Buffer
->size
: 0;
1943 if(lBufferSize
<= lByteOffset
-lTotalBufferSize
)
1945 // Offset is past this buffer so increment BuffersPlayed
1948 else if(lTotalBufferSize
<= lByteOffset
)
1950 // Offset is within this buffer
1951 // Set Current Buffer
1952 Source
->Buffer
= BufferList
->buffer
;
1953 Source
->BuffersPlayed
= BuffersPlayed
;
1955 // SW Mixer Positions are in Samples
1956 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1957 FrameSizeFromFmt(Buffer
->FmtType
, Buffer
->FmtChannels
);
1961 // Increment the TotalBufferSize
1962 lTotalBufferSize
+= lBufferSize
;
1964 // Move on to next buffer in the Queue
1965 BufferList
= BufferList
->next
;
1967 // Offset is out of range of the buffer queue
1975 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1976 offset supplied by the application). This takes into account the fact that the buffer format
1977 may have been modifed by AL (e.g 8bit samples are converted to float)
1979 static ALint
GetByteOffset(ALsource
*Source
)
1981 ALbuffer
*Buffer
= NULL
;
1982 ALbufferlistitem
*BufferList
;
1983 ALint ByteOffset
= -1;
1985 // Find the first non-NULL Buffer in the Queue
1986 BufferList
= Source
->queue
;
1989 if(BufferList
->buffer
)
1991 Buffer
= BufferList
->buffer
;
1994 BufferList
= BufferList
->next
;
1999 Source
->lOffset
= 0;
2003 // Determine the ByteOffset (and ensure it is block aligned)
2004 switch(Source
->lOffsetType
)
2006 case AL_BYTE_OFFSET
:
2007 // Take into consideration the original format
2008 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->OriginalFormat
);
2009 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtType
, Buffer
->FmtChannels
);
2012 case AL_SAMPLE_OFFSET
:
2013 ByteOffset
= Source
->lOffset
* BytesFromFmt(Buffer
->FmtType
);
2017 // Note - lOffset is internally stored as Milliseconds
2018 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * Buffer
->Frequency
);
2019 ByteOffset
*= BytesFromFmt(Buffer
->FmtType
);
2023 Source
->lOffset
= 0;
2028 static ALint
FramesFromBytes(ALint offset
, ALenum format
)
2030 if(format
==AL_FORMAT_MONO_IMA4
)
2032 // Round down to nearest ADPCM block
2034 // Multiply by compression rate (65 sample frames per block)
2037 else if(format
==AL_FORMAT_STEREO_IMA4
)
2043 offset
/= aluFrameSizeFromFormat(format
);
2048 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2052 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2054 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2055 Context
->SourceMap
.array
[pos
].value
= NULL
;
2057 // For each buffer in the source's queue, decrement its reference counter and remove it
2058 while(temp
->queue
!= NULL
)
2060 ALbufferlistitem
*BufferList
= temp
->queue
;
2061 temp
->queue
= BufferList
->next
;
2063 if(BufferList
->buffer
!= NULL
)
2064 BufferList
->buffer
->refcount
--;
2068 for(j
= 0;j
< MAX_SENDS
;++j
)
2070 if(temp
->Send
[j
].Slot
)
2071 temp
->Send
[j
].Slot
->refcount
--;
2072 temp
->Send
[j
].Slot
= NULL
;
2075 // Release source structure
2076 ALTHUNK_REMOVEENTRY(temp
->source
);
2077 memset(temp
, 0, sizeof(ALsource
));