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
;
553 BufferListItem
->prev
= NULL
;
555 Source
->queue
= BufferListItem
;
556 Source
->BuffersInQueue
= 1;
558 if(aluChannelsFromFormat(buffer
->format
) == 1)
559 Source
->Update
= CalcSourceParams
;
561 Source
->Update
= CalcNonAttnSourceParams
;
563 Source
->Mix
= MixSource
;
565 // Increment reference counter for buffer
570 // Source is now in UNDETERMINED mode
571 Source
->lSourceType
= AL_UNDETERMINED
;
573 Source
->BuffersPlayed
= 0;
575 // Update AL_BUFFER parameter
576 Source
->Buffer
= buffer
;
577 Source
->NeedsUpdate
= AL_TRUE
;
580 alSetError(pContext
, AL_INVALID_VALUE
);
583 alSetError(pContext
, AL_INVALID_OPERATION
);
586 case AL_SOURCE_STATE
:
588 alSetError(pContext
, AL_INVALID_OPERATION
);
592 case AL_SAMPLE_OFFSET
:
596 Source
->lOffsetType
= eParam
;
598 // Store Offset (convert Seconds into Milliseconds)
599 if(eParam
== AL_SEC_OFFSET
)
600 Source
->lOffset
= lValue
* 1000;
602 Source
->lOffset
= lValue
;
604 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
606 if(ApplyOffset(Source
) == AL_FALSE
)
607 alSetError(pContext
, AL_INVALID_VALUE
);
611 alSetError(pContext
, AL_INVALID_VALUE
);
614 case AL_DIRECT_FILTER
: {
615 ALfilter
*filter
= NULL
;
618 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
622 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
623 Source
->DirectFilter
.filter
= 0;
626 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
627 Source
->NeedsUpdate
= AL_TRUE
;
630 alSetError(pContext
, AL_INVALID_VALUE
);
633 case AL_DIRECT_FILTER_GAINHF_AUTO
:
634 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
636 Source
->DryGainHFAuto
= lValue
;
637 Source
->NeedsUpdate
= AL_TRUE
;
640 alSetError(pContext
, AL_INVALID_VALUE
);
643 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
644 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
646 Source
->WetGainAuto
= lValue
;
647 Source
->NeedsUpdate
= AL_TRUE
;
650 alSetError(pContext
, AL_INVALID_VALUE
);
653 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
654 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
656 Source
->WetGainHFAuto
= lValue
;
657 Source
->NeedsUpdate
= AL_TRUE
;
660 alSetError(pContext
, AL_INVALID_VALUE
);
663 case AL_DISTANCE_MODEL
:
664 if(lValue
== AL_NONE
||
665 lValue
== AL_INVERSE_DISTANCE
||
666 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
667 lValue
== AL_LINEAR_DISTANCE
||
668 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
669 lValue
== AL_EXPONENT_DISTANCE
||
670 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
672 Source
->DistanceModel
= lValue
;
673 if(pContext
->SourceDistanceModel
)
674 Source
->NeedsUpdate
= AL_TRUE
;
677 alSetError(pContext
, AL_INVALID_VALUE
);
681 alSetError(pContext
, AL_INVALID_ENUM
);
686 alSetError(pContext
, AL_INVALID_NAME
);
688 ProcessContext(pContext
);
692 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
694 ALCcontext
*pContext
;
697 pContext
= GetContextSuspended();
698 if(!pContext
) return;
700 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
702 ALCdevice
*device
= pContext
->Device
;
709 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
712 case AL_AUXILIARY_SEND_FILTER
: {
713 ALeffectslot
*ALEffectSlot
= NULL
;
714 ALfilter
*ALFilter
= NULL
;
716 if((ALuint
)lValue2
< device
->NumAuxSends
&&
718 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
720 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
722 /* Release refcount on the previous slot, and add one for
724 if(Source
->Send
[lValue2
].Slot
)
725 Source
->Send
[lValue2
].Slot
->refcount
--;
726 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
727 if(Source
->Send
[lValue2
].Slot
)
728 Source
->Send
[lValue2
].Slot
->refcount
++;
733 Source
->Send
[lValue2
].WetFilter
.type
= 0;
734 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
737 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
738 Source
->NeedsUpdate
= AL_TRUE
;
741 alSetError(pContext
, AL_INVALID_VALUE
);
745 alSetError(pContext
, AL_INVALID_ENUM
);
750 alSetError(pContext
, AL_INVALID_NAME
);
752 ProcessContext(pContext
);
756 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
758 ALCcontext
*pContext
;
760 pContext
= GetContextSuspended();
761 if(!pContext
) return;
765 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
769 case AL_SOURCE_RELATIVE
:
770 case AL_CONE_INNER_ANGLE
:
771 case AL_CONE_OUTER_ANGLE
:
774 case AL_SOURCE_STATE
:
776 case AL_SAMPLE_OFFSET
:
778 case AL_MAX_DISTANCE
:
779 case AL_ROLLOFF_FACTOR
:
780 case AL_REFERENCE_DISTANCE
:
781 case AL_DIRECT_FILTER
:
782 case AL_DIRECT_FILTER_GAINHF_AUTO
:
783 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
784 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
785 case AL_DISTANCE_MODEL
:
786 alSourcei(source
, eParam
, plValues
[0]);
792 case AL_AUXILIARY_SEND_FILTER
:
793 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
797 alSetError(pContext
, AL_INVALID_ENUM
);
802 alSetError(pContext
, AL_INVALID_NAME
);
805 alSetError(pContext
, AL_INVALID_VALUE
);
807 ProcessContext(pContext
);
811 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
813 ALCcontext
*pContext
;
818 pContext
= GetContextSuspended();
819 if(!pContext
) return;
823 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
828 *pflValue
= Source
->flPitch
;
832 *pflValue
= Source
->flGain
;
836 *pflValue
= Source
->flMinGain
;
840 *pflValue
= Source
->flMaxGain
;
843 case AL_MAX_DISTANCE
:
844 *pflValue
= Source
->flMaxDistance
;
847 case AL_ROLLOFF_FACTOR
:
848 *pflValue
= Source
->flRollOffFactor
;
851 case AL_CONE_OUTER_GAIN
:
852 *pflValue
= Source
->flOuterGain
;
855 case AL_CONE_OUTER_GAINHF
:
856 *pflValue
= Source
->OuterGainHF
;
860 case AL_SAMPLE_OFFSET
:
862 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
863 pContext
->Device
->Frequency
;
864 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
865 *pflValue
= Offsets
[0];
868 case AL_CONE_INNER_ANGLE
:
869 *pflValue
= Source
->flInnerAngle
;
872 case AL_CONE_OUTER_ANGLE
:
873 *pflValue
= Source
->flOuterAngle
;
876 case AL_REFERENCE_DISTANCE
:
877 *pflValue
= Source
->flRefDistance
;
880 case AL_AIR_ABSORPTION_FACTOR
:
881 *pflValue
= Source
->AirAbsorptionFactor
;
884 case AL_ROOM_ROLLOFF_FACTOR
:
885 *pflValue
= Source
->RoomRolloffFactor
;
888 case AL_DOPPLER_FACTOR
:
889 *pflValue
= Source
->DopplerFactor
;
893 alSetError(pContext
, AL_INVALID_ENUM
);
898 alSetError(pContext
, AL_INVALID_NAME
);
901 alSetError(pContext
, AL_INVALID_VALUE
);
903 ProcessContext(pContext
);
907 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
909 ALCcontext
*pContext
;
912 pContext
= GetContextSuspended();
913 if(!pContext
) return;
915 if(pflValue1
&& pflValue2
&& pflValue3
)
917 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
922 *pflValue1
= Source
->vPosition
[0];
923 *pflValue2
= Source
->vPosition
[1];
924 *pflValue3
= Source
->vPosition
[2];
928 *pflValue1
= Source
->vVelocity
[0];
929 *pflValue2
= Source
->vVelocity
[1];
930 *pflValue3
= Source
->vVelocity
[2];
934 *pflValue1
= Source
->vOrientation
[0];
935 *pflValue2
= Source
->vOrientation
[1];
936 *pflValue3
= Source
->vOrientation
[2];
940 alSetError(pContext
, AL_INVALID_ENUM
);
945 alSetError(pContext
, AL_INVALID_NAME
);
948 alSetError(pContext
, AL_INVALID_VALUE
);
950 ProcessContext(pContext
);
954 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
956 ALCcontext
*pContext
;
961 pContext
= GetContextSuspended();
962 if(!pContext
) return;
966 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
974 case AL_MAX_DISTANCE
:
975 case AL_ROLLOFF_FACTOR
:
976 case AL_DOPPLER_FACTOR
:
977 case AL_CONE_OUTER_GAIN
:
979 case AL_SAMPLE_OFFSET
:
981 case AL_CONE_INNER_ANGLE
:
982 case AL_CONE_OUTER_ANGLE
:
983 case AL_REFERENCE_DISTANCE
:
984 case AL_CONE_OUTER_GAINHF
:
985 case AL_AIR_ABSORPTION_FACTOR
:
986 case AL_ROOM_ROLLOFF_FACTOR
:
987 alGetSourcef(source
, eParam
, pflValues
);
993 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
996 case AL_SAMPLE_RW_OFFSETS_SOFT
:
997 case AL_BYTE_RW_OFFSETS_SOFT
:
998 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
999 pContext
->Device
->Frequency
;
1000 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1001 pflValues
[0] = Offsets
[0];
1002 pflValues
[1] = Offsets
[1];
1006 alSetError(pContext
, AL_INVALID_ENUM
);
1011 alSetError(pContext
, AL_INVALID_NAME
);
1014 alSetError(pContext
, AL_INVALID_VALUE
);
1016 ProcessContext(pContext
);
1020 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1022 ALCcontext
*pContext
;
1024 ALdouble Offsets
[2];
1027 pContext
= GetContextSuspended();
1028 if(!pContext
) return;
1032 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1036 case AL_MAX_DISTANCE
:
1037 *plValue
= (ALint
)Source
->flMaxDistance
;
1040 case AL_ROLLOFF_FACTOR
:
1041 *plValue
= (ALint
)Source
->flRollOffFactor
;
1044 case AL_REFERENCE_DISTANCE
:
1045 *plValue
= (ALint
)Source
->flRefDistance
;
1048 case AL_SOURCE_RELATIVE
:
1049 *plValue
= Source
->bHeadRelative
;
1052 case AL_CONE_INNER_ANGLE
:
1053 *plValue
= (ALint
)Source
->flInnerAngle
;
1056 case AL_CONE_OUTER_ANGLE
:
1057 *plValue
= (ALint
)Source
->flOuterAngle
;
1061 *plValue
= Source
->bLooping
;
1065 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1068 case AL_SOURCE_STATE
:
1069 *plValue
= Source
->state
;
1072 case AL_BUFFERS_QUEUED
:
1073 *plValue
= Source
->BuffersInQueue
;
1076 case AL_BUFFERS_PROCESSED
:
1077 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1079 /* Buffers on a looping source are in a perpetual state
1080 * of PENDING, so don't report any as PROCESSED */
1084 *plValue
= Source
->BuffersPlayed
;
1087 case AL_SOURCE_TYPE
:
1088 *plValue
= Source
->lSourceType
;
1092 case AL_SAMPLE_OFFSET
:
1093 case AL_BYTE_OFFSET
:
1094 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1095 pContext
->Device
->Frequency
;
1096 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1097 *plValue
= (ALint
)Offsets
[0];
1100 case AL_DIRECT_FILTER
:
1101 *plValue
= Source
->DirectFilter
.filter
;
1104 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1105 *plValue
= Source
->DryGainHFAuto
;
1108 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1109 *plValue
= Source
->WetGainAuto
;
1112 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1113 *plValue
= Source
->WetGainHFAuto
;
1116 case AL_DOPPLER_FACTOR
:
1117 *plValue
= (ALint
)Source
->DopplerFactor
;
1120 case AL_DISTANCE_MODEL
:
1121 *plValue
= Source
->DistanceModel
;
1125 alSetError(pContext
, AL_INVALID_ENUM
);
1130 alSetError(pContext
, AL_INVALID_NAME
);
1133 alSetError(pContext
, AL_INVALID_VALUE
);
1135 ProcessContext(pContext
);
1139 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1141 ALCcontext
*pContext
;
1144 pContext
= GetContextSuspended();
1145 if(!pContext
) return;
1147 if(plValue1
&& plValue2
&& plValue3
)
1149 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1154 *plValue1
= (ALint
)Source
->vPosition
[0];
1155 *plValue2
= (ALint
)Source
->vPosition
[1];
1156 *plValue3
= (ALint
)Source
->vPosition
[2];
1160 *plValue1
= (ALint
)Source
->vVelocity
[0];
1161 *plValue2
= (ALint
)Source
->vVelocity
[1];
1162 *plValue3
= (ALint
)Source
->vVelocity
[2];
1166 *plValue1
= (ALint
)Source
->vOrientation
[0];
1167 *plValue2
= (ALint
)Source
->vOrientation
[1];
1168 *plValue3
= (ALint
)Source
->vOrientation
[2];
1172 alSetError(pContext
, AL_INVALID_ENUM
);
1177 alSetError(pContext
, AL_INVALID_NAME
);
1180 alSetError(pContext
, AL_INVALID_VALUE
);
1182 ProcessContext(pContext
);
1186 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1188 ALCcontext
*pContext
;
1190 ALdouble Offsets
[2];
1193 pContext
= GetContextSuspended();
1194 if(!pContext
) return;
1198 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1202 case AL_SOURCE_RELATIVE
:
1203 case AL_CONE_INNER_ANGLE
:
1204 case AL_CONE_OUTER_ANGLE
:
1207 case AL_SOURCE_STATE
:
1208 case AL_BUFFERS_QUEUED
:
1209 case AL_BUFFERS_PROCESSED
:
1211 case AL_SAMPLE_OFFSET
:
1212 case AL_BYTE_OFFSET
:
1213 case AL_MAX_DISTANCE
:
1214 case AL_ROLLOFF_FACTOR
:
1215 case AL_DOPPLER_FACTOR
:
1216 case AL_REFERENCE_DISTANCE
:
1217 case AL_SOURCE_TYPE
:
1218 case AL_DIRECT_FILTER
:
1219 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1220 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1221 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1222 case AL_DISTANCE_MODEL
:
1223 alGetSourcei(source
, eParam
, plValues
);
1229 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1232 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1233 case AL_BYTE_RW_OFFSETS_SOFT
:
1234 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1235 pContext
->Device
->Frequency
;
1236 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1237 plValues
[0] = (ALint
)Offsets
[0];
1238 plValues
[1] = (ALint
)Offsets
[1];
1242 alSetError(pContext
, AL_INVALID_ENUM
);
1247 alSetError(pContext
, AL_INVALID_NAME
);
1250 alSetError(pContext
, AL_INVALID_VALUE
);
1252 ProcessContext(pContext
);
1256 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1258 alSourcePlayv(1, &source
);
1261 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1263 ALCcontext
*Context
;
1265 ALbufferlistitem
*BufferList
;
1268 Context
= GetContextSuspended();
1269 if(!Context
) return;
1273 alSetError(Context
, AL_INVALID_VALUE
);
1276 if(n
> 0 && !sources
)
1278 alSetError(Context
, AL_INVALID_VALUE
);
1282 // Check that all the Sources are valid
1283 for(i
= 0;i
< n
;i
++)
1285 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1287 alSetError(Context
, AL_INVALID_NAME
);
1292 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1297 newcount
= Context
->MaxActiveSources
<< 1;
1299 temp
= realloc(Context
->ActiveSources
,
1300 sizeof(*Context
->ActiveSources
) * newcount
);
1303 alSetError(Context
, AL_OUT_OF_MEMORY
);
1307 Context
->ActiveSources
= temp
;
1308 Context
->MaxActiveSources
= newcount
;
1311 for(i
= 0;i
< n
;i
++)
1313 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1315 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1316 BufferList
= Source
->queue
;
1319 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1321 BufferList
= BufferList
->next
;
1326 Source
->state
= AL_STOPPED
;
1327 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1328 Source
->position
= 0;
1329 Source
->position_fraction
= 0;
1330 Source
->lOffset
= 0;
1334 if(Source
->state
!= AL_PAUSED
)
1336 Source
->state
= AL_PLAYING
;
1337 Source
->position
= 0;
1338 Source
->position_fraction
= 0;
1339 Source
->BuffersPlayed
= 0;
1341 Source
->Buffer
= Source
->queue
->buffer
;
1344 Source
->state
= AL_PLAYING
;
1346 // Check if an Offset has been set
1348 ApplyOffset(Source
);
1350 // If device is disconnected, go right to stopped
1351 if(!Context
->Device
->Connected
)
1353 Source
->state
= AL_STOPPED
;
1354 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1355 Source
->position
= 0;
1356 Source
->position_fraction
= 0;
1360 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1362 if(Context
->ActiveSources
[j
] == Source
)
1365 if(j
== Context
->ActiveSourceCount
)
1366 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1371 ProcessContext(Context
);
1374 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1376 alSourcePausev(1, &source
);
1379 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1381 ALCcontext
*Context
;
1385 Context
= GetContextSuspended();
1386 if(!Context
) return;
1390 alSetError(Context
, AL_INVALID_VALUE
);
1393 if(n
> 0 && !sources
)
1395 alSetError(Context
, AL_INVALID_VALUE
);
1399 // Check all the Sources are valid
1400 for(i
= 0;i
< n
;i
++)
1402 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1404 alSetError(Context
, AL_INVALID_NAME
);
1409 for(i
= 0;i
< n
;i
++)
1411 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1412 if(Source
->state
== AL_PLAYING
)
1413 Source
->state
= AL_PAUSED
;
1417 ProcessContext(Context
);
1420 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1422 alSourceStopv(1, &source
);
1425 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1427 ALCcontext
*Context
;
1431 Context
= GetContextSuspended();
1432 if(!Context
) return;
1436 alSetError(Context
, AL_INVALID_VALUE
);
1439 if(n
> 0 && !sources
)
1441 alSetError(Context
, AL_INVALID_VALUE
);
1445 // Check all the Sources are valid
1446 for(i
= 0;i
< n
;i
++)
1448 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1450 alSetError(Context
, AL_INVALID_NAME
);
1455 for(i
= 0;i
< n
;i
++)
1457 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1458 if(Source
->state
!= AL_INITIAL
)
1460 Source
->state
= AL_STOPPED
;
1461 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1463 Source
->lOffset
= 0;
1467 ProcessContext(Context
);
1470 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1472 alSourceRewindv(1, &source
);
1475 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1477 ALCcontext
*Context
;
1481 Context
= GetContextSuspended();
1482 if(!Context
) return;
1486 alSetError(Context
, AL_INVALID_VALUE
);
1489 if(n
> 0 && !sources
)
1491 alSetError(Context
, AL_INVALID_VALUE
);
1495 // Check all the Sources are valid
1496 for(i
= 0;i
< n
;i
++)
1498 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1500 alSetError(Context
, AL_INVALID_NAME
);
1505 for(i
= 0;i
< n
;i
++)
1507 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1508 if(Source
->state
!= AL_INITIAL
)
1510 Source
->state
= AL_INITIAL
;
1511 Source
->position
= 0;
1512 Source
->position_fraction
= 0;
1513 Source
->BuffersPlayed
= 0;
1515 Source
->Buffer
= Source
->queue
->buffer
;
1517 Source
->lOffset
= 0;
1521 ProcessContext(Context
);
1525 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1527 ALCcontext
*Context
;
1532 ALbufferlistitem
*BufferListStart
;
1533 ALbufferlistitem
*BufferList
;
1540 Context
= GetContextSuspended();
1541 if(!Context
) return;
1545 alSetError(Context
, AL_INVALID_VALUE
);
1549 // Check that all buffers are valid or zero and that the source is valid
1551 // Check that this is a valid source
1552 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1554 alSetError(Context
, AL_INVALID_NAME
);
1558 // Check that this is not a STATIC Source
1559 if(Source
->lSourceType
== AL_STATIC
)
1561 // Invalid Source Type (can't queue on a Static Source)
1562 alSetError(Context
, AL_INVALID_OPERATION
);
1566 device
= Context
->Device
;
1571 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1572 BufferList
= Source
->queue
;
1575 if(BufferList
->buffer
)
1577 Frequency
= BufferList
->buffer
->frequency
;
1578 Format
= BufferList
->buffer
->eOriginalFormat
;
1581 BufferList
= BufferList
->next
;
1584 for(i
= 0;i
< n
;i
++)
1589 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1591 alSetError(Context
, AL_INVALID_NAME
);
1595 if(Frequency
== -1 && Format
== -1)
1597 Frequency
= buffer
->frequency
;
1598 Format
= buffer
->eOriginalFormat
;
1600 if(aluChannelsFromFormat(buffer
->format
) == 1)
1601 Source
->Update
= CalcSourceParams
;
1603 Source
->Update
= CalcNonAttnSourceParams
;
1605 Source
->Mix
= MixSource
;
1607 Source
->NeedsUpdate
= AL_TRUE
;
1609 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1611 alSetError(Context
, AL_INVALID_OPERATION
);
1616 // Change Source Type
1617 Source
->lSourceType
= AL_STREAMING
;
1619 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1621 // All buffers are valid - so add them to the list
1622 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1623 BufferListStart
->buffer
= buffer
;
1624 BufferListStart
->next
= NULL
;
1625 BufferListStart
->prev
= NULL
;
1627 // Increment reference counter for buffer
1628 if(buffer
) buffer
->refcount
++;
1630 BufferList
= BufferListStart
;
1632 for(i
= 1;i
< n
;i
++)
1634 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1636 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1637 BufferList
->next
->buffer
= buffer
;
1638 BufferList
->next
->next
= NULL
;
1639 BufferList
->next
->prev
= BufferList
;
1641 // Increment reference counter for buffer
1642 if(buffer
) buffer
->refcount
++;
1644 BufferList
= BufferList
->next
;
1647 if(Source
->queue
== NULL
)
1649 Source
->queue
= BufferListStart
;
1650 // Update Current Buffer
1651 Source
->Buffer
= BufferListStart
->buffer
;
1655 // Find end of queue
1656 BufferList
= Source
->queue
;
1657 while(BufferList
->next
!= NULL
)
1658 BufferList
= BufferList
->next
;
1660 BufferList
->next
= BufferListStart
;
1661 BufferList
->next
->prev
= BufferList
;
1664 // Update number of buffers in queue
1665 Source
->BuffersInQueue
+= n
;
1668 ProcessContext(Context
);
1672 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1673 // an array of buffer IDs that are to be filled with the names of the buffers removed
1674 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1676 ALCcontext
*Context
;
1679 ALbufferlistitem
*BufferList
;
1684 Context
= GetContextSuspended();
1685 if(!Context
) return;
1689 alSetError(Context
, AL_INVALID_VALUE
);
1693 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1695 alSetError(Context
, AL_INVALID_NAME
);
1699 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1700 (ALuint
)n
> Source
->BuffersPlayed
)
1702 // Some buffers can't be unqueue because they have not been processed
1703 alSetError(Context
, AL_INVALID_VALUE
);
1707 for(i
= 0;i
< n
;i
++)
1709 BufferList
= Source
->queue
;
1710 Source
->queue
= BufferList
->next
;
1712 if(BufferList
->buffer
)
1714 // Record name of buffer
1715 buffers
[i
] = BufferList
->buffer
->buffer
;
1716 // Decrement buffer reference counter
1717 BufferList
->buffer
->refcount
--;
1722 // Release memory for buffer list item
1724 Source
->BuffersInQueue
--;
1727 Source
->queue
->prev
= NULL
;
1729 if(Source
->state
!= AL_PLAYING
)
1732 Source
->Buffer
= Source
->queue
->buffer
;
1734 Source
->Buffer
= NULL
;
1736 Source
->BuffersPlayed
-= n
;
1739 ProcessContext(Context
);
1743 static ALvoid
InitSourceParams(ALsource
*Source
)
1745 Source
->flInnerAngle
= 360.0f
;
1746 Source
->flOuterAngle
= 360.0f
;
1747 Source
->flPitch
= 1.0f
;
1748 Source
->vPosition
[0] = 0.0f
;
1749 Source
->vPosition
[1] = 0.0f
;
1750 Source
->vPosition
[2] = 0.0f
;
1751 Source
->vOrientation
[0] = 0.0f
;
1752 Source
->vOrientation
[1] = 0.0f
;
1753 Source
->vOrientation
[2] = 0.0f
;
1754 Source
->vVelocity
[0] = 0.0f
;
1755 Source
->vVelocity
[1] = 0.0f
;
1756 Source
->vVelocity
[2] = 0.0f
;
1757 Source
->flRefDistance
= 1.0f
;
1758 Source
->flMaxDistance
= FLT_MAX
;
1759 Source
->flRollOffFactor
= 1.0f
;
1760 Source
->bLooping
= AL_FALSE
;
1761 Source
->flGain
= 1.0f
;
1762 Source
->flMinGain
= 0.0f
;
1763 Source
->flMaxGain
= 1.0f
;
1764 Source
->flOuterGain
= 0.0f
;
1765 Source
->OuterGainHF
= 1.0f
;
1767 Source
->DryGainHFAuto
= AL_TRUE
;
1768 Source
->WetGainAuto
= AL_TRUE
;
1769 Source
->WetGainHFAuto
= AL_TRUE
;
1770 Source
->AirAbsorptionFactor
= 0.0f
;
1771 Source
->RoomRolloffFactor
= 0.0f
;
1772 Source
->DopplerFactor
= 1.0f
;
1774 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1776 Source
->Resampler
= DefaultResampler
;
1778 Source
->state
= AL_INITIAL
;
1779 Source
->lSourceType
= AL_UNDETERMINED
;
1781 Source
->NeedsUpdate
= AL_TRUE
;
1783 Source
->Buffer
= NULL
;
1790 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1791 The offset is relative to the start of the queue (not the start of the current buffer)
1793 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1795 ALbufferlistitem
*BufferList
;
1796 ALbuffer
*Buffer
= NULL
;
1798 ALint Channels
, Bytes
;
1799 ALuint readPos
, writePos
;
1800 ALenum OriginalFormat
;
1801 ALuint TotalBufferDataSize
;
1804 // Find the first non-NULL Buffer in the Queue
1805 BufferList
= Source
->queue
;
1808 if(BufferList
->buffer
)
1810 Buffer
= BufferList
->buffer
;
1813 BufferList
= BufferList
->next
;
1816 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1823 // Get Current Buffer Size and frequency (in milliseconds)
1824 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1825 OriginalFormat
= Buffer
->eOriginalFormat
;
1826 Channels
= aluChannelsFromFormat(Buffer
->format
);
1827 Bytes
= aluBytesFromFormat(Buffer
->format
);
1829 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1830 readPos
= Source
->position
* Channels
* Bytes
;
1831 // Add byte length of any processed buffers in the queue
1832 TotalBufferDataSize
= 0;
1833 BufferList
= Source
->queue
;
1834 for(i
= 0;BufferList
;i
++)
1836 if(BufferList
->buffer
)
1838 if(i
< Source
->BuffersPlayed
)
1839 readPos
+= BufferList
->buffer
->size
;
1840 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1842 BufferList
= BufferList
->next
;
1844 if(Source
->state
== AL_PLAYING
)
1845 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1849 if(Source
->bLooping
)
1851 readPos
%= TotalBufferDataSize
;
1852 writePos
%= TotalBufferDataSize
;
1856 // Wrap positions back to 0
1857 if(readPos
>= TotalBufferDataSize
)
1859 if(writePos
>= TotalBufferDataSize
)
1866 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1867 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1869 case AL_SAMPLE_OFFSET
:
1870 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1871 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1872 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1874 case AL_BYTE_OFFSET
:
1875 case AL_BYTE_RW_OFFSETS_SOFT
:
1876 // Take into account the original format of the Buffer
1877 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1878 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1880 // Round down to nearest ADPCM block
1881 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1882 if(Source
->state
== AL_PLAYING
)
1884 // Round up to nearest ADPCM block
1885 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1888 offset
[1] = offset
[0];
1890 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1891 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1892 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1893 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1894 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1895 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1897 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1898 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1900 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1902 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1903 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1905 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1907 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1908 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1910 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1912 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1913 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1915 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1917 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1918 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1922 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1923 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1924 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1934 Apply a playback offset to the Source. This function will update the queue (to correctly
1935 mark buffers as 'pending' or 'processed' depending upon the new offset.
1937 static ALboolean
ApplyOffset(ALsource
*Source
)
1939 ALbufferlistitem
*BufferList
;
1941 ALint lBufferSize
, lTotalBufferSize
;
1942 ALint BuffersPlayed
;
1945 // Get true byte offset
1946 lByteOffset
= GetByteOffset(Source
);
1948 // If the offset is invalid, don't apply it
1949 if(lByteOffset
== -1)
1952 // Sort out the queue (pending and processed states)
1953 BufferList
= Source
->queue
;
1954 lTotalBufferSize
= 0;
1959 Buffer
= BufferList
->buffer
;
1960 lBufferSize
= Buffer
? Buffer
->size
: 0;
1962 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1964 // Offset is past this buffer so increment BuffersPlayed
1967 else if(lTotalBufferSize
<= lByteOffset
)
1969 // Offset is within this buffer
1970 // Set Current Buffer
1971 Source
->Buffer
= BufferList
->buffer
;
1972 Source
->BuffersPlayed
= BuffersPlayed
;
1974 // SW Mixer Positions are in Samples
1975 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1976 aluFrameSizeFromFormat(Buffer
->format
);
1980 // Increment the TotalBufferSize
1981 lTotalBufferSize
+= lBufferSize
;
1983 // Move on to next buffer in the Queue
1984 BufferList
= BufferList
->next
;
1986 // Offset is out of range of the buffer queue
1994 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1995 offset supplied by the application). This takes into account the fact that the buffer format
1996 may have been modifed by AL (e.g 8bit samples are converted to float)
1998 static ALint
GetByteOffset(ALsource
*Source
)
2000 ALbuffer
*Buffer
= NULL
;
2001 ALbufferlistitem
*BufferList
;
2002 ALdouble BufferFreq
;
2003 ALint Channels
, Bytes
;
2004 ALint ByteOffset
= -1;
2006 // Find the first non-NULL Buffer in the Queue
2007 BufferList
= Source
->queue
;
2010 if(BufferList
->buffer
)
2012 Buffer
= BufferList
->buffer
;
2015 BufferList
= BufferList
->next
;
2020 Source
->lOffset
= 0;
2024 BufferFreq
= ((ALdouble
)Buffer
->frequency
);
2025 Channels
= aluChannelsFromFormat(Buffer
->format
);
2026 Bytes
= aluBytesFromFormat(Buffer
->format
);
2028 // Determine the ByteOffset (and ensure it is block aligned)
2029 switch(Source
->lOffsetType
)
2031 case AL_BYTE_OFFSET
:
2032 // Take into consideration the original format
2033 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2035 ByteOffset
*= Channels
* Bytes
;
2038 case AL_SAMPLE_OFFSET
:
2039 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2043 // Note - lOffset is internally stored as Milliseconds
2044 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * BufferFreq
);
2045 ByteOffset
*= Channels
* Bytes
;
2049 Source
->lOffset
= 0;
2054 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2056 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2058 // Round down to nearest ADPCM block
2059 offset
/= 36 * channels
;
2060 // Multiply by compression rate (65 sample frames per block)
2063 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2064 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2065 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2067 /* muLaw has 1 byte per sample */
2068 offset
/= 1 * channels
;
2070 else if(format
== AL_FORMAT_REAR_MULAW
)
2072 /* Rear is 2 channels */
2075 else if(format
== AL_FORMAT_REAR8
)
2077 else if(format
== AL_FORMAT_REAR16
)
2079 else if(format
== AL_FORMAT_REAR32
)
2083 ALuint bytes
= aluBytesFromFormat(format
);
2084 offset
/= bytes
* channels
;
2090 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2094 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2096 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2097 Context
->SourceMap
.array
[pos
].value
= NULL
;
2099 // For each buffer in the source's queue, decrement its reference counter and remove it
2100 while(temp
->queue
!= NULL
)
2102 ALbufferlistitem
*BufferList
= temp
->queue
;
2103 temp
->queue
= BufferList
->next
;
2105 if(BufferList
->buffer
!= NULL
)
2106 BufferList
->buffer
->refcount
--;
2110 for(j
= 0;j
< MAX_SENDS
;++j
)
2112 if(temp
->Send
[j
].Slot
)
2113 temp
->Send
[j
].Slot
->refcount
--;
2114 temp
->Send
[j
].Slot
= NULL
;
2117 // Release source structure
2118 ALTHUNK_REMOVEENTRY(temp
->source
);
2119 memset(temp
, 0, sizeof(ALsource
));