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
)
52 Context
= GetContextSuspended();
57 Device
= Context
->Device
;
59 // Check that enough memory has been allocted in the 'sources' array for n Sources
60 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
62 // Check that the requested number of sources can be generated
63 if((Context
->SourceMap
.size
+ n
) <= (ALsizei
)Device
->MaxNoOfSources
)
67 // Add additional sources to the list
70 ALsource
*source
= calloc(1, sizeof(ALsource
));
73 alSetError(Context
, AL_OUT_OF_MEMORY
);
74 alDeleteSources(i
, sources
);
78 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
79 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
81 if(err
!= AL_NO_ERROR
)
83 ALTHUNK_REMOVEENTRY(source
->source
);
84 memset(source
, 0, sizeof(ALsource
));
87 alSetError(Context
, err
);
88 alDeleteSources(i
, sources
);
92 sources
[i
++] = source
->source
;
93 InitSourceParams(source
);
98 // Not enough resources to create the Sources
99 alSetError(Context
, AL_INVALID_VALUE
);
105 alSetError(Context
, AL_INVALID_VALUE
);
109 ProcessContext(Context
);
113 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
119 ALbufferlistitem
*BufferList
;
120 ALboolean bSourcesValid
= AL_TRUE
;
122 Context
= GetContextSuspended();
127 Device
= Context
->Device
;
129 // Check that all Sources are valid (and can therefore be deleted)
130 for (i
= 0; i
< n
; i
++)
132 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
134 alSetError(Context
, AL_INVALID_NAME
);
135 bSourcesValid
= AL_FALSE
;
142 // All Sources are valid, and can be deleted
143 for(i
= 0; i
< n
; i
++)
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) != NULL
)
148 // For each buffer in the source's queue, decrement its reference counter and remove it
149 while(Source
->queue
!= NULL
)
151 BufferList
= Source
->queue
;
152 // Decrement buffer's reference counter
153 if(BufferList
->buffer
!= NULL
)
154 BufferList
->buffer
->refcount
--;
155 // Update queue to point to next element in list
156 Source
->queue
= BufferList
->next
;
157 // Release memory allocated for buffer list item
161 for(j
= 0;j
< MAX_SENDS
;++j
)
163 if(Source
->Send
[j
].Slot
)
164 Source
->Send
[j
].Slot
->refcount
--;
165 Source
->Send
[j
].Slot
= NULL
;
168 // Remove Source from list of Sources
169 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
170 ALTHUNK_REMOVEENTRY(Source
->source
);
172 memset(Source
,0,sizeof(ALsource
));
179 alSetError(Context
, AL_INVALID_VALUE
);
181 ProcessContext(Context
);
185 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
190 Context
= GetContextSuspended();
191 if(!Context
) return AL_FALSE
;
193 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
195 ProcessContext(Context
);
201 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
203 ALCcontext
*pContext
;
206 pContext
= GetContextSuspended();
207 if(!pContext
) return;
209 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
216 Source
->flPitch
= flValue
;
217 if(Source
->flPitch
< 0.001f
)
218 Source
->flPitch
= 0.001f
;
219 Source
->NeedsUpdate
= AL_TRUE
;
222 alSetError(pContext
, AL_INVALID_VALUE
);
225 case AL_CONE_INNER_ANGLE
:
226 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
228 Source
->flInnerAngle
= flValue
;
229 Source
->NeedsUpdate
= AL_TRUE
;
232 alSetError(pContext
, AL_INVALID_VALUE
);
235 case AL_CONE_OUTER_ANGLE
:
236 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
238 Source
->flOuterAngle
= flValue
;
239 Source
->NeedsUpdate
= AL_TRUE
;
242 alSetError(pContext
, AL_INVALID_VALUE
);
248 Source
->flGain
= flValue
;
249 Source
->NeedsUpdate
= AL_TRUE
;
252 alSetError(pContext
, AL_INVALID_VALUE
);
255 case AL_MAX_DISTANCE
:
258 Source
->flMaxDistance
= flValue
;
259 Source
->NeedsUpdate
= AL_TRUE
;
262 alSetError(pContext
, AL_INVALID_VALUE
);
265 case AL_ROLLOFF_FACTOR
:
268 Source
->flRollOffFactor
= flValue
;
269 Source
->NeedsUpdate
= AL_TRUE
;
272 alSetError(pContext
, AL_INVALID_VALUE
);
275 case AL_REFERENCE_DISTANCE
:
278 Source
->flRefDistance
= flValue
;
279 Source
->NeedsUpdate
= AL_TRUE
;
282 alSetError(pContext
, AL_INVALID_VALUE
);
286 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
288 Source
->flMinGain
= flValue
;
289 Source
->NeedsUpdate
= AL_TRUE
;
292 alSetError(pContext
, AL_INVALID_VALUE
);
296 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
298 Source
->flMaxGain
= flValue
;
299 Source
->NeedsUpdate
= AL_TRUE
;
302 alSetError(pContext
, AL_INVALID_VALUE
);
305 case AL_CONE_OUTER_GAIN
:
306 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
308 Source
->flOuterGain
= flValue
;
309 Source
->NeedsUpdate
= AL_TRUE
;
312 alSetError(pContext
, AL_INVALID_VALUE
);
315 case AL_CONE_OUTER_GAINHF
:
316 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
318 Source
->OuterGainHF
= flValue
;
319 Source
->NeedsUpdate
= AL_TRUE
;
322 alSetError(pContext
, AL_INVALID_VALUE
);
325 case AL_AIR_ABSORPTION_FACTOR
:
326 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
328 Source
->AirAbsorptionFactor
= flValue
;
329 Source
->NeedsUpdate
= AL_TRUE
;
332 alSetError(pContext
, AL_INVALID_VALUE
);
335 case AL_ROOM_ROLLOFF_FACTOR
:
336 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
338 Source
->RoomRolloffFactor
= flValue
;
339 Source
->NeedsUpdate
= AL_TRUE
;
342 alSetError(pContext
, AL_INVALID_VALUE
);
345 case AL_DOPPLER_FACTOR
:
346 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
348 Source
->DopplerFactor
= flValue
;
349 Source
->NeedsUpdate
= AL_TRUE
;
352 alSetError(pContext
, AL_INVALID_VALUE
);
356 case AL_SAMPLE_OFFSET
:
360 Source
->lOffsetType
= eParam
;
362 // Store Offset (convert Seconds into Milliseconds)
363 if(eParam
== AL_SEC_OFFSET
)
364 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
366 Source
->lOffset
= (ALint
)flValue
;
368 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
370 if(ApplyOffset(Source
) == AL_FALSE
)
371 alSetError(pContext
, AL_INVALID_VALUE
);
375 alSetError(pContext
, AL_INVALID_VALUE
);
379 alSetError(pContext
, AL_INVALID_ENUM
);
385 // Invalid Source Name
386 alSetError(pContext
, AL_INVALID_NAME
);
389 ProcessContext(pContext
);
393 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
395 ALCcontext
*pContext
;
398 pContext
= GetContextSuspended();
399 if(!pContext
) return;
401 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
406 Source
->vPosition
[0] = flValue1
;
407 Source
->vPosition
[1] = flValue2
;
408 Source
->vPosition
[2] = flValue3
;
409 Source
->NeedsUpdate
= AL_TRUE
;
413 Source
->vVelocity
[0] = flValue1
;
414 Source
->vVelocity
[1] = flValue2
;
415 Source
->vVelocity
[2] = flValue3
;
416 Source
->NeedsUpdate
= AL_TRUE
;
420 Source
->vOrientation
[0] = flValue1
;
421 Source
->vOrientation
[1] = flValue2
;
422 Source
->vOrientation
[2] = flValue3
;
423 Source
->NeedsUpdate
= AL_TRUE
;
427 alSetError(pContext
, AL_INVALID_ENUM
);
432 alSetError(pContext
, AL_INVALID_NAME
);
434 ProcessContext(pContext
);
438 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
440 ALCcontext
*pContext
;
442 pContext
= GetContextSuspended();
443 if(!pContext
) return;
447 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
452 case AL_CONE_INNER_ANGLE
:
453 case AL_CONE_OUTER_ANGLE
:
455 case AL_MAX_DISTANCE
:
456 case AL_ROLLOFF_FACTOR
:
457 case AL_REFERENCE_DISTANCE
:
460 case AL_CONE_OUTER_GAIN
:
461 case AL_CONE_OUTER_GAINHF
:
463 case AL_SAMPLE_OFFSET
:
465 case AL_AIR_ABSORPTION_FACTOR
:
466 case AL_ROOM_ROLLOFF_FACTOR
:
467 alSourcef(source
, eParam
, pflValues
[0]);
473 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
477 alSetError(pContext
, AL_INVALID_ENUM
);
482 alSetError(pContext
, AL_INVALID_NAME
);
485 alSetError(pContext
, AL_INVALID_VALUE
);
487 ProcessContext(pContext
);
491 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
493 ALCcontext
*pContext
;
495 ALbufferlistitem
*BufferListItem
;
497 pContext
= GetContextSuspended();
498 if(!pContext
) return;
500 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
502 ALCdevice
*device
= pContext
->Device
;
506 case AL_MAX_DISTANCE
:
507 case AL_ROLLOFF_FACTOR
:
508 case AL_CONE_INNER_ANGLE
:
509 case AL_CONE_OUTER_ANGLE
:
510 case AL_REFERENCE_DISTANCE
:
511 alSourcef(source
, eParam
, (ALfloat
)lValue
);
514 case AL_SOURCE_RELATIVE
:
515 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
517 Source
->bHeadRelative
= (ALboolean
)lValue
;
518 Source
->NeedsUpdate
= AL_TRUE
;
521 alSetError(pContext
, AL_INVALID_VALUE
);
525 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
526 Source
->bLooping
= (ALboolean
)lValue
;
528 alSetError(pContext
, AL_INVALID_VALUE
);
532 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
534 ALbuffer
*buffer
= NULL
;
537 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
539 // Remove all elements in the queue
540 while(Source
->queue
!= NULL
)
542 BufferListItem
= Source
->queue
;
543 Source
->queue
= BufferListItem
->next
;
544 // Decrement reference counter for buffer
545 if(BufferListItem
->buffer
)
546 BufferListItem
->buffer
->refcount
--;
547 // Release memory for buffer list item
548 free(BufferListItem
);
549 // Decrement the number of buffers in the queue
550 Source
->BuffersInQueue
--;
553 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
556 // Source is now in STATIC mode
557 Source
->lSourceType
= AL_STATIC
;
559 // Add the selected buffer to the queue
560 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
561 BufferListItem
->buffer
= buffer
;
562 BufferListItem
->next
= NULL
;
564 Source
->queue
= BufferListItem
;
565 Source
->BuffersInQueue
= 1;
567 Source
->LoopStart
= buffer
->LoopStart
;
568 Source
->LoopEnd
= buffer
->LoopEnd
;
570 // Increment reference counter for buffer
575 // Source is now in UNDETERMINED mode
576 Source
->lSourceType
= AL_UNDETERMINED
;
578 Source
->BuffersPlayed
= 0;
580 // Update AL_BUFFER parameter
581 Source
->Buffer
= buffer
;
582 Source
->NeedsUpdate
= AL_TRUE
;
585 alSetError(pContext
, AL_INVALID_VALUE
);
588 alSetError(pContext
, AL_INVALID_OPERATION
);
591 case AL_SOURCE_STATE
:
593 alSetError(pContext
, AL_INVALID_OPERATION
);
597 case AL_SAMPLE_OFFSET
:
601 Source
->lOffsetType
= eParam
;
603 // Store Offset (convert Seconds into Milliseconds)
604 if(eParam
== AL_SEC_OFFSET
)
605 Source
->lOffset
= lValue
* 1000;
607 Source
->lOffset
= lValue
;
609 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
611 if(ApplyOffset(Source
) == AL_FALSE
)
612 alSetError(pContext
, AL_INVALID_VALUE
);
616 alSetError(pContext
, AL_INVALID_VALUE
);
619 case AL_DIRECT_FILTER
: {
620 ALfilter
*filter
= NULL
;
623 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
627 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
628 Source
->DirectFilter
.filter
= 0;
631 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
632 Source
->NeedsUpdate
= AL_TRUE
;
635 alSetError(pContext
, AL_INVALID_VALUE
);
638 case AL_DIRECT_FILTER_GAINHF_AUTO
:
639 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
641 Source
->DryGainHFAuto
= lValue
;
642 Source
->NeedsUpdate
= AL_TRUE
;
645 alSetError(pContext
, AL_INVALID_VALUE
);
648 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
649 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
651 Source
->WetGainAuto
= lValue
;
652 Source
->NeedsUpdate
= AL_TRUE
;
655 alSetError(pContext
, AL_INVALID_VALUE
);
658 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
659 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
661 Source
->WetGainHFAuto
= lValue
;
662 Source
->NeedsUpdate
= AL_TRUE
;
665 alSetError(pContext
, AL_INVALID_VALUE
);
668 case AL_DISTANCE_MODEL
:
669 if(lValue
== AL_NONE
||
670 lValue
== AL_INVERSE_DISTANCE
||
671 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
672 lValue
== AL_LINEAR_DISTANCE
||
673 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
674 lValue
== AL_EXPONENT_DISTANCE
||
675 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
677 Source
->DistanceModel
= lValue
;
678 if(pContext
->SourceDistanceModel
)
679 Source
->NeedsUpdate
= AL_TRUE
;
682 alSetError(pContext
, AL_INVALID_VALUE
);
686 alSetError(pContext
, AL_INVALID_ENUM
);
691 alSetError(pContext
, AL_INVALID_NAME
);
693 ProcessContext(pContext
);
697 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
699 ALCcontext
*pContext
;
702 pContext
= GetContextSuspended();
703 if(!pContext
) return;
705 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
707 ALCdevice
*device
= pContext
->Device
;
714 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
717 case AL_AUXILIARY_SEND_FILTER
: {
718 ALeffectslot
*ALEffectSlot
= NULL
;
719 ALfilter
*ALFilter
= NULL
;
721 if((ALuint
)lValue2
< device
->NumAuxSends
&&
723 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
725 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
727 /* Release refcount on the previous slot, and add one for
729 if(Source
->Send
[lValue2
].Slot
)
730 Source
->Send
[lValue2
].Slot
->refcount
--;
731 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
732 if(Source
->Send
[lValue2
].Slot
)
733 Source
->Send
[lValue2
].Slot
->refcount
++;
738 Source
->Send
[lValue2
].WetFilter
.type
= 0;
739 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
742 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
743 Source
->NeedsUpdate
= AL_TRUE
;
746 alSetError(pContext
, AL_INVALID_VALUE
);
750 alSetError(pContext
, AL_INVALID_ENUM
);
755 alSetError(pContext
, AL_INVALID_NAME
);
757 ProcessContext(pContext
);
761 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
763 ALCcontext
*pContext
;
765 pContext
= GetContextSuspended();
766 if(!pContext
) return;
770 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
774 case AL_SOURCE_RELATIVE
:
775 case AL_CONE_INNER_ANGLE
:
776 case AL_CONE_OUTER_ANGLE
:
779 case AL_SOURCE_STATE
:
781 case AL_SAMPLE_OFFSET
:
783 case AL_MAX_DISTANCE
:
784 case AL_ROLLOFF_FACTOR
:
785 case AL_REFERENCE_DISTANCE
:
786 case AL_DIRECT_FILTER
:
787 case AL_DIRECT_FILTER_GAINHF_AUTO
:
788 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
789 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
790 case AL_DISTANCE_MODEL
:
791 alSourcei(source
, eParam
, plValues
[0]);
797 case AL_AUXILIARY_SEND_FILTER
:
798 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
802 alSetError(pContext
, AL_INVALID_ENUM
);
807 alSetError(pContext
, AL_INVALID_NAME
);
810 alSetError(pContext
, AL_INVALID_VALUE
);
812 ProcessContext(pContext
);
816 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
818 ALCcontext
*pContext
;
823 pContext
= GetContextSuspended();
824 if(!pContext
) return;
828 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
833 *pflValue
= Source
->flPitch
;
837 *pflValue
= Source
->flGain
;
841 *pflValue
= Source
->flMinGain
;
845 *pflValue
= Source
->flMaxGain
;
848 case AL_MAX_DISTANCE
:
849 *pflValue
= Source
->flMaxDistance
;
852 case AL_ROLLOFF_FACTOR
:
853 *pflValue
= Source
->flRollOffFactor
;
856 case AL_CONE_OUTER_GAIN
:
857 *pflValue
= Source
->flOuterGain
;
860 case AL_CONE_OUTER_GAINHF
:
861 *pflValue
= Source
->OuterGainHF
;
865 case AL_SAMPLE_OFFSET
:
867 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
868 pContext
->Device
->Frequency
;
869 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
870 *pflValue
= Offsets
[0];
873 case AL_CONE_INNER_ANGLE
:
874 *pflValue
= Source
->flInnerAngle
;
877 case AL_CONE_OUTER_ANGLE
:
878 *pflValue
= Source
->flOuterAngle
;
881 case AL_REFERENCE_DISTANCE
:
882 *pflValue
= Source
->flRefDistance
;
885 case AL_AIR_ABSORPTION_FACTOR
:
886 *pflValue
= Source
->AirAbsorptionFactor
;
889 case AL_ROOM_ROLLOFF_FACTOR
:
890 *pflValue
= Source
->RoomRolloffFactor
;
893 case AL_DOPPLER_FACTOR
:
894 *pflValue
= Source
->DopplerFactor
;
898 alSetError(pContext
, AL_INVALID_ENUM
);
903 alSetError(pContext
, AL_INVALID_NAME
);
906 alSetError(pContext
, AL_INVALID_VALUE
);
908 ProcessContext(pContext
);
912 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
914 ALCcontext
*pContext
;
917 pContext
= GetContextSuspended();
918 if(!pContext
) return;
920 if(pflValue1
&& pflValue2
&& pflValue3
)
922 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
927 *pflValue1
= Source
->vPosition
[0];
928 *pflValue2
= Source
->vPosition
[1];
929 *pflValue3
= Source
->vPosition
[2];
933 *pflValue1
= Source
->vVelocity
[0];
934 *pflValue2
= Source
->vVelocity
[1];
935 *pflValue3
= Source
->vVelocity
[2];
939 *pflValue1
= Source
->vOrientation
[0];
940 *pflValue2
= Source
->vOrientation
[1];
941 *pflValue3
= Source
->vOrientation
[2];
945 alSetError(pContext
, AL_INVALID_ENUM
);
950 alSetError(pContext
, AL_INVALID_NAME
);
953 alSetError(pContext
, AL_INVALID_VALUE
);
955 ProcessContext(pContext
);
959 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
961 ALCcontext
*pContext
;
966 pContext
= GetContextSuspended();
967 if(!pContext
) return;
971 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
979 case AL_MAX_DISTANCE
:
980 case AL_ROLLOFF_FACTOR
:
981 case AL_DOPPLER_FACTOR
:
982 case AL_CONE_OUTER_GAIN
:
984 case AL_SAMPLE_OFFSET
:
986 case AL_CONE_INNER_ANGLE
:
987 case AL_CONE_OUTER_ANGLE
:
988 case AL_REFERENCE_DISTANCE
:
989 case AL_CONE_OUTER_GAINHF
:
990 case AL_AIR_ABSORPTION_FACTOR
:
991 case AL_ROOM_ROLLOFF_FACTOR
:
992 alGetSourcef(source
, eParam
, pflValues
);
995 case AL_SAMPLE_RW_OFFSETS_EXT
:
996 case AL_BYTE_RW_OFFSETS_EXT
:
997 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
998 pContext
->Device
->Frequency
;
999 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1000 pflValues
[0] = Offsets
[0];
1001 pflValues
[1] = Offsets
[1];
1005 pflValues
[0] = Source
->vPosition
[0];
1006 pflValues
[1] = Source
->vPosition
[1];
1007 pflValues
[2] = Source
->vPosition
[2];
1011 pflValues
[0] = Source
->vVelocity
[0];
1012 pflValues
[1] = Source
->vVelocity
[1];
1013 pflValues
[2] = Source
->vVelocity
[2];
1017 pflValues
[0] = Source
->vOrientation
[0];
1018 pflValues
[1] = Source
->vOrientation
[1];
1019 pflValues
[2] = Source
->vOrientation
[2];
1023 alSetError(pContext
, AL_INVALID_ENUM
);
1028 alSetError(pContext
, AL_INVALID_NAME
);
1031 alSetError(pContext
, AL_INVALID_VALUE
);
1033 ProcessContext(pContext
);
1037 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1039 ALCcontext
*pContext
;
1041 ALdouble Offsets
[2];
1044 pContext
= GetContextSuspended();
1045 if(!pContext
) return;
1049 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1053 case AL_MAX_DISTANCE
:
1054 *plValue
= (ALint
)Source
->flMaxDistance
;
1057 case AL_ROLLOFF_FACTOR
:
1058 *plValue
= (ALint
)Source
->flRollOffFactor
;
1061 case AL_REFERENCE_DISTANCE
:
1062 *plValue
= (ALint
)Source
->flRefDistance
;
1065 case AL_SOURCE_RELATIVE
:
1066 *plValue
= Source
->bHeadRelative
;
1069 case AL_CONE_INNER_ANGLE
:
1070 *plValue
= (ALint
)Source
->flInnerAngle
;
1073 case AL_CONE_OUTER_ANGLE
:
1074 *plValue
= (ALint
)Source
->flOuterAngle
;
1078 *plValue
= Source
->bLooping
;
1082 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1085 case AL_SOURCE_STATE
:
1086 *plValue
= Source
->state
;
1089 case AL_BUFFERS_QUEUED
:
1090 *plValue
= Source
->BuffersInQueue
;
1093 case AL_BUFFERS_PROCESSED
:
1094 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1096 /* Buffers on a looping source are in a perpetual state
1097 * of PENDING, so don't report any as PROCESSED */
1101 *plValue
= Source
->BuffersPlayed
;
1104 case AL_SOURCE_TYPE
:
1105 *plValue
= Source
->lSourceType
;
1109 case AL_SAMPLE_OFFSET
:
1110 case AL_BYTE_OFFSET
:
1111 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1112 pContext
->Device
->Frequency
;
1113 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1114 *plValue
= (ALint
)Offsets
[0];
1117 case AL_DIRECT_FILTER
:
1118 *plValue
= Source
->DirectFilter
.filter
;
1121 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1122 *plValue
= Source
->DryGainHFAuto
;
1125 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1126 *plValue
= Source
->WetGainAuto
;
1129 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1130 *plValue
= Source
->WetGainHFAuto
;
1133 case AL_DOPPLER_FACTOR
:
1134 *plValue
= (ALint
)Source
->DopplerFactor
;
1137 case AL_DISTANCE_MODEL
:
1138 *plValue
= Source
->DistanceModel
;
1142 alSetError(pContext
, AL_INVALID_ENUM
);
1147 alSetError(pContext
, AL_INVALID_NAME
);
1150 alSetError(pContext
, AL_INVALID_VALUE
);
1152 ProcessContext(pContext
);
1156 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1158 ALCcontext
*pContext
;
1161 pContext
= GetContextSuspended();
1162 if(!pContext
) return;
1164 if(plValue1
&& plValue2
&& plValue3
)
1166 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1171 *plValue1
= (ALint
)Source
->vPosition
[0];
1172 *plValue2
= (ALint
)Source
->vPosition
[1];
1173 *plValue3
= (ALint
)Source
->vPosition
[2];
1177 *plValue1
= (ALint
)Source
->vVelocity
[0];
1178 *plValue2
= (ALint
)Source
->vVelocity
[1];
1179 *plValue3
= (ALint
)Source
->vVelocity
[2];
1183 *plValue1
= (ALint
)Source
->vOrientation
[0];
1184 *plValue2
= (ALint
)Source
->vOrientation
[1];
1185 *plValue3
= (ALint
)Source
->vOrientation
[2];
1189 alSetError(pContext
, AL_INVALID_ENUM
);
1194 alSetError(pContext
, AL_INVALID_NAME
);
1197 alSetError(pContext
, AL_INVALID_VALUE
);
1199 ProcessContext(pContext
);
1203 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1205 ALCcontext
*pContext
;
1207 ALdouble Offsets
[2];
1210 pContext
= GetContextSuspended();
1211 if(!pContext
) return;
1215 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1219 case AL_SOURCE_RELATIVE
:
1220 case AL_CONE_INNER_ANGLE
:
1221 case AL_CONE_OUTER_ANGLE
:
1224 case AL_SOURCE_STATE
:
1225 case AL_BUFFERS_QUEUED
:
1226 case AL_BUFFERS_PROCESSED
:
1228 case AL_SAMPLE_OFFSET
:
1229 case AL_BYTE_OFFSET
:
1230 case AL_MAX_DISTANCE
:
1231 case AL_ROLLOFF_FACTOR
:
1232 case AL_DOPPLER_FACTOR
:
1233 case AL_REFERENCE_DISTANCE
:
1234 case AL_SOURCE_TYPE
:
1235 case AL_DIRECT_FILTER
:
1236 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1237 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1238 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1239 case AL_DISTANCE_MODEL
:
1240 alGetSourcei(source
, eParam
, plValues
);
1243 case AL_SAMPLE_RW_OFFSETS_EXT
:
1244 case AL_BYTE_RW_OFFSETS_EXT
:
1245 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1246 pContext
->Device
->Frequency
;
1247 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1248 plValues
[0] = (ALint
)Offsets
[0];
1249 plValues
[1] = (ALint
)Offsets
[1];
1253 plValues
[0] = (ALint
)Source
->vPosition
[0];
1254 plValues
[1] = (ALint
)Source
->vPosition
[1];
1255 plValues
[2] = (ALint
)Source
->vPosition
[2];
1259 plValues
[0] = (ALint
)Source
->vVelocity
[0];
1260 plValues
[1] = (ALint
)Source
->vVelocity
[1];
1261 plValues
[2] = (ALint
)Source
->vVelocity
[2];
1265 plValues
[0] = (ALint
)Source
->vOrientation
[0];
1266 plValues
[1] = (ALint
)Source
->vOrientation
[1];
1267 plValues
[2] = (ALint
)Source
->vOrientation
[2];
1271 alSetError(pContext
, AL_INVALID_ENUM
);
1276 alSetError(pContext
, AL_INVALID_NAME
);
1279 alSetError(pContext
, AL_INVALID_VALUE
);
1281 ProcessContext(pContext
);
1285 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1287 alSourcePlayv(1, &source
);
1290 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1292 ALCcontext
*Context
;
1294 ALbufferlistitem
*BufferList
;
1297 Context
= GetContextSuspended();
1298 if(!Context
) return;
1302 alSetError(Context
, AL_INVALID_VALUE
);
1306 // Check that all the Sources are valid
1307 for(i
= 0;i
< n
;i
++)
1309 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1311 alSetError(Context
, AL_INVALID_NAME
);
1316 for(i
= 0;i
< n
;i
++)
1318 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1320 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1321 BufferList
= Source
->queue
;
1324 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1326 BufferList
= BufferList
->next
;
1331 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1335 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1336 Source
->DryGains
[j
] = 0.0f
;
1337 for(j
= 0;j
< MAX_SENDS
;j
++)
1338 Source
->WetGains
[j
] = 0.0f
;
1340 if(Source
->state
!= AL_PAUSED
)
1342 Source
->state
= AL_PLAYING
;
1343 Source
->position
= 0;
1344 Source
->position_fraction
= 0;
1345 Source
->BuffersPlayed
= 0;
1347 Source
->Buffer
= Source
->queue
->buffer
;
1350 Source
->state
= AL_PLAYING
;
1352 // Check if an Offset has been set
1354 ApplyOffset(Source
);
1356 if(Source
->BuffersPlayed
== 0 && Source
->position
== 0 &&
1357 Source
->position_fraction
== 0)
1358 Source
->FirstStart
= AL_TRUE
;
1360 Source
->FirstStart
= AL_FALSE
;
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;
1373 ProcessContext(Context
);
1376 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1378 alSourcePausev(1, &source
);
1381 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1383 ALCcontext
*Context
;
1387 Context
= GetContextSuspended();
1388 if(!Context
) return;
1392 alSetError(Context
, AL_INVALID_VALUE
);
1396 // Check all the Sources are valid
1397 for(i
= 0;i
< n
;i
++)
1399 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1401 alSetError(Context
, AL_INVALID_NAME
);
1406 for(i
= 0;i
< n
;i
++)
1408 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1409 if(Source
->state
== AL_PLAYING
)
1410 Source
->state
= AL_PAUSED
;
1414 ProcessContext(Context
);
1417 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1419 alSourceStopv(1, &source
);
1422 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1424 ALCcontext
*Context
;
1428 Context
= GetContextSuspended();
1429 if(!Context
) return;
1433 alSetError(Context
, AL_INVALID_VALUE
);
1437 // Check all the Sources are valid
1438 for(i
= 0;i
< n
;i
++)
1440 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1442 alSetError(Context
, AL_INVALID_NAME
);
1447 for(i
= 0;i
< n
;i
++)
1449 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1450 if(Source
->state
!= AL_INITIAL
)
1452 Source
->state
= AL_STOPPED
;
1453 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1455 Source
->lOffset
= 0;
1459 ProcessContext(Context
);
1462 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1464 alSourceRewindv(1, &source
);
1467 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1469 ALCcontext
*Context
;
1473 Context
= GetContextSuspended();
1474 if(!Context
) return;
1478 alSetError(Context
, AL_INVALID_VALUE
);
1482 // Check all the Sources are valid
1483 for(i
= 0;i
< n
;i
++)
1485 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1487 alSetError(Context
, AL_INVALID_NAME
);
1492 for(i
= 0;i
< n
;i
++)
1494 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1495 if(Source
->state
!= AL_INITIAL
)
1497 Source
->state
= AL_INITIAL
;
1498 Source
->position
= 0;
1499 Source
->position_fraction
= 0;
1500 Source
->BuffersPlayed
= 0;
1502 Source
->Buffer
= Source
->queue
->buffer
;
1504 Source
->lOffset
= 0;
1508 ProcessContext(Context
);
1512 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1514 ALCcontext
*Context
;
1519 ALbufferlistitem
*BufferListStart
;
1520 ALbufferlistitem
*BufferList
;
1521 ALboolean HadFormat
;
1528 Context
= GetContextSuspended();
1529 if(!Context
) return;
1531 // Check that all buffers are valid or zero and that the source is valid
1533 // Check that this is a valid source
1534 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1536 alSetError(Context
, AL_INVALID_NAME
);
1540 // Check that this is not a STATIC Source
1541 if(Source
->lSourceType
== AL_STATIC
)
1543 // Invalid Source Type (can't queue on a Static Source)
1544 alSetError(Context
, AL_INVALID_OPERATION
);
1548 device
= Context
->Device
;
1552 HadFormat
= AL_FALSE
;
1554 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1555 BufferList
= Source
->queue
;
1558 if(BufferList
->buffer
)
1560 Frequency
= BufferList
->buffer
->frequency
;
1561 Format
= BufferList
->buffer
->format
;
1562 HadFormat
= AL_TRUE
;
1565 BufferList
= BufferList
->next
;
1568 for(i
= 0;i
< n
;i
++)
1573 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1575 alSetError(Context
, AL_INVALID_NAME
);
1579 if(Frequency
== -1 && Format
== -1)
1581 Frequency
= buffer
->frequency
;
1582 Format
= buffer
->format
;
1584 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->format
)
1586 alSetError(Context
, AL_INVALID_OPERATION
);
1591 // Change Source Type
1592 Source
->lSourceType
= AL_STREAMING
;
1594 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1596 // All buffers are valid - so add them to the list
1597 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1598 BufferListStart
->buffer
= buffer
;
1599 BufferListStart
->next
= NULL
;
1601 // Increment reference counter for buffer
1602 if(buffer
) buffer
->refcount
++;
1604 BufferList
= BufferListStart
;
1606 for(i
= 1;i
< n
;i
++)
1608 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1610 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1611 BufferList
->next
->buffer
= buffer
;
1612 BufferList
->next
->next
= NULL
;
1614 // Increment reference counter for buffer
1615 if(buffer
) buffer
->refcount
++;
1617 BufferList
= BufferList
->next
;
1620 if(Source
->queue
== NULL
)
1622 Source
->queue
= BufferListStart
;
1623 // Update Current Buffer
1624 Source
->Buffer
= BufferListStart
->buffer
;
1628 // Find end of queue
1629 BufferList
= Source
->queue
;
1630 while(BufferList
->next
!= NULL
)
1631 BufferList
= BufferList
->next
;
1633 BufferList
->next
= BufferListStart
;
1636 // Update number of buffers in queue
1637 Source
->BuffersInQueue
+= n
;
1638 // If no previous format, mark the source dirty now that it may have one
1640 Source
->NeedsUpdate
= AL_TRUE
;
1643 ProcessContext(Context
);
1647 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1648 // an array of buffer IDs that are to be filled with the names of the buffers removed
1649 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1651 ALCcontext
*Context
;
1654 ALbufferlistitem
*BufferList
;
1659 Context
= GetContextSuspended();
1660 if(!Context
) return;
1662 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1664 alSetError(Context
, AL_INVALID_NAME
);
1668 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1669 (ALuint
)n
> Source
->BuffersPlayed
)
1671 // Some buffers can't be unqueue because they have not been processed
1672 alSetError(Context
, AL_INVALID_VALUE
);
1676 for(i
= 0;i
< n
;i
++)
1678 BufferList
= Source
->queue
;
1679 Source
->queue
= BufferList
->next
;
1681 if(BufferList
->buffer
)
1683 // Record name of buffer
1684 buffers
[i
] = BufferList
->buffer
->buffer
;
1685 // Decrement buffer reference counter
1686 BufferList
->buffer
->refcount
--;
1691 // Release memory for buffer list item
1693 Source
->BuffersInQueue
--;
1696 if(Source
->state
!= AL_PLAYING
)
1699 Source
->Buffer
= Source
->queue
->buffer
;
1701 Source
->Buffer
= NULL
;
1703 Source
->BuffersPlayed
-= n
;
1706 ProcessContext(Context
);
1710 static ALvoid
InitSourceParams(ALsource
*Source
)
1712 Source
->flInnerAngle
= 360.0f
;
1713 Source
->flOuterAngle
= 360.0f
;
1714 Source
->flPitch
= 1.0f
;
1715 Source
->vPosition
[0] = 0.0f
;
1716 Source
->vPosition
[1] = 0.0f
;
1717 Source
->vPosition
[2] = 0.0f
;
1718 Source
->vOrientation
[0] = 0.0f
;
1719 Source
->vOrientation
[1] = 0.0f
;
1720 Source
->vOrientation
[2] = 0.0f
;
1721 Source
->vVelocity
[0] = 0.0f
;
1722 Source
->vVelocity
[1] = 0.0f
;
1723 Source
->vVelocity
[2] = 0.0f
;
1724 Source
->flRefDistance
= 1.0f
;
1725 Source
->flMaxDistance
= FLT_MAX
;
1726 Source
->flRollOffFactor
= 1.0f
;
1727 Source
->bLooping
= AL_FALSE
;
1728 Source
->flGain
= 1.0f
;
1729 Source
->flMinGain
= 0.0f
;
1730 Source
->flMaxGain
= 1.0f
;
1731 Source
->flOuterGain
= 0.0f
;
1732 Source
->OuterGainHF
= 1.0f
;
1734 Source
->DryGainHFAuto
= AL_TRUE
;
1735 Source
->WetGainAuto
= AL_TRUE
;
1736 Source
->WetGainHFAuto
= AL_TRUE
;
1737 Source
->AirAbsorptionFactor
= 0.0f
;
1738 Source
->RoomRolloffFactor
= 0.0f
;
1739 Source
->DopplerFactor
= 1.0f
;
1741 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1743 Source
->Resampler
= DefaultResampler
;
1745 Source
->state
= AL_INITIAL
;
1746 Source
->lSourceType
= AL_UNDETERMINED
;
1748 Source
->NeedsUpdate
= AL_TRUE
;
1750 Source
->Buffer
= NULL
;
1757 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1758 The offset is relative to the start of the queue (not the start of the current buffer)
1760 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1762 ALbufferlistitem
*BufferList
;
1763 ALbuffer
*Buffer
= NULL
;
1765 ALint Channels
, Bytes
;
1766 ALuint readPos
, writePos
;
1767 ALenum OriginalFormat
;
1768 ALuint TotalBufferDataSize
;
1771 // Find the first non-NULL Buffer in the Queue
1772 BufferList
= Source
->queue
;
1775 if(BufferList
->buffer
)
1777 Buffer
= BufferList
->buffer
;
1780 BufferList
= BufferList
->next
;
1783 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1790 // Get Current Buffer Size and frequency (in milliseconds)
1791 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1792 OriginalFormat
= Buffer
->eOriginalFormat
;
1793 Channels
= aluChannelsFromFormat(Buffer
->format
);
1794 Bytes
= aluBytesFromFormat(Buffer
->format
);
1796 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1797 readPos
= Source
->position
* Channels
* Bytes
;
1798 // Add byte length of any processed buffers in the queue
1799 TotalBufferDataSize
= 0;
1800 BufferList
= Source
->queue
;
1801 for(i
= 0;BufferList
;i
++)
1803 if(BufferList
->buffer
)
1805 if(i
< Source
->BuffersPlayed
)
1806 readPos
+= BufferList
->buffer
->size
;
1807 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1809 BufferList
= BufferList
->next
;
1811 if(Source
->state
== AL_PLAYING
)
1812 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1816 if(Source
->bLooping
)
1818 readPos
%= TotalBufferDataSize
;
1819 writePos
%= TotalBufferDataSize
;
1823 // Clamp positions to TotalBufferDataSize
1824 if(readPos
> TotalBufferDataSize
)
1825 readPos
= TotalBufferDataSize
;
1826 if(writePos
> TotalBufferDataSize
)
1827 writePos
= TotalBufferDataSize
;
1833 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1834 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1836 case AL_SAMPLE_OFFSET
:
1837 case AL_SAMPLE_RW_OFFSETS_EXT
:
1838 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1839 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1841 case AL_BYTE_OFFSET
:
1842 case AL_BYTE_RW_OFFSETS_EXT
:
1843 // Take into account the original format of the Buffer
1844 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1845 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1847 // Round down to nearest ADPCM block
1848 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1849 if(Source
->state
== AL_PLAYING
)
1851 // Round up to nearest ADPCM block
1852 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1855 offset
[1] = offset
[0];
1857 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1858 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1859 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1860 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1861 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1862 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1864 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1865 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1867 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1869 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1870 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1872 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1874 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1875 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1877 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1879 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1880 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1882 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1884 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1885 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1889 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1890 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1891 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1901 Apply a playback offset to the Source. This function will update the queue (to correctly
1902 mark buffers as 'pending' or 'processed' depending upon the new offset.
1904 static ALboolean
ApplyOffset(ALsource
*Source
)
1906 ALbufferlistitem
*BufferList
;
1908 ALint lBufferSize
, lTotalBufferSize
;
1909 ALint BuffersPlayed
;
1912 // Get true byte offset
1913 lByteOffset
= GetByteOffset(Source
);
1915 // If the offset is invalid, don't apply it
1916 if(lByteOffset
== -1)
1919 // Sort out the queue (pending and processed states)
1920 BufferList
= Source
->queue
;
1921 lTotalBufferSize
= 0;
1926 Buffer
= BufferList
->buffer
;
1927 lBufferSize
= Buffer
? Buffer
->size
: 0;
1929 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1931 // Offset is past this buffer so increment BuffersPlayed
1934 else if(lTotalBufferSize
<= lByteOffset
)
1936 // Offset is within this buffer
1937 // Set Current Buffer
1938 Source
->Buffer
= BufferList
->buffer
;
1939 Source
->BuffersPlayed
= BuffersPlayed
;
1941 // SW Mixer Positions are in Samples
1942 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1943 aluBytesFromFormat(Buffer
->format
) /
1944 aluChannelsFromFormat(Buffer
->format
);
1948 // Increment the TotalBufferSize
1949 lTotalBufferSize
+= lBufferSize
;
1951 // Move on to next buffer in the Queue
1952 BufferList
= BufferList
->next
;
1954 // Offset is out of range of the buffer queue
1962 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1963 offset supplied by the application). This takes into account the fact that the buffer format
1964 may have been modifed by AL (e.g 8bit samples are converted to float)
1966 static ALint
GetByteOffset(ALsource
*Source
)
1968 ALbuffer
*Buffer
= NULL
;
1969 ALbufferlistitem
*BufferList
;
1971 ALint Channels
, Bytes
;
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 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
1993 Channels
= aluChannelsFromFormat(Buffer
->format
);
1994 Bytes
= aluBytesFromFormat(Buffer
->format
);
1996 // Determine the ByteOffset (and ensure it is block aligned)
1997 switch(Source
->lOffsetType
)
1999 case AL_BYTE_OFFSET
:
2000 // Take into consideration the original format
2001 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2003 ByteOffset
*= Channels
* Bytes
;
2006 case AL_SAMPLE_OFFSET
:
2007 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2011 // Note - lOffset is internally stored as Milliseconds
2012 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2013 ByteOffset
*= Channels
* Bytes
;
2017 Source
->lOffset
= 0;
2022 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2024 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2026 // Round down to nearest ADPCM block
2027 offset
/= 36 * channels
;
2028 // Multiply by compression rate (65 sample frames per block)
2031 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2032 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2033 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2035 /* muLaw has 1 byte per sample */
2036 offset
/= 1 * channels
;
2038 else if(format
== AL_FORMAT_REAR_MULAW
)
2040 /* Rear is 2 channels */
2043 else if(format
== AL_FORMAT_REAR8
)
2045 else if(format
== AL_FORMAT_REAR16
)
2047 else if(format
== AL_FORMAT_REAR32
)
2051 ALuint bytes
= aluBytesFromFormat(format
);
2052 offset
/= bytes
* channels
;
2058 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2062 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2064 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2065 Context
->SourceMap
.array
[pos
].value
= NULL
;
2067 // For each buffer in the source's queue, decrement its reference counter and remove it
2068 while(temp
->queue
!= NULL
)
2070 ALbufferlistitem
*BufferList
= temp
->queue
;
2071 // Decrement buffer's reference counter
2072 if(BufferList
->buffer
!= NULL
)
2073 BufferList
->buffer
->refcount
--;
2074 // Update queue to point to next element in list
2075 temp
->queue
= BufferList
->next
;
2076 // Release memory allocated for buffer list item
2080 for(j
= 0;j
< MAX_SENDS
;++j
)
2082 if(temp
->Send
[j
].Slot
)
2083 temp
->Send
[j
].Slot
->refcount
--;
2086 // Release source structure
2087 ALTHUNK_REMOVEENTRY(temp
->source
);
2088 memset(temp
, 0, sizeof(ALsource
));