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(ALsource
*pSource
);
36 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
);
37 static ALboolean
ApplyOffset(ALsource
*pSource
);
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(*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
;
233 pSource
->NeedsUpdate
= AL_TRUE
;
236 alSetError(AL_INVALID_VALUE
);
239 case AL_CONE_INNER_ANGLE
:
240 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
242 pSource
->flInnerAngle
= flValue
;
243 pSource
->NeedsUpdate
= AL_TRUE
;
246 alSetError(AL_INVALID_VALUE
);
249 case AL_CONE_OUTER_ANGLE
:
250 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
252 pSource
->flOuterAngle
= flValue
;
253 pSource
->NeedsUpdate
= AL_TRUE
;
256 alSetError(AL_INVALID_VALUE
);
262 pSource
->flGain
= flValue
;
263 pSource
->NeedsUpdate
= AL_TRUE
;
266 alSetError(AL_INVALID_VALUE
);
269 case AL_MAX_DISTANCE
:
272 pSource
->flMaxDistance
= flValue
;
273 pSource
->NeedsUpdate
= AL_TRUE
;
276 alSetError(AL_INVALID_VALUE
);
279 case AL_ROLLOFF_FACTOR
:
282 pSource
->flRollOffFactor
= flValue
;
283 pSource
->NeedsUpdate
= AL_TRUE
;
286 alSetError(AL_INVALID_VALUE
);
289 case AL_REFERENCE_DISTANCE
:
292 pSource
->flRefDistance
= flValue
;
293 pSource
->NeedsUpdate
= AL_TRUE
;
296 alSetError(AL_INVALID_VALUE
);
300 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
302 pSource
->flMinGain
= flValue
;
303 pSource
->NeedsUpdate
= AL_TRUE
;
306 alSetError(AL_INVALID_VALUE
);
310 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
312 pSource
->flMaxGain
= flValue
;
313 pSource
->NeedsUpdate
= AL_TRUE
;
316 alSetError(AL_INVALID_VALUE
);
319 case AL_CONE_OUTER_GAIN
:
320 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
322 pSource
->flOuterGain
= flValue
;
323 pSource
->NeedsUpdate
= AL_TRUE
;
326 alSetError(AL_INVALID_VALUE
);
329 case AL_CONE_OUTER_GAINHF
:
330 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
332 pSource
->OuterGainHF
= flValue
;
333 pSource
->NeedsUpdate
= AL_TRUE
;
336 alSetError(AL_INVALID_VALUE
);
339 case AL_AIR_ABSORPTION_FACTOR
:
340 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
342 pSource
->AirAbsorptionFactor
= flValue
;
343 pSource
->NeedsUpdate
= AL_TRUE
;
346 alSetError(AL_INVALID_VALUE
);
349 case AL_ROOM_ROLLOFF_FACTOR
:
350 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
352 pSource
->RoomRolloffFactor
= flValue
;
353 pSource
->NeedsUpdate
= AL_TRUE
;
356 alSetError(AL_INVALID_VALUE
);
359 case AL_DOPPLER_FACTOR
:
360 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
362 pSource
->DopplerFactor
= flValue
;
363 pSource
->NeedsUpdate
= AL_TRUE
;
366 alSetError(AL_INVALID_VALUE
);
370 case AL_SAMPLE_OFFSET
:
374 pSource
->lOffsetType
= eParam
;
376 // Store Offset (convert Seconds into Milliseconds)
377 if(eParam
== AL_SEC_OFFSET
)
378 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
380 pSource
->lOffset
= (ALint
)flValue
;
382 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
384 if(ApplyOffset(pSource
) == AL_FALSE
)
385 alSetError(AL_INVALID_VALUE
);
389 alSetError(AL_INVALID_VALUE
);
393 alSetError(AL_INVALID_ENUM
);
399 // Invalid Source Name
400 alSetError(AL_INVALID_NAME
);
403 ProcessContext(pContext
);
407 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
409 ALCcontext
*pContext
;
412 pContext
= GetContextSuspended();
413 if(!pContext
) return;
415 if(alIsSource(source
))
417 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
421 pSource
->vPosition
[0] = flValue1
;
422 pSource
->vPosition
[1] = flValue2
;
423 pSource
->vPosition
[2] = flValue3
;
424 pSource
->NeedsUpdate
= AL_TRUE
;
428 pSource
->vVelocity
[0] = flValue1
;
429 pSource
->vVelocity
[1] = flValue2
;
430 pSource
->vVelocity
[2] = flValue3
;
431 pSource
->NeedsUpdate
= AL_TRUE
;
435 pSource
->vOrientation
[0] = flValue1
;
436 pSource
->vOrientation
[1] = flValue2
;
437 pSource
->vOrientation
[2] = flValue3
;
438 pSource
->NeedsUpdate
= AL_TRUE
;
442 alSetError(AL_INVALID_ENUM
);
447 alSetError(AL_INVALID_NAME
);
449 ProcessContext(pContext
);
453 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
455 ALCcontext
*pContext
;
457 pContext
= GetContextSuspended();
458 if(!pContext
) return;
462 if(alIsSource(source
))
467 case AL_CONE_INNER_ANGLE
:
468 case AL_CONE_OUTER_ANGLE
:
470 case AL_MAX_DISTANCE
:
471 case AL_ROLLOFF_FACTOR
:
472 case AL_REFERENCE_DISTANCE
:
475 case AL_CONE_OUTER_GAIN
:
476 case AL_CONE_OUTER_GAINHF
:
478 case AL_SAMPLE_OFFSET
:
480 case AL_AIR_ABSORPTION_FACTOR
:
481 case AL_ROOM_ROLLOFF_FACTOR
:
482 alSourcef(source
, eParam
, pflValues
[0]);
488 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
492 alSetError(AL_INVALID_ENUM
);
497 alSetError(AL_INVALID_NAME
);
500 alSetError(AL_INVALID_VALUE
);
502 ProcessContext(pContext
);
506 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
508 ALCcontext
*pContext
;
510 ALbufferlistitem
*pALBufferListItem
;
512 pContext
= GetContextSuspended();
513 if(!pContext
) return;
515 if(alIsSource(source
))
517 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
521 case AL_MAX_DISTANCE
:
522 case AL_ROLLOFF_FACTOR
:
523 case AL_REFERENCE_DISTANCE
:
524 alSourcef(source
, eParam
, (ALfloat
)lValue
);
527 case AL_SOURCE_RELATIVE
:
528 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
530 pSource
->bHeadRelative
= (ALboolean
)lValue
;
531 pSource
->NeedsUpdate
= AL_TRUE
;
534 alSetError(AL_INVALID_VALUE
);
537 case AL_CONE_INNER_ANGLE
:
538 if(lValue
>= 0 && lValue
<= 360)
540 pSource
->flInnerAngle
= (float)lValue
;
541 pSource
->NeedsUpdate
= AL_TRUE
;
544 alSetError(AL_INVALID_VALUE
);
547 case AL_CONE_OUTER_ANGLE
:
548 if(lValue
>= 0 && lValue
<= 360)
550 pSource
->flOuterAngle
= (float)lValue
;
551 pSource
->NeedsUpdate
= AL_TRUE
;
554 alSetError(AL_INVALID_VALUE
);
558 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
559 pSource
->bLooping
= (ALboolean
)lValue
;
561 alSetError(AL_INVALID_VALUE
);
565 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
567 if(alIsBuffer(lValue
))
569 ALbuffer
*buffer
= NULL
;
571 // Remove all elements in the queue
572 while(pSource
->queue
!= NULL
)
574 pALBufferListItem
= pSource
->queue
;
575 pSource
->queue
= pALBufferListItem
->next
;
576 // Decrement reference counter for buffer
577 if(pALBufferListItem
->buffer
)
578 pALBufferListItem
->buffer
->refcount
--;
579 // Release memory for buffer list item
580 free(pALBufferListItem
);
581 // Decrement the number of buffers in the queue
582 pSource
->BuffersInQueue
--;
585 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
588 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
);
590 // Source is now in STATIC mode
591 pSource
->lSourceType
= AL_STATIC
;
593 // Add the selected buffer to the queue
594 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
595 pALBufferListItem
->buffer
= buffer
;
596 pALBufferListItem
->next
= NULL
;
598 pSource
->queue
= pALBufferListItem
;
599 pSource
->BuffersInQueue
= 1;
601 // Increment reference counter for buffer
606 // Source is now in UNDETERMINED mode
607 pSource
->lSourceType
= AL_UNDETERMINED
;
608 pSource
->BuffersPlayed
= 0;
611 // Update AL_BUFFER parameter
612 pSource
->Buffer
= buffer
;
613 pSource
->NeedsUpdate
= AL_TRUE
;
616 alSetError(AL_INVALID_VALUE
);
619 alSetError(AL_INVALID_OPERATION
);
622 case AL_SOURCE_STATE
:
624 alSetError(AL_INVALID_OPERATION
);
628 case AL_SAMPLE_OFFSET
:
632 pSource
->lOffsetType
= eParam
;
634 // Store Offset (convert Seconds into Milliseconds)
635 if(eParam
== AL_SEC_OFFSET
)
636 pSource
->lOffset
= lValue
* 1000;
638 pSource
->lOffset
= lValue
;
640 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
642 if(ApplyOffset(pSource
) == AL_FALSE
)
643 alSetError(AL_INVALID_VALUE
);
647 alSetError(AL_INVALID_VALUE
);
650 case AL_DIRECT_FILTER
:
651 if(alIsFilter(lValue
))
653 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
656 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
657 pSource
->DirectFilter
.filter
= 0;
660 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
661 pSource
->NeedsUpdate
= AL_TRUE
;
664 alSetError(AL_INVALID_VALUE
);
667 case AL_DIRECT_FILTER_GAINHF_AUTO
:
668 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
670 pSource
->DryGainHFAuto
= lValue
;
671 pSource
->NeedsUpdate
= AL_TRUE
;
674 alSetError(AL_INVALID_VALUE
);
677 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
678 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
680 pSource
->WetGainAuto
= lValue
;
681 pSource
->NeedsUpdate
= AL_TRUE
;
684 alSetError(AL_INVALID_VALUE
);
687 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
688 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
690 pSource
->WetGainHFAuto
= lValue
;
691 pSource
->NeedsUpdate
= AL_TRUE
;
694 alSetError(AL_INVALID_VALUE
);
697 case AL_DISTANCE_MODEL
:
698 if(lValue
== AL_NONE
||
699 lValue
== AL_INVERSE_DISTANCE
||
700 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
701 lValue
== AL_LINEAR_DISTANCE
||
702 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
703 lValue
== AL_EXPONENT_DISTANCE
||
704 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
706 pSource
->DistanceModel
= lValue
;
707 if(pContext
->SourceDistanceModel
)
708 pSource
->NeedsUpdate
= AL_TRUE
;
711 alSetError(AL_INVALID_VALUE
);
715 alSetError(AL_INVALID_ENUM
);
720 alSetError(AL_INVALID_NAME
);
722 ProcessContext(pContext
);
726 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
728 ALCcontext
*pContext
;
730 pContext
= GetContextSuspended();
731 if(!pContext
) return;
733 if(alIsSource(source
))
735 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
736 ALCdevice
*Device
= pContext
->Device
;
743 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
746 case AL_AUXILIARY_SEND_FILTER
:
747 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
748 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
751 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
752 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
754 /* Release refcount on the previous slot, and add one for
756 if(pSource
->Send
[lValue2
].Slot
)
757 pSource
->Send
[lValue2
].Slot
->refcount
--;
758 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
759 if(pSource
->Send
[lValue2
].Slot
)
760 pSource
->Send
[lValue2
].Slot
->refcount
++;
765 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
766 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
769 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
770 pSource
->NeedsUpdate
= AL_TRUE
;
773 alSetError(AL_INVALID_VALUE
);
777 alSetError(AL_INVALID_ENUM
);
782 alSetError(AL_INVALID_NAME
);
784 ProcessContext(pContext
);
788 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
790 ALCcontext
*pContext
;
792 pContext
= GetContextSuspended();
793 if(!pContext
) return;
797 if(alIsSource(source
))
801 case AL_SOURCE_RELATIVE
:
802 case AL_CONE_INNER_ANGLE
:
803 case AL_CONE_OUTER_ANGLE
:
806 case AL_SOURCE_STATE
:
808 case AL_SAMPLE_OFFSET
:
810 case AL_MAX_DISTANCE
:
811 case AL_ROLLOFF_FACTOR
:
812 case AL_REFERENCE_DISTANCE
:
813 case AL_DIRECT_FILTER
:
814 case AL_DIRECT_FILTER_GAINHF_AUTO
:
815 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
816 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
817 case AL_DISTANCE_MODEL
:
818 alSourcei(source
, eParam
, plValues
[0]);
824 case AL_AUXILIARY_SEND_FILTER
:
825 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
829 alSetError(AL_INVALID_ENUM
);
834 alSetError(AL_INVALID_NAME
);
837 alSetError(AL_INVALID_VALUE
);
839 ProcessContext(pContext
);
843 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
845 ALCcontext
*pContext
;
850 pContext
= GetContextSuspended();
851 if(!pContext
) return;
855 if(alIsSource(source
))
857 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
862 *pflValue
= pSource
->flPitch
;
866 *pflValue
= pSource
->flGain
;
870 *pflValue
= pSource
->flMinGain
;
874 *pflValue
= pSource
->flMaxGain
;
877 case AL_MAX_DISTANCE
:
878 *pflValue
= pSource
->flMaxDistance
;
881 case AL_ROLLOFF_FACTOR
:
882 *pflValue
= pSource
->flRollOffFactor
;
885 case AL_CONE_OUTER_GAIN
:
886 *pflValue
= pSource
->flOuterGain
;
889 case AL_CONE_OUTER_GAINHF
:
890 *pflValue
= pSource
->OuterGainHF
;
894 case AL_SAMPLE_OFFSET
:
896 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
897 pContext
->Device
->Frequency
;
898 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
899 *pflValue
= flOffset
[0];
901 alSetError(AL_INVALID_OPERATION
);
904 case AL_SEC_RW_OFFSETS_EXT
:
905 case AL_SAMPLE_RW_OFFSETS_EXT
:
906 case AL_BYTE_RW_OFFSETS_EXT
:
907 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
908 pContext
->Device
->Frequency
;
909 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
911 pflValue
[0] = flOffset
[0];
912 pflValue
[1] = flOffset
[1];
915 alSetError(AL_INVALID_OPERATION
);
918 case AL_CONE_INNER_ANGLE
:
919 *pflValue
= pSource
->flInnerAngle
;
922 case AL_CONE_OUTER_ANGLE
:
923 *pflValue
= pSource
->flOuterAngle
;
926 case AL_REFERENCE_DISTANCE
:
927 *pflValue
= pSource
->flRefDistance
;
930 case AL_AIR_ABSORPTION_FACTOR
:
931 *pflValue
= pSource
->AirAbsorptionFactor
;
934 case AL_ROOM_ROLLOFF_FACTOR
:
935 *pflValue
= pSource
->RoomRolloffFactor
;
938 case AL_DOPPLER_FACTOR
:
939 *pflValue
= pSource
->DopplerFactor
;
943 alSetError(AL_INVALID_ENUM
);
948 alSetError(AL_INVALID_NAME
);
951 alSetError(AL_INVALID_VALUE
);
953 ProcessContext(pContext
);
957 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
959 ALCcontext
*pContext
;
962 pContext
= GetContextSuspended();
963 if(!pContext
) return;
965 if(pflValue1
&& pflValue2
&& pflValue3
)
967 if(alIsSource(source
))
969 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
974 *pflValue1
= pSource
->vPosition
[0];
975 *pflValue2
= pSource
->vPosition
[1];
976 *pflValue3
= pSource
->vPosition
[2];
980 *pflValue1
= pSource
->vVelocity
[0];
981 *pflValue2
= pSource
->vVelocity
[1];
982 *pflValue3
= pSource
->vVelocity
[2];
986 *pflValue1
= pSource
->vOrientation
[0];
987 *pflValue2
= pSource
->vOrientation
[1];
988 *pflValue3
= 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
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
1008 ALCcontext
*pContext
;
1011 pContext
= GetContextSuspended();
1012 if(!pContext
) return;
1016 if(alIsSource(source
))
1018 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1026 case AL_MAX_DISTANCE
:
1027 case AL_ROLLOFF_FACTOR
:
1028 case AL_DOPPLER_FACTOR
:
1029 case AL_CONE_OUTER_GAIN
:
1031 case AL_SAMPLE_OFFSET
:
1032 case AL_BYTE_OFFSET
:
1033 case AL_CONE_INNER_ANGLE
:
1034 case AL_CONE_OUTER_ANGLE
:
1035 case AL_REFERENCE_DISTANCE
:
1036 case AL_CONE_OUTER_GAINHF
:
1037 case AL_AIR_ABSORPTION_FACTOR
:
1038 case AL_ROOM_ROLLOFF_FACTOR
:
1039 alGetSourcef(source
, eParam
, pflValues
);
1043 pflValues
[0] = pSource
->vPosition
[0];
1044 pflValues
[1] = pSource
->vPosition
[1];
1045 pflValues
[2] = pSource
->vPosition
[2];
1049 pflValues
[0] = pSource
->vVelocity
[0];
1050 pflValues
[1] = pSource
->vVelocity
[1];
1051 pflValues
[2] = pSource
->vVelocity
[2];
1055 pflValues
[0] = pSource
->vOrientation
[0];
1056 pflValues
[1] = pSource
->vOrientation
[1];
1057 pflValues
[2] = pSource
->vOrientation
[2];
1061 alSetError(AL_INVALID_ENUM
);
1066 alSetError(AL_INVALID_NAME
);
1069 alSetError(AL_INVALID_VALUE
);
1071 ProcessContext(pContext
);
1075 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1077 ALCcontext
*pContext
;
1079 ALfloat flOffset
[2];
1082 pContext
= GetContextSuspended();
1083 if(!pContext
) return;
1087 if(alIsSource(source
))
1089 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1093 case AL_MAX_DISTANCE
:
1094 *plValue
= (ALint
)pSource
->flMaxDistance
;
1097 case AL_ROLLOFF_FACTOR
:
1098 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1101 case AL_REFERENCE_DISTANCE
:
1102 *plValue
= (ALint
)pSource
->flRefDistance
;
1105 case AL_SOURCE_RELATIVE
:
1106 *plValue
= pSource
->bHeadRelative
;
1109 case AL_CONE_INNER_ANGLE
:
1110 *plValue
= (ALint
)pSource
->flInnerAngle
;
1113 case AL_CONE_OUTER_ANGLE
:
1114 *plValue
= (ALint
)pSource
->flOuterAngle
;
1118 *plValue
= pSource
->bLooping
;
1122 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1125 case AL_SOURCE_STATE
:
1126 *plValue
= pSource
->state
;
1129 case AL_BUFFERS_QUEUED
:
1130 *plValue
= pSource
->BuffersInQueue
;
1133 case AL_BUFFERS_PROCESSED
:
1134 if(pSource
->bLooping
)
1136 /* Buffers on a looping source are in a perpetual state
1137 * of PENDING, so don't report any as PROCESSED */
1141 *plValue
= pSource
->BuffersPlayed
;
1144 case AL_SOURCE_TYPE
:
1145 *plValue
= pSource
->lSourceType
;
1149 case AL_SAMPLE_OFFSET
:
1150 case AL_BYTE_OFFSET
:
1151 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1152 pContext
->Device
->Frequency
;
1153 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1154 *plValue
= (ALint
)flOffset
[0];
1156 alSetError(AL_INVALID_OPERATION
);
1159 case AL_SEC_RW_OFFSETS_EXT
:
1160 case AL_SAMPLE_RW_OFFSETS_EXT
:
1161 case AL_BYTE_RW_OFFSETS_EXT
:
1162 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1163 pContext
->Device
->Frequency
;
1164 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1166 plValue
[0] = (ALint
)flOffset
[0];
1167 plValue
[1] = (ALint
)flOffset
[1];
1170 alSetError(AL_INVALID_OPERATION
);
1173 case AL_DIRECT_FILTER
:
1174 *plValue
= pSource
->DirectFilter
.filter
;
1177 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1178 *plValue
= pSource
->DryGainHFAuto
;
1181 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1182 *plValue
= pSource
->WetGainAuto
;
1185 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1186 *plValue
= pSource
->WetGainHFAuto
;
1189 case AL_DOPPLER_FACTOR
:
1190 *plValue
= (ALint
)pSource
->DopplerFactor
;
1193 case AL_DISTANCE_MODEL
:
1194 *plValue
= pSource
->DistanceModel
;
1198 alSetError(AL_INVALID_ENUM
);
1203 alSetError(AL_INVALID_NAME
);
1206 alSetError(AL_INVALID_VALUE
);
1208 ProcessContext(pContext
);
1212 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1214 ALCcontext
*pContext
;
1217 pContext
= GetContextSuspended();
1218 if(!pContext
) return;
1220 if(plValue1
&& plValue2
&& plValue3
)
1222 if(alIsSource(source
))
1224 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1229 *plValue1
= (ALint
)pSource
->vPosition
[0];
1230 *plValue2
= (ALint
)pSource
->vPosition
[1];
1231 *plValue3
= (ALint
)pSource
->vPosition
[2];
1235 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1236 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1237 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1241 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1242 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1243 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1247 alSetError(AL_INVALID_ENUM
);
1252 alSetError(AL_INVALID_NAME
);
1255 alSetError(AL_INVALID_VALUE
);
1257 ProcessContext(pContext
);
1261 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1263 ALCcontext
*pContext
;
1266 pContext
= GetContextSuspended();
1267 if(!pContext
) return;
1271 if(alIsSource(source
))
1273 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1277 case AL_SOURCE_RELATIVE
:
1278 case AL_CONE_INNER_ANGLE
:
1279 case AL_CONE_OUTER_ANGLE
:
1282 case AL_SOURCE_STATE
:
1283 case AL_BUFFERS_QUEUED
:
1284 case AL_BUFFERS_PROCESSED
:
1286 case AL_SAMPLE_OFFSET
:
1287 case AL_BYTE_OFFSET
:
1288 case AL_MAX_DISTANCE
:
1289 case AL_ROLLOFF_FACTOR
:
1290 case AL_DOPPLER_FACTOR
:
1291 case AL_REFERENCE_DISTANCE
:
1292 case AL_SOURCE_TYPE
:
1293 case AL_DIRECT_FILTER
:
1294 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1295 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1296 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1297 case AL_DISTANCE_MODEL
:
1298 alGetSourcei(source
, eParam
, plValues
);
1302 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1303 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1304 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1308 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1309 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1310 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1314 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1315 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1316 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1320 alSetError(AL_INVALID_ENUM
);
1325 alSetError(AL_INVALID_NAME
);
1328 alSetError(AL_INVALID_VALUE
);
1330 ProcessContext(pContext
);
1334 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1336 alSourcePlayv(1, &source
);
1339 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1341 ALCcontext
*pContext
;
1343 ALbufferlistitem
*ALBufferList
;
1344 ALboolean bSourcesValid
= AL_TRUE
;
1348 pContext
= GetContextSuspended();
1349 if(!pContext
) return;
1353 // Check that all the Sources are valid
1354 for(i
= 0; i
< n
; i
++)
1356 if(!alIsSource(pSourceList
[i
]))
1358 alSetError(AL_INVALID_NAME
);
1359 bSourcesValid
= AL_FALSE
;
1366 for(i
= 0; i
< n
; i
++)
1368 // Assume Source won't need to play
1371 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1373 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1374 ALBufferList
= pSource
->queue
;
1377 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1382 ALBufferList
= ALBufferList
->next
;
1387 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1388 pSource
->DryGains
[j
] = 0.0f
;
1389 for(j
= 0;j
< MAX_SENDS
;j
++)
1390 pSource
->WetGains
[j
] = 0.0f
;
1392 if(pSource
->state
!= AL_PAUSED
)
1394 pSource
->state
= AL_PLAYING
;
1395 pSource
->position
= 0;
1396 pSource
->position_fraction
= 0;
1397 pSource
->BuffersPlayed
= 0;
1399 pSource
->Buffer
= pSource
->queue
->buffer
;
1402 pSource
->state
= AL_PLAYING
;
1404 // Check if an Offset has been set
1405 if(pSource
->lOffset
)
1406 ApplyOffset(pSource
);
1408 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1409 pSource
->position_fraction
== 0)
1410 pSource
->FirstStart
= AL_TRUE
;
1412 pSource
->FirstStart
= AL_FALSE
;
1414 // If device is disconnected, go right to stopped
1415 if(!pContext
->Device
->Connected
)
1417 pSource
->state
= AL_STOPPED
;
1418 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1419 pSource
->position
= 0;
1420 pSource
->position_fraction
= 0;
1424 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1430 // sources is a NULL pointer
1431 alSetError(AL_INVALID_VALUE
);
1434 ProcessContext(pContext
);
1437 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1439 alSourcePausev(1, &source
);
1442 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1444 ALCcontext
*Context
;
1447 ALboolean bSourcesValid
= AL_TRUE
;
1449 Context
= GetContextSuspended();
1450 if(!Context
) return;
1454 // Check all the Sources are valid
1457 if(!alIsSource(sources
[i
]))
1459 alSetError(AL_INVALID_NAME
);
1460 bSourcesValid
= AL_FALSE
;
1467 for(i
= 0;i
< n
;i
++)
1469 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1470 if(Source
->state
== AL_PLAYING
)
1471 Source
->state
= AL_PAUSED
;
1477 // sources is a NULL pointer
1478 alSetError(AL_INVALID_VALUE
);
1481 ProcessContext(Context
);
1484 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1486 alSourceStopv(1, &source
);
1489 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1491 ALCcontext
*Context
;
1494 ALboolean bSourcesValid
= AL_TRUE
;
1496 Context
= GetContextSuspended();
1497 if(!Context
) return;
1501 // Check all the Sources are valid
1502 for(i
= 0;i
< n
;i
++)
1504 if(!alIsSource(sources
[i
]))
1506 alSetError(AL_INVALID_NAME
);
1507 bSourcesValid
= AL_FALSE
;
1514 for(i
= 0;i
< n
;i
++)
1516 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1517 if(Source
->state
!= AL_INITIAL
)
1519 Source
->state
= AL_STOPPED
;
1520 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1522 Source
->lOffset
= 0;
1528 // sources is a NULL pointer
1529 alSetError(AL_INVALID_VALUE
);
1532 ProcessContext(Context
);
1535 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1537 alSourceRewindv(1, &source
);
1540 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1542 ALCcontext
*Context
;
1545 ALboolean bSourcesValid
= AL_TRUE
;
1547 Context
= GetContextSuspended();
1548 if(!Context
) return;
1552 // Check all the Sources are valid
1553 for(i
= 0;i
< n
;i
++)
1555 if(!alIsSource(sources
[i
]))
1557 alSetError(AL_INVALID_NAME
);
1558 bSourcesValid
= AL_FALSE
;
1565 for(i
= 0;i
< n
;i
++)
1567 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1568 if(Source
->state
!= AL_INITIAL
)
1570 Source
->state
= AL_INITIAL
;
1571 Source
->position
= 0;
1572 Source
->position_fraction
= 0;
1573 Source
->BuffersPlayed
= 0;
1575 Source
->Buffer
= Source
->queue
->buffer
;
1577 Source
->lOffset
= 0;
1583 // sources is a NULL pointer
1584 alSetError(AL_INVALID_VALUE
);
1587 ProcessContext(Context
);
1591 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1593 ALCcontext
*Context
;
1596 ALbufferlistitem
*ALBufferList
;
1597 ALbufferlistitem
*ALBufferListStart
;
1600 ALboolean bBuffersValid
= AL_TRUE
;
1601 ALboolean hadFormat
= AL_FALSE
;
1606 Context
= GetContextSuspended();
1607 if(!Context
) return;
1609 // Check that all buffers are valid or zero and that the source is valid
1611 // Check that this is a valid source
1612 if(alIsSource(source
))
1614 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1616 // Check that this is not a STATIC Source
1617 if(ALSource
->lSourceType
!= AL_STATIC
)
1622 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1623 ALBufferList
= ALSource
->queue
;
1626 if (ALBufferList
->buffer
)
1628 iFrequency
= ALBufferList
->buffer
->frequency
;
1629 iFormat
= ALBufferList
->buffer
->format
;
1630 hadFormat
= AL_TRUE
;
1633 ALBufferList
= ALBufferList
->next
;
1636 for(i
= 0; i
< n
; i
++)
1640 if(!alIsBuffer(buffers
[i
]))
1642 alSetError(AL_INVALID_NAME
);
1643 bBuffersValid
= AL_FALSE
;
1649 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1650 if(iFrequency
== -1 && iFormat
== -1)
1652 iFrequency
= buffer
->frequency
;
1653 iFormat
= buffer
->format
;
1655 else if(iFrequency
!= buffer
->frequency
||
1656 iFormat
!= buffer
->format
)
1658 alSetError(AL_INVALID_OPERATION
);
1659 bBuffersValid
= AL_FALSE
;
1666 ALbuffer
*buffer
= NULL
;
1668 // Change Source Type
1669 ALSource
->lSourceType
= AL_STREAMING
;
1671 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1673 // All buffers are valid - so add them to the list
1674 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1675 ALBufferListStart
->buffer
= buffer
;
1676 ALBufferListStart
->next
= NULL
;
1678 // Increment reference counter for buffer
1679 if(buffer
) buffer
->refcount
++;
1681 ALBufferList
= ALBufferListStart
;
1683 for(i
= 1; i
< n
; i
++)
1685 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1687 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1688 ALBufferList
->next
->buffer
= buffer
;
1689 ALBufferList
->next
->next
= NULL
;
1691 // Increment reference counter for buffer
1692 if(buffer
) buffer
->refcount
++;
1694 ALBufferList
= ALBufferList
->next
;
1697 if(ALSource
->queue
== NULL
)
1699 ALSource
->queue
= ALBufferListStart
;
1700 // Update Current Buffer
1701 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1705 // Find end of queue
1706 ALBufferList
= ALSource
->queue
;
1707 while(ALBufferList
->next
!= NULL
)
1708 ALBufferList
= ALBufferList
->next
;
1710 ALBufferList
->next
= ALBufferListStart
;
1713 // Update number of buffers in queue
1714 ALSource
->BuffersInQueue
+= n
;
1715 // If no previous format, mark the source dirty now that it may
1718 ALSource
->NeedsUpdate
= AL_TRUE
;
1723 // Invalid Source Type (can't queue on a Static Source)
1724 alSetError(AL_INVALID_OPERATION
);
1729 // Invalid Source Name
1730 alSetError(AL_INVALID_NAME
);
1733 ProcessContext(Context
);
1737 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1738 // an array of buffer IDs that are to be filled with the names of the buffers removed
1739 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1741 ALCcontext
*Context
;
1744 ALbufferlistitem
*ALBufferList
;
1745 ALboolean bBuffersProcessed
;
1750 bBuffersProcessed
= AL_TRUE
;
1752 Context
= GetContextSuspended();
1753 if(!Context
) return;
1755 if(alIsSource(source
))
1757 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1759 // If all 'n' buffers have been processed, remove them from the queue
1760 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1762 for(i
= 0; i
< n
; i
++)
1764 ALBufferList
= ALSource
->queue
;
1766 ALSource
->queue
= ALBufferList
->next
;
1767 // Record name of buffer
1768 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1769 // Decrement buffer reference counter
1770 if(ALBufferList
->buffer
)
1771 ALBufferList
->buffer
->refcount
--;
1773 // Release memory for buffer list item
1775 ALSource
->BuffersInQueue
--;
1778 if(ALSource
->state
!= AL_PLAYING
)
1781 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1783 ALSource
->Buffer
= NULL
;
1786 ALSource
->BuffersPlayed
-= n
;
1790 // Some buffers can't be unqueue because they have not been processed
1791 alSetError(AL_INVALID_VALUE
);
1796 // Invalid Source Name
1797 alSetError(AL_INVALID_NAME
);
1800 ProcessContext(Context
);
1804 static ALvoid
InitSourceParams(ALsource
*pSource
)
1806 pSource
->flInnerAngle
= 360.0f
;
1807 pSource
->flOuterAngle
= 360.0f
;
1808 pSource
->flPitch
= 1.0f
;
1809 pSource
->vPosition
[0] = 0.0f
;
1810 pSource
->vPosition
[1] = 0.0f
;
1811 pSource
->vPosition
[2] = 0.0f
;
1812 pSource
->vOrientation
[0] = 0.0f
;
1813 pSource
->vOrientation
[1] = 0.0f
;
1814 pSource
->vOrientation
[2] = 0.0f
;
1815 pSource
->vVelocity
[0] = 0.0f
;
1816 pSource
->vVelocity
[1] = 0.0f
;
1817 pSource
->vVelocity
[2] = 0.0f
;
1818 pSource
->flRefDistance
= 1.0f
;
1819 pSource
->flMaxDistance
= FLT_MAX
;
1820 pSource
->flRollOffFactor
= 1.0f
;
1821 pSource
->bLooping
= AL_FALSE
;
1822 pSource
->flGain
= 1.0f
;
1823 pSource
->flMinGain
= 0.0f
;
1824 pSource
->flMaxGain
= 1.0f
;
1825 pSource
->flOuterGain
= 0.0f
;
1826 pSource
->OuterGainHF
= 1.0f
;
1828 pSource
->DryGainHFAuto
= AL_TRUE
;
1829 pSource
->WetGainAuto
= AL_TRUE
;
1830 pSource
->WetGainHFAuto
= AL_TRUE
;
1831 pSource
->AirAbsorptionFactor
= 0.0f
;
1832 pSource
->RoomRolloffFactor
= 0.0f
;
1833 pSource
->DopplerFactor
= 1.0f
;
1835 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1837 pSource
->Resampler
= DefaultResampler
;
1839 pSource
->state
= AL_INITIAL
;
1840 pSource
->lSourceType
= AL_UNDETERMINED
;
1842 pSource
->NeedsUpdate
= AL_TRUE
;
1844 pSource
->Buffer
= NULL
;
1851 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1852 The offset is relative to the start of the queue (not the start of the current buffer)
1854 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
)
1856 ALbufferlistitem
*pBufferList
;
1858 ALfloat flBufferFreq
;
1859 ALint lChannels
, lBytes
;
1860 ALint readPos
, writePos
;
1861 ALenum eOriginalFormat
;
1862 ALboolean bReturn
= AL_TRUE
;
1863 ALint lTotalBufferDataSize
;
1866 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1868 pBuffer
= pSource
->Buffer
;
1869 // Get Current Buffer Size and frequency (in milliseconds)
1870 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1871 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1872 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1873 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1875 // Get Current BytesPlayed
1876 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1877 // Add byte length of any processed buffers in the queue
1878 pBufferList
= pSource
->queue
;
1879 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1881 readPos
+= pBufferList
->buffer
->size
;
1882 pBufferList
= pBufferList
->next
;
1885 if(pSource
->state
== AL_PLAYING
)
1886 writePos
= readPos
+ ((ALuint
)(updateLen
*flBufferFreq
) * lChannels
* lBytes
);
1890 lTotalBufferDataSize
= 0;
1891 pBufferList
= pSource
->queue
;
1894 if (pBufferList
->buffer
)
1895 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1896 pBufferList
= pBufferList
->next
;
1899 if (pSource
->bLooping
)
1904 readPos
%= lTotalBufferDataSize
;
1908 writePos
%= lTotalBufferDataSize
;
1912 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1915 else if(readPos
> lTotalBufferDataSize
)
1916 readPos
= lTotalBufferDataSize
;
1919 else if(writePos
> lTotalBufferDataSize
)
1920 writePos
= lTotalBufferDataSize
;
1926 case AL_SEC_RW_OFFSETS_EXT
:
1927 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1928 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1930 case AL_SAMPLE_OFFSET
:
1931 case AL_SAMPLE_RW_OFFSETS_EXT
:
1932 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1933 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1935 case AL_BYTE_OFFSET
:
1936 case AL_BYTE_RW_OFFSETS_EXT
:
1937 // Take into account the original format of the Buffer
1938 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1939 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1941 // Round down to nearest ADPCM block
1942 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1943 if(pSource
->state
== AL_PLAYING
)
1945 // Round up to nearest ADPCM block
1946 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1949 pflOffset
[1] = pflOffset
[0];
1951 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1953 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1954 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1956 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1958 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1959 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1961 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1963 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1964 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1968 ALuint OrigBytes
= aluBytesFromFormat(eOriginalFormat
);
1969 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* OrigBytes
);
1970 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* OrigBytes
);
1977 pflOffset
[0] = 0.0f
;
1978 pflOffset
[1] = 0.0f
;
1988 Apply a playback offset to the Source. This function will update the queue (to correctly
1989 mark buffers as 'pending' or 'processed' depending upon the new offset.
1991 static ALboolean
ApplyOffset(ALsource
*pSource
)
1993 ALbufferlistitem
*pBufferList
;
1995 ALint lBufferSize
, lTotalBufferSize
;
1998 // Get true byte offset
1999 lByteOffset
= GetByteOffset(pSource
);
2001 // If the offset is invalid, don't apply it
2002 if(lByteOffset
== -1)
2005 // Sort out the queue (pending and processed states)
2006 pBufferList
= pSource
->queue
;
2007 lTotalBufferSize
= 0;
2008 pSource
->BuffersPlayed
= 0;
2012 pBuffer
= pBufferList
->buffer
;
2013 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
2015 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
2017 // Offset is past this buffer so increment BuffersPlayed
2018 pSource
->BuffersPlayed
++;
2020 else if(lTotalBufferSize
<= lByteOffset
)
2022 // Offset is within this buffer
2023 // Set Current Buffer
2024 pSource
->Buffer
= pBufferList
->buffer
;
2026 // SW Mixer Positions are in Samples
2027 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2028 aluBytesFromFormat(pBuffer
->format
) /
2029 aluChannelsFromFormat(pBuffer
->format
);
2033 // Increment the TotalBufferSize
2034 lTotalBufferSize
+= lBufferSize
;
2036 // Move on to next buffer in the Queue
2037 pBufferList
= pBufferList
->next
;
2047 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2048 offset supplied by the application). This takes into account the fact that the buffer format
2049 may have been modifed by AL (e.g 8bit samples are converted to float)
2051 static ALint
GetByteOffset(ALsource
*pSource
)
2053 ALbuffer
*pBuffer
= NULL
;
2054 ALbufferlistitem
*pBufferList
;
2055 ALfloat flBufferFreq
;
2056 ALint lChannels
, lBytes
;
2057 ALint lByteOffset
= -1;
2058 ALint lTotalBufferDataSize
;
2059 ALenum OriginalFormat
;
2061 // Find the first non-NULL Buffer in the Queue
2062 pBufferList
= pSource
->queue
;
2065 if (pBufferList
->buffer
)
2067 pBuffer
= pBufferList
->buffer
;
2070 pBufferList
= pBufferList
->next
;
2075 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2076 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2077 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2078 OriginalFormat
= pBuffer
->eOriginalFormat
;
2080 // Determine the ByteOffset (and ensure it is block aligned)
2081 switch (pSource
->lOffsetType
)
2083 case AL_BYTE_OFFSET
:
2084 // Take into consideration the original format
2085 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2086 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2088 // Round down to nearest ADPCM block
2089 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2090 // Multiply by compression rate
2091 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2092 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2094 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2096 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2097 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2099 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2101 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2102 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2104 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2106 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2107 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2111 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2112 lByteOffset
= pSource
->lOffset
/ OrigBytes
* lBytes
;
2113 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2117 case AL_SAMPLE_OFFSET
:
2118 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2122 // Note - lOffset is internally stored as Milliseconds
2123 lByteOffset
= (ALint
)(pSource
->lOffset
/ 1000.0f
* flBufferFreq
);
2124 lByteOffset
*= lChannels
* lBytes
;
2128 lTotalBufferDataSize
= 0;
2129 pBufferList
= pSource
->queue
;
2132 if (pBufferList
->buffer
)
2133 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2134 pBufferList
= pBufferList
->next
;
2137 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2138 if (lByteOffset
>= lTotalBufferDataSize
)
2143 pSource
->lOffset
= 0;
2149 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2153 while(Context
->Source
)
2155 ALsource
*temp
= Context
->Source
;
2156 Context
->Source
= temp
->next
;
2158 // For each buffer in the source's queue, decrement its reference counter and remove it
2159 while(temp
->queue
!= NULL
)
2161 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2162 // Decrement buffer's reference counter
2163 if(ALBufferList
->buffer
!= NULL
)
2164 ALBufferList
->buffer
->refcount
--;
2165 // Update queue to point to next element in list
2166 temp
->queue
= ALBufferList
->next
;
2167 // Release memory allocated for buffer list item
2171 for(j
= 0;j
< MAX_SENDS
;++j
)
2173 if(temp
->Send
[j
].Slot
)
2174 temp
->Send
[j
].Slot
->refcount
--;
2177 // Release source structure
2178 ALTHUNK_REMOVEENTRY(temp
->source
);
2179 memset(temp
, 0, sizeof(ALsource
));
2182 Context
->SourceCount
= 0;