2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
33 #include "alAuxEffectSlot.h"
35 static ALvoid
InitSourceParams(ALCcontext
*Context
, ALsource
*pSource
);
36 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
);
37 static ALvoid
ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
);
38 static ALint
GetByteOffset(ALsource
*pSource
);
40 ALAPI ALvoid ALAPIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
46 Context
= GetContextSuspended();
51 Device
= Context
->Device
;
53 // Check that enough memory has been allocted in the 'sources' array for n Sources
54 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
56 // Check that the requested number of sources can be generated
57 if((Context
->SourceCount
+ n
) <= Device
->MaxNoOfSources
)
59 ALsource
**list
= &Context
->Source
;
61 list
= &(*list
)->next
;
63 // Add additional sources to the list (Source->next points to the location for the next Source structure)
66 *list
= calloc(1, sizeof(ALsource
));
69 alDeleteSources(i
, sources
);
70 alSetError(AL_OUT_OF_MEMORY
);
74 sources
[i
] = (ALuint
)ALTHUNK_ADDENTRY(*list
);
75 (*list
)->source
= sources
[i
];
77 InitSourceParams(Context
, *list
);
78 Context
->SourceCount
++;
81 list
= &(*list
)->next
;
86 // Not enough resources to create the Sources
87 alSetError(AL_INVALID_VALUE
);
93 alSetError(AL_INVALID_VALUE
);
97 ProcessContext(Context
);
101 ALAPI ALvoid ALAPIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
108 ALbufferlistitem
*ALBufferList
;
109 ALboolean bSourcesValid
= AL_TRUE
;
111 Context
= GetContextSuspended();
116 Device
= Context
->Device
;
118 // Check that all Sources are valid (and can therefore be deleted)
119 for (i
= 0; i
< n
; i
++)
121 if (!alIsSource(sources
[i
]))
123 alSetError(AL_INVALID_NAME
);
124 bSourcesValid
= AL_FALSE
;
131 // All Sources are valid, and can be deleted
132 for(i
= 0; i
< n
; i
++)
134 // Recheck that the Source is valid, because there could be duplicated Source names
135 if(alIsSource(sources
[i
]))
137 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
138 alSourceStop((ALuint
)ALSource
->source
);
140 // For each buffer in the source's queue, decrement its reference counter and remove it
141 while (ALSource
->queue
!= NULL
)
143 ALBufferList
= ALSource
->queue
;
144 // Decrement buffer's reference counter
145 if(ALBufferList
->buffer
!= NULL
)
146 ALBufferList
->buffer
->refcount
--;
147 // Update queue to point to next element in list
148 ALSource
->queue
= ALBufferList
->next
;
149 // Release memory allocated for buffer list item
153 for(j
= 0;j
< MAX_SENDS
;++j
)
155 if(ALSource
->Send
[j
].Slot
)
156 ALSource
->Send
[j
].Slot
->refcount
--;
157 ALSource
->Send
[j
].Slot
= NULL
;
160 // Decrement Source count
161 Context
->SourceCount
--;
163 // Remove Source from list of Sources
164 list
= &Context
->Source
;
165 while(*list
&& *list
!= ALSource
)
166 list
= &(*list
)->next
;
169 *list
= (*list
)->next
;
170 ALTHUNK_REMOVEENTRY(ALSource
->source
);
172 memset(ALSource
,0,sizeof(ALsource
));
179 alSetError(AL_INVALID_VALUE
);
181 ProcessContext(Context
);
185 ALAPI ALboolean ALAPIENTRY
alIsSource(ALuint source
)
187 ALboolean result
=AL_FALSE
;
191 Context
= GetContextSuspended();
192 if(!Context
) return AL_FALSE
;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source
= Context
->Source
;
198 if(Source
->source
== source
)
204 Source
= Source
->next
;
207 ProcessContext(Context
);
213 ALAPI ALvoid ALAPIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
215 ALCcontext
*pContext
;
218 pContext
= GetContextSuspended();
219 if(!pContext
) return;
221 if(alIsSource(source
))
223 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
230 pSource
->flPitch
= flValue
;
231 if(pSource
->flPitch
< 0.001f
)
232 pSource
->flPitch
= 0.001f
;
235 alSetError(AL_INVALID_VALUE
);
238 case AL_CONE_INNER_ANGLE
:
239 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
240 pSource
->flInnerAngle
= flValue
;
242 alSetError(AL_INVALID_VALUE
);
245 case AL_CONE_OUTER_ANGLE
:
246 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
247 pSource
->flOuterAngle
= flValue
;
249 alSetError(AL_INVALID_VALUE
);
254 pSource
->flGain
= flValue
;
256 alSetError(AL_INVALID_VALUE
);
259 case AL_MAX_DISTANCE
:
261 pSource
->flMaxDistance
= flValue
;
263 alSetError(AL_INVALID_VALUE
);
266 case AL_ROLLOFF_FACTOR
:
268 pSource
->flRollOffFactor
= flValue
;
270 alSetError(AL_INVALID_VALUE
);
273 case AL_REFERENCE_DISTANCE
:
275 pSource
->flRefDistance
= flValue
;
277 alSetError(AL_INVALID_VALUE
);
281 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
282 pSource
->flMinGain
= flValue
;
284 alSetError(AL_INVALID_VALUE
);
288 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
289 pSource
->flMaxGain
= flValue
;
291 alSetError(AL_INVALID_VALUE
);
294 case AL_CONE_OUTER_GAIN
:
295 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
296 pSource
->flOuterGain
= flValue
;
298 alSetError(AL_INVALID_VALUE
);
301 case AL_CONE_OUTER_GAINHF
:
302 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
303 pSource
->OuterGainHF
= flValue
;
305 alSetError(AL_INVALID_VALUE
);
308 case AL_AIR_ABSORPTION_FACTOR
:
309 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
310 pSource
->AirAbsorptionFactor
= flValue
;
312 alSetError(AL_INVALID_VALUE
);
315 case AL_ROOM_ROLLOFF_FACTOR
:
316 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
317 pSource
->RoomRolloffFactor
= flValue
;
319 alSetError(AL_INVALID_VALUE
);
322 case AL_DOPPLER_FACTOR
:
323 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
324 pSource
->DopplerFactor
= flValue
;
326 alSetError(AL_INVALID_VALUE
);
330 case AL_SAMPLE_OFFSET
:
334 pSource
->lOffsetType
= eParam
;
336 // Store Offset (convert Seconds into Milliseconds)
337 if(eParam
== AL_SEC_OFFSET
)
338 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
340 pSource
->lOffset
= (ALint
)flValue
;
342 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
343 ApplyOffset(pSource
, AL_TRUE
);
346 alSetError(AL_INVALID_VALUE
);
350 alSetError(AL_INVALID_ENUM
);
356 // Invalid Source Name
357 alSetError(AL_INVALID_NAME
);
360 ProcessContext(pContext
);
364 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
366 ALCcontext
*pContext
;
369 pContext
= GetContextSuspended();
370 if(!pContext
) return;
372 if(alIsSource(source
))
374 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
378 pSource
->vPosition
[0] = flValue1
;
379 pSource
->vPosition
[1] = flValue2
;
380 pSource
->vPosition
[2] = flValue3
;
384 pSource
->vVelocity
[0] = flValue1
;
385 pSource
->vVelocity
[1] = flValue2
;
386 pSource
->vVelocity
[2] = flValue3
;
390 pSource
->vOrientation
[0] = flValue1
;
391 pSource
->vOrientation
[1] = flValue2
;
392 pSource
->vOrientation
[2] = flValue3
;
396 alSetError(AL_INVALID_ENUM
);
401 alSetError(AL_INVALID_NAME
);
403 ProcessContext(pContext
);
407 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
409 ALCcontext
*pContext
;
411 pContext
= GetContextSuspended();
412 if(!pContext
) return;
416 if(alIsSource(source
))
421 case AL_CONE_INNER_ANGLE
:
422 case AL_CONE_OUTER_ANGLE
:
424 case AL_MAX_DISTANCE
:
425 case AL_ROLLOFF_FACTOR
:
426 case AL_REFERENCE_DISTANCE
:
429 case AL_CONE_OUTER_GAIN
:
430 case AL_CONE_OUTER_GAINHF
:
432 case AL_SAMPLE_OFFSET
:
434 case AL_AIR_ABSORPTION_FACTOR
:
435 case AL_ROOM_ROLLOFF_FACTOR
:
436 alSourcef(source
, eParam
, pflValues
[0]);
442 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
446 alSetError(AL_INVALID_ENUM
);
451 alSetError(AL_INVALID_NAME
);
454 alSetError(AL_INVALID_VALUE
);
456 ProcessContext(pContext
);
460 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
462 ALCcontext
*pContext
;
464 ALbufferlistitem
*pALBufferListItem
;
466 pContext
= GetContextSuspended();
467 if(!pContext
) return;
469 if(alIsSource(source
))
471 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
475 case AL_MAX_DISTANCE
:
476 case AL_ROLLOFF_FACTOR
:
477 case AL_REFERENCE_DISTANCE
:
478 alSourcef(source
, eParam
, (ALfloat
)lValue
);
481 case AL_SOURCE_RELATIVE
:
482 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
483 pSource
->bHeadRelative
= (ALboolean
)lValue
;
485 alSetError(AL_INVALID_VALUE
);
488 case AL_CONE_INNER_ANGLE
:
489 if(lValue
>= 0 && lValue
<= 360)
490 pSource
->flInnerAngle
= (float)lValue
;
492 alSetError(AL_INVALID_VALUE
);
495 case AL_CONE_OUTER_ANGLE
:
496 if(lValue
>= 0 && lValue
<= 360)
497 pSource
->flOuterAngle
= (float)lValue
;
499 alSetError(AL_INVALID_VALUE
);
503 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
504 pSource
->bLooping
= (ALboolean
)lValue
;
506 alSetError(AL_INVALID_VALUE
);
510 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
512 if(alIsBuffer(lValue
))
514 ALbuffer
*buffer
= NULL
;
516 // Remove all elements in the queue
517 while(pSource
->queue
!= NULL
)
519 pALBufferListItem
= pSource
->queue
;
520 pSource
->queue
= pALBufferListItem
->next
;
521 // Decrement reference counter for buffer
522 if(pALBufferListItem
->buffer
)
523 pALBufferListItem
->buffer
->refcount
--;
524 // Release memory for buffer list item
525 free(pALBufferListItem
);
526 // Decrement the number of buffers in the queue
527 pSource
->BuffersInQueue
--;
530 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
533 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
);
535 // Source is now in STATIC mode
536 pSource
->lSourceType
= AL_STATIC
;
538 // Add the selected buffer to the queue
539 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
540 pALBufferListItem
->buffer
= buffer
;
541 pALBufferListItem
->next
= NULL
;
543 pSource
->queue
= pALBufferListItem
;
544 pSource
->BuffersInQueue
= 1;
546 // Increment reference counter for buffer
551 // Source is now in UNDETERMINED mode
552 pSource
->lSourceType
= AL_UNDETERMINED
;
553 pSource
->BuffersPlayed
= 0;
556 // Update AL_BUFFER parameter
557 pSource
->Buffer
= buffer
;
560 alSetError(AL_INVALID_VALUE
);
563 alSetError(AL_INVALID_OPERATION
);
566 case AL_SOURCE_STATE
:
568 alSetError(AL_INVALID_OPERATION
);
572 case AL_SAMPLE_OFFSET
:
576 pSource
->lOffsetType
= eParam
;
578 // Store Offset (convert Seconds into Milliseconds)
579 if(eParam
== AL_SEC_OFFSET
)
580 pSource
->lOffset
= lValue
* 1000;
582 pSource
->lOffset
= lValue
;
584 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
585 ApplyOffset(pSource
, AL_TRUE
);
588 alSetError(AL_INVALID_VALUE
);
591 case AL_DIRECT_FILTER
:
592 if(alIsFilter(lValue
))
594 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
597 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
598 pSource
->DirectFilter
.filter
= 0;
601 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
604 alSetError(AL_INVALID_VALUE
);
607 case AL_DIRECT_FILTER_GAINHF_AUTO
:
608 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
609 pSource
->DryGainHFAuto
= lValue
;
611 alSetError(AL_INVALID_VALUE
);
614 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
615 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
616 pSource
->WetGainAuto
= lValue
;
618 alSetError(AL_INVALID_VALUE
);
621 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
622 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
623 pSource
->WetGainHFAuto
= lValue
;
625 alSetError(AL_INVALID_VALUE
);
628 case AL_DISTANCE_MODEL
:
629 if(lValue
== AL_NONE
||
630 lValue
== AL_INVERSE_DISTANCE
||
631 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
632 lValue
== AL_LINEAR_DISTANCE
||
633 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
634 lValue
== AL_EXPONENT_DISTANCE
||
635 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
636 pSource
->DistanceModel
= lValue
;
638 alSetError(AL_INVALID_VALUE
);
642 alSetError(AL_INVALID_ENUM
);
647 alSetError(AL_INVALID_NAME
);
649 ProcessContext(pContext
);
653 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
655 ALCcontext
*pContext
;
657 pContext
= GetContextSuspended();
658 if(!pContext
) return;
660 if(alIsSource(source
))
662 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
663 ALCdevice
*Device
= pContext
->Device
;
670 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
673 case AL_AUXILIARY_SEND_FILTER
:
674 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
675 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
678 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
679 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
681 /* Release refcount on the previous slot, and add one for
683 if(pSource
->Send
[lValue2
].Slot
)
684 pSource
->Send
[lValue2
].Slot
->refcount
--;
685 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
686 if(pSource
->Send
[lValue2
].Slot
)
687 pSource
->Send
[lValue2
].Slot
->refcount
++;
692 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
693 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
696 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
699 alSetError(AL_INVALID_VALUE
);
703 alSetError(AL_INVALID_ENUM
);
708 alSetError(AL_INVALID_NAME
);
710 ProcessContext(pContext
);
714 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
716 ALCcontext
*pContext
;
718 pContext
= GetContextSuspended();
719 if(!pContext
) return;
723 if(alIsSource(source
))
727 case AL_SOURCE_RELATIVE
:
728 case AL_CONE_INNER_ANGLE
:
729 case AL_CONE_OUTER_ANGLE
:
732 case AL_SOURCE_STATE
:
734 case AL_SAMPLE_OFFSET
:
736 case AL_MAX_DISTANCE
:
737 case AL_ROLLOFF_FACTOR
:
738 case AL_REFERENCE_DISTANCE
:
739 case AL_DIRECT_FILTER
:
740 case AL_DIRECT_FILTER_GAINHF_AUTO
:
741 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
742 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
743 case AL_DISTANCE_MODEL
:
744 alSourcei(source
, eParam
, plValues
[0]);
750 case AL_AUXILIARY_SEND_FILTER
:
751 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
755 alSetError(AL_INVALID_ENUM
);
760 alSetError(AL_INVALID_NAME
);
763 alSetError(AL_INVALID_VALUE
);
765 ProcessContext(pContext
);
769 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
771 ALCcontext
*pContext
;
775 pContext
= GetContextSuspended();
776 if(!pContext
) return;
780 if(alIsSource(source
))
782 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
787 *pflValue
= pSource
->flPitch
;
791 *pflValue
= pSource
->flGain
;
795 *pflValue
= pSource
->flMinGain
;
799 *pflValue
= pSource
->flMaxGain
;
802 case AL_MAX_DISTANCE
:
803 *pflValue
= pSource
->flMaxDistance
;
806 case AL_ROLLOFF_FACTOR
:
807 *pflValue
= pSource
->flRollOffFactor
;
810 case AL_CONE_OUTER_GAIN
:
811 *pflValue
= pSource
->flOuterGain
;
814 case AL_CONE_OUTER_GAINHF
:
815 *pflValue
= pSource
->OuterGainHF
;
819 case AL_SAMPLE_OFFSET
:
821 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
822 *pflValue
= flOffset
[0];
824 alSetError(AL_INVALID_OPERATION
);
827 case AL_SEC_RW_OFFSETS_EXT
:
828 case AL_SAMPLE_RW_OFFSETS_EXT
:
829 case AL_BYTE_RW_OFFSETS_EXT
:
830 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
832 pflValue
[0] = flOffset
[0];
833 pflValue
[1] = flOffset
[1];
836 alSetError(AL_INVALID_OPERATION
);
839 case AL_CONE_INNER_ANGLE
:
840 *pflValue
= pSource
->flInnerAngle
;
843 case AL_CONE_OUTER_ANGLE
:
844 *pflValue
= pSource
->flOuterAngle
;
847 case AL_REFERENCE_DISTANCE
:
848 *pflValue
= pSource
->flRefDistance
;
851 case AL_AIR_ABSORPTION_FACTOR
:
852 *pflValue
= pSource
->AirAbsorptionFactor
;
855 case AL_ROOM_ROLLOFF_FACTOR
:
856 *pflValue
= pSource
->RoomRolloffFactor
;
859 case AL_DOPPLER_FACTOR
:
860 *pflValue
= pSource
->DopplerFactor
;
864 alSetError(AL_INVALID_ENUM
);
869 alSetError(AL_INVALID_NAME
);
872 alSetError(AL_INVALID_VALUE
);
874 ProcessContext(pContext
);
878 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
880 ALCcontext
*pContext
;
883 pContext
= GetContextSuspended();
884 if(!pContext
) return;
886 if(pflValue1
&& pflValue2
&& pflValue3
)
888 if(alIsSource(source
))
890 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
895 *pflValue1
= pSource
->vPosition
[0];
896 *pflValue2
= pSource
->vPosition
[1];
897 *pflValue3
= pSource
->vPosition
[2];
901 *pflValue1
= pSource
->vVelocity
[0];
902 *pflValue2
= pSource
->vVelocity
[1];
903 *pflValue3
= pSource
->vVelocity
[2];
907 *pflValue1
= pSource
->vOrientation
[0];
908 *pflValue2
= pSource
->vOrientation
[1];
909 *pflValue3
= pSource
->vOrientation
[2];
913 alSetError(AL_INVALID_ENUM
);
918 alSetError(AL_INVALID_NAME
);
921 alSetError(AL_INVALID_VALUE
);
923 ProcessContext(pContext
);
927 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
929 ALCcontext
*pContext
;
932 pContext
= GetContextSuspended();
933 if(!pContext
) return;
937 if(alIsSource(source
))
939 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
947 case AL_MAX_DISTANCE
:
948 case AL_ROLLOFF_FACTOR
:
949 case AL_DOPPLER_FACTOR
:
950 case AL_CONE_OUTER_GAIN
:
952 case AL_SAMPLE_OFFSET
:
954 case AL_CONE_INNER_ANGLE
:
955 case AL_CONE_OUTER_ANGLE
:
956 case AL_REFERENCE_DISTANCE
:
957 case AL_CONE_OUTER_GAINHF
:
958 case AL_AIR_ABSORPTION_FACTOR
:
959 case AL_ROOM_ROLLOFF_FACTOR
:
960 alGetSourcef(source
, eParam
, pflValues
);
964 pflValues
[0] = pSource
->vPosition
[0];
965 pflValues
[1] = pSource
->vPosition
[1];
966 pflValues
[2] = pSource
->vPosition
[2];
970 pflValues
[0] = pSource
->vVelocity
[0];
971 pflValues
[1] = pSource
->vVelocity
[1];
972 pflValues
[2] = pSource
->vVelocity
[2];
976 pflValues
[0] = pSource
->vOrientation
[0];
977 pflValues
[1] = pSource
->vOrientation
[1];
978 pflValues
[2] = pSource
->vOrientation
[2];
982 alSetError(AL_INVALID_ENUM
);
987 alSetError(AL_INVALID_NAME
);
990 alSetError(AL_INVALID_VALUE
);
992 ProcessContext(pContext
);
996 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
998 ALCcontext
*pContext
;
1000 ALfloat flOffset
[2];
1002 pContext
= GetContextSuspended();
1003 if(!pContext
) return;
1007 if(alIsSource(source
))
1009 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1013 case AL_MAX_DISTANCE
:
1014 *plValue
= (ALint
)pSource
->flMaxDistance
;
1017 case AL_ROLLOFF_FACTOR
:
1018 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1021 case AL_REFERENCE_DISTANCE
:
1022 *plValue
= (ALint
)pSource
->flRefDistance
;
1025 case AL_SOURCE_RELATIVE
:
1026 *plValue
= pSource
->bHeadRelative
;
1029 case AL_CONE_INNER_ANGLE
:
1030 *plValue
= (ALint
)pSource
->flInnerAngle
;
1033 case AL_CONE_OUTER_ANGLE
:
1034 *plValue
= (ALint
)pSource
->flOuterAngle
;
1038 *plValue
= pSource
->bLooping
;
1042 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1045 case AL_SOURCE_STATE
:
1046 *plValue
= pSource
->state
;
1049 case AL_BUFFERS_QUEUED
:
1050 *plValue
= pSource
->BuffersInQueue
;
1053 case AL_BUFFERS_PROCESSED
:
1054 if(pSource
->bLooping
)
1056 /* Buffers on a looping source are in a perpetual state
1057 * of PENDING, so don't report any as PROCESSED */
1061 *plValue
= pSource
->BuffersPlayed
;
1064 case AL_SOURCE_TYPE
:
1065 *plValue
= pSource
->lSourceType
;
1069 case AL_SAMPLE_OFFSET
:
1070 case AL_BYTE_OFFSET
:
1071 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1072 *plValue
= (ALint
)flOffset
[0];
1074 alSetError(AL_INVALID_OPERATION
);
1077 case AL_SEC_RW_OFFSETS_EXT
:
1078 case AL_SAMPLE_RW_OFFSETS_EXT
:
1079 case AL_BYTE_RW_OFFSETS_EXT
:
1080 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1082 plValue
[0] = (ALint
)flOffset
[0];
1083 plValue
[1] = (ALint
)flOffset
[1];
1086 alSetError(AL_INVALID_OPERATION
);
1089 case AL_DIRECT_FILTER
:
1090 *plValue
= pSource
->DirectFilter
.filter
;
1093 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1094 *plValue
= pSource
->DryGainHFAuto
;
1097 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1098 *plValue
= pSource
->WetGainAuto
;
1101 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1102 *plValue
= pSource
->WetGainHFAuto
;
1105 case AL_DOPPLER_FACTOR
:
1106 *plValue
= (ALint
)pSource
->DopplerFactor
;
1109 case AL_DISTANCE_MODEL
:
1110 *plValue
= pSource
->DistanceModel
;
1114 alSetError(AL_INVALID_ENUM
);
1119 alSetError(AL_INVALID_NAME
);
1122 alSetError(AL_INVALID_VALUE
);
1124 ProcessContext(pContext
);
1128 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1130 ALCcontext
*pContext
;
1133 pContext
= GetContextSuspended();
1134 if(!pContext
) return;
1136 if(plValue1
&& plValue2
&& plValue3
)
1138 if(alIsSource(source
))
1140 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1145 *plValue1
= (ALint
)pSource
->vPosition
[0];
1146 *plValue2
= (ALint
)pSource
->vPosition
[1];
1147 *plValue3
= (ALint
)pSource
->vPosition
[2];
1151 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1152 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1153 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1157 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1158 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1159 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1163 alSetError(AL_INVALID_ENUM
);
1168 alSetError(AL_INVALID_NAME
);
1171 alSetError(AL_INVALID_VALUE
);
1173 ProcessContext(pContext
);
1177 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1179 ALCcontext
*pContext
;
1182 pContext
= GetContextSuspended();
1183 if(!pContext
) return;
1187 if(alIsSource(source
))
1189 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1193 case AL_SOURCE_RELATIVE
:
1194 case AL_CONE_INNER_ANGLE
:
1195 case AL_CONE_OUTER_ANGLE
:
1198 case AL_SOURCE_STATE
:
1199 case AL_BUFFERS_QUEUED
:
1200 case AL_BUFFERS_PROCESSED
:
1202 case AL_SAMPLE_OFFSET
:
1203 case AL_BYTE_OFFSET
:
1204 case AL_MAX_DISTANCE
:
1205 case AL_ROLLOFF_FACTOR
:
1206 case AL_DOPPLER_FACTOR
:
1207 case AL_REFERENCE_DISTANCE
:
1208 case AL_SOURCE_TYPE
:
1209 case AL_DIRECT_FILTER
:
1210 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1211 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1212 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1213 case AL_DISTANCE_MODEL
:
1214 alGetSourcei(source
, eParam
, plValues
);
1218 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1219 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1220 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1224 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1225 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1226 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1230 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1231 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1232 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1236 alSetError(AL_INVALID_ENUM
);
1241 alSetError(AL_INVALID_NAME
);
1244 alSetError(AL_INVALID_VALUE
);
1246 ProcessContext(pContext
);
1250 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1252 alSourcePlayv(1, &source
);
1256 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1258 ALCcontext
*pContext
;
1260 ALbufferlistitem
*ALBufferList
;
1261 ALboolean bSourcesValid
= AL_TRUE
;
1265 pContext
= GetContextSuspended();
1266 if(!pContext
) return;
1270 // Check that all the Sources are valid
1271 for(i
= 0; i
< n
; i
++)
1273 if(!alIsSource(pSourceList
[i
]))
1275 alSetError(AL_INVALID_NAME
);
1276 bSourcesValid
= AL_FALSE
;
1283 for(i
= 0; i
< n
; i
++)
1285 // Assume Source won't need to play
1288 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1290 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1291 ALBufferList
= pSource
->queue
;
1294 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1299 ALBufferList
= ALBufferList
->next
;
1304 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1305 pSource
->DryGains
[j
] = 0.0f
;
1306 for(j
= 0;j
< MAX_SENDS
;j
++)
1307 pSource
->WetGains
[j
] = 0.0f
;
1309 if(pSource
->state
!= AL_PAUSED
)
1311 pSource
->state
= AL_PLAYING
;
1312 pSource
->position
= 0;
1313 pSource
->position_fraction
= 0;
1314 pSource
->BuffersPlayed
= 0;
1316 pSource
->Buffer
= pSource
->queue
->buffer
;
1319 pSource
->state
= AL_PLAYING
;
1321 // Check if an Offset has been set
1322 if(pSource
->lOffset
)
1323 ApplyOffset(pSource
, AL_FALSE
);
1325 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1326 pSource
->position_fraction
== 0)
1327 pSource
->FirstStart
= AL_TRUE
;
1329 pSource
->FirstStart
= AL_FALSE
;
1331 // If device is disconnected, go right to stopped
1332 if(!pContext
->Device
->Connected
)
1334 pSource
->state
= AL_STOPPED
;
1335 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1336 pSource
->position
= 0;
1337 pSource
->position_fraction
= 0;
1341 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1347 // sources is a NULL pointer
1348 alSetError(AL_INVALID_VALUE
);
1351 ProcessContext(pContext
);
1354 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1356 alSourcePausev(1, &source
);
1360 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1362 ALCcontext
*Context
;
1365 ALboolean bSourcesValid
= AL_TRUE
;
1367 Context
= GetContextSuspended();
1368 if(!Context
) return;
1372 // Check all the Sources are valid
1375 if(!alIsSource(sources
[i
]))
1377 alSetError(AL_INVALID_NAME
);
1378 bSourcesValid
= AL_FALSE
;
1385 for(i
= 0;i
< n
;i
++)
1387 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1388 if(Source
->state
== AL_PLAYING
)
1389 Source
->state
= AL_PAUSED
;
1395 // sources is a NULL pointer
1396 alSetError(AL_INVALID_VALUE
);
1399 ProcessContext(Context
);
1402 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1404 alSourceStopv(1, &source
);
1408 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1410 ALCcontext
*Context
;
1413 ALboolean bSourcesValid
= AL_TRUE
;
1415 Context
= GetContextSuspended();
1416 if(!Context
) return;
1420 // Check all the Sources are valid
1421 for(i
= 0;i
< n
;i
++)
1423 if(!alIsSource(sources
[i
]))
1425 alSetError(AL_INVALID_NAME
);
1426 bSourcesValid
= AL_FALSE
;
1433 for(i
= 0;i
< n
;i
++)
1435 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1436 if(Source
->state
!= AL_INITIAL
)
1438 Source
->state
= AL_STOPPED
;
1439 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1441 Source
->lOffset
= 0;
1447 // sources is a NULL pointer
1448 alSetError(AL_INVALID_VALUE
);
1451 ProcessContext(Context
);
1454 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1456 alSourceRewindv(1, &source
);
1460 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1462 ALCcontext
*Context
;
1465 ALboolean bSourcesValid
= AL_TRUE
;
1467 Context
= GetContextSuspended();
1468 if(!Context
) return;
1472 // Check all the Sources are valid
1473 for(i
= 0;i
< n
;i
++)
1475 if(!alIsSource(sources
[i
]))
1477 alSetError(AL_INVALID_NAME
);
1478 bSourcesValid
= AL_FALSE
;
1485 for(i
= 0;i
< n
;i
++)
1487 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1488 if(Source
->state
!= AL_INITIAL
)
1490 Source
->state
= AL_INITIAL
;
1491 Source
->position
= 0;
1492 Source
->position_fraction
= 0;
1493 Source
->BuffersPlayed
= 0;
1495 Source
->Buffer
= Source
->queue
->buffer
;
1497 Source
->lOffset
= 0;
1503 // sources is a NULL pointer
1504 alSetError(AL_INVALID_VALUE
);
1507 ProcessContext(Context
);
1511 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1513 ALCcontext
*Context
;
1516 ALbufferlistitem
*ALBufferList
;
1517 ALbufferlistitem
*ALBufferListStart
;
1520 ALboolean bBuffersValid
= AL_TRUE
;
1525 Context
= GetContextSuspended();
1526 if(!Context
) return;
1528 // Check that all buffers are valid or zero and that the source is valid
1530 // Check that this is a valid source
1531 if(alIsSource(source
))
1533 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1535 // Check that this is not a STATIC Source
1536 if(ALSource
->lSourceType
!= AL_STATIC
)
1541 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1542 ALBufferList
= ALSource
->queue
;
1545 if (ALBufferList
->buffer
)
1547 iFrequency
= ALBufferList
->buffer
->frequency
;
1548 iFormat
= ALBufferList
->buffer
->format
;
1551 ALBufferList
= ALBufferList
->next
;
1554 for(i
= 0; i
< n
; i
++)
1558 if(!alIsBuffer(buffers
[i
]))
1560 alSetError(AL_INVALID_NAME
);
1561 bBuffersValid
= AL_FALSE
;
1567 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1568 if(iFrequency
== -1 && iFormat
== -1)
1570 iFrequency
= buffer
->frequency
;
1571 iFormat
= buffer
->format
;
1573 else if(iFrequency
!= buffer
->frequency
||
1574 iFormat
!= buffer
->format
)
1576 alSetError(AL_INVALID_OPERATION
);
1577 bBuffersValid
= AL_FALSE
;
1584 ALbuffer
*buffer
= NULL
;
1586 // Change Source Type
1587 ALSource
->lSourceType
= AL_STREAMING
;
1589 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1591 // All buffers are valid - so add them to the list
1592 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1593 ALBufferListStart
->buffer
= buffer
;
1594 ALBufferListStart
->next
= NULL
;
1596 // Increment reference counter for buffer
1597 if(buffer
) buffer
->refcount
++;
1599 ALBufferList
= ALBufferListStart
;
1601 for(i
= 1; i
< n
; i
++)
1603 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1605 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1606 ALBufferList
->next
->buffer
= buffer
;
1607 ALBufferList
->next
->next
= NULL
;
1609 // Increment reference counter for buffer
1610 if(buffer
) buffer
->refcount
++;
1612 ALBufferList
= ALBufferList
->next
;
1615 if(ALSource
->queue
== NULL
)
1617 ALSource
->queue
= ALBufferListStart
;
1618 // Update Current Buffer
1619 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1623 // Find end of queue
1624 ALBufferList
= ALSource
->queue
;
1625 while(ALBufferList
->next
!= NULL
)
1626 ALBufferList
= ALBufferList
->next
;
1628 ALBufferList
->next
= ALBufferListStart
;
1631 // Update number of buffers in queue
1632 ALSource
->BuffersInQueue
+= n
;
1637 // Invalid Source Type (can't queue on a Static Source)
1638 alSetError(AL_INVALID_OPERATION
);
1643 // Invalid Source Name
1644 alSetError(AL_INVALID_NAME
);
1647 ProcessContext(Context
);
1651 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1652 // an array of buffer IDs that are to be filled with the names of the buffers removed
1653 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1655 ALCcontext
*Context
;
1658 ALbufferlistitem
*ALBufferList
;
1659 ALboolean bBuffersProcessed
;
1664 bBuffersProcessed
= AL_TRUE
;
1666 Context
= GetContextSuspended();
1667 if(!Context
) return;
1669 if(alIsSource(source
))
1671 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1673 // If all 'n' buffers have been processed, remove them from the queue
1674 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1676 for(i
= 0; i
< n
; i
++)
1678 ALBufferList
= ALSource
->queue
;
1680 ALSource
->queue
= ALBufferList
->next
;
1681 // Record name of buffer
1682 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1683 // Decrement buffer reference counter
1684 if(ALBufferList
->buffer
)
1685 ALBufferList
->buffer
->refcount
--;
1687 // Release memory for buffer list item
1689 ALSource
->BuffersInQueue
--;
1692 if(ALSource
->state
!= AL_PLAYING
)
1695 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1697 ALSource
->Buffer
= NULL
;
1700 ALSource
->BuffersPlayed
-= n
;
1704 // Some buffers can't be unqueue because they have not been processed
1705 alSetError(AL_INVALID_VALUE
);
1710 // Invalid Source Name
1711 alSetError(AL_INVALID_NAME
);
1714 ProcessContext(Context
);
1718 static ALvoid
InitSourceParams(ALCcontext
*Context
, ALsource
*pSource
)
1720 pSource
->flInnerAngle
= 360.0f
;
1721 pSource
->flOuterAngle
= 360.0f
;
1722 pSource
->flPitch
= 1.0f
;
1723 pSource
->vPosition
[0] = 0.0f
;
1724 pSource
->vPosition
[1] = 0.0f
;
1725 pSource
->vPosition
[2] = 0.0f
;
1726 pSource
->vOrientation
[0] = 0.0f
;
1727 pSource
->vOrientation
[1] = 0.0f
;
1728 pSource
->vOrientation
[2] = 0.0f
;
1729 pSource
->vVelocity
[0] = 0.0f
;
1730 pSource
->vVelocity
[1] = 0.0f
;
1731 pSource
->vVelocity
[2] = 0.0f
;
1732 pSource
->flRefDistance
= 1.0f
;
1733 pSource
->flMaxDistance
= FLT_MAX
;
1734 pSource
->flRollOffFactor
= 1.0f
;
1735 pSource
->bLooping
= AL_FALSE
;
1736 pSource
->flGain
= 1.0f
;
1737 pSource
->flMinGain
= 0.0f
;
1738 pSource
->flMaxGain
= 1.0f
;
1739 pSource
->flOuterGain
= 0.0f
;
1740 pSource
->OuterGainHF
= 1.0f
;
1742 pSource
->DryGainHFAuto
= AL_TRUE
;
1743 pSource
->WetGainAuto
= AL_TRUE
;
1744 pSource
->WetGainHFAuto
= AL_TRUE
;
1745 pSource
->AirAbsorptionFactor
= 0.0f
;
1746 pSource
->RoomRolloffFactor
= 0.0f
;
1747 pSource
->DopplerFactor
= 1.0f
;
1749 pSource
->DistanceModel
= Context
->DistanceModel
;
1751 pSource
->state
= AL_INITIAL
;
1752 pSource
->lSourceType
= AL_UNDETERMINED
;
1754 pSource
->Buffer
= NULL
;
1761 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1762 The offset is relative to the start of the queue (not the start of the current buffer)
1764 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1766 ALbufferlistitem
*pBufferList
;
1768 ALfloat flBufferFreq
;
1770 ALint readPos
, writePos
;
1771 ALenum eOriginalFormat
;
1772 ALboolean bReturn
= AL_TRUE
;
1773 ALint lTotalBufferDataSize
;
1776 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1778 pBuffer
= pSource
->Buffer
;
1779 // Get Current Buffer Size and frequency (in milliseconds)
1780 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1781 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1782 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1784 // Get Current BytesPlayed
1785 readPos
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1786 // Add byte length of any processed buffers in the queue
1787 pBufferList
= pSource
->queue
;
1788 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1790 readPos
+= pBufferList
->buffer
->size
;
1791 pBufferList
= pBufferList
->next
;
1794 if(pSource
->state
== AL_PLAYING
)
1795 writePos
= readPos
+ (updateSize
* lChannels
* 2);
1799 lTotalBufferDataSize
= 0;
1800 pBufferList
= pSource
->queue
;
1803 if (pBufferList
->buffer
)
1804 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1805 pBufferList
= pBufferList
->next
;
1808 if (pSource
->bLooping
)
1813 readPos
%= lTotalBufferDataSize
;
1817 writePos
%= lTotalBufferDataSize
;
1821 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1824 else if(readPos
> lTotalBufferDataSize
)
1825 readPos
= lTotalBufferDataSize
;
1828 else if(writePos
> lTotalBufferDataSize
)
1829 writePos
= lTotalBufferDataSize
;
1835 case AL_SEC_RW_OFFSETS_EXT
:
1836 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* 2.0f
* flBufferFreq
);
1837 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* 2.0f
* flBufferFreq
);
1839 case AL_SAMPLE_OFFSET
:
1840 case AL_SAMPLE_RW_OFFSETS_EXT
:
1841 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* 2));
1842 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* 2));
1844 case AL_BYTE_OFFSET
:
1845 case AL_BYTE_RW_OFFSETS_EXT
:
1846 // Take into account the original format of the Buffer
1847 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1848 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1850 // Round down to nearest ADPCM block
1851 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * 2 * lChannels
)) * 36 * lChannels
);
1852 if(pSource
->state
== AL_PLAYING
)
1854 // Round up to nearest ADPCM block
1855 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * 2 * lChannels
) - 1) / (65 * 2 * lChannels
)) * 36 * lChannels
);
1858 pflOffset
[1] = pflOffset
[0];
1860 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1862 pflOffset
[0] = (ALfloat
)(readPos
>> 2);
1863 pflOffset
[1] = (ALfloat
)(writePos
>> 2);
1865 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1867 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1868 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1870 else if (aluBytesFromFormat(eOriginalFormat
) == 1)
1872 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1873 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1875 else if (aluBytesFromFormat(eOriginalFormat
) == 4)
1877 pflOffset
[0] = (ALfloat
)(readPos
<< 1);
1878 pflOffset
[1] = (ALfloat
)(writePos
<< 1);
1882 pflOffset
[0] = (ALfloat
)readPos
;
1883 pflOffset
[1] = (ALfloat
)writePos
;
1890 pflOffset
[0] = 0.0f
;
1891 pflOffset
[1] = 0.0f
;
1901 Apply a playback offset to the Source. This function will update the queue (to correctly
1902 mark buffers as 'pending' or 'processed' depending upon the new offset.
1904 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1906 ALbufferlistitem
*pBufferList
;
1908 ALint lBufferSize
, lTotalBufferSize
;
1911 // Get true byte offset
1912 lByteOffset
= GetByteOffset(pSource
);
1914 // If this is a valid offset apply it
1915 if (lByteOffset
!= -1)
1917 // Sort out the queue (pending and processed states)
1918 pBufferList
= pSource
->queue
;
1919 lTotalBufferSize
= 0;
1920 pSource
->BuffersPlayed
= 0;
1923 pBuffer
= pBufferList
->buffer
;
1924 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
1926 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
1928 // Offset is past this buffer so increment BuffersPlayed
1929 pSource
->BuffersPlayed
++;
1931 else if (lTotalBufferSize
<= lByteOffset
)
1933 // Offset is within this buffer
1934 // Set Current Buffer
1935 pSource
->Buffer
= pBufferList
->buffer
;
1937 // SW Mixer Positions are in Samples
1938 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
1939 aluBytesFromFormat(pBuffer
->format
) /
1940 aluChannelsFromFormat(pBuffer
->format
);
1943 // Increment the TotalBufferSize
1944 lTotalBufferSize
+= lBufferSize
;
1946 // Move on to next buffer in the Queue
1947 pBufferList
= pBufferList
->next
;
1953 alSetError(AL_INVALID_VALUE
);
1957 pSource
->lOffset
= 0;
1964 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1965 offset supplied by the application). This takes into account the fact that the buffer format
1966 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
1968 static ALint
GetByteOffset(ALsource
*pSource
)
1970 ALbuffer
*pBuffer
= NULL
;
1971 ALbufferlistitem
*pBufferList
;
1972 ALfloat flBufferFreq
;
1974 ALint lByteOffset
= -1;
1975 ALint lTotalBufferDataSize
;
1977 // Find the first non-NULL Buffer in the Queue
1978 pBufferList
= pSource
->queue
;
1981 if (pBufferList
->buffer
)
1983 pBuffer
= pBufferList
->buffer
;
1986 pBufferList
= pBufferList
->next
;
1991 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
1992 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1994 // Determine the ByteOffset (and ensure it is block aligned)
1995 switch (pSource
->lOffsetType
)
1997 case AL_BYTE_OFFSET
:
1998 // Take into consideration the original format
1999 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
2000 (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2002 // Round down to nearest ADPCM block
2003 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2004 // Multiply by compression rate
2005 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2006 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2008 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR8
)
2010 lByteOffset
= pSource
->lOffset
* 4;
2011 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2013 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR16
)
2015 lByteOffset
= pSource
->lOffset
* 2;
2016 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2018 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 1)
2020 lByteOffset
= pSource
->lOffset
* 2;
2021 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2023 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 4)
2025 lByteOffset
= pSource
->lOffset
/ 2;
2026 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2030 lByteOffset
= pSource
->lOffset
;
2031 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2035 case AL_SAMPLE_OFFSET
:
2036 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2040 // Note - lOffset is internally stored as Milliseconds
2041 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2042 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2046 lTotalBufferDataSize
= 0;
2047 pBufferList
= pSource
->queue
;
2050 if (pBufferList
->buffer
)
2051 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2052 pBufferList
= pBufferList
->next
;
2055 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2056 if (lByteOffset
>= lTotalBufferDataSize
)
2064 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2068 while(Context
->Source
)
2070 ALsource
*temp
= Context
->Source
;
2071 Context
->Source
= temp
->next
;
2073 // For each buffer in the source's queue, decrement its reference counter and remove it
2074 while(temp
->queue
!= NULL
)
2076 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2077 // Decrement buffer's reference counter
2078 if(ALBufferList
->buffer
!= NULL
)
2079 ALBufferList
->buffer
->refcount
--;
2080 // Update queue to point to next element in list
2081 temp
->queue
= ALBufferList
->next
;
2082 // Release memory allocated for buffer list item
2086 for(j
= 0;j
< MAX_SENDS
;++j
)
2088 if(temp
->Send
[j
].Slot
)
2089 temp
->Send
[j
].Slot
->refcount
--;
2092 // Release source structure
2093 ALTHUNK_REMOVEENTRY(temp
->source
);
2094 memset(temp
, 0, sizeof(ALsource
));
2097 Context
->SourceCount
= 0;