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_CONE_INNER_ANGLE
:
524 case AL_CONE_OUTER_ANGLE
:
525 case AL_REFERENCE_DISTANCE
:
526 alSourcef(source
, eParam
, (ALfloat
)lValue
);
529 case AL_SOURCE_RELATIVE
:
530 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
532 pSource
->bHeadRelative
= (ALboolean
)lValue
;
533 pSource
->NeedsUpdate
= AL_TRUE
;
536 alSetError(AL_INVALID_VALUE
);
540 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
541 pSource
->bLooping
= (ALboolean
)lValue
;
543 alSetError(AL_INVALID_VALUE
);
547 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
549 if(alIsBuffer(lValue
))
551 ALbuffer
*buffer
= NULL
;
553 // Remove all elements in the queue
554 while(pSource
->queue
!= NULL
)
556 pALBufferListItem
= pSource
->queue
;
557 pSource
->queue
= pALBufferListItem
->next
;
558 // Decrement reference counter for buffer
559 if(pALBufferListItem
->buffer
)
560 pALBufferListItem
->buffer
->refcount
--;
561 // Release memory for buffer list item
562 free(pALBufferListItem
);
563 // Decrement the number of buffers in the queue
564 pSource
->BuffersInQueue
--;
567 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
570 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
);
572 // Source is now in STATIC mode
573 pSource
->lSourceType
= AL_STATIC
;
575 // Add the selected buffer to the queue
576 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
577 pALBufferListItem
->buffer
= buffer
;
578 pALBufferListItem
->next
= NULL
;
580 pSource
->queue
= pALBufferListItem
;
581 pSource
->BuffersInQueue
= 1;
583 // Increment reference counter for buffer
588 // Source is now in UNDETERMINED mode
589 pSource
->lSourceType
= AL_UNDETERMINED
;
590 pSource
->BuffersPlayed
= 0;
593 // Update AL_BUFFER parameter
594 pSource
->Buffer
= buffer
;
595 pSource
->NeedsUpdate
= AL_TRUE
;
598 alSetError(AL_INVALID_VALUE
);
601 alSetError(AL_INVALID_OPERATION
);
604 case AL_SOURCE_STATE
:
606 alSetError(AL_INVALID_OPERATION
);
610 case AL_SAMPLE_OFFSET
:
614 pSource
->lOffsetType
= eParam
;
616 // Store Offset (convert Seconds into Milliseconds)
617 if(eParam
== AL_SEC_OFFSET
)
618 pSource
->lOffset
= lValue
* 1000;
620 pSource
->lOffset
= lValue
;
622 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
624 if(ApplyOffset(pSource
) == AL_FALSE
)
625 alSetError(AL_INVALID_VALUE
);
629 alSetError(AL_INVALID_VALUE
);
632 case AL_DIRECT_FILTER
:
633 if(alIsFilter(lValue
))
635 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
638 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
639 pSource
->DirectFilter
.filter
= 0;
642 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
643 pSource
->NeedsUpdate
= AL_TRUE
;
646 alSetError(AL_INVALID_VALUE
);
649 case AL_DIRECT_FILTER_GAINHF_AUTO
:
650 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
652 pSource
->DryGainHFAuto
= lValue
;
653 pSource
->NeedsUpdate
= AL_TRUE
;
656 alSetError(AL_INVALID_VALUE
);
659 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
660 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
662 pSource
->WetGainAuto
= lValue
;
663 pSource
->NeedsUpdate
= AL_TRUE
;
666 alSetError(AL_INVALID_VALUE
);
669 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
670 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
672 pSource
->WetGainHFAuto
= lValue
;
673 pSource
->NeedsUpdate
= AL_TRUE
;
676 alSetError(AL_INVALID_VALUE
);
679 case AL_DISTANCE_MODEL
:
680 if(lValue
== AL_NONE
||
681 lValue
== AL_INVERSE_DISTANCE
||
682 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
683 lValue
== AL_LINEAR_DISTANCE
||
684 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
685 lValue
== AL_EXPONENT_DISTANCE
||
686 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
688 pSource
->DistanceModel
= lValue
;
689 if(pContext
->SourceDistanceModel
)
690 pSource
->NeedsUpdate
= AL_TRUE
;
693 alSetError(AL_INVALID_VALUE
);
697 alSetError(AL_INVALID_ENUM
);
702 alSetError(AL_INVALID_NAME
);
704 ProcessContext(pContext
);
708 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
710 ALCcontext
*pContext
;
712 pContext
= GetContextSuspended();
713 if(!pContext
) return;
715 if(alIsSource(source
))
717 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
718 ALCdevice
*Device
= pContext
->Device
;
725 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
728 case AL_AUXILIARY_SEND_FILTER
:
729 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
730 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
733 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
734 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
736 /* Release refcount on the previous slot, and add one for
738 if(pSource
->Send
[lValue2
].Slot
)
739 pSource
->Send
[lValue2
].Slot
->refcount
--;
740 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
741 if(pSource
->Send
[lValue2
].Slot
)
742 pSource
->Send
[lValue2
].Slot
->refcount
++;
747 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
748 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
751 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
752 pSource
->NeedsUpdate
= AL_TRUE
;
755 alSetError(AL_INVALID_VALUE
);
759 alSetError(AL_INVALID_ENUM
);
764 alSetError(AL_INVALID_NAME
);
766 ProcessContext(pContext
);
770 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
772 ALCcontext
*pContext
;
774 pContext
= GetContextSuspended();
775 if(!pContext
) return;
779 if(alIsSource(source
))
783 case AL_SOURCE_RELATIVE
:
784 case AL_CONE_INNER_ANGLE
:
785 case AL_CONE_OUTER_ANGLE
:
788 case AL_SOURCE_STATE
:
790 case AL_SAMPLE_OFFSET
:
792 case AL_MAX_DISTANCE
:
793 case AL_ROLLOFF_FACTOR
:
794 case AL_REFERENCE_DISTANCE
:
795 case AL_DIRECT_FILTER
:
796 case AL_DIRECT_FILTER_GAINHF_AUTO
:
797 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
798 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
799 case AL_DISTANCE_MODEL
:
800 alSourcei(source
, eParam
, plValues
[0]);
806 case AL_AUXILIARY_SEND_FILTER
:
807 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
811 alSetError(AL_INVALID_ENUM
);
816 alSetError(AL_INVALID_NAME
);
819 alSetError(AL_INVALID_VALUE
);
821 ProcessContext(pContext
);
825 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
827 ALCcontext
*pContext
;
832 pContext
= GetContextSuspended();
833 if(!pContext
) return;
837 if(alIsSource(source
))
839 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
844 *pflValue
= pSource
->flPitch
;
848 *pflValue
= pSource
->flGain
;
852 *pflValue
= pSource
->flMinGain
;
856 *pflValue
= pSource
->flMaxGain
;
859 case AL_MAX_DISTANCE
:
860 *pflValue
= pSource
->flMaxDistance
;
863 case AL_ROLLOFF_FACTOR
:
864 *pflValue
= pSource
->flRollOffFactor
;
867 case AL_CONE_OUTER_GAIN
:
868 *pflValue
= pSource
->flOuterGain
;
871 case AL_CONE_OUTER_GAINHF
:
872 *pflValue
= pSource
->OuterGainHF
;
876 case AL_SAMPLE_OFFSET
:
878 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
879 pContext
->Device
->Frequency
;
880 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
881 *pflValue
= flOffset
[0];
883 alSetError(AL_INVALID_OPERATION
);
886 case AL_CONE_INNER_ANGLE
:
887 *pflValue
= pSource
->flInnerAngle
;
890 case AL_CONE_OUTER_ANGLE
:
891 *pflValue
= pSource
->flOuterAngle
;
894 case AL_REFERENCE_DISTANCE
:
895 *pflValue
= pSource
->flRefDistance
;
898 case AL_AIR_ABSORPTION_FACTOR
:
899 *pflValue
= pSource
->AirAbsorptionFactor
;
902 case AL_ROOM_ROLLOFF_FACTOR
:
903 *pflValue
= pSource
->RoomRolloffFactor
;
906 case AL_DOPPLER_FACTOR
:
907 *pflValue
= pSource
->DopplerFactor
;
911 alSetError(AL_INVALID_ENUM
);
916 alSetError(AL_INVALID_NAME
);
919 alSetError(AL_INVALID_VALUE
);
921 ProcessContext(pContext
);
925 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
927 ALCcontext
*pContext
;
930 pContext
= GetContextSuspended();
931 if(!pContext
) return;
933 if(pflValue1
&& pflValue2
&& pflValue3
)
935 if(alIsSource(source
))
937 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
942 *pflValue1
= pSource
->vPosition
[0];
943 *pflValue2
= pSource
->vPosition
[1];
944 *pflValue3
= pSource
->vPosition
[2];
948 *pflValue1
= pSource
->vVelocity
[0];
949 *pflValue2
= pSource
->vVelocity
[1];
950 *pflValue3
= pSource
->vVelocity
[2];
954 *pflValue1
= pSource
->vOrientation
[0];
955 *pflValue2
= pSource
->vOrientation
[1];
956 *pflValue3
= pSource
->vOrientation
[2];
960 alSetError(AL_INVALID_ENUM
);
965 alSetError(AL_INVALID_NAME
);
968 alSetError(AL_INVALID_VALUE
);
970 ProcessContext(pContext
);
974 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
976 ALCcontext
*pContext
;
981 pContext
= GetContextSuspended();
982 if(!pContext
) return;
986 if(alIsSource(source
))
988 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
996 case AL_MAX_DISTANCE
:
997 case AL_ROLLOFF_FACTOR
:
998 case AL_DOPPLER_FACTOR
:
999 case AL_CONE_OUTER_GAIN
:
1001 case AL_SAMPLE_OFFSET
:
1002 case AL_BYTE_OFFSET
:
1003 case AL_CONE_INNER_ANGLE
:
1004 case AL_CONE_OUTER_ANGLE
:
1005 case AL_REFERENCE_DISTANCE
:
1006 case AL_CONE_OUTER_GAINHF
:
1007 case AL_AIR_ABSORPTION_FACTOR
:
1008 case AL_ROOM_ROLLOFF_FACTOR
:
1009 alGetSourcef(source
, eParam
, pflValues
);
1012 case AL_SAMPLE_RW_OFFSETS_EXT
:
1013 case AL_BYTE_RW_OFFSETS_EXT
:
1014 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1015 pContext
->Device
->Frequency
;
1016 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1018 pflValues
[0] = flOffset
[0];
1019 pflValues
[1] = flOffset
[1];
1022 alSetError(AL_INVALID_OPERATION
);
1026 pflValues
[0] = pSource
->vPosition
[0];
1027 pflValues
[1] = pSource
->vPosition
[1];
1028 pflValues
[2] = pSource
->vPosition
[2];
1032 pflValues
[0] = pSource
->vVelocity
[0];
1033 pflValues
[1] = pSource
->vVelocity
[1];
1034 pflValues
[2] = pSource
->vVelocity
[2];
1038 pflValues
[0] = pSource
->vOrientation
[0];
1039 pflValues
[1] = pSource
->vOrientation
[1];
1040 pflValues
[2] = pSource
->vOrientation
[2];
1044 alSetError(AL_INVALID_ENUM
);
1049 alSetError(AL_INVALID_NAME
);
1052 alSetError(AL_INVALID_VALUE
);
1054 ProcessContext(pContext
);
1058 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1060 ALCcontext
*pContext
;
1062 ALfloat flOffset
[2];
1065 pContext
= GetContextSuspended();
1066 if(!pContext
) return;
1070 if(alIsSource(source
))
1072 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1076 case AL_MAX_DISTANCE
:
1077 *plValue
= (ALint
)pSource
->flMaxDistance
;
1080 case AL_ROLLOFF_FACTOR
:
1081 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1084 case AL_REFERENCE_DISTANCE
:
1085 *plValue
= (ALint
)pSource
->flRefDistance
;
1088 case AL_SOURCE_RELATIVE
:
1089 *plValue
= pSource
->bHeadRelative
;
1092 case AL_CONE_INNER_ANGLE
:
1093 *plValue
= (ALint
)pSource
->flInnerAngle
;
1096 case AL_CONE_OUTER_ANGLE
:
1097 *plValue
= (ALint
)pSource
->flOuterAngle
;
1101 *plValue
= pSource
->bLooping
;
1105 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1108 case AL_SOURCE_STATE
:
1109 *plValue
= pSource
->state
;
1112 case AL_BUFFERS_QUEUED
:
1113 *plValue
= pSource
->BuffersInQueue
;
1116 case AL_BUFFERS_PROCESSED
:
1117 if(pSource
->bLooping
)
1119 /* Buffers on a looping source are in a perpetual state
1120 * of PENDING, so don't report any as PROCESSED */
1124 *plValue
= pSource
->BuffersPlayed
;
1127 case AL_SOURCE_TYPE
:
1128 *plValue
= pSource
->lSourceType
;
1132 case AL_SAMPLE_OFFSET
:
1133 case AL_BYTE_OFFSET
:
1134 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1135 pContext
->Device
->Frequency
;
1136 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1137 *plValue
= (ALint
)flOffset
[0];
1139 alSetError(AL_INVALID_OPERATION
);
1142 case AL_DIRECT_FILTER
:
1143 *plValue
= pSource
->DirectFilter
.filter
;
1146 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1147 *plValue
= pSource
->DryGainHFAuto
;
1150 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1151 *plValue
= pSource
->WetGainAuto
;
1154 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1155 *plValue
= pSource
->WetGainHFAuto
;
1158 case AL_DOPPLER_FACTOR
:
1159 *plValue
= (ALint
)pSource
->DopplerFactor
;
1162 case AL_DISTANCE_MODEL
:
1163 *plValue
= pSource
->DistanceModel
;
1167 alSetError(AL_INVALID_ENUM
);
1172 alSetError(AL_INVALID_NAME
);
1175 alSetError(AL_INVALID_VALUE
);
1177 ProcessContext(pContext
);
1181 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1183 ALCcontext
*pContext
;
1186 pContext
= GetContextSuspended();
1187 if(!pContext
) return;
1189 if(plValue1
&& plValue2
&& plValue3
)
1191 if(alIsSource(source
))
1193 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1198 *plValue1
= (ALint
)pSource
->vPosition
[0];
1199 *plValue2
= (ALint
)pSource
->vPosition
[1];
1200 *plValue3
= (ALint
)pSource
->vPosition
[2];
1204 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1205 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1206 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1210 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1211 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1212 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1216 alSetError(AL_INVALID_ENUM
);
1221 alSetError(AL_INVALID_NAME
);
1224 alSetError(AL_INVALID_VALUE
);
1226 ProcessContext(pContext
);
1230 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1232 ALCcontext
*pContext
;
1234 ALfloat flOffset
[2];
1237 pContext
= GetContextSuspended();
1238 if(!pContext
) return;
1242 if(alIsSource(source
))
1244 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1248 case AL_SOURCE_RELATIVE
:
1249 case AL_CONE_INNER_ANGLE
:
1250 case AL_CONE_OUTER_ANGLE
:
1253 case AL_SOURCE_STATE
:
1254 case AL_BUFFERS_QUEUED
:
1255 case AL_BUFFERS_PROCESSED
:
1257 case AL_SAMPLE_OFFSET
:
1258 case AL_BYTE_OFFSET
:
1259 case AL_MAX_DISTANCE
:
1260 case AL_ROLLOFF_FACTOR
:
1261 case AL_DOPPLER_FACTOR
:
1262 case AL_REFERENCE_DISTANCE
:
1263 case AL_SOURCE_TYPE
:
1264 case AL_DIRECT_FILTER
:
1265 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1268 case AL_DISTANCE_MODEL
:
1269 alGetSourcei(source
, eParam
, plValues
);
1272 case AL_SAMPLE_RW_OFFSETS_EXT
:
1273 case AL_BYTE_RW_OFFSETS_EXT
:
1274 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1275 pContext
->Device
->Frequency
;
1276 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1278 plValues
[0] = (ALint
)flOffset
[0];
1279 plValues
[1] = (ALint
)flOffset
[1];
1282 alSetError(AL_INVALID_OPERATION
);
1286 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1287 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1288 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1292 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1293 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1294 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1298 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1299 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1300 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1304 alSetError(AL_INVALID_ENUM
);
1309 alSetError(AL_INVALID_NAME
);
1312 alSetError(AL_INVALID_VALUE
);
1314 ProcessContext(pContext
);
1318 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1320 alSourcePlayv(1, &source
);
1323 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1325 ALCcontext
*pContext
;
1327 ALbufferlistitem
*ALBufferList
;
1328 ALboolean bSourcesValid
= AL_TRUE
;
1332 pContext
= GetContextSuspended();
1333 if(!pContext
) return;
1337 // Check that all the Sources are valid
1338 for(i
= 0; i
< n
; i
++)
1340 if(!alIsSource(pSourceList
[i
]))
1342 alSetError(AL_INVALID_NAME
);
1343 bSourcesValid
= AL_FALSE
;
1350 for(i
= 0; i
< n
; i
++)
1352 // Assume Source won't need to play
1355 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1357 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1358 ALBufferList
= pSource
->queue
;
1361 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1366 ALBufferList
= ALBufferList
->next
;
1371 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1372 pSource
->DryGains
[j
] = 0.0f
;
1373 for(j
= 0;j
< MAX_SENDS
;j
++)
1374 pSource
->WetGains
[j
] = 0.0f
;
1376 if(pSource
->state
!= AL_PAUSED
)
1378 pSource
->state
= AL_PLAYING
;
1379 pSource
->position
= 0;
1380 pSource
->position_fraction
= 0;
1381 pSource
->BuffersPlayed
= 0;
1383 pSource
->Buffer
= pSource
->queue
->buffer
;
1386 pSource
->state
= AL_PLAYING
;
1388 // Check if an Offset has been set
1389 if(pSource
->lOffset
)
1390 ApplyOffset(pSource
);
1392 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1393 pSource
->position_fraction
== 0)
1394 pSource
->FirstStart
= AL_TRUE
;
1396 pSource
->FirstStart
= AL_FALSE
;
1398 // If device is disconnected, go right to stopped
1399 if(!pContext
->Device
->Connected
)
1401 pSource
->state
= AL_STOPPED
;
1402 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1403 pSource
->position
= 0;
1404 pSource
->position_fraction
= 0;
1408 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1414 // sources is a NULL pointer
1415 alSetError(AL_INVALID_VALUE
);
1418 ProcessContext(pContext
);
1421 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1423 alSourcePausev(1, &source
);
1426 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1428 ALCcontext
*Context
;
1431 ALboolean bSourcesValid
= AL_TRUE
;
1433 Context
= GetContextSuspended();
1434 if(!Context
) return;
1438 // Check all the Sources are valid
1441 if(!alIsSource(sources
[i
]))
1443 alSetError(AL_INVALID_NAME
);
1444 bSourcesValid
= AL_FALSE
;
1451 for(i
= 0;i
< n
;i
++)
1453 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1454 if(Source
->state
== AL_PLAYING
)
1455 Source
->state
= AL_PAUSED
;
1461 // sources is a NULL pointer
1462 alSetError(AL_INVALID_VALUE
);
1465 ProcessContext(Context
);
1468 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1470 alSourceStopv(1, &source
);
1473 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1475 ALCcontext
*Context
;
1478 ALboolean bSourcesValid
= AL_TRUE
;
1480 Context
= GetContextSuspended();
1481 if(!Context
) return;
1485 // Check all the Sources are valid
1486 for(i
= 0;i
< n
;i
++)
1488 if(!alIsSource(sources
[i
]))
1490 alSetError(AL_INVALID_NAME
);
1491 bSourcesValid
= AL_FALSE
;
1498 for(i
= 0;i
< n
;i
++)
1500 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1501 if(Source
->state
!= AL_INITIAL
)
1503 Source
->state
= AL_STOPPED
;
1504 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1506 Source
->lOffset
= 0;
1512 // sources is a NULL pointer
1513 alSetError(AL_INVALID_VALUE
);
1516 ProcessContext(Context
);
1519 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1521 alSourceRewindv(1, &source
);
1524 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1526 ALCcontext
*Context
;
1529 ALboolean bSourcesValid
= AL_TRUE
;
1531 Context
= GetContextSuspended();
1532 if(!Context
) return;
1536 // Check all the Sources are valid
1537 for(i
= 0;i
< n
;i
++)
1539 if(!alIsSource(sources
[i
]))
1541 alSetError(AL_INVALID_NAME
);
1542 bSourcesValid
= AL_FALSE
;
1549 for(i
= 0;i
< n
;i
++)
1551 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1552 if(Source
->state
!= AL_INITIAL
)
1554 Source
->state
= AL_INITIAL
;
1555 Source
->position
= 0;
1556 Source
->position_fraction
= 0;
1557 Source
->BuffersPlayed
= 0;
1559 Source
->Buffer
= Source
->queue
->buffer
;
1561 Source
->lOffset
= 0;
1567 // sources is a NULL pointer
1568 alSetError(AL_INVALID_VALUE
);
1571 ProcessContext(Context
);
1575 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1577 ALCcontext
*Context
;
1580 ALbufferlistitem
*ALBufferList
;
1581 ALbufferlistitem
*ALBufferListStart
;
1584 ALboolean bBuffersValid
= AL_TRUE
;
1585 ALboolean hadFormat
= AL_FALSE
;
1590 Context
= GetContextSuspended();
1591 if(!Context
) return;
1593 // Check that all buffers are valid or zero and that the source is valid
1595 // Check that this is a valid source
1596 if(alIsSource(source
))
1598 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1600 // Check that this is not a STATIC Source
1601 if(ALSource
->lSourceType
!= AL_STATIC
)
1606 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1607 ALBufferList
= ALSource
->queue
;
1610 if (ALBufferList
->buffer
)
1612 iFrequency
= ALBufferList
->buffer
->frequency
;
1613 iFormat
= ALBufferList
->buffer
->format
;
1614 hadFormat
= AL_TRUE
;
1617 ALBufferList
= ALBufferList
->next
;
1620 for(i
= 0; i
< n
; i
++)
1624 if(!alIsBuffer(buffers
[i
]))
1626 alSetError(AL_INVALID_NAME
);
1627 bBuffersValid
= AL_FALSE
;
1633 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1634 if(iFrequency
== -1 && iFormat
== -1)
1636 iFrequency
= buffer
->frequency
;
1637 iFormat
= buffer
->format
;
1639 else if(iFrequency
!= buffer
->frequency
||
1640 iFormat
!= buffer
->format
)
1642 alSetError(AL_INVALID_OPERATION
);
1643 bBuffersValid
= AL_FALSE
;
1650 ALbuffer
*buffer
= NULL
;
1652 // Change Source Type
1653 ALSource
->lSourceType
= AL_STREAMING
;
1655 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1657 // All buffers are valid - so add them to the list
1658 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1659 ALBufferListStart
->buffer
= buffer
;
1660 ALBufferListStart
->next
= NULL
;
1662 // Increment reference counter for buffer
1663 if(buffer
) buffer
->refcount
++;
1665 ALBufferList
= ALBufferListStart
;
1667 for(i
= 1; i
< n
; i
++)
1669 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1671 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1672 ALBufferList
->next
->buffer
= buffer
;
1673 ALBufferList
->next
->next
= NULL
;
1675 // Increment reference counter for buffer
1676 if(buffer
) buffer
->refcount
++;
1678 ALBufferList
= ALBufferList
->next
;
1681 if(ALSource
->queue
== NULL
)
1683 ALSource
->queue
= ALBufferListStart
;
1684 // Update Current Buffer
1685 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1689 // Find end of queue
1690 ALBufferList
= ALSource
->queue
;
1691 while(ALBufferList
->next
!= NULL
)
1692 ALBufferList
= ALBufferList
->next
;
1694 ALBufferList
->next
= ALBufferListStart
;
1697 // Update number of buffers in queue
1698 ALSource
->BuffersInQueue
+= n
;
1699 // If no previous format, mark the source dirty now that it may
1702 ALSource
->NeedsUpdate
= AL_TRUE
;
1707 // Invalid Source Type (can't queue on a Static Source)
1708 alSetError(AL_INVALID_OPERATION
);
1713 // Invalid Source Name
1714 alSetError(AL_INVALID_NAME
);
1717 ProcessContext(Context
);
1721 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1722 // an array of buffer IDs that are to be filled with the names of the buffers removed
1723 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1725 ALCcontext
*Context
;
1728 ALbufferlistitem
*ALBufferList
;
1729 ALboolean bBuffersProcessed
;
1734 bBuffersProcessed
= AL_TRUE
;
1736 Context
= GetContextSuspended();
1737 if(!Context
) return;
1739 if(alIsSource(source
))
1741 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1743 // If all 'n' buffers have been processed, remove them from the queue
1744 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1746 for(i
= 0; i
< n
; i
++)
1748 ALBufferList
= ALSource
->queue
;
1750 ALSource
->queue
= ALBufferList
->next
;
1751 // Record name of buffer
1752 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1753 // Decrement buffer reference counter
1754 if(ALBufferList
->buffer
)
1755 ALBufferList
->buffer
->refcount
--;
1757 // Release memory for buffer list item
1759 ALSource
->BuffersInQueue
--;
1762 if(ALSource
->state
!= AL_PLAYING
)
1765 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1767 ALSource
->Buffer
= NULL
;
1770 ALSource
->BuffersPlayed
-= n
;
1774 // Some buffers can't be unqueue because they have not been processed
1775 alSetError(AL_INVALID_VALUE
);
1780 // Invalid Source Name
1781 alSetError(AL_INVALID_NAME
);
1784 ProcessContext(Context
);
1788 static ALvoid
InitSourceParams(ALsource
*pSource
)
1790 pSource
->flInnerAngle
= 360.0f
;
1791 pSource
->flOuterAngle
= 360.0f
;
1792 pSource
->flPitch
= 1.0f
;
1793 pSource
->vPosition
[0] = 0.0f
;
1794 pSource
->vPosition
[1] = 0.0f
;
1795 pSource
->vPosition
[2] = 0.0f
;
1796 pSource
->vOrientation
[0] = 0.0f
;
1797 pSource
->vOrientation
[1] = 0.0f
;
1798 pSource
->vOrientation
[2] = 0.0f
;
1799 pSource
->vVelocity
[0] = 0.0f
;
1800 pSource
->vVelocity
[1] = 0.0f
;
1801 pSource
->vVelocity
[2] = 0.0f
;
1802 pSource
->flRefDistance
= 1.0f
;
1803 pSource
->flMaxDistance
= FLT_MAX
;
1804 pSource
->flRollOffFactor
= 1.0f
;
1805 pSource
->bLooping
= AL_FALSE
;
1806 pSource
->flGain
= 1.0f
;
1807 pSource
->flMinGain
= 0.0f
;
1808 pSource
->flMaxGain
= 1.0f
;
1809 pSource
->flOuterGain
= 0.0f
;
1810 pSource
->OuterGainHF
= 1.0f
;
1812 pSource
->DryGainHFAuto
= AL_TRUE
;
1813 pSource
->WetGainAuto
= AL_TRUE
;
1814 pSource
->WetGainHFAuto
= AL_TRUE
;
1815 pSource
->AirAbsorptionFactor
= 0.0f
;
1816 pSource
->RoomRolloffFactor
= 0.0f
;
1817 pSource
->DopplerFactor
= 1.0f
;
1819 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1821 pSource
->Resampler
= DefaultResampler
;
1823 pSource
->state
= AL_INITIAL
;
1824 pSource
->lSourceType
= AL_UNDETERMINED
;
1826 pSource
->NeedsUpdate
= AL_TRUE
;
1828 pSource
->Buffer
= NULL
;
1835 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1836 The offset is relative to the start of the queue (not the start of the current buffer)
1838 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
)
1840 ALbufferlistitem
*pBufferList
;
1842 ALfloat flBufferFreq
;
1843 ALint lChannels
, lBytes
;
1844 ALint readPos
, writePos
;
1845 ALenum eOriginalFormat
;
1846 ALboolean bReturn
= AL_TRUE
;
1847 ALint lTotalBufferDataSize
;
1850 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1852 pBuffer
= pSource
->Buffer
;
1853 // Get Current Buffer Size and frequency (in milliseconds)
1854 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1855 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1856 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1857 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1859 // Get Current BytesPlayed
1860 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1861 // Add byte length of any processed buffers in the queue
1862 pBufferList
= pSource
->queue
;
1863 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1865 readPos
+= pBufferList
->buffer
->size
;
1866 pBufferList
= pBufferList
->next
;
1869 if(pSource
->state
== AL_PLAYING
)
1870 writePos
= readPos
+ ((ALuint
)(updateLen
*flBufferFreq
) * lChannels
* lBytes
);
1874 lTotalBufferDataSize
= 0;
1875 pBufferList
= pSource
->queue
;
1878 if (pBufferList
->buffer
)
1879 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1880 pBufferList
= pBufferList
->next
;
1883 if (pSource
->bLooping
)
1888 readPos
%= lTotalBufferDataSize
;
1892 writePos
%= lTotalBufferDataSize
;
1896 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1899 else if(readPos
> lTotalBufferDataSize
)
1900 readPos
= lTotalBufferDataSize
;
1903 else if(writePos
> lTotalBufferDataSize
)
1904 writePos
= lTotalBufferDataSize
;
1910 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1911 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1913 case AL_SAMPLE_OFFSET
:
1914 case AL_SAMPLE_RW_OFFSETS_EXT
:
1915 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1916 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1918 case AL_BYTE_OFFSET
:
1919 case AL_BYTE_RW_OFFSETS_EXT
:
1920 // Take into account the original format of the Buffer
1921 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1922 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1924 // Round down to nearest ADPCM block
1925 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1926 if(pSource
->state
== AL_PLAYING
)
1928 // Round up to nearest ADPCM block
1929 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1932 pflOffset
[1] = pflOffset
[0];
1934 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1936 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1937 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1939 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1941 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1942 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1944 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1946 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1947 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1951 ALuint OrigBytes
= aluBytesFromFormat(eOriginalFormat
);
1952 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* OrigBytes
);
1953 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* OrigBytes
);
1960 pflOffset
[0] = 0.0f
;
1961 pflOffset
[1] = 0.0f
;
1971 Apply a playback offset to the Source. This function will update the queue (to correctly
1972 mark buffers as 'pending' or 'processed' depending upon the new offset.
1974 static ALboolean
ApplyOffset(ALsource
*pSource
)
1976 ALbufferlistitem
*pBufferList
;
1978 ALint lBufferSize
, lTotalBufferSize
;
1981 // Get true byte offset
1982 lByteOffset
= GetByteOffset(pSource
);
1984 // If the offset is invalid, don't apply it
1985 if(lByteOffset
== -1)
1988 // Sort out the queue (pending and processed states)
1989 pBufferList
= pSource
->queue
;
1990 lTotalBufferSize
= 0;
1991 pSource
->BuffersPlayed
= 0;
1995 pBuffer
= pBufferList
->buffer
;
1996 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
1998 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
2000 // Offset is past this buffer so increment BuffersPlayed
2001 pSource
->BuffersPlayed
++;
2003 else if(lTotalBufferSize
<= lByteOffset
)
2005 // Offset is within this buffer
2006 // Set Current Buffer
2007 pSource
->Buffer
= pBufferList
->buffer
;
2009 // SW Mixer Positions are in Samples
2010 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2011 aluBytesFromFormat(pBuffer
->format
) /
2012 aluChannelsFromFormat(pBuffer
->format
);
2016 // Increment the TotalBufferSize
2017 lTotalBufferSize
+= lBufferSize
;
2019 // Move on to next buffer in the Queue
2020 pBufferList
= pBufferList
->next
;
2030 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2031 offset supplied by the application). This takes into account the fact that the buffer format
2032 may have been modifed by AL (e.g 8bit samples are converted to float)
2034 static ALint
GetByteOffset(ALsource
*pSource
)
2036 ALbuffer
*pBuffer
= NULL
;
2037 ALbufferlistitem
*pBufferList
;
2038 ALfloat flBufferFreq
;
2039 ALint lChannels
, lBytes
;
2040 ALint lByteOffset
= -1;
2041 ALint lTotalBufferDataSize
;
2042 ALenum OriginalFormat
;
2044 // Find the first non-NULL Buffer in the Queue
2045 pBufferList
= pSource
->queue
;
2048 if (pBufferList
->buffer
)
2050 pBuffer
= pBufferList
->buffer
;
2053 pBufferList
= pBufferList
->next
;
2058 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2059 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2060 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2061 OriginalFormat
= pBuffer
->eOriginalFormat
;
2063 // Determine the ByteOffset (and ensure it is block aligned)
2064 switch (pSource
->lOffsetType
)
2066 case AL_BYTE_OFFSET
:
2067 // Take into consideration the original format
2068 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2069 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2071 // Round down to nearest ADPCM block
2072 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2073 // Multiply by compression rate
2074 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2075 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2077 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2079 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2080 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2082 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2084 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2085 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2087 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2089 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2090 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2094 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2095 lByteOffset
= pSource
->lOffset
/ OrigBytes
* lBytes
;
2096 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2100 case AL_SAMPLE_OFFSET
:
2101 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2105 // Note - lOffset is internally stored as Milliseconds
2106 lByteOffset
= (ALint
)(pSource
->lOffset
/ 1000.0f
* flBufferFreq
);
2107 lByteOffset
*= lChannels
* lBytes
;
2111 lTotalBufferDataSize
= 0;
2112 pBufferList
= pSource
->queue
;
2115 if (pBufferList
->buffer
)
2116 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2117 pBufferList
= pBufferList
->next
;
2120 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2121 if (lByteOffset
>= lTotalBufferDataSize
)
2126 pSource
->lOffset
= 0;
2132 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2136 while(Context
->Source
)
2138 ALsource
*temp
= Context
->Source
;
2139 Context
->Source
= temp
->next
;
2141 // For each buffer in the source's queue, decrement its reference counter and remove it
2142 while(temp
->queue
!= NULL
)
2144 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2145 // Decrement buffer's reference counter
2146 if(ALBufferList
->buffer
!= NULL
)
2147 ALBufferList
->buffer
->refcount
--;
2148 // Update queue to point to next element in list
2149 temp
->queue
= ALBufferList
->next
;
2150 // Release memory allocated for buffer list item
2154 for(j
= 0;j
< MAX_SENDS
;++j
)
2156 if(temp
->Send
[j
].Slot
)
2157 temp
->Send
[j
].Slot
->refcount
--;
2160 // Release source structure
2161 ALTHUNK_REMOVEENTRY(temp
->source
);
2162 memset(temp
, 0, sizeof(ALsource
));
2165 Context
->SourceCount
= 0;