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
);
352 case AL_SAMPLE_OFFSET
:
356 pSource
->lOffsetType
= eParam
;
358 // Store Offset (convert Seconds into Milliseconds)
359 if (eParam
== AL_SEC_OFFSET
)
360 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
362 pSource
->lOffset
= (ALint
)flValue
;
364 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
365 ApplyOffset(pSource
, AL_TRUE
);
368 alSetError(AL_INVALID_VALUE
);
372 alSetError(AL_INVALID_ENUM
);
378 // Invalid Source Name
379 alSetError(AL_INVALID_NAME
);
382 ProcessContext(pContext
);
387 alSetError(AL_INVALID_OPERATION
);
394 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
396 ALCcontext
*pContext
;
399 pContext
= alcGetCurrentContext();
402 SuspendContext(pContext
);
404 if (alIsSource(source
))
406 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
410 pSource
->vPosition
[0] = flValue1
;
411 pSource
->vPosition
[1] = flValue2
;
412 pSource
->vPosition
[2] = flValue3
;
416 pSource
->vVelocity
[0] = flValue1
;
417 pSource
->vVelocity
[1] = flValue2
;
418 pSource
->vVelocity
[2] = flValue3
;
422 pSource
->vOrientation
[0] = flValue1
;
423 pSource
->vOrientation
[1] = flValue2
;
424 pSource
->vOrientation
[2] = flValue3
;
428 alSetError(AL_INVALID_ENUM
);
433 alSetError(AL_INVALID_NAME
);
435 ProcessContext(pContext
);
439 alSetError(AL_INVALID_OPERATION
);
446 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
448 ALCcontext
*pContext
;
450 pContext
= alcGetCurrentContext();
453 SuspendContext(pContext
);
457 if (alIsSource(source
))
462 case AL_CONE_INNER_ANGLE
:
463 case AL_CONE_OUTER_ANGLE
:
465 case AL_MAX_DISTANCE
:
466 case AL_ROLLOFF_FACTOR
:
467 case AL_REFERENCE_DISTANCE
:
470 case AL_CONE_OUTER_GAIN
:
471 case AL_CONE_OUTER_GAINHF
:
473 case AL_SAMPLE_OFFSET
:
475 alSourcef(source
, eParam
, pflValues
[0]);
481 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
485 alSetError(AL_INVALID_ENUM
);
490 alSetError(AL_INVALID_NAME
);
493 alSetError(AL_INVALID_VALUE
);
495 ProcessContext(pContext
);
498 alSetError(AL_INVALID_OPERATION
);
504 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
506 ALCcontext
*pContext
;
508 ALbufferlistitem
*pALBufferListItem
;
513 pContext
= alcGetCurrentContext();
516 SuspendContext(pContext
);
518 if (alIsSource(source
))
520 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
524 case AL_MAX_DISTANCE
:
525 case AL_ROLLOFF_FACTOR
:
526 case AL_REFERENCE_DISTANCE
:
527 alSourcef(source
, eParam
, (ALfloat
)lValue
);
530 case AL_SOURCE_RELATIVE
:
531 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
532 pSource
->bHeadRelative
= (ALboolean
)lValue
;
534 alSetError(AL_INVALID_VALUE
);
537 case AL_CONE_INNER_ANGLE
:
538 if ((lValue
>= 0) && (lValue
<= 360))
539 pSource
->flInnerAngle
= (float)lValue
;
541 alSetError(AL_INVALID_VALUE
);
544 case AL_CONE_OUTER_ANGLE
:
545 if ((lValue
>= 0) && (lValue
<= 360))
546 pSource
->flOuterAngle
= (float)lValue
;
548 alSetError(AL_INVALID_VALUE
);
552 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
553 pSource
->bLooping
= (ALboolean
)lValue
;
555 alSetError(AL_INVALID_VALUE
);
559 if ((pSource
->state
== AL_STOPPED
) || (pSource
->state
== AL_INITIAL
))
561 if (alIsBuffer(lValue
))
563 // Remove all elements in the queue
564 while (pSource
->queue
!= NULL
)
566 pALBufferListItem
= pSource
->queue
;
567 pSource
->queue
= pALBufferListItem
->next
;
568 // Decrement reference counter for buffer
569 if (pALBufferListItem
->buffer
)
570 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
)))->refcount
--;
571 // Record size of buffer
572 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
))->size
;
573 DataSize
+= BufferSize
;
574 // Increment the number of buffers removed from queue
576 // Release memory for buffer list item
577 free(pALBufferListItem
);
578 // Decrement the number of buffers in the queue
579 pSource
->BuffersInQueue
--;
582 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
585 // Source is now in STATIC mode
586 pSource
->lSourceType
= AL_STATIC
;
588 // Add the selected buffer to the queue
589 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
590 pALBufferListItem
->buffer
= lValue
;
591 pALBufferListItem
->bufferstate
= PENDING
;
592 pALBufferListItem
->flag
= 0;
593 pALBufferListItem
->next
= NULL
;
595 pSource
->queue
= pALBufferListItem
;
596 pSource
->BuffersInQueue
= 1;
598 DataSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
))->size
;
600 // Increment reference counter for buffer
601 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(lValue
)))->refcount
++;
605 // Source is now in UNDETERMINED mode
606 pSource
->lSourceType
= AL_UNDETERMINED
;
609 // Set Buffers Processed
610 pSource
->BuffersProcessed
= 0;
612 // Update AL_BUFFER parameter
613 pSource
->ulBufferID
= lValue
;
616 alSetError(AL_INVALID_VALUE
);
619 alSetError(AL_INVALID_OPERATION
);
622 case AL_SOURCE_STATE
:
624 alSetError(AL_INVALID_OPERATION
);
628 case AL_SAMPLE_OFFSET
:
632 pSource
->lOffsetType
= eParam
;
634 // Store Offset (convert Seconds into Milliseconds)
635 if (eParam
== AL_SEC_OFFSET
)
636 pSource
->lOffset
= lValue
* 1000;
638 pSource
->lOffset
= lValue
;
640 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
641 ApplyOffset(pSource
, AL_TRUE
);
644 alSetError(AL_INVALID_VALUE
);
647 case AL_DIRECT_FILTER
:
648 if(alIsFilter(lValue
))
650 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
653 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
654 pSource
->DirectFilter
.filter
= 0;
657 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
660 alSetError(AL_INVALID_VALUE
);
663 case AL_DIRECT_FILTER_GAINHF_AUTO
:
664 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
665 pSource
->DryGainHFAuto
= lValue
;
667 alSetError(AL_INVALID_VALUE
);
671 alSetError(AL_INVALID_ENUM
);
676 alSetError(AL_INVALID_NAME
);
678 ProcessContext(pContext
);
681 alSetError(AL_INVALID_OPERATION
);
687 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
689 ALCcontext
*pContext
;
691 pContext
= alcGetCurrentContext();
694 SuspendContext(pContext
);
696 if (alIsSource(source
))
703 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
707 alSetError(AL_INVALID_ENUM
);
712 alSetError(AL_INVALID_NAME
);
714 ProcessContext(pContext
);
717 alSetError(AL_INVALID_OPERATION
);
723 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
725 ALCcontext
*pContext
;
727 pContext
= alcGetCurrentContext();
730 SuspendContext(pContext
);
734 if (alIsSource(source
))
738 case AL_SOURCE_RELATIVE
:
739 case AL_CONE_INNER_ANGLE
:
740 case AL_CONE_OUTER_ANGLE
:
743 case AL_SOURCE_STATE
:
745 case AL_SAMPLE_OFFSET
:
747 case AL_MAX_DISTANCE
:
748 case AL_ROLLOFF_FACTOR
:
749 case AL_REFERENCE_DISTANCE
:
750 case AL_DIRECT_FILTER
:
751 case AL_DIRECT_FILTER_GAINHF_AUTO
:
752 alSourcei(source
, eParam
, plValues
[0]);
758 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
762 alSetError(AL_INVALID_ENUM
);
767 alSetError(AL_INVALID_NAME
);
770 alSetError(AL_INVALID_VALUE
);
772 ProcessContext(pContext
);
775 alSetError(AL_INVALID_OPERATION
);
781 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
783 ALCcontext
*pContext
;
787 pContext
= alcGetCurrentContext();
790 SuspendContext(pContext
);
794 if (alIsSource(source
))
796 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
801 *pflValue
= pSource
->flPitch
;
805 *pflValue
= pSource
->flGain
;
809 *pflValue
= pSource
->flMinGain
;
813 *pflValue
= pSource
->flMaxGain
;
816 case AL_MAX_DISTANCE
:
817 *pflValue
= pSource
->flMaxDistance
;
820 case AL_ROLLOFF_FACTOR
:
821 *pflValue
= pSource
->flRollOffFactor
;
824 case AL_CONE_OUTER_GAIN
:
825 *pflValue
= pSource
->flOuterGain
;
828 case AL_CONE_OUTER_GAINHF
:
829 *pflValue
= pSource
->OuterGainHF
;
833 case AL_SAMPLE_OFFSET
:
835 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
836 *pflValue
= flOffset
;
838 alSetError(AL_INVALID_OPERATION
);
841 case AL_CONE_INNER_ANGLE
:
842 *pflValue
= pSource
->flInnerAngle
;
845 case AL_CONE_OUTER_ANGLE
:
846 *pflValue
= pSource
->flOuterAngle
;
849 case AL_REFERENCE_DISTANCE
:
850 *pflValue
= pSource
->flRefDistance
;
854 alSetError(AL_INVALID_ENUM
);
859 alSetError(AL_INVALID_NAME
);
862 alSetError(AL_INVALID_VALUE
);
864 ProcessContext(pContext
);
867 alSetError(AL_INVALID_OPERATION
);
873 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
875 ALCcontext
*pContext
;
878 pContext
= alcGetCurrentContext();
881 SuspendContext(pContext
);
883 if ((pflValue1
) && (pflValue2
) && (pflValue3
))
885 if (alIsSource(source
))
887 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
892 *pflValue1
= pSource
->vPosition
[0];
893 *pflValue2
= pSource
->vPosition
[1];
894 *pflValue3
= pSource
->vPosition
[2];
898 *pflValue1
= pSource
->vVelocity
[0];
899 *pflValue2
= pSource
->vVelocity
[1];
900 *pflValue3
= pSource
->vVelocity
[2];
904 *pflValue1
= pSource
->vOrientation
[0];
905 *pflValue2
= pSource
->vOrientation
[1];
906 *pflValue3
= pSource
->vOrientation
[2];
910 alSetError(AL_INVALID_ENUM
);
915 alSetError(AL_INVALID_NAME
);
918 alSetError(AL_INVALID_VALUE
);
920 ProcessContext(pContext
);
923 alSetError(AL_INVALID_OPERATION
);
929 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
931 ALCcontext
*pContext
;
934 pContext
= alcGetCurrentContext();
937 SuspendContext(pContext
);
941 if (alIsSource(source
))
943 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
951 case AL_MAX_DISTANCE
:
952 case AL_ROLLOFF_FACTOR
:
953 case AL_CONE_OUTER_GAIN
:
955 case AL_SAMPLE_OFFSET
:
957 case AL_CONE_INNER_ANGLE
:
958 case AL_CONE_OUTER_ANGLE
:
959 case AL_REFERENCE_DISTANCE
:
960 case AL_CONE_OUTER_GAINHF
:
961 alGetSourcef(source
, eParam
, pflValues
);
965 pflValues
[0] = pSource
->vPosition
[0];
966 pflValues
[1] = pSource
->vPosition
[1];
967 pflValues
[2] = pSource
->vPosition
[2];
971 pflValues
[0] = pSource
->vVelocity
[0];
972 pflValues
[1] = pSource
->vVelocity
[1];
973 pflValues
[2] = pSource
->vVelocity
[2];
977 pflValues
[0] = pSource
->vOrientation
[0];
978 pflValues
[1] = pSource
->vOrientation
[1];
979 pflValues
[2] = pSource
->vOrientation
[2];
983 alSetError(AL_INVALID_ENUM
);
988 alSetError(AL_INVALID_NAME
);
991 alSetError(AL_INVALID_VALUE
);
993 ProcessContext(pContext
);
996 alSetError(AL_INVALID_OPERATION
);
1002 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1004 ALCcontext
*pContext
;
1008 pContext
= alcGetCurrentContext();
1011 SuspendContext(pContext
);
1015 if (alIsSource(source
))
1017 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1021 case AL_MAX_DISTANCE
:
1022 *plValue
= (ALint
)pSource
->flMaxDistance
;
1025 case AL_ROLLOFF_FACTOR
:
1026 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1029 case AL_REFERENCE_DISTANCE
:
1030 *plValue
= (ALint
)pSource
->flRefDistance
;
1033 case AL_SOURCE_RELATIVE
:
1034 *plValue
= pSource
->bHeadRelative
;
1037 case AL_CONE_INNER_ANGLE
:
1038 *plValue
= (ALint
)pSource
->flInnerAngle
;
1041 case AL_CONE_OUTER_ANGLE
:
1042 *plValue
= (ALint
)pSource
->flOuterAngle
;
1046 *plValue
= pSource
->bLooping
;
1050 *plValue
= pSource
->ulBufferID
;
1053 case AL_SOURCE_STATE
:
1054 *plValue
= pSource
->state
;
1057 case AL_BUFFERS_QUEUED
:
1058 *plValue
= pSource
->BuffersInQueue
;
1061 case AL_BUFFERS_PROCESSED
:
1062 if(pSource
->bLooping
)
1064 /* Buffers on a looping source are in a perpetual state
1065 * of PENDING, so don't report any as PROCESSED */
1069 *plValue
= pSource
->BuffersProcessed
;
1072 case AL_SOURCE_TYPE
:
1073 *plValue
= pSource
->lSourceType
;
1077 case AL_SAMPLE_OFFSET
:
1078 case AL_BYTE_OFFSET
:
1079 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
1080 *plValue
= (ALint
)flOffset
;
1082 alSetError(AL_INVALID_OPERATION
);
1085 case AL_DIRECT_FILTER
:
1086 *plValue
= pSource
->DirectFilter
.filter
;
1089 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1090 *plValue
= pSource
->DryGainHFAuto
;
1094 alSetError(AL_INVALID_ENUM
);
1099 alSetError(AL_INVALID_NAME
);
1102 alSetError(AL_INVALID_VALUE
);
1104 ProcessContext(pContext
);
1107 alSetError(AL_INVALID_OPERATION
);
1113 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1115 ALCcontext
*pContext
;
1118 pContext
= alcGetCurrentContext();
1121 SuspendContext(pContext
);
1123 if ((plValue1
) && (plValue2
) && (plValue3
))
1125 if (alIsSource(source
))
1127 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1132 *plValue1
= (ALint
)pSource
->vPosition
[0];
1133 *plValue2
= (ALint
)pSource
->vPosition
[1];
1134 *plValue3
= (ALint
)pSource
->vPosition
[2];
1138 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1139 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1140 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1144 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1145 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1146 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1150 alSetError(AL_INVALID_ENUM
);
1155 alSetError(AL_INVALID_NAME
);
1158 alSetError(AL_INVALID_VALUE
);
1160 ProcessContext(pContext
);
1163 alSetError(AL_INVALID_OPERATION
);
1169 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1171 ALCcontext
*pContext
;
1174 pContext
= alcGetCurrentContext();
1177 SuspendContext(pContext
);
1181 if (alIsSource(source
))
1183 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1187 case AL_SOURCE_RELATIVE
:
1188 case AL_CONE_INNER_ANGLE
:
1189 case AL_CONE_OUTER_ANGLE
:
1192 case AL_SOURCE_STATE
:
1193 case AL_BUFFERS_QUEUED
:
1194 case AL_BUFFERS_PROCESSED
:
1196 case AL_SAMPLE_OFFSET
:
1197 case AL_BYTE_OFFSET
:
1198 case AL_MAX_DISTANCE
:
1199 case AL_ROLLOFF_FACTOR
:
1200 case AL_REFERENCE_DISTANCE
:
1201 case AL_SOURCE_TYPE
:
1202 case AL_DIRECT_FILTER
:
1203 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1204 alGetSourcei(source
, eParam
, plValues
);
1208 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1209 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1210 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1214 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1215 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1216 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1220 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1221 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1222 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1226 alSetError(AL_INVALID_ENUM
);
1231 alSetError(AL_INVALID_NAME
);
1234 alSetError(AL_INVALID_VALUE
);
1236 ProcessContext(pContext
);
1239 alSetError(AL_INVALID_OPERATION
);
1245 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1247 alSourcePlayv(1, &source
);
1251 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1253 ALCcontext
*pContext
;
1255 ALbufferlistitem
*ALBufferList
;
1256 ALboolean bSourcesValid
= AL_TRUE
;
1260 pContext
= alcGetCurrentContext();
1263 SuspendContext(pContext
);
1267 // Check that all the Sources are valid
1268 for (i
= 0; i
< n
; i
++)
1270 if (!alIsSource(pSourceList
[i
]))
1272 alSetError(AL_INVALID_NAME
);
1273 bSourcesValid
= AL_FALSE
;
1280 for (i
= 0; i
< n
; i
++)
1282 // Assume Source won't need to play
1285 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]));
1287 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1288 ALBufferList
= pSource
->queue
;
1289 while (ALBufferList
)
1291 if ((ALBufferList
->buffer
!= 0) && (((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
))
1296 ALBufferList
= ALBufferList
->next
;
1301 if (pSource
->state
!= AL_PAUSED
)
1303 pSource
->state
= AL_PLAYING
;
1304 pSource
->inuse
= AL_TRUE
;
1305 pSource
->play
= AL_TRUE
;
1306 pSource
->position
= 0;
1307 pSource
->position_fraction
= 0;
1308 pSource
->BuffersProcessed
= 0;
1309 pSource
->BuffersPlayed
= 0;
1310 pSource
->BufferPosition
= 0;
1311 pSource
->lBytesPlayed
= 0;
1313 pSource
->ulBufferID
= pSource
->queue
->buffer
;
1315 // Make sure all the Buffers in the queue are marked as PENDING
1316 ALBufferList
= pSource
->queue
;
1317 while (ALBufferList
)
1319 ALBufferList
->bufferstate
= PENDING
;
1320 ALBufferList
= ALBufferList
->next
;
1325 pSource
->state
= AL_PLAYING
;
1326 pSource
->inuse
= AL_TRUE
;
1327 pSource
->play
= AL_TRUE
;
1330 // Check if an Offset has been set
1331 if (pSource
->lOffset
)
1332 ApplyOffset(pSource
, AL_FALSE
);
1336 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1337 ALBufferList
= pSource
->queue
;
1338 while (ALBufferList
)
1340 ALBufferList
->bufferstate
= PROCESSED
;
1341 ALBufferList
= ALBufferList
->next
;
1344 pSource
->BuffersPlayed
= pSource
->BuffersProcessed
= pSource
->BuffersInQueue
;
1351 // sources is a NULL pointer
1352 alSetError(AL_INVALID_VALUE
);
1355 ProcessContext(pContext
);
1360 alSetError(AL_INVALID_OPERATION
);
1366 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1368 alSourcePausev(1, &source
);
1372 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1374 ALCcontext
*Context
;
1377 ALboolean bSourcesValid
= AL_TRUE
;
1379 Context
=alcGetCurrentContext();
1382 SuspendContext(Context
);
1386 // Check all the Sources are valid
1389 if (!alIsSource(sources
[i
]))
1391 alSetError(AL_INVALID_NAME
);
1392 bSourcesValid
= AL_FALSE
;
1401 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1402 if (Source
->state
==AL_PLAYING
)
1404 Source
->state
=AL_PAUSED
;
1405 Source
->inuse
=AL_FALSE
;
1412 // sources is a NULL pointer
1413 alSetError(AL_INVALID_VALUE
);
1416 ProcessContext(Context
);
1421 alSetError(AL_INVALID_OPERATION
);
1427 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1429 alSourceStopv(1, &source
);
1433 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1435 ALCcontext
*Context
;
1438 ALbufferlistitem
*ALBufferListItem
;
1439 ALboolean bSourcesValid
= AL_TRUE
;
1441 Context
=alcGetCurrentContext();
1444 SuspendContext(Context
);
1448 // Check all the Sources are valid
1451 if (!alIsSource(sources
[i
]))
1453 alSetError(AL_INVALID_NAME
);
1454 bSourcesValid
= AL_FALSE
;
1463 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1464 if (Source
->state
!=AL_INITIAL
)
1466 Source
->state
=AL_STOPPED
;
1467 Source
->inuse
=AL_FALSE
;
1468 Source
->BuffersPlayed
= Source
->BuffersProcessed
= Source
->BuffersInQueue
;
1469 ALBufferListItem
= Source
->queue
;
1470 while (ALBufferListItem
!= NULL
)
1472 ALBufferListItem
->bufferstate
= PROCESSED
;
1473 ALBufferListItem
= ALBufferListItem
->next
;
1476 Source
->lOffset
= 0;
1482 // sources is a NULL pointer
1483 alSetError(AL_INVALID_VALUE
);
1486 ProcessContext(Context
);
1491 alSetError(AL_INVALID_OPERATION
);
1497 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1499 alSourceRewindv(1, &source
);
1503 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1505 ALCcontext
*Context
;
1508 ALbufferlistitem
*ALBufferListItem
;
1509 ALboolean bSourcesValid
= AL_TRUE
;
1511 Context
=alcGetCurrentContext();
1514 SuspendContext(Context
);
1518 // Check all the Sources are valid
1521 if (!alIsSource(sources
[i
]))
1523 alSetError(AL_INVALID_NAME
);
1524 bSourcesValid
= AL_FALSE
;
1533 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1534 if (Source
->state
!=AL_INITIAL
)
1536 Source
->state
=AL_INITIAL
;
1537 Source
->inuse
=AL_FALSE
;
1539 Source
->position_fraction
=0;
1540 Source
->BuffersProcessed
= 0;
1541 ALBufferListItem
= Source
->queue
;
1542 while (ALBufferListItem
!= NULL
)
1544 ALBufferListItem
->bufferstate
= PENDING
;
1545 ALBufferListItem
= ALBufferListItem
->next
;
1548 Source
->ulBufferID
= Source
->queue
->buffer
;
1550 Source
->lOffset
= 0;
1556 // sources is a NULL pointer
1557 alSetError(AL_INVALID_VALUE
);
1560 ProcessContext(Context
);
1565 alSetError(AL_INVALID_OPERATION
);
1572 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1574 ALCcontext
*Context
;
1577 ALbufferlistitem
*ALBufferList
;
1578 ALbufferlistitem
*ALBufferListStart
;
1583 ALboolean bBuffersValid
= AL_TRUE
;
1588 Context
=alcGetCurrentContext();
1591 SuspendContext(Context
);
1596 // Check that all buffers are valid or zero and that the source is valid
1598 // Check that this is a valid source
1599 if (alIsSource(source
))
1601 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1603 // Check that this is not a STATIC Source
1604 if (ALSource
->lSourceType
!= AL_STATIC
)
1609 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1610 ALBufferList
= ALSource
->queue
;
1611 while (ALBufferList
)
1613 if (ALBufferList
->buffer
)
1615 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->frequency
;
1616 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->format
;
1619 ALBufferList
= ALBufferList
->next
;
1622 for (i
= 0; i
< n
; i
++)
1624 if (alIsBuffer(buffers
[i
]))
1628 if ((iFrequency
== -1) && (iFormat
== -1))
1630 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
;
1631 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
;
1635 if ((iFrequency
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
) ||
1636 (iFormat
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
))
1638 alSetError(AL_INVALID_OPERATION
);
1639 bBuffersValid
= AL_FALSE
;
1647 alSetError(AL_INVALID_NAME
);
1648 bBuffersValid
= AL_FALSE
;
1655 // Change Source Type
1656 ALSource
->lSourceType
= AL_STREAMING
;
1658 // All buffers are valid - so add them to the list
1659 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1660 ALBufferListStart
->buffer
= buffers
[0];
1661 ALBufferListStart
->bufferstate
= PENDING
;
1662 ALBufferListStart
->flag
= 0;
1663 ALBufferListStart
->next
= NULL
;
1666 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]))->size
;
1670 DataSize
+= BufferSize
;
1672 // Increment reference counter for buffer
1674 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[0])))->refcount
++;
1676 ALBufferList
= ALBufferListStart
;
1678 for (i
= 1; i
< n
; i
++)
1680 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1681 ALBufferList
->next
->buffer
= buffers
[i
];
1682 ALBufferList
->next
->bufferstate
= PENDING
;
1683 ALBufferList
->next
->flag
= 0;
1684 ALBufferList
->next
->next
= NULL
;
1687 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]))->size
;
1691 DataSize
+= BufferSize
;
1693 // Increment reference counter for buffer
1695 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->refcount
++;
1697 ALBufferList
= ALBufferList
->next
;
1700 if (ALSource
->queue
== NULL
)
1702 ALSource
->queue
= ALBufferListStart
;
1703 // Update Current Buffer
1704 ALSource
->ulBufferID
= ALBufferListStart
->buffer
;
1708 // Find end of queue
1709 ALBufferList
= ALSource
->queue
;
1710 while (ALBufferList
->next
!= NULL
)
1712 ALBufferList
= ALBufferList
->next
;
1715 ALBufferList
->next
= ALBufferListStart
;
1718 // Update number of buffers in queue
1719 ALSource
->BuffersInQueue
+= n
;
1724 // Invalid Source Type (can't queue on a Static Source)
1725 alSetError(AL_INVALID_OPERATION
);
1730 // Invalid Source Name
1731 alSetError(AL_INVALID_NAME
);
1734 ProcessContext(Context
);
1739 alSetError(AL_INVALID_OPERATION
);
1746 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1747 // an array of buffer IDs that are to be filled with the names of the buffers removed
1748 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1750 ALCcontext
*Context
;
1753 ALbufferlistitem
*ALBufferList
;
1757 ALboolean bBuffersProcessed
;
1764 bBuffersProcessed
= AL_TRUE
;
1766 Context
=alcGetCurrentContext();
1769 SuspendContext(Context
);
1771 if (alIsSource(source
))
1773 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1775 // Check that all 'n' buffers have been processed
1776 ALBufferList
= ALSource
->queue
;
1777 for (i
= 0; i
< n
; i
++)
1779 if ((ALBufferList
!= NULL
) && (ALBufferList
->bufferstate
== PROCESSED
))
1781 ALBufferList
= ALBufferList
->next
;
1785 bBuffersProcessed
= AL_FALSE
;
1790 // If all 'n' buffers have been processed, remove them from the queue
1791 if (bBuffersProcessed
)
1793 for (i
= 0; i
< n
; i
++)
1795 ALBufferList
= ALSource
->queue
;
1797 ALSource
->queue
= ALBufferList
->next
;
1798 // Record name of buffer
1799 buffers
[i
] = ALBufferList
->buffer
;
1800 // Decrement buffer reference counter
1801 if (ALBufferList
->buffer
)
1802 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
1803 // Record size of buffer
1804 if (ALBufferList
->buffer
)
1805 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
;
1809 DataSize
+= BufferSize
;
1810 // Release memory for buffer list item
1812 ALSource
->BuffersInQueue
--;
1813 ALSource
->BuffersProcessed
--;
1816 if (ALSource
->state
!= AL_PLAYING
)
1818 if (ALSource
->queue
)
1819 BufferID
= ALSource
->queue
->buffer
;
1823 ALSource
->ulBufferID
= BufferID
;
1826 if((ALuint
)n
> ALSource
->BuffersPlayed
)
1828 ALSource
->BuffersPlayed
= 0;
1829 ALSource
->BufferPosition
= 0;
1832 ALSource
->BuffersPlayed
-= n
;
1836 // Some buffers can't be unqueue because they have not been processed
1837 alSetError(AL_INVALID_VALUE
);
1842 // Invalid Source Name
1843 alSetError(AL_INVALID_NAME
);
1846 ProcessContext(Context
);
1851 alSetError(AL_INVALID_OPERATION
);
1858 static ALvoid
InitSourceParams(ALsource
*pSource
)
1860 pSource
->flInnerAngle
= 360.0f
;
1861 pSource
->flOuterAngle
= 360.0f
;
1862 pSource
->flPitch
= 1.0f
;
1863 pSource
->vPosition
[0] = 0.0f
;
1864 pSource
->vPosition
[1] = 0.0f
;
1865 pSource
->vPosition
[2] = 0.0f
;
1866 pSource
->vOrientation
[0] = 0.0f
;
1867 pSource
->vOrientation
[1] = 0.0f
;
1868 pSource
->vOrientation
[2] = 0.0f
;
1869 pSource
->vVelocity
[0] = 0.0f
;
1870 pSource
->vVelocity
[1] = 0.0f
;
1871 pSource
->vVelocity
[2] = 0.0f
;
1872 pSource
->flRefDistance
= 1.0f
;
1873 pSource
->flMaxDistance
= FLT_MAX
;
1874 pSource
->flRollOffFactor
= 1.0f
;
1875 pSource
->bLooping
= AL_FALSE
;
1876 pSource
->flGain
= 1.0f
;
1877 pSource
->flMinGain
= 0.0f
;
1878 pSource
->flMaxGain
= 1.0f
;
1879 pSource
->flOuterGain
= 0.0f
;
1881 pSource
->DryGainHFAuto
= AL_TRUE
;
1883 pSource
->state
= AL_INITIAL
;
1884 pSource
->lSourceType
= AL_UNDETERMINED
;
1886 pSource
->ulBufferID
= 0;
1893 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1894 The offset is relative to the start of the queue (not the start of the current buffer)
1896 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
)
1898 ALbufferlistitem
*pBufferList
;
1899 ALfloat flBufferFreq
;
1900 ALint lBytesPlayed
, lChannels
;
1901 ALenum eOriginalFormat
;
1902 ALboolean bReturn
= AL_TRUE
;
1903 ALint lTotalBufferDataSize
;
1905 if (((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
)) && (pSource
->ulBufferID
))
1907 // Get Current Buffer Size and frequency (in milliseconds)
1908 flBufferFreq
= (ALfloat
)(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->frequency
);
1909 eOriginalFormat
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->eOriginalFormat
;
1910 lChannels
= ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->format
== AL_FORMAT_MONO16
)?1:2);
1912 // Get Current BytesPlayed
1913 lBytesPlayed
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1914 // Add byte length of any processed buffers in the queue
1915 pBufferList
= pSource
->queue
;
1916 while ((pBufferList
) && (pBufferList
->bufferstate
== PROCESSED
))
1918 lBytesPlayed
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1919 pBufferList
= pBufferList
->next
;
1922 lTotalBufferDataSize
= 0;
1923 pBufferList
= pSource
->queue
;
1926 if (pBufferList
->buffer
)
1927 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1928 pBufferList
= pBufferList
->next
;
1931 if (pSource
->bLooping
)
1933 if (lBytesPlayed
< 0)
1936 lBytesPlayed
= lBytesPlayed
% lTotalBufferDataSize
;
1940 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1941 if(lBytesPlayed
< 0)
1943 if(lBytesPlayed
> lTotalBufferDataSize
)
1944 lBytesPlayed
= lTotalBufferDataSize
;
1950 *pflOffset
= ((ALfloat
)lBytesPlayed
/ (lChannels
* 2.0f
* flBufferFreq
));
1952 case AL_SAMPLE_OFFSET
:
1953 *pflOffset
= (ALfloat
)(lBytesPlayed
/ (lChannels
* 2));
1955 case AL_BYTE_OFFSET
:
1956 // Take into account the original format of the Buffer
1957 if ((eOriginalFormat
== AL_FORMAT_MONO8
) || (eOriginalFormat
== AL_FORMAT_STEREO8
))
1959 *pflOffset
= (ALfloat
)(lBytesPlayed
>> 1);
1961 else if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1963 // Compression rate of the ADPCM supported is 3.6111 to 1
1964 lBytesPlayed
= (ALint
)((ALfloat
)lBytesPlayed
/ 3.6111f
);
1965 // Round down to nearest ADPCM block
1966 *pflOffset
= (ALfloat
)((lBytesPlayed
/ (36 * lChannels
)) * 36 * lChannels
);
1970 *pflOffset
= (ALfloat
)lBytesPlayed
;
1987 Apply a playback offset to the Source. This function will update the queue (to correctly
1988 mark buffers as 'pending' or 'processed' depending upon the new offset.
1990 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1992 ALbufferlistitem
*pBufferList
;
1993 ALint lBufferSize
, lTotalBufferSize
;
1996 // Get true byte offset
1997 lByteOffset
= GetByteOffset(pSource
);
1999 // If this is a valid offset apply it
2000 if (lByteOffset
!= -1)
2002 // Sort out the queue (pending and processed states)
2003 pBufferList
= pSource
->queue
;
2004 lTotalBufferSize
= 0;
2005 pSource
->BuffersPlayed
= 0;
2006 pSource
->BuffersProcessed
= 0;
2009 lBufferSize
= pBufferList
->buffer
? ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
: 0;
2011 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2013 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2014 // update the state to PROCESSED
2015 pSource
->BuffersPlayed
++;
2017 if (!pSource
->bLooping
)
2019 pBufferList
->bufferstate
= PROCESSED
;
2020 pSource
->BuffersProcessed
++;
2023 else if (lTotalBufferSize
<= lByteOffset
)
2025 // Offset is within this buffer
2026 pBufferList
->bufferstate
= PENDING
;
2028 // Set Current Buffer ID
2029 pSource
->ulBufferID
= pBufferList
->buffer
;
2031 // Set current position in this buffer
2032 pSource
->BufferPosition
= lByteOffset
- lTotalBufferSize
;
2034 // Set Total Bytes Played to Offset
2035 pSource
->lBytesPlayed
= lByteOffset
;
2037 // SW Mixer Positions are in Samples
2038 pSource
->position
= pSource
->BufferPosition
/ ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->format
== AL_FORMAT_MONO16
)?2:4);
2042 // Offset is before this buffer, so mark as pending
2043 pBufferList
->bufferstate
= PENDING
;
2046 // Increment the TotalBufferSize
2047 lTotalBufferSize
+= lBufferSize
;
2049 // Move on to next buffer in the Queue
2050 pBufferList
= pBufferList
->next
;
2056 alSetError(AL_INVALID_VALUE
);
2060 pSource
->lOffset
= 0;
2067 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2068 offset supplied by the application). This takes into account the fact that the buffer format
2069 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2071 static ALint
GetByteOffset(ALsource
*pSource
)
2073 ALbuffer
*pBuffer
= NULL
;
2074 ALbufferlistitem
*pBufferList
;
2075 ALfloat flBufferFreq
;
2077 ALint lByteOffset
= -1;
2078 ALint lTotalBufferDataSize
;
2080 // Find the first non-NULL Buffer in the Queue
2081 pBufferList
= pSource
->queue
;
2084 if (pBufferList
->buffer
)
2086 pBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
2089 pBufferList
= pBufferList
->next
;
2094 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2095 lChannels
= (pBuffer
->format
== AL_FORMAT_MONO16
)?1:2;
2097 // Determine the ByteOffset (and ensure it is block aligned)
2098 switch (pSource
->lOffsetType
)
2100 case AL_BYTE_OFFSET
:
2101 // Take into consideration the original format
2102 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO8
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO8
))
2104 lByteOffset
= pSource
->lOffset
* 2;
2105 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2107 else if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2109 // Round down to nearest ADPCM block
2110 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2111 // Multiply by compression rate
2112 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2113 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2117 lByteOffset
= pSource
->lOffset
;
2118 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2122 case AL_SAMPLE_OFFSET
:
2123 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2127 // Note - lOffset is internally stored as Milliseconds
2128 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2129 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2133 lTotalBufferDataSize
= 0;
2134 pBufferList
= pSource
->queue
;
2137 if (pBufferList
->buffer
)
2138 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2139 pBufferList
= pBufferList
->next
;
2142 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2143 if (lByteOffset
>= lTotalBufferDataSize
)