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 pSource
->Format
= buffer
->format
;
539 pSource
->Frequency
= buffer
->frequency
;
541 // Add the selected buffer to the queue
542 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
543 pALBufferListItem
->buffer
= buffer
;
544 pALBufferListItem
->next
= NULL
;
546 pSource
->queue
= pALBufferListItem
;
547 pSource
->BuffersInQueue
= 1;
549 // Increment reference counter for buffer
554 // Source is now in UNDETERMINED mode
555 pSource
->lSourceType
= AL_UNDETERMINED
;
556 pSource
->BuffersPlayed
= 0;
559 // Update AL_BUFFER parameter
560 pSource
->Buffer
= buffer
;
563 alSetError(AL_INVALID_VALUE
);
566 alSetError(AL_INVALID_OPERATION
);
569 case AL_SOURCE_STATE
:
571 alSetError(AL_INVALID_OPERATION
);
575 case AL_SAMPLE_OFFSET
:
579 pSource
->lOffsetType
= eParam
;
581 // Store Offset (convert Seconds into Milliseconds)
582 if(eParam
== AL_SEC_OFFSET
)
583 pSource
->lOffset
= lValue
* 1000;
585 pSource
->lOffset
= lValue
;
587 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
588 ApplyOffset(pSource
, AL_TRUE
);
591 alSetError(AL_INVALID_VALUE
);
594 case AL_DIRECT_FILTER
:
595 if(alIsFilter(lValue
))
597 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
600 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
601 pSource
->DirectFilter
.filter
= 0;
604 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
607 alSetError(AL_INVALID_VALUE
);
610 case AL_DIRECT_FILTER_GAINHF_AUTO
:
611 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
612 pSource
->DryGainHFAuto
= lValue
;
614 alSetError(AL_INVALID_VALUE
);
617 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
618 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
619 pSource
->WetGainAuto
= lValue
;
621 alSetError(AL_INVALID_VALUE
);
624 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
625 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
626 pSource
->WetGainHFAuto
= lValue
;
628 alSetError(AL_INVALID_VALUE
);
631 case AL_DISTANCE_MODEL
:
632 if(lValue
== AL_NONE
||
633 lValue
== AL_INVERSE_DISTANCE
||
634 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
635 lValue
== AL_LINEAR_DISTANCE
||
636 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
637 lValue
== AL_EXPONENT_DISTANCE
||
638 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
639 pSource
->DistanceModel
= lValue
;
641 alSetError(AL_INVALID_VALUE
);
645 alSetError(AL_INVALID_ENUM
);
650 alSetError(AL_INVALID_NAME
);
652 ProcessContext(pContext
);
656 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
658 ALCcontext
*pContext
;
660 pContext
= GetContextSuspended();
661 if(!pContext
) return;
663 if(alIsSource(source
))
665 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
666 ALCdevice
*Device
= pContext
->Device
;
673 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
676 case AL_AUXILIARY_SEND_FILTER
:
677 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
678 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
681 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
682 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
684 /* Release refcount on the previous slot, and add one for
686 if(pSource
->Send
[lValue2
].Slot
)
687 pSource
->Send
[lValue2
].Slot
->refcount
--;
688 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
689 if(pSource
->Send
[lValue2
].Slot
)
690 pSource
->Send
[lValue2
].Slot
->refcount
++;
695 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
696 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
699 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
702 alSetError(AL_INVALID_VALUE
);
706 alSetError(AL_INVALID_ENUM
);
711 alSetError(AL_INVALID_NAME
);
713 ProcessContext(pContext
);
717 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
719 ALCcontext
*pContext
;
721 pContext
= GetContextSuspended();
722 if(!pContext
) return;
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 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
745 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
746 case AL_DISTANCE_MODEL
:
747 alSourcei(source
, eParam
, plValues
[0]);
753 case AL_AUXILIARY_SEND_FILTER
:
754 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
758 alSetError(AL_INVALID_ENUM
);
763 alSetError(AL_INVALID_NAME
);
766 alSetError(AL_INVALID_VALUE
);
768 ProcessContext(pContext
);
772 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
774 ALCcontext
*pContext
;
778 pContext
= GetContextSuspended();
779 if(!pContext
) return;
783 if(alIsSource(source
))
785 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
790 *pflValue
= pSource
->flPitch
;
794 *pflValue
= pSource
->flGain
;
798 *pflValue
= pSource
->flMinGain
;
802 *pflValue
= pSource
->flMaxGain
;
805 case AL_MAX_DISTANCE
:
806 *pflValue
= pSource
->flMaxDistance
;
809 case AL_ROLLOFF_FACTOR
:
810 *pflValue
= pSource
->flRollOffFactor
;
813 case AL_CONE_OUTER_GAIN
:
814 *pflValue
= pSource
->flOuterGain
;
817 case AL_CONE_OUTER_GAINHF
:
818 *pflValue
= pSource
->OuterGainHF
;
822 case AL_SAMPLE_OFFSET
:
824 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
825 *pflValue
= flOffset
[0];
827 alSetError(AL_INVALID_OPERATION
);
830 case AL_SEC_RW_OFFSETS_EXT
:
831 case AL_SAMPLE_RW_OFFSETS_EXT
:
832 case AL_BYTE_RW_OFFSETS_EXT
:
833 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
835 pflValue
[0] = flOffset
[0];
836 pflValue
[1] = flOffset
[1];
839 alSetError(AL_INVALID_OPERATION
);
842 case AL_CONE_INNER_ANGLE
:
843 *pflValue
= pSource
->flInnerAngle
;
846 case AL_CONE_OUTER_ANGLE
:
847 *pflValue
= pSource
->flOuterAngle
;
850 case AL_REFERENCE_DISTANCE
:
851 *pflValue
= pSource
->flRefDistance
;
854 case AL_AIR_ABSORPTION_FACTOR
:
855 *pflValue
= pSource
->AirAbsorptionFactor
;
858 case AL_ROOM_ROLLOFF_FACTOR
:
859 *pflValue
= pSource
->RoomRolloffFactor
;
862 case AL_DOPPLER_FACTOR
:
863 *pflValue
= pSource
->DopplerFactor
;
867 alSetError(AL_INVALID_ENUM
);
872 alSetError(AL_INVALID_NAME
);
875 alSetError(AL_INVALID_VALUE
);
877 ProcessContext(pContext
);
881 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
883 ALCcontext
*pContext
;
886 pContext
= GetContextSuspended();
887 if(!pContext
) return;
889 if(pflValue1
&& pflValue2
&& pflValue3
)
891 if(alIsSource(source
))
893 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
898 *pflValue1
= pSource
->vPosition
[0];
899 *pflValue2
= pSource
->vPosition
[1];
900 *pflValue3
= pSource
->vPosition
[2];
904 *pflValue1
= pSource
->vVelocity
[0];
905 *pflValue2
= pSource
->vVelocity
[1];
906 *pflValue3
= pSource
->vVelocity
[2];
910 *pflValue1
= pSource
->vOrientation
[0];
911 *pflValue2
= pSource
->vOrientation
[1];
912 *pflValue3
= pSource
->vOrientation
[2];
916 alSetError(AL_INVALID_ENUM
);
921 alSetError(AL_INVALID_NAME
);
924 alSetError(AL_INVALID_VALUE
);
926 ProcessContext(pContext
);
930 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
932 ALCcontext
*pContext
;
935 pContext
= GetContextSuspended();
936 if(!pContext
) return;
940 if(alIsSource(source
))
942 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
950 case AL_MAX_DISTANCE
:
951 case AL_ROLLOFF_FACTOR
:
952 case AL_DOPPLER_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 case AL_AIR_ABSORPTION_FACTOR
:
962 case AL_ROOM_ROLLOFF_FACTOR
:
963 alGetSourcef(source
, eParam
, pflValues
);
967 pflValues
[0] = pSource
->vPosition
[0];
968 pflValues
[1] = pSource
->vPosition
[1];
969 pflValues
[2] = pSource
->vPosition
[2];
973 pflValues
[0] = pSource
->vVelocity
[0];
974 pflValues
[1] = pSource
->vVelocity
[1];
975 pflValues
[2] = pSource
->vVelocity
[2];
979 pflValues
[0] = pSource
->vOrientation
[0];
980 pflValues
[1] = pSource
->vOrientation
[1];
981 pflValues
[2] = pSource
->vOrientation
[2];
985 alSetError(AL_INVALID_ENUM
);
990 alSetError(AL_INVALID_NAME
);
993 alSetError(AL_INVALID_VALUE
);
995 ProcessContext(pContext
);
999 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1001 ALCcontext
*pContext
;
1003 ALfloat flOffset
[2];
1005 pContext
= GetContextSuspended();
1006 if(!pContext
) return;
1010 if(alIsSource(source
))
1012 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1016 case AL_MAX_DISTANCE
:
1017 *plValue
= (ALint
)pSource
->flMaxDistance
;
1020 case AL_ROLLOFF_FACTOR
:
1021 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1024 case AL_REFERENCE_DISTANCE
:
1025 *plValue
= (ALint
)pSource
->flRefDistance
;
1028 case AL_SOURCE_RELATIVE
:
1029 *plValue
= pSource
->bHeadRelative
;
1032 case AL_CONE_INNER_ANGLE
:
1033 *plValue
= (ALint
)pSource
->flInnerAngle
;
1036 case AL_CONE_OUTER_ANGLE
:
1037 *plValue
= (ALint
)pSource
->flOuterAngle
;
1041 *plValue
= pSource
->bLooping
;
1045 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1048 case AL_SOURCE_STATE
:
1049 *plValue
= pSource
->state
;
1052 case AL_BUFFERS_QUEUED
:
1053 *plValue
= pSource
->BuffersInQueue
;
1056 case AL_BUFFERS_PROCESSED
:
1057 if(pSource
->bLooping
)
1059 /* Buffers on a looping source are in a perpetual state
1060 * of PENDING, so don't report any as PROCESSED */
1064 *plValue
= pSource
->BuffersPlayed
;
1067 case AL_SOURCE_TYPE
:
1068 *plValue
= pSource
->lSourceType
;
1072 case AL_SAMPLE_OFFSET
:
1073 case AL_BYTE_OFFSET
:
1074 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1075 *plValue
= (ALint
)flOffset
[0];
1077 alSetError(AL_INVALID_OPERATION
);
1080 case AL_SEC_RW_OFFSETS_EXT
:
1081 case AL_SAMPLE_RW_OFFSETS_EXT
:
1082 case AL_BYTE_RW_OFFSETS_EXT
:
1083 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1085 plValue
[0] = (ALint
)flOffset
[0];
1086 plValue
[1] = (ALint
)flOffset
[1];
1089 alSetError(AL_INVALID_OPERATION
);
1092 case AL_DIRECT_FILTER
:
1093 *plValue
= pSource
->DirectFilter
.filter
;
1096 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1097 *plValue
= pSource
->DryGainHFAuto
;
1100 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1101 *plValue
= pSource
->WetGainAuto
;
1104 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1105 *plValue
= pSource
->WetGainHFAuto
;
1108 case AL_DOPPLER_FACTOR
:
1109 *plValue
= (ALint
)pSource
->DopplerFactor
;
1112 case AL_DISTANCE_MODEL
:
1113 *plValue
= pSource
->DistanceModel
;
1117 alSetError(AL_INVALID_ENUM
);
1122 alSetError(AL_INVALID_NAME
);
1125 alSetError(AL_INVALID_VALUE
);
1127 ProcessContext(pContext
);
1131 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1133 ALCcontext
*pContext
;
1136 pContext
= GetContextSuspended();
1137 if(!pContext
) return;
1139 if(plValue1
&& plValue2
&& plValue3
)
1141 if(alIsSource(source
))
1143 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1148 *plValue1
= (ALint
)pSource
->vPosition
[0];
1149 *plValue2
= (ALint
)pSource
->vPosition
[1];
1150 *plValue3
= (ALint
)pSource
->vPosition
[2];
1154 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1155 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1156 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1160 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1161 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1162 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1166 alSetError(AL_INVALID_ENUM
);
1171 alSetError(AL_INVALID_NAME
);
1174 alSetError(AL_INVALID_VALUE
);
1176 ProcessContext(pContext
);
1180 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1182 ALCcontext
*pContext
;
1185 pContext
= GetContextSuspended();
1186 if(!pContext
) return;
1190 if(alIsSource(source
))
1192 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1196 case AL_SOURCE_RELATIVE
:
1197 case AL_CONE_INNER_ANGLE
:
1198 case AL_CONE_OUTER_ANGLE
:
1201 case AL_SOURCE_STATE
:
1202 case AL_BUFFERS_QUEUED
:
1203 case AL_BUFFERS_PROCESSED
:
1205 case AL_SAMPLE_OFFSET
:
1206 case AL_BYTE_OFFSET
:
1207 case AL_MAX_DISTANCE
:
1208 case AL_ROLLOFF_FACTOR
:
1209 case AL_DOPPLER_FACTOR
:
1210 case AL_REFERENCE_DISTANCE
:
1211 case AL_SOURCE_TYPE
:
1212 case AL_DIRECT_FILTER
:
1213 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1214 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1215 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1216 case AL_DISTANCE_MODEL
:
1217 alGetSourcei(source
, eParam
, plValues
);
1221 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1222 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1223 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1227 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1228 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1229 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1233 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1234 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1235 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1239 alSetError(AL_INVALID_ENUM
);
1244 alSetError(AL_INVALID_NAME
);
1247 alSetError(AL_INVALID_VALUE
);
1249 ProcessContext(pContext
);
1253 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1255 alSourcePlayv(1, &source
);
1259 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1261 ALCcontext
*pContext
;
1263 ALbufferlistitem
*ALBufferList
;
1264 ALboolean bSourcesValid
= AL_TRUE
;
1268 pContext
= GetContextSuspended();
1269 if(!pContext
) return;
1273 // Check that all the Sources are valid
1274 for(i
= 0; i
< n
; i
++)
1276 if(!alIsSource(pSourceList
[i
]))
1278 alSetError(AL_INVALID_NAME
);
1279 bSourcesValid
= AL_FALSE
;
1286 for(i
= 0; i
< n
; i
++)
1288 // Assume Source won't need to play
1291 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1293 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1294 ALBufferList
= pSource
->queue
;
1297 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1302 ALBufferList
= ALBufferList
->next
;
1307 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1308 pSource
->DryGains
[j
] = 0.0f
;
1309 for(j
= 0;j
< MAX_SENDS
;j
++)
1310 pSource
->WetGains
[j
] = 0.0f
;
1312 if(pSource
->state
!= AL_PAUSED
)
1314 pSource
->state
= AL_PLAYING
;
1315 pSource
->position
= 0;
1316 pSource
->position_fraction
= 0;
1317 pSource
->BuffersPlayed
= 0;
1319 pSource
->Buffer
= pSource
->queue
->buffer
;
1322 pSource
->state
= AL_PLAYING
;
1324 // Check if an Offset has been set
1325 if(pSource
->lOffset
)
1326 ApplyOffset(pSource
, AL_FALSE
);
1328 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1329 pSource
->position_fraction
== 0)
1330 pSource
->FirstStart
= AL_TRUE
;
1332 pSource
->FirstStart
= AL_FALSE
;
1334 // If device is disconnected, go right to stopped
1335 if(!pContext
->Device
->Connected
)
1337 pSource
->state
= AL_STOPPED
;
1338 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1339 pSource
->position
= 0;
1340 pSource
->position_fraction
= 0;
1344 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1350 // sources is a NULL pointer
1351 alSetError(AL_INVALID_VALUE
);
1354 ProcessContext(pContext
);
1357 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1359 alSourcePausev(1, &source
);
1363 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1365 ALCcontext
*Context
;
1368 ALboolean bSourcesValid
= AL_TRUE
;
1370 Context
= GetContextSuspended();
1371 if(!Context
) return;
1375 // Check all the Sources are valid
1378 if(!alIsSource(sources
[i
]))
1380 alSetError(AL_INVALID_NAME
);
1381 bSourcesValid
= AL_FALSE
;
1388 for(i
= 0;i
< n
;i
++)
1390 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1391 if(Source
->state
== AL_PLAYING
)
1392 Source
->state
= AL_PAUSED
;
1398 // sources is a NULL pointer
1399 alSetError(AL_INVALID_VALUE
);
1402 ProcessContext(Context
);
1405 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1407 alSourceStopv(1, &source
);
1411 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1413 ALCcontext
*Context
;
1416 ALboolean bSourcesValid
= AL_TRUE
;
1418 Context
= GetContextSuspended();
1419 if(!Context
) return;
1423 // Check all the Sources are valid
1424 for(i
= 0;i
< n
;i
++)
1426 if(!alIsSource(sources
[i
]))
1428 alSetError(AL_INVALID_NAME
);
1429 bSourcesValid
= AL_FALSE
;
1436 for(i
= 0;i
< n
;i
++)
1438 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1439 if(Source
->state
!= AL_INITIAL
)
1441 Source
->state
= AL_STOPPED
;
1442 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1444 Source
->lOffset
= 0;
1450 // sources is a NULL pointer
1451 alSetError(AL_INVALID_VALUE
);
1454 ProcessContext(Context
);
1457 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1459 alSourceRewindv(1, &source
);
1463 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1465 ALCcontext
*Context
;
1468 ALboolean bSourcesValid
= AL_TRUE
;
1470 Context
= GetContextSuspended();
1471 if(!Context
) return;
1475 // Check all the Sources are valid
1476 for(i
= 0;i
< n
;i
++)
1478 if(!alIsSource(sources
[i
]))
1480 alSetError(AL_INVALID_NAME
);
1481 bSourcesValid
= AL_FALSE
;
1488 for(i
= 0;i
< n
;i
++)
1490 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1491 if(Source
->state
!= AL_INITIAL
)
1493 Source
->state
= AL_INITIAL
;
1494 Source
->position
= 0;
1495 Source
->position_fraction
= 0;
1496 Source
->BuffersPlayed
= 0;
1498 Source
->Buffer
= Source
->queue
->buffer
;
1500 Source
->lOffset
= 0;
1506 // sources is a NULL pointer
1507 alSetError(AL_INVALID_VALUE
);
1510 ProcessContext(Context
);
1514 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1516 ALCcontext
*Context
;
1519 ALbufferlistitem
*ALBufferList
;
1520 ALbufferlistitem
*ALBufferListStart
;
1523 ALboolean bBuffersValid
= AL_TRUE
;
1528 Context
= GetContextSuspended();
1529 if(!Context
) return;
1531 // Check that all buffers are valid or zero and that the source is valid
1533 // Check that this is a valid source
1534 if(alIsSource(source
))
1536 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1538 // Check that this is not a STATIC Source
1539 if(ALSource
->lSourceType
!= AL_STATIC
)
1544 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1545 ALBufferList
= ALSource
->queue
;
1548 if (ALBufferList
->buffer
)
1550 iFrequency
= ALBufferList
->buffer
->frequency
;
1551 iFormat
= ALBufferList
->buffer
->format
;
1554 ALBufferList
= ALBufferList
->next
;
1557 for(i
= 0; i
< n
; i
++)
1561 if(!alIsBuffer(buffers
[i
]))
1563 alSetError(AL_INVALID_NAME
);
1564 bBuffersValid
= AL_FALSE
;
1570 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1571 if(iFrequency
== -1 && iFormat
== -1)
1573 iFrequency
= buffer
->frequency
;
1574 iFormat
= buffer
->format
;
1576 else if(iFrequency
!= buffer
->frequency
||
1577 iFormat
!= buffer
->format
)
1579 alSetError(AL_INVALID_OPERATION
);
1580 bBuffersValid
= AL_FALSE
;
1587 ALbuffer
*buffer
= NULL
;
1589 // Change Source Type
1590 ALSource
->lSourceType
= AL_STREAMING
;
1592 ALSource
->Format
= iFormat
;
1593 ALSource
->Frequency
= iFrequency
;
1596 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1598 // All buffers are valid - so add them to the list
1599 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1600 ALBufferListStart
->buffer
= buffer
;
1601 ALBufferListStart
->next
= NULL
;
1603 // Increment reference counter for buffer
1604 if(buffer
) buffer
->refcount
++;
1606 ALBufferList
= ALBufferListStart
;
1608 for(i
= 1; i
< n
; i
++)
1611 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1613 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1614 ALBufferList
->next
->buffer
= buffer
;
1615 ALBufferList
->next
->next
= NULL
;
1617 // Increment reference counter for buffer
1618 if(buffer
) buffer
->refcount
++;
1620 ALBufferList
= ALBufferList
->next
;
1623 if(ALSource
->queue
== NULL
)
1625 ALSource
->queue
= ALBufferListStart
;
1626 // Update Current Buffer
1627 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1631 // Find end of queue
1632 ALBufferList
= ALSource
->queue
;
1633 while(ALBufferList
->next
!= NULL
)
1634 ALBufferList
= ALBufferList
->next
;
1636 ALBufferList
->next
= ALBufferListStart
;
1639 // Update number of buffers in queue
1640 ALSource
->BuffersInQueue
+= n
;
1645 // Invalid Source Type (can't queue on a Static Source)
1646 alSetError(AL_INVALID_OPERATION
);
1651 // Invalid Source Name
1652 alSetError(AL_INVALID_NAME
);
1655 ProcessContext(Context
);
1659 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1660 // an array of buffer IDs that are to be filled with the names of the buffers removed
1661 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1663 ALCcontext
*Context
;
1666 ALbufferlistitem
*ALBufferList
;
1667 ALboolean bBuffersProcessed
;
1672 bBuffersProcessed
= AL_TRUE
;
1674 Context
= GetContextSuspended();
1675 if(!Context
) return;
1677 if(alIsSource(source
))
1679 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1681 // If all 'n' buffers have been processed, remove them from the queue
1682 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1684 for(i
= 0; i
< n
; i
++)
1686 ALBufferList
= ALSource
->queue
;
1688 ALSource
->queue
= ALBufferList
->next
;
1689 // Record name of buffer
1690 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1691 // Decrement buffer reference counter
1692 if(ALBufferList
->buffer
)
1693 ALBufferList
->buffer
->refcount
--;
1695 // Release memory for buffer list item
1697 ALSource
->BuffersInQueue
--;
1700 if(ALSource
->state
!= AL_PLAYING
)
1703 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1705 ALSource
->Buffer
= NULL
;
1708 ALSource
->BuffersPlayed
-= n
;
1712 // Some buffers can't be unqueue because they have not been processed
1713 alSetError(AL_INVALID_VALUE
);
1718 // Invalid Source Name
1719 alSetError(AL_INVALID_NAME
);
1722 ProcessContext(Context
);
1726 static ALvoid
InitSourceParams(ALCcontext
*Context
, ALsource
*pSource
)
1728 pSource
->flInnerAngle
= 360.0f
;
1729 pSource
->flOuterAngle
= 360.0f
;
1730 pSource
->flPitch
= 1.0f
;
1731 pSource
->vPosition
[0] = 0.0f
;
1732 pSource
->vPosition
[1] = 0.0f
;
1733 pSource
->vPosition
[2] = 0.0f
;
1734 pSource
->vOrientation
[0] = 0.0f
;
1735 pSource
->vOrientation
[1] = 0.0f
;
1736 pSource
->vOrientation
[2] = 0.0f
;
1737 pSource
->vVelocity
[0] = 0.0f
;
1738 pSource
->vVelocity
[1] = 0.0f
;
1739 pSource
->vVelocity
[2] = 0.0f
;
1740 pSource
->flRefDistance
= 1.0f
;
1741 pSource
->flMaxDistance
= FLT_MAX
;
1742 pSource
->flRollOffFactor
= 1.0f
;
1743 pSource
->bLooping
= AL_FALSE
;
1744 pSource
->flGain
= 1.0f
;
1745 pSource
->flMinGain
= 0.0f
;
1746 pSource
->flMaxGain
= 1.0f
;
1747 pSource
->flOuterGain
= 0.0f
;
1748 pSource
->OuterGainHF
= 1.0f
;
1750 pSource
->DryGainHFAuto
= AL_TRUE
;
1751 pSource
->WetGainAuto
= AL_TRUE
;
1752 pSource
->WetGainHFAuto
= AL_TRUE
;
1753 pSource
->AirAbsorptionFactor
= 0.0f
;
1754 pSource
->RoomRolloffFactor
= 0.0f
;
1755 pSource
->DopplerFactor
= 1.0f
;
1757 pSource
->DistanceModel
= Context
->DistanceModel
;
1759 pSource
->state
= AL_INITIAL
;
1760 pSource
->lSourceType
= AL_UNDETERMINED
;
1762 pSource
->Buffer
= NULL
;
1769 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1770 The offset is relative to the start of the queue (not the start of the current buffer)
1772 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1774 ALbufferlistitem
*pBufferList
;
1776 ALfloat flBufferFreq
;
1778 ALint readPos
, writePos
;
1779 ALenum eOriginalFormat
;
1780 ALboolean bReturn
= AL_TRUE
;
1781 ALint lTotalBufferDataSize
;
1784 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1786 pBuffer
= pSource
->Buffer
;
1787 // Get Current Buffer Size and frequency (in milliseconds)
1788 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1789 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1790 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1792 // Get Current BytesPlayed
1793 readPos
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1794 // Add byte length of any processed buffers in the queue
1795 pBufferList
= pSource
->queue
;
1796 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1798 readPos
+= pBufferList
->buffer
->size
;
1799 pBufferList
= pBufferList
->next
;
1802 if(pSource
->state
== AL_PLAYING
)
1803 writePos
= readPos
+ (updateSize
* lChannels
* 2);
1807 lTotalBufferDataSize
= 0;
1808 pBufferList
= pSource
->queue
;
1811 if (pBufferList
->buffer
)
1812 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1813 pBufferList
= pBufferList
->next
;
1816 if (pSource
->bLooping
)
1821 readPos
%= lTotalBufferDataSize
;
1825 writePos
%= lTotalBufferDataSize
;
1829 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1832 else if(readPos
> lTotalBufferDataSize
)
1833 readPos
= lTotalBufferDataSize
;
1836 else if(writePos
> lTotalBufferDataSize
)
1837 writePos
= lTotalBufferDataSize
;
1843 case AL_SEC_RW_OFFSETS_EXT
:
1844 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* 2.0f
* flBufferFreq
);
1845 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* 2.0f
* flBufferFreq
);
1847 case AL_SAMPLE_OFFSET
:
1848 case AL_SAMPLE_RW_OFFSETS_EXT
:
1849 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* 2));
1850 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* 2));
1852 case AL_BYTE_OFFSET
:
1853 case AL_BYTE_RW_OFFSETS_EXT
:
1854 // Take into account the original format of the Buffer
1855 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1856 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1858 // Round down to nearest ADPCM block
1859 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * 2 * lChannels
)) * 36 * lChannels
);
1860 if(pSource
->state
== AL_PLAYING
)
1862 // Round up to nearest ADPCM block
1863 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * 2 * lChannels
) - 1) / (65 * 2 * lChannels
)) * 36 * lChannels
);
1866 pflOffset
[1] = pflOffset
[0];
1868 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1870 pflOffset
[0] = (ALfloat
)(readPos
>> 2);
1871 pflOffset
[1] = (ALfloat
)(writePos
>> 2);
1873 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1875 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1876 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1878 else if (aluBytesFromFormat(eOriginalFormat
) == 1)
1880 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1881 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1883 else if (aluBytesFromFormat(eOriginalFormat
) == 4)
1885 pflOffset
[0] = (ALfloat
)(readPos
<< 1);
1886 pflOffset
[1] = (ALfloat
)(writePos
<< 1);
1890 pflOffset
[0] = (ALfloat
)readPos
;
1891 pflOffset
[1] = (ALfloat
)writePos
;
1898 pflOffset
[0] = 0.0f
;
1899 pflOffset
[1] = 0.0f
;
1909 Apply a playback offset to the Source. This function will update the queue (to correctly
1910 mark buffers as 'pending' or 'processed' depending upon the new offset.
1912 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1914 ALbufferlistitem
*pBufferList
;
1916 ALint lBufferSize
, lTotalBufferSize
;
1919 // Get true byte offset
1920 lByteOffset
= GetByteOffset(pSource
);
1922 // If this is a valid offset apply it
1923 if (lByteOffset
!= -1)
1925 // Sort out the queue (pending and processed states)
1926 pBufferList
= pSource
->queue
;
1927 lTotalBufferSize
= 0;
1928 pSource
->BuffersPlayed
= 0;
1931 pBuffer
= pBufferList
->buffer
;
1932 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
1934 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
1936 // Offset is past this buffer so increment BuffersPlayed
1937 pSource
->BuffersPlayed
++;
1939 else if (lTotalBufferSize
<= lByteOffset
)
1941 // Offset is within this buffer
1942 // Set Current Buffer
1943 pSource
->Buffer
= pBufferList
->buffer
;
1945 // SW Mixer Positions are in Samples
1946 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
1947 aluBytesFromFormat(pBuffer
->format
) /
1948 aluChannelsFromFormat(pBuffer
->format
);
1951 // Increment the TotalBufferSize
1952 lTotalBufferSize
+= lBufferSize
;
1954 // Move on to next buffer in the Queue
1955 pBufferList
= pBufferList
->next
;
1961 alSetError(AL_INVALID_VALUE
);
1965 pSource
->lOffset
= 0;
1972 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1973 offset supplied by the application). This takes into account the fact that the buffer format
1974 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
1976 static ALint
GetByteOffset(ALsource
*pSource
)
1978 ALbuffer
*pBuffer
= NULL
;
1979 ALbufferlistitem
*pBufferList
;
1980 ALfloat flBufferFreq
;
1982 ALint lByteOffset
= -1;
1983 ALint lTotalBufferDataSize
;
1985 // Find the first non-NULL Buffer in the Queue
1986 pBufferList
= pSource
->queue
;
1989 if (pBufferList
->buffer
)
1991 pBuffer
= pBufferList
->buffer
;
1994 pBufferList
= pBufferList
->next
;
1999 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2000 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2002 // Determine the ByteOffset (and ensure it is block aligned)
2003 switch (pSource
->lOffsetType
)
2005 case AL_BYTE_OFFSET
:
2006 // Take into consideration the original format
2007 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
2008 (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2010 // Round down to nearest ADPCM block
2011 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2012 // Multiply by compression rate
2013 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2014 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2016 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR8
)
2018 lByteOffset
= pSource
->lOffset
* 4;
2019 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2021 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR16
)
2023 lByteOffset
= pSource
->lOffset
* 2;
2024 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2026 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 1)
2028 lByteOffset
= pSource
->lOffset
* 2;
2029 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2031 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 4)
2033 lByteOffset
= pSource
->lOffset
/ 2;
2034 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2038 lByteOffset
= pSource
->lOffset
;
2039 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2043 case AL_SAMPLE_OFFSET
:
2044 lByteOffset
= pSource
->lOffset
* lChannels
* 2;
2048 // Note - lOffset is internally stored as Milliseconds
2049 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* 2.0f
* flBufferFreq
/ 1000.0f
);
2050 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2054 lTotalBufferDataSize
= 0;
2055 pBufferList
= pSource
->queue
;
2058 if (pBufferList
->buffer
)
2059 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2060 pBufferList
= pBufferList
->next
;
2063 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2064 if (lByteOffset
>= lTotalBufferDataSize
)
2072 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2076 while(Context
->Source
)
2078 ALsource
*temp
= Context
->Source
;
2079 Context
->Source
= temp
->next
;
2081 // For each buffer in the source's queue, decrement its reference counter and remove it
2082 while(temp
->queue
!= NULL
)
2084 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2085 // Decrement buffer's reference counter
2086 if(ALBufferList
->buffer
!= NULL
)
2087 ALBufferList
->buffer
->refcount
--;
2088 // Update queue to point to next element in list
2089 temp
->queue
= ALBufferList
->next
;
2090 // Release memory allocated for buffer list item
2094 for(j
= 0;j
< MAX_SENDS
;++j
)
2096 if(temp
->Send
[j
].Slot
)
2097 temp
->Send
[j
].Slot
->refcount
--;
2100 // Release source structure
2101 ALTHUNK_REMOVEENTRY(temp
->source
);
2102 memset(temp
, 0, sizeof(ALsource
));
2105 Context
->SourceCount
= 0;