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(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
150 if(Context
->ActiveSources
[j
] == Source
)
152 ALsizei end
= --(Context
->ActiveSourceCount
);
153 Context
->ActiveSources
[j
] = Context
->ActiveSources
[end
];
158 // For each buffer in the source's queue, decrement its reference counter and remove it
159 while(Source
->queue
!= NULL
)
161 BufferList
= Source
->queue
;
162 // Decrement buffer's reference counter
163 if(BufferList
->buffer
!= NULL
)
164 BufferList
->buffer
->refcount
--;
165 // Update queue to point to next element in list
166 Source
->queue
= BufferList
->next
;
167 // Release memory allocated for buffer list item
171 for(j
= 0;j
< MAX_SENDS
;++j
)
173 if(Source
->Send
[j
].Slot
)
174 Source
->Send
[j
].Slot
->refcount
--;
175 Source
->Send
[j
].Slot
= NULL
;
178 // Remove Source from list of Sources
179 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
180 ALTHUNK_REMOVEENTRY(Source
->source
);
182 memset(Source
,0,sizeof(ALsource
));
189 alSetError(Context
, AL_INVALID_VALUE
);
191 ProcessContext(Context
);
195 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
200 Context
= GetContextSuspended();
201 if(!Context
) return AL_FALSE
;
203 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
205 ProcessContext(Context
);
211 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
213 ALCcontext
*pContext
;
216 pContext
= GetContextSuspended();
217 if(!pContext
) return;
219 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
226 Source
->flPitch
= flValue
;
227 if(Source
->flPitch
< 0.001f
)
228 Source
->flPitch
= 0.001f
;
229 Source
->NeedsUpdate
= AL_TRUE
;
232 alSetError(pContext
, AL_INVALID_VALUE
);
235 case AL_CONE_INNER_ANGLE
:
236 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
238 Source
->flInnerAngle
= flValue
;
239 Source
->NeedsUpdate
= AL_TRUE
;
242 alSetError(pContext
, AL_INVALID_VALUE
);
245 case AL_CONE_OUTER_ANGLE
:
246 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
248 Source
->flOuterAngle
= flValue
;
249 Source
->NeedsUpdate
= AL_TRUE
;
252 alSetError(pContext
, AL_INVALID_VALUE
);
258 Source
->flGain
= flValue
;
259 Source
->NeedsUpdate
= AL_TRUE
;
262 alSetError(pContext
, AL_INVALID_VALUE
);
265 case AL_MAX_DISTANCE
:
268 Source
->flMaxDistance
= flValue
;
269 Source
->NeedsUpdate
= AL_TRUE
;
272 alSetError(pContext
, AL_INVALID_VALUE
);
275 case AL_ROLLOFF_FACTOR
:
278 Source
->flRollOffFactor
= flValue
;
279 Source
->NeedsUpdate
= AL_TRUE
;
282 alSetError(pContext
, AL_INVALID_VALUE
);
285 case AL_REFERENCE_DISTANCE
:
288 Source
->flRefDistance
= flValue
;
289 Source
->NeedsUpdate
= AL_TRUE
;
292 alSetError(pContext
, AL_INVALID_VALUE
);
296 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
298 Source
->flMinGain
= flValue
;
299 Source
->NeedsUpdate
= AL_TRUE
;
302 alSetError(pContext
, AL_INVALID_VALUE
);
306 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
308 Source
->flMaxGain
= flValue
;
309 Source
->NeedsUpdate
= AL_TRUE
;
312 alSetError(pContext
, AL_INVALID_VALUE
);
315 case AL_CONE_OUTER_GAIN
:
316 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
318 Source
->flOuterGain
= flValue
;
319 Source
->NeedsUpdate
= AL_TRUE
;
322 alSetError(pContext
, AL_INVALID_VALUE
);
325 case AL_CONE_OUTER_GAINHF
:
326 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
328 Source
->OuterGainHF
= flValue
;
329 Source
->NeedsUpdate
= AL_TRUE
;
332 alSetError(pContext
, AL_INVALID_VALUE
);
335 case AL_AIR_ABSORPTION_FACTOR
:
336 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
338 Source
->AirAbsorptionFactor
= flValue
;
339 Source
->NeedsUpdate
= AL_TRUE
;
342 alSetError(pContext
, AL_INVALID_VALUE
);
345 case AL_ROOM_ROLLOFF_FACTOR
:
346 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
348 Source
->RoomRolloffFactor
= flValue
;
349 Source
->NeedsUpdate
= AL_TRUE
;
352 alSetError(pContext
, AL_INVALID_VALUE
);
355 case AL_DOPPLER_FACTOR
:
356 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
358 Source
->DopplerFactor
= flValue
;
359 Source
->NeedsUpdate
= AL_TRUE
;
362 alSetError(pContext
, AL_INVALID_VALUE
);
366 case AL_SAMPLE_OFFSET
:
370 Source
->lOffsetType
= eParam
;
372 // Store Offset (convert Seconds into Milliseconds)
373 if(eParam
== AL_SEC_OFFSET
)
374 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
376 Source
->lOffset
= (ALint
)flValue
;
378 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
380 if(ApplyOffset(Source
) == AL_FALSE
)
381 alSetError(pContext
, AL_INVALID_VALUE
);
385 alSetError(pContext
, AL_INVALID_VALUE
);
389 alSetError(pContext
, AL_INVALID_ENUM
);
395 // Invalid Source Name
396 alSetError(pContext
, AL_INVALID_NAME
);
399 ProcessContext(pContext
);
403 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
405 ALCcontext
*pContext
;
408 pContext
= GetContextSuspended();
409 if(!pContext
) return;
411 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
416 Source
->vPosition
[0] = flValue1
;
417 Source
->vPosition
[1] = flValue2
;
418 Source
->vPosition
[2] = flValue3
;
419 Source
->NeedsUpdate
= AL_TRUE
;
423 Source
->vVelocity
[0] = flValue1
;
424 Source
->vVelocity
[1] = flValue2
;
425 Source
->vVelocity
[2] = flValue3
;
426 Source
->NeedsUpdate
= AL_TRUE
;
430 Source
->vOrientation
[0] = flValue1
;
431 Source
->vOrientation
[1] = flValue2
;
432 Source
->vOrientation
[2] = flValue3
;
433 Source
->NeedsUpdate
= AL_TRUE
;
437 alSetError(pContext
, AL_INVALID_ENUM
);
442 alSetError(pContext
, AL_INVALID_NAME
);
444 ProcessContext(pContext
);
448 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
450 ALCcontext
*pContext
;
452 pContext
= GetContextSuspended();
453 if(!pContext
) return;
457 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
462 case AL_CONE_INNER_ANGLE
:
463 case AL_CONE_OUTER_ANGLE
:
465 case AL_MAX_DISTANCE
:
466 case AL_ROLLOFF_FACTOR
:
467 case AL_REFERENCE_DISTANCE
:
470 case AL_CONE_OUTER_GAIN
:
471 case AL_CONE_OUTER_GAINHF
:
473 case AL_SAMPLE_OFFSET
:
475 case AL_AIR_ABSORPTION_FACTOR
:
476 case AL_ROOM_ROLLOFF_FACTOR
:
477 alSourcef(source
, eParam
, pflValues
[0]);
483 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
487 alSetError(pContext
, AL_INVALID_ENUM
);
492 alSetError(pContext
, AL_INVALID_NAME
);
495 alSetError(pContext
, AL_INVALID_VALUE
);
497 ProcessContext(pContext
);
501 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
503 ALCcontext
*pContext
;
505 ALbufferlistitem
*BufferListItem
;
507 pContext
= GetContextSuspended();
508 if(!pContext
) return;
510 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
512 ALCdevice
*device
= pContext
->Device
;
516 case AL_MAX_DISTANCE
:
517 case AL_ROLLOFF_FACTOR
:
518 case AL_CONE_INNER_ANGLE
:
519 case AL_CONE_OUTER_ANGLE
:
520 case AL_REFERENCE_DISTANCE
:
521 alSourcef(source
, eParam
, (ALfloat
)lValue
);
524 case AL_SOURCE_RELATIVE
:
525 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
527 Source
->bHeadRelative
= (ALboolean
)lValue
;
528 Source
->NeedsUpdate
= AL_TRUE
;
531 alSetError(pContext
, AL_INVALID_VALUE
);
535 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
536 Source
->bLooping
= (ALboolean
)lValue
;
538 alSetError(pContext
, AL_INVALID_VALUE
);
542 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
544 ALbuffer
*buffer
= NULL
;
547 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
549 // Remove all elements in the queue
550 while(Source
->queue
!= NULL
)
552 BufferListItem
= Source
->queue
;
553 Source
->queue
= BufferListItem
->next
;
554 // Decrement reference counter for buffer
555 if(BufferListItem
->buffer
)
556 BufferListItem
->buffer
->refcount
--;
557 // Release memory for buffer list item
558 free(BufferListItem
);
559 // Decrement the number of buffers in the queue
560 Source
->BuffersInQueue
--;
563 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
566 // Source is now in STATIC mode
567 Source
->lSourceType
= AL_STATIC
;
569 // Add the selected buffer to the queue
570 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
571 BufferListItem
->buffer
= buffer
;
572 BufferListItem
->next
= NULL
;
574 Source
->queue
= BufferListItem
;
575 Source
->BuffersInQueue
= 1;
577 if(aluChannelsFromFormat(buffer
->format
) == 1)
578 Source
->Update
= CalcSourceParams
;
580 Source
->Update
= CalcNonAttnSourceParams
;
582 // Increment reference counter for buffer
587 // Source is now in UNDETERMINED mode
588 Source
->lSourceType
= AL_UNDETERMINED
;
590 Source
->BuffersPlayed
= 0;
592 // Update AL_BUFFER parameter
593 Source
->Buffer
= buffer
;
594 Source
->NeedsUpdate
= AL_TRUE
;
597 alSetError(pContext
, AL_INVALID_VALUE
);
600 alSetError(pContext
, AL_INVALID_OPERATION
);
603 case AL_SOURCE_STATE
:
605 alSetError(pContext
, AL_INVALID_OPERATION
);
609 case AL_SAMPLE_OFFSET
:
613 Source
->lOffsetType
= eParam
;
615 // Store Offset (convert Seconds into Milliseconds)
616 if(eParam
== AL_SEC_OFFSET
)
617 Source
->lOffset
= lValue
* 1000;
619 Source
->lOffset
= lValue
;
621 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
623 if(ApplyOffset(Source
) == AL_FALSE
)
624 alSetError(pContext
, AL_INVALID_VALUE
);
628 alSetError(pContext
, AL_INVALID_VALUE
);
631 case AL_DIRECT_FILTER
: {
632 ALfilter
*filter
= NULL
;
635 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
639 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
640 Source
->DirectFilter
.filter
= 0;
643 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
644 Source
->NeedsUpdate
= AL_TRUE
;
647 alSetError(pContext
, AL_INVALID_VALUE
);
650 case AL_DIRECT_FILTER_GAINHF_AUTO
:
651 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
653 Source
->DryGainHFAuto
= lValue
;
654 Source
->NeedsUpdate
= AL_TRUE
;
657 alSetError(pContext
, AL_INVALID_VALUE
);
660 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
661 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
663 Source
->WetGainAuto
= lValue
;
664 Source
->NeedsUpdate
= AL_TRUE
;
667 alSetError(pContext
, AL_INVALID_VALUE
);
670 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
671 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
673 Source
->WetGainHFAuto
= lValue
;
674 Source
->NeedsUpdate
= AL_TRUE
;
677 alSetError(pContext
, AL_INVALID_VALUE
);
680 case AL_DISTANCE_MODEL
:
681 if(lValue
== AL_NONE
||
682 lValue
== AL_INVERSE_DISTANCE
||
683 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
684 lValue
== AL_LINEAR_DISTANCE
||
685 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
686 lValue
== AL_EXPONENT_DISTANCE
||
687 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
689 Source
->DistanceModel
= lValue
;
690 if(pContext
->SourceDistanceModel
)
691 Source
->NeedsUpdate
= AL_TRUE
;
694 alSetError(pContext
, AL_INVALID_VALUE
);
698 alSetError(pContext
, AL_INVALID_ENUM
);
703 alSetError(pContext
, AL_INVALID_NAME
);
705 ProcessContext(pContext
);
709 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
711 ALCcontext
*pContext
;
714 pContext
= GetContextSuspended();
715 if(!pContext
) return;
717 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
719 ALCdevice
*device
= pContext
->Device
;
726 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
729 case AL_AUXILIARY_SEND_FILTER
: {
730 ALeffectslot
*ALEffectSlot
= NULL
;
731 ALfilter
*ALFilter
= NULL
;
733 if((ALuint
)lValue2
< device
->NumAuxSends
&&
735 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
737 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
739 /* Release refcount on the previous slot, and add one for
741 if(Source
->Send
[lValue2
].Slot
)
742 Source
->Send
[lValue2
].Slot
->refcount
--;
743 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
744 if(Source
->Send
[lValue2
].Slot
)
745 Source
->Send
[lValue2
].Slot
->refcount
++;
750 Source
->Send
[lValue2
].WetFilter
.type
= 0;
751 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
754 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
755 Source
->NeedsUpdate
= AL_TRUE
;
758 alSetError(pContext
, AL_INVALID_VALUE
);
762 alSetError(pContext
, AL_INVALID_ENUM
);
767 alSetError(pContext
, AL_INVALID_NAME
);
769 ProcessContext(pContext
);
773 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
775 ALCcontext
*pContext
;
777 pContext
= GetContextSuspended();
778 if(!pContext
) return;
782 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
786 case AL_SOURCE_RELATIVE
:
787 case AL_CONE_INNER_ANGLE
:
788 case AL_CONE_OUTER_ANGLE
:
791 case AL_SOURCE_STATE
:
793 case AL_SAMPLE_OFFSET
:
795 case AL_MAX_DISTANCE
:
796 case AL_ROLLOFF_FACTOR
:
797 case AL_REFERENCE_DISTANCE
:
798 case AL_DIRECT_FILTER
:
799 case AL_DIRECT_FILTER_GAINHF_AUTO
:
800 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
801 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
802 case AL_DISTANCE_MODEL
:
803 alSourcei(source
, eParam
, plValues
[0]);
809 case AL_AUXILIARY_SEND_FILTER
:
810 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
814 alSetError(pContext
, AL_INVALID_ENUM
);
819 alSetError(pContext
, AL_INVALID_NAME
);
822 alSetError(pContext
, AL_INVALID_VALUE
);
824 ProcessContext(pContext
);
828 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
830 ALCcontext
*pContext
;
835 pContext
= GetContextSuspended();
836 if(!pContext
) return;
840 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
845 *pflValue
= Source
->flPitch
;
849 *pflValue
= Source
->flGain
;
853 *pflValue
= Source
->flMinGain
;
857 *pflValue
= Source
->flMaxGain
;
860 case AL_MAX_DISTANCE
:
861 *pflValue
= Source
->flMaxDistance
;
864 case AL_ROLLOFF_FACTOR
:
865 *pflValue
= Source
->flRollOffFactor
;
868 case AL_CONE_OUTER_GAIN
:
869 *pflValue
= Source
->flOuterGain
;
872 case AL_CONE_OUTER_GAINHF
:
873 *pflValue
= Source
->OuterGainHF
;
877 case AL_SAMPLE_OFFSET
:
879 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
880 pContext
->Device
->Frequency
;
881 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
882 *pflValue
= Offsets
[0];
885 case AL_CONE_INNER_ANGLE
:
886 *pflValue
= Source
->flInnerAngle
;
889 case AL_CONE_OUTER_ANGLE
:
890 *pflValue
= Source
->flOuterAngle
;
893 case AL_REFERENCE_DISTANCE
:
894 *pflValue
= Source
->flRefDistance
;
897 case AL_AIR_ABSORPTION_FACTOR
:
898 *pflValue
= Source
->AirAbsorptionFactor
;
901 case AL_ROOM_ROLLOFF_FACTOR
:
902 *pflValue
= Source
->RoomRolloffFactor
;
905 case AL_DOPPLER_FACTOR
:
906 *pflValue
= Source
->DopplerFactor
;
910 alSetError(pContext
, AL_INVALID_ENUM
);
915 alSetError(pContext
, AL_INVALID_NAME
);
918 alSetError(pContext
, AL_INVALID_VALUE
);
920 ProcessContext(pContext
);
924 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
926 ALCcontext
*pContext
;
929 pContext
= GetContextSuspended();
930 if(!pContext
) return;
932 if(pflValue1
&& pflValue2
&& pflValue3
)
934 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
939 *pflValue1
= Source
->vPosition
[0];
940 *pflValue2
= Source
->vPosition
[1];
941 *pflValue3
= Source
->vPosition
[2];
945 *pflValue1
= Source
->vVelocity
[0];
946 *pflValue2
= Source
->vVelocity
[1];
947 *pflValue3
= Source
->vVelocity
[2];
951 *pflValue1
= Source
->vOrientation
[0];
952 *pflValue2
= Source
->vOrientation
[1];
953 *pflValue3
= Source
->vOrientation
[2];
957 alSetError(pContext
, AL_INVALID_ENUM
);
962 alSetError(pContext
, AL_INVALID_NAME
);
965 alSetError(pContext
, AL_INVALID_VALUE
);
967 ProcessContext(pContext
);
971 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
973 ALCcontext
*pContext
;
978 pContext
= GetContextSuspended();
979 if(!pContext
) return;
983 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
991 case AL_MAX_DISTANCE
:
992 case AL_ROLLOFF_FACTOR
:
993 case AL_DOPPLER_FACTOR
:
994 case AL_CONE_OUTER_GAIN
:
996 case AL_SAMPLE_OFFSET
:
998 case AL_CONE_INNER_ANGLE
:
999 case AL_CONE_OUTER_ANGLE
:
1000 case AL_REFERENCE_DISTANCE
:
1001 case AL_CONE_OUTER_GAINHF
:
1002 case AL_AIR_ABSORPTION_FACTOR
:
1003 case AL_ROOM_ROLLOFF_FACTOR
:
1004 alGetSourcef(source
, eParam
, pflValues
);
1010 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
1013 case AL_SAMPLE_RW_OFFSETS_EXT
:
1014 case AL_BYTE_RW_OFFSETS_EXT
:
1015 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1016 pContext
->Device
->Frequency
;
1017 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1018 pflValues
[0] = Offsets
[0];
1019 pflValues
[1] = Offsets
[1];
1023 alSetError(pContext
, AL_INVALID_ENUM
);
1028 alSetError(pContext
, AL_INVALID_NAME
);
1031 alSetError(pContext
, AL_INVALID_VALUE
);
1033 ProcessContext(pContext
);
1037 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1039 ALCcontext
*pContext
;
1041 ALdouble Offsets
[2];
1044 pContext
= GetContextSuspended();
1045 if(!pContext
) return;
1049 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1053 case AL_MAX_DISTANCE
:
1054 *plValue
= (ALint
)Source
->flMaxDistance
;
1057 case AL_ROLLOFF_FACTOR
:
1058 *plValue
= (ALint
)Source
->flRollOffFactor
;
1061 case AL_REFERENCE_DISTANCE
:
1062 *plValue
= (ALint
)Source
->flRefDistance
;
1065 case AL_SOURCE_RELATIVE
:
1066 *plValue
= Source
->bHeadRelative
;
1069 case AL_CONE_INNER_ANGLE
:
1070 *plValue
= (ALint
)Source
->flInnerAngle
;
1073 case AL_CONE_OUTER_ANGLE
:
1074 *plValue
= (ALint
)Source
->flOuterAngle
;
1078 *plValue
= Source
->bLooping
;
1082 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1085 case AL_SOURCE_STATE
:
1086 *plValue
= Source
->state
;
1089 case AL_BUFFERS_QUEUED
:
1090 *plValue
= Source
->BuffersInQueue
;
1093 case AL_BUFFERS_PROCESSED
:
1094 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1096 /* Buffers on a looping source are in a perpetual state
1097 * of PENDING, so don't report any as PROCESSED */
1101 *plValue
= Source
->BuffersPlayed
;
1104 case AL_SOURCE_TYPE
:
1105 *plValue
= Source
->lSourceType
;
1109 case AL_SAMPLE_OFFSET
:
1110 case AL_BYTE_OFFSET
:
1111 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1112 pContext
->Device
->Frequency
;
1113 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1114 *plValue
= (ALint
)Offsets
[0];
1117 case AL_DIRECT_FILTER
:
1118 *plValue
= Source
->DirectFilter
.filter
;
1121 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1122 *plValue
= Source
->DryGainHFAuto
;
1125 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1126 *plValue
= Source
->WetGainAuto
;
1129 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1130 *plValue
= Source
->WetGainHFAuto
;
1133 case AL_DOPPLER_FACTOR
:
1134 *plValue
= (ALint
)Source
->DopplerFactor
;
1137 case AL_DISTANCE_MODEL
:
1138 *plValue
= Source
->DistanceModel
;
1142 alSetError(pContext
, AL_INVALID_ENUM
);
1147 alSetError(pContext
, AL_INVALID_NAME
);
1150 alSetError(pContext
, AL_INVALID_VALUE
);
1152 ProcessContext(pContext
);
1156 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1158 ALCcontext
*pContext
;
1161 pContext
= GetContextSuspended();
1162 if(!pContext
) return;
1164 if(plValue1
&& plValue2
&& plValue3
)
1166 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1171 *plValue1
= (ALint
)Source
->vPosition
[0];
1172 *plValue2
= (ALint
)Source
->vPosition
[1];
1173 *plValue3
= (ALint
)Source
->vPosition
[2];
1177 *plValue1
= (ALint
)Source
->vVelocity
[0];
1178 *plValue2
= (ALint
)Source
->vVelocity
[1];
1179 *plValue3
= (ALint
)Source
->vVelocity
[2];
1183 *plValue1
= (ALint
)Source
->vOrientation
[0];
1184 *plValue2
= (ALint
)Source
->vOrientation
[1];
1185 *plValue3
= (ALint
)Source
->vOrientation
[2];
1189 alSetError(pContext
, AL_INVALID_ENUM
);
1194 alSetError(pContext
, AL_INVALID_NAME
);
1197 alSetError(pContext
, AL_INVALID_VALUE
);
1199 ProcessContext(pContext
);
1203 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1205 ALCcontext
*pContext
;
1207 ALdouble Offsets
[2];
1210 pContext
= GetContextSuspended();
1211 if(!pContext
) return;
1215 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1219 case AL_SOURCE_RELATIVE
:
1220 case AL_CONE_INNER_ANGLE
:
1221 case AL_CONE_OUTER_ANGLE
:
1224 case AL_SOURCE_STATE
:
1225 case AL_BUFFERS_QUEUED
:
1226 case AL_BUFFERS_PROCESSED
:
1228 case AL_SAMPLE_OFFSET
:
1229 case AL_BYTE_OFFSET
:
1230 case AL_MAX_DISTANCE
:
1231 case AL_ROLLOFF_FACTOR
:
1232 case AL_DOPPLER_FACTOR
:
1233 case AL_REFERENCE_DISTANCE
:
1234 case AL_SOURCE_TYPE
:
1235 case AL_DIRECT_FILTER
:
1236 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1237 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1238 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1239 case AL_DISTANCE_MODEL
:
1240 alGetSourcei(source
, eParam
, plValues
);
1246 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1249 case AL_SAMPLE_RW_OFFSETS_EXT
:
1250 case AL_BYTE_RW_OFFSETS_EXT
:
1251 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1252 pContext
->Device
->Frequency
;
1253 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1254 plValues
[0] = (ALint
)Offsets
[0];
1255 plValues
[1] = (ALint
)Offsets
[1];
1259 alSetError(pContext
, AL_INVALID_ENUM
);
1264 alSetError(pContext
, AL_INVALID_NAME
);
1267 alSetError(pContext
, AL_INVALID_VALUE
);
1269 ProcessContext(pContext
);
1273 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1275 alSourcePlayv(1, &source
);
1278 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1280 ALCcontext
*Context
;
1282 ALbufferlistitem
*BufferList
;
1285 Context
= GetContextSuspended();
1286 if(!Context
) return;
1290 alSetError(Context
, AL_INVALID_VALUE
);
1294 // Check that all the Sources are valid
1295 for(i
= 0;i
< n
;i
++)
1297 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1299 alSetError(Context
, AL_INVALID_NAME
);
1304 if(Context
->ActiveSourceCount
+n
< n
)
1306 alSetError(Context
, AL_OUT_OF_MEMORY
);
1310 while(Context
->MaxActiveSources
< Context
->ActiveSourceCount
+n
)
1315 newcount
= Context
->MaxActiveSources
<< 1;
1317 temp
= realloc(Context
->ActiveSources
,
1318 sizeof(*Context
->ActiveSources
) * newcount
);
1321 alSetError(Context
, AL_OUT_OF_MEMORY
);
1325 Context
->ActiveSources
= temp
;
1326 Context
->MaxActiveSources
= newcount
;
1329 for(i
= 0;i
< n
;i
++)
1331 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1333 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1334 BufferList
= Source
->queue
;
1337 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1339 BufferList
= BufferList
->next
;
1344 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1348 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1349 Source
->DryGains
[j
] = 0.0f
;
1350 for(j
= 0;j
< MAX_SENDS
;j
++)
1351 Source
->WetGains
[j
] = 0.0f
;
1353 if(Source
->state
!= AL_PAUSED
)
1355 Source
->state
= AL_PLAYING
;
1356 Source
->position
= 0;
1357 Source
->position_fraction
= 0;
1358 Source
->BuffersPlayed
= 0;
1360 Source
->Buffer
= Source
->queue
->buffer
;
1363 Source
->state
= AL_PLAYING
;
1365 // Check if an Offset has been set
1367 ApplyOffset(Source
);
1369 Source
->FirstStart
= AL_TRUE
;
1371 // If device is disconnected, go right to stopped
1372 if(!Context
->Device
->Connected
)
1374 Source
->state
= AL_STOPPED
;
1375 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1376 Source
->position
= 0;
1377 Source
->position_fraction
= 0;
1381 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1383 if(Context
->ActiveSources
[j
] == Source
)
1386 if(j
== Context
->ActiveSourceCount
)
1387 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1392 ProcessContext(Context
);
1395 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1397 alSourcePausev(1, &source
);
1400 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1402 ALCcontext
*Context
;
1406 Context
= GetContextSuspended();
1407 if(!Context
) return;
1411 alSetError(Context
, AL_INVALID_VALUE
);
1415 // Check all the Sources are valid
1416 for(i
= 0;i
< n
;i
++)
1418 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1420 alSetError(Context
, AL_INVALID_NAME
);
1425 for(i
= 0;i
< n
;i
++)
1427 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1428 if(Source
->state
== AL_PLAYING
)
1429 Source
->state
= AL_PAUSED
;
1433 ProcessContext(Context
);
1436 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1438 alSourceStopv(1, &source
);
1441 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1443 ALCcontext
*Context
;
1447 Context
= GetContextSuspended();
1448 if(!Context
) return;
1452 alSetError(Context
, AL_INVALID_VALUE
);
1456 // Check all the Sources are valid
1457 for(i
= 0;i
< n
;i
++)
1459 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1461 alSetError(Context
, AL_INVALID_NAME
);
1466 for(i
= 0;i
< n
;i
++)
1468 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1469 if(Source
->state
!= AL_INITIAL
)
1471 Source
->state
= AL_STOPPED
;
1472 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1474 Source
->lOffset
= 0;
1478 ProcessContext(Context
);
1481 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1483 alSourceRewindv(1, &source
);
1486 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1488 ALCcontext
*Context
;
1492 Context
= GetContextSuspended();
1493 if(!Context
) return;
1497 alSetError(Context
, AL_INVALID_VALUE
);
1501 // Check all the Sources are valid
1502 for(i
= 0;i
< n
;i
++)
1504 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1506 alSetError(Context
, AL_INVALID_NAME
);
1511 for(i
= 0;i
< n
;i
++)
1513 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1514 if(Source
->state
!= AL_INITIAL
)
1516 Source
->state
= AL_INITIAL
;
1517 Source
->position
= 0;
1518 Source
->position_fraction
= 0;
1519 Source
->BuffersPlayed
= 0;
1521 Source
->Buffer
= Source
->queue
->buffer
;
1523 Source
->lOffset
= 0;
1527 ProcessContext(Context
);
1531 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1533 ALCcontext
*Context
;
1538 ALbufferlistitem
*BufferListStart
;
1539 ALbufferlistitem
*BufferList
;
1546 Context
= GetContextSuspended();
1547 if(!Context
) return;
1549 // Check that all buffers are valid or zero and that the source is valid
1551 // Check that this is a valid source
1552 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1554 alSetError(Context
, AL_INVALID_NAME
);
1558 // Check that this is not a STATIC Source
1559 if(Source
->lSourceType
== AL_STATIC
)
1561 // Invalid Source Type (can't queue on a Static Source)
1562 alSetError(Context
, AL_INVALID_OPERATION
);
1566 device
= Context
->Device
;
1571 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1572 BufferList
= Source
->queue
;
1575 if(BufferList
->buffer
)
1577 Frequency
= BufferList
->buffer
->frequency
;
1578 Format
= BufferList
->buffer
->eOriginalFormat
;
1581 BufferList
= BufferList
->next
;
1584 for(i
= 0;i
< n
;i
++)
1589 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1591 alSetError(Context
, AL_INVALID_NAME
);
1595 if(Frequency
== -1 && Format
== -1)
1597 Frequency
= buffer
->frequency
;
1598 Format
= buffer
->eOriginalFormat
;
1599 if(aluChannelsFromFormat(buffer
->format
) == 1)
1600 Source
->Update
= CalcSourceParams
;
1602 Source
->Update
= CalcNonAttnSourceParams
;
1603 Source
->NeedsUpdate
= AL_TRUE
;
1605 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1607 alSetError(Context
, AL_INVALID_OPERATION
);
1612 // Change Source Type
1613 Source
->lSourceType
= AL_STREAMING
;
1615 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1617 // All buffers are valid - so add them to the list
1618 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1619 BufferListStart
->buffer
= buffer
;
1620 BufferListStart
->next
= NULL
;
1622 // Increment reference counter for buffer
1623 if(buffer
) buffer
->refcount
++;
1625 BufferList
= BufferListStart
;
1627 for(i
= 1;i
< n
;i
++)
1629 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1631 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1632 BufferList
->next
->buffer
= buffer
;
1633 BufferList
->next
->next
= NULL
;
1635 // Increment reference counter for buffer
1636 if(buffer
) buffer
->refcount
++;
1638 BufferList
= BufferList
->next
;
1641 if(Source
->queue
== NULL
)
1643 Source
->queue
= BufferListStart
;
1644 // Update Current Buffer
1645 Source
->Buffer
= BufferListStart
->buffer
;
1649 // Find end of queue
1650 BufferList
= Source
->queue
;
1651 while(BufferList
->next
!= NULL
)
1652 BufferList
= BufferList
->next
;
1654 BufferList
->next
= BufferListStart
;
1657 // Update number of buffers in queue
1658 Source
->BuffersInQueue
+= n
;
1661 ProcessContext(Context
);
1665 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1666 // an array of buffer IDs that are to be filled with the names of the buffers removed
1667 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1669 ALCcontext
*Context
;
1672 ALbufferlistitem
*BufferList
;
1677 Context
= GetContextSuspended();
1678 if(!Context
) return;
1680 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1682 alSetError(Context
, AL_INVALID_NAME
);
1686 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1687 (ALuint
)n
> Source
->BuffersPlayed
)
1689 // Some buffers can't be unqueue because they have not been processed
1690 alSetError(Context
, AL_INVALID_VALUE
);
1694 for(i
= 0;i
< n
;i
++)
1696 BufferList
= Source
->queue
;
1697 Source
->queue
= BufferList
->next
;
1699 if(BufferList
->buffer
)
1701 // Record name of buffer
1702 buffers
[i
] = BufferList
->buffer
->buffer
;
1703 // Decrement buffer reference counter
1704 BufferList
->buffer
->refcount
--;
1709 // Release memory for buffer list item
1711 Source
->BuffersInQueue
--;
1714 if(Source
->state
!= AL_PLAYING
)
1717 Source
->Buffer
= Source
->queue
->buffer
;
1719 Source
->Buffer
= NULL
;
1721 Source
->BuffersPlayed
-= n
;
1724 ProcessContext(Context
);
1728 static ALvoid
InitSourceParams(ALsource
*Source
)
1730 Source
->flInnerAngle
= 360.0f
;
1731 Source
->flOuterAngle
= 360.0f
;
1732 Source
->flPitch
= 1.0f
;
1733 Source
->vPosition
[0] = 0.0f
;
1734 Source
->vPosition
[1] = 0.0f
;
1735 Source
->vPosition
[2] = 0.0f
;
1736 Source
->vOrientation
[0] = 0.0f
;
1737 Source
->vOrientation
[1] = 0.0f
;
1738 Source
->vOrientation
[2] = 0.0f
;
1739 Source
->vVelocity
[0] = 0.0f
;
1740 Source
->vVelocity
[1] = 0.0f
;
1741 Source
->vVelocity
[2] = 0.0f
;
1742 Source
->flRefDistance
= 1.0f
;
1743 Source
->flMaxDistance
= FLT_MAX
;
1744 Source
->flRollOffFactor
= 1.0f
;
1745 Source
->bLooping
= AL_FALSE
;
1746 Source
->flGain
= 1.0f
;
1747 Source
->flMinGain
= 0.0f
;
1748 Source
->flMaxGain
= 1.0f
;
1749 Source
->flOuterGain
= 0.0f
;
1750 Source
->OuterGainHF
= 1.0f
;
1752 Source
->DryGainHFAuto
= AL_TRUE
;
1753 Source
->WetGainAuto
= AL_TRUE
;
1754 Source
->WetGainHFAuto
= AL_TRUE
;
1755 Source
->AirAbsorptionFactor
= 0.0f
;
1756 Source
->RoomRolloffFactor
= 0.0f
;
1757 Source
->DopplerFactor
= 1.0f
;
1759 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1761 Source
->Resampler
= DefaultResampler
;
1763 Source
->state
= AL_INITIAL
;
1764 Source
->lSourceType
= AL_UNDETERMINED
;
1766 Source
->NeedsUpdate
= AL_TRUE
;
1768 Source
->Buffer
= NULL
;
1775 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1776 The offset is relative to the start of the queue (not the start of the current buffer)
1778 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1780 ALbufferlistitem
*BufferList
;
1781 ALbuffer
*Buffer
= NULL
;
1783 ALint Channels
, Bytes
;
1784 ALuint readPos
, writePos
;
1785 ALenum OriginalFormat
;
1786 ALuint TotalBufferDataSize
;
1789 // Find the first non-NULL Buffer in the Queue
1790 BufferList
= Source
->queue
;
1793 if(BufferList
->buffer
)
1795 Buffer
= BufferList
->buffer
;
1798 BufferList
= BufferList
->next
;
1801 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1808 // Get Current Buffer Size and frequency (in milliseconds)
1809 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1810 OriginalFormat
= Buffer
->eOriginalFormat
;
1811 Channels
= aluChannelsFromFormat(Buffer
->format
);
1812 Bytes
= aluBytesFromFormat(Buffer
->format
);
1814 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1815 readPos
= Source
->position
* Channels
* Bytes
;
1816 // Add byte length of any processed buffers in the queue
1817 TotalBufferDataSize
= 0;
1818 BufferList
= Source
->queue
;
1819 for(i
= 0;BufferList
;i
++)
1821 if(BufferList
->buffer
)
1823 if(i
< Source
->BuffersPlayed
)
1824 readPos
+= BufferList
->buffer
->size
;
1825 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1827 BufferList
= BufferList
->next
;
1829 if(Source
->state
== AL_PLAYING
)
1830 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1834 if(Source
->bLooping
)
1836 readPos
%= TotalBufferDataSize
;
1837 writePos
%= TotalBufferDataSize
;
1841 // Clamp positions to TotalBufferDataSize
1842 if(readPos
> TotalBufferDataSize
)
1843 readPos
= TotalBufferDataSize
;
1844 if(writePos
> TotalBufferDataSize
)
1845 writePos
= TotalBufferDataSize
;
1851 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1852 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1854 case AL_SAMPLE_OFFSET
:
1855 case AL_SAMPLE_RW_OFFSETS_EXT
:
1856 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1857 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1859 case AL_BYTE_OFFSET
:
1860 case AL_BYTE_RW_OFFSETS_EXT
:
1861 // Take into account the original format of the Buffer
1862 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1863 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1865 // Round down to nearest ADPCM block
1866 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1867 if(Source
->state
== AL_PLAYING
)
1869 // Round up to nearest ADPCM block
1870 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1873 offset
[1] = offset
[0];
1875 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1876 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1877 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1878 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1879 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1880 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1882 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1883 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1885 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1887 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1888 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1890 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1892 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1893 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1895 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1897 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1898 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1900 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1902 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1903 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1907 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1908 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1909 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1919 Apply a playback offset to the Source. This function will update the queue (to correctly
1920 mark buffers as 'pending' or 'processed' depending upon the new offset.
1922 static ALboolean
ApplyOffset(ALsource
*Source
)
1924 ALbufferlistitem
*BufferList
;
1926 ALint lBufferSize
, lTotalBufferSize
;
1927 ALint BuffersPlayed
;
1930 // Get true byte offset
1931 lByteOffset
= GetByteOffset(Source
);
1933 // If the offset is invalid, don't apply it
1934 if(lByteOffset
== -1)
1937 // Sort out the queue (pending and processed states)
1938 BufferList
= Source
->queue
;
1939 lTotalBufferSize
= 0;
1944 Buffer
= BufferList
->buffer
;
1945 lBufferSize
= Buffer
? Buffer
->size
: 0;
1947 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1949 // Offset is past this buffer so increment BuffersPlayed
1952 else if(lTotalBufferSize
<= lByteOffset
)
1954 // Offset is within this buffer
1955 // Set Current Buffer
1956 Source
->Buffer
= BufferList
->buffer
;
1957 Source
->BuffersPlayed
= BuffersPlayed
;
1959 // SW Mixer Positions are in Samples
1960 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1961 aluFrameSizeFromFormat(Buffer
->format
);
1965 // Increment the TotalBufferSize
1966 lTotalBufferSize
+= lBufferSize
;
1968 // Move on to next buffer in the Queue
1969 BufferList
= BufferList
->next
;
1971 // Offset is out of range of the buffer queue
1979 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1980 offset supplied by the application). This takes into account the fact that the buffer format
1981 may have been modifed by AL (e.g 8bit samples are converted to float)
1983 static ALint
GetByteOffset(ALsource
*Source
)
1985 ALbuffer
*Buffer
= NULL
;
1986 ALbufferlistitem
*BufferList
;
1988 ALint Channels
, Bytes
;
1989 ALint ByteOffset
= -1;
1991 // Find the first non-NULL Buffer in the Queue
1992 BufferList
= Source
->queue
;
1995 if(BufferList
->buffer
)
1997 Buffer
= BufferList
->buffer
;
2000 BufferList
= BufferList
->next
;
2005 Source
->lOffset
= 0;
2009 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
2010 Channels
= aluChannelsFromFormat(Buffer
->format
);
2011 Bytes
= aluBytesFromFormat(Buffer
->format
);
2013 // Determine the ByteOffset (and ensure it is block aligned)
2014 switch(Source
->lOffsetType
)
2016 case AL_BYTE_OFFSET
:
2017 // Take into consideration the original format
2018 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2020 ByteOffset
*= Channels
* Bytes
;
2023 case AL_SAMPLE_OFFSET
:
2024 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2028 // Note - lOffset is internally stored as Milliseconds
2029 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2030 ByteOffset
*= Channels
* Bytes
;
2034 Source
->lOffset
= 0;
2039 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2041 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2043 // Round down to nearest ADPCM block
2044 offset
/= 36 * channels
;
2045 // Multiply by compression rate (65 sample frames per block)
2048 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2049 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2050 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2052 /* muLaw has 1 byte per sample */
2053 offset
/= 1 * channels
;
2055 else if(format
== AL_FORMAT_REAR_MULAW
)
2057 /* Rear is 2 channels */
2060 else if(format
== AL_FORMAT_REAR8
)
2062 else if(format
== AL_FORMAT_REAR16
)
2064 else if(format
== AL_FORMAT_REAR32
)
2068 ALuint bytes
= aluBytesFromFormat(format
);
2069 offset
/= bytes
* channels
;
2075 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2079 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2081 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2082 Context
->SourceMap
.array
[pos
].value
= NULL
;
2084 // For each buffer in the source's queue, decrement its reference counter and remove it
2085 while(temp
->queue
!= NULL
)
2087 ALbufferlistitem
*BufferList
= temp
->queue
;
2088 // Decrement buffer's reference counter
2089 if(BufferList
->buffer
!= NULL
)
2090 BufferList
->buffer
->refcount
--;
2091 // Update queue to point to next element in list
2092 temp
->queue
= BufferList
->next
;
2093 // Release memory allocated for buffer list item
2097 for(j
= 0;j
< MAX_SENDS
;++j
)
2099 if(temp
->Send
[j
].Slot
)
2100 temp
->Send
[j
].Slot
->refcount
--;
2103 // Release source structure
2104 ALTHUNK_REMOVEENTRY(temp
->source
);
2105 memset(temp
, 0, sizeof(ALsource
));