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
30 static ALvoid
InitSourceParams(ALsource
*pSource
);
31 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
);
32 static ALvoid
ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
);
33 static ALint
GetByteOffset(ALsource
*pSource
);
35 ALAPI ALvoid ALAPIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
41 Context
= alcGetCurrentContext();
44 SuspendContext(Context
);
48 Device
= alcGetContextsDevice(Context
);
52 // Check that enough memory has been allocted in the 'sources' array for n Sources
53 if (!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
55 // Check that the requested number of sources can be generated
56 if ((Context
->SourceCount
+ n
) <= Device
->MaxNoOfSources
)
58 ALsource
**list
= &Context
->Source
;
60 list
= &(*list
)->next
;
62 // Add additional sources to the list (Source->next points to the location for the next Source structure)
65 *list
= calloc(1, sizeof(ALsource
));
68 sources
[i
]=(ALuint
)ALTHUNK_ADDENTRY(*list
);
69 (*list
)->source
= sources
[i
];
71 InitSourceParams(*list
);
72 Context
->SourceCount
++;
75 list
= &(*list
)->next
;
79 // If we didn't create all the Sources, we must have run out or memory
81 alSetError(AL_OUT_OF_MEMORY
);
85 // Not enough resources to create the Sources
86 alSetError(AL_INVALID_VALUE
);
92 alSetError(AL_INVALID_VALUE
);
97 // No Device created, or attached to Context
98 alSetError(AL_INVALID_OPERATION
);
102 ProcessContext(Context
);
107 alSetError(AL_INVALID_OPERATION
);
114 ALAPI ALvoid ALAPIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
121 ALbufferlistitem
*ALBufferList
;
122 ALboolean bSourcesValid
= AL_TRUE
;
124 Context
= alcGetCurrentContext();
127 SuspendContext(Context
);
131 Device
= alcGetContextsDevice(Context
);
135 if ((ALuint
)n
<= Context
->SourceCount
)
137 // Check that all Sources are valid (and can therefore be deleted)
138 for (i
= 0; i
< n
; i
++)
140 if (!alIsSource(sources
[i
]))
142 alSetError(AL_INVALID_NAME
);
143 bSourcesValid
= AL_FALSE
;
150 // All Sources are valid, and can be deleted
151 for (i
= 0; i
< n
; i
++)
153 // Recheck that the Source is valid, because there could be duplicated Source names
154 if (alIsSource(sources
[i
]))
156 ALSource
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
157 alSourceStop((ALuint
)ALSource
->source
);
159 // For each buffer in the source's queue, decrement its reference counter and remove it
160 while (ALSource
->queue
!= NULL
)
162 ALBufferList
= ALSource
->queue
;
163 // Decrement buffer's reference counter
164 if (ALBufferList
->buffer
!= 0)
165 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
166 // Update queue to point to next element in list
167 ALSource
->queue
= ALBufferList
->next
;
168 // Release memory allocated for buffer list item
172 // Decrement Source count
173 Context
->SourceCount
--;
175 // Remove Source from list of Sources
176 list
= &Context
->Source
;
177 while(*list
&& *list
!= ALSource
)
178 list
= &(*list
)->next
;
181 *list
= (*list
)->next
;
182 ALTHUNK_REMOVEENTRY(ALSource
->source
);
184 memset(ALSource
,0,sizeof(ALsource
));
193 // Trying to delete more Sources than have been generated
194 alSetError(AL_INVALID_NAME
);
199 // No Device created, or attached to Context
200 alSetError(AL_INVALID_OPERATION
);
204 alSetError(AL_INVALID_VALUE
);
206 ProcessContext(Context
);
211 alSetError(AL_INVALID_OPERATION
);
218 ALAPI ALboolean ALAPIENTRY
alIsSource(ALuint source
)
220 ALboolean result
=AL_FALSE
;
224 Context
=alcGetCurrentContext();
227 SuspendContext(Context
);
229 // To determine if this is a valid Source name, look through the list of generated Sources
230 Source
= Context
->Source
;
233 if (Source
== (ALsource
*)ALTHUNK_LOOKUPENTRY(source
))
239 Source
= Source
->next
;
242 ProcessContext(Context
);
247 alSetError(AL_INVALID_OPERATION
);
254 ALAPI ALvoid ALAPIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
256 ALCcontext
*pContext
;
259 pContext
= alcGetCurrentContext();
262 SuspendContext(pContext
);
264 if (alIsSource(source
))
266 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
273 pSource
->flPitch
= flValue
;
274 if(pSource
->flPitch
< 0.001f
)
275 pSource
->flPitch
= 0.001f
;
278 alSetError(AL_INVALID_VALUE
);
281 case AL_CONE_INNER_ANGLE
:
282 if ((flValue
>= 0.0f
) && (flValue
<= 360.0f
))
283 pSource
->flInnerAngle
= flValue
;
285 alSetError(AL_INVALID_VALUE
);
288 case AL_CONE_OUTER_ANGLE
:
289 if ((flValue
>= 0.0f
) && (flValue
<= 360.0f
))
290 pSource
->flOuterAngle
= flValue
;
292 alSetError(AL_INVALID_VALUE
);
297 pSource
->flGain
= flValue
;
299 alSetError(AL_INVALID_VALUE
);
302 case AL_MAX_DISTANCE
:
304 pSource
->flMaxDistance
= flValue
;
306 alSetError(AL_INVALID_VALUE
);
309 case AL_ROLLOFF_FACTOR
:
311 pSource
->flRollOffFactor
= flValue
;
313 alSetError(AL_INVALID_VALUE
);
316 case AL_REFERENCE_DISTANCE
:
318 pSource
->flRefDistance
= flValue
;
320 alSetError(AL_INVALID_VALUE
);
324 if ((flValue
>= 0.0f
) && (flValue
<= 1.0f
))
325 pSource
->flMinGain
= flValue
;
327 alSetError(AL_INVALID_VALUE
);
331 if ((flValue
>= 0.0f
) && (flValue
<= 1.0f
))
332 pSource
->flMaxGain
= flValue
;
334 alSetError(AL_INVALID_VALUE
);
337 case AL_CONE_OUTER_GAIN
:
338 if ((flValue
>= 0.0f
) && (flValue
<= 1.0f
))
339 pSource
->flOuterGain
= flValue
;
341 alSetError(AL_INVALID_VALUE
);
344 case AL_CONE_OUTER_GAINHF
:
345 if ((flValue
>= 0.0f
) && (flValue
<= 1.0f
))
346 pSource
->OuterGainHF
= flValue
;
348 alSetError(AL_INVALID_VALUE
);
351 case AL_AIR_ABSORPTION_FACTOR
:
352 if (flValue
>= 0.0f
&& flValue
<= 10.0f
)
353 pSource
->AirAbsorptionFactor
= flValue
;
355 alSetError(AL_INVALID_VALUE
);
358 case AL_ROOM_ROLLOFF_FACTOR
:
359 if (flValue
>= 0.0f
&& flValue
<= 1.0f
)
360 pSource
->RoomRolloffFactor
= flValue
;
362 alSetError(AL_INVALID_VALUE
);
366 case AL_SAMPLE_OFFSET
:
370 pSource
->lOffsetType
= eParam
;
372 // Store Offset (convert Seconds into Milliseconds)
373 if (eParam
== AL_SEC_OFFSET
)
374 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
376 pSource
->lOffset
= (ALint
)flValue
;
378 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
379 ApplyOffset(pSource
, AL_TRUE
);
382 alSetError(AL_INVALID_VALUE
);
386 alSetError(AL_INVALID_ENUM
);
392 // Invalid Source Name
393 alSetError(AL_INVALID_NAME
);
396 ProcessContext(pContext
);
401 alSetError(AL_INVALID_OPERATION
);
408 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
410 ALCcontext
*pContext
;
413 pContext
= alcGetCurrentContext();
416 SuspendContext(pContext
);
418 if (alIsSource(source
))
420 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
424 pSource
->vPosition
[0] = flValue1
;
425 pSource
->vPosition
[1] = flValue2
;
426 pSource
->vPosition
[2] = flValue3
;
430 pSource
->vVelocity
[0] = flValue1
;
431 pSource
->vVelocity
[1] = flValue2
;
432 pSource
->vVelocity
[2] = flValue3
;
436 pSource
->vOrientation
[0] = flValue1
;
437 pSource
->vOrientation
[1] = flValue2
;
438 pSource
->vOrientation
[2] = flValue3
;
442 alSetError(AL_INVALID_ENUM
);
447 alSetError(AL_INVALID_NAME
);
449 ProcessContext(pContext
);
453 alSetError(AL_INVALID_OPERATION
);
460 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
462 ALCcontext
*pContext
;
464 pContext
= alcGetCurrentContext();
467 SuspendContext(pContext
);
471 if (alIsSource(source
))
476 case AL_CONE_INNER_ANGLE
:
477 case AL_CONE_OUTER_ANGLE
:
479 case AL_MAX_DISTANCE
:
480 case AL_ROLLOFF_FACTOR
:
481 case AL_REFERENCE_DISTANCE
:
484 case AL_CONE_OUTER_GAIN
:
485 case AL_CONE_OUTER_GAINHF
:
487 case AL_SAMPLE_OFFSET
:
489 case AL_AIR_ABSORPTION_FACTOR
:
490 case AL_ROOM_ROLLOFF_FACTOR
:
491 alSourcef(source
, eParam
, pflValues
[0]);
497 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
501 alSetError(AL_INVALID_ENUM
);
506 alSetError(AL_INVALID_NAME
);
509 alSetError(AL_INVALID_VALUE
);
511 ProcessContext(pContext
);
514 alSetError(AL_INVALID_OPERATION
);
520 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
522 ALCcontext
*pContext
;
524 ALbufferlistitem
*pALBufferListItem
;
529 pContext
= alcGetCurrentContext();
532 SuspendContext(pContext
);
534 if (alIsSource(source
))
536 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
540 case AL_MAX_DISTANCE
:
541 case AL_ROLLOFF_FACTOR
:
542 case AL_REFERENCE_DISTANCE
:
543 alSourcef(source
, eParam
, (ALfloat
)lValue
);
546 case AL_SOURCE_RELATIVE
:
547 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
548 pSource
->bHeadRelative
= (ALboolean
)lValue
;
550 alSetError(AL_INVALID_VALUE
);
553 case AL_CONE_INNER_ANGLE
:
554 if ((lValue
>= 0) && (lValue
<= 360))
555 pSource
->flInnerAngle
= (float)lValue
;
557 alSetError(AL_INVALID_VALUE
);
560 case AL_CONE_OUTER_ANGLE
:
561 if ((lValue
>= 0) && (lValue
<= 360))
562 pSource
->flOuterAngle
= (float)lValue
;
564 alSetError(AL_INVALID_VALUE
);
568 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
569 pSource
->bLooping
= (ALboolean
)lValue
;
571 alSetError(AL_INVALID_VALUE
);
575 if ((pSource
->state
== AL_STOPPED
) || (pSource
->state
== AL_INITIAL
))
577 if (alIsBuffer(lValue
))
579 // Remove all elements in the queue
580 while (pSource
->queue
!= NULL
)
582 pALBufferListItem
= pSource
->queue
;
583 pSource
->queue
= pALBufferListItem
->next
;
584 // Decrement reference counter for buffer
585 if (pALBufferListItem
->buffer
)
586 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
)))->refcount
--;
587 // Record size of buffer
588 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
))->size
;
589 DataSize
+= BufferSize
;
590 // Increment the number of buffers removed from queue
592 // Release memory for buffer list item
593 free(pALBufferListItem
);
594 // Decrement the number of buffers in the queue
595 pSource
->BuffersInQueue
--;
598 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
601 // Source is now in STATIC mode
602 pSource
->lSourceType
= AL_STATIC
;
604 // Add the selected buffer to the queue
605 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
606 pALBufferListItem
->buffer
= lValue
;
607 pALBufferListItem
->bufferstate
= PENDING
;
608 pALBufferListItem
->flag
= 0;
609 pALBufferListItem
->next
= NULL
;
611 pSource
->queue
= pALBufferListItem
;
612 pSource
->BuffersInQueue
= 1;
614 DataSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
))->size
;
616 // Increment reference counter for buffer
617 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(lValue
)))->refcount
++;
621 // Source is now in UNDETERMINED mode
622 pSource
->lSourceType
= AL_UNDETERMINED
;
625 // Set Buffers Processed
626 pSource
->BuffersProcessed
= 0;
628 // Update AL_BUFFER parameter
629 pSource
->ulBufferID
= lValue
;
632 alSetError(AL_INVALID_VALUE
);
635 alSetError(AL_INVALID_OPERATION
);
638 case AL_SOURCE_STATE
:
640 alSetError(AL_INVALID_OPERATION
);
644 case AL_SAMPLE_OFFSET
:
648 pSource
->lOffsetType
= eParam
;
650 // Store Offset (convert Seconds into Milliseconds)
651 if (eParam
== AL_SEC_OFFSET
)
652 pSource
->lOffset
= lValue
* 1000;
654 pSource
->lOffset
= lValue
;
656 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
657 ApplyOffset(pSource
, AL_TRUE
);
660 alSetError(AL_INVALID_VALUE
);
663 case AL_DIRECT_FILTER
:
664 if(alIsFilter(lValue
))
666 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
669 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
670 pSource
->DirectFilter
.filter
= 0;
673 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
676 alSetError(AL_INVALID_VALUE
);
679 case AL_DIRECT_FILTER_GAINHF_AUTO
:
680 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
681 pSource
->DryGainHFAuto
= lValue
;
683 alSetError(AL_INVALID_VALUE
);
686 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
687 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
688 pSource
->WetGainAuto
= lValue
;
690 alSetError(AL_INVALID_VALUE
);
693 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
694 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
695 pSource
->WetGainHFAuto
= lValue
;
697 alSetError(AL_INVALID_VALUE
);
701 alSetError(AL_INVALID_ENUM
);
706 alSetError(AL_INVALID_NAME
);
708 ProcessContext(pContext
);
711 alSetError(AL_INVALID_OPERATION
);
717 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
719 ALCcontext
*pContext
;
721 pContext
= alcGetCurrentContext();
724 SuspendContext(pContext
);
726 if (alIsSource(source
))
728 ALsource
*pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
735 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
738 case AL_AUXILIARY_SEND_FILTER
:
739 if(lValue2
>= 0 && lValue2
<= 0 &&
740 alIsAuxiliaryEffectSlot(lValue1
) && alIsFilter(lValue3
))
742 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
743 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
748 pSource
->Send
[lValue2
].Slot
.effectslot
= 0;
751 memcpy(&pSource
->Send
[lValue2
].Slot
, ALEffectSlot
, sizeof(*ALEffectSlot
));
756 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
757 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
760 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
763 alSetError(AL_INVALID_VALUE
);
767 alSetError(AL_INVALID_ENUM
);
772 alSetError(AL_INVALID_NAME
);
774 ProcessContext(pContext
);
777 alSetError(AL_INVALID_OPERATION
);
783 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
785 ALCcontext
*pContext
;
787 pContext
= alcGetCurrentContext();
790 SuspendContext(pContext
);
794 if (alIsSource(source
))
798 case AL_SOURCE_RELATIVE
:
799 case AL_CONE_INNER_ANGLE
:
800 case AL_CONE_OUTER_ANGLE
:
803 case AL_SOURCE_STATE
:
805 case AL_SAMPLE_OFFSET
:
807 case AL_MAX_DISTANCE
:
808 case AL_ROLLOFF_FACTOR
:
809 case AL_REFERENCE_DISTANCE
:
810 case AL_DIRECT_FILTER
:
811 case AL_DIRECT_FILTER_GAINHF_AUTO
:
812 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
813 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
814 alSourcei(source
, eParam
, plValues
[0]);
820 case AL_AUXILIARY_SEND_FILTER
:
821 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
825 alSetError(AL_INVALID_ENUM
);
830 alSetError(AL_INVALID_NAME
);
833 alSetError(AL_INVALID_VALUE
);
835 ProcessContext(pContext
);
838 alSetError(AL_INVALID_OPERATION
);
844 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
846 ALCcontext
*pContext
;
850 pContext
= alcGetCurrentContext();
853 SuspendContext(pContext
);
857 if (alIsSource(source
))
859 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
864 *pflValue
= pSource
->flPitch
;
868 *pflValue
= pSource
->flGain
;
872 *pflValue
= pSource
->flMinGain
;
876 *pflValue
= pSource
->flMaxGain
;
879 case AL_MAX_DISTANCE
:
880 *pflValue
= pSource
->flMaxDistance
;
883 case AL_ROLLOFF_FACTOR
:
884 *pflValue
= pSource
->flRollOffFactor
;
887 case AL_CONE_OUTER_GAIN
:
888 *pflValue
= pSource
->flOuterGain
;
891 case AL_CONE_OUTER_GAINHF
:
892 *pflValue
= pSource
->OuterGainHF
;
896 case AL_SAMPLE_OFFSET
:
898 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
899 *pflValue
= flOffset
;
901 alSetError(AL_INVALID_OPERATION
);
904 case AL_CONE_INNER_ANGLE
:
905 *pflValue
= pSource
->flInnerAngle
;
908 case AL_CONE_OUTER_ANGLE
:
909 *pflValue
= pSource
->flOuterAngle
;
912 case AL_REFERENCE_DISTANCE
:
913 *pflValue
= pSource
->flRefDistance
;
916 case AL_AIR_ABSORPTION_FACTOR
:
917 *pflValue
= pSource
->AirAbsorptionFactor
;
920 case AL_ROOM_ROLLOFF_FACTOR
:
921 *pflValue
= pSource
->RoomRolloffFactor
;
925 alSetError(AL_INVALID_ENUM
);
930 alSetError(AL_INVALID_NAME
);
933 alSetError(AL_INVALID_VALUE
);
935 ProcessContext(pContext
);
938 alSetError(AL_INVALID_OPERATION
);
944 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
946 ALCcontext
*pContext
;
949 pContext
= alcGetCurrentContext();
952 SuspendContext(pContext
);
954 if ((pflValue1
) && (pflValue2
) && (pflValue3
))
956 if (alIsSource(source
))
958 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
963 *pflValue1
= pSource
->vPosition
[0];
964 *pflValue2
= pSource
->vPosition
[1];
965 *pflValue3
= pSource
->vPosition
[2];
969 *pflValue1
= pSource
->vVelocity
[0];
970 *pflValue2
= pSource
->vVelocity
[1];
971 *pflValue3
= pSource
->vVelocity
[2];
975 *pflValue1
= pSource
->vOrientation
[0];
976 *pflValue2
= pSource
->vOrientation
[1];
977 *pflValue3
= pSource
->vOrientation
[2];
981 alSetError(AL_INVALID_ENUM
);
986 alSetError(AL_INVALID_NAME
);
989 alSetError(AL_INVALID_VALUE
);
991 ProcessContext(pContext
);
994 alSetError(AL_INVALID_OPERATION
);
1000 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
1002 ALCcontext
*pContext
;
1005 pContext
= alcGetCurrentContext();
1008 SuspendContext(pContext
);
1012 if (alIsSource(source
))
1014 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1022 case AL_MAX_DISTANCE
:
1023 case AL_ROLLOFF_FACTOR
:
1024 case AL_CONE_OUTER_GAIN
:
1026 case AL_SAMPLE_OFFSET
:
1027 case AL_BYTE_OFFSET
:
1028 case AL_CONE_INNER_ANGLE
:
1029 case AL_CONE_OUTER_ANGLE
:
1030 case AL_REFERENCE_DISTANCE
:
1031 case AL_CONE_OUTER_GAINHF
:
1032 case AL_AIR_ABSORPTION_FACTOR
:
1033 case AL_ROOM_ROLLOFF_FACTOR
:
1034 alGetSourcef(source
, eParam
, pflValues
);
1038 pflValues
[0] = pSource
->vPosition
[0];
1039 pflValues
[1] = pSource
->vPosition
[1];
1040 pflValues
[2] = pSource
->vPosition
[2];
1044 pflValues
[0] = pSource
->vVelocity
[0];
1045 pflValues
[1] = pSource
->vVelocity
[1];
1046 pflValues
[2] = pSource
->vVelocity
[2];
1050 pflValues
[0] = pSource
->vOrientation
[0];
1051 pflValues
[1] = pSource
->vOrientation
[1];
1052 pflValues
[2] = pSource
->vOrientation
[2];
1056 alSetError(AL_INVALID_ENUM
);
1061 alSetError(AL_INVALID_NAME
);
1064 alSetError(AL_INVALID_VALUE
);
1066 ProcessContext(pContext
);
1069 alSetError(AL_INVALID_OPERATION
);
1075 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1077 ALCcontext
*pContext
;
1081 pContext
= alcGetCurrentContext();
1084 SuspendContext(pContext
);
1088 if (alIsSource(source
))
1090 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1094 case AL_MAX_DISTANCE
:
1095 *plValue
= (ALint
)pSource
->flMaxDistance
;
1098 case AL_ROLLOFF_FACTOR
:
1099 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1102 case AL_REFERENCE_DISTANCE
:
1103 *plValue
= (ALint
)pSource
->flRefDistance
;
1106 case AL_SOURCE_RELATIVE
:
1107 *plValue
= pSource
->bHeadRelative
;
1110 case AL_CONE_INNER_ANGLE
:
1111 *plValue
= (ALint
)pSource
->flInnerAngle
;
1114 case AL_CONE_OUTER_ANGLE
:
1115 *plValue
= (ALint
)pSource
->flOuterAngle
;
1119 *plValue
= pSource
->bLooping
;
1123 *plValue
= pSource
->ulBufferID
;
1126 case AL_SOURCE_STATE
:
1127 *plValue
= pSource
->state
;
1130 case AL_BUFFERS_QUEUED
:
1131 *plValue
= pSource
->BuffersInQueue
;
1134 case AL_BUFFERS_PROCESSED
:
1135 if(pSource
->bLooping
)
1137 /* Buffers on a looping source are in a perpetual state
1138 * of PENDING, so don't report any as PROCESSED */
1142 *plValue
= pSource
->BuffersProcessed
;
1145 case AL_SOURCE_TYPE
:
1146 *plValue
= pSource
->lSourceType
;
1150 case AL_SAMPLE_OFFSET
:
1151 case AL_BYTE_OFFSET
:
1152 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
1153 *plValue
= (ALint
)flOffset
;
1155 alSetError(AL_INVALID_OPERATION
);
1158 case AL_DIRECT_FILTER
:
1159 *plValue
= pSource
->DirectFilter
.filter
;
1162 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1163 *plValue
= pSource
->DryGainHFAuto
;
1166 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1167 *plValue
= pSource
->WetGainAuto
;
1170 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1171 *plValue
= pSource
->WetGainHFAuto
;
1175 alSetError(AL_INVALID_ENUM
);
1180 alSetError(AL_INVALID_NAME
);
1183 alSetError(AL_INVALID_VALUE
);
1185 ProcessContext(pContext
);
1188 alSetError(AL_INVALID_OPERATION
);
1194 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1196 ALCcontext
*pContext
;
1199 pContext
= alcGetCurrentContext();
1202 SuspendContext(pContext
);
1204 if ((plValue1
) && (plValue2
) && (plValue3
))
1206 if (alIsSource(source
))
1208 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1213 *plValue1
= (ALint
)pSource
->vPosition
[0];
1214 *plValue2
= (ALint
)pSource
->vPosition
[1];
1215 *plValue3
= (ALint
)pSource
->vPosition
[2];
1219 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1220 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1221 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1225 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1226 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1227 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1231 alSetError(AL_INVALID_ENUM
);
1236 alSetError(AL_INVALID_NAME
);
1239 alSetError(AL_INVALID_VALUE
);
1241 ProcessContext(pContext
);
1244 alSetError(AL_INVALID_OPERATION
);
1250 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1252 ALCcontext
*pContext
;
1255 pContext
= alcGetCurrentContext();
1258 SuspendContext(pContext
);
1262 if (alIsSource(source
))
1264 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1268 case AL_SOURCE_RELATIVE
:
1269 case AL_CONE_INNER_ANGLE
:
1270 case AL_CONE_OUTER_ANGLE
:
1273 case AL_SOURCE_STATE
:
1274 case AL_BUFFERS_QUEUED
:
1275 case AL_BUFFERS_PROCESSED
:
1277 case AL_SAMPLE_OFFSET
:
1278 case AL_BYTE_OFFSET
:
1279 case AL_MAX_DISTANCE
:
1280 case AL_ROLLOFF_FACTOR
:
1281 case AL_REFERENCE_DISTANCE
:
1282 case AL_SOURCE_TYPE
:
1283 case AL_DIRECT_FILTER
:
1284 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1285 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1286 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1287 alGetSourcei(source
, eParam
, plValues
);
1291 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1292 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1293 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1297 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1298 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1299 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1303 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1304 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1305 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1309 alSetError(AL_INVALID_ENUM
);
1314 alSetError(AL_INVALID_NAME
);
1317 alSetError(AL_INVALID_VALUE
);
1319 ProcessContext(pContext
);
1322 alSetError(AL_INVALID_OPERATION
);
1328 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1330 alSourcePlayv(1, &source
);
1334 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1336 ALCcontext
*pContext
;
1338 ALbufferlistitem
*ALBufferList
;
1339 ALboolean bSourcesValid
= AL_TRUE
;
1343 pContext
= alcGetCurrentContext();
1346 SuspendContext(pContext
);
1350 // Check that all the Sources are valid
1351 for (i
= 0; i
< n
; i
++)
1353 if (!alIsSource(pSourceList
[i
]))
1355 alSetError(AL_INVALID_NAME
);
1356 bSourcesValid
= AL_FALSE
;
1363 for (i
= 0; i
< n
; i
++)
1365 // Assume Source won't need to play
1368 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]));
1370 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1371 ALBufferList
= pSource
->queue
;
1372 while (ALBufferList
)
1374 if ((ALBufferList
->buffer
!= 0) && (((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
))
1379 ALBufferList
= ALBufferList
->next
;
1384 if (pSource
->state
!= AL_PAUSED
)
1386 pSource
->state
= AL_PLAYING
;
1387 pSource
->inuse
= AL_TRUE
;
1388 pSource
->play
= AL_TRUE
;
1389 pSource
->position
= 0;
1390 pSource
->position_fraction
= 0;
1391 pSource
->BuffersProcessed
= 0;
1392 pSource
->BuffersPlayed
= 0;
1393 pSource
->BufferPosition
= 0;
1394 pSource
->lBytesPlayed
= 0;
1396 pSource
->ulBufferID
= pSource
->queue
->buffer
;
1398 // Make sure all the Buffers in the queue are marked as PENDING
1399 ALBufferList
= pSource
->queue
;
1400 while (ALBufferList
)
1402 ALBufferList
->bufferstate
= PENDING
;
1403 ALBufferList
= ALBufferList
->next
;
1408 pSource
->state
= AL_PLAYING
;
1409 pSource
->inuse
= AL_TRUE
;
1410 pSource
->play
= AL_TRUE
;
1413 // Check if an Offset has been set
1414 if (pSource
->lOffset
)
1415 ApplyOffset(pSource
, AL_FALSE
);
1419 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1420 ALBufferList
= pSource
->queue
;
1421 while (ALBufferList
)
1423 ALBufferList
->bufferstate
= PROCESSED
;
1424 ALBufferList
= ALBufferList
->next
;
1427 pSource
->BuffersPlayed
= pSource
->BuffersProcessed
= pSource
->BuffersInQueue
;
1434 // sources is a NULL pointer
1435 alSetError(AL_INVALID_VALUE
);
1438 ProcessContext(pContext
);
1443 alSetError(AL_INVALID_OPERATION
);
1449 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1451 alSourcePausev(1, &source
);
1455 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1457 ALCcontext
*Context
;
1460 ALboolean bSourcesValid
= AL_TRUE
;
1462 Context
=alcGetCurrentContext();
1465 SuspendContext(Context
);
1469 // Check all the Sources are valid
1472 if (!alIsSource(sources
[i
]))
1474 alSetError(AL_INVALID_NAME
);
1475 bSourcesValid
= AL_FALSE
;
1484 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1485 if (Source
->state
==AL_PLAYING
)
1487 Source
->state
=AL_PAUSED
;
1488 Source
->inuse
=AL_FALSE
;
1495 // sources is a NULL pointer
1496 alSetError(AL_INVALID_VALUE
);
1499 ProcessContext(Context
);
1504 alSetError(AL_INVALID_OPERATION
);
1510 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1512 alSourceStopv(1, &source
);
1516 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1518 ALCcontext
*Context
;
1521 ALbufferlistitem
*ALBufferListItem
;
1522 ALboolean bSourcesValid
= AL_TRUE
;
1524 Context
=alcGetCurrentContext();
1527 SuspendContext(Context
);
1531 // Check all the Sources are valid
1534 if (!alIsSource(sources
[i
]))
1536 alSetError(AL_INVALID_NAME
);
1537 bSourcesValid
= AL_FALSE
;
1546 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1547 if (Source
->state
!=AL_INITIAL
)
1549 Source
->state
=AL_STOPPED
;
1550 Source
->inuse
=AL_FALSE
;
1551 Source
->BuffersPlayed
= Source
->BuffersProcessed
= Source
->BuffersInQueue
;
1552 ALBufferListItem
= Source
->queue
;
1553 while (ALBufferListItem
!= NULL
)
1555 ALBufferListItem
->bufferstate
= PROCESSED
;
1556 ALBufferListItem
= ALBufferListItem
->next
;
1559 Source
->lOffset
= 0;
1565 // sources is a NULL pointer
1566 alSetError(AL_INVALID_VALUE
);
1569 ProcessContext(Context
);
1574 alSetError(AL_INVALID_OPERATION
);
1580 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1582 alSourceRewindv(1, &source
);
1586 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1588 ALCcontext
*Context
;
1591 ALbufferlistitem
*ALBufferListItem
;
1592 ALboolean bSourcesValid
= AL_TRUE
;
1594 Context
=alcGetCurrentContext();
1597 SuspendContext(Context
);
1601 // Check all the Sources are valid
1604 if (!alIsSource(sources
[i
]))
1606 alSetError(AL_INVALID_NAME
);
1607 bSourcesValid
= AL_FALSE
;
1616 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1617 if (Source
->state
!=AL_INITIAL
)
1619 Source
->state
=AL_INITIAL
;
1620 Source
->inuse
=AL_FALSE
;
1622 Source
->position_fraction
=0;
1623 Source
->BuffersProcessed
= 0;
1624 ALBufferListItem
= Source
->queue
;
1625 while (ALBufferListItem
!= NULL
)
1627 ALBufferListItem
->bufferstate
= PENDING
;
1628 ALBufferListItem
= ALBufferListItem
->next
;
1631 Source
->ulBufferID
= Source
->queue
->buffer
;
1633 Source
->lOffset
= 0;
1639 // sources is a NULL pointer
1640 alSetError(AL_INVALID_VALUE
);
1643 ProcessContext(Context
);
1648 alSetError(AL_INVALID_OPERATION
);
1655 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1657 ALCcontext
*Context
;
1660 ALbufferlistitem
*ALBufferList
;
1661 ALbufferlistitem
*ALBufferListStart
;
1666 ALboolean bBuffersValid
= AL_TRUE
;
1671 Context
=alcGetCurrentContext();
1674 SuspendContext(Context
);
1679 // Check that all buffers are valid or zero and that the source is valid
1681 // Check that this is a valid source
1682 if (alIsSource(source
))
1684 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1686 // Check that this is not a STATIC Source
1687 if (ALSource
->lSourceType
!= AL_STATIC
)
1692 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1693 ALBufferList
= ALSource
->queue
;
1694 while (ALBufferList
)
1696 if (ALBufferList
->buffer
)
1698 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->frequency
;
1699 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->format
;
1702 ALBufferList
= ALBufferList
->next
;
1705 for (i
= 0; i
< n
; i
++)
1707 if (alIsBuffer(buffers
[i
]))
1711 if ((iFrequency
== -1) && (iFormat
== -1))
1713 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
;
1714 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
;
1718 if ((iFrequency
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
) ||
1719 (iFormat
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
))
1721 alSetError(AL_INVALID_OPERATION
);
1722 bBuffersValid
= AL_FALSE
;
1730 alSetError(AL_INVALID_NAME
);
1731 bBuffersValid
= AL_FALSE
;
1738 // Change Source Type
1739 ALSource
->lSourceType
= AL_STREAMING
;
1741 // All buffers are valid - so add them to the list
1742 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1743 ALBufferListStart
->buffer
= buffers
[0];
1744 ALBufferListStart
->bufferstate
= PENDING
;
1745 ALBufferListStart
->flag
= 0;
1746 ALBufferListStart
->next
= NULL
;
1749 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]))->size
;
1753 DataSize
+= BufferSize
;
1755 // Increment reference counter for buffer
1757 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[0])))->refcount
++;
1759 ALBufferList
= ALBufferListStart
;
1761 for (i
= 1; i
< n
; i
++)
1763 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1764 ALBufferList
->next
->buffer
= buffers
[i
];
1765 ALBufferList
->next
->bufferstate
= PENDING
;
1766 ALBufferList
->next
->flag
= 0;
1767 ALBufferList
->next
->next
= NULL
;
1770 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]))->size
;
1774 DataSize
+= BufferSize
;
1776 // Increment reference counter for buffer
1778 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->refcount
++;
1780 ALBufferList
= ALBufferList
->next
;
1783 if (ALSource
->queue
== NULL
)
1785 ALSource
->queue
= ALBufferListStart
;
1786 // Update Current Buffer
1787 ALSource
->ulBufferID
= ALBufferListStart
->buffer
;
1791 // Find end of queue
1792 ALBufferList
= ALSource
->queue
;
1793 while (ALBufferList
->next
!= NULL
)
1795 ALBufferList
= ALBufferList
->next
;
1798 ALBufferList
->next
= ALBufferListStart
;
1801 // Update number of buffers in queue
1802 ALSource
->BuffersInQueue
+= n
;
1807 // Invalid Source Type (can't queue on a Static Source)
1808 alSetError(AL_INVALID_OPERATION
);
1813 // Invalid Source Name
1814 alSetError(AL_INVALID_NAME
);
1817 ProcessContext(Context
);
1822 alSetError(AL_INVALID_OPERATION
);
1829 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1830 // an array of buffer IDs that are to be filled with the names of the buffers removed
1831 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1833 ALCcontext
*Context
;
1836 ALbufferlistitem
*ALBufferList
;
1840 ALboolean bBuffersProcessed
;
1847 bBuffersProcessed
= AL_TRUE
;
1849 Context
=alcGetCurrentContext();
1852 SuspendContext(Context
);
1854 if (alIsSource(source
))
1856 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1858 // Check that all 'n' buffers have been processed
1859 ALBufferList
= ALSource
->queue
;
1860 for (i
= 0; i
< n
; i
++)
1862 if ((ALBufferList
!= NULL
) && (ALBufferList
->bufferstate
== PROCESSED
))
1864 ALBufferList
= ALBufferList
->next
;
1868 bBuffersProcessed
= AL_FALSE
;
1873 // If all 'n' buffers have been processed, remove them from the queue
1874 if (bBuffersProcessed
)
1876 for (i
= 0; i
< n
; i
++)
1878 ALBufferList
= ALSource
->queue
;
1880 ALSource
->queue
= ALBufferList
->next
;
1881 // Record name of buffer
1882 buffers
[i
] = ALBufferList
->buffer
;
1883 // Decrement buffer reference counter
1884 if (ALBufferList
->buffer
)
1885 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
1886 // Record size of buffer
1887 if (ALBufferList
->buffer
)
1888 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
;
1892 DataSize
+= BufferSize
;
1893 // Release memory for buffer list item
1895 ALSource
->BuffersInQueue
--;
1896 ALSource
->BuffersProcessed
--;
1899 if (ALSource
->state
!= AL_PLAYING
)
1901 if (ALSource
->queue
)
1902 BufferID
= ALSource
->queue
->buffer
;
1906 ALSource
->ulBufferID
= BufferID
;
1909 if((ALuint
)n
> ALSource
->BuffersPlayed
)
1911 ALSource
->BuffersPlayed
= 0;
1912 ALSource
->BufferPosition
= 0;
1915 ALSource
->BuffersPlayed
-= n
;
1919 // Some buffers can't be unqueue because they have not been processed
1920 alSetError(AL_INVALID_VALUE
);
1925 // Invalid Source Name
1926 alSetError(AL_INVALID_NAME
);
1929 ProcessContext(Context
);
1934 alSetError(AL_INVALID_OPERATION
);
1941 static ALvoid
InitSourceParams(ALsource
*pSource
)
1943 pSource
->flInnerAngle
= 360.0f
;
1944 pSource
->flOuterAngle
= 360.0f
;
1945 pSource
->flPitch
= 1.0f
;
1946 pSource
->vPosition
[0] = 0.0f
;
1947 pSource
->vPosition
[1] = 0.0f
;
1948 pSource
->vPosition
[2] = 0.0f
;
1949 pSource
->vOrientation
[0] = 0.0f
;
1950 pSource
->vOrientation
[1] = 0.0f
;
1951 pSource
->vOrientation
[2] = 0.0f
;
1952 pSource
->vVelocity
[0] = 0.0f
;
1953 pSource
->vVelocity
[1] = 0.0f
;
1954 pSource
->vVelocity
[2] = 0.0f
;
1955 pSource
->flRefDistance
= 1.0f
;
1956 pSource
->flMaxDistance
= FLT_MAX
;
1957 pSource
->flRollOffFactor
= 1.0f
;
1958 pSource
->bLooping
= AL_FALSE
;
1959 pSource
->flGain
= 1.0f
;
1960 pSource
->flMinGain
= 0.0f
;
1961 pSource
->flMaxGain
= 1.0f
;
1962 pSource
->flOuterGain
= 0.0f
;
1964 pSource
->DryGainHFAuto
= AL_TRUE
;
1965 pSource
->WetGainAuto
= AL_TRUE
;
1966 pSource
->WetGainHFAuto
= AL_TRUE
;
1967 pSource
->AirAbsorptionFactor
= 0.0f
;
1969 pSource
->state
= AL_INITIAL
;
1970 pSource
->lSourceType
= AL_UNDETERMINED
;
1972 pSource
->ulBufferID
= 0;
1979 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1980 The offset is relative to the start of the queue (not the start of the current buffer)
1982 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
)
1984 ALbufferlistitem
*pBufferList
;
1985 ALfloat flBufferFreq
;
1986 ALint lBytesPlayed
, lChannels
;
1987 ALenum eOriginalFormat
;
1988 ALboolean bReturn
= AL_TRUE
;
1989 ALint lTotalBufferDataSize
;
1991 if (((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
)) && (pSource
->ulBufferID
))
1993 // Get Current Buffer Size and frequency (in milliseconds)
1994 flBufferFreq
= (ALfloat
)(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->frequency
);
1995 eOriginalFormat
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->eOriginalFormat
;
1996 lChannels
= ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->format
== AL_FORMAT_MONO16
)?1:2);
1998 // Get Current BytesPlayed
1999 lBytesPlayed
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
2000 // Add byte length of any processed buffers in the queue
2001 pBufferList
= pSource
->queue
;
2002 while ((pBufferList
) && (pBufferList
->bufferstate
== PROCESSED
))
2004 lBytesPlayed
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2005 pBufferList
= pBufferList
->next
;
2008 lTotalBufferDataSize
= 0;
2009 pBufferList
= pSource
->queue
;
2012 if (pBufferList
->buffer
)
2013 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2014 pBufferList
= pBufferList
->next
;
2017 if (pSource
->bLooping
)
2019 if (lBytesPlayed
< 0)
2022 lBytesPlayed
= lBytesPlayed
% lTotalBufferDataSize
;
2026 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2027 if(lBytesPlayed
< 0)
2029 if(lBytesPlayed
> lTotalBufferDataSize
)
2030 lBytesPlayed
= lTotalBufferDataSize
;
2036 *pflOffset
= ((ALfloat
)lBytesPlayed
/ (lChannels
* 2.0f
* flBufferFreq
));
2038 case AL_SAMPLE_OFFSET
:
2039 *pflOffset
= (ALfloat
)(lBytesPlayed
/ (lChannels
* 2));
2041 case AL_BYTE_OFFSET
:
2042 // Take into account the original format of the Buffer
2043 if ((eOriginalFormat
== AL_FORMAT_MONO8
) || (eOriginalFormat
== AL_FORMAT_STEREO8
))
2045 *pflOffset
= (ALfloat
)(lBytesPlayed
>> 1);
2047 else if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2049 // Compression rate of the ADPCM supported is 3.6111 to 1
2050 lBytesPlayed
= (ALint
)((ALfloat
)lBytesPlayed
/ 3.6111f
);
2051 // Round down to nearest ADPCM block
2052 *pflOffset
= (ALfloat
)((lBytesPlayed
/ (36 * lChannels
)) * 36 * lChannels
);
2056 *pflOffset
= (ALfloat
)lBytesPlayed
;
2073 Apply a playback offset to the Source. This function will update the queue (to correctly
2074 mark buffers as 'pending' or 'processed' depending upon the new offset.
2076 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
2078 ALbufferlistitem
*pBufferList
;
2079 ALint lBufferSize
, lTotalBufferSize
;
2082 // Get true byte offset
2083 lByteOffset
= GetByteOffset(pSource
);
2085 // If this is a valid offset apply it
2086 if (lByteOffset
!= -1)
2088 // Sort out the queue (pending and processed states)
2089 pBufferList
= pSource
->queue
;
2090 lTotalBufferSize
= 0;
2091 pSource
->BuffersPlayed
= 0;
2092 pSource
->BuffersProcessed
= 0;
2095 lBufferSize
= pBufferList
->buffer
? ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
: 0;
2097 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2099 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2100 // update the state to PROCESSED
2101 pSource
->BuffersPlayed
++;
2103 if (!pSource
->bLooping
)
2105 pBufferList
->bufferstate
= PROCESSED
;
2106 pSource
->BuffersProcessed
++;
2109 else if (lTotalBufferSize
<= lByteOffset
)
2111 // Offset is within this buffer
2112 pBufferList
->bufferstate
= PENDING
;
2114 // Set Current Buffer ID
2115 pSource
->ulBufferID
= pBufferList
->buffer
;
2117 // Set current position in this buffer
2118 pSource
->BufferPosition
= lByteOffset
- lTotalBufferSize
;
2120 // Set Total Bytes Played to Offset
2121 pSource
->lBytesPlayed
= lByteOffset
;
2123 // SW Mixer Positions are in Samples
2124 pSource
->position
= pSource
->BufferPosition
/ ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->format
== AL_FORMAT_MONO16
)?2:4);
2128 // Offset is before this buffer, so mark as pending
2129 pBufferList
->bufferstate
= PENDING
;
2132 // Increment the TotalBufferSize
2133 lTotalBufferSize
+= lBufferSize
;
2135 // Move on to next buffer in the Queue
2136 pBufferList
= pBufferList
->next
;
2142 alSetError(AL_INVALID_VALUE
);
2146 pSource
->lOffset
= 0;
2153 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2154 offset supplied by the application). This takes into account the fact that the buffer format
2155 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2157 static ALint
GetByteOffset(ALsource
*pSource
)
2159 ALbuffer
*pBuffer
= NULL
;
2160 ALbufferlistitem
*pBufferList
;
2161 ALfloat flBufferFreq
;
2163 ALint lByteOffset
= -1;
2164 ALint lTotalBufferDataSize
;
2166 // Find the first non-NULL Buffer in the Queue
2167 pBufferList
= pSource
->queue
;
2170 if (pBufferList
->buffer
)
2172 pBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
2175 pBufferList
= pBufferList
->next
;
2180 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2181 lChannels
= (pBuffer
->format
== AL_FORMAT_MONO16
)?1:2;
2183 // Determine the ByteOffset (and ensure it is block aligned)
2184 switch (pSource
->lOffsetType
)
2186 case AL_BYTE_OFFSET
:
2187 // Take into consideration the original format
2188 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO8
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO8
))
2190 lByteOffset
= pSource
->lOffset
* 2;
2191 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2193 else if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2195 // Round down to nearest ADPCM block
2196 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2197 // Multiply by compression rate
2198 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2199 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2203 lByteOffset
= pSource
->lOffset
;
2204 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2208 case AL_SAMPLE_OFFSET
:
2209 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2213 // Note - lOffset is internally stored as Milliseconds
2214 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2215 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2219 lTotalBufferDataSize
= 0;
2220 pBufferList
= pSource
->queue
;
2223 if (pBufferList
->buffer
)
2224 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2225 pBufferList
= pBufferList
->next
;
2228 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2229 if (lByteOffset
>= lTotalBufferDataSize
)