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 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
42 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
43 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
44 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
46 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
52 Context
= GetContextSuspended();
57 Device
= Context
->Device
;
59 // Check that enough memory has been allocted in the 'sources' array for n Sources
60 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
62 // Check that the requested number of sources can be generated
63 if((Context
->SourceMap
.size
+ n
) <= (ALsizei
)Device
->MaxNoOfSources
)
67 // Add additional sources to the list
70 ALsource
*source
= calloc(1, sizeof(ALsource
));
73 alSetError(Context
, AL_OUT_OF_MEMORY
);
74 alDeleteSources(i
, sources
);
78 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
79 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
81 if(err
!= AL_NO_ERROR
)
83 ALTHUNK_REMOVEENTRY(source
->source
);
84 memset(source
, 0, sizeof(ALsource
));
87 alSetError(Context
, err
);
88 alDeleteSources(i
, sources
);
92 sources
[i
++] = source
->source
;
93 InitSourceParams(source
);
98 // Not enough resources to create the Sources
99 alSetError(Context
, AL_INVALID_VALUE
);
105 alSetError(Context
, AL_INVALID_VALUE
);
109 ProcessContext(Context
);
113 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
119 ALbufferlistitem
*BufferList
;
120 ALboolean bSourcesValid
= AL_TRUE
;
122 Context
= GetContextSuspended();
127 Device
= Context
->Device
;
129 // Check that all Sources are valid (and can therefore be deleted)
130 for (i
= 0; i
< n
; i
++)
132 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
134 alSetError(Context
, AL_INVALID_NAME
);
135 bSourcesValid
= AL_FALSE
;
142 // All Sources are valid, and can be deleted
143 for(i
= 0; i
< n
; i
++)
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) != NULL
)
148 // For each buffer in the source's queue, decrement its reference counter and remove it
149 while(Source
->queue
!= NULL
)
151 BufferList
= Source
->queue
;
152 // Decrement buffer's reference counter
153 if(BufferList
->buffer
!= NULL
)
154 BufferList
->buffer
->refcount
--;
155 // Update queue to point to next element in list
156 Source
->queue
= BufferList
->next
;
157 // Release memory allocated for buffer list item
161 for(j
= 0;j
< MAX_SENDS
;++j
)
163 if(Source
->Send
[j
].Slot
)
164 Source
->Send
[j
].Slot
->refcount
--;
165 Source
->Send
[j
].Slot
= NULL
;
168 // Remove Source from list of Sources
169 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
170 ALTHUNK_REMOVEENTRY(Source
->source
);
172 memset(Source
,0,sizeof(ALsource
));
179 alSetError(Context
, AL_INVALID_VALUE
);
181 ProcessContext(Context
);
185 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
190 Context
= GetContextSuspended();
191 if(!Context
) return AL_FALSE
;
193 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
195 ProcessContext(Context
);
201 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
203 ALCcontext
*pContext
;
206 pContext
= GetContextSuspended();
207 if(!pContext
) return;
209 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
216 Source
->flPitch
= flValue
;
217 if(Source
->flPitch
< 0.001f
)
218 Source
->flPitch
= 0.001f
;
219 Source
->NeedsUpdate
= AL_TRUE
;
222 alSetError(pContext
, AL_INVALID_VALUE
);
225 case AL_CONE_INNER_ANGLE
:
226 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
228 Source
->flInnerAngle
= flValue
;
229 Source
->NeedsUpdate
= AL_TRUE
;
232 alSetError(pContext
, AL_INVALID_VALUE
);
235 case AL_CONE_OUTER_ANGLE
:
236 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
238 Source
->flOuterAngle
= flValue
;
239 Source
->NeedsUpdate
= AL_TRUE
;
242 alSetError(pContext
, AL_INVALID_VALUE
);
248 Source
->flGain
= flValue
;
249 Source
->NeedsUpdate
= AL_TRUE
;
252 alSetError(pContext
, AL_INVALID_VALUE
);
255 case AL_MAX_DISTANCE
:
258 Source
->flMaxDistance
= flValue
;
259 Source
->NeedsUpdate
= AL_TRUE
;
262 alSetError(pContext
, AL_INVALID_VALUE
);
265 case AL_ROLLOFF_FACTOR
:
268 Source
->flRollOffFactor
= flValue
;
269 Source
->NeedsUpdate
= AL_TRUE
;
272 alSetError(pContext
, AL_INVALID_VALUE
);
275 case AL_REFERENCE_DISTANCE
:
278 Source
->flRefDistance
= flValue
;
279 Source
->NeedsUpdate
= AL_TRUE
;
282 alSetError(pContext
, AL_INVALID_VALUE
);
286 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
288 Source
->flMinGain
= flValue
;
289 Source
->NeedsUpdate
= AL_TRUE
;
292 alSetError(pContext
, AL_INVALID_VALUE
);
296 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
298 Source
->flMaxGain
= flValue
;
299 Source
->NeedsUpdate
= AL_TRUE
;
302 alSetError(pContext
, AL_INVALID_VALUE
);
305 case AL_CONE_OUTER_GAIN
:
306 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
308 Source
->flOuterGain
= flValue
;
309 Source
->NeedsUpdate
= AL_TRUE
;
312 alSetError(pContext
, AL_INVALID_VALUE
);
315 case AL_CONE_OUTER_GAINHF
:
316 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
318 Source
->OuterGainHF
= flValue
;
319 Source
->NeedsUpdate
= AL_TRUE
;
322 alSetError(pContext
, AL_INVALID_VALUE
);
325 case AL_AIR_ABSORPTION_FACTOR
:
326 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
328 Source
->AirAbsorptionFactor
= flValue
;
329 Source
->NeedsUpdate
= AL_TRUE
;
332 alSetError(pContext
, AL_INVALID_VALUE
);
335 case AL_ROOM_ROLLOFF_FACTOR
:
336 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
338 Source
->RoomRolloffFactor
= flValue
;
339 Source
->NeedsUpdate
= AL_TRUE
;
342 alSetError(pContext
, AL_INVALID_VALUE
);
345 case AL_DOPPLER_FACTOR
:
346 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
348 Source
->DopplerFactor
= flValue
;
349 Source
->NeedsUpdate
= AL_TRUE
;
352 alSetError(pContext
, AL_INVALID_VALUE
);
356 case AL_SAMPLE_OFFSET
:
360 Source
->lOffsetType
= eParam
;
362 // Store Offset (convert Seconds into Milliseconds)
363 if(eParam
== AL_SEC_OFFSET
)
364 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
366 Source
->lOffset
= (ALint
)flValue
;
368 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
370 if(ApplyOffset(Source
) == AL_FALSE
)
371 alSetError(pContext
, AL_INVALID_VALUE
);
375 alSetError(pContext
, AL_INVALID_VALUE
);
379 alSetError(pContext
, AL_INVALID_ENUM
);
385 // Invalid Source Name
386 alSetError(pContext
, AL_INVALID_NAME
);
389 ProcessContext(pContext
);
393 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
395 ALCcontext
*pContext
;
398 pContext
= GetContextSuspended();
399 if(!pContext
) return;
401 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
406 Source
->vPosition
[0] = flValue1
;
407 Source
->vPosition
[1] = flValue2
;
408 Source
->vPosition
[2] = flValue3
;
409 Source
->NeedsUpdate
= AL_TRUE
;
413 Source
->vVelocity
[0] = flValue1
;
414 Source
->vVelocity
[1] = flValue2
;
415 Source
->vVelocity
[2] = flValue3
;
416 Source
->NeedsUpdate
= AL_TRUE
;
420 Source
->vOrientation
[0] = flValue1
;
421 Source
->vOrientation
[1] = flValue2
;
422 Source
->vOrientation
[2] = flValue3
;
423 Source
->NeedsUpdate
= AL_TRUE
;
427 alSetError(pContext
, AL_INVALID_ENUM
);
432 alSetError(pContext
, AL_INVALID_NAME
);
434 ProcessContext(pContext
);
438 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
440 ALCcontext
*pContext
;
442 pContext
= GetContextSuspended();
443 if(!pContext
) return;
447 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
452 case AL_CONE_INNER_ANGLE
:
453 case AL_CONE_OUTER_ANGLE
:
455 case AL_MAX_DISTANCE
:
456 case AL_ROLLOFF_FACTOR
:
457 case AL_REFERENCE_DISTANCE
:
460 case AL_CONE_OUTER_GAIN
:
461 case AL_CONE_OUTER_GAINHF
:
463 case AL_SAMPLE_OFFSET
:
465 case AL_AIR_ABSORPTION_FACTOR
:
466 case AL_ROOM_ROLLOFF_FACTOR
:
467 alSourcef(source
, eParam
, pflValues
[0]);
473 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
477 alSetError(pContext
, AL_INVALID_ENUM
);
482 alSetError(pContext
, AL_INVALID_NAME
);
485 alSetError(pContext
, AL_INVALID_VALUE
);
487 ProcessContext(pContext
);
491 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
493 ALCcontext
*pContext
;
495 ALbufferlistitem
*BufferListItem
;
497 pContext
= GetContextSuspended();
498 if(!pContext
) return;
500 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
502 ALCdevice
*device
= pContext
->Device
;
506 case AL_MAX_DISTANCE
:
507 case AL_ROLLOFF_FACTOR
:
508 case AL_CONE_INNER_ANGLE
:
509 case AL_CONE_OUTER_ANGLE
:
510 case AL_REFERENCE_DISTANCE
:
511 alSourcef(source
, eParam
, (ALfloat
)lValue
);
514 case AL_SOURCE_RELATIVE
:
515 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
517 Source
->bHeadRelative
= (ALboolean
)lValue
;
518 Source
->NeedsUpdate
= AL_TRUE
;
521 alSetError(pContext
, AL_INVALID_VALUE
);
525 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
526 Source
->bLooping
= (ALboolean
)lValue
;
528 alSetError(pContext
, AL_INVALID_VALUE
);
532 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
534 ALbuffer
*buffer
= NULL
;
537 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
539 // Remove all elements in the queue
540 while(Source
->queue
!= NULL
)
542 BufferListItem
= Source
->queue
;
543 Source
->queue
= BufferListItem
->next
;
544 // Decrement reference counter for buffer
545 if(BufferListItem
->buffer
)
546 BufferListItem
->buffer
->refcount
--;
547 // Release memory for buffer list item
548 free(BufferListItem
);
549 // Decrement the number of buffers in the queue
550 Source
->BuffersInQueue
--;
553 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
556 // Source is now in STATIC mode
557 Source
->lSourceType
= AL_STATIC
;
559 // Add the selected buffer to the queue
560 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
561 BufferListItem
->buffer
= buffer
;
562 BufferListItem
->next
= NULL
;
564 Source
->queue
= BufferListItem
;
565 Source
->BuffersInQueue
= 1;
567 // Increment reference counter for buffer
572 // Source is now in UNDETERMINED mode
573 Source
->lSourceType
= AL_UNDETERMINED
;
575 Source
->BuffersPlayed
= 0;
577 // Update AL_BUFFER parameter
578 Source
->Buffer
= buffer
;
579 Source
->NeedsUpdate
= AL_TRUE
;
582 alSetError(pContext
, AL_INVALID_VALUE
);
585 alSetError(pContext
, AL_INVALID_OPERATION
);
588 case AL_SOURCE_STATE
:
590 alSetError(pContext
, AL_INVALID_OPERATION
);
594 case AL_SAMPLE_OFFSET
:
598 Source
->lOffsetType
= eParam
;
600 // Store Offset (convert Seconds into Milliseconds)
601 if(eParam
== AL_SEC_OFFSET
)
602 Source
->lOffset
= lValue
* 1000;
604 Source
->lOffset
= lValue
;
606 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
608 if(ApplyOffset(Source
) == AL_FALSE
)
609 alSetError(pContext
, AL_INVALID_VALUE
);
613 alSetError(pContext
, AL_INVALID_VALUE
);
616 case AL_DIRECT_FILTER
: {
617 ALfilter
*filter
= NULL
;
620 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
624 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
625 Source
->DirectFilter
.filter
= 0;
628 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
629 Source
->NeedsUpdate
= AL_TRUE
;
632 alSetError(pContext
, AL_INVALID_VALUE
);
635 case AL_DIRECT_FILTER_GAINHF_AUTO
:
636 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
638 Source
->DryGainHFAuto
= lValue
;
639 Source
->NeedsUpdate
= AL_TRUE
;
642 alSetError(pContext
, AL_INVALID_VALUE
);
645 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
646 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
648 Source
->WetGainAuto
= lValue
;
649 Source
->NeedsUpdate
= AL_TRUE
;
652 alSetError(pContext
, AL_INVALID_VALUE
);
655 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
656 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
658 Source
->WetGainHFAuto
= lValue
;
659 Source
->NeedsUpdate
= AL_TRUE
;
662 alSetError(pContext
, AL_INVALID_VALUE
);
665 case AL_DISTANCE_MODEL
:
666 if(lValue
== AL_NONE
||
667 lValue
== AL_INVERSE_DISTANCE
||
668 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
669 lValue
== AL_LINEAR_DISTANCE
||
670 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
671 lValue
== AL_EXPONENT_DISTANCE
||
672 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
674 Source
->DistanceModel
= lValue
;
675 if(pContext
->SourceDistanceModel
)
676 Source
->NeedsUpdate
= AL_TRUE
;
679 alSetError(pContext
, AL_INVALID_VALUE
);
683 alSetError(pContext
, AL_INVALID_ENUM
);
688 alSetError(pContext
, AL_INVALID_NAME
);
690 ProcessContext(pContext
);
694 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
696 ALCcontext
*pContext
;
699 pContext
= GetContextSuspended();
700 if(!pContext
) return;
702 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
704 ALCdevice
*device
= pContext
->Device
;
711 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
714 case AL_AUXILIARY_SEND_FILTER
: {
715 ALeffectslot
*ALEffectSlot
= NULL
;
716 ALfilter
*ALFilter
= NULL
;
718 if((ALuint
)lValue2
< device
->NumAuxSends
&&
720 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
722 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
724 /* Release refcount on the previous slot, and add one for
726 if(Source
->Send
[lValue2
].Slot
)
727 Source
->Send
[lValue2
].Slot
->refcount
--;
728 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
729 if(Source
->Send
[lValue2
].Slot
)
730 Source
->Send
[lValue2
].Slot
->refcount
++;
735 Source
->Send
[lValue2
].WetFilter
.type
= 0;
736 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
739 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
740 Source
->NeedsUpdate
= AL_TRUE
;
743 alSetError(pContext
, AL_INVALID_VALUE
);
747 alSetError(pContext
, AL_INVALID_ENUM
);
752 alSetError(pContext
, AL_INVALID_NAME
);
754 ProcessContext(pContext
);
758 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
760 ALCcontext
*pContext
;
762 pContext
= GetContextSuspended();
763 if(!pContext
) return;
767 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
771 case AL_SOURCE_RELATIVE
:
772 case AL_CONE_INNER_ANGLE
:
773 case AL_CONE_OUTER_ANGLE
:
776 case AL_SOURCE_STATE
:
778 case AL_SAMPLE_OFFSET
:
780 case AL_MAX_DISTANCE
:
781 case AL_ROLLOFF_FACTOR
:
782 case AL_REFERENCE_DISTANCE
:
783 case AL_DIRECT_FILTER
:
784 case AL_DIRECT_FILTER_GAINHF_AUTO
:
785 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
786 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
787 case AL_DISTANCE_MODEL
:
788 alSourcei(source
, eParam
, plValues
[0]);
794 case AL_AUXILIARY_SEND_FILTER
:
795 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
799 alSetError(pContext
, AL_INVALID_ENUM
);
804 alSetError(pContext
, AL_INVALID_NAME
);
807 alSetError(pContext
, AL_INVALID_VALUE
);
809 ProcessContext(pContext
);
813 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
815 ALCcontext
*pContext
;
820 pContext
= GetContextSuspended();
821 if(!pContext
) return;
825 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
830 *pflValue
= Source
->flPitch
;
834 *pflValue
= Source
->flGain
;
838 *pflValue
= Source
->flMinGain
;
842 *pflValue
= Source
->flMaxGain
;
845 case AL_MAX_DISTANCE
:
846 *pflValue
= Source
->flMaxDistance
;
849 case AL_ROLLOFF_FACTOR
:
850 *pflValue
= Source
->flRollOffFactor
;
853 case AL_CONE_OUTER_GAIN
:
854 *pflValue
= Source
->flOuterGain
;
857 case AL_CONE_OUTER_GAINHF
:
858 *pflValue
= Source
->OuterGainHF
;
862 case AL_SAMPLE_OFFSET
:
864 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
865 pContext
->Device
->Frequency
;
866 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
867 *pflValue
= Offsets
[0];
870 case AL_CONE_INNER_ANGLE
:
871 *pflValue
= Source
->flInnerAngle
;
874 case AL_CONE_OUTER_ANGLE
:
875 *pflValue
= Source
->flOuterAngle
;
878 case AL_REFERENCE_DISTANCE
:
879 *pflValue
= Source
->flRefDistance
;
882 case AL_AIR_ABSORPTION_FACTOR
:
883 *pflValue
= Source
->AirAbsorptionFactor
;
886 case AL_ROOM_ROLLOFF_FACTOR
:
887 *pflValue
= Source
->RoomRolloffFactor
;
890 case AL_DOPPLER_FACTOR
:
891 *pflValue
= Source
->DopplerFactor
;
895 alSetError(pContext
, AL_INVALID_ENUM
);
900 alSetError(pContext
, AL_INVALID_NAME
);
903 alSetError(pContext
, AL_INVALID_VALUE
);
905 ProcessContext(pContext
);
909 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
911 ALCcontext
*pContext
;
914 pContext
= GetContextSuspended();
915 if(!pContext
) return;
917 if(pflValue1
&& pflValue2
&& pflValue3
)
919 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
924 *pflValue1
= Source
->vPosition
[0];
925 *pflValue2
= Source
->vPosition
[1];
926 *pflValue3
= Source
->vPosition
[2];
930 *pflValue1
= Source
->vVelocity
[0];
931 *pflValue2
= Source
->vVelocity
[1];
932 *pflValue3
= Source
->vVelocity
[2];
936 *pflValue1
= Source
->vOrientation
[0];
937 *pflValue2
= Source
->vOrientation
[1];
938 *pflValue3
= Source
->vOrientation
[2];
942 alSetError(pContext
, AL_INVALID_ENUM
);
947 alSetError(pContext
, AL_INVALID_NAME
);
950 alSetError(pContext
, AL_INVALID_VALUE
);
952 ProcessContext(pContext
);
956 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
958 ALCcontext
*pContext
;
963 pContext
= GetContextSuspended();
964 if(!pContext
) return;
968 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
976 case AL_MAX_DISTANCE
:
977 case AL_ROLLOFF_FACTOR
:
978 case AL_DOPPLER_FACTOR
:
979 case AL_CONE_OUTER_GAIN
:
981 case AL_SAMPLE_OFFSET
:
983 case AL_CONE_INNER_ANGLE
:
984 case AL_CONE_OUTER_ANGLE
:
985 case AL_REFERENCE_DISTANCE
:
986 case AL_CONE_OUTER_GAINHF
:
987 case AL_AIR_ABSORPTION_FACTOR
:
988 case AL_ROOM_ROLLOFF_FACTOR
:
989 alGetSourcef(source
, eParam
, pflValues
);
992 case AL_SAMPLE_RW_OFFSETS_EXT
:
993 case AL_BYTE_RW_OFFSETS_EXT
:
994 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
995 pContext
->Device
->Frequency
;
996 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
997 pflValues
[0] = Offsets
[0];
998 pflValues
[1] = Offsets
[1];
1002 pflValues
[0] = Source
->vPosition
[0];
1003 pflValues
[1] = Source
->vPosition
[1];
1004 pflValues
[2] = Source
->vPosition
[2];
1008 pflValues
[0] = Source
->vVelocity
[0];
1009 pflValues
[1] = Source
->vVelocity
[1];
1010 pflValues
[2] = Source
->vVelocity
[2];
1014 pflValues
[0] = Source
->vOrientation
[0];
1015 pflValues
[1] = Source
->vOrientation
[1];
1016 pflValues
[2] = Source
->vOrientation
[2];
1020 alSetError(pContext
, AL_INVALID_ENUM
);
1025 alSetError(pContext
, AL_INVALID_NAME
);
1028 alSetError(pContext
, AL_INVALID_VALUE
);
1030 ProcessContext(pContext
);
1034 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1036 ALCcontext
*pContext
;
1038 ALdouble Offsets
[2];
1041 pContext
= GetContextSuspended();
1042 if(!pContext
) return;
1046 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1050 case AL_MAX_DISTANCE
:
1051 *plValue
= (ALint
)Source
->flMaxDistance
;
1054 case AL_ROLLOFF_FACTOR
:
1055 *plValue
= (ALint
)Source
->flRollOffFactor
;
1058 case AL_REFERENCE_DISTANCE
:
1059 *plValue
= (ALint
)Source
->flRefDistance
;
1062 case AL_SOURCE_RELATIVE
:
1063 *plValue
= Source
->bHeadRelative
;
1066 case AL_CONE_INNER_ANGLE
:
1067 *plValue
= (ALint
)Source
->flInnerAngle
;
1070 case AL_CONE_OUTER_ANGLE
:
1071 *plValue
= (ALint
)Source
->flOuterAngle
;
1075 *plValue
= Source
->bLooping
;
1079 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1082 case AL_SOURCE_STATE
:
1083 *plValue
= Source
->state
;
1086 case AL_BUFFERS_QUEUED
:
1087 *plValue
= Source
->BuffersInQueue
;
1090 case AL_BUFFERS_PROCESSED
:
1091 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1093 /* Buffers on a looping source are in a perpetual state
1094 * of PENDING, so don't report any as PROCESSED */
1098 *plValue
= Source
->BuffersPlayed
;
1101 case AL_SOURCE_TYPE
:
1102 *plValue
= Source
->lSourceType
;
1106 case AL_SAMPLE_OFFSET
:
1107 case AL_BYTE_OFFSET
:
1108 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1109 pContext
->Device
->Frequency
;
1110 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1111 *plValue
= (ALint
)Offsets
[0];
1114 case AL_DIRECT_FILTER
:
1115 *plValue
= Source
->DirectFilter
.filter
;
1118 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1119 *plValue
= Source
->DryGainHFAuto
;
1122 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1123 *plValue
= Source
->WetGainAuto
;
1126 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1127 *plValue
= Source
->WetGainHFAuto
;
1130 case AL_DOPPLER_FACTOR
:
1131 *plValue
= (ALint
)Source
->DopplerFactor
;
1134 case AL_DISTANCE_MODEL
:
1135 *plValue
= Source
->DistanceModel
;
1139 alSetError(pContext
, AL_INVALID_ENUM
);
1144 alSetError(pContext
, AL_INVALID_NAME
);
1147 alSetError(pContext
, AL_INVALID_VALUE
);
1149 ProcessContext(pContext
);
1153 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1155 ALCcontext
*pContext
;
1158 pContext
= GetContextSuspended();
1159 if(!pContext
) return;
1161 if(plValue1
&& plValue2
&& plValue3
)
1163 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1168 *plValue1
= (ALint
)Source
->vPosition
[0];
1169 *plValue2
= (ALint
)Source
->vPosition
[1];
1170 *plValue3
= (ALint
)Source
->vPosition
[2];
1174 *plValue1
= (ALint
)Source
->vVelocity
[0];
1175 *plValue2
= (ALint
)Source
->vVelocity
[1];
1176 *plValue3
= (ALint
)Source
->vVelocity
[2];
1180 *plValue1
= (ALint
)Source
->vOrientation
[0];
1181 *plValue2
= (ALint
)Source
->vOrientation
[1];
1182 *plValue3
= (ALint
)Source
->vOrientation
[2];
1186 alSetError(pContext
, AL_INVALID_ENUM
);
1191 alSetError(pContext
, AL_INVALID_NAME
);
1194 alSetError(pContext
, AL_INVALID_VALUE
);
1196 ProcessContext(pContext
);
1200 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1202 ALCcontext
*pContext
;
1204 ALdouble Offsets
[2];
1207 pContext
= GetContextSuspended();
1208 if(!pContext
) return;
1212 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1216 case AL_SOURCE_RELATIVE
:
1217 case AL_CONE_INNER_ANGLE
:
1218 case AL_CONE_OUTER_ANGLE
:
1221 case AL_SOURCE_STATE
:
1222 case AL_BUFFERS_QUEUED
:
1223 case AL_BUFFERS_PROCESSED
:
1225 case AL_SAMPLE_OFFSET
:
1226 case AL_BYTE_OFFSET
:
1227 case AL_MAX_DISTANCE
:
1228 case AL_ROLLOFF_FACTOR
:
1229 case AL_DOPPLER_FACTOR
:
1230 case AL_REFERENCE_DISTANCE
:
1231 case AL_SOURCE_TYPE
:
1232 case AL_DIRECT_FILTER
:
1233 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1234 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1235 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1236 case AL_DISTANCE_MODEL
:
1237 alGetSourcei(source
, eParam
, plValues
);
1240 case AL_SAMPLE_RW_OFFSETS_EXT
:
1241 case AL_BYTE_RW_OFFSETS_EXT
:
1242 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1243 pContext
->Device
->Frequency
;
1244 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1245 plValues
[0] = (ALint
)Offsets
[0];
1246 plValues
[1] = (ALint
)Offsets
[1];
1250 plValues
[0] = (ALint
)Source
->vPosition
[0];
1251 plValues
[1] = (ALint
)Source
->vPosition
[1];
1252 plValues
[2] = (ALint
)Source
->vPosition
[2];
1256 plValues
[0] = (ALint
)Source
->vVelocity
[0];
1257 plValues
[1] = (ALint
)Source
->vVelocity
[1];
1258 plValues
[2] = (ALint
)Source
->vVelocity
[2];
1262 plValues
[0] = (ALint
)Source
->vOrientation
[0];
1263 plValues
[1] = (ALint
)Source
->vOrientation
[1];
1264 plValues
[2] = (ALint
)Source
->vOrientation
[2];
1268 alSetError(pContext
, AL_INVALID_ENUM
);
1273 alSetError(pContext
, AL_INVALID_NAME
);
1276 alSetError(pContext
, AL_INVALID_VALUE
);
1278 ProcessContext(pContext
);
1282 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1284 alSourcePlayv(1, &source
);
1287 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1289 ALCcontext
*Context
;
1291 ALbufferlistitem
*BufferList
;
1294 Context
= GetContextSuspended();
1295 if(!Context
) return;
1299 alSetError(Context
, AL_INVALID_VALUE
);
1303 // Check that all the Sources are valid
1304 for(i
= 0;i
< n
;i
++)
1306 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1308 alSetError(Context
, AL_INVALID_NAME
);
1313 for(i
= 0;i
< n
;i
++)
1315 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1317 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1318 BufferList
= Source
->queue
;
1321 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1323 BufferList
= BufferList
->next
;
1328 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1332 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1333 Source
->DryGains
[j
] = 0.0f
;
1334 for(j
= 0;j
< MAX_SENDS
;j
++)
1335 Source
->WetGains
[j
] = 0.0f
;
1337 if(Source
->state
!= AL_PAUSED
)
1339 Source
->state
= AL_PLAYING
;
1340 Source
->position
= 0;
1341 Source
->position_fraction
= 0;
1342 Source
->BuffersPlayed
= 0;
1344 Source
->Buffer
= Source
->queue
->buffer
;
1347 Source
->state
= AL_PLAYING
;
1349 // Check if an Offset has been set
1351 ApplyOffset(Source
);
1353 if(Source
->BuffersPlayed
== 0 && Source
->position
== 0 &&
1354 Source
->position_fraction
== 0)
1355 Source
->FirstStart
= AL_TRUE
;
1357 Source
->FirstStart
= AL_FALSE
;
1359 // If device is disconnected, go right to stopped
1360 if(!Context
->Device
->Connected
)
1362 Source
->state
= AL_STOPPED
;
1363 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1364 Source
->position
= 0;
1365 Source
->position_fraction
= 0;
1370 ProcessContext(Context
);
1373 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1375 alSourcePausev(1, &source
);
1378 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1380 ALCcontext
*Context
;
1384 Context
= GetContextSuspended();
1385 if(!Context
) return;
1389 alSetError(Context
, AL_INVALID_VALUE
);
1393 // Check all the Sources are valid
1394 for(i
= 0;i
< n
;i
++)
1396 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1398 alSetError(Context
, AL_INVALID_NAME
);
1403 for(i
= 0;i
< n
;i
++)
1405 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1406 if(Source
->state
== AL_PLAYING
)
1407 Source
->state
= AL_PAUSED
;
1411 ProcessContext(Context
);
1414 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1416 alSourceStopv(1, &source
);
1419 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1421 ALCcontext
*Context
;
1425 Context
= GetContextSuspended();
1426 if(!Context
) return;
1430 alSetError(Context
, AL_INVALID_VALUE
);
1434 // Check all the Sources are valid
1435 for(i
= 0;i
< n
;i
++)
1437 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1439 alSetError(Context
, AL_INVALID_NAME
);
1444 for(i
= 0;i
< n
;i
++)
1446 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1447 if(Source
->state
!= AL_INITIAL
)
1449 Source
->state
= AL_STOPPED
;
1450 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1452 Source
->lOffset
= 0;
1456 ProcessContext(Context
);
1459 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1461 alSourceRewindv(1, &source
);
1464 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1466 ALCcontext
*Context
;
1470 Context
= GetContextSuspended();
1471 if(!Context
) return;
1475 alSetError(Context
, AL_INVALID_VALUE
);
1479 // Check all the Sources are valid
1480 for(i
= 0;i
< n
;i
++)
1482 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1484 alSetError(Context
, AL_INVALID_NAME
);
1489 for(i
= 0;i
< n
;i
++)
1491 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1492 if(Source
->state
!= AL_INITIAL
)
1494 Source
->state
= AL_INITIAL
;
1495 Source
->position
= 0;
1496 Source
->position_fraction
= 0;
1497 Source
->BuffersPlayed
= 0;
1499 Source
->Buffer
= Source
->queue
->buffer
;
1501 Source
->lOffset
= 0;
1505 ProcessContext(Context
);
1509 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1511 ALCcontext
*Context
;
1516 ALbufferlistitem
*BufferListStart
;
1517 ALbufferlistitem
*BufferList
;
1518 ALboolean HadFormat
;
1525 Context
= GetContextSuspended();
1526 if(!Context
) return;
1528 // Check that all buffers are valid or zero and that the source is valid
1530 // Check that this is a valid source
1531 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1533 alSetError(Context
, AL_INVALID_NAME
);
1537 // Check that this is not a STATIC Source
1538 if(Source
->lSourceType
== AL_STATIC
)
1540 // Invalid Source Type (can't queue on a Static Source)
1541 alSetError(Context
, AL_INVALID_OPERATION
);
1545 device
= Context
->Device
;
1549 HadFormat
= AL_FALSE
;
1551 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1552 BufferList
= Source
->queue
;
1555 if(BufferList
->buffer
)
1557 Frequency
= BufferList
->buffer
->frequency
;
1558 Format
= BufferList
->buffer
->format
;
1559 HadFormat
= AL_TRUE
;
1562 BufferList
= BufferList
->next
;
1565 for(i
= 0;i
< n
;i
++)
1570 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1572 alSetError(Context
, AL_INVALID_NAME
);
1576 if(Frequency
== -1 && Format
== -1)
1578 Frequency
= buffer
->frequency
;
1579 Format
= buffer
->format
;
1581 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->format
)
1583 alSetError(Context
, AL_INVALID_OPERATION
);
1588 // Change Source Type
1589 Source
->lSourceType
= AL_STREAMING
;
1591 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1593 // All buffers are valid - so add them to the list
1594 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1595 BufferListStart
->buffer
= buffer
;
1596 BufferListStart
->next
= NULL
;
1598 // Increment reference counter for buffer
1599 if(buffer
) buffer
->refcount
++;
1601 BufferList
= BufferListStart
;
1603 for(i
= 1;i
< n
;i
++)
1605 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1607 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1608 BufferList
->next
->buffer
= buffer
;
1609 BufferList
->next
->next
= NULL
;
1611 // Increment reference counter for buffer
1612 if(buffer
) buffer
->refcount
++;
1614 BufferList
= BufferList
->next
;
1617 if(Source
->queue
== NULL
)
1619 Source
->queue
= BufferListStart
;
1620 // Update Current Buffer
1621 Source
->Buffer
= BufferListStart
->buffer
;
1625 // Find end of queue
1626 BufferList
= Source
->queue
;
1627 while(BufferList
->next
!= NULL
)
1628 BufferList
= BufferList
->next
;
1630 BufferList
->next
= BufferListStart
;
1633 // Update number of buffers in queue
1634 Source
->BuffersInQueue
+= n
;
1635 // If no previous format, mark the source dirty now that it may have one
1637 Source
->NeedsUpdate
= AL_TRUE
;
1640 ProcessContext(Context
);
1644 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1645 // an array of buffer IDs that are to be filled with the names of the buffers removed
1646 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1648 ALCcontext
*Context
;
1651 ALbufferlistitem
*BufferList
;
1656 Context
= GetContextSuspended();
1657 if(!Context
) return;
1659 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1661 alSetError(Context
, AL_INVALID_NAME
);
1665 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1666 (ALuint
)n
> Source
->BuffersPlayed
)
1668 // Some buffers can't be unqueue because they have not been processed
1669 alSetError(Context
, AL_INVALID_VALUE
);
1673 for(i
= 0;i
< n
;i
++)
1675 BufferList
= Source
->queue
;
1676 Source
->queue
= BufferList
->next
;
1678 if(BufferList
->buffer
)
1680 // Record name of buffer
1681 buffers
[i
] = BufferList
->buffer
->buffer
;
1682 // Decrement buffer reference counter
1683 BufferList
->buffer
->refcount
--;
1688 // Release memory for buffer list item
1690 Source
->BuffersInQueue
--;
1693 if(Source
->state
!= AL_PLAYING
)
1696 Source
->Buffer
= Source
->queue
->buffer
;
1698 Source
->Buffer
= NULL
;
1700 Source
->BuffersPlayed
-= n
;
1703 ProcessContext(Context
);
1707 static ALvoid
InitSourceParams(ALsource
*Source
)
1709 Source
->flInnerAngle
= 360.0f
;
1710 Source
->flOuterAngle
= 360.0f
;
1711 Source
->flPitch
= 1.0f
;
1712 Source
->vPosition
[0] = 0.0f
;
1713 Source
->vPosition
[1] = 0.0f
;
1714 Source
->vPosition
[2] = 0.0f
;
1715 Source
->vOrientation
[0] = 0.0f
;
1716 Source
->vOrientation
[1] = 0.0f
;
1717 Source
->vOrientation
[2] = 0.0f
;
1718 Source
->vVelocity
[0] = 0.0f
;
1719 Source
->vVelocity
[1] = 0.0f
;
1720 Source
->vVelocity
[2] = 0.0f
;
1721 Source
->flRefDistance
= 1.0f
;
1722 Source
->flMaxDistance
= FLT_MAX
;
1723 Source
->flRollOffFactor
= 1.0f
;
1724 Source
->bLooping
= AL_FALSE
;
1725 Source
->flGain
= 1.0f
;
1726 Source
->flMinGain
= 0.0f
;
1727 Source
->flMaxGain
= 1.0f
;
1728 Source
->flOuterGain
= 0.0f
;
1729 Source
->OuterGainHF
= 1.0f
;
1731 Source
->DryGainHFAuto
= AL_TRUE
;
1732 Source
->WetGainAuto
= AL_TRUE
;
1733 Source
->WetGainHFAuto
= AL_TRUE
;
1734 Source
->AirAbsorptionFactor
= 0.0f
;
1735 Source
->RoomRolloffFactor
= 0.0f
;
1736 Source
->DopplerFactor
= 1.0f
;
1738 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1740 Source
->Resampler
= DefaultResampler
;
1742 Source
->state
= AL_INITIAL
;
1743 Source
->lSourceType
= AL_UNDETERMINED
;
1745 Source
->NeedsUpdate
= AL_TRUE
;
1747 Source
->Buffer
= NULL
;
1754 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1755 The offset is relative to the start of the queue (not the start of the current buffer)
1757 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1759 ALbufferlistitem
*BufferList
;
1760 ALbuffer
*Buffer
= NULL
;
1762 ALint Channels
, Bytes
;
1763 ALuint readPos
, writePos
;
1764 ALenum OriginalFormat
;
1765 ALuint TotalBufferDataSize
;
1768 // Find the first non-NULL Buffer in the Queue
1769 BufferList
= Source
->queue
;
1772 if(BufferList
->buffer
)
1774 Buffer
= BufferList
->buffer
;
1777 BufferList
= BufferList
->next
;
1780 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1787 // Get Current Buffer Size and frequency (in milliseconds)
1788 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1789 OriginalFormat
= Buffer
->eOriginalFormat
;
1790 Channels
= aluChannelsFromFormat(Buffer
->format
);
1791 Bytes
= aluBytesFromFormat(Buffer
->format
);
1793 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1794 readPos
= Source
->position
* Channels
* Bytes
;
1795 // Add byte length of any processed buffers in the queue
1796 TotalBufferDataSize
= 0;
1797 BufferList
= Source
->queue
;
1798 for(i
= 0;BufferList
;i
++)
1800 if(BufferList
->buffer
)
1802 if(i
< Source
->BuffersPlayed
)
1803 readPos
+= BufferList
->buffer
->size
;
1804 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1806 BufferList
= BufferList
->next
;
1808 if(Source
->state
== AL_PLAYING
)
1809 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1813 if(Source
->bLooping
)
1815 readPos
%= TotalBufferDataSize
;
1816 writePos
%= TotalBufferDataSize
;
1820 // Clamp positions to TotalBufferDataSize
1821 if(readPos
> TotalBufferDataSize
)
1822 readPos
= TotalBufferDataSize
;
1823 if(writePos
> TotalBufferDataSize
)
1824 writePos
= TotalBufferDataSize
;
1830 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1831 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1833 case AL_SAMPLE_OFFSET
:
1834 case AL_SAMPLE_RW_OFFSETS_EXT
:
1835 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1836 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1838 case AL_BYTE_OFFSET
:
1839 case AL_BYTE_RW_OFFSETS_EXT
:
1840 // Take into account the original format of the Buffer
1841 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1842 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1844 // Round down to nearest ADPCM block
1845 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1846 if(Source
->state
== AL_PLAYING
)
1848 // Round up to nearest ADPCM block
1849 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1852 offset
[1] = offset
[0];
1854 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1855 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1856 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1857 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1858 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1859 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1861 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1862 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1864 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1866 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1867 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1869 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1871 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1872 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1874 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1876 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1877 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1879 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1881 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1882 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1886 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1887 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1888 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1898 Apply a playback offset to the Source. This function will update the queue (to correctly
1899 mark buffers as 'pending' or 'processed' depending upon the new offset.
1901 static ALboolean
ApplyOffset(ALsource
*Source
)
1903 ALbufferlistitem
*BufferList
;
1905 ALint lBufferSize
, lTotalBufferSize
;
1906 ALint BuffersPlayed
;
1909 // Get true byte offset
1910 lByteOffset
= GetByteOffset(Source
);
1912 // If the offset is invalid, don't apply it
1913 if(lByteOffset
== -1)
1916 // Sort out the queue (pending and processed states)
1917 BufferList
= Source
->queue
;
1918 lTotalBufferSize
= 0;
1923 Buffer
= BufferList
->buffer
;
1924 lBufferSize
= Buffer
? Buffer
->size
: 0;
1926 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1928 // Offset is past this buffer so increment BuffersPlayed
1931 else if(lTotalBufferSize
<= lByteOffset
)
1933 // Offset is within this buffer
1934 // Set Current Buffer
1935 Source
->Buffer
= BufferList
->buffer
;
1936 Source
->BuffersPlayed
= BuffersPlayed
;
1938 // SW Mixer Positions are in Samples
1939 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1940 aluFrameSizeFromFormat(Buffer
->format
);
1944 // Increment the TotalBufferSize
1945 lTotalBufferSize
+= lBufferSize
;
1947 // Move on to next buffer in the Queue
1948 BufferList
= BufferList
->next
;
1950 // Offset is out of range of the buffer queue
1958 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1959 offset supplied by the application). This takes into account the fact that the buffer format
1960 may have been modifed by AL (e.g 8bit samples are converted to float)
1962 static ALint
GetByteOffset(ALsource
*Source
)
1964 ALbuffer
*Buffer
= NULL
;
1965 ALbufferlistitem
*BufferList
;
1967 ALint Channels
, Bytes
;
1968 ALint ByteOffset
= -1;
1970 // Find the first non-NULL Buffer in the Queue
1971 BufferList
= Source
->queue
;
1974 if(BufferList
->buffer
)
1976 Buffer
= BufferList
->buffer
;
1979 BufferList
= BufferList
->next
;
1984 Source
->lOffset
= 0;
1988 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
1989 Channels
= aluChannelsFromFormat(Buffer
->format
);
1990 Bytes
= aluBytesFromFormat(Buffer
->format
);
1992 // Determine the ByteOffset (and ensure it is block aligned)
1993 switch(Source
->lOffsetType
)
1995 case AL_BYTE_OFFSET
:
1996 // Take into consideration the original format
1997 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
1999 ByteOffset
*= Channels
* Bytes
;
2002 case AL_SAMPLE_OFFSET
:
2003 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2007 // Note - lOffset is internally stored as Milliseconds
2008 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2009 ByteOffset
*= Channels
* Bytes
;
2013 Source
->lOffset
= 0;
2018 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2020 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2022 // Round down to nearest ADPCM block
2023 offset
/= 36 * channels
;
2024 // Multiply by compression rate (65 sample frames per block)
2027 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2028 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2029 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2031 /* muLaw has 1 byte per sample */
2032 offset
/= 1 * channels
;
2034 else if(format
== AL_FORMAT_REAR_MULAW
)
2036 /* Rear is 2 channels */
2039 else if(format
== AL_FORMAT_REAR8
)
2041 else if(format
== AL_FORMAT_REAR16
)
2043 else if(format
== AL_FORMAT_REAR32
)
2047 ALuint bytes
= aluBytesFromFormat(format
);
2048 offset
/= bytes
* channels
;
2054 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2058 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2060 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2061 Context
->SourceMap
.array
[pos
].value
= NULL
;
2063 // For each buffer in the source's queue, decrement its reference counter and remove it
2064 while(temp
->queue
!= NULL
)
2066 ALbufferlistitem
*BufferList
= temp
->queue
;
2067 // Decrement buffer's reference counter
2068 if(BufferList
->buffer
!= NULL
)
2069 BufferList
->buffer
->refcount
--;
2070 // Update queue to point to next element in list
2071 temp
->queue
= BufferList
->next
;
2072 // Release memory allocated for buffer list item
2076 for(j
= 0;j
< MAX_SENDS
;++j
)
2078 if(temp
->Send
[j
].Slot
)
2079 temp
->Send
[j
].Slot
->refcount
--;
2082 // Release source structure
2083 ALTHUNK_REMOVEENTRY(temp
->source
);
2084 memset(temp
, 0, sizeof(ALsource
));