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
, ALuint updateSize
);
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
;
849 pContext
= GetContextSuspended();
850 if(!pContext
) return;
854 if(alIsSource(source
))
856 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
861 *pflValue
= pSource
->flPitch
;
865 *pflValue
= pSource
->flGain
;
869 *pflValue
= pSource
->flMinGain
;
873 *pflValue
= pSource
->flMaxGain
;
876 case AL_MAX_DISTANCE
:
877 *pflValue
= pSource
->flMaxDistance
;
880 case AL_ROLLOFF_FACTOR
:
881 *pflValue
= pSource
->flRollOffFactor
;
884 case AL_CONE_OUTER_GAIN
:
885 *pflValue
= pSource
->flOuterGain
;
888 case AL_CONE_OUTER_GAINHF
:
889 *pflValue
= pSource
->OuterGainHF
;
893 case AL_SAMPLE_OFFSET
:
895 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
896 *pflValue
= flOffset
[0];
898 alSetError(AL_INVALID_OPERATION
);
901 case AL_SEC_RW_OFFSETS_EXT
:
902 case AL_SAMPLE_RW_OFFSETS_EXT
:
903 case AL_BYTE_RW_OFFSETS_EXT
:
904 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
906 pflValue
[0] = flOffset
[0];
907 pflValue
[1] = flOffset
[1];
910 alSetError(AL_INVALID_OPERATION
);
913 case AL_CONE_INNER_ANGLE
:
914 *pflValue
= pSource
->flInnerAngle
;
917 case AL_CONE_OUTER_ANGLE
:
918 *pflValue
= pSource
->flOuterAngle
;
921 case AL_REFERENCE_DISTANCE
:
922 *pflValue
= pSource
->flRefDistance
;
925 case AL_AIR_ABSORPTION_FACTOR
:
926 *pflValue
= pSource
->AirAbsorptionFactor
;
929 case AL_ROOM_ROLLOFF_FACTOR
:
930 *pflValue
= pSource
->RoomRolloffFactor
;
933 case AL_DOPPLER_FACTOR
:
934 *pflValue
= pSource
->DopplerFactor
;
938 alSetError(AL_INVALID_ENUM
);
943 alSetError(AL_INVALID_NAME
);
946 alSetError(AL_INVALID_VALUE
);
948 ProcessContext(pContext
);
952 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
954 ALCcontext
*pContext
;
957 pContext
= GetContextSuspended();
958 if(!pContext
) return;
960 if(pflValue1
&& pflValue2
&& pflValue3
)
962 if(alIsSource(source
))
964 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
969 *pflValue1
= pSource
->vPosition
[0];
970 *pflValue2
= pSource
->vPosition
[1];
971 *pflValue3
= pSource
->vPosition
[2];
975 *pflValue1
= pSource
->vVelocity
[0];
976 *pflValue2
= pSource
->vVelocity
[1];
977 *pflValue3
= pSource
->vVelocity
[2];
981 *pflValue1
= pSource
->vOrientation
[0];
982 *pflValue2
= pSource
->vOrientation
[1];
983 *pflValue3
= pSource
->vOrientation
[2];
987 alSetError(AL_INVALID_ENUM
);
992 alSetError(AL_INVALID_NAME
);
995 alSetError(AL_INVALID_VALUE
);
997 ProcessContext(pContext
);
1001 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
1003 ALCcontext
*pContext
;
1006 pContext
= GetContextSuspended();
1007 if(!pContext
) return;
1011 if(alIsSource(source
))
1013 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1021 case AL_MAX_DISTANCE
:
1022 case AL_ROLLOFF_FACTOR
:
1023 case AL_DOPPLER_FACTOR
:
1024 case AL_CONE_OUTER_GAIN
:
1026 case AL_SAMPLE_OFFSET
:
1027 case AL_BYTE_OFFSET
:
1028 case AL_CONE_INNER_ANGLE
:
1029 case AL_CONE_OUTER_ANGLE
:
1030 case AL_REFERENCE_DISTANCE
:
1031 case AL_CONE_OUTER_GAINHF
:
1032 case AL_AIR_ABSORPTION_FACTOR
:
1033 case AL_ROOM_ROLLOFF_FACTOR
:
1034 alGetSourcef(source
, eParam
, pflValues
);
1038 pflValues
[0] = pSource
->vPosition
[0];
1039 pflValues
[1] = pSource
->vPosition
[1];
1040 pflValues
[2] = pSource
->vPosition
[2];
1044 pflValues
[0] = pSource
->vVelocity
[0];
1045 pflValues
[1] = pSource
->vVelocity
[1];
1046 pflValues
[2] = pSource
->vVelocity
[2];
1050 pflValues
[0] = pSource
->vOrientation
[0];
1051 pflValues
[1] = pSource
->vOrientation
[1];
1052 pflValues
[2] = pSource
->vOrientation
[2];
1056 alSetError(AL_INVALID_ENUM
);
1061 alSetError(AL_INVALID_NAME
);
1064 alSetError(AL_INVALID_VALUE
);
1066 ProcessContext(pContext
);
1070 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1072 ALCcontext
*pContext
;
1074 ALfloat flOffset
[2];
1076 pContext
= GetContextSuspended();
1077 if(!pContext
) return;
1081 if(alIsSource(source
))
1083 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1087 case AL_MAX_DISTANCE
:
1088 *plValue
= (ALint
)pSource
->flMaxDistance
;
1091 case AL_ROLLOFF_FACTOR
:
1092 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1095 case AL_REFERENCE_DISTANCE
:
1096 *plValue
= (ALint
)pSource
->flRefDistance
;
1099 case AL_SOURCE_RELATIVE
:
1100 *plValue
= pSource
->bHeadRelative
;
1103 case AL_CONE_INNER_ANGLE
:
1104 *plValue
= (ALint
)pSource
->flInnerAngle
;
1107 case AL_CONE_OUTER_ANGLE
:
1108 *plValue
= (ALint
)pSource
->flOuterAngle
;
1112 *plValue
= pSource
->bLooping
;
1116 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1119 case AL_SOURCE_STATE
:
1120 *plValue
= pSource
->state
;
1123 case AL_BUFFERS_QUEUED
:
1124 *plValue
= pSource
->BuffersInQueue
;
1127 case AL_BUFFERS_PROCESSED
:
1128 if(pSource
->bLooping
)
1130 /* Buffers on a looping source are in a perpetual state
1131 * of PENDING, so don't report any as PROCESSED */
1135 *plValue
= pSource
->BuffersPlayed
;
1138 case AL_SOURCE_TYPE
:
1139 *plValue
= pSource
->lSourceType
;
1143 case AL_SAMPLE_OFFSET
:
1144 case AL_BYTE_OFFSET
:
1145 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1146 *plValue
= (ALint
)flOffset
[0];
1148 alSetError(AL_INVALID_OPERATION
);
1151 case AL_SEC_RW_OFFSETS_EXT
:
1152 case AL_SAMPLE_RW_OFFSETS_EXT
:
1153 case AL_BYTE_RW_OFFSETS_EXT
:
1154 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1156 plValue
[0] = (ALint
)flOffset
[0];
1157 plValue
[1] = (ALint
)flOffset
[1];
1160 alSetError(AL_INVALID_OPERATION
);
1163 case AL_DIRECT_FILTER
:
1164 *plValue
= pSource
->DirectFilter
.filter
;
1167 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1168 *plValue
= pSource
->DryGainHFAuto
;
1171 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1172 *plValue
= pSource
->WetGainAuto
;
1175 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1176 *plValue
= pSource
->WetGainHFAuto
;
1179 case AL_DOPPLER_FACTOR
:
1180 *plValue
= (ALint
)pSource
->DopplerFactor
;
1183 case AL_DISTANCE_MODEL
:
1184 *plValue
= pSource
->DistanceModel
;
1188 alSetError(AL_INVALID_ENUM
);
1193 alSetError(AL_INVALID_NAME
);
1196 alSetError(AL_INVALID_VALUE
);
1198 ProcessContext(pContext
);
1202 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1204 ALCcontext
*pContext
;
1207 pContext
= GetContextSuspended();
1208 if(!pContext
) return;
1210 if(plValue1
&& plValue2
&& plValue3
)
1212 if(alIsSource(source
))
1214 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1219 *plValue1
= (ALint
)pSource
->vPosition
[0];
1220 *plValue2
= (ALint
)pSource
->vPosition
[1];
1221 *plValue3
= (ALint
)pSource
->vPosition
[2];
1225 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1226 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1227 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1231 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1232 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1233 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1237 alSetError(AL_INVALID_ENUM
);
1242 alSetError(AL_INVALID_NAME
);
1245 alSetError(AL_INVALID_VALUE
);
1247 ProcessContext(pContext
);
1251 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1253 ALCcontext
*pContext
;
1256 pContext
= GetContextSuspended();
1257 if(!pContext
) return;
1261 if(alIsSource(source
))
1263 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1267 case AL_SOURCE_RELATIVE
:
1268 case AL_CONE_INNER_ANGLE
:
1269 case AL_CONE_OUTER_ANGLE
:
1272 case AL_SOURCE_STATE
:
1273 case AL_BUFFERS_QUEUED
:
1274 case AL_BUFFERS_PROCESSED
:
1276 case AL_SAMPLE_OFFSET
:
1277 case AL_BYTE_OFFSET
:
1278 case AL_MAX_DISTANCE
:
1279 case AL_ROLLOFF_FACTOR
:
1280 case AL_DOPPLER_FACTOR
:
1281 case AL_REFERENCE_DISTANCE
:
1282 case AL_SOURCE_TYPE
:
1283 case AL_DIRECT_FILTER
:
1284 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1285 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1286 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1287 case AL_DISTANCE_MODEL
:
1288 alGetSourcei(source
, eParam
, plValues
);
1292 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1293 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1294 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1298 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1299 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1300 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1304 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1305 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1306 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1310 alSetError(AL_INVALID_ENUM
);
1315 alSetError(AL_INVALID_NAME
);
1318 alSetError(AL_INVALID_VALUE
);
1320 ProcessContext(pContext
);
1324 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1326 alSourcePlayv(1, &source
);
1329 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1331 ALCcontext
*pContext
;
1333 ALbufferlistitem
*ALBufferList
;
1334 ALboolean bSourcesValid
= AL_TRUE
;
1338 pContext
= GetContextSuspended();
1339 if(!pContext
) return;
1343 // Check that all the Sources are valid
1344 for(i
= 0; i
< n
; i
++)
1346 if(!alIsSource(pSourceList
[i
]))
1348 alSetError(AL_INVALID_NAME
);
1349 bSourcesValid
= AL_FALSE
;
1356 for(i
= 0; i
< n
; i
++)
1358 // Assume Source won't need to play
1361 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1363 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1364 ALBufferList
= pSource
->queue
;
1367 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1372 ALBufferList
= ALBufferList
->next
;
1377 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1378 pSource
->DryGains
[j
] = 0.0f
;
1379 for(j
= 0;j
< MAX_SENDS
;j
++)
1380 pSource
->WetGains
[j
] = 0.0f
;
1382 if(pSource
->state
!= AL_PAUSED
)
1384 pSource
->state
= AL_PLAYING
;
1385 pSource
->position
= 0;
1386 pSource
->position_fraction
= 0;
1387 pSource
->BuffersPlayed
= 0;
1389 pSource
->Buffer
= pSource
->queue
->buffer
;
1392 pSource
->state
= AL_PLAYING
;
1394 // Check if an Offset has been set
1395 if(pSource
->lOffset
)
1396 ApplyOffset(pSource
);
1398 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1399 pSource
->position_fraction
== 0)
1400 pSource
->FirstStart
= AL_TRUE
;
1402 pSource
->FirstStart
= AL_FALSE
;
1404 // If device is disconnected, go right to stopped
1405 if(!pContext
->Device
->Connected
)
1407 pSource
->state
= AL_STOPPED
;
1408 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1409 pSource
->position
= 0;
1410 pSource
->position_fraction
= 0;
1414 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1420 // sources is a NULL pointer
1421 alSetError(AL_INVALID_VALUE
);
1424 ProcessContext(pContext
);
1427 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1429 alSourcePausev(1, &source
);
1432 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1434 ALCcontext
*Context
;
1437 ALboolean bSourcesValid
= AL_TRUE
;
1439 Context
= GetContextSuspended();
1440 if(!Context
) return;
1444 // Check all the Sources are valid
1447 if(!alIsSource(sources
[i
]))
1449 alSetError(AL_INVALID_NAME
);
1450 bSourcesValid
= AL_FALSE
;
1457 for(i
= 0;i
< n
;i
++)
1459 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1460 if(Source
->state
== AL_PLAYING
)
1461 Source
->state
= AL_PAUSED
;
1467 // sources is a NULL pointer
1468 alSetError(AL_INVALID_VALUE
);
1471 ProcessContext(Context
);
1474 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1476 alSourceStopv(1, &source
);
1479 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1481 ALCcontext
*Context
;
1484 ALboolean bSourcesValid
= AL_TRUE
;
1486 Context
= GetContextSuspended();
1487 if(!Context
) return;
1491 // Check all the Sources are valid
1492 for(i
= 0;i
< n
;i
++)
1494 if(!alIsSource(sources
[i
]))
1496 alSetError(AL_INVALID_NAME
);
1497 bSourcesValid
= AL_FALSE
;
1504 for(i
= 0;i
< n
;i
++)
1506 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1507 if(Source
->state
!= AL_INITIAL
)
1509 Source
->state
= AL_STOPPED
;
1510 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1512 Source
->lOffset
= 0;
1518 // sources is a NULL pointer
1519 alSetError(AL_INVALID_VALUE
);
1522 ProcessContext(Context
);
1525 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1527 alSourceRewindv(1, &source
);
1530 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1532 ALCcontext
*Context
;
1535 ALboolean bSourcesValid
= AL_TRUE
;
1537 Context
= GetContextSuspended();
1538 if(!Context
) return;
1542 // Check all the Sources are valid
1543 for(i
= 0;i
< n
;i
++)
1545 if(!alIsSource(sources
[i
]))
1547 alSetError(AL_INVALID_NAME
);
1548 bSourcesValid
= AL_FALSE
;
1555 for(i
= 0;i
< n
;i
++)
1557 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1558 if(Source
->state
!= AL_INITIAL
)
1560 Source
->state
= AL_INITIAL
;
1561 Source
->position
= 0;
1562 Source
->position_fraction
= 0;
1563 Source
->BuffersPlayed
= 0;
1565 Source
->Buffer
= Source
->queue
->buffer
;
1567 Source
->lOffset
= 0;
1573 // sources is a NULL pointer
1574 alSetError(AL_INVALID_VALUE
);
1577 ProcessContext(Context
);
1581 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1583 ALCcontext
*Context
;
1586 ALbufferlistitem
*ALBufferList
;
1587 ALbufferlistitem
*ALBufferListStart
;
1590 ALboolean bBuffersValid
= AL_TRUE
;
1591 ALboolean hadFormat
= AL_FALSE
;
1596 Context
= GetContextSuspended();
1597 if(!Context
) return;
1599 // Check that all buffers are valid or zero and that the source is valid
1601 // Check that this is a valid source
1602 if(alIsSource(source
))
1604 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1606 // Check that this is not a STATIC Source
1607 if(ALSource
->lSourceType
!= AL_STATIC
)
1612 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1613 ALBufferList
= ALSource
->queue
;
1616 if (ALBufferList
->buffer
)
1618 iFrequency
= ALBufferList
->buffer
->frequency
;
1619 iFormat
= ALBufferList
->buffer
->format
;
1620 hadFormat
= AL_TRUE
;
1623 ALBufferList
= ALBufferList
->next
;
1626 for(i
= 0; i
< n
; i
++)
1630 if(!alIsBuffer(buffers
[i
]))
1632 alSetError(AL_INVALID_NAME
);
1633 bBuffersValid
= AL_FALSE
;
1639 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1640 if(iFrequency
== -1 && iFormat
== -1)
1642 iFrequency
= buffer
->frequency
;
1643 iFormat
= buffer
->format
;
1645 else if(iFrequency
!= buffer
->frequency
||
1646 iFormat
!= buffer
->format
)
1648 alSetError(AL_INVALID_OPERATION
);
1649 bBuffersValid
= AL_FALSE
;
1656 ALbuffer
*buffer
= NULL
;
1658 // Change Source Type
1659 ALSource
->lSourceType
= AL_STREAMING
;
1661 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1663 // All buffers are valid - so add them to the list
1664 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1665 ALBufferListStart
->buffer
= buffer
;
1666 ALBufferListStart
->next
= NULL
;
1668 // Increment reference counter for buffer
1669 if(buffer
) buffer
->refcount
++;
1671 ALBufferList
= ALBufferListStart
;
1673 for(i
= 1; i
< n
; i
++)
1675 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1677 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1678 ALBufferList
->next
->buffer
= buffer
;
1679 ALBufferList
->next
->next
= NULL
;
1681 // Increment reference counter for buffer
1682 if(buffer
) buffer
->refcount
++;
1684 ALBufferList
= ALBufferList
->next
;
1687 if(ALSource
->queue
== NULL
)
1689 ALSource
->queue
= ALBufferListStart
;
1690 // Update Current Buffer
1691 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1695 // Find end of queue
1696 ALBufferList
= ALSource
->queue
;
1697 while(ALBufferList
->next
!= NULL
)
1698 ALBufferList
= ALBufferList
->next
;
1700 ALBufferList
->next
= ALBufferListStart
;
1703 // Update number of buffers in queue
1704 ALSource
->BuffersInQueue
+= n
;
1705 // If no previous format, mark the source dirty now that it may
1708 ALSource
->NeedsUpdate
= AL_TRUE
;
1713 // Invalid Source Type (can't queue on a Static Source)
1714 alSetError(AL_INVALID_OPERATION
);
1719 // Invalid Source Name
1720 alSetError(AL_INVALID_NAME
);
1723 ProcessContext(Context
);
1727 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1728 // an array of buffer IDs that are to be filled with the names of the buffers removed
1729 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1731 ALCcontext
*Context
;
1734 ALbufferlistitem
*ALBufferList
;
1735 ALboolean bBuffersProcessed
;
1740 bBuffersProcessed
= AL_TRUE
;
1742 Context
= GetContextSuspended();
1743 if(!Context
) return;
1745 if(alIsSource(source
))
1747 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1749 // If all 'n' buffers have been processed, remove them from the queue
1750 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1752 for(i
= 0; i
< n
; i
++)
1754 ALBufferList
= ALSource
->queue
;
1756 ALSource
->queue
= ALBufferList
->next
;
1757 // Record name of buffer
1758 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1759 // Decrement buffer reference counter
1760 if(ALBufferList
->buffer
)
1761 ALBufferList
->buffer
->refcount
--;
1763 // Release memory for buffer list item
1765 ALSource
->BuffersInQueue
--;
1768 if(ALSource
->state
!= AL_PLAYING
)
1771 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1773 ALSource
->Buffer
= NULL
;
1776 ALSource
->BuffersPlayed
-= n
;
1780 // Some buffers can't be unqueue because they have not been processed
1781 alSetError(AL_INVALID_VALUE
);
1786 // Invalid Source Name
1787 alSetError(AL_INVALID_NAME
);
1790 ProcessContext(Context
);
1794 static ALvoid
InitSourceParams(ALsource
*pSource
)
1796 pSource
->flInnerAngle
= 360.0f
;
1797 pSource
->flOuterAngle
= 360.0f
;
1798 pSource
->flPitch
= 1.0f
;
1799 pSource
->vPosition
[0] = 0.0f
;
1800 pSource
->vPosition
[1] = 0.0f
;
1801 pSource
->vPosition
[2] = 0.0f
;
1802 pSource
->vOrientation
[0] = 0.0f
;
1803 pSource
->vOrientation
[1] = 0.0f
;
1804 pSource
->vOrientation
[2] = 0.0f
;
1805 pSource
->vVelocity
[0] = 0.0f
;
1806 pSource
->vVelocity
[1] = 0.0f
;
1807 pSource
->vVelocity
[2] = 0.0f
;
1808 pSource
->flRefDistance
= 1.0f
;
1809 pSource
->flMaxDistance
= FLT_MAX
;
1810 pSource
->flRollOffFactor
= 1.0f
;
1811 pSource
->bLooping
= AL_FALSE
;
1812 pSource
->flGain
= 1.0f
;
1813 pSource
->flMinGain
= 0.0f
;
1814 pSource
->flMaxGain
= 1.0f
;
1815 pSource
->flOuterGain
= 0.0f
;
1816 pSource
->OuterGainHF
= 1.0f
;
1818 pSource
->DryGainHFAuto
= AL_TRUE
;
1819 pSource
->WetGainAuto
= AL_TRUE
;
1820 pSource
->WetGainHFAuto
= AL_TRUE
;
1821 pSource
->AirAbsorptionFactor
= 0.0f
;
1822 pSource
->RoomRolloffFactor
= 0.0f
;
1823 pSource
->DopplerFactor
= 1.0f
;
1825 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1827 pSource
->Resampler
= DefaultResampler
;
1829 pSource
->state
= AL_INITIAL
;
1830 pSource
->lSourceType
= AL_UNDETERMINED
;
1832 pSource
->NeedsUpdate
= AL_TRUE
;
1834 pSource
->Buffer
= NULL
;
1841 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1842 The offset is relative to the start of the queue (not the start of the current buffer)
1844 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1846 ALbufferlistitem
*pBufferList
;
1848 ALfloat flBufferFreq
;
1849 ALint lChannels
, lBytes
;
1850 ALint readPos
, writePos
;
1851 ALenum eOriginalFormat
;
1852 ALboolean bReturn
= AL_TRUE
;
1853 ALint lTotalBufferDataSize
;
1856 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1858 pBuffer
= pSource
->Buffer
;
1859 // Get Current Buffer Size and frequency (in milliseconds)
1860 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1861 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1862 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1863 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1865 // Get Current BytesPlayed
1866 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1867 // Add byte length of any processed buffers in the queue
1868 pBufferList
= pSource
->queue
;
1869 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1871 readPos
+= pBufferList
->buffer
->size
;
1872 pBufferList
= pBufferList
->next
;
1875 if(pSource
->state
== AL_PLAYING
)
1876 writePos
= readPos
+ (updateSize
* lChannels
* lBytes
);
1880 lTotalBufferDataSize
= 0;
1881 pBufferList
= pSource
->queue
;
1884 if (pBufferList
->buffer
)
1885 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1886 pBufferList
= pBufferList
->next
;
1889 if (pSource
->bLooping
)
1894 readPos
%= lTotalBufferDataSize
;
1898 writePos
%= lTotalBufferDataSize
;
1902 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1905 else if(readPos
> lTotalBufferDataSize
)
1906 readPos
= lTotalBufferDataSize
;
1909 else if(writePos
> lTotalBufferDataSize
)
1910 writePos
= lTotalBufferDataSize
;
1916 case AL_SEC_RW_OFFSETS_EXT
:
1917 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1918 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1920 case AL_SAMPLE_OFFSET
:
1921 case AL_SAMPLE_RW_OFFSETS_EXT
:
1922 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1923 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1925 case AL_BYTE_OFFSET
:
1926 case AL_BYTE_RW_OFFSETS_EXT
:
1927 // Take into account the original format of the Buffer
1928 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1929 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1931 // Round down to nearest ADPCM block
1932 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1933 if(pSource
->state
== AL_PLAYING
)
1935 // Round up to nearest ADPCM block
1936 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1939 pflOffset
[1] = pflOffset
[0];
1941 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1943 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1944 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1946 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1948 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1949 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1951 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1953 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1954 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1958 ALuint OrigBytes
= aluBytesFromFormat(eOriginalFormat
);
1959 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* OrigBytes
);
1960 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* OrigBytes
);
1967 pflOffset
[0] = 0.0f
;
1968 pflOffset
[1] = 0.0f
;
1978 Apply a playback offset to the Source. This function will update the queue (to correctly
1979 mark buffers as 'pending' or 'processed' depending upon the new offset.
1981 static ALboolean
ApplyOffset(ALsource
*pSource
)
1983 ALbufferlistitem
*pBufferList
;
1985 ALint lBufferSize
, lTotalBufferSize
;
1988 // Get true byte offset
1989 lByteOffset
= GetByteOffset(pSource
);
1991 // If the offset is invalid, don't apply it
1992 if(lByteOffset
== -1)
1995 // Sort out the queue (pending and processed states)
1996 pBufferList
= pSource
->queue
;
1997 lTotalBufferSize
= 0;
1998 pSource
->BuffersPlayed
= 0;
2002 pBuffer
= pBufferList
->buffer
;
2003 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
2005 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
2007 // Offset is past this buffer so increment BuffersPlayed
2008 pSource
->BuffersPlayed
++;
2010 else if(lTotalBufferSize
<= lByteOffset
)
2012 // Offset is within this buffer
2013 // Set Current Buffer
2014 pSource
->Buffer
= pBufferList
->buffer
;
2016 // SW Mixer Positions are in Samples
2017 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2018 aluBytesFromFormat(pBuffer
->format
) /
2019 aluChannelsFromFormat(pBuffer
->format
);
2023 // Increment the TotalBufferSize
2024 lTotalBufferSize
+= lBufferSize
;
2026 // Move on to next buffer in the Queue
2027 pBufferList
= pBufferList
->next
;
2037 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2038 offset supplied by the application). This takes into account the fact that the buffer format
2039 may have been modifed by AL (e.g 8bit samples are converted to float)
2041 static ALint
GetByteOffset(ALsource
*pSource
)
2043 ALbuffer
*pBuffer
= NULL
;
2044 ALbufferlistitem
*pBufferList
;
2045 ALfloat flBufferFreq
;
2046 ALint lChannels
, lBytes
;
2047 ALint lByteOffset
= -1;
2048 ALint lTotalBufferDataSize
;
2049 ALenum OriginalFormat
;
2051 // Find the first non-NULL Buffer in the Queue
2052 pBufferList
= pSource
->queue
;
2055 if (pBufferList
->buffer
)
2057 pBuffer
= pBufferList
->buffer
;
2060 pBufferList
= pBufferList
->next
;
2065 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2066 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2067 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2068 OriginalFormat
= pBuffer
->eOriginalFormat
;
2070 // Determine the ByteOffset (and ensure it is block aligned)
2071 switch (pSource
->lOffsetType
)
2073 case AL_BYTE_OFFSET
:
2074 // Take into consideration the original format
2075 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2076 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2078 // Round down to nearest ADPCM block
2079 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2080 // Multiply by compression rate
2081 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2082 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2084 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2086 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2087 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2089 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2091 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2092 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2094 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2096 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2097 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2101 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2102 lByteOffset
= pSource
->lOffset
/ OrigBytes
* lBytes
;
2103 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2107 case AL_SAMPLE_OFFSET
:
2108 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2112 // Note - lOffset is internally stored as Milliseconds
2113 lByteOffset
= (ALint
)(pSource
->lOffset
/ 1000.0f
* flBufferFreq
);
2114 lByteOffset
*= lChannels
* lBytes
;
2118 lTotalBufferDataSize
= 0;
2119 pBufferList
= pSource
->queue
;
2122 if (pBufferList
->buffer
)
2123 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2124 pBufferList
= pBufferList
->next
;
2127 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2128 if (lByteOffset
>= lTotalBufferDataSize
)
2133 pSource
->lOffset
= 0;
2139 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2143 while(Context
->Source
)
2145 ALsource
*temp
= Context
->Source
;
2146 Context
->Source
= temp
->next
;
2148 // For each buffer in the source's queue, decrement its reference counter and remove it
2149 while(temp
->queue
!= NULL
)
2151 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2152 // Decrement buffer's reference counter
2153 if(ALBufferList
->buffer
!= NULL
)
2154 ALBufferList
->buffer
->refcount
--;
2155 // Update queue to point to next element in list
2156 temp
->queue
= ALBufferList
->next
;
2157 // Release memory allocated for buffer list item
2161 for(j
= 0;j
< MAX_SENDS
;++j
)
2163 if(temp
->Send
[j
].Slot
)
2164 temp
->Send
[j
].Slot
->refcount
--;
2167 // Release source structure
2168 ALTHUNK_REMOVEENTRY(temp
->source
);
2169 memset(temp
, 0, sizeof(ALsource
));
2172 Context
->SourceCount
= 0;