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
!= 0)
146 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(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
;
467 pContext
= GetContextSuspended();
468 if(!pContext
) return;
470 if(alIsSource(source
))
472 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
476 case AL_MAX_DISTANCE
:
477 case AL_ROLLOFF_FACTOR
:
478 case AL_REFERENCE_DISTANCE
:
479 alSourcef(source
, eParam
, (ALfloat
)lValue
);
482 case AL_SOURCE_RELATIVE
:
483 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
484 pSource
->bHeadRelative
= (ALboolean
)lValue
;
486 alSetError(AL_INVALID_VALUE
);
489 case AL_CONE_INNER_ANGLE
:
490 if(lValue
>= 0 && lValue
<= 360)
491 pSource
->flInnerAngle
= (float)lValue
;
493 alSetError(AL_INVALID_VALUE
);
496 case AL_CONE_OUTER_ANGLE
:
497 if(lValue
>= 0 && lValue
<= 360)
498 pSource
->flOuterAngle
= (float)lValue
;
500 alSetError(AL_INVALID_VALUE
);
504 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
506 pSource
->bLooping
= (ALboolean
)lValue
;
508 pALBufferListItem
= pSource
->queue
;
509 for(i
= 0;pALBufferListItem
!= NULL
;i
++)
511 if(lValue
== AL_FALSE
&& i
<= pSource
->BuffersPlayed
)
512 pALBufferListItem
->bufferstate
= PROCESSED
;
514 pALBufferListItem
->bufferstate
= PENDING
;
515 pALBufferListItem
= pALBufferListItem
->next
;
519 alSetError(AL_INVALID_VALUE
);
523 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
525 if(alIsBuffer(lValue
))
527 // Remove all elements in the queue
528 while(pSource
->queue
!= NULL
)
530 pALBufferListItem
= pSource
->queue
;
531 pSource
->queue
= pALBufferListItem
->next
;
532 // Decrement reference counter for buffer
533 if (pALBufferListItem
->buffer
)
534 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem
->buffer
)))->refcount
--;
535 // Release memory for buffer list item
536 free(pALBufferListItem
);
537 // Decrement the number of buffers in the queue
538 pSource
->BuffersInQueue
--;
541 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
544 // Source is now in STATIC mode
545 pSource
->lSourceType
= AL_STATIC
;
547 // Add the selected buffer to the queue
548 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
549 pALBufferListItem
->buffer
= lValue
;
550 pALBufferListItem
->bufferstate
= PENDING
;
551 pALBufferListItem
->flag
= 0;
552 pALBufferListItem
->next
= NULL
;
554 pSource
->queue
= pALBufferListItem
;
555 pSource
->BuffersInQueue
= 1;
557 // Increment reference counter for buffer
558 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(lValue
)))->refcount
++;
562 // Source is now in UNDETERMINED mode
563 pSource
->lSourceType
= AL_UNDETERMINED
;
564 pSource
->BuffersPlayed
= 0;
567 // Update AL_BUFFER parameter
568 pSource
->ulBufferID
= lValue
;
571 alSetError(AL_INVALID_VALUE
);
574 alSetError(AL_INVALID_OPERATION
);
577 case AL_SOURCE_STATE
:
579 alSetError(AL_INVALID_OPERATION
);
583 case AL_SAMPLE_OFFSET
:
587 pSource
->lOffsetType
= eParam
;
589 // Store Offset (convert Seconds into Milliseconds)
590 if(eParam
== AL_SEC_OFFSET
)
591 pSource
->lOffset
= lValue
* 1000;
593 pSource
->lOffset
= lValue
;
595 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
596 ApplyOffset(pSource
, AL_TRUE
);
599 alSetError(AL_INVALID_VALUE
);
602 case AL_DIRECT_FILTER
:
603 if(alIsFilter(lValue
))
605 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
608 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
609 pSource
->DirectFilter
.filter
= 0;
612 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
615 alSetError(AL_INVALID_VALUE
);
618 case AL_DIRECT_FILTER_GAINHF_AUTO
:
619 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
620 pSource
->DryGainHFAuto
= lValue
;
622 alSetError(AL_INVALID_VALUE
);
625 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
626 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
627 pSource
->WetGainAuto
= lValue
;
629 alSetError(AL_INVALID_VALUE
);
632 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
633 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
634 pSource
->WetGainHFAuto
= lValue
;
636 alSetError(AL_INVALID_VALUE
);
639 case AL_DISTANCE_MODEL
:
640 if(lValue
== AL_NONE
||
641 lValue
== AL_INVERSE_DISTANCE
||
642 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
643 lValue
== AL_LINEAR_DISTANCE
||
644 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
645 lValue
== AL_EXPONENT_DISTANCE
||
646 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
647 pSource
->DistanceModel
= lValue
;
649 alSetError(AL_INVALID_VALUE
);
653 alSetError(AL_INVALID_ENUM
);
658 alSetError(AL_INVALID_NAME
);
660 ProcessContext(pContext
);
664 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
666 ALCcontext
*pContext
;
668 pContext
= GetContextSuspended();
669 if(!pContext
) return;
671 if(alIsSource(source
))
673 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
680 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
683 case AL_AUXILIARY_SEND_FILTER
:
684 if(lValue2
>= 0 && lValue2
< MAX_SENDS
&&
685 (alIsAuxiliaryEffectSlot(lValue1
) || lValue1
== 0) &&
688 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
689 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
691 /* Release refcount on the previous slot, and add one for
693 if(pSource
->Send
[lValue2
].Slot
)
694 pSource
->Send
[lValue2
].Slot
->refcount
--;
695 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
696 if(pSource
->Send
[lValue2
].Slot
)
697 pSource
->Send
[lValue2
].Slot
->refcount
++;
702 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
703 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
706 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
709 alSetError(AL_INVALID_VALUE
);
713 alSetError(AL_INVALID_ENUM
);
718 alSetError(AL_INVALID_NAME
);
720 ProcessContext(pContext
);
724 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
726 ALCcontext
*pContext
;
728 pContext
= GetContextSuspended();
729 if(!pContext
) return;
733 if(alIsSource(source
))
737 case AL_SOURCE_RELATIVE
:
738 case AL_CONE_INNER_ANGLE
:
739 case AL_CONE_OUTER_ANGLE
:
742 case AL_SOURCE_STATE
:
744 case AL_SAMPLE_OFFSET
:
746 case AL_MAX_DISTANCE
:
747 case AL_ROLLOFF_FACTOR
:
748 case AL_REFERENCE_DISTANCE
:
749 case AL_DIRECT_FILTER
:
750 case AL_DIRECT_FILTER_GAINHF_AUTO
:
751 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
752 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
753 case AL_DISTANCE_MODEL
:
754 alSourcei(source
, eParam
, plValues
[0]);
760 case AL_AUXILIARY_SEND_FILTER
:
761 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
765 alSetError(AL_INVALID_ENUM
);
770 alSetError(AL_INVALID_NAME
);
773 alSetError(AL_INVALID_VALUE
);
775 ProcessContext(pContext
);
779 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
781 ALCcontext
*pContext
;
785 pContext
= GetContextSuspended();
786 if(!pContext
) return;
790 if(alIsSource(source
))
792 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
797 *pflValue
= pSource
->flPitch
;
801 *pflValue
= pSource
->flGain
;
805 *pflValue
= pSource
->flMinGain
;
809 *pflValue
= pSource
->flMaxGain
;
812 case AL_MAX_DISTANCE
:
813 *pflValue
= pSource
->flMaxDistance
;
816 case AL_ROLLOFF_FACTOR
:
817 *pflValue
= pSource
->flRollOffFactor
;
820 case AL_CONE_OUTER_GAIN
:
821 *pflValue
= pSource
->flOuterGain
;
824 case AL_CONE_OUTER_GAINHF
:
825 *pflValue
= pSource
->OuterGainHF
;
829 case AL_SAMPLE_OFFSET
:
831 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
832 *pflValue
= flOffset
[0];
834 alSetError(AL_INVALID_OPERATION
);
837 case AL_SEC_RW_OFFSETS_EXT
:
838 case AL_SAMPLE_RW_OFFSETS_EXT
:
839 case AL_BYTE_RW_OFFSETS_EXT
:
840 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
842 pflValue
[0] = flOffset
[0];
843 pflValue
[1] = flOffset
[1];
846 alSetError(AL_INVALID_OPERATION
);
849 case AL_CONE_INNER_ANGLE
:
850 *pflValue
= pSource
->flInnerAngle
;
853 case AL_CONE_OUTER_ANGLE
:
854 *pflValue
= pSource
->flOuterAngle
;
857 case AL_REFERENCE_DISTANCE
:
858 *pflValue
= pSource
->flRefDistance
;
861 case AL_AIR_ABSORPTION_FACTOR
:
862 *pflValue
= pSource
->AirAbsorptionFactor
;
865 case AL_ROOM_ROLLOFF_FACTOR
:
866 *pflValue
= pSource
->RoomRolloffFactor
;
869 case AL_DOPPLER_FACTOR
:
870 *pflValue
= pSource
->DopplerFactor
;
874 alSetError(AL_INVALID_ENUM
);
879 alSetError(AL_INVALID_NAME
);
882 alSetError(AL_INVALID_VALUE
);
884 ProcessContext(pContext
);
888 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
890 ALCcontext
*pContext
;
893 pContext
= GetContextSuspended();
894 if(!pContext
) return;
896 if(pflValue1
&& pflValue2
&& pflValue3
)
898 if(alIsSource(source
))
900 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
905 *pflValue1
= pSource
->vPosition
[0];
906 *pflValue2
= pSource
->vPosition
[1];
907 *pflValue3
= pSource
->vPosition
[2];
911 *pflValue1
= pSource
->vVelocity
[0];
912 *pflValue2
= pSource
->vVelocity
[1];
913 *pflValue3
= pSource
->vVelocity
[2];
917 *pflValue1
= pSource
->vOrientation
[0];
918 *pflValue2
= pSource
->vOrientation
[1];
919 *pflValue3
= pSource
->vOrientation
[2];
923 alSetError(AL_INVALID_ENUM
);
928 alSetError(AL_INVALID_NAME
);
931 alSetError(AL_INVALID_VALUE
);
933 ProcessContext(pContext
);
937 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
939 ALCcontext
*pContext
;
942 pContext
= GetContextSuspended();
943 if(!pContext
) return;
947 if(alIsSource(source
))
949 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
957 case AL_MAX_DISTANCE
:
958 case AL_ROLLOFF_FACTOR
:
959 case AL_DOPPLER_FACTOR
:
960 case AL_CONE_OUTER_GAIN
:
962 case AL_SAMPLE_OFFSET
:
964 case AL_CONE_INNER_ANGLE
:
965 case AL_CONE_OUTER_ANGLE
:
966 case AL_REFERENCE_DISTANCE
:
967 case AL_CONE_OUTER_GAINHF
:
968 case AL_AIR_ABSORPTION_FACTOR
:
969 case AL_ROOM_ROLLOFF_FACTOR
:
970 alGetSourcef(source
, eParam
, pflValues
);
974 pflValues
[0] = pSource
->vPosition
[0];
975 pflValues
[1] = pSource
->vPosition
[1];
976 pflValues
[2] = pSource
->vPosition
[2];
980 pflValues
[0] = pSource
->vVelocity
[0];
981 pflValues
[1] = pSource
->vVelocity
[1];
982 pflValues
[2] = pSource
->vVelocity
[2];
986 pflValues
[0] = pSource
->vOrientation
[0];
987 pflValues
[1] = pSource
->vOrientation
[1];
988 pflValues
[2] = pSource
->vOrientation
[2];
992 alSetError(AL_INVALID_ENUM
);
997 alSetError(AL_INVALID_NAME
);
1000 alSetError(AL_INVALID_VALUE
);
1002 ProcessContext(pContext
);
1006 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1008 ALCcontext
*pContext
;
1010 ALfloat flOffset
[2];
1012 pContext
= GetContextSuspended();
1013 if(!pContext
) return;
1017 if(alIsSource(source
))
1019 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1023 case AL_MAX_DISTANCE
:
1024 *plValue
= (ALint
)pSource
->flMaxDistance
;
1027 case AL_ROLLOFF_FACTOR
:
1028 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1031 case AL_REFERENCE_DISTANCE
:
1032 *plValue
= (ALint
)pSource
->flRefDistance
;
1035 case AL_SOURCE_RELATIVE
:
1036 *plValue
= pSource
->bHeadRelative
;
1039 case AL_CONE_INNER_ANGLE
:
1040 *plValue
= (ALint
)pSource
->flInnerAngle
;
1043 case AL_CONE_OUTER_ANGLE
:
1044 *plValue
= (ALint
)pSource
->flOuterAngle
;
1048 *plValue
= pSource
->bLooping
;
1052 *plValue
= pSource
->ulBufferID
;
1055 case AL_SOURCE_STATE
:
1056 *plValue
= pSource
->state
;
1059 case AL_BUFFERS_QUEUED
:
1060 *plValue
= pSource
->BuffersInQueue
;
1063 case AL_BUFFERS_PROCESSED
:
1064 if(pSource
->bLooping
)
1066 /* Buffers on a looping source are in a perpetual state
1067 * of PENDING, so don't report any as PROCESSED */
1071 *plValue
= pSource
->BuffersPlayed
;
1074 case AL_SOURCE_TYPE
:
1075 *plValue
= pSource
->lSourceType
;
1079 case AL_SAMPLE_OFFSET
:
1080 case AL_BYTE_OFFSET
:
1081 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1082 *plValue
= (ALint
)flOffset
[0];
1084 alSetError(AL_INVALID_OPERATION
);
1087 case AL_SEC_RW_OFFSETS_EXT
:
1088 case AL_SAMPLE_RW_OFFSETS_EXT
:
1089 case AL_BYTE_RW_OFFSETS_EXT
:
1090 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1092 plValue
[0] = (ALint
)flOffset
[0];
1093 plValue
[1] = (ALint
)flOffset
[1];
1096 alSetError(AL_INVALID_OPERATION
);
1099 case AL_DIRECT_FILTER
:
1100 *plValue
= pSource
->DirectFilter
.filter
;
1103 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1104 *plValue
= pSource
->DryGainHFAuto
;
1107 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1108 *plValue
= pSource
->WetGainAuto
;
1111 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1112 *plValue
= pSource
->WetGainHFAuto
;
1115 case AL_DOPPLER_FACTOR
:
1116 *plValue
= (ALint
)pSource
->DopplerFactor
;
1119 case AL_DISTANCE_MODEL
:
1120 *plValue
= pSource
->DistanceModel
;
1124 alSetError(AL_INVALID_ENUM
);
1129 alSetError(AL_INVALID_NAME
);
1132 alSetError(AL_INVALID_VALUE
);
1134 ProcessContext(pContext
);
1138 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1140 ALCcontext
*pContext
;
1143 pContext
= GetContextSuspended();
1144 if(!pContext
) return;
1146 if(plValue1
&& plValue2
&& plValue3
)
1148 if(alIsSource(source
))
1150 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1155 *plValue1
= (ALint
)pSource
->vPosition
[0];
1156 *plValue2
= (ALint
)pSource
->vPosition
[1];
1157 *plValue3
= (ALint
)pSource
->vPosition
[2];
1161 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1162 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1163 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1167 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1168 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1169 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1173 alSetError(AL_INVALID_ENUM
);
1178 alSetError(AL_INVALID_NAME
);
1181 alSetError(AL_INVALID_VALUE
);
1183 ProcessContext(pContext
);
1187 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1189 ALCcontext
*pContext
;
1192 pContext
= GetContextSuspended();
1193 if(!pContext
) return;
1197 if(alIsSource(source
))
1199 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1203 case AL_SOURCE_RELATIVE
:
1204 case AL_CONE_INNER_ANGLE
:
1205 case AL_CONE_OUTER_ANGLE
:
1208 case AL_SOURCE_STATE
:
1209 case AL_BUFFERS_QUEUED
:
1210 case AL_BUFFERS_PROCESSED
:
1212 case AL_SAMPLE_OFFSET
:
1213 case AL_BYTE_OFFSET
:
1214 case AL_MAX_DISTANCE
:
1215 case AL_ROLLOFF_FACTOR
:
1216 case AL_DOPPLER_FACTOR
:
1217 case AL_REFERENCE_DISTANCE
:
1218 case AL_SOURCE_TYPE
:
1219 case AL_DIRECT_FILTER
:
1220 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1221 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1222 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1223 case AL_DISTANCE_MODEL
:
1224 alGetSourcei(source
, eParam
, plValues
);
1228 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1229 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1230 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1234 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1235 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1236 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1240 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1241 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1242 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1246 alSetError(AL_INVALID_ENUM
);
1251 alSetError(AL_INVALID_NAME
);
1254 alSetError(AL_INVALID_VALUE
);
1256 ProcessContext(pContext
);
1260 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1262 alSourcePlayv(1, &source
);
1266 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1268 ALCcontext
*pContext
;
1270 ALbufferlistitem
*ALBufferList
;
1271 ALboolean bSourcesValid
= AL_TRUE
;
1275 pContext
= GetContextSuspended();
1276 if(!pContext
) return;
1280 // Check that all the Sources are valid
1281 for(i
= 0; i
< n
; i
++)
1283 if(!alIsSource(pSourceList
[i
]))
1285 alSetError(AL_INVALID_NAME
);
1286 bSourcesValid
= AL_FALSE
;
1293 for(i
= 0; i
< n
; i
++)
1295 // Assume Source won't need to play
1298 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1300 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1301 ALBufferList
= pSource
->queue
;
1304 if(ALBufferList
->buffer
!= 0 && ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
))->size
)
1309 ALBufferList
= ALBufferList
->next
;
1314 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1315 pSource
->DryGains
[j
] = 0.0f
;
1316 for(j
= 0;j
< MAX_SENDS
;j
++)
1317 pSource
->WetGains
[j
] = 0.0f
;
1319 if(pSource
->state
!= AL_PAUSED
)
1321 pSource
->state
= AL_PLAYING
;
1322 pSource
->inuse
= AL_TRUE
;
1323 pSource
->play
= AL_TRUE
;
1324 pSource
->position
= 0;
1325 pSource
->position_fraction
= 0;
1326 pSource
->BuffersPlayed
= 0;
1327 pSource
->FirstStart
= AL_TRUE
;
1329 pSource
->ulBufferID
= pSource
->queue
->buffer
;
1331 // Make sure all the Buffers in the queue are marked as PENDING
1332 ALBufferList
= pSource
->queue
;
1335 ALBufferList
->bufferstate
= PENDING
;
1336 ALBufferList
= ALBufferList
->next
;
1341 pSource
->state
= AL_PLAYING
;
1342 pSource
->inuse
= AL_TRUE
;
1343 pSource
->play
= AL_TRUE
;
1344 pSource
->FirstStart
= AL_FALSE
;
1347 // Check if an Offset has been set
1348 if(pSource
->lOffset
)
1349 ApplyOffset(pSource
, AL_FALSE
);
1353 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1354 ALBufferList
= pSource
->queue
;
1357 ALBufferList
->bufferstate
= PROCESSED
;
1358 ALBufferList
= ALBufferList
->next
;
1361 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1368 // sources is a NULL pointer
1369 alSetError(AL_INVALID_VALUE
);
1372 ProcessContext(pContext
);
1375 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1377 alSourcePausev(1, &source
);
1381 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1383 ALCcontext
*Context
;
1386 ALboolean bSourcesValid
= AL_TRUE
;
1388 Context
= GetContextSuspended();
1389 if(!Context
) return;
1393 // Check all the Sources are valid
1396 if(!alIsSource(sources
[i
]))
1398 alSetError(AL_INVALID_NAME
);
1399 bSourcesValid
= AL_FALSE
;
1406 for(i
= 0;i
< n
;i
++)
1408 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1409 if(Source
->state
== AL_PLAYING
)
1411 Source
->state
= AL_PAUSED
;
1412 Source
->inuse
= AL_FALSE
;
1419 // sources is a NULL pointer
1420 alSetError(AL_INVALID_VALUE
);
1423 ProcessContext(Context
);
1426 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1428 alSourceStopv(1, &source
);
1432 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1434 ALCcontext
*Context
;
1437 ALbufferlistitem
*ALBufferListItem
;
1438 ALboolean bSourcesValid
= AL_TRUE
;
1440 Context
= GetContextSuspended();
1441 if(!Context
) return;
1445 // Check all the Sources are valid
1446 for(i
= 0;i
< n
;i
++)
1448 if(!alIsSource(sources
[i
]))
1450 alSetError(AL_INVALID_NAME
);
1451 bSourcesValid
= AL_FALSE
;
1458 for(i
= 0;i
< n
;i
++)
1460 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1461 if(Source
->state
!= AL_INITIAL
)
1463 Source
->state
= AL_STOPPED
;
1464 Source
->inuse
= AL_FALSE
;
1465 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1466 ALBufferListItem
= Source
->queue
;
1467 while(ALBufferListItem
!= NULL
)
1469 ALBufferListItem
->bufferstate
= PROCESSED
;
1470 ALBufferListItem
= ALBufferListItem
->next
;
1473 Source
->lOffset
= 0;
1479 // sources is a NULL pointer
1480 alSetError(AL_INVALID_VALUE
);
1483 ProcessContext(Context
);
1486 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1488 alSourceRewindv(1, &source
);
1492 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1494 ALCcontext
*Context
;
1497 ALbufferlistitem
*ALBufferListItem
;
1498 ALboolean bSourcesValid
= AL_TRUE
;
1500 Context
= GetContextSuspended();
1501 if(!Context
) return;
1505 // Check all the Sources are valid
1506 for(i
= 0;i
< n
;i
++)
1508 if(!alIsSource(sources
[i
]))
1510 alSetError(AL_INVALID_NAME
);
1511 bSourcesValid
= AL_FALSE
;
1518 for(i
= 0;i
< n
;i
++)
1520 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1521 if(Source
->state
!= AL_INITIAL
)
1523 Source
->state
= AL_INITIAL
;
1524 Source
->inuse
= AL_FALSE
;
1525 Source
->position
= 0;
1526 Source
->position_fraction
= 0;
1527 Source
->BuffersPlayed
= 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
);
1551 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1553 ALCcontext
*Context
;
1556 ALbufferlistitem
*ALBufferList
;
1557 ALbufferlistitem
*ALBufferListStart
;
1560 ALboolean bBuffersValid
= AL_TRUE
;
1565 Context
= GetContextSuspended();
1566 if(!Context
) return;
1568 // Check that all buffers are valid or zero and that the source is valid
1570 // Check that this is a valid source
1571 if(alIsSource(source
))
1573 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1575 // Check that this is not a STATIC Source
1576 if(ALSource
->lSourceType
!= AL_STATIC
)
1581 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1582 ALBufferList
= ALSource
->queue
;
1585 if (ALBufferList
->buffer
)
1587 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->frequency
;
1588 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->format
;
1591 ALBufferList
= ALBufferList
->next
;
1594 for(i
= 0; i
< n
; i
++)
1596 if(alIsBuffer(buffers
[i
]))
1600 if((iFrequency
== -1) && (iFormat
== -1))
1602 iFrequency
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
;
1603 iFormat
= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
;
1607 if((iFrequency
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->frequency
) ||
1608 (iFormat
!= ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->format
))
1610 alSetError(AL_INVALID_OPERATION
);
1611 bBuffersValid
= AL_FALSE
;
1619 alSetError(AL_INVALID_NAME
);
1620 bBuffersValid
= AL_FALSE
;
1627 // Change Source Type
1628 ALSource
->lSourceType
= AL_STREAMING
;
1630 // All buffers are valid - so add them to the list
1631 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1632 ALBufferListStart
->buffer
= buffers
[0];
1633 ALBufferListStart
->bufferstate
= PENDING
;
1634 ALBufferListStart
->flag
= 0;
1635 ALBufferListStart
->next
= NULL
;
1637 // Increment reference counter for buffer
1639 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[0])))->refcount
++;
1641 ALBufferList
= ALBufferListStart
;
1643 for(i
= 1; i
< n
; i
++)
1645 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1646 ALBufferList
->next
->buffer
= buffers
[i
];
1647 ALBufferList
->next
->bufferstate
= PENDING
;
1648 ALBufferList
->next
->flag
= 0;
1649 ALBufferList
->next
->next
= NULL
;
1651 // Increment reference counter for buffer
1653 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(buffers
[i
])))->refcount
++;
1655 ALBufferList
= ALBufferList
->next
;
1658 if(ALSource
->queue
== NULL
)
1660 ALSource
->queue
= ALBufferListStart
;
1661 // Update Current Buffer
1662 ALSource
->ulBufferID
= ALBufferListStart
->buffer
;
1666 // Find end of queue
1667 ALBufferList
= ALSource
->queue
;
1668 while(ALBufferList
->next
!= NULL
)
1669 ALBufferList
= ALBufferList
->next
;
1671 ALBufferList
->next
= ALBufferListStart
;
1674 // Update number of buffers in queue
1675 ALSource
->BuffersInQueue
+= n
;
1680 // Invalid Source Type (can't queue on a Static Source)
1681 alSetError(AL_INVALID_OPERATION
);
1686 // Invalid Source Name
1687 alSetError(AL_INVALID_NAME
);
1690 ProcessContext(Context
);
1694 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1695 // an array of buffer IDs that are to be filled with the names of the buffers removed
1696 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1698 ALCcontext
*Context
;
1701 ALbufferlistitem
*ALBufferList
;
1703 ALboolean bBuffersProcessed
;
1708 bBuffersProcessed
= AL_TRUE
;
1710 Context
= GetContextSuspended();
1711 if(!Context
) return;
1713 if(alIsSource(source
))
1715 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1717 // Check that all 'n' buffers have been processed
1718 ALBufferList
= ALSource
->queue
;
1719 for(i
= 0; i
< n
; i
++)
1721 if(ALBufferList
!= NULL
&& ALBufferList
->bufferstate
== PROCESSED
)
1723 ALBufferList
= ALBufferList
->next
;
1727 bBuffersProcessed
= AL_FALSE
;
1732 // If all 'n' buffers have been processed, remove them from the queue
1733 if(bBuffersProcessed
)
1735 for(i
= 0; i
< n
; i
++)
1737 ALBufferList
= ALSource
->queue
;
1739 ALSource
->queue
= ALBufferList
->next
;
1740 // Record name of buffer
1741 buffers
[i
] = ALBufferList
->buffer
;
1742 // Decrement buffer reference counter
1743 if(ALBufferList
->buffer
)
1744 ((ALbuffer
*)(ALTHUNK_LOOKUPENTRY(ALBufferList
->buffer
)))->refcount
--;
1746 // Release memory for buffer list item
1748 ALSource
->BuffersInQueue
--;
1751 if(ALSource
->state
!= AL_PLAYING
)
1753 if (ALSource
->queue
)
1754 BufferID
= ALSource
->queue
->buffer
;
1758 ALSource
->ulBufferID
= BufferID
;
1761 if((ALuint
)n
> ALSource
->BuffersPlayed
)
1762 ALSource
->BuffersPlayed
= 0;
1764 ALSource
->BuffersPlayed
-= n
;
1768 // Some buffers can't be unqueue because they have not been processed
1769 alSetError(AL_INVALID_VALUE
);
1774 // Invalid Source Name
1775 alSetError(AL_INVALID_NAME
);
1778 ProcessContext(Context
);
1782 static ALvoid
InitSourceParams(ALCcontext
*Context
, ALsource
*pSource
)
1784 pSource
->flInnerAngle
= 360.0f
;
1785 pSource
->flOuterAngle
= 360.0f
;
1786 pSource
->flPitch
= 1.0f
;
1787 pSource
->vPosition
[0] = 0.0f
;
1788 pSource
->vPosition
[1] = 0.0f
;
1789 pSource
->vPosition
[2] = 0.0f
;
1790 pSource
->vOrientation
[0] = 0.0f
;
1791 pSource
->vOrientation
[1] = 0.0f
;
1792 pSource
->vOrientation
[2] = 0.0f
;
1793 pSource
->vVelocity
[0] = 0.0f
;
1794 pSource
->vVelocity
[1] = 0.0f
;
1795 pSource
->vVelocity
[2] = 0.0f
;
1796 pSource
->flRefDistance
= 1.0f
;
1797 pSource
->flMaxDistance
= FLT_MAX
;
1798 pSource
->flRollOffFactor
= 1.0f
;
1799 pSource
->bLooping
= AL_FALSE
;
1800 pSource
->flGain
= 1.0f
;
1801 pSource
->flMinGain
= 0.0f
;
1802 pSource
->flMaxGain
= 1.0f
;
1803 pSource
->flOuterGain
= 0.0f
;
1804 pSource
->OuterGainHF
= 1.0f
;
1806 pSource
->DryGainHFAuto
= AL_TRUE
;
1807 pSource
->WetGainAuto
= AL_TRUE
;
1808 pSource
->WetGainHFAuto
= AL_TRUE
;
1809 pSource
->AirAbsorptionFactor
= 0.0f
;
1810 pSource
->RoomRolloffFactor
= 0.0f
;
1811 pSource
->DopplerFactor
= 1.0f
;
1813 pSource
->DistanceModel
= Context
->DistanceModel
;
1815 pSource
->state
= AL_INITIAL
;
1816 pSource
->lSourceType
= AL_UNDETERMINED
;
1818 pSource
->ulBufferID
= 0;
1825 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1826 The offset is relative to the start of the queue (not the start of the current buffer)
1828 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1830 ALbufferlistitem
*pBufferList
;
1832 ALfloat flBufferFreq
;
1834 ALint readPos
, writePos
;
1835 ALenum eOriginalFormat
;
1836 ALboolean bReturn
= AL_TRUE
;
1837 ALint lTotalBufferDataSize
;
1839 if (((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
)) && (pSource
->ulBufferID
))
1841 pBuffer
= ALTHUNK_LOOKUPENTRY(pSource
->ulBufferID
);
1842 // Get Current Buffer Size and frequency (in milliseconds)
1843 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1844 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1845 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1847 // Get Current BytesPlayed
1848 readPos
= pSource
->position
* lChannels
* 2; // NOTE : This is the byte offset into the *current* buffer
1849 // Add byte length of any processed buffers in the queue
1850 pBufferList
= pSource
->queue
;
1851 while ((pBufferList
) && (pBufferList
->bufferstate
== PROCESSED
))
1853 readPos
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1854 pBufferList
= pBufferList
->next
;
1857 if(pSource
->state
== AL_PLAYING
)
1858 writePos
= readPos
+ (updateSize
* lChannels
* 2);
1862 lTotalBufferDataSize
= 0;
1863 pBufferList
= pSource
->queue
;
1866 if (pBufferList
->buffer
)
1867 lTotalBufferDataSize
+= ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
))->size
;
1868 pBufferList
= pBufferList
->next
;
1871 if (pSource
->bLooping
)
1876 readPos
%= lTotalBufferDataSize
;
1880 writePos
%= lTotalBufferDataSize
;
1884 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1887 else if(readPos
> lTotalBufferDataSize
)
1888 readPos
= lTotalBufferDataSize
;
1891 else if(writePos
> lTotalBufferDataSize
)
1892 writePos
= lTotalBufferDataSize
;
1898 case AL_SEC_RW_OFFSETS_EXT
:
1899 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* 2.0f
* flBufferFreq
);
1900 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* 2.0f
* flBufferFreq
);
1902 case AL_SAMPLE_OFFSET
:
1903 case AL_SAMPLE_RW_OFFSETS_EXT
:
1904 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* 2));
1905 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* 2));
1907 case AL_BYTE_OFFSET
:
1908 case AL_BYTE_RW_OFFSETS_EXT
:
1909 // Take into account the original format of the Buffer
1910 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1911 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1913 // Round down to nearest ADPCM block
1914 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * 2 * lChannels
)) * 36 * lChannels
);
1915 if(pSource
->state
== AL_PLAYING
)
1917 // Round up to nearest ADPCM block
1918 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * 2 * lChannels
) - 1) / (65 * 2 * lChannels
)) * 36 * lChannels
);
1921 pflOffset
[1] = pflOffset
[0];
1923 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1925 pflOffset
[0] = (ALfloat
)(readPos
>> 2);
1926 pflOffset
[1] = (ALfloat
)(writePos
>> 2);
1928 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1930 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1931 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1933 else if (aluBytesFromFormat(eOriginalFormat
) == 1)
1935 pflOffset
[0] = (ALfloat
)(readPos
>> 1);
1936 pflOffset
[1] = (ALfloat
)(writePos
>> 1);
1938 else if (aluBytesFromFormat(eOriginalFormat
) == 4)
1940 pflOffset
[0] = (ALfloat
)(readPos
<< 1);
1941 pflOffset
[1] = (ALfloat
)(writePos
<< 1);
1945 pflOffset
[0] = (ALfloat
)readPos
;
1946 pflOffset
[1] = (ALfloat
)writePos
;
1953 pflOffset
[0] = 0.0f
;
1954 pflOffset
[1] = 0.0f
;
1964 Apply a playback offset to the Source. This function will update the queue (to correctly
1965 mark buffers as 'pending' or 'processed' depending upon the new offset.
1967 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1969 ALbufferlistitem
*pBufferList
;
1971 ALint lBufferSize
, lTotalBufferSize
;
1974 // Get true byte offset
1975 lByteOffset
= GetByteOffset(pSource
);
1977 // If this is a valid offset apply it
1978 if (lByteOffset
!= -1)
1980 // Sort out the queue (pending and processed states)
1981 pBufferList
= pSource
->queue
;
1982 lTotalBufferSize
= 0;
1983 pSource
->BuffersPlayed
= 0;
1986 pBuffer
= ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
1987 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
1989 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
1991 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
1992 // update the state to PROCESSED
1993 pSource
->BuffersPlayed
++;
1995 if (!pSource
->bLooping
)
1996 pBufferList
->bufferstate
= PROCESSED
;
1998 else if (lTotalBufferSize
<= lByteOffset
)
2000 // Offset is within this buffer
2001 pBufferList
->bufferstate
= PENDING
;
2003 // Set Current Buffer ID
2004 pSource
->ulBufferID
= pBufferList
->buffer
;
2006 // SW Mixer Positions are in Samples
2007 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2008 aluBytesFromFormat(pBuffer
->format
) /
2009 aluChannelsFromFormat(pBuffer
->format
);
2013 // Offset is before this buffer, so mark as pending
2014 pBufferList
->bufferstate
= PENDING
;
2017 // Increment the TotalBufferSize
2018 lTotalBufferSize
+= lBufferSize
;
2020 // Move on to next buffer in the Queue
2021 pBufferList
= pBufferList
->next
;
2027 alSetError(AL_INVALID_VALUE
);
2031 pSource
->lOffset
= 0;
2038 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2039 offset supplied by the application). This takes into account the fact that the buffer format
2040 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2042 static ALint
GetByteOffset(ALsource
*pSource
)
2044 ALbuffer
*pBuffer
= NULL
;
2045 ALbufferlistitem
*pBufferList
;
2046 ALfloat flBufferFreq
;
2048 ALint lByteOffset
= -1;
2049 ALint lTotalBufferDataSize
;
2051 // Find the first non-NULL Buffer in the Queue
2052 pBufferList
= pSource
->queue
;
2055 if (pBufferList
->buffer
)
2057 pBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(pBufferList
->buffer
);
2060 pBufferList
= pBufferList
->next
;
2065 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2066 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2068 // Determine the ByteOffset (and ensure it is block aligned)
2069 switch (pSource
->lOffsetType
)
2071 case AL_BYTE_OFFSET
:
2072 // Take into consideration the original format
2073 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
2074 (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2076 // Round down to nearest ADPCM block
2077 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2078 // Multiply by compression rate
2079 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2080 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2082 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR8
)
2084 lByteOffset
= pSource
->lOffset
* 4;
2085 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2087 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR16
)
2089 lByteOffset
= pSource
->lOffset
* 2;
2090 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2092 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 1)
2094 lByteOffset
= pSource
->lOffset
* 2;
2095 lByteOffset
-= (lByteOffset
% (lChannels
* 2));
2097 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 4)
2099 lByteOffset
= pSource
->lOffset
/ 2;
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
)
2138 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2141 if(Context
->SourceCount
> 0)
2142 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context
->SourceCount
);
2145 while(Context
->Source
)
2147 ALsource
*temp
= Context
->Source
;
2148 Context
->Source
= Context
->Source
->next
;
2150 // Release source structure
2151 ALTHUNK_REMOVEENTRY(temp
->source
);
2152 memset(temp
, 0, sizeof(ALsource
));
2155 Context
->SourceCount
= 0;