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 DECL_VERIFIER(Source
, ALsource
, source
)
41 DECL_VERIFIER(Buffer
, ALbuffer
, buffer
)
42 DECL_VERIFIER(Filter
, ALfilter
, filter
)
43 DECL_VERIFIER(EffectSlot
, ALeffectslot
, effectslot
)
45 ALAPI ALvoid ALAPIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
51 Context
= GetContextSuspended();
56 Device
= Context
->Device
;
58 // Check that enough memory has been allocted in the 'sources' array for n Sources
59 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
61 // Check that the requested number of sources can be generated
62 if((Context
->SourceCount
+ n
) <= Device
->MaxNoOfSources
)
64 ALsource
**list
= &Context
->SourceList
;
66 list
= &(*list
)->next
;
68 // Add additional sources to the list (Source->next points to the location for the next Source structure)
71 *list
= calloc(1, sizeof(ALsource
));
74 alDeleteSources(i
, sources
);
75 alSetError(Context
, AL_OUT_OF_MEMORY
);
79 sources
[i
] = (ALuint
)ALTHUNK_ADDENTRY(*list
);
80 (*list
)->source
= sources
[i
];
82 InitSourceParams(*list
);
83 Context
->SourceCount
++;
86 list
= &(*list
)->next
;
91 // Not enough resources to create the Sources
92 alSetError(Context
, AL_INVALID_VALUE
);
98 alSetError(Context
, AL_INVALID_VALUE
);
102 ProcessContext(Context
);
106 ALAPI ALvoid ALAPIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
113 ALbufferlistitem
*ALBufferList
;
114 ALboolean bSourcesValid
= AL_TRUE
;
116 Context
= GetContextSuspended();
121 Device
= Context
->Device
;
123 // Check that all Sources are valid (and can therefore be deleted)
124 for (i
= 0; i
< n
; i
++)
126 if(VerifySource(Context
->SourceList
, sources
[i
]) == NULL
)
128 alSetError(Context
, AL_INVALID_NAME
);
129 bSourcesValid
= AL_FALSE
;
136 // All Sources are valid, and can be deleted
137 for(i
= 0; i
< n
; i
++)
139 // Recheck that the Source is valid, because there could be duplicated Source names
140 if((ALSource
=VerifySource(Context
->SourceList
, sources
[i
])) != NULL
)
142 alSourceStop((ALuint
)ALSource
->source
);
144 // For each buffer in the source's queue, decrement its reference counter and remove it
145 while (ALSource
->queue
!= NULL
)
147 ALBufferList
= ALSource
->queue
;
148 // Decrement buffer's reference counter
149 if(ALBufferList
->buffer
!= NULL
)
150 ALBufferList
->buffer
->refcount
--;
151 // Update queue to point to next element in list
152 ALSource
->queue
= ALBufferList
->next
;
153 // Release memory allocated for buffer list item
157 for(j
= 0;j
< MAX_SENDS
;++j
)
159 if(ALSource
->Send
[j
].Slot
)
160 ALSource
->Send
[j
].Slot
->refcount
--;
161 ALSource
->Send
[j
].Slot
= NULL
;
164 // Decrement Source count
165 Context
->SourceCount
--;
167 // Remove Source from list of Sources
168 list
= &Context
->SourceList
;
169 while(*list
&& *list
!= ALSource
)
170 list
= &(*list
)->next
;
173 *list
= (*list
)->next
;
174 ALTHUNK_REMOVEENTRY(ALSource
->source
);
176 memset(ALSource
,0,sizeof(ALsource
));
183 alSetError(Context
, AL_INVALID_VALUE
);
185 ProcessContext(Context
);
189 ALAPI ALboolean ALAPIENTRY
alIsSource(ALuint source
)
194 Context
= GetContextSuspended();
195 if(!Context
) return AL_FALSE
;
197 result
= (VerifySource(Context
->SourceList
, source
) ? AL_TRUE
: AL_FALSE
);
199 ProcessContext(Context
);
205 ALAPI ALvoid ALAPIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
207 ALCcontext
*pContext
;
210 pContext
= GetContextSuspended();
211 if(!pContext
) return;
213 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
220 pSource
->flPitch
= flValue
;
221 if(pSource
->flPitch
< 0.001f
)
222 pSource
->flPitch
= 0.001f
;
223 pSource
->NeedsUpdate
= AL_TRUE
;
226 alSetError(pContext
, AL_INVALID_VALUE
);
229 case AL_CONE_INNER_ANGLE
:
230 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
232 pSource
->flInnerAngle
= flValue
;
233 pSource
->NeedsUpdate
= AL_TRUE
;
236 alSetError(pContext
, AL_INVALID_VALUE
);
239 case AL_CONE_OUTER_ANGLE
:
240 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
242 pSource
->flOuterAngle
= flValue
;
243 pSource
->NeedsUpdate
= AL_TRUE
;
246 alSetError(pContext
, AL_INVALID_VALUE
);
252 pSource
->flGain
= flValue
;
253 pSource
->NeedsUpdate
= AL_TRUE
;
256 alSetError(pContext
, AL_INVALID_VALUE
);
259 case AL_MAX_DISTANCE
:
262 pSource
->flMaxDistance
= flValue
;
263 pSource
->NeedsUpdate
= AL_TRUE
;
266 alSetError(pContext
, AL_INVALID_VALUE
);
269 case AL_ROLLOFF_FACTOR
:
272 pSource
->flRollOffFactor
= flValue
;
273 pSource
->NeedsUpdate
= AL_TRUE
;
276 alSetError(pContext
, AL_INVALID_VALUE
);
279 case AL_REFERENCE_DISTANCE
:
282 pSource
->flRefDistance
= flValue
;
283 pSource
->NeedsUpdate
= AL_TRUE
;
286 alSetError(pContext
, AL_INVALID_VALUE
);
290 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
292 pSource
->flMinGain
= flValue
;
293 pSource
->NeedsUpdate
= AL_TRUE
;
296 alSetError(pContext
, AL_INVALID_VALUE
);
300 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
302 pSource
->flMaxGain
= flValue
;
303 pSource
->NeedsUpdate
= AL_TRUE
;
306 alSetError(pContext
, AL_INVALID_VALUE
);
309 case AL_CONE_OUTER_GAIN
:
310 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
312 pSource
->flOuterGain
= flValue
;
313 pSource
->NeedsUpdate
= AL_TRUE
;
316 alSetError(pContext
, AL_INVALID_VALUE
);
319 case AL_CONE_OUTER_GAINHF
:
320 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
322 pSource
->OuterGainHF
= flValue
;
323 pSource
->NeedsUpdate
= AL_TRUE
;
326 alSetError(pContext
, AL_INVALID_VALUE
);
329 case AL_AIR_ABSORPTION_FACTOR
:
330 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
332 pSource
->AirAbsorptionFactor
= flValue
;
333 pSource
->NeedsUpdate
= AL_TRUE
;
336 alSetError(pContext
, AL_INVALID_VALUE
);
339 case AL_ROOM_ROLLOFF_FACTOR
:
340 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
342 pSource
->RoomRolloffFactor
= flValue
;
343 pSource
->NeedsUpdate
= AL_TRUE
;
346 alSetError(pContext
, AL_INVALID_VALUE
);
349 case AL_DOPPLER_FACTOR
:
350 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
352 pSource
->DopplerFactor
= flValue
;
353 pSource
->NeedsUpdate
= AL_TRUE
;
356 alSetError(pContext
, AL_INVALID_VALUE
);
360 case AL_SAMPLE_OFFSET
:
364 pSource
->lOffsetType
= eParam
;
366 // Store Offset (convert Seconds into Milliseconds)
367 if(eParam
== AL_SEC_OFFSET
)
368 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
370 pSource
->lOffset
= (ALint
)flValue
;
372 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
374 if(ApplyOffset(pSource
) == AL_FALSE
)
375 alSetError(pContext
, AL_INVALID_VALUE
);
379 alSetError(pContext
, AL_INVALID_VALUE
);
383 alSetError(pContext
, AL_INVALID_ENUM
);
389 // Invalid Source Name
390 alSetError(pContext
, AL_INVALID_NAME
);
393 ProcessContext(pContext
);
397 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
399 ALCcontext
*pContext
;
402 pContext
= GetContextSuspended();
403 if(!pContext
) return;
405 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
410 pSource
->vPosition
[0] = flValue1
;
411 pSource
->vPosition
[1] = flValue2
;
412 pSource
->vPosition
[2] = flValue3
;
413 pSource
->NeedsUpdate
= AL_TRUE
;
417 pSource
->vVelocity
[0] = flValue1
;
418 pSource
->vVelocity
[1] = flValue2
;
419 pSource
->vVelocity
[2] = flValue3
;
420 pSource
->NeedsUpdate
= AL_TRUE
;
424 pSource
->vOrientation
[0] = flValue1
;
425 pSource
->vOrientation
[1] = flValue2
;
426 pSource
->vOrientation
[2] = flValue3
;
427 pSource
->NeedsUpdate
= AL_TRUE
;
431 alSetError(pContext
, AL_INVALID_ENUM
);
436 alSetError(pContext
, AL_INVALID_NAME
);
438 ProcessContext(pContext
);
442 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
444 ALCcontext
*pContext
;
446 pContext
= GetContextSuspended();
447 if(!pContext
) return;
451 if(VerifySource(pContext
->SourceList
, source
) != NULL
)
456 case AL_CONE_INNER_ANGLE
:
457 case AL_CONE_OUTER_ANGLE
:
459 case AL_MAX_DISTANCE
:
460 case AL_ROLLOFF_FACTOR
:
461 case AL_REFERENCE_DISTANCE
:
464 case AL_CONE_OUTER_GAIN
:
465 case AL_CONE_OUTER_GAINHF
:
467 case AL_SAMPLE_OFFSET
:
469 case AL_AIR_ABSORPTION_FACTOR
:
470 case AL_ROOM_ROLLOFF_FACTOR
:
471 alSourcef(source
, eParam
, pflValues
[0]);
477 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
481 alSetError(pContext
, AL_INVALID_ENUM
);
486 alSetError(pContext
, AL_INVALID_NAME
);
489 alSetError(pContext
, AL_INVALID_VALUE
);
491 ProcessContext(pContext
);
495 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
497 ALCcontext
*pContext
;
499 ALbufferlistitem
*pALBufferListItem
;
501 pContext
= GetContextSuspended();
502 if(!pContext
) return;
504 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
506 ALCdevice
*device
= pContext
->Device
;
510 case AL_MAX_DISTANCE
:
511 case AL_ROLLOFF_FACTOR
:
512 case AL_CONE_INNER_ANGLE
:
513 case AL_CONE_OUTER_ANGLE
:
514 case AL_REFERENCE_DISTANCE
:
515 alSourcef(source
, eParam
, (ALfloat
)lValue
);
518 case AL_SOURCE_RELATIVE
:
519 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
521 pSource
->bHeadRelative
= (ALboolean
)lValue
;
522 pSource
->NeedsUpdate
= AL_TRUE
;
525 alSetError(pContext
, AL_INVALID_VALUE
);
529 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
530 pSource
->bLooping
= (ALboolean
)lValue
;
532 alSetError(pContext
, AL_INVALID_VALUE
);
536 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
538 ALbuffer
*buffer
= NULL
;
541 (buffer
=VerifyBuffer(device
->BufferList
, lValue
)) != NULL
)
543 // Remove all elements in the queue
544 while(pSource
->queue
!= NULL
)
546 pALBufferListItem
= pSource
->queue
;
547 pSource
->queue
= pALBufferListItem
->next
;
548 // Decrement reference counter for buffer
549 if(pALBufferListItem
->buffer
)
550 pALBufferListItem
->buffer
->refcount
--;
551 // Release memory for buffer list item
552 free(pALBufferListItem
);
553 // Decrement the number of buffers in the queue
554 pSource
->BuffersInQueue
--;
557 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
560 // Source is now in STATIC mode
561 pSource
->lSourceType
= AL_STATIC
;
563 // Add the selected buffer to the queue
564 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
565 pALBufferListItem
->buffer
= buffer
;
566 pALBufferListItem
->next
= NULL
;
568 pSource
->queue
= pALBufferListItem
;
569 pSource
->BuffersInQueue
= 1;
571 // Increment reference counter for buffer
576 // Source is now in UNDETERMINED mode
577 pSource
->lSourceType
= AL_UNDETERMINED
;
578 pSource
->BuffersPlayed
= 0;
581 // Update AL_BUFFER parameter
582 pSource
->Buffer
= buffer
;
583 pSource
->NeedsUpdate
= AL_TRUE
;
586 alSetError(pContext
, AL_INVALID_VALUE
);
589 alSetError(pContext
, AL_INVALID_OPERATION
);
592 case AL_SOURCE_STATE
:
594 alSetError(pContext
, AL_INVALID_OPERATION
);
598 case AL_SAMPLE_OFFSET
:
602 pSource
->lOffsetType
= eParam
;
604 // Store Offset (convert Seconds into Milliseconds)
605 if(eParam
== AL_SEC_OFFSET
)
606 pSource
->lOffset
= lValue
* 1000;
608 pSource
->lOffset
= lValue
;
610 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
612 if(ApplyOffset(pSource
) == AL_FALSE
)
613 alSetError(pContext
, AL_INVALID_VALUE
);
617 alSetError(pContext
, AL_INVALID_VALUE
);
620 case AL_DIRECT_FILTER
: {
621 ALfilter
*filter
= NULL
;
624 (filter
=VerifyFilter(pContext
->Device
->FilterList
, lValue
)) != NULL
)
628 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
629 pSource
->DirectFilter
.filter
= 0;
632 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
633 pSource
->NeedsUpdate
= AL_TRUE
;
636 alSetError(pContext
, AL_INVALID_VALUE
);
639 case AL_DIRECT_FILTER_GAINHF_AUTO
:
640 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
642 pSource
->DryGainHFAuto
= lValue
;
643 pSource
->NeedsUpdate
= AL_TRUE
;
646 alSetError(pContext
, AL_INVALID_VALUE
);
649 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
650 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
652 pSource
->WetGainAuto
= lValue
;
653 pSource
->NeedsUpdate
= AL_TRUE
;
656 alSetError(pContext
, AL_INVALID_VALUE
);
659 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
660 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
662 pSource
->WetGainHFAuto
= lValue
;
663 pSource
->NeedsUpdate
= AL_TRUE
;
666 alSetError(pContext
, AL_INVALID_VALUE
);
669 case AL_DISTANCE_MODEL
:
670 if(lValue
== AL_NONE
||
671 lValue
== AL_INVERSE_DISTANCE
||
672 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
673 lValue
== AL_LINEAR_DISTANCE
||
674 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
675 lValue
== AL_EXPONENT_DISTANCE
||
676 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
678 pSource
->DistanceModel
= lValue
;
679 if(pContext
->SourceDistanceModel
)
680 pSource
->NeedsUpdate
= AL_TRUE
;
683 alSetError(pContext
, AL_INVALID_VALUE
);
687 alSetError(pContext
, AL_INVALID_ENUM
);
692 alSetError(pContext
, AL_INVALID_NAME
);
694 ProcessContext(pContext
);
698 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
700 ALCcontext
*pContext
;
703 pContext
= GetContextSuspended();
704 if(!pContext
) return;
706 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
708 ALCdevice
*device
= pContext
->Device
;
715 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
718 case AL_AUXILIARY_SEND_FILTER
: {
719 ALeffectslot
*ALEffectSlot
= NULL
;
720 ALfilter
*ALFilter
= NULL
;
722 if((ALuint
)lValue2
< device
->NumAuxSends
&&
724 (ALEffectSlot
=VerifyEffectSlot(pContext
->EffectSlotList
, lValue1
)) != NULL
) &&
726 (ALFilter
=VerifyFilter(device
->FilterList
, lValue3
)) != NULL
))
728 /* Release refcount on the previous slot, and add one for
730 if(pSource
->Send
[lValue2
].Slot
)
731 pSource
->Send
[lValue2
].Slot
->refcount
--;
732 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
733 if(pSource
->Send
[lValue2
].Slot
)
734 pSource
->Send
[lValue2
].Slot
->refcount
++;
739 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
740 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
743 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
744 pSource
->NeedsUpdate
= AL_TRUE
;
747 alSetError(pContext
, AL_INVALID_VALUE
);
751 alSetError(pContext
, AL_INVALID_ENUM
);
756 alSetError(pContext
, AL_INVALID_NAME
);
758 ProcessContext(pContext
);
762 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
764 ALCcontext
*pContext
;
766 pContext
= GetContextSuspended();
767 if(!pContext
) return;
771 if(VerifySource(pContext
->SourceList
, source
) != NULL
)
775 case AL_SOURCE_RELATIVE
:
776 case AL_CONE_INNER_ANGLE
:
777 case AL_CONE_OUTER_ANGLE
:
780 case AL_SOURCE_STATE
:
782 case AL_SAMPLE_OFFSET
:
784 case AL_MAX_DISTANCE
:
785 case AL_ROLLOFF_FACTOR
:
786 case AL_REFERENCE_DISTANCE
:
787 case AL_DIRECT_FILTER
:
788 case AL_DIRECT_FILTER_GAINHF_AUTO
:
789 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
790 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
791 case AL_DISTANCE_MODEL
:
792 alSourcei(source
, eParam
, plValues
[0]);
798 case AL_AUXILIARY_SEND_FILTER
:
799 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
803 alSetError(pContext
, AL_INVALID_ENUM
);
808 alSetError(pContext
, AL_INVALID_NAME
);
811 alSetError(pContext
, AL_INVALID_VALUE
);
813 ProcessContext(pContext
);
817 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
819 ALCcontext
*pContext
;
824 pContext
= GetContextSuspended();
825 if(!pContext
) return;
829 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
834 *pflValue
= pSource
->flPitch
;
838 *pflValue
= pSource
->flGain
;
842 *pflValue
= pSource
->flMinGain
;
846 *pflValue
= pSource
->flMaxGain
;
849 case AL_MAX_DISTANCE
:
850 *pflValue
= pSource
->flMaxDistance
;
853 case AL_ROLLOFF_FACTOR
:
854 *pflValue
= pSource
->flRollOffFactor
;
857 case AL_CONE_OUTER_GAIN
:
858 *pflValue
= pSource
->flOuterGain
;
861 case AL_CONE_OUTER_GAINHF
:
862 *pflValue
= pSource
->OuterGainHF
;
866 case AL_SAMPLE_OFFSET
:
868 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
869 pContext
->Device
->Frequency
;
870 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
871 *pflValue
= flOffset
[0];
873 alSetError(pContext
, AL_INVALID_OPERATION
);
876 case AL_CONE_INNER_ANGLE
:
877 *pflValue
= pSource
->flInnerAngle
;
880 case AL_CONE_OUTER_ANGLE
:
881 *pflValue
= pSource
->flOuterAngle
;
884 case AL_REFERENCE_DISTANCE
:
885 *pflValue
= pSource
->flRefDistance
;
888 case AL_AIR_ABSORPTION_FACTOR
:
889 *pflValue
= pSource
->AirAbsorptionFactor
;
892 case AL_ROOM_ROLLOFF_FACTOR
:
893 *pflValue
= pSource
->RoomRolloffFactor
;
896 case AL_DOPPLER_FACTOR
:
897 *pflValue
= pSource
->DopplerFactor
;
901 alSetError(pContext
, AL_INVALID_ENUM
);
906 alSetError(pContext
, AL_INVALID_NAME
);
909 alSetError(pContext
, AL_INVALID_VALUE
);
911 ProcessContext(pContext
);
915 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
917 ALCcontext
*pContext
;
920 pContext
= GetContextSuspended();
921 if(!pContext
) return;
923 if(pflValue1
&& pflValue2
&& pflValue3
)
925 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
930 *pflValue1
= pSource
->vPosition
[0];
931 *pflValue2
= pSource
->vPosition
[1];
932 *pflValue3
= pSource
->vPosition
[2];
936 *pflValue1
= pSource
->vVelocity
[0];
937 *pflValue2
= pSource
->vVelocity
[1];
938 *pflValue3
= pSource
->vVelocity
[2];
942 *pflValue1
= pSource
->vOrientation
[0];
943 *pflValue2
= pSource
->vOrientation
[1];
944 *pflValue3
= pSource
->vOrientation
[2];
948 alSetError(pContext
, AL_INVALID_ENUM
);
953 alSetError(pContext
, AL_INVALID_NAME
);
956 alSetError(pContext
, AL_INVALID_VALUE
);
958 ProcessContext(pContext
);
962 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
964 ALCcontext
*pContext
;
969 pContext
= GetContextSuspended();
970 if(!pContext
) return;
974 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
982 case AL_MAX_DISTANCE
:
983 case AL_ROLLOFF_FACTOR
:
984 case AL_DOPPLER_FACTOR
:
985 case AL_CONE_OUTER_GAIN
:
987 case AL_SAMPLE_OFFSET
:
989 case AL_CONE_INNER_ANGLE
:
990 case AL_CONE_OUTER_ANGLE
:
991 case AL_REFERENCE_DISTANCE
:
992 case AL_CONE_OUTER_GAINHF
:
993 case AL_AIR_ABSORPTION_FACTOR
:
994 case AL_ROOM_ROLLOFF_FACTOR
:
995 alGetSourcef(source
, eParam
, pflValues
);
998 case AL_SAMPLE_RW_OFFSETS_EXT
:
999 case AL_BYTE_RW_OFFSETS_EXT
:
1000 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1001 pContext
->Device
->Frequency
;
1002 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1004 pflValues
[0] = flOffset
[0];
1005 pflValues
[1] = flOffset
[1];
1008 alSetError(pContext
, AL_INVALID_OPERATION
);
1012 pflValues
[0] = pSource
->vPosition
[0];
1013 pflValues
[1] = pSource
->vPosition
[1];
1014 pflValues
[2] = pSource
->vPosition
[2];
1018 pflValues
[0] = pSource
->vVelocity
[0];
1019 pflValues
[1] = pSource
->vVelocity
[1];
1020 pflValues
[2] = pSource
->vVelocity
[2];
1024 pflValues
[0] = pSource
->vOrientation
[0];
1025 pflValues
[1] = pSource
->vOrientation
[1];
1026 pflValues
[2] = pSource
->vOrientation
[2];
1030 alSetError(pContext
, AL_INVALID_ENUM
);
1035 alSetError(pContext
, AL_INVALID_NAME
);
1038 alSetError(pContext
, AL_INVALID_VALUE
);
1040 ProcessContext(pContext
);
1044 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1046 ALCcontext
*pContext
;
1048 ALfloat flOffset
[2];
1051 pContext
= GetContextSuspended();
1052 if(!pContext
) return;
1056 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1060 case AL_MAX_DISTANCE
:
1061 *plValue
= (ALint
)pSource
->flMaxDistance
;
1064 case AL_ROLLOFF_FACTOR
:
1065 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1068 case AL_REFERENCE_DISTANCE
:
1069 *plValue
= (ALint
)pSource
->flRefDistance
;
1072 case AL_SOURCE_RELATIVE
:
1073 *plValue
= pSource
->bHeadRelative
;
1076 case AL_CONE_INNER_ANGLE
:
1077 *plValue
= (ALint
)pSource
->flInnerAngle
;
1080 case AL_CONE_OUTER_ANGLE
:
1081 *plValue
= (ALint
)pSource
->flOuterAngle
;
1085 *plValue
= pSource
->bLooping
;
1089 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1092 case AL_SOURCE_STATE
:
1093 *plValue
= pSource
->state
;
1096 case AL_BUFFERS_QUEUED
:
1097 *plValue
= pSource
->BuffersInQueue
;
1100 case AL_BUFFERS_PROCESSED
:
1101 if(pSource
->bLooping
)
1103 /* Buffers on a looping source are in a perpetual state
1104 * of PENDING, so don't report any as PROCESSED */
1108 *plValue
= pSource
->BuffersPlayed
;
1111 case AL_SOURCE_TYPE
:
1112 *plValue
= pSource
->lSourceType
;
1116 case AL_SAMPLE_OFFSET
:
1117 case AL_BYTE_OFFSET
:
1118 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1119 pContext
->Device
->Frequency
;
1120 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1121 *plValue
= (ALint
)flOffset
[0];
1123 alSetError(pContext
, AL_INVALID_OPERATION
);
1126 case AL_DIRECT_FILTER
:
1127 *plValue
= pSource
->DirectFilter
.filter
;
1130 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1131 *plValue
= pSource
->DryGainHFAuto
;
1134 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1135 *plValue
= pSource
->WetGainAuto
;
1138 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1139 *plValue
= pSource
->WetGainHFAuto
;
1142 case AL_DOPPLER_FACTOR
:
1143 *plValue
= (ALint
)pSource
->DopplerFactor
;
1146 case AL_DISTANCE_MODEL
:
1147 *plValue
= pSource
->DistanceModel
;
1151 alSetError(pContext
, AL_INVALID_ENUM
);
1156 alSetError(pContext
, AL_INVALID_NAME
);
1159 alSetError(pContext
, AL_INVALID_VALUE
);
1161 ProcessContext(pContext
);
1165 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1167 ALCcontext
*pContext
;
1170 pContext
= GetContextSuspended();
1171 if(!pContext
) return;
1173 if(plValue1
&& plValue2
&& plValue3
)
1175 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1180 *plValue1
= (ALint
)pSource
->vPosition
[0];
1181 *plValue2
= (ALint
)pSource
->vPosition
[1];
1182 *plValue3
= (ALint
)pSource
->vPosition
[2];
1186 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1187 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1188 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1192 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1193 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1194 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1198 alSetError(pContext
, AL_INVALID_ENUM
);
1203 alSetError(pContext
, AL_INVALID_NAME
);
1206 alSetError(pContext
, AL_INVALID_VALUE
);
1208 ProcessContext(pContext
);
1212 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1214 ALCcontext
*pContext
;
1216 ALfloat flOffset
[2];
1219 pContext
= GetContextSuspended();
1220 if(!pContext
) return;
1224 if((pSource
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1228 case AL_SOURCE_RELATIVE
:
1229 case AL_CONE_INNER_ANGLE
:
1230 case AL_CONE_OUTER_ANGLE
:
1233 case AL_SOURCE_STATE
:
1234 case AL_BUFFERS_QUEUED
:
1235 case AL_BUFFERS_PROCESSED
:
1237 case AL_SAMPLE_OFFSET
:
1238 case AL_BYTE_OFFSET
:
1239 case AL_MAX_DISTANCE
:
1240 case AL_ROLLOFF_FACTOR
:
1241 case AL_DOPPLER_FACTOR
:
1242 case AL_REFERENCE_DISTANCE
:
1243 case AL_SOURCE_TYPE
:
1244 case AL_DIRECT_FILTER
:
1245 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1246 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1247 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1248 case AL_DISTANCE_MODEL
:
1249 alGetSourcei(source
, eParam
, plValues
);
1252 case AL_SAMPLE_RW_OFFSETS_EXT
:
1253 case AL_BYTE_RW_OFFSETS_EXT
:
1254 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1255 pContext
->Device
->Frequency
;
1256 if(GetSourceOffset(pSource
, eParam
, flOffset
, updateLen
))
1258 plValues
[0] = (ALint
)flOffset
[0];
1259 plValues
[1] = (ALint
)flOffset
[1];
1262 alSetError(pContext
, AL_INVALID_OPERATION
);
1266 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1267 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1268 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1272 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1273 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1274 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1278 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1279 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1280 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1284 alSetError(pContext
, AL_INVALID_ENUM
);
1289 alSetError(pContext
, AL_INVALID_NAME
);
1292 alSetError(pContext
, AL_INVALID_VALUE
);
1294 ProcessContext(pContext
);
1298 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1300 alSourcePlayv(1, &source
);
1303 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1305 ALCcontext
*pContext
;
1307 ALbufferlistitem
*ALBufferList
;
1308 ALboolean bSourcesValid
= AL_TRUE
;
1312 pContext
= GetContextSuspended();
1313 if(!pContext
) return;
1317 // Check that all the Sources are valid
1318 for(i
= 0; i
< n
; i
++)
1320 if(!VerifySource(pContext
->SourceList
, pSourceList
[i
]))
1322 alSetError(pContext
, AL_INVALID_NAME
);
1323 bSourcesValid
= AL_FALSE
;
1330 for(i
= 0; i
< n
; i
++)
1332 // Assume Source won't need to play
1335 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1337 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1338 ALBufferList
= pSource
->queue
;
1341 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1346 ALBufferList
= ALBufferList
->next
;
1351 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1352 pSource
->DryGains
[j
] = 0.0f
;
1353 for(j
= 0;j
< MAX_SENDS
;j
++)
1354 pSource
->WetGains
[j
] = 0.0f
;
1356 if(pSource
->state
!= AL_PAUSED
)
1358 pSource
->state
= AL_PLAYING
;
1359 pSource
->position
= 0;
1360 pSource
->position_fraction
= 0;
1361 pSource
->BuffersPlayed
= 0;
1363 pSource
->Buffer
= pSource
->queue
->buffer
;
1366 pSource
->state
= AL_PLAYING
;
1368 // Check if an Offset has been set
1369 if(pSource
->lOffset
)
1370 ApplyOffset(pSource
);
1372 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1373 pSource
->position_fraction
== 0)
1374 pSource
->FirstStart
= AL_TRUE
;
1376 pSource
->FirstStart
= AL_FALSE
;
1378 // If device is disconnected, go right to stopped
1379 if(!pContext
->Device
->Connected
)
1381 pSource
->state
= AL_STOPPED
;
1382 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1383 pSource
->position
= 0;
1384 pSource
->position_fraction
= 0;
1388 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1394 // sources is a NULL pointer
1395 alSetError(pContext
, AL_INVALID_VALUE
);
1398 ProcessContext(pContext
);
1401 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1403 alSourcePausev(1, &source
);
1406 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1408 ALCcontext
*Context
;
1411 ALboolean bSourcesValid
= AL_TRUE
;
1413 Context
= GetContextSuspended();
1414 if(!Context
) return;
1418 // Check all the Sources are valid
1421 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1423 alSetError(Context
, AL_INVALID_NAME
);
1424 bSourcesValid
= AL_FALSE
;
1431 for(i
= 0;i
< n
;i
++)
1433 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1434 if(Source
->state
== AL_PLAYING
)
1435 Source
->state
= AL_PAUSED
;
1441 // sources is a NULL pointer
1442 alSetError(Context
, AL_INVALID_VALUE
);
1445 ProcessContext(Context
);
1448 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1450 alSourceStopv(1, &source
);
1453 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1455 ALCcontext
*Context
;
1458 ALboolean bSourcesValid
= AL_TRUE
;
1460 Context
= GetContextSuspended();
1461 if(!Context
) return;
1465 // Check all the Sources are valid
1466 for(i
= 0;i
< n
;i
++)
1468 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1470 alSetError(Context
, AL_INVALID_NAME
);
1471 bSourcesValid
= AL_FALSE
;
1478 for(i
= 0;i
< n
;i
++)
1480 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1481 if(Source
->state
!= AL_INITIAL
)
1483 Source
->state
= AL_STOPPED
;
1484 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1486 Source
->lOffset
= 0;
1492 // sources is a NULL pointer
1493 alSetError(Context
, AL_INVALID_VALUE
);
1496 ProcessContext(Context
);
1499 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1501 alSourceRewindv(1, &source
);
1504 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1506 ALCcontext
*Context
;
1509 ALboolean bSourcesValid
= AL_TRUE
;
1511 Context
= GetContextSuspended();
1512 if(!Context
) return;
1516 // Check all the Sources are valid
1517 for(i
= 0;i
< n
;i
++)
1519 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1521 alSetError(Context
, AL_INVALID_NAME
);
1522 bSourcesValid
= AL_FALSE
;
1529 for(i
= 0;i
< n
;i
++)
1531 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1532 if(Source
->state
!= AL_INITIAL
)
1534 Source
->state
= AL_INITIAL
;
1535 Source
->position
= 0;
1536 Source
->position_fraction
= 0;
1537 Source
->BuffersPlayed
= 0;
1539 Source
->Buffer
= Source
->queue
->buffer
;
1541 Source
->lOffset
= 0;
1547 // sources is a NULL pointer
1548 alSetError(Context
, AL_INVALID_VALUE
);
1551 ProcessContext(Context
);
1555 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1557 ALCcontext
*Context
;
1560 ALbufferlistitem
*ALBufferList
;
1561 ALbufferlistitem
*ALBufferListStart
;
1564 ALboolean bBuffersValid
= AL_TRUE
;
1565 ALboolean hadFormat
= AL_FALSE
;
1570 Context
= GetContextSuspended();
1571 if(!Context
) return;
1573 // Check that all buffers are valid or zero and that the source is valid
1575 // Check that this is a valid source
1576 if((ALSource
=VerifySource(Context
->SourceList
, source
)) != NULL
)
1578 // Check that this is not a STATIC Source
1579 if(ALSource
->lSourceType
!= AL_STATIC
)
1581 ALCdevice
*device
= Context
->Device
;
1586 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1587 ALBufferList
= ALSource
->queue
;
1590 if (ALBufferList
->buffer
)
1592 iFrequency
= ALBufferList
->buffer
->frequency
;
1593 iFormat
= ALBufferList
->buffer
->format
;
1594 hadFormat
= AL_TRUE
;
1597 ALBufferList
= ALBufferList
->next
;
1600 for(i
= 0; i
< n
; i
++)
1607 if((buffer
=VerifyBuffer(device
->BufferList
, buffers
[i
])) == NULL
)
1609 alSetError(Context
, AL_INVALID_NAME
);
1610 bBuffersValid
= AL_FALSE
;
1614 if(iFrequency
== -1 && iFormat
== -1)
1616 iFrequency
= buffer
->frequency
;
1617 iFormat
= buffer
->format
;
1619 else if(iFrequency
!= buffer
->frequency
||
1620 iFormat
!= buffer
->format
)
1622 alSetError(Context
, AL_INVALID_OPERATION
);
1623 bBuffersValid
= AL_FALSE
;
1632 // Change Source Type
1633 ALSource
->lSourceType
= AL_STREAMING
;
1635 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1637 // All buffers are valid - so add them to the list
1638 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1639 ALBufferListStart
->buffer
= buffer
;
1640 ALBufferListStart
->next
= NULL
;
1642 // Increment reference counter for buffer
1643 if(buffer
) buffer
->refcount
++;
1645 ALBufferList
= ALBufferListStart
;
1647 for(i
= 1; i
< n
; i
++)
1649 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1651 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1652 ALBufferList
->next
->buffer
= buffer
;
1653 ALBufferList
->next
->next
= NULL
;
1655 // Increment reference counter for buffer
1656 if(buffer
) buffer
->refcount
++;
1658 ALBufferList
= ALBufferList
->next
;
1661 if(ALSource
->queue
== NULL
)
1663 ALSource
->queue
= ALBufferListStart
;
1664 // Update Current Buffer
1665 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1669 // Find end of queue
1670 ALBufferList
= ALSource
->queue
;
1671 while(ALBufferList
->next
!= NULL
)
1672 ALBufferList
= ALBufferList
->next
;
1674 ALBufferList
->next
= ALBufferListStart
;
1677 // Update number of buffers in queue
1678 ALSource
->BuffersInQueue
+= n
;
1679 // If no previous format, mark the source dirty now that it may
1682 ALSource
->NeedsUpdate
= AL_TRUE
;
1687 // Invalid Source Type (can't queue on a Static Source)
1688 alSetError(Context
, AL_INVALID_OPERATION
);
1693 // Invalid Source Name
1694 alSetError(Context
, AL_INVALID_NAME
);
1697 ProcessContext(Context
);
1701 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1702 // an array of buffer IDs that are to be filled with the names of the buffers removed
1703 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1705 ALCcontext
*Context
;
1708 ALbufferlistitem
*ALBufferList
;
1709 ALboolean bBuffersProcessed
;
1714 bBuffersProcessed
= AL_TRUE
;
1716 Context
= GetContextSuspended();
1717 if(!Context
) return;
1719 if((ALSource
=VerifySource(Context
->SourceList
, source
)) != NULL
)
1721 // If all 'n' buffers have been processed, remove them from the queue
1722 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1724 for(i
= 0; i
< n
; i
++)
1726 ALBufferList
= ALSource
->queue
;
1728 ALSource
->queue
= ALBufferList
->next
;
1729 if(ALBufferList
->buffer
)
1731 // Record name of buffer
1732 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1733 // Decrement buffer reference counter
1734 ALBufferList
->buffer
->refcount
--;
1739 // Release memory for buffer list item
1741 ALSource
->BuffersInQueue
--;
1744 if(ALSource
->state
!= AL_PLAYING
)
1747 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1749 ALSource
->Buffer
= NULL
;
1752 ALSource
->BuffersPlayed
-= n
;
1756 // Some buffers can't be unqueue because they have not been processed
1757 alSetError(Context
, AL_INVALID_VALUE
);
1762 // Invalid Source Name
1763 alSetError(Context
, AL_INVALID_NAME
);
1766 ProcessContext(Context
);
1770 static ALvoid
InitSourceParams(ALsource
*pSource
)
1772 pSource
->flInnerAngle
= 360.0f
;
1773 pSource
->flOuterAngle
= 360.0f
;
1774 pSource
->flPitch
= 1.0f
;
1775 pSource
->vPosition
[0] = 0.0f
;
1776 pSource
->vPosition
[1] = 0.0f
;
1777 pSource
->vPosition
[2] = 0.0f
;
1778 pSource
->vOrientation
[0] = 0.0f
;
1779 pSource
->vOrientation
[1] = 0.0f
;
1780 pSource
->vOrientation
[2] = 0.0f
;
1781 pSource
->vVelocity
[0] = 0.0f
;
1782 pSource
->vVelocity
[1] = 0.0f
;
1783 pSource
->vVelocity
[2] = 0.0f
;
1784 pSource
->flRefDistance
= 1.0f
;
1785 pSource
->flMaxDistance
= FLT_MAX
;
1786 pSource
->flRollOffFactor
= 1.0f
;
1787 pSource
->bLooping
= AL_FALSE
;
1788 pSource
->flGain
= 1.0f
;
1789 pSource
->flMinGain
= 0.0f
;
1790 pSource
->flMaxGain
= 1.0f
;
1791 pSource
->flOuterGain
= 0.0f
;
1792 pSource
->OuterGainHF
= 1.0f
;
1794 pSource
->DryGainHFAuto
= AL_TRUE
;
1795 pSource
->WetGainAuto
= AL_TRUE
;
1796 pSource
->WetGainHFAuto
= AL_TRUE
;
1797 pSource
->AirAbsorptionFactor
= 0.0f
;
1798 pSource
->RoomRolloffFactor
= 0.0f
;
1799 pSource
->DopplerFactor
= 1.0f
;
1801 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1803 pSource
->Resampler
= DefaultResampler
;
1805 pSource
->state
= AL_INITIAL
;
1806 pSource
->lSourceType
= AL_UNDETERMINED
;
1808 pSource
->NeedsUpdate
= AL_TRUE
;
1810 pSource
->Buffer
= NULL
;
1817 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1818 The offset is relative to the start of the queue (not the start of the current buffer)
1820 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
)
1822 ALbufferlistitem
*pBufferList
;
1824 ALfloat flBufferFreq
;
1825 ALint lChannels
, lBytes
;
1826 ALint readPos
, writePos
;
1827 ALenum eOriginalFormat
;
1828 ALboolean bReturn
= AL_TRUE
;
1829 ALint lTotalBufferDataSize
;
1832 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1834 pBuffer
= pSource
->Buffer
;
1835 // Get Current Buffer Size and frequency (in milliseconds)
1836 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1837 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1838 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1839 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1841 // Get Current BytesPlayed
1842 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1843 // Add byte length of any processed buffers in the queue
1844 pBufferList
= pSource
->queue
;
1845 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1847 readPos
+= pBufferList
->buffer
->size
;
1848 pBufferList
= pBufferList
->next
;
1851 if(pSource
->state
== AL_PLAYING
)
1852 writePos
= readPos
+ ((ALuint
)(updateLen
*flBufferFreq
) * lChannels
* lBytes
);
1856 lTotalBufferDataSize
= 0;
1857 pBufferList
= pSource
->queue
;
1860 if (pBufferList
->buffer
)
1861 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1862 pBufferList
= pBufferList
->next
;
1865 if (pSource
->bLooping
)
1870 readPos
%= lTotalBufferDataSize
;
1874 writePos
%= lTotalBufferDataSize
;
1878 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1881 else if(readPos
> lTotalBufferDataSize
)
1882 readPos
= lTotalBufferDataSize
;
1885 else if(writePos
> lTotalBufferDataSize
)
1886 writePos
= lTotalBufferDataSize
;
1892 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1893 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1895 case AL_SAMPLE_OFFSET
:
1896 case AL_SAMPLE_RW_OFFSETS_EXT
:
1897 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1898 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1900 case AL_BYTE_OFFSET
:
1901 case AL_BYTE_RW_OFFSETS_EXT
:
1902 // Take into account the original format of the Buffer
1903 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1904 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1906 // Round down to nearest ADPCM block
1907 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1908 if(pSource
->state
== AL_PLAYING
)
1910 // Round up to nearest ADPCM block
1911 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1914 pflOffset
[1] = pflOffset
[0];
1916 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1918 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1919 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1921 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1923 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1924 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1926 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1928 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1929 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1933 ALuint OrigBytes
= aluBytesFromFormat(eOriginalFormat
);
1934 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* OrigBytes
);
1935 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* OrigBytes
);
1942 pflOffset
[0] = 0.0f
;
1943 pflOffset
[1] = 0.0f
;
1953 Apply a playback offset to the Source. This function will update the queue (to correctly
1954 mark buffers as 'pending' or 'processed' depending upon the new offset.
1956 static ALboolean
ApplyOffset(ALsource
*pSource
)
1958 ALbufferlistitem
*pBufferList
;
1960 ALint lBufferSize
, lTotalBufferSize
;
1963 // Get true byte offset
1964 lByteOffset
= GetByteOffset(pSource
);
1966 // If the offset is invalid, don't apply it
1967 if(lByteOffset
== -1)
1970 // Sort out the queue (pending and processed states)
1971 pBufferList
= pSource
->queue
;
1972 lTotalBufferSize
= 0;
1973 pSource
->BuffersPlayed
= 0;
1977 pBuffer
= pBufferList
->buffer
;
1978 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
1980 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1982 // Offset is past this buffer so increment BuffersPlayed
1983 pSource
->BuffersPlayed
++;
1985 else if(lTotalBufferSize
<= lByteOffset
)
1987 // Offset is within this buffer
1988 // Set Current Buffer
1989 pSource
->Buffer
= pBufferList
->buffer
;
1991 // SW Mixer Positions are in Samples
1992 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
1993 aluBytesFromFormat(pBuffer
->format
) /
1994 aluChannelsFromFormat(pBuffer
->format
);
1998 // Increment the TotalBufferSize
1999 lTotalBufferSize
+= lBufferSize
;
2001 // Move on to next buffer in the Queue
2002 pBufferList
= pBufferList
->next
;
2012 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2013 offset supplied by the application). This takes into account the fact that the buffer format
2014 may have been modifed by AL (e.g 8bit samples are converted to float)
2016 static ALint
GetByteOffset(ALsource
*pSource
)
2018 ALbuffer
*pBuffer
= NULL
;
2019 ALbufferlistitem
*pBufferList
;
2020 ALfloat flBufferFreq
;
2021 ALint lChannels
, lBytes
;
2022 ALint lByteOffset
= -1;
2023 ALint lTotalBufferDataSize
;
2024 ALenum OriginalFormat
;
2026 // Find the first non-NULL Buffer in the Queue
2027 pBufferList
= pSource
->queue
;
2030 if (pBufferList
->buffer
)
2032 pBuffer
= pBufferList
->buffer
;
2035 pBufferList
= pBufferList
->next
;
2040 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2041 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2042 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2043 OriginalFormat
= pBuffer
->eOriginalFormat
;
2045 // Determine the ByteOffset (and ensure it is block aligned)
2046 switch (pSource
->lOffsetType
)
2048 case AL_BYTE_OFFSET
:
2049 // Take into consideration the original format
2050 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2051 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2053 // Round down to nearest ADPCM block
2054 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2055 // Multiply by compression rate
2056 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2057 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2059 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2061 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2062 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2064 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2066 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2067 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2069 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2071 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2072 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2076 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2077 lByteOffset
= pSource
->lOffset
/ OrigBytes
* lBytes
;
2078 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2082 case AL_SAMPLE_OFFSET
:
2083 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2087 // Note - lOffset is internally stored as Milliseconds
2088 lByteOffset
= (ALint
)(pSource
->lOffset
/ 1000.0f
* flBufferFreq
);
2089 lByteOffset
*= lChannels
* lBytes
;
2093 lTotalBufferDataSize
= 0;
2094 pBufferList
= pSource
->queue
;
2097 if (pBufferList
->buffer
)
2098 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2099 pBufferList
= pBufferList
->next
;
2102 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2103 if (lByteOffset
>= lTotalBufferDataSize
)
2108 pSource
->lOffset
= 0;
2114 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2118 while(Context
->SourceList
)
2120 ALsource
*temp
= Context
->SourceList
;
2121 Context
->SourceList
= temp
->next
;
2123 // For each buffer in the source's queue, decrement its reference counter and remove it
2124 while(temp
->queue
!= NULL
)
2126 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2127 // Decrement buffer's reference counter
2128 if(ALBufferList
->buffer
!= NULL
)
2129 ALBufferList
->buffer
->refcount
--;
2130 // Update queue to point to next element in list
2131 temp
->queue
= ALBufferList
->next
;
2132 // Release memory allocated for buffer list item
2136 for(j
= 0;j
< MAX_SENDS
;++j
)
2138 if(temp
->Send
[j
].Slot
)
2139 temp
->Send
[j
].Slot
->refcount
--;
2142 // Release source structure
2143 ALTHUNK_REMOVEENTRY(temp
->source
);
2144 memset(temp
, 0, sizeof(ALsource
));
2147 Context
->SourceCount
= 0;