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
*Source
);
36 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum eName
, ALdouble
*Offsets
, ALdouble updateLen
);
37 static ALboolean
ApplyOffset(ALsource
*Source
);
38 static ALint
GetByteOffset(ALsource
*Source
);
39 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
);
41 DECL_VERIFIER(Filter
, ALfilter
, filter
)
43 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
44 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
45 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
47 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
53 Context
= GetContextSuspended();
58 Device
= Context
->Device
;
60 // Check that enough memory has been allocted in the 'sources' array for n Sources
61 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
63 // Check that the requested number of sources can be generated
64 if((Context
->SourceMap
.size
+ n
) <= (ALsizei
)Device
->MaxNoOfSources
)
68 // Add additional sources to the list
71 ALsource
*source
= calloc(1, sizeof(ALsource
));
74 alSetError(Context
, AL_OUT_OF_MEMORY
);
75 alDeleteSources(i
, sources
);
79 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
80 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
82 if(err
!= AL_NO_ERROR
)
84 ALTHUNK_REMOVEENTRY(source
->source
);
85 memset(source
, 0, sizeof(ALsource
));
88 alSetError(Context
, err
);
89 alDeleteSources(i
, sources
);
93 sources
[i
++] = source
->source
;
94 InitSourceParams(source
);
99 // Not enough resources to create the Sources
100 alSetError(Context
, AL_INVALID_VALUE
);
106 alSetError(Context
, AL_INVALID_VALUE
);
110 ProcessContext(Context
);
114 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
120 ALbufferlistitem
*BufferList
;
121 ALboolean bSourcesValid
= AL_TRUE
;
123 Context
= GetContextSuspended();
128 Device
= Context
->Device
;
130 // Check that all Sources are valid (and can therefore be deleted)
131 for (i
= 0; i
< n
; i
++)
133 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
135 alSetError(Context
, AL_INVALID_NAME
);
136 bSourcesValid
= AL_FALSE
;
143 // All Sources are valid, and can be deleted
144 for(i
= 0; i
< n
; i
++)
146 // Recheck that the Source is valid, because there could be duplicated Source names
147 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) != NULL
)
149 // For each buffer in the source's queue, decrement its reference counter and remove it
150 while(Source
->queue
!= NULL
)
152 BufferList
= Source
->queue
;
153 // Decrement buffer's reference counter
154 if(BufferList
->buffer
!= NULL
)
155 BufferList
->buffer
->refcount
--;
156 // Update queue to point to next element in list
157 Source
->queue
= BufferList
->next
;
158 // Release memory allocated for buffer list item
162 for(j
= 0;j
< MAX_SENDS
;++j
)
164 if(Source
->Send
[j
].Slot
)
165 Source
->Send
[j
].Slot
->refcount
--;
166 Source
->Send
[j
].Slot
= NULL
;
169 // Remove Source from list of Sources
170 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
171 ALTHUNK_REMOVEENTRY(Source
->source
);
173 memset(Source
,0,sizeof(ALsource
));
180 alSetError(Context
, AL_INVALID_VALUE
);
182 ProcessContext(Context
);
186 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
191 Context
= GetContextSuspended();
192 if(!Context
) return AL_FALSE
;
194 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
196 ProcessContext(Context
);
202 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
204 ALCcontext
*pContext
;
207 pContext
= GetContextSuspended();
208 if(!pContext
) return;
210 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
217 Source
->flPitch
= flValue
;
218 if(Source
->flPitch
< 0.001f
)
219 Source
->flPitch
= 0.001f
;
220 Source
->NeedsUpdate
= AL_TRUE
;
223 alSetError(pContext
, AL_INVALID_VALUE
);
226 case AL_CONE_INNER_ANGLE
:
227 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
229 Source
->flInnerAngle
= flValue
;
230 Source
->NeedsUpdate
= AL_TRUE
;
233 alSetError(pContext
, AL_INVALID_VALUE
);
236 case AL_CONE_OUTER_ANGLE
:
237 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
239 Source
->flOuterAngle
= flValue
;
240 Source
->NeedsUpdate
= AL_TRUE
;
243 alSetError(pContext
, AL_INVALID_VALUE
);
249 Source
->flGain
= flValue
;
250 Source
->NeedsUpdate
= AL_TRUE
;
253 alSetError(pContext
, AL_INVALID_VALUE
);
256 case AL_MAX_DISTANCE
:
259 Source
->flMaxDistance
= flValue
;
260 Source
->NeedsUpdate
= AL_TRUE
;
263 alSetError(pContext
, AL_INVALID_VALUE
);
266 case AL_ROLLOFF_FACTOR
:
269 Source
->flRollOffFactor
= flValue
;
270 Source
->NeedsUpdate
= AL_TRUE
;
273 alSetError(pContext
, AL_INVALID_VALUE
);
276 case AL_REFERENCE_DISTANCE
:
279 Source
->flRefDistance
= flValue
;
280 Source
->NeedsUpdate
= AL_TRUE
;
283 alSetError(pContext
, AL_INVALID_VALUE
);
287 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
289 Source
->flMinGain
= flValue
;
290 Source
->NeedsUpdate
= AL_TRUE
;
293 alSetError(pContext
, AL_INVALID_VALUE
);
297 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
299 Source
->flMaxGain
= flValue
;
300 Source
->NeedsUpdate
= AL_TRUE
;
303 alSetError(pContext
, AL_INVALID_VALUE
);
306 case AL_CONE_OUTER_GAIN
:
307 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
309 Source
->flOuterGain
= flValue
;
310 Source
->NeedsUpdate
= AL_TRUE
;
313 alSetError(pContext
, AL_INVALID_VALUE
);
316 case AL_CONE_OUTER_GAINHF
:
317 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
319 Source
->OuterGainHF
= flValue
;
320 Source
->NeedsUpdate
= AL_TRUE
;
323 alSetError(pContext
, AL_INVALID_VALUE
);
326 case AL_AIR_ABSORPTION_FACTOR
:
327 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
329 Source
->AirAbsorptionFactor
= flValue
;
330 Source
->NeedsUpdate
= AL_TRUE
;
333 alSetError(pContext
, AL_INVALID_VALUE
);
336 case AL_ROOM_ROLLOFF_FACTOR
:
337 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
339 Source
->RoomRolloffFactor
= flValue
;
340 Source
->NeedsUpdate
= AL_TRUE
;
343 alSetError(pContext
, AL_INVALID_VALUE
);
346 case AL_DOPPLER_FACTOR
:
347 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
349 Source
->DopplerFactor
= flValue
;
350 Source
->NeedsUpdate
= AL_TRUE
;
353 alSetError(pContext
, AL_INVALID_VALUE
);
357 case AL_SAMPLE_OFFSET
:
361 Source
->lOffsetType
= eParam
;
363 // Store Offset (convert Seconds into Milliseconds)
364 if(eParam
== AL_SEC_OFFSET
)
365 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
367 Source
->lOffset
= (ALint
)flValue
;
369 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
371 if(ApplyOffset(Source
) == AL_FALSE
)
372 alSetError(pContext
, AL_INVALID_VALUE
);
376 alSetError(pContext
, AL_INVALID_VALUE
);
380 alSetError(pContext
, AL_INVALID_ENUM
);
386 // Invalid Source Name
387 alSetError(pContext
, AL_INVALID_NAME
);
390 ProcessContext(pContext
);
394 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
396 ALCcontext
*pContext
;
399 pContext
= GetContextSuspended();
400 if(!pContext
) return;
402 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
407 Source
->vPosition
[0] = flValue1
;
408 Source
->vPosition
[1] = flValue2
;
409 Source
->vPosition
[2] = flValue3
;
410 Source
->NeedsUpdate
= AL_TRUE
;
414 Source
->vVelocity
[0] = flValue1
;
415 Source
->vVelocity
[1] = flValue2
;
416 Source
->vVelocity
[2] = flValue3
;
417 Source
->NeedsUpdate
= AL_TRUE
;
421 Source
->vOrientation
[0] = flValue1
;
422 Source
->vOrientation
[1] = flValue2
;
423 Source
->vOrientation
[2] = flValue3
;
424 Source
->NeedsUpdate
= AL_TRUE
;
428 alSetError(pContext
, AL_INVALID_ENUM
);
433 alSetError(pContext
, AL_INVALID_NAME
);
435 ProcessContext(pContext
);
439 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
441 ALCcontext
*pContext
;
443 pContext
= GetContextSuspended();
444 if(!pContext
) return;
448 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
453 case AL_CONE_INNER_ANGLE
:
454 case AL_CONE_OUTER_ANGLE
:
456 case AL_MAX_DISTANCE
:
457 case AL_ROLLOFF_FACTOR
:
458 case AL_REFERENCE_DISTANCE
:
461 case AL_CONE_OUTER_GAIN
:
462 case AL_CONE_OUTER_GAINHF
:
464 case AL_SAMPLE_OFFSET
:
466 case AL_AIR_ABSORPTION_FACTOR
:
467 case AL_ROOM_ROLLOFF_FACTOR
:
468 alSourcef(source
, eParam
, pflValues
[0]);
474 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
478 alSetError(pContext
, AL_INVALID_ENUM
);
483 alSetError(pContext
, AL_INVALID_NAME
);
486 alSetError(pContext
, AL_INVALID_VALUE
);
488 ProcessContext(pContext
);
492 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
494 ALCcontext
*pContext
;
496 ALbufferlistitem
*BufferListItem
;
498 pContext
= GetContextSuspended();
499 if(!pContext
) return;
501 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
503 ALCdevice
*device
= pContext
->Device
;
507 case AL_MAX_DISTANCE
:
508 case AL_ROLLOFF_FACTOR
:
509 case AL_CONE_INNER_ANGLE
:
510 case AL_CONE_OUTER_ANGLE
:
511 case AL_REFERENCE_DISTANCE
:
512 alSourcef(source
, eParam
, (ALfloat
)lValue
);
515 case AL_SOURCE_RELATIVE
:
516 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
518 Source
->bHeadRelative
= (ALboolean
)lValue
;
519 Source
->NeedsUpdate
= AL_TRUE
;
522 alSetError(pContext
, AL_INVALID_VALUE
);
526 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
527 Source
->bLooping
= (ALboolean
)lValue
;
529 alSetError(pContext
, AL_INVALID_VALUE
);
533 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
535 ALbuffer
*buffer
= NULL
;
538 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
540 // Remove all elements in the queue
541 while(Source
->queue
!= NULL
)
543 BufferListItem
= Source
->queue
;
544 Source
->queue
= BufferListItem
->next
;
545 // Decrement reference counter for buffer
546 if(BufferListItem
->buffer
)
547 BufferListItem
->buffer
->refcount
--;
548 // Release memory for buffer list item
549 free(BufferListItem
);
550 // Decrement the number of buffers in the queue
551 Source
->BuffersInQueue
--;
554 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
557 // Source is now in STATIC mode
558 Source
->lSourceType
= AL_STATIC
;
560 // Add the selected buffer to the queue
561 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
562 BufferListItem
->buffer
= buffer
;
563 BufferListItem
->next
= NULL
;
565 Source
->queue
= BufferListItem
;
566 Source
->BuffersInQueue
= 1;
568 // Increment reference counter for buffer
573 // Source is now in UNDETERMINED mode
574 Source
->lSourceType
= AL_UNDETERMINED
;
576 Source
->BuffersPlayed
= 0;
578 // Update AL_BUFFER parameter
579 Source
->Buffer
= buffer
;
580 Source
->NeedsUpdate
= AL_TRUE
;
583 alSetError(pContext
, AL_INVALID_VALUE
);
586 alSetError(pContext
, AL_INVALID_OPERATION
);
589 case AL_SOURCE_STATE
:
591 alSetError(pContext
, AL_INVALID_OPERATION
);
595 case AL_SAMPLE_OFFSET
:
599 Source
->lOffsetType
= eParam
;
601 // Store Offset (convert Seconds into Milliseconds)
602 if(eParam
== AL_SEC_OFFSET
)
603 Source
->lOffset
= lValue
* 1000;
605 Source
->lOffset
= lValue
;
607 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
609 if(ApplyOffset(Source
) == AL_FALSE
)
610 alSetError(pContext
, AL_INVALID_VALUE
);
614 alSetError(pContext
, AL_INVALID_VALUE
);
617 case AL_DIRECT_FILTER
: {
618 ALfilter
*filter
= NULL
;
621 (filter
=VerifyFilter(pContext
->Device
->FilterList
, lValue
)) != NULL
)
625 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
626 Source
->DirectFilter
.filter
= 0;
629 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
630 Source
->NeedsUpdate
= AL_TRUE
;
633 alSetError(pContext
, AL_INVALID_VALUE
);
636 case AL_DIRECT_FILTER_GAINHF_AUTO
:
637 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
639 Source
->DryGainHFAuto
= lValue
;
640 Source
->NeedsUpdate
= AL_TRUE
;
643 alSetError(pContext
, AL_INVALID_VALUE
);
646 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
647 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
649 Source
->WetGainAuto
= lValue
;
650 Source
->NeedsUpdate
= AL_TRUE
;
653 alSetError(pContext
, AL_INVALID_VALUE
);
656 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
657 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
659 Source
->WetGainHFAuto
= lValue
;
660 Source
->NeedsUpdate
= AL_TRUE
;
663 alSetError(pContext
, AL_INVALID_VALUE
);
666 case AL_DISTANCE_MODEL
:
667 if(lValue
== AL_NONE
||
668 lValue
== AL_INVERSE_DISTANCE
||
669 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
670 lValue
== AL_LINEAR_DISTANCE
||
671 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
672 lValue
== AL_EXPONENT_DISTANCE
||
673 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
675 Source
->DistanceModel
= lValue
;
676 if(pContext
->SourceDistanceModel
)
677 Source
->NeedsUpdate
= AL_TRUE
;
680 alSetError(pContext
, AL_INVALID_VALUE
);
684 alSetError(pContext
, AL_INVALID_ENUM
);
689 alSetError(pContext
, AL_INVALID_NAME
);
691 ProcessContext(pContext
);
695 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
697 ALCcontext
*pContext
;
700 pContext
= GetContextSuspended();
701 if(!pContext
) return;
703 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
705 ALCdevice
*device
= pContext
->Device
;
712 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
715 case AL_AUXILIARY_SEND_FILTER
: {
716 ALeffectslot
*ALEffectSlot
= NULL
;
717 ALfilter
*ALFilter
= NULL
;
719 if((ALuint
)lValue2
< device
->NumAuxSends
&&
721 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
723 (ALFilter
=VerifyFilter(device
->FilterList
, lValue3
)) != NULL
))
725 /* Release refcount on the previous slot, and add one for
727 if(Source
->Send
[lValue2
].Slot
)
728 Source
->Send
[lValue2
].Slot
->refcount
--;
729 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
730 if(Source
->Send
[lValue2
].Slot
)
731 Source
->Send
[lValue2
].Slot
->refcount
++;
736 Source
->Send
[lValue2
].WetFilter
.type
= 0;
737 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
740 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
741 Source
->NeedsUpdate
= AL_TRUE
;
744 alSetError(pContext
, AL_INVALID_VALUE
);
748 alSetError(pContext
, AL_INVALID_ENUM
);
753 alSetError(pContext
, AL_INVALID_NAME
);
755 ProcessContext(pContext
);
759 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
761 ALCcontext
*pContext
;
763 pContext
= GetContextSuspended();
764 if(!pContext
) return;
768 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
772 case AL_SOURCE_RELATIVE
:
773 case AL_CONE_INNER_ANGLE
:
774 case AL_CONE_OUTER_ANGLE
:
777 case AL_SOURCE_STATE
:
779 case AL_SAMPLE_OFFSET
:
781 case AL_MAX_DISTANCE
:
782 case AL_ROLLOFF_FACTOR
:
783 case AL_REFERENCE_DISTANCE
:
784 case AL_DIRECT_FILTER
:
785 case AL_DIRECT_FILTER_GAINHF_AUTO
:
786 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
787 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
788 case AL_DISTANCE_MODEL
:
789 alSourcei(source
, eParam
, plValues
[0]);
795 case AL_AUXILIARY_SEND_FILTER
:
796 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
800 alSetError(pContext
, AL_INVALID_ENUM
);
805 alSetError(pContext
, AL_INVALID_NAME
);
808 alSetError(pContext
, AL_INVALID_VALUE
);
810 ProcessContext(pContext
);
814 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
816 ALCcontext
*pContext
;
821 pContext
= GetContextSuspended();
822 if(!pContext
) return;
826 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
831 *pflValue
= Source
->flPitch
;
835 *pflValue
= Source
->flGain
;
839 *pflValue
= Source
->flMinGain
;
843 *pflValue
= Source
->flMaxGain
;
846 case AL_MAX_DISTANCE
:
847 *pflValue
= Source
->flMaxDistance
;
850 case AL_ROLLOFF_FACTOR
:
851 *pflValue
= Source
->flRollOffFactor
;
854 case AL_CONE_OUTER_GAIN
:
855 *pflValue
= Source
->flOuterGain
;
858 case AL_CONE_OUTER_GAINHF
:
859 *pflValue
= Source
->OuterGainHF
;
863 case AL_SAMPLE_OFFSET
:
865 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
866 pContext
->Device
->Frequency
;
867 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
868 *pflValue
= Offsets
[0];
871 case AL_CONE_INNER_ANGLE
:
872 *pflValue
= Source
->flInnerAngle
;
875 case AL_CONE_OUTER_ANGLE
:
876 *pflValue
= Source
->flOuterAngle
;
879 case AL_REFERENCE_DISTANCE
:
880 *pflValue
= Source
->flRefDistance
;
883 case AL_AIR_ABSORPTION_FACTOR
:
884 *pflValue
= Source
->AirAbsorptionFactor
;
887 case AL_ROOM_ROLLOFF_FACTOR
:
888 *pflValue
= Source
->RoomRolloffFactor
;
891 case AL_DOPPLER_FACTOR
:
892 *pflValue
= Source
->DopplerFactor
;
896 alSetError(pContext
, AL_INVALID_ENUM
);
901 alSetError(pContext
, AL_INVALID_NAME
);
904 alSetError(pContext
, AL_INVALID_VALUE
);
906 ProcessContext(pContext
);
910 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
912 ALCcontext
*pContext
;
915 pContext
= GetContextSuspended();
916 if(!pContext
) return;
918 if(pflValue1
&& pflValue2
&& pflValue3
)
920 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
925 *pflValue1
= Source
->vPosition
[0];
926 *pflValue2
= Source
->vPosition
[1];
927 *pflValue3
= Source
->vPosition
[2];
931 *pflValue1
= Source
->vVelocity
[0];
932 *pflValue2
= Source
->vVelocity
[1];
933 *pflValue3
= Source
->vVelocity
[2];
937 *pflValue1
= Source
->vOrientation
[0];
938 *pflValue2
= Source
->vOrientation
[1];
939 *pflValue3
= Source
->vOrientation
[2];
943 alSetError(pContext
, AL_INVALID_ENUM
);
948 alSetError(pContext
, AL_INVALID_NAME
);
951 alSetError(pContext
, AL_INVALID_VALUE
);
953 ProcessContext(pContext
);
957 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
959 ALCcontext
*pContext
;
964 pContext
= GetContextSuspended();
965 if(!pContext
) return;
969 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
977 case AL_MAX_DISTANCE
:
978 case AL_ROLLOFF_FACTOR
:
979 case AL_DOPPLER_FACTOR
:
980 case AL_CONE_OUTER_GAIN
:
982 case AL_SAMPLE_OFFSET
:
984 case AL_CONE_INNER_ANGLE
:
985 case AL_CONE_OUTER_ANGLE
:
986 case AL_REFERENCE_DISTANCE
:
987 case AL_CONE_OUTER_GAINHF
:
988 case AL_AIR_ABSORPTION_FACTOR
:
989 case AL_ROOM_ROLLOFF_FACTOR
:
990 alGetSourcef(source
, eParam
, pflValues
);
993 case AL_SAMPLE_RW_OFFSETS_EXT
:
994 case AL_BYTE_RW_OFFSETS_EXT
:
995 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
996 pContext
->Device
->Frequency
;
997 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
998 pflValues
[0] = Offsets
[0];
999 pflValues
[1] = Offsets
[1];
1003 pflValues
[0] = Source
->vPosition
[0];
1004 pflValues
[1] = Source
->vPosition
[1];
1005 pflValues
[2] = Source
->vPosition
[2];
1009 pflValues
[0] = Source
->vVelocity
[0];
1010 pflValues
[1] = Source
->vVelocity
[1];
1011 pflValues
[2] = Source
->vVelocity
[2];
1015 pflValues
[0] = Source
->vOrientation
[0];
1016 pflValues
[1] = Source
->vOrientation
[1];
1017 pflValues
[2] = Source
->vOrientation
[2];
1021 alSetError(pContext
, AL_INVALID_ENUM
);
1026 alSetError(pContext
, AL_INVALID_NAME
);
1029 alSetError(pContext
, AL_INVALID_VALUE
);
1031 ProcessContext(pContext
);
1035 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1037 ALCcontext
*pContext
;
1039 ALdouble Offsets
[2];
1042 pContext
= GetContextSuspended();
1043 if(!pContext
) return;
1047 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1051 case AL_MAX_DISTANCE
:
1052 *plValue
= (ALint
)Source
->flMaxDistance
;
1055 case AL_ROLLOFF_FACTOR
:
1056 *plValue
= (ALint
)Source
->flRollOffFactor
;
1059 case AL_REFERENCE_DISTANCE
:
1060 *plValue
= (ALint
)Source
->flRefDistance
;
1063 case AL_SOURCE_RELATIVE
:
1064 *plValue
= Source
->bHeadRelative
;
1067 case AL_CONE_INNER_ANGLE
:
1068 *plValue
= (ALint
)Source
->flInnerAngle
;
1071 case AL_CONE_OUTER_ANGLE
:
1072 *plValue
= (ALint
)Source
->flOuterAngle
;
1076 *plValue
= Source
->bLooping
;
1080 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1083 case AL_SOURCE_STATE
:
1084 *plValue
= Source
->state
;
1087 case AL_BUFFERS_QUEUED
:
1088 *plValue
= Source
->BuffersInQueue
;
1091 case AL_BUFFERS_PROCESSED
:
1092 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1094 /* Buffers on a looping source are in a perpetual state
1095 * of PENDING, so don't report any as PROCESSED */
1099 *plValue
= Source
->BuffersPlayed
;
1102 case AL_SOURCE_TYPE
:
1103 *plValue
= Source
->lSourceType
;
1107 case AL_SAMPLE_OFFSET
:
1108 case AL_BYTE_OFFSET
:
1109 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1110 pContext
->Device
->Frequency
;
1111 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1112 *plValue
= (ALint
)Offsets
[0];
1115 case AL_DIRECT_FILTER
:
1116 *plValue
= Source
->DirectFilter
.filter
;
1119 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1120 *plValue
= Source
->DryGainHFAuto
;
1123 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1124 *plValue
= Source
->WetGainAuto
;
1127 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1128 *plValue
= Source
->WetGainHFAuto
;
1131 case AL_DOPPLER_FACTOR
:
1132 *plValue
= (ALint
)Source
->DopplerFactor
;
1135 case AL_DISTANCE_MODEL
:
1136 *plValue
= Source
->DistanceModel
;
1140 alSetError(pContext
, AL_INVALID_ENUM
);
1145 alSetError(pContext
, AL_INVALID_NAME
);
1148 alSetError(pContext
, AL_INVALID_VALUE
);
1150 ProcessContext(pContext
);
1154 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1156 ALCcontext
*pContext
;
1159 pContext
= GetContextSuspended();
1160 if(!pContext
) return;
1162 if(plValue1
&& plValue2
&& plValue3
)
1164 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1169 *plValue1
= (ALint
)Source
->vPosition
[0];
1170 *plValue2
= (ALint
)Source
->vPosition
[1];
1171 *plValue3
= (ALint
)Source
->vPosition
[2];
1175 *plValue1
= (ALint
)Source
->vVelocity
[0];
1176 *plValue2
= (ALint
)Source
->vVelocity
[1];
1177 *plValue3
= (ALint
)Source
->vVelocity
[2];
1181 *plValue1
= (ALint
)Source
->vOrientation
[0];
1182 *plValue2
= (ALint
)Source
->vOrientation
[1];
1183 *plValue3
= (ALint
)Source
->vOrientation
[2];
1187 alSetError(pContext
, AL_INVALID_ENUM
);
1192 alSetError(pContext
, AL_INVALID_NAME
);
1195 alSetError(pContext
, AL_INVALID_VALUE
);
1197 ProcessContext(pContext
);
1201 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1203 ALCcontext
*pContext
;
1205 ALdouble Offsets
[2];
1208 pContext
= GetContextSuspended();
1209 if(!pContext
) return;
1213 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1217 case AL_SOURCE_RELATIVE
:
1218 case AL_CONE_INNER_ANGLE
:
1219 case AL_CONE_OUTER_ANGLE
:
1222 case AL_SOURCE_STATE
:
1223 case AL_BUFFERS_QUEUED
:
1224 case AL_BUFFERS_PROCESSED
:
1226 case AL_SAMPLE_OFFSET
:
1227 case AL_BYTE_OFFSET
:
1228 case AL_MAX_DISTANCE
:
1229 case AL_ROLLOFF_FACTOR
:
1230 case AL_DOPPLER_FACTOR
:
1231 case AL_REFERENCE_DISTANCE
:
1232 case AL_SOURCE_TYPE
:
1233 case AL_DIRECT_FILTER
:
1234 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1235 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1236 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1237 case AL_DISTANCE_MODEL
:
1238 alGetSourcei(source
, eParam
, plValues
);
1241 case AL_SAMPLE_RW_OFFSETS_EXT
:
1242 case AL_BYTE_RW_OFFSETS_EXT
:
1243 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1244 pContext
->Device
->Frequency
;
1245 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1246 plValues
[0] = (ALint
)Offsets
[0];
1247 plValues
[1] = (ALint
)Offsets
[1];
1251 plValues
[0] = (ALint
)Source
->vPosition
[0];
1252 plValues
[1] = (ALint
)Source
->vPosition
[1];
1253 plValues
[2] = (ALint
)Source
->vPosition
[2];
1257 plValues
[0] = (ALint
)Source
->vVelocity
[0];
1258 plValues
[1] = (ALint
)Source
->vVelocity
[1];
1259 plValues
[2] = (ALint
)Source
->vVelocity
[2];
1263 plValues
[0] = (ALint
)Source
->vOrientation
[0];
1264 plValues
[1] = (ALint
)Source
->vOrientation
[1];
1265 plValues
[2] = (ALint
)Source
->vOrientation
[2];
1269 alSetError(pContext
, AL_INVALID_ENUM
);
1274 alSetError(pContext
, AL_INVALID_NAME
);
1277 alSetError(pContext
, AL_INVALID_VALUE
);
1279 ProcessContext(pContext
);
1283 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1285 alSourcePlayv(1, &source
);
1288 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1290 ALCcontext
*Context
;
1292 ALbufferlistitem
*BufferList
;
1295 Context
= GetContextSuspended();
1296 if(!Context
) return;
1300 alSetError(Context
, AL_INVALID_VALUE
);
1304 // Check that all the Sources are valid
1305 for(i
= 0;i
< n
;i
++)
1307 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1309 alSetError(Context
, AL_INVALID_NAME
);
1314 for(i
= 0;i
< n
;i
++)
1316 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1318 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1319 BufferList
= Source
->queue
;
1322 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1324 BufferList
= BufferList
->next
;
1329 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1333 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1334 Source
->DryGains
[j
] = 0.0f
;
1335 for(j
= 0;j
< MAX_SENDS
;j
++)
1336 Source
->WetGains
[j
] = 0.0f
;
1338 if(Source
->state
!= AL_PAUSED
)
1340 Source
->state
= AL_PLAYING
;
1341 Source
->position
= 0;
1342 Source
->position_fraction
= 0;
1343 Source
->BuffersPlayed
= 0;
1345 Source
->Buffer
= Source
->queue
->buffer
;
1348 Source
->state
= AL_PLAYING
;
1350 // Check if an Offset has been set
1352 ApplyOffset(Source
);
1354 if(Source
->BuffersPlayed
== 0 && Source
->position
== 0 &&
1355 Source
->position_fraction
== 0)
1356 Source
->FirstStart
= AL_TRUE
;
1358 Source
->FirstStart
= AL_FALSE
;
1360 // If device is disconnected, go right to stopped
1361 if(!Context
->Device
->Connected
)
1363 Source
->state
= AL_STOPPED
;
1364 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1365 Source
->position
= 0;
1366 Source
->position_fraction
= 0;
1371 ProcessContext(Context
);
1374 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1376 alSourcePausev(1, &source
);
1379 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1381 ALCcontext
*Context
;
1385 Context
= GetContextSuspended();
1386 if(!Context
) return;
1390 alSetError(Context
, AL_INVALID_VALUE
);
1394 // Check all the Sources are valid
1395 for(i
= 0;i
< n
;i
++)
1397 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1399 alSetError(Context
, AL_INVALID_NAME
);
1404 for(i
= 0;i
< n
;i
++)
1406 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1407 if(Source
->state
== AL_PLAYING
)
1408 Source
->state
= AL_PAUSED
;
1412 ProcessContext(Context
);
1415 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1417 alSourceStopv(1, &source
);
1420 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1422 ALCcontext
*Context
;
1426 Context
= GetContextSuspended();
1427 if(!Context
) return;
1431 alSetError(Context
, AL_INVALID_VALUE
);
1435 // Check all the Sources are valid
1436 for(i
= 0;i
< n
;i
++)
1438 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1440 alSetError(Context
, AL_INVALID_NAME
);
1445 for(i
= 0;i
< n
;i
++)
1447 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1448 if(Source
->state
!= AL_INITIAL
)
1450 Source
->state
= AL_STOPPED
;
1451 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1453 Source
->lOffset
= 0;
1457 ProcessContext(Context
);
1460 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1462 alSourceRewindv(1, &source
);
1465 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1467 ALCcontext
*Context
;
1471 Context
= GetContextSuspended();
1472 if(!Context
) return;
1476 alSetError(Context
, AL_INVALID_VALUE
);
1480 // Check all the Sources are valid
1481 for(i
= 0;i
< n
;i
++)
1483 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1485 alSetError(Context
, AL_INVALID_NAME
);
1490 for(i
= 0;i
< n
;i
++)
1492 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1493 if(Source
->state
!= AL_INITIAL
)
1495 Source
->state
= AL_INITIAL
;
1496 Source
->position
= 0;
1497 Source
->position_fraction
= 0;
1498 Source
->BuffersPlayed
= 0;
1500 Source
->Buffer
= Source
->queue
->buffer
;
1502 Source
->lOffset
= 0;
1506 ProcessContext(Context
);
1510 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1512 ALCcontext
*Context
;
1517 ALbufferlistitem
*BufferListStart
;
1518 ALbufferlistitem
*BufferList
;
1519 ALboolean HadFormat
;
1526 Context
= GetContextSuspended();
1527 if(!Context
) return;
1529 // Check that all buffers are valid or zero and that the source is valid
1531 // Check that this is a valid source
1532 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1534 alSetError(Context
, AL_INVALID_NAME
);
1538 // Check that this is not a STATIC Source
1539 if(Source
->lSourceType
== AL_STATIC
)
1541 // Invalid Source Type (can't queue on a Static Source)
1542 alSetError(Context
, AL_INVALID_OPERATION
);
1546 device
= Context
->Device
;
1550 HadFormat
= AL_FALSE
;
1552 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1553 BufferList
= Source
->queue
;
1556 if(BufferList
->buffer
)
1558 Frequency
= BufferList
->buffer
->frequency
;
1559 Format
= BufferList
->buffer
->format
;
1560 HadFormat
= AL_TRUE
;
1563 BufferList
= BufferList
->next
;
1566 for(i
= 0;i
< n
;i
++)
1571 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1573 alSetError(Context
, AL_INVALID_NAME
);
1577 if(Frequency
== -1 && Format
== -1)
1579 Frequency
= buffer
->frequency
;
1580 Format
= buffer
->format
;
1582 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->format
)
1584 alSetError(Context
, AL_INVALID_OPERATION
);
1589 // Change Source Type
1590 Source
->lSourceType
= AL_STREAMING
;
1592 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1594 // All buffers are valid - so add them to the list
1595 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1596 BufferListStart
->buffer
= buffer
;
1597 BufferListStart
->next
= NULL
;
1599 // Increment reference counter for buffer
1600 if(buffer
) buffer
->refcount
++;
1602 BufferList
= BufferListStart
;
1604 for(i
= 1;i
< n
;i
++)
1606 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1608 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1609 BufferList
->next
->buffer
= buffer
;
1610 BufferList
->next
->next
= NULL
;
1612 // Increment reference counter for buffer
1613 if(buffer
) buffer
->refcount
++;
1615 BufferList
= BufferList
->next
;
1618 if(Source
->queue
== NULL
)
1620 Source
->queue
= BufferListStart
;
1621 // Update Current Buffer
1622 Source
->Buffer
= BufferListStart
->buffer
;
1626 // Find end of queue
1627 BufferList
= Source
->queue
;
1628 while(BufferList
->next
!= NULL
)
1629 BufferList
= BufferList
->next
;
1631 BufferList
->next
= BufferListStart
;
1634 // Update number of buffers in queue
1635 Source
->BuffersInQueue
+= n
;
1636 // If no previous format, mark the source dirty now that it may have one
1638 Source
->NeedsUpdate
= AL_TRUE
;
1641 ProcessContext(Context
);
1645 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1646 // an array of buffer IDs that are to be filled with the names of the buffers removed
1647 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1649 ALCcontext
*Context
;
1652 ALbufferlistitem
*BufferList
;
1657 Context
= GetContextSuspended();
1658 if(!Context
) return;
1660 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1662 alSetError(Context
, AL_INVALID_NAME
);
1666 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1667 (ALuint
)n
> Source
->BuffersPlayed
)
1669 // Some buffers can't be unqueue because they have not been processed
1670 alSetError(Context
, AL_INVALID_VALUE
);
1674 for(i
= 0;i
< n
;i
++)
1676 BufferList
= Source
->queue
;
1677 Source
->queue
= BufferList
->next
;
1679 if(BufferList
->buffer
)
1681 // Record name of buffer
1682 buffers
[i
] = BufferList
->buffer
->buffer
;
1683 // Decrement buffer reference counter
1684 BufferList
->buffer
->refcount
--;
1689 // Release memory for buffer list item
1691 Source
->BuffersInQueue
--;
1694 if(Source
->state
!= AL_PLAYING
)
1697 Source
->Buffer
= Source
->queue
->buffer
;
1699 Source
->Buffer
= NULL
;
1701 Source
->BuffersPlayed
-= n
;
1704 ProcessContext(Context
);
1708 static ALvoid
InitSourceParams(ALsource
*Source
)
1710 Source
->flInnerAngle
= 360.0f
;
1711 Source
->flOuterAngle
= 360.0f
;
1712 Source
->flPitch
= 1.0f
;
1713 Source
->vPosition
[0] = 0.0f
;
1714 Source
->vPosition
[1] = 0.0f
;
1715 Source
->vPosition
[2] = 0.0f
;
1716 Source
->vOrientation
[0] = 0.0f
;
1717 Source
->vOrientation
[1] = 0.0f
;
1718 Source
->vOrientation
[2] = 0.0f
;
1719 Source
->vVelocity
[0] = 0.0f
;
1720 Source
->vVelocity
[1] = 0.0f
;
1721 Source
->vVelocity
[2] = 0.0f
;
1722 Source
->flRefDistance
= 1.0f
;
1723 Source
->flMaxDistance
= FLT_MAX
;
1724 Source
->flRollOffFactor
= 1.0f
;
1725 Source
->bLooping
= AL_FALSE
;
1726 Source
->flGain
= 1.0f
;
1727 Source
->flMinGain
= 0.0f
;
1728 Source
->flMaxGain
= 1.0f
;
1729 Source
->flOuterGain
= 0.0f
;
1730 Source
->OuterGainHF
= 1.0f
;
1732 Source
->DryGainHFAuto
= AL_TRUE
;
1733 Source
->WetGainAuto
= AL_TRUE
;
1734 Source
->WetGainHFAuto
= AL_TRUE
;
1735 Source
->AirAbsorptionFactor
= 0.0f
;
1736 Source
->RoomRolloffFactor
= 0.0f
;
1737 Source
->DopplerFactor
= 1.0f
;
1739 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1741 Source
->Resampler
= DefaultResampler
;
1743 Source
->state
= AL_INITIAL
;
1744 Source
->lSourceType
= AL_UNDETERMINED
;
1746 Source
->NeedsUpdate
= AL_TRUE
;
1748 Source
->Buffer
= NULL
;
1755 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1756 The offset is relative to the start of the queue (not the start of the current buffer)
1758 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1760 ALbufferlistitem
*BufferList
;
1761 ALbuffer
*Buffer
= NULL
;
1763 ALint Channels
, Bytes
;
1764 ALint readPos
, writePos
;
1765 ALenum OriginalFormat
;
1766 ALint TotalBufferDataSize
;
1769 // Find the first non-NULL Buffer in the Queue
1770 BufferList
= Source
->queue
;
1773 if(BufferList
->buffer
)
1775 Buffer
= BufferList
->buffer
;
1778 BufferList
= BufferList
->next
;
1781 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1788 // Get Current Buffer Size and frequency (in milliseconds)
1789 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1790 OriginalFormat
= Buffer
->eOriginalFormat
;
1791 Channels
= aluChannelsFromFormat(Buffer
->format
);
1792 Bytes
= aluBytesFromFormat(Buffer
->format
);
1794 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1795 readPos
= Source
->position
* Channels
* Bytes
;
1796 // Add byte length of any processed buffers in the queue
1797 TotalBufferDataSize
= 0;
1798 BufferList
= Source
->queue
;
1799 for(i
= 0;BufferList
;i
++)
1801 if(BufferList
->buffer
)
1803 if(i
< Source
->BuffersPlayed
)
1804 readPos
+= BufferList
->buffer
->size
;
1805 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1807 BufferList
= BufferList
->next
;
1809 if(Source
->state
== AL_PLAYING
)
1810 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1814 if(Source
->bLooping
)
1816 readPos
%= TotalBufferDataSize
;
1817 writePos
%= TotalBufferDataSize
;
1821 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1824 else if(readPos
> TotalBufferDataSize
)
1825 readPos
= TotalBufferDataSize
;
1828 else if(writePos
> TotalBufferDataSize
)
1829 writePos
= TotalBufferDataSize
;
1835 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1836 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1838 case AL_SAMPLE_OFFSET
:
1839 case AL_SAMPLE_RW_OFFSETS_EXT
:
1840 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1841 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1843 case AL_BYTE_OFFSET
:
1844 case AL_BYTE_RW_OFFSETS_EXT
:
1845 // Take into account the original format of the Buffer
1846 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1847 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1849 // Round down to nearest ADPCM block
1850 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1851 if(Source
->state
== AL_PLAYING
)
1853 // Round up to nearest ADPCM block
1854 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1857 offset
[1] = offset
[0];
1859 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1860 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1861 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1862 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1863 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1864 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1866 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1867 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1869 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1871 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1872 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1874 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1876 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1877 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1879 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1881 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1882 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1884 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1886 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1887 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1891 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1892 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1893 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1903 Apply a playback offset to the Source. This function will update the queue (to correctly
1904 mark buffers as 'pending' or 'processed' depending upon the new offset.
1906 static ALboolean
ApplyOffset(ALsource
*Source
)
1908 ALbufferlistitem
*BufferList
;
1910 ALint lBufferSize
, lTotalBufferSize
;
1911 ALint BuffersPlayed
;
1914 // Get true byte offset
1915 lByteOffset
= GetByteOffset(Source
);
1917 // If the offset is invalid, don't apply it
1918 if(lByteOffset
== -1)
1921 // Sort out the queue (pending and processed states)
1922 BufferList
= Source
->queue
;
1923 lTotalBufferSize
= 0;
1928 Buffer
= BufferList
->buffer
;
1929 lBufferSize
= Buffer
? Buffer
->size
: 0;
1931 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1933 // Offset is past this buffer so increment BuffersPlayed
1936 else if(lTotalBufferSize
<= lByteOffset
)
1939 // Offset is within this buffer
1940 // Set Current Buffer
1941 Source
->Buffer
= BufferList
->buffer
;
1942 Source
->BuffersPlayed
= BuffersPlayed
;
1944 // SW Mixer Positions are in Samples
1945 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1946 aluBytesFromFormat(Buffer
->format
) /
1947 aluChannelsFromFormat(Buffer
->format
);
1951 // Increment the TotalBufferSize
1952 lTotalBufferSize
+= lBufferSize
;
1954 // Move on to next buffer in the Queue
1955 BufferList
= BufferList
->next
;
1957 // Offset is out of range of the buffer queue
1965 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1966 offset supplied by the application). This takes into account the fact that the buffer format
1967 may have been modifed by AL (e.g 8bit samples are converted to float)
1969 static ALint
GetByteOffset(ALsource
*Source
)
1971 ALbuffer
*Buffer
= NULL
;
1972 ALbufferlistitem
*BufferList
;
1974 ALint Channels
, Bytes
;
1975 ALint ByteOffset
= -1;
1977 // Find the first non-NULL Buffer in the Queue
1978 BufferList
= Source
->queue
;
1981 if(BufferList
->buffer
)
1983 Buffer
= BufferList
->buffer
;
1986 BufferList
= BufferList
->next
;
1991 Source
->lOffset
= 0;
1995 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
1996 Channels
= aluChannelsFromFormat(Buffer
->format
);
1997 Bytes
= aluBytesFromFormat(Buffer
->format
);
1999 // Determine the ByteOffset (and ensure it is block aligned)
2000 switch(Source
->lOffsetType
)
2002 case AL_BYTE_OFFSET
:
2003 // Take into consideration the original format
2004 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2006 ByteOffset
*= Channels
* Bytes
;
2009 case AL_SAMPLE_OFFSET
:
2010 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2014 // Note - lOffset is internally stored as Milliseconds
2015 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2016 ByteOffset
*= Channels
* Bytes
;
2020 Source
->lOffset
= 0;
2025 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2027 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2029 // Round down to nearest ADPCM block
2030 offset
/= 36 * channels
;
2031 // Multiply by compression rate (65 sample frames per block)
2034 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2035 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2036 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2038 /* muLaw has 1 byte per sample */
2039 offset
/= 1 * channels
;
2041 else if(format
== AL_FORMAT_REAR_MULAW
)
2043 /* Rear is 2 channels */
2046 else if(format
== AL_FORMAT_REAR8
)
2048 else if(format
== AL_FORMAT_REAR16
)
2050 else if(format
== AL_FORMAT_REAR32
)
2054 ALuint bytes
= aluBytesFromFormat(format
);
2055 offset
/= bytes
* channels
;
2061 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2065 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2067 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2068 Context
->SourceMap
.array
[pos
].value
= NULL
;
2070 // For each buffer in the source's queue, decrement its reference counter and remove it
2071 while(temp
->queue
!= NULL
)
2073 ALbufferlistitem
*BufferList
= temp
->queue
;
2074 // Decrement buffer's reference counter
2075 if(BufferList
->buffer
!= NULL
)
2076 BufferList
->buffer
->refcount
--;
2077 // Update queue to point to next element in list
2078 temp
->queue
= BufferList
->next
;
2079 // Release memory allocated for buffer list item
2083 for(j
= 0;j
< MAX_SENDS
;++j
)
2085 if(temp
->Send
[j
].Slot
)
2086 temp
->Send
[j
].Slot
->refcount
--;
2089 // Release source structure
2090 ALTHUNK_REMOVEENTRY(temp
->source
);
2091 memset(temp
, 0, sizeof(ALsource
));