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 if(ALBufferList
->buffer
)
1753 // Record name of buffer
1754 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1755 // Decrement buffer reference counter
1756 ALBufferList
->buffer
->refcount
--;
1761 // Release memory for buffer list item
1763 ALSource
->BuffersInQueue
--;
1766 if(ALSource
->state
!= AL_PLAYING
)
1769 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1771 ALSource
->Buffer
= NULL
;
1774 ALSource
->BuffersPlayed
-= n
;
1778 // Some buffers can't be unqueue because they have not been processed
1779 alSetError(AL_INVALID_VALUE
);
1784 // Invalid Source Name
1785 alSetError(AL_INVALID_NAME
);
1788 ProcessContext(Context
);
1792 static ALvoid
InitSourceParams(ALsource
*pSource
)
1794 pSource
->flInnerAngle
= 360.0f
;
1795 pSource
->flOuterAngle
= 360.0f
;
1796 pSource
->flPitch
= 1.0f
;
1797 pSource
->vPosition
[0] = 0.0f
;
1798 pSource
->vPosition
[1] = 0.0f
;
1799 pSource
->vPosition
[2] = 0.0f
;
1800 pSource
->vOrientation
[0] = 0.0f
;
1801 pSource
->vOrientation
[1] = 0.0f
;
1802 pSource
->vOrientation
[2] = 0.0f
;
1803 pSource
->vVelocity
[0] = 0.0f
;
1804 pSource
->vVelocity
[1] = 0.0f
;
1805 pSource
->vVelocity
[2] = 0.0f
;
1806 pSource
->flRefDistance
= 1.0f
;
1807 pSource
->flMaxDistance
= FLT_MAX
;
1808 pSource
->flRollOffFactor
= 1.0f
;
1809 pSource
->bLooping
= AL_FALSE
;
1810 pSource
->flGain
= 1.0f
;
1811 pSource
->flMinGain
= 0.0f
;
1812 pSource
->flMaxGain
= 1.0f
;
1813 pSource
->flOuterGain
= 0.0f
;
1814 pSource
->OuterGainHF
= 1.0f
;
1816 pSource
->DryGainHFAuto
= AL_TRUE
;
1817 pSource
->WetGainAuto
= AL_TRUE
;
1818 pSource
->WetGainHFAuto
= AL_TRUE
;
1819 pSource
->AirAbsorptionFactor
= 0.0f
;
1820 pSource
->RoomRolloffFactor
= 0.0f
;
1821 pSource
->DopplerFactor
= 1.0f
;
1823 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1825 pSource
->Resampler
= DefaultResampler
;
1827 pSource
->state
= AL_INITIAL
;
1828 pSource
->lSourceType
= AL_UNDETERMINED
;
1830 pSource
->NeedsUpdate
= AL_TRUE
;
1832 pSource
->Buffer
= NULL
;
1839 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1840 The offset is relative to the start of the queue (not the start of the current buffer)
1842 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
)
1844 ALbufferlistitem
*pBufferList
;
1846 ALfloat flBufferFreq
;
1847 ALint lChannels
, lBytes
;
1848 ALint readPos
, writePos
;
1849 ALenum eOriginalFormat
;
1850 ALboolean bReturn
= AL_TRUE
;
1851 ALint lTotalBufferDataSize
;
1854 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1856 pBuffer
= pSource
->Buffer
;
1857 // Get Current Buffer Size and frequency (in milliseconds)
1858 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1859 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1860 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1861 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1863 // Get Current BytesPlayed
1864 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1865 // Add byte length of any processed buffers in the queue
1866 pBufferList
= pSource
->queue
;
1867 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1869 readPos
+= pBufferList
->buffer
->size
;
1870 pBufferList
= pBufferList
->next
;
1873 if(pSource
->state
== AL_PLAYING
)
1874 writePos
= readPos
+ ((ALuint
)(updateLen
*flBufferFreq
) * lChannels
* lBytes
);
1878 lTotalBufferDataSize
= 0;
1879 pBufferList
= pSource
->queue
;
1882 if (pBufferList
->buffer
)
1883 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1884 pBufferList
= pBufferList
->next
;
1887 if (pSource
->bLooping
)
1892 readPos
%= lTotalBufferDataSize
;
1896 writePos
%= lTotalBufferDataSize
;
1900 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1903 else if(readPos
> lTotalBufferDataSize
)
1904 readPos
= lTotalBufferDataSize
;
1907 else if(writePos
> lTotalBufferDataSize
)
1908 writePos
= lTotalBufferDataSize
;
1914 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1915 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1917 case AL_SAMPLE_OFFSET
:
1918 case AL_SAMPLE_RW_OFFSETS_EXT
:
1919 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1920 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1922 case AL_BYTE_OFFSET
:
1923 case AL_BYTE_RW_OFFSETS_EXT
:
1924 // Take into account the original format of the Buffer
1925 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1926 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1928 // Round down to nearest ADPCM block
1929 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1930 if(pSource
->state
== AL_PLAYING
)
1932 // Round up to nearest ADPCM block
1933 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1936 pflOffset
[1] = pflOffset
[0];
1938 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1940 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1941 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1943 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1945 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1946 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1948 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1950 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1951 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1955 ALuint OrigBytes
= aluBytesFromFormat(eOriginalFormat
);
1956 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* OrigBytes
);
1957 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* OrigBytes
);
1964 pflOffset
[0] = 0.0f
;
1965 pflOffset
[1] = 0.0f
;
1975 Apply a playback offset to the Source. This function will update the queue (to correctly
1976 mark buffers as 'pending' or 'processed' depending upon the new offset.
1978 static ALboolean
ApplyOffset(ALsource
*pSource
)
1980 ALbufferlistitem
*pBufferList
;
1982 ALint lBufferSize
, lTotalBufferSize
;
1985 // Get true byte offset
1986 lByteOffset
= GetByteOffset(pSource
);
1988 // If the offset is invalid, don't apply it
1989 if(lByteOffset
== -1)
1992 // Sort out the queue (pending and processed states)
1993 pBufferList
= pSource
->queue
;
1994 lTotalBufferSize
= 0;
1995 pSource
->BuffersPlayed
= 0;
1999 pBuffer
= pBufferList
->buffer
;
2000 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
2002 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
2004 // Offset is past this buffer so increment BuffersPlayed
2005 pSource
->BuffersPlayed
++;
2007 else if(lTotalBufferSize
<= lByteOffset
)
2009 // Offset is within this buffer
2010 // Set Current Buffer
2011 pSource
->Buffer
= pBufferList
->buffer
;
2013 // SW Mixer Positions are in Samples
2014 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2015 aluBytesFromFormat(pBuffer
->format
) /
2016 aluChannelsFromFormat(pBuffer
->format
);
2020 // Increment the TotalBufferSize
2021 lTotalBufferSize
+= lBufferSize
;
2023 // Move on to next buffer in the Queue
2024 pBufferList
= pBufferList
->next
;
2034 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2035 offset supplied by the application). This takes into account the fact that the buffer format
2036 may have been modifed by AL (e.g 8bit samples are converted to float)
2038 static ALint
GetByteOffset(ALsource
*pSource
)
2040 ALbuffer
*pBuffer
= NULL
;
2041 ALbufferlistitem
*pBufferList
;
2042 ALfloat flBufferFreq
;
2043 ALint lChannels
, lBytes
;
2044 ALint lByteOffset
= -1;
2045 ALint lTotalBufferDataSize
;
2046 ALenum OriginalFormat
;
2048 // Find the first non-NULL Buffer in the Queue
2049 pBufferList
= pSource
->queue
;
2052 if (pBufferList
->buffer
)
2054 pBuffer
= pBufferList
->buffer
;
2057 pBufferList
= pBufferList
->next
;
2062 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2063 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2064 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2065 OriginalFormat
= pBuffer
->eOriginalFormat
;
2067 // Determine the ByteOffset (and ensure it is block aligned)
2068 switch (pSource
->lOffsetType
)
2070 case AL_BYTE_OFFSET
:
2071 // Take into consideration the original format
2072 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2073 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2075 // Round down to nearest ADPCM block
2076 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2077 // Multiply by compression rate
2078 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2079 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2081 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2083 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2084 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2086 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2088 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2089 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2091 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2093 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2094 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2098 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2099 lByteOffset
= pSource
->lOffset
/ OrigBytes
* lBytes
;
2100 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2104 case AL_SAMPLE_OFFSET
:
2105 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2109 // Note - lOffset is internally stored as Milliseconds
2110 lByteOffset
= (ALint
)(pSource
->lOffset
/ 1000.0f
* flBufferFreq
);
2111 lByteOffset
*= lChannels
* lBytes
;
2115 lTotalBufferDataSize
= 0;
2116 pBufferList
= pSource
->queue
;
2119 if (pBufferList
->buffer
)
2120 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2121 pBufferList
= pBufferList
->next
;
2124 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2125 if (lByteOffset
>= lTotalBufferDataSize
)
2130 pSource
->lOffset
= 0;
2136 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2140 while(Context
->Source
)
2142 ALsource
*temp
= Context
->Source
;
2143 Context
->Source
= temp
->next
;
2145 // For each buffer in the source's queue, decrement its reference counter and remove it
2146 while(temp
->queue
!= NULL
)
2148 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2149 // Decrement buffer's reference counter
2150 if(ALBufferList
->buffer
!= NULL
)
2151 ALBufferList
->buffer
->refcount
--;
2152 // Update queue to point to next element in list
2153 temp
->queue
= ALBufferList
->next
;
2154 // Release memory allocated for buffer list item
2158 for(j
= 0;j
< MAX_SENDS
;++j
)
2160 if(temp
->Send
[j
].Slot
)
2161 temp
->Send
[j
].Slot
->refcount
--;
2164 // Release source structure
2165 ALTHUNK_REMOVEENTRY(temp
->source
);
2166 memset(temp
, 0, sizeof(ALsource
));
2169 Context
->SourceCount
= 0;