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
);
359 case AL_SAMPLE_OFFSET
:
363 pSource
->lOffsetType
= eParam
;
365 // Store Offset (convert Seconds into Milliseconds)
366 if (eParam
== AL_SEC_OFFSET
)
367 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
369 pSource
->lOffset
= (ALint
)flValue
;
371 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
372 ApplyOffset(pSource
, AL_TRUE
);
375 alSetError(AL_INVALID_VALUE
);
379 alSetError(AL_INVALID_ENUM
);
385 // Invalid Source Name
386 alSetError(AL_INVALID_NAME
);
389 ProcessContext(pContext
);
394 alSetError(AL_INVALID_OPERATION
);
401 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
403 ALCcontext
*pContext
;
406 pContext
= alcGetCurrentContext();
409 SuspendContext(pContext
);
411 if (alIsSource(source
))
413 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
417 pSource
->vPosition
[0] = flValue1
;
418 pSource
->vPosition
[1] = flValue2
;
419 pSource
->vPosition
[2] = flValue3
;
423 pSource
->vVelocity
[0] = flValue1
;
424 pSource
->vVelocity
[1] = flValue2
;
425 pSource
->vVelocity
[2] = flValue3
;
429 pSource
->vOrientation
[0] = flValue1
;
430 pSource
->vOrientation
[1] = flValue2
;
431 pSource
->vOrientation
[2] = flValue3
;
435 alSetError(AL_INVALID_ENUM
);
440 alSetError(AL_INVALID_NAME
);
442 ProcessContext(pContext
);
446 alSetError(AL_INVALID_OPERATION
);
453 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
455 ALCcontext
*pContext
;
457 pContext
= alcGetCurrentContext();
460 SuspendContext(pContext
);
464 if (alIsSource(source
))
469 case AL_CONE_INNER_ANGLE
:
470 case AL_CONE_OUTER_ANGLE
:
472 case AL_MAX_DISTANCE
:
473 case AL_ROLLOFF_FACTOR
:
474 case AL_REFERENCE_DISTANCE
:
477 case AL_CONE_OUTER_GAIN
:
478 case AL_CONE_OUTER_GAINHF
:
480 case AL_SAMPLE_OFFSET
:
482 case AL_AIR_ABSORPTION_FACTOR
:
483 alSourcef(source
, eParam
, pflValues
[0]);
489 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
493 alSetError(AL_INVALID_ENUM
);
498 alSetError(AL_INVALID_NAME
);
501 alSetError(AL_INVALID_VALUE
);
503 ProcessContext(pContext
);
506 alSetError(AL_INVALID_OPERATION
);
512 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
514 ALCcontext
*pContext
;
516 ALbufferlistitem
*pALBufferListItem
;
521 pContext
= alcGetCurrentContext();
524 SuspendContext(pContext
);
526 if (alIsSource(source
))
528 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
532 case AL_MAX_DISTANCE
:
533 case AL_ROLLOFF_FACTOR
:
534 case AL_REFERENCE_DISTANCE
:
535 alSourcef(source
, eParam
, (ALfloat
)lValue
);
538 case AL_SOURCE_RELATIVE
:
539 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
540 pSource
->bHeadRelative
= (ALboolean
)lValue
;
542 alSetError(AL_INVALID_VALUE
);
545 case AL_CONE_INNER_ANGLE
:
546 if ((lValue
>= 0) && (lValue
<= 360))
547 pSource
->flInnerAngle
= (float)lValue
;
549 alSetError(AL_INVALID_VALUE
);
552 case AL_CONE_OUTER_ANGLE
:
553 if ((lValue
>= 0) && (lValue
<= 360))
554 pSource
->flOuterAngle
= (float)lValue
;
556 alSetError(AL_INVALID_VALUE
);
560 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
561 pSource
->bLooping
= (ALboolean
)lValue
;
563 alSetError(AL_INVALID_VALUE
);
567 if ((pSource
->state
== AL_STOPPED
) || (pSource
->state
== AL_INITIAL
))
569 if (alIsBuffer(lValue
))
571 // Remove all elements in the queue
572 while (pSource
->queue
!= NULL
)
574 pALBufferListItem
= pSource
->queue
;
575 pSource
->queue
= pALBufferListItem
->next
;
576 // Decrement reference counter for buffer
577 if (pALBufferListItem
->buffer
)
578 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
)))->refcount
--;
579 // Record size of buffer
580 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
))->size
;
581 DataSize
+= BufferSize
;
582 // Increment the number of buffers removed from queue
584 // Release memory for buffer list item
585 free(pALBufferListItem
);
586 // Decrement the number of buffers in the queue
587 pSource
->BuffersInQueue
--;
590 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
593 // Source is now in STATIC mode
594 pSource
->lSourceType
= AL_STATIC
;
596 // Add the selected buffer to the queue
597 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
598 pALBufferListItem
->buffer
= lValue
;
599 pALBufferListItem
->bufferstate
= PENDING
;
600 pALBufferListItem
->flag
= 0;
601 pALBufferListItem
->next
= NULL
;
603 pSource
->queue
= pALBufferListItem
;
604 pSource
->BuffersInQueue
= 1;
606 DataSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
))->size
;
608 // Increment reference counter for buffer
609 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(lValue
)))->refcount
++;
613 // Source is now in UNDETERMINED mode
614 pSource
->lSourceType
= AL_UNDETERMINED
;
617 // Set Buffers Processed
618 pSource
->BuffersProcessed
= 0;
620 // Update AL_BUFFER parameter
621 pSource
->ulBufferID
= lValue
;
624 alSetError(AL_INVALID_VALUE
);
627 alSetError(AL_INVALID_OPERATION
);
630 case AL_SOURCE_STATE
:
632 alSetError(AL_INVALID_OPERATION
);
636 case AL_SAMPLE_OFFSET
:
640 pSource
->lOffsetType
= eParam
;
642 // Store Offset (convert Seconds into Milliseconds)
643 if (eParam
== AL_SEC_OFFSET
)
644 pSource
->lOffset
= lValue
* 1000;
646 pSource
->lOffset
= lValue
;
648 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
649 ApplyOffset(pSource
, AL_TRUE
);
652 alSetError(AL_INVALID_VALUE
);
655 case AL_DIRECT_FILTER
:
656 if(alIsFilter(lValue
))
658 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
661 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
662 pSource
->DirectFilter
.filter
= 0;
665 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
668 alSetError(AL_INVALID_VALUE
);
671 case AL_DIRECT_FILTER_GAINHF_AUTO
:
672 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
673 pSource
->DryGainHFAuto
= lValue
;
675 alSetError(AL_INVALID_VALUE
);
678 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
679 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
680 pSource
->WetGainHFAuto
= lValue
;
682 alSetError(AL_INVALID_VALUE
);
686 alSetError(AL_INVALID_ENUM
);
691 alSetError(AL_INVALID_NAME
);
693 ProcessContext(pContext
);
696 alSetError(AL_INVALID_OPERATION
);
702 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
704 ALCcontext
*pContext
;
706 pContext
= alcGetCurrentContext();
709 SuspendContext(pContext
);
711 if (alIsSource(source
))
718 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
722 alSetError(AL_INVALID_ENUM
);
727 alSetError(AL_INVALID_NAME
);
729 ProcessContext(pContext
);
732 alSetError(AL_INVALID_OPERATION
);
738 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
740 ALCcontext
*pContext
;
742 pContext
= alcGetCurrentContext();
745 SuspendContext(pContext
);
749 if (alIsSource(source
))
753 case AL_SOURCE_RELATIVE
:
754 case AL_CONE_INNER_ANGLE
:
755 case AL_CONE_OUTER_ANGLE
:
758 case AL_SOURCE_STATE
:
760 case AL_SAMPLE_OFFSET
:
762 case AL_MAX_DISTANCE
:
763 case AL_ROLLOFF_FACTOR
:
764 case AL_REFERENCE_DISTANCE
:
765 case AL_DIRECT_FILTER
:
766 case AL_DIRECT_FILTER_GAINHF_AUTO
:
767 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
768 alSourcei(source
, eParam
, plValues
[0]);
774 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
778 alSetError(AL_INVALID_ENUM
);
783 alSetError(AL_INVALID_NAME
);
786 alSetError(AL_INVALID_VALUE
);
788 ProcessContext(pContext
);
791 alSetError(AL_INVALID_OPERATION
);
797 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
799 ALCcontext
*pContext
;
803 pContext
= alcGetCurrentContext();
806 SuspendContext(pContext
);
810 if (alIsSource(source
))
812 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
817 *pflValue
= pSource
->flPitch
;
821 *pflValue
= pSource
->flGain
;
825 *pflValue
= pSource
->flMinGain
;
829 *pflValue
= pSource
->flMaxGain
;
832 case AL_MAX_DISTANCE
:
833 *pflValue
= pSource
->flMaxDistance
;
836 case AL_ROLLOFF_FACTOR
:
837 *pflValue
= pSource
->flRollOffFactor
;
840 case AL_CONE_OUTER_GAIN
:
841 *pflValue
= pSource
->flOuterGain
;
844 case AL_CONE_OUTER_GAINHF
:
845 *pflValue
= pSource
->OuterGainHF
;
849 case AL_SAMPLE_OFFSET
:
851 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
852 *pflValue
= flOffset
;
854 alSetError(AL_INVALID_OPERATION
);
857 case AL_CONE_INNER_ANGLE
:
858 *pflValue
= pSource
->flInnerAngle
;
861 case AL_CONE_OUTER_ANGLE
:
862 *pflValue
= pSource
->flOuterAngle
;
865 case AL_REFERENCE_DISTANCE
:
866 *pflValue
= pSource
->flRefDistance
;
869 case AL_AIR_ABSORPTION_FACTOR
:
870 *pflValue
= pSource
->AirAbsorptionFactor
;
874 alSetError(AL_INVALID_ENUM
);
879 alSetError(AL_INVALID_NAME
);
882 alSetError(AL_INVALID_VALUE
);
884 ProcessContext(pContext
);
887 alSetError(AL_INVALID_OPERATION
);
893 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
895 ALCcontext
*pContext
;
898 pContext
= alcGetCurrentContext();
901 SuspendContext(pContext
);
903 if ((pflValue1
) && (pflValue2
) && (pflValue3
))
905 if (alIsSource(source
))
907 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
912 *pflValue1
= pSource
->vPosition
[0];
913 *pflValue2
= pSource
->vPosition
[1];
914 *pflValue3
= pSource
->vPosition
[2];
918 *pflValue1
= pSource
->vVelocity
[0];
919 *pflValue2
= pSource
->vVelocity
[1];
920 *pflValue3
= pSource
->vVelocity
[2];
924 *pflValue1
= pSource
->vOrientation
[0];
925 *pflValue2
= pSource
->vOrientation
[1];
926 *pflValue3
= pSource
->vOrientation
[2];
930 alSetError(AL_INVALID_ENUM
);
935 alSetError(AL_INVALID_NAME
);
938 alSetError(AL_INVALID_VALUE
);
940 ProcessContext(pContext
);
943 alSetError(AL_INVALID_OPERATION
);
949 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
951 ALCcontext
*pContext
;
954 pContext
= alcGetCurrentContext();
957 SuspendContext(pContext
);
961 if (alIsSource(source
))
963 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
971 case AL_MAX_DISTANCE
:
972 case AL_ROLLOFF_FACTOR
:
973 case AL_CONE_OUTER_GAIN
:
975 case AL_SAMPLE_OFFSET
:
977 case AL_CONE_INNER_ANGLE
:
978 case AL_CONE_OUTER_ANGLE
:
979 case AL_REFERENCE_DISTANCE
:
980 case AL_CONE_OUTER_GAINHF
:
981 case AL_AIR_ABSORPTION_FACTOR
:
982 alGetSourcef(source
, eParam
, pflValues
);
986 pflValues
[0] = pSource
->vPosition
[0];
987 pflValues
[1] = pSource
->vPosition
[1];
988 pflValues
[2] = pSource
->vPosition
[2];
992 pflValues
[0] = pSource
->vVelocity
[0];
993 pflValues
[1] = pSource
->vVelocity
[1];
994 pflValues
[2] = pSource
->vVelocity
[2];
998 pflValues
[0] = pSource
->vOrientation
[0];
999 pflValues
[1] = pSource
->vOrientation
[1];
1000 pflValues
[2] = pSource
->vOrientation
[2];
1004 alSetError(AL_INVALID_ENUM
);
1009 alSetError(AL_INVALID_NAME
);
1012 alSetError(AL_INVALID_VALUE
);
1014 ProcessContext(pContext
);
1017 alSetError(AL_INVALID_OPERATION
);
1023 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1025 ALCcontext
*pContext
;
1029 pContext
= alcGetCurrentContext();
1032 SuspendContext(pContext
);
1036 if (alIsSource(source
))
1038 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1042 case AL_MAX_DISTANCE
:
1043 *plValue
= (ALint
)pSource
->flMaxDistance
;
1046 case AL_ROLLOFF_FACTOR
:
1047 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1050 case AL_REFERENCE_DISTANCE
:
1051 *plValue
= (ALint
)pSource
->flRefDistance
;
1054 case AL_SOURCE_RELATIVE
:
1055 *plValue
= pSource
->bHeadRelative
;
1058 case AL_CONE_INNER_ANGLE
:
1059 *plValue
= (ALint
)pSource
->flInnerAngle
;
1062 case AL_CONE_OUTER_ANGLE
:
1063 *plValue
= (ALint
)pSource
->flOuterAngle
;
1067 *plValue
= pSource
->bLooping
;
1071 *plValue
= pSource
->ulBufferID
;
1074 case AL_SOURCE_STATE
:
1075 *plValue
= pSource
->state
;
1078 case AL_BUFFERS_QUEUED
:
1079 *plValue
= pSource
->BuffersInQueue
;
1082 case AL_BUFFERS_PROCESSED
:
1083 if(pSource
->bLooping
)
1085 /* Buffers on a looping source are in a perpetual state
1086 * of PENDING, so don't report any as PROCESSED */
1090 *plValue
= pSource
->BuffersProcessed
;
1093 case AL_SOURCE_TYPE
:
1094 *plValue
= pSource
->lSourceType
;
1098 case AL_SAMPLE_OFFSET
:
1099 case AL_BYTE_OFFSET
:
1100 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
1101 *plValue
= (ALint
)flOffset
;
1103 alSetError(AL_INVALID_OPERATION
);
1106 case AL_DIRECT_FILTER
:
1107 *plValue
= pSource
->DirectFilter
.filter
;
1110 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1111 *plValue
= pSource
->DryGainHFAuto
;
1114 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1115 *plValue
= pSource
->WetGainHFAuto
;
1119 alSetError(AL_INVALID_ENUM
);
1124 alSetError(AL_INVALID_NAME
);
1127 alSetError(AL_INVALID_VALUE
);
1129 ProcessContext(pContext
);
1132 alSetError(AL_INVALID_OPERATION
);
1138 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1140 ALCcontext
*pContext
;
1143 pContext
= alcGetCurrentContext();
1146 SuspendContext(pContext
);
1148 if ((plValue1
) && (plValue2
) && (plValue3
))
1150 if (alIsSource(source
))
1152 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1157 *plValue1
= (ALint
)pSource
->vPosition
[0];
1158 *plValue2
= (ALint
)pSource
->vPosition
[1];
1159 *plValue3
= (ALint
)pSource
->vPosition
[2];
1163 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1164 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1165 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1169 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1170 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1171 *plValue3
= (ALint
)pSource
->vOrientation
[2];
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
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1196 ALCcontext
*pContext
;
1199 pContext
= alcGetCurrentContext();
1202 SuspendContext(pContext
);
1206 if (alIsSource(source
))
1208 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1212 case AL_SOURCE_RELATIVE
:
1213 case AL_CONE_INNER_ANGLE
:
1214 case AL_CONE_OUTER_ANGLE
:
1217 case AL_SOURCE_STATE
:
1218 case AL_BUFFERS_QUEUED
:
1219 case AL_BUFFERS_PROCESSED
:
1221 case AL_SAMPLE_OFFSET
:
1222 case AL_BYTE_OFFSET
:
1223 case AL_MAX_DISTANCE
:
1224 case AL_ROLLOFF_FACTOR
:
1225 case AL_REFERENCE_DISTANCE
:
1226 case AL_SOURCE_TYPE
:
1227 case AL_DIRECT_FILTER
:
1228 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1229 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1230 alGetSourcei(source
, eParam
, plValues
);
1234 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1235 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1236 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1240 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1241 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1242 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1246 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1247 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1248 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1252 alSetError(AL_INVALID_ENUM
);
1257 alSetError(AL_INVALID_NAME
);
1260 alSetError(AL_INVALID_VALUE
);
1262 ProcessContext(pContext
);
1265 alSetError(AL_INVALID_OPERATION
);
1271 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1273 alSourcePlayv(1, &source
);
1277 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1279 ALCcontext
*pContext
;
1281 ALbufferlistitem
*ALBufferList
;
1282 ALboolean bSourcesValid
= AL_TRUE
;
1286 pContext
= alcGetCurrentContext();
1289 SuspendContext(pContext
);
1293 // Check that all the Sources are valid
1294 for (i
= 0; i
< n
; i
++)
1296 if (!alIsSource(pSourceList
[i
]))
1298 alSetError(AL_INVALID_NAME
);
1299 bSourcesValid
= AL_FALSE
;
1306 for (i
= 0; i
< n
; i
++)
1308 // Assume Source won't need to play
1311 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]));
1313 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1314 ALBufferList
= pSource
->queue
;
1315 while (ALBufferList
)
1317 if ((ALBufferList
->buffer
!= 0) && (((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
))
1322 ALBufferList
= ALBufferList
->next
;
1327 if (pSource
->state
!= AL_PAUSED
)
1329 pSource
->state
= AL_PLAYING
;
1330 pSource
->inuse
= AL_TRUE
;
1331 pSource
->play
= AL_TRUE
;
1332 pSource
->position
= 0;
1333 pSource
->position_fraction
= 0;
1334 pSource
->BuffersProcessed
= 0;
1335 pSource
->BuffersPlayed
= 0;
1336 pSource
->BufferPosition
= 0;
1337 pSource
->lBytesPlayed
= 0;
1339 pSource
->ulBufferID
= pSource
->queue
->buffer
;
1341 // Make sure all the Buffers in the queue are marked as PENDING
1342 ALBufferList
= pSource
->queue
;
1343 while (ALBufferList
)
1345 ALBufferList
->bufferstate
= PENDING
;
1346 ALBufferList
= ALBufferList
->next
;
1351 pSource
->state
= AL_PLAYING
;
1352 pSource
->inuse
= AL_TRUE
;
1353 pSource
->play
= AL_TRUE
;
1356 // Check if an Offset has been set
1357 if (pSource
->lOffset
)
1358 ApplyOffset(pSource
, AL_FALSE
);
1362 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1363 ALBufferList
= pSource
->queue
;
1364 while (ALBufferList
)
1366 ALBufferList
->bufferstate
= PROCESSED
;
1367 ALBufferList
= ALBufferList
->next
;
1370 pSource
->BuffersPlayed
= pSource
->BuffersProcessed
= pSource
->BuffersInQueue
;
1377 // sources is a NULL pointer
1378 alSetError(AL_INVALID_VALUE
);
1381 ProcessContext(pContext
);
1386 alSetError(AL_INVALID_OPERATION
);
1392 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1394 alSourcePausev(1, &source
);
1398 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1400 ALCcontext
*Context
;
1403 ALboolean bSourcesValid
= AL_TRUE
;
1405 Context
=alcGetCurrentContext();
1408 SuspendContext(Context
);
1412 // Check all the Sources are valid
1415 if (!alIsSource(sources
[i
]))
1417 alSetError(AL_INVALID_NAME
);
1418 bSourcesValid
= AL_FALSE
;
1427 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1428 if (Source
->state
==AL_PLAYING
)
1430 Source
->state
=AL_PAUSED
;
1431 Source
->inuse
=AL_FALSE
;
1438 // sources is a NULL pointer
1439 alSetError(AL_INVALID_VALUE
);
1442 ProcessContext(Context
);
1447 alSetError(AL_INVALID_OPERATION
);
1453 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1455 alSourceStopv(1, &source
);
1459 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1461 ALCcontext
*Context
;
1464 ALbufferlistitem
*ALBufferListItem
;
1465 ALboolean bSourcesValid
= AL_TRUE
;
1467 Context
=alcGetCurrentContext();
1470 SuspendContext(Context
);
1474 // Check all the Sources are valid
1477 if (!alIsSource(sources
[i
]))
1479 alSetError(AL_INVALID_NAME
);
1480 bSourcesValid
= AL_FALSE
;
1489 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1490 if (Source
->state
!=AL_INITIAL
)
1492 Source
->state
=AL_STOPPED
;
1493 Source
->inuse
=AL_FALSE
;
1494 Source
->BuffersPlayed
= Source
->BuffersProcessed
= Source
->BuffersInQueue
;
1495 ALBufferListItem
= Source
->queue
;
1496 while (ALBufferListItem
!= NULL
)
1498 ALBufferListItem
->bufferstate
= PROCESSED
;
1499 ALBufferListItem
= ALBufferListItem
->next
;
1502 Source
->lOffset
= 0;
1508 // sources is a NULL pointer
1509 alSetError(AL_INVALID_VALUE
);
1512 ProcessContext(Context
);
1517 alSetError(AL_INVALID_OPERATION
);
1523 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1525 alSourceRewindv(1, &source
);
1529 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1531 ALCcontext
*Context
;
1534 ALbufferlistitem
*ALBufferListItem
;
1535 ALboolean bSourcesValid
= AL_TRUE
;
1537 Context
=alcGetCurrentContext();
1540 SuspendContext(Context
);
1544 // Check all the Sources are valid
1547 if (!alIsSource(sources
[i
]))
1549 alSetError(AL_INVALID_NAME
);
1550 bSourcesValid
= AL_FALSE
;
1559 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1560 if (Source
->state
!=AL_INITIAL
)
1562 Source
->state
=AL_INITIAL
;
1563 Source
->inuse
=AL_FALSE
;
1565 Source
->position_fraction
=0;
1566 Source
->BuffersProcessed
= 0;
1567 ALBufferListItem
= Source
->queue
;
1568 while (ALBufferListItem
!= NULL
)
1570 ALBufferListItem
->bufferstate
= PENDING
;
1571 ALBufferListItem
= ALBufferListItem
->next
;
1574 Source
->ulBufferID
= Source
->queue
->buffer
;
1576 Source
->lOffset
= 0;
1582 // sources is a NULL pointer
1583 alSetError(AL_INVALID_VALUE
);
1586 ProcessContext(Context
);
1591 alSetError(AL_INVALID_OPERATION
);
1598 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1600 ALCcontext
*Context
;
1603 ALbufferlistitem
*ALBufferList
;
1604 ALbufferlistitem
*ALBufferListStart
;
1609 ALboolean bBuffersValid
= AL_TRUE
;
1614 Context
=alcGetCurrentContext();
1617 SuspendContext(Context
);
1622 // Check that all buffers are valid or zero and that the source is valid
1624 // Check that this is a valid source
1625 if (alIsSource(source
))
1627 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1629 // Check that this is not a STATIC Source
1630 if (ALSource
->lSourceType
!= AL_STATIC
)
1635 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1636 ALBufferList
= ALSource
->queue
;
1637 while (ALBufferList
)
1639 if (ALBufferList
->buffer
)
1641 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->frequency
;
1642 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->format
;
1645 ALBufferList
= ALBufferList
->next
;
1648 for (i
= 0; i
< n
; i
++)
1650 if (alIsBuffer(buffers
[i
]))
1654 if ((iFrequency
== -1) && (iFormat
== -1))
1656 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
;
1657 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
;
1661 if ((iFrequency
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
) ||
1662 (iFormat
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
))
1664 alSetError(AL_INVALID_OPERATION
);
1665 bBuffersValid
= AL_FALSE
;
1673 alSetError(AL_INVALID_NAME
);
1674 bBuffersValid
= AL_FALSE
;
1681 // Change Source Type
1682 ALSource
->lSourceType
= AL_STREAMING
;
1684 // All buffers are valid - so add them to the list
1685 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1686 ALBufferListStart
->buffer
= buffers
[0];
1687 ALBufferListStart
->bufferstate
= PENDING
;
1688 ALBufferListStart
->flag
= 0;
1689 ALBufferListStart
->next
= NULL
;
1692 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]))->size
;
1696 DataSize
+= BufferSize
;
1698 // Increment reference counter for buffer
1700 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[0])))->refcount
++;
1702 ALBufferList
= ALBufferListStart
;
1704 for (i
= 1; i
< n
; i
++)
1706 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1707 ALBufferList
->next
->buffer
= buffers
[i
];
1708 ALBufferList
->next
->bufferstate
= PENDING
;
1709 ALBufferList
->next
->flag
= 0;
1710 ALBufferList
->next
->next
= NULL
;
1713 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]))->size
;
1717 DataSize
+= BufferSize
;
1719 // Increment reference counter for buffer
1721 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->refcount
++;
1723 ALBufferList
= ALBufferList
->next
;
1726 if (ALSource
->queue
== NULL
)
1728 ALSource
->queue
= ALBufferListStart
;
1729 // Update Current Buffer
1730 ALSource
->ulBufferID
= ALBufferListStart
->buffer
;
1734 // Find end of queue
1735 ALBufferList
= ALSource
->queue
;
1736 while (ALBufferList
->next
!= NULL
)
1738 ALBufferList
= ALBufferList
->next
;
1741 ALBufferList
->next
= ALBufferListStart
;
1744 // Update number of buffers in queue
1745 ALSource
->BuffersInQueue
+= n
;
1750 // Invalid Source Type (can't queue on a Static Source)
1751 alSetError(AL_INVALID_OPERATION
);
1756 // Invalid Source Name
1757 alSetError(AL_INVALID_NAME
);
1760 ProcessContext(Context
);
1765 alSetError(AL_INVALID_OPERATION
);
1772 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1773 // an array of buffer IDs that are to be filled with the names of the buffers removed
1774 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1776 ALCcontext
*Context
;
1779 ALbufferlistitem
*ALBufferList
;
1783 ALboolean bBuffersProcessed
;
1790 bBuffersProcessed
= AL_TRUE
;
1792 Context
=alcGetCurrentContext();
1795 SuspendContext(Context
);
1797 if (alIsSource(source
))
1799 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1801 // Check that all 'n' buffers have been processed
1802 ALBufferList
= ALSource
->queue
;
1803 for (i
= 0; i
< n
; i
++)
1805 if ((ALBufferList
!= NULL
) && (ALBufferList
->bufferstate
== PROCESSED
))
1807 ALBufferList
= ALBufferList
->next
;
1811 bBuffersProcessed
= AL_FALSE
;
1816 // If all 'n' buffers have been processed, remove them from the queue
1817 if (bBuffersProcessed
)
1819 for (i
= 0; i
< n
; i
++)
1821 ALBufferList
= ALSource
->queue
;
1823 ALSource
->queue
= ALBufferList
->next
;
1824 // Record name of buffer
1825 buffers
[i
] = ALBufferList
->buffer
;
1826 // Decrement buffer reference counter
1827 if (ALBufferList
->buffer
)
1828 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
1829 // Record size of buffer
1830 if (ALBufferList
->buffer
)
1831 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
;
1835 DataSize
+= BufferSize
;
1836 // Release memory for buffer list item
1838 ALSource
->BuffersInQueue
--;
1839 ALSource
->BuffersProcessed
--;
1842 if (ALSource
->state
!= AL_PLAYING
)
1844 if (ALSource
->queue
)
1845 BufferID
= ALSource
->queue
->buffer
;
1849 ALSource
->ulBufferID
= BufferID
;
1852 if((ALuint
)n
> ALSource
->BuffersPlayed
)
1854 ALSource
->BuffersPlayed
= 0;
1855 ALSource
->BufferPosition
= 0;
1858 ALSource
->BuffersPlayed
-= n
;
1862 // Some buffers can't be unqueue because they have not been processed
1863 alSetError(AL_INVALID_VALUE
);
1868 // Invalid Source Name
1869 alSetError(AL_INVALID_NAME
);
1872 ProcessContext(Context
);
1877 alSetError(AL_INVALID_OPERATION
);
1884 static ALvoid
InitSourceParams(ALsource
*pSource
)
1886 pSource
->flInnerAngle
= 360.0f
;
1887 pSource
->flOuterAngle
= 360.0f
;
1888 pSource
->flPitch
= 1.0f
;
1889 pSource
->vPosition
[0] = 0.0f
;
1890 pSource
->vPosition
[1] = 0.0f
;
1891 pSource
->vPosition
[2] = 0.0f
;
1892 pSource
->vOrientation
[0] = 0.0f
;
1893 pSource
->vOrientation
[1] = 0.0f
;
1894 pSource
->vOrientation
[2] = 0.0f
;
1895 pSource
->vVelocity
[0] = 0.0f
;
1896 pSource
->vVelocity
[1] = 0.0f
;
1897 pSource
->vVelocity
[2] = 0.0f
;
1898 pSource
->flRefDistance
= 1.0f
;
1899 pSource
->flMaxDistance
= FLT_MAX
;
1900 pSource
->flRollOffFactor
= 1.0f
;
1901 pSource
->bLooping
= AL_FALSE
;
1902 pSource
->flGain
= 1.0f
;
1903 pSource
->flMinGain
= 0.0f
;
1904 pSource
->flMaxGain
= 1.0f
;
1905 pSource
->flOuterGain
= 0.0f
;
1907 pSource
->DryGainHFAuto
= AL_TRUE
;
1908 pSource
->WetGainHFAuto
= AL_TRUE
;
1909 pSource
->AirAbsorptionFactor
= 0.0f
;
1911 pSource
->state
= AL_INITIAL
;
1912 pSource
->lSourceType
= AL_UNDETERMINED
;
1914 pSource
->ulBufferID
= 0;
1921 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1922 The offset is relative to the start of the queue (not the start of the current buffer)
1924 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
)
1926 ALbufferlistitem
*pBufferList
;
1927 ALfloat flBufferFreq
;
1928 ALint lBytesPlayed
, lChannels
;
1929 ALenum eOriginalFormat
;
1930 ALboolean bReturn
= AL_TRUE
;
1931 ALint lTotalBufferDataSize
;
1933 if (((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
)) && (pSource
->ulBufferID
))
1935 // Get Current Buffer Size and frequency (in milliseconds)
1936 flBufferFreq
= (ALfloat
)(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->frequency
);
1937 eOriginalFormat
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->eOriginalFormat
;
1938 lChannels
= ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->format
== AL_FORMAT_MONO16
)?1:2);
1940 // Get Current BytesPlayed
1941 lBytesPlayed
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1942 // Add byte length of any processed buffers in the queue
1943 pBufferList
= pSource
->queue
;
1944 while ((pBufferList
) && (pBufferList
->bufferstate
== PROCESSED
))
1946 lBytesPlayed
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1947 pBufferList
= pBufferList
->next
;
1950 lTotalBufferDataSize
= 0;
1951 pBufferList
= pSource
->queue
;
1954 if (pBufferList
->buffer
)
1955 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1956 pBufferList
= pBufferList
->next
;
1959 if (pSource
->bLooping
)
1961 if (lBytesPlayed
< 0)
1964 lBytesPlayed
= lBytesPlayed
% lTotalBufferDataSize
;
1968 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1969 if(lBytesPlayed
< 0)
1971 if(lBytesPlayed
> lTotalBufferDataSize
)
1972 lBytesPlayed
= lTotalBufferDataSize
;
1978 *pflOffset
= ((ALfloat
)lBytesPlayed
/ (lChannels
* 2.0f
* flBufferFreq
));
1980 case AL_SAMPLE_OFFSET
:
1981 *pflOffset
= (ALfloat
)(lBytesPlayed
/ (lChannels
* 2));
1983 case AL_BYTE_OFFSET
:
1984 // Take into account the original format of the Buffer
1985 if ((eOriginalFormat
== AL_FORMAT_MONO8
) || (eOriginalFormat
== AL_FORMAT_STEREO8
))
1987 *pflOffset
= (ALfloat
)(lBytesPlayed
>> 1);
1989 else if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1991 // Compression rate of the ADPCM supported is 3.6111 to 1
1992 lBytesPlayed
= (ALint
)((ALfloat
)lBytesPlayed
/ 3.6111f
);
1993 // Round down to nearest ADPCM block
1994 *pflOffset
= (ALfloat
)((lBytesPlayed
/ (36 * lChannels
)) * 36 * lChannels
);
1998 *pflOffset
= (ALfloat
)lBytesPlayed
;
2015 Apply a playback offset to the Source. This function will update the queue (to correctly
2016 mark buffers as 'pending' or 'processed' depending upon the new offset.
2018 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
2020 ALbufferlistitem
*pBufferList
;
2021 ALint lBufferSize
, lTotalBufferSize
;
2024 // Get true byte offset
2025 lByteOffset
= GetByteOffset(pSource
);
2027 // If this is a valid offset apply it
2028 if (lByteOffset
!= -1)
2030 // Sort out the queue (pending and processed states)
2031 pBufferList
= pSource
->queue
;
2032 lTotalBufferSize
= 0;
2033 pSource
->BuffersPlayed
= 0;
2034 pSource
->BuffersProcessed
= 0;
2037 lBufferSize
= pBufferList
->buffer
? ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
: 0;
2039 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2041 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2042 // update the state to PROCESSED
2043 pSource
->BuffersPlayed
++;
2045 if (!pSource
->bLooping
)
2047 pBufferList
->bufferstate
= PROCESSED
;
2048 pSource
->BuffersProcessed
++;
2051 else if (lTotalBufferSize
<= lByteOffset
)
2053 // Offset is within this buffer
2054 pBufferList
->bufferstate
= PENDING
;
2056 // Set Current Buffer ID
2057 pSource
->ulBufferID
= pBufferList
->buffer
;
2059 // Set current position in this buffer
2060 pSource
->BufferPosition
= lByteOffset
- lTotalBufferSize
;
2062 // Set Total Bytes Played to Offset
2063 pSource
->lBytesPlayed
= lByteOffset
;
2065 // SW Mixer Positions are in Samples
2066 pSource
->position
= pSource
->BufferPosition
/ ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->format
== AL_FORMAT_MONO16
)?2:4);
2070 // Offset is before this buffer, so mark as pending
2071 pBufferList
->bufferstate
= PENDING
;
2074 // Increment the TotalBufferSize
2075 lTotalBufferSize
+= lBufferSize
;
2077 // Move on to next buffer in the Queue
2078 pBufferList
= pBufferList
->next
;
2084 alSetError(AL_INVALID_VALUE
);
2088 pSource
->lOffset
= 0;
2095 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2096 offset supplied by the application). This takes into account the fact that the buffer format
2097 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2099 static ALint
GetByteOffset(ALsource
*pSource
)
2101 ALbuffer
*pBuffer
= NULL
;
2102 ALbufferlistitem
*pBufferList
;
2103 ALfloat flBufferFreq
;
2105 ALint lByteOffset
= -1;
2106 ALint lTotalBufferDataSize
;
2108 // Find the first non-NULL Buffer in the Queue
2109 pBufferList
= pSource
->queue
;
2112 if (pBufferList
->buffer
)
2114 pBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
2117 pBufferList
= pBufferList
->next
;
2122 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2123 lChannels
= (pBuffer
->format
== AL_FORMAT_MONO16
)?1:2;
2125 // Determine the ByteOffset (and ensure it is block aligned)
2126 switch (pSource
->lOffsetType
)
2128 case AL_BYTE_OFFSET
:
2129 // Take into consideration the original format
2130 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO8
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO8
))
2132 lByteOffset
= pSource
->lOffset
* 2;
2133 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2135 else if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2137 // Round down to nearest ADPCM block
2138 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2139 // Multiply by compression rate
2140 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2141 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2145 lByteOffset
= pSource
->lOffset
;
2146 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2150 case AL_SAMPLE_OFFSET
:
2151 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2155 // Note - lOffset is internally stored as Milliseconds
2156 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2157 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2161 lTotalBufferDataSize
= 0;
2162 pBufferList
= pSource
->queue
;
2165 if (pBufferList
->buffer
)
2166 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2167 pBufferList
= pBufferList
->next
;
2170 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2171 if (lByteOffset
>= lTotalBufferDataSize
)