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
);
345 case AL_SAMPLE_OFFSET
:
349 pSource
->lOffsetType
= eParam
;
351 // Store Offset (convert Seconds into Milliseconds)
352 if (eParam
== AL_SEC_OFFSET
)
353 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
355 pSource
->lOffset
= (ALint
)flValue
;
357 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
358 ApplyOffset(pSource
, AL_TRUE
);
361 alSetError(AL_INVALID_VALUE
);
365 alSetError(AL_INVALID_ENUM
);
371 // Invalid Source Name
372 alSetError(AL_INVALID_NAME
);
375 ProcessContext(pContext
);
380 alSetError(AL_INVALID_OPERATION
);
387 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
389 ALCcontext
*pContext
;
392 pContext
= alcGetCurrentContext();
395 SuspendContext(pContext
);
397 if (alIsSource(source
))
399 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
403 pSource
->vPosition
[0] = flValue1
;
404 pSource
->vPosition
[1] = flValue2
;
405 pSource
->vPosition
[2] = flValue3
;
409 pSource
->vVelocity
[0] = flValue1
;
410 pSource
->vVelocity
[1] = flValue2
;
411 pSource
->vVelocity
[2] = flValue3
;
415 pSource
->vOrientation
[0] = flValue1
;
416 pSource
->vOrientation
[1] = flValue2
;
417 pSource
->vOrientation
[2] = flValue3
;
421 alSetError(AL_INVALID_ENUM
);
426 alSetError(AL_INVALID_NAME
);
428 ProcessContext(pContext
);
432 alSetError(AL_INVALID_OPERATION
);
439 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
441 ALCcontext
*pContext
;
443 pContext
= alcGetCurrentContext();
446 SuspendContext(pContext
);
450 if (alIsSource(source
))
455 case AL_CONE_INNER_ANGLE
:
456 case AL_CONE_OUTER_ANGLE
:
458 case AL_MAX_DISTANCE
:
459 case AL_ROLLOFF_FACTOR
:
460 case AL_REFERENCE_DISTANCE
:
463 case AL_CONE_OUTER_GAIN
:
465 case AL_SAMPLE_OFFSET
:
467 alSourcef(source
, eParam
, pflValues
[0]);
473 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
477 alSetError(AL_INVALID_ENUM
);
482 alSetError(AL_INVALID_NAME
);
485 alSetError(AL_INVALID_VALUE
);
487 ProcessContext(pContext
);
490 alSetError(AL_INVALID_OPERATION
);
496 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
498 ALCcontext
*pContext
;
500 ALbufferlistitem
*pALBufferListItem
;
505 pContext
= alcGetCurrentContext();
508 SuspendContext(pContext
);
510 if (alIsSource(source
))
512 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
516 case AL_MAX_DISTANCE
:
517 case AL_ROLLOFF_FACTOR
:
518 case AL_REFERENCE_DISTANCE
:
519 alSourcef(source
, eParam
, (ALfloat
)lValue
);
522 case AL_SOURCE_RELATIVE
:
523 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
524 pSource
->bHeadRelative
= (ALboolean
)lValue
;
526 alSetError(AL_INVALID_VALUE
);
529 case AL_CONE_INNER_ANGLE
:
530 if ((lValue
>= 0) && (lValue
<= 360))
531 pSource
->flInnerAngle
= (float)lValue
;
533 alSetError(AL_INVALID_VALUE
);
536 case AL_CONE_OUTER_ANGLE
:
537 if ((lValue
>= 0) && (lValue
<= 360))
538 pSource
->flOuterAngle
= (float)lValue
;
540 alSetError(AL_INVALID_VALUE
);
544 if ((lValue
== AL_FALSE
) || (lValue
== AL_TRUE
))
545 pSource
->bLooping
= (ALboolean
)lValue
;
547 alSetError(AL_INVALID_VALUE
);
551 if ((pSource
->state
== AL_STOPPED
) || (pSource
->state
== AL_INITIAL
))
553 if (alIsBuffer(lValue
))
555 // Remove all elements in the queue
556 while (pSource
->queue
!= NULL
)
558 pALBufferListItem
= pSource
->queue
;
559 pSource
->queue
= pALBufferListItem
->next
;
560 // Decrement reference counter for buffer
561 if (pALBufferListItem
->buffer
)
562 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
)))->refcount
--;
563 // Record size of buffer
564 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
))->size
;
565 DataSize
+= BufferSize
;
566 // Increment the number of buffers removed from queue
568 // Release memory for buffer list item
569 free(pALBufferListItem
);
570 // Decrement the number of buffers in the queue
571 pSource
->BuffersInQueue
--;
574 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
577 // Source is now in STATIC mode
578 pSource
->lSourceType
= AL_STATIC
;
580 // Add the selected buffer to the queue
581 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
582 pALBufferListItem
->buffer
= lValue
;
583 pALBufferListItem
->bufferstate
= PENDING
;
584 pALBufferListItem
->flag
= 0;
585 pALBufferListItem
->next
= NULL
;
587 pSource
->queue
= pALBufferListItem
;
588 pSource
->BuffersInQueue
= 1;
590 DataSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
))->size
;
592 // Increment reference counter for buffer
593 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(lValue
)))->refcount
++;
597 // Source is now in UNDETERMINED mode
598 pSource
->lSourceType
= AL_UNDETERMINED
;
601 // Set Buffers Processed
602 pSource
->BuffersProcessed
= 0;
604 // Update AL_BUFFER parameter
605 pSource
->ulBufferID
= lValue
;
608 alSetError(AL_INVALID_VALUE
);
611 alSetError(AL_INVALID_OPERATION
);
614 case AL_SOURCE_STATE
:
616 alSetError(AL_INVALID_OPERATION
);
620 case AL_SAMPLE_OFFSET
:
624 pSource
->lOffsetType
= eParam
;
626 // Store Offset (convert Seconds into Milliseconds)
627 if (eParam
== AL_SEC_OFFSET
)
628 pSource
->lOffset
= lValue
* 1000;
630 pSource
->lOffset
= lValue
;
632 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
633 ApplyOffset(pSource
, AL_TRUE
);
636 alSetError(AL_INVALID_VALUE
);
639 case AL_DIRECT_FILTER
:
640 if(alIsFilter(lValue
))
642 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
645 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
646 pSource
->DirectFilter
.filter
= 0;
649 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
652 alSetError(AL_INVALID_VALUE
);
655 case AL_DIRECT_FILTER_GAINHF_AUTO
:
656 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
657 pSource
->DryGainHFAuto
= lValue
;
659 alSetError(AL_INVALID_VALUE
);
663 alSetError(AL_INVALID_ENUM
);
668 alSetError(AL_INVALID_NAME
);
670 ProcessContext(pContext
);
673 alSetError(AL_INVALID_OPERATION
);
679 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
681 ALCcontext
*pContext
;
683 pContext
= alcGetCurrentContext();
686 SuspendContext(pContext
);
688 if (alIsSource(source
))
695 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
699 alSetError(AL_INVALID_ENUM
);
704 alSetError(AL_INVALID_NAME
);
706 ProcessContext(pContext
);
709 alSetError(AL_INVALID_OPERATION
);
715 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
717 ALCcontext
*pContext
;
719 pContext
= alcGetCurrentContext();
722 SuspendContext(pContext
);
726 if (alIsSource(source
))
730 case AL_SOURCE_RELATIVE
:
731 case AL_CONE_INNER_ANGLE
:
732 case AL_CONE_OUTER_ANGLE
:
735 case AL_SOURCE_STATE
:
737 case AL_SAMPLE_OFFSET
:
739 case AL_MAX_DISTANCE
:
740 case AL_ROLLOFF_FACTOR
:
741 case AL_REFERENCE_DISTANCE
:
742 case AL_DIRECT_FILTER
:
743 case AL_DIRECT_FILTER_GAINHF_AUTO
:
744 alSourcei(source
, eParam
, plValues
[0]);
750 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
754 alSetError(AL_INVALID_ENUM
);
759 alSetError(AL_INVALID_NAME
);
762 alSetError(AL_INVALID_VALUE
);
764 ProcessContext(pContext
);
767 alSetError(AL_INVALID_OPERATION
);
773 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
775 ALCcontext
*pContext
;
779 pContext
= alcGetCurrentContext();
782 SuspendContext(pContext
);
786 if (alIsSource(source
))
788 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
793 *pflValue
= pSource
->flPitch
;
797 *pflValue
= pSource
->flGain
;
801 *pflValue
= pSource
->flMinGain
;
805 *pflValue
= pSource
->flMaxGain
;
808 case AL_MAX_DISTANCE
:
809 *pflValue
= pSource
->flMaxDistance
;
812 case AL_ROLLOFF_FACTOR
:
813 *pflValue
= pSource
->flRollOffFactor
;
816 case AL_CONE_OUTER_GAIN
:
817 *pflValue
= pSource
->flOuterGain
;
821 case AL_SAMPLE_OFFSET
:
823 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
824 *pflValue
= flOffset
;
826 alSetError(AL_INVALID_OPERATION
);
829 case AL_CONE_INNER_ANGLE
:
830 *pflValue
= pSource
->flInnerAngle
;
833 case AL_CONE_OUTER_ANGLE
:
834 *pflValue
= pSource
->flOuterAngle
;
837 case AL_REFERENCE_DISTANCE
:
838 *pflValue
= pSource
->flRefDistance
;
842 alSetError(AL_INVALID_ENUM
);
847 alSetError(AL_INVALID_NAME
);
850 alSetError(AL_INVALID_VALUE
);
852 ProcessContext(pContext
);
855 alSetError(AL_INVALID_OPERATION
);
861 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
863 ALCcontext
*pContext
;
866 pContext
= alcGetCurrentContext();
869 SuspendContext(pContext
);
871 if ((pflValue1
) && (pflValue2
) && (pflValue3
))
873 if (alIsSource(source
))
875 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
880 *pflValue1
= pSource
->vPosition
[0];
881 *pflValue2
= pSource
->vPosition
[1];
882 *pflValue3
= pSource
->vPosition
[2];
886 *pflValue1
= pSource
->vVelocity
[0];
887 *pflValue2
= pSource
->vVelocity
[1];
888 *pflValue3
= pSource
->vVelocity
[2];
892 *pflValue1
= pSource
->vOrientation
[0];
893 *pflValue2
= pSource
->vOrientation
[1];
894 *pflValue3
= pSource
->vOrientation
[2];
898 alSetError(AL_INVALID_ENUM
);
903 alSetError(AL_INVALID_NAME
);
906 alSetError(AL_INVALID_VALUE
);
908 ProcessContext(pContext
);
911 alSetError(AL_INVALID_OPERATION
);
917 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
919 ALCcontext
*pContext
;
922 pContext
= alcGetCurrentContext();
925 SuspendContext(pContext
);
929 if (alIsSource(source
))
931 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
939 case AL_MAX_DISTANCE
:
940 case AL_ROLLOFF_FACTOR
:
941 case AL_CONE_OUTER_GAIN
:
943 case AL_SAMPLE_OFFSET
:
945 case AL_CONE_INNER_ANGLE
:
946 case AL_CONE_OUTER_ANGLE
:
947 case AL_REFERENCE_DISTANCE
:
948 alGetSourcef(source
, eParam
, pflValues
);
952 pflValues
[0] = pSource
->vPosition
[0];
953 pflValues
[1] = pSource
->vPosition
[1];
954 pflValues
[2] = pSource
->vPosition
[2];
958 pflValues
[0] = pSource
->vVelocity
[0];
959 pflValues
[1] = pSource
->vVelocity
[1];
960 pflValues
[2] = pSource
->vVelocity
[2];
964 pflValues
[0] = pSource
->vOrientation
[0];
965 pflValues
[1] = pSource
->vOrientation
[1];
966 pflValues
[2] = pSource
->vOrientation
[2];
970 alSetError(AL_INVALID_ENUM
);
975 alSetError(AL_INVALID_NAME
);
978 alSetError(AL_INVALID_VALUE
);
980 ProcessContext(pContext
);
983 alSetError(AL_INVALID_OPERATION
);
989 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
991 ALCcontext
*pContext
;
995 pContext
= alcGetCurrentContext();
998 SuspendContext(pContext
);
1002 if (alIsSource(source
))
1004 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1008 case AL_MAX_DISTANCE
:
1009 *plValue
= (ALint
)pSource
->flMaxDistance
;
1012 case AL_ROLLOFF_FACTOR
:
1013 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1016 case AL_REFERENCE_DISTANCE
:
1017 *plValue
= (ALint
)pSource
->flRefDistance
;
1020 case AL_SOURCE_RELATIVE
:
1021 *plValue
= pSource
->bHeadRelative
;
1024 case AL_CONE_INNER_ANGLE
:
1025 *plValue
= (ALint
)pSource
->flInnerAngle
;
1028 case AL_CONE_OUTER_ANGLE
:
1029 *plValue
= (ALint
)pSource
->flOuterAngle
;
1033 *plValue
= pSource
->bLooping
;
1037 *plValue
= pSource
->ulBufferID
;
1040 case AL_SOURCE_STATE
:
1041 *plValue
= pSource
->state
;
1044 case AL_BUFFERS_QUEUED
:
1045 *plValue
= pSource
->BuffersInQueue
;
1048 case AL_BUFFERS_PROCESSED
:
1049 if(pSource
->bLooping
)
1051 /* Buffers on a looping source are in a perpetual state
1052 * of PENDING, so don't report any as PROCESSED */
1056 *plValue
= pSource
->BuffersProcessed
;
1059 case AL_SOURCE_TYPE
:
1060 *plValue
= pSource
->lSourceType
;
1064 case AL_SAMPLE_OFFSET
:
1065 case AL_BYTE_OFFSET
:
1066 if (GetSourceOffset(pSource
, eParam
, &flOffset
))
1067 *plValue
= (ALint
)flOffset
;
1069 alSetError(AL_INVALID_OPERATION
);
1072 case AL_DIRECT_FILTER
:
1073 *plValue
= pSource
->DirectFilter
.filter
;
1076 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1077 *plValue
= pSource
->DryGainHFAuto
;
1081 alSetError(AL_INVALID_ENUM
);
1086 alSetError(AL_INVALID_NAME
);
1089 alSetError(AL_INVALID_VALUE
);
1091 ProcessContext(pContext
);
1094 alSetError(AL_INVALID_OPERATION
);
1100 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1102 ALCcontext
*pContext
;
1105 pContext
= alcGetCurrentContext();
1108 SuspendContext(pContext
);
1110 if ((plValue1
) && (plValue2
) && (plValue3
))
1112 if (alIsSource(source
))
1114 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1119 *plValue1
= (ALint
)pSource
->vPosition
[0];
1120 *plValue2
= (ALint
)pSource
->vPosition
[1];
1121 *plValue3
= (ALint
)pSource
->vPosition
[2];
1125 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1126 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1127 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1131 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1132 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1133 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1137 alSetError(AL_INVALID_ENUM
);
1142 alSetError(AL_INVALID_NAME
);
1145 alSetError(AL_INVALID_VALUE
);
1147 ProcessContext(pContext
);
1150 alSetError(AL_INVALID_OPERATION
);
1156 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1158 ALCcontext
*pContext
;
1161 pContext
= alcGetCurrentContext();
1164 SuspendContext(pContext
);
1168 if (alIsSource(source
))
1170 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(source
));
1174 case AL_SOURCE_RELATIVE
:
1175 case AL_CONE_INNER_ANGLE
:
1176 case AL_CONE_OUTER_ANGLE
:
1179 case AL_SOURCE_STATE
:
1180 case AL_BUFFERS_QUEUED
:
1181 case AL_BUFFERS_PROCESSED
:
1183 case AL_SAMPLE_OFFSET
:
1184 case AL_BYTE_OFFSET
:
1185 case AL_MAX_DISTANCE
:
1186 case AL_ROLLOFF_FACTOR
:
1187 case AL_REFERENCE_DISTANCE
:
1188 case AL_SOURCE_TYPE
:
1189 case AL_DIRECT_FILTER
:
1190 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1191 alGetSourcei(source
, eParam
, plValues
);
1195 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1196 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1197 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1201 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1202 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1203 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1207 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1208 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1209 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1213 alSetError(AL_INVALID_ENUM
);
1218 alSetError(AL_INVALID_NAME
);
1221 alSetError(AL_INVALID_VALUE
);
1223 ProcessContext(pContext
);
1226 alSetError(AL_INVALID_OPERATION
);
1232 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1234 alSourcePlayv(1, &source
);
1238 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1240 ALCcontext
*pContext
;
1242 ALbufferlistitem
*ALBufferList
;
1243 ALboolean bSourcesValid
= AL_TRUE
;
1247 pContext
= alcGetCurrentContext();
1250 SuspendContext(pContext
);
1254 // Check that all the Sources are valid
1255 for (i
= 0; i
< n
; i
++)
1257 if (!alIsSource(pSourceList
[i
]))
1259 alSetError(AL_INVALID_NAME
);
1260 bSourcesValid
= AL_FALSE
;
1267 for (i
= 0; i
< n
; i
++)
1269 // Assume Source won't need to play
1272 pSource
= ((ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]));
1274 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1275 ALBufferList
= pSource
->queue
;
1276 while (ALBufferList
)
1278 if ((ALBufferList
->buffer
!= 0) && (((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
))
1283 ALBufferList
= ALBufferList
->next
;
1288 if (pSource
->state
!= AL_PAUSED
)
1290 pSource
->state
= AL_PLAYING
;
1291 pSource
->inuse
= AL_TRUE
;
1292 pSource
->play
= AL_TRUE
;
1293 pSource
->position
= 0;
1294 pSource
->position_fraction
= 0;
1295 pSource
->BuffersProcessed
= 0;
1296 pSource
->BuffersPlayed
= 0;
1297 pSource
->BufferPosition
= 0;
1298 pSource
->lBytesPlayed
= 0;
1300 pSource
->ulBufferID
= pSource
->queue
->buffer
;
1302 // Make sure all the Buffers in the queue are marked as PENDING
1303 ALBufferList
= pSource
->queue
;
1304 while (ALBufferList
)
1306 ALBufferList
->bufferstate
= PENDING
;
1307 ALBufferList
= ALBufferList
->next
;
1312 pSource
->state
= AL_PLAYING
;
1313 pSource
->inuse
= AL_TRUE
;
1314 pSource
->play
= AL_TRUE
;
1317 // Check if an Offset has been set
1318 if (pSource
->lOffset
)
1319 ApplyOffset(pSource
, AL_FALSE
);
1323 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1324 ALBufferList
= pSource
->queue
;
1325 while (ALBufferList
)
1327 ALBufferList
->bufferstate
= PROCESSED
;
1328 ALBufferList
= ALBufferList
->next
;
1331 pSource
->BuffersPlayed
= pSource
->BuffersProcessed
= pSource
->BuffersInQueue
;
1338 // sources is a NULL pointer
1339 alSetError(AL_INVALID_VALUE
);
1342 ProcessContext(pContext
);
1347 alSetError(AL_INVALID_OPERATION
);
1353 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1355 alSourcePausev(1, &source
);
1359 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1361 ALCcontext
*Context
;
1364 ALboolean bSourcesValid
= AL_TRUE
;
1366 Context
=alcGetCurrentContext();
1369 SuspendContext(Context
);
1373 // Check all the Sources are valid
1376 if (!alIsSource(sources
[i
]))
1378 alSetError(AL_INVALID_NAME
);
1379 bSourcesValid
= AL_FALSE
;
1388 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1389 if (Source
->state
==AL_PLAYING
)
1391 Source
->state
=AL_PAUSED
;
1392 Source
->inuse
=AL_FALSE
;
1399 // sources is a NULL pointer
1400 alSetError(AL_INVALID_VALUE
);
1403 ProcessContext(Context
);
1408 alSetError(AL_INVALID_OPERATION
);
1414 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1416 alSourceStopv(1, &source
);
1420 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1422 ALCcontext
*Context
;
1425 ALbufferlistitem
*ALBufferListItem
;
1426 ALboolean bSourcesValid
= AL_TRUE
;
1428 Context
=alcGetCurrentContext();
1431 SuspendContext(Context
);
1435 // Check all the Sources are valid
1438 if (!alIsSource(sources
[i
]))
1440 alSetError(AL_INVALID_NAME
);
1441 bSourcesValid
= AL_FALSE
;
1450 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1451 if (Source
->state
!=AL_INITIAL
)
1453 Source
->state
=AL_STOPPED
;
1454 Source
->inuse
=AL_FALSE
;
1455 Source
->BuffersPlayed
= Source
->BuffersProcessed
= Source
->BuffersInQueue
;
1456 ALBufferListItem
= Source
->queue
;
1457 while (ALBufferListItem
!= NULL
)
1459 ALBufferListItem
->bufferstate
= PROCESSED
;
1460 ALBufferListItem
= ALBufferListItem
->next
;
1463 Source
->lOffset
= 0;
1469 // sources is a NULL pointer
1470 alSetError(AL_INVALID_VALUE
);
1473 ProcessContext(Context
);
1478 alSetError(AL_INVALID_OPERATION
);
1484 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1486 alSourceRewindv(1, &source
);
1490 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1492 ALCcontext
*Context
;
1495 ALbufferlistitem
*ALBufferListItem
;
1496 ALboolean bSourcesValid
= AL_TRUE
;
1498 Context
=alcGetCurrentContext();
1501 SuspendContext(Context
);
1505 // Check all the Sources are valid
1508 if (!alIsSource(sources
[i
]))
1510 alSetError(AL_INVALID_NAME
);
1511 bSourcesValid
= AL_FALSE
;
1520 Source
=((ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]));
1521 if (Source
->state
!=AL_INITIAL
)
1523 Source
->state
=AL_INITIAL
;
1524 Source
->inuse
=AL_FALSE
;
1526 Source
->position_fraction
=0;
1527 Source
->BuffersProcessed
= 0;
1528 ALBufferListItem
= Source
->queue
;
1529 while (ALBufferListItem
!= NULL
)
1531 ALBufferListItem
->bufferstate
= PENDING
;
1532 ALBufferListItem
= ALBufferListItem
->next
;
1535 Source
->ulBufferID
= Source
->queue
->buffer
;
1537 Source
->lOffset
= 0;
1543 // sources is a NULL pointer
1544 alSetError(AL_INVALID_VALUE
);
1547 ProcessContext(Context
);
1552 alSetError(AL_INVALID_OPERATION
);
1559 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1561 ALCcontext
*Context
;
1564 ALbufferlistitem
*ALBufferList
;
1565 ALbufferlistitem
*ALBufferListStart
;
1570 ALboolean bBuffersValid
= AL_TRUE
;
1575 Context
=alcGetCurrentContext();
1578 SuspendContext(Context
);
1583 // Check that all buffers are valid or zero and that the source is valid
1585 // Check that this is a valid source
1586 if (alIsSource(source
))
1588 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1590 // Check that this is not a STATIC Source
1591 if (ALSource
->lSourceType
!= AL_STATIC
)
1596 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1597 ALBufferList
= ALSource
->queue
;
1598 while (ALBufferList
)
1600 if (ALBufferList
->buffer
)
1602 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->frequency
;
1603 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->format
;
1606 ALBufferList
= ALBufferList
->next
;
1609 for (i
= 0; i
< n
; i
++)
1611 if (alIsBuffer(buffers
[i
]))
1615 if ((iFrequency
== -1) && (iFormat
== -1))
1617 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
;
1618 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
;
1622 if ((iFrequency
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
) ||
1623 (iFormat
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
))
1625 alSetError(AL_INVALID_OPERATION
);
1626 bBuffersValid
= AL_FALSE
;
1634 alSetError(AL_INVALID_NAME
);
1635 bBuffersValid
= AL_FALSE
;
1642 // Change Source Type
1643 ALSource
->lSourceType
= AL_STREAMING
;
1645 // All buffers are valid - so add them to the list
1646 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1647 ALBufferListStart
->buffer
= buffers
[0];
1648 ALBufferListStart
->bufferstate
= PENDING
;
1649 ALBufferListStart
->flag
= 0;
1650 ALBufferListStart
->next
= NULL
;
1653 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]))->size
;
1657 DataSize
+= BufferSize
;
1659 // Increment reference counter for buffer
1661 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[0])))->refcount
++;
1663 ALBufferList
= ALBufferListStart
;
1665 for (i
= 1; i
< n
; i
++)
1667 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1668 ALBufferList
->next
->buffer
= buffers
[i
];
1669 ALBufferList
->next
->bufferstate
= PENDING
;
1670 ALBufferList
->next
->flag
= 0;
1671 ALBufferList
->next
->next
= NULL
;
1674 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]))->size
;
1678 DataSize
+= BufferSize
;
1680 // Increment reference counter for buffer
1682 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->refcount
++;
1684 ALBufferList
= ALBufferList
->next
;
1687 if (ALSource
->queue
== NULL
)
1689 ALSource
->queue
= ALBufferListStart
;
1690 // Update Current Buffer
1691 ALSource
->ulBufferID
= ALBufferListStart
->buffer
;
1695 // Find end of queue
1696 ALBufferList
= ALSource
->queue
;
1697 while (ALBufferList
->next
!= NULL
)
1699 ALBufferList
= ALBufferList
->next
;
1702 ALBufferList
->next
= ALBufferListStart
;
1705 // Update number of buffers in queue
1706 ALSource
->BuffersInQueue
+= n
;
1711 // Invalid Source Type (can't queue on a Static Source)
1712 alSetError(AL_INVALID_OPERATION
);
1717 // Invalid Source Name
1718 alSetError(AL_INVALID_NAME
);
1721 ProcessContext(Context
);
1726 alSetError(AL_INVALID_OPERATION
);
1733 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1734 // an array of buffer IDs that are to be filled with the names of the buffers removed
1735 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1737 ALCcontext
*Context
;
1740 ALbufferlistitem
*ALBufferList
;
1744 ALboolean bBuffersProcessed
;
1751 bBuffersProcessed
= AL_TRUE
;
1753 Context
=alcGetCurrentContext();
1756 SuspendContext(Context
);
1758 if (alIsSource(source
))
1760 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1762 // Check that all 'n' buffers have been processed
1763 ALBufferList
= ALSource
->queue
;
1764 for (i
= 0; i
< n
; i
++)
1766 if ((ALBufferList
!= NULL
) && (ALBufferList
->bufferstate
== PROCESSED
))
1768 ALBufferList
= ALBufferList
->next
;
1772 bBuffersProcessed
= AL_FALSE
;
1777 // If all 'n' buffers have been processed, remove them from the queue
1778 if (bBuffersProcessed
)
1780 for (i
= 0; i
< n
; i
++)
1782 ALBufferList
= ALSource
->queue
;
1784 ALSource
->queue
= ALBufferList
->next
;
1785 // Record name of buffer
1786 buffers
[i
] = ALBufferList
->buffer
;
1787 // Decrement buffer reference counter
1788 if (ALBufferList
->buffer
)
1789 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
1790 // Record size of buffer
1791 if (ALBufferList
->buffer
)
1792 BufferSize
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
;
1796 DataSize
+= BufferSize
;
1797 // Release memory for buffer list item
1799 ALSource
->BuffersInQueue
--;
1800 ALSource
->BuffersProcessed
--;
1803 if (ALSource
->state
!= AL_PLAYING
)
1805 if (ALSource
->queue
)
1806 BufferID
= ALSource
->queue
->buffer
;
1810 ALSource
->ulBufferID
= BufferID
;
1813 if((ALuint
)n
> ALSource
->BuffersPlayed
)
1815 ALSource
->BuffersPlayed
= 0;
1816 ALSource
->BufferPosition
= 0;
1819 ALSource
->BuffersPlayed
-= n
;
1823 // Some buffers can't be unqueue because they have not been processed
1824 alSetError(AL_INVALID_VALUE
);
1829 // Invalid Source Name
1830 alSetError(AL_INVALID_NAME
);
1833 ProcessContext(Context
);
1838 alSetError(AL_INVALID_OPERATION
);
1845 static ALvoid
InitSourceParams(ALsource
*pSource
)
1847 pSource
->flInnerAngle
= 360.0f
;
1848 pSource
->flOuterAngle
= 360.0f
;
1849 pSource
->flPitch
= 1.0f
;
1850 pSource
->vPosition
[0] = 0.0f
;
1851 pSource
->vPosition
[1] = 0.0f
;
1852 pSource
->vPosition
[2] = 0.0f
;
1853 pSource
->vOrientation
[0] = 0.0f
;
1854 pSource
->vOrientation
[1] = 0.0f
;
1855 pSource
->vOrientation
[2] = 0.0f
;
1856 pSource
->vVelocity
[0] = 0.0f
;
1857 pSource
->vVelocity
[1] = 0.0f
;
1858 pSource
->vVelocity
[2] = 0.0f
;
1859 pSource
->flRefDistance
= 1.0f
;
1860 pSource
->flMaxDistance
= FLT_MAX
;
1861 pSource
->flRollOffFactor
= 1.0f
;
1862 pSource
->bLooping
= AL_FALSE
;
1863 pSource
->flGain
= 1.0f
;
1864 pSource
->flMinGain
= 0.0f
;
1865 pSource
->flMaxGain
= 1.0f
;
1866 pSource
->flOuterGain
= 0.0f
;
1868 pSource
->DryGainHFAuto
= AL_TRUE
;
1870 pSource
->state
= AL_INITIAL
;
1871 pSource
->lSourceType
= AL_UNDETERMINED
;
1873 pSource
->ulBufferID
= 0;
1880 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1881 The offset is relative to the start of the queue (not the start of the current buffer)
1883 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
)
1885 ALbufferlistitem
*pBufferList
;
1886 ALfloat flBufferFreq
;
1887 ALint lBytesPlayed
, lChannels
;
1888 ALenum eOriginalFormat
;
1889 ALboolean bReturn
= AL_TRUE
;
1890 ALint lTotalBufferDataSize
;
1892 if (((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
)) && (pSource
->ulBufferID
))
1894 // Get Current Buffer Size and frequency (in milliseconds)
1895 flBufferFreq
= (ALfloat
)(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->frequency
);
1896 eOriginalFormat
= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->eOriginalFormat
;
1897 lChannels
= ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
))->format
== AL_FORMAT_MONO16
)?1:2);
1899 // Get Current BytesPlayed
1900 lBytesPlayed
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1901 // Add byte length of any processed buffers in the queue
1902 pBufferList
= pSource
->queue
;
1903 while ((pBufferList
) && (pBufferList
->bufferstate
== PROCESSED
))
1905 lBytesPlayed
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1906 pBufferList
= pBufferList
->next
;
1909 lTotalBufferDataSize
= 0;
1910 pBufferList
= pSource
->queue
;
1913 if (pBufferList
->buffer
)
1914 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1915 pBufferList
= pBufferList
->next
;
1918 if (pSource
->bLooping
)
1920 if (lBytesPlayed
< 0)
1923 lBytesPlayed
= lBytesPlayed
% lTotalBufferDataSize
;
1927 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1928 if(lBytesPlayed
< 0)
1930 if(lBytesPlayed
> lTotalBufferDataSize
)
1931 lBytesPlayed
= lTotalBufferDataSize
;
1937 *pflOffset
= ((ALfloat
)lBytesPlayed
/ (lChannels
* 2.0f
* flBufferFreq
));
1939 case AL_SAMPLE_OFFSET
:
1940 *pflOffset
= (ALfloat
)(lBytesPlayed
/ (lChannels
* 2));
1942 case AL_BYTE_OFFSET
:
1943 // Take into account the original format of the Buffer
1944 if ((eOriginalFormat
== AL_FORMAT_MONO8
) || (eOriginalFormat
== AL_FORMAT_STEREO8
))
1946 *pflOffset
= (ALfloat
)(lBytesPlayed
>> 1);
1948 else if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1950 // Compression rate of the ADPCM supported is 3.6111 to 1
1951 lBytesPlayed
= (ALint
)((ALfloat
)lBytesPlayed
/ 3.6111f
);
1952 // Round down to nearest ADPCM block
1953 *pflOffset
= (ALfloat
)((lBytesPlayed
/ (36 * lChannels
)) * 36 * lChannels
);
1957 *pflOffset
= (ALfloat
)lBytesPlayed
;
1974 Apply a playback offset to the Source. This function will update the queue (to correctly
1975 mark buffers as 'pending' or 'processed' depending upon the new offset.
1977 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1979 ALbufferlistitem
*pBufferList
;
1980 ALint lBufferSize
, lTotalBufferSize
;
1983 // Get true byte offset
1984 lByteOffset
= GetByteOffset(pSource
);
1986 // If this is a valid offset apply it
1987 if (lByteOffset
!= -1)
1989 // Sort out the queue (pending and processed states)
1990 pBufferList
= pSource
->queue
;
1991 lTotalBufferSize
= 0;
1992 pSource
->BuffersPlayed
= 0;
1993 pSource
->BuffersProcessed
= 0;
1996 lBufferSize
= pBufferList
->buffer
? ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
: 0;
1998 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2000 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2001 // update the state to PROCESSED
2002 pSource
->BuffersPlayed
++;
2004 if (!pSource
->bLooping
)
2006 pBufferList
->bufferstate
= PROCESSED
;
2007 pSource
->BuffersProcessed
++;
2010 else if (lTotalBufferSize
<= lByteOffset
)
2012 // Offset is within this buffer
2013 pBufferList
->bufferstate
= PENDING
;
2015 // Set Current Buffer ID
2016 pSource
->ulBufferID
= pBufferList
->buffer
;
2018 // Set current position in this buffer
2019 pSource
->BufferPosition
= lByteOffset
- lTotalBufferSize
;
2021 // Set Total Bytes Played to Offset
2022 pSource
->lBytesPlayed
= lByteOffset
;
2024 // SW Mixer Positions are in Samples
2025 pSource
->position
= pSource
->BufferPosition
/ ((((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->format
== AL_FORMAT_MONO16
)?2:4);
2029 // Offset is before this buffer, so mark as pending
2030 pBufferList
->bufferstate
= PENDING
;
2033 // Increment the TotalBufferSize
2034 lTotalBufferSize
+= lBufferSize
;
2036 // Move on to next buffer in the Queue
2037 pBufferList
= pBufferList
->next
;
2043 alSetError(AL_INVALID_VALUE
);
2047 pSource
->lOffset
= 0;
2054 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2055 offset supplied by the application). This takes into account the fact that the buffer format
2056 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2058 static ALint
GetByteOffset(ALsource
*pSource
)
2060 ALbuffer
*pBuffer
= NULL
;
2061 ALbufferlistitem
*pBufferList
;
2062 ALfloat flBufferFreq
;
2064 ALint lByteOffset
= -1;
2065 ALint lTotalBufferDataSize
;
2067 // Find the first non-NULL Buffer in the Queue
2068 pBufferList
= pSource
->queue
;
2071 if (pBufferList
->buffer
)
2073 pBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
2076 pBufferList
= pBufferList
->next
;
2081 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2082 lChannels
= (pBuffer
->format
== AL_FORMAT_MONO16
)?1:2;
2084 // Determine the ByteOffset (and ensure it is block aligned)
2085 switch (pSource
->lOffsetType
)
2087 case AL_BYTE_OFFSET
:
2088 // Take into consideration the original format
2089 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO8
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO8
))
2091 lByteOffset
= pSource
->lOffset
* 2;
2092 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2094 else if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) || (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2096 // Round down to nearest ADPCM block
2097 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2098 // Multiply by compression rate
2099 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2100 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2104 lByteOffset
= pSource
->lOffset
;
2105 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2109 case AL_SAMPLE_OFFSET
:
2110 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2114 // Note - lOffset is internally stored as Milliseconds
2115 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2116 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2120 lTotalBufferDataSize
= 0;
2121 pBufferList
= pSource
->queue
;
2124 if (pBufferList
->buffer
)
2125 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
2126 pBufferList
= pBufferList
->next
;
2129 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2130 if (lByteOffset
>= lTotalBufferDataSize
)