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 // Increment reference counter for buffer
582 // Source is now in UNDETERMINED mode
583 Source
->lSourceType
= AL_UNDETERMINED
;
585 Source
->BuffersPlayed
= 0;
587 // Update AL_BUFFER parameter
588 Source
->Buffer
= buffer
;
589 Source
->NeedsUpdate
= AL_TRUE
;
592 alSetError(pContext
, AL_INVALID_VALUE
);
595 alSetError(pContext
, AL_INVALID_OPERATION
);
598 case AL_SOURCE_STATE
:
600 alSetError(pContext
, AL_INVALID_OPERATION
);
604 case AL_SAMPLE_OFFSET
:
608 Source
->lOffsetType
= eParam
;
610 // Store Offset (convert Seconds into Milliseconds)
611 if(eParam
== AL_SEC_OFFSET
)
612 Source
->lOffset
= lValue
* 1000;
614 Source
->lOffset
= lValue
;
616 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
618 if(ApplyOffset(Source
) == AL_FALSE
)
619 alSetError(pContext
, AL_INVALID_VALUE
);
623 alSetError(pContext
, AL_INVALID_VALUE
);
626 case AL_DIRECT_FILTER
: {
627 ALfilter
*filter
= NULL
;
630 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
634 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
635 Source
->DirectFilter
.filter
= 0;
638 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
639 Source
->NeedsUpdate
= AL_TRUE
;
642 alSetError(pContext
, AL_INVALID_VALUE
);
645 case AL_DIRECT_FILTER_GAINHF_AUTO
:
646 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
648 Source
->DryGainHFAuto
= lValue
;
649 Source
->NeedsUpdate
= AL_TRUE
;
652 alSetError(pContext
, AL_INVALID_VALUE
);
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
656 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
658 Source
->WetGainAuto
= lValue
;
659 Source
->NeedsUpdate
= AL_TRUE
;
662 alSetError(pContext
, AL_INVALID_VALUE
);
665 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
666 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
668 Source
->WetGainHFAuto
= lValue
;
669 Source
->NeedsUpdate
= AL_TRUE
;
672 alSetError(pContext
, AL_INVALID_VALUE
);
675 case AL_DISTANCE_MODEL
:
676 if(lValue
== AL_NONE
||
677 lValue
== AL_INVERSE_DISTANCE
||
678 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
679 lValue
== AL_LINEAR_DISTANCE
||
680 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
681 lValue
== AL_EXPONENT_DISTANCE
||
682 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
684 Source
->DistanceModel
= lValue
;
685 if(pContext
->SourceDistanceModel
)
686 Source
->NeedsUpdate
= AL_TRUE
;
689 alSetError(pContext
, AL_INVALID_VALUE
);
693 alSetError(pContext
, AL_INVALID_ENUM
);
698 alSetError(pContext
, AL_INVALID_NAME
);
700 ProcessContext(pContext
);
704 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
706 ALCcontext
*pContext
;
709 pContext
= GetContextSuspended();
710 if(!pContext
) return;
712 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
714 ALCdevice
*device
= pContext
->Device
;
721 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
724 case AL_AUXILIARY_SEND_FILTER
: {
725 ALeffectslot
*ALEffectSlot
= NULL
;
726 ALfilter
*ALFilter
= NULL
;
728 if((ALuint
)lValue2
< device
->NumAuxSends
&&
730 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
732 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
734 /* Release refcount on the previous slot, and add one for
736 if(Source
->Send
[lValue2
].Slot
)
737 Source
->Send
[lValue2
].Slot
->refcount
--;
738 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
739 if(Source
->Send
[lValue2
].Slot
)
740 Source
->Send
[lValue2
].Slot
->refcount
++;
745 Source
->Send
[lValue2
].WetFilter
.type
= 0;
746 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
749 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
750 Source
->NeedsUpdate
= AL_TRUE
;
753 alSetError(pContext
, AL_INVALID_VALUE
);
757 alSetError(pContext
, AL_INVALID_ENUM
);
762 alSetError(pContext
, AL_INVALID_NAME
);
764 ProcessContext(pContext
);
768 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
770 ALCcontext
*pContext
;
772 pContext
= GetContextSuspended();
773 if(!pContext
) return;
777 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
781 case AL_SOURCE_RELATIVE
:
782 case AL_CONE_INNER_ANGLE
:
783 case AL_CONE_OUTER_ANGLE
:
786 case AL_SOURCE_STATE
:
788 case AL_SAMPLE_OFFSET
:
790 case AL_MAX_DISTANCE
:
791 case AL_ROLLOFF_FACTOR
:
792 case AL_REFERENCE_DISTANCE
:
793 case AL_DIRECT_FILTER
:
794 case AL_DIRECT_FILTER_GAINHF_AUTO
:
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
796 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
797 case AL_DISTANCE_MODEL
:
798 alSourcei(source
, eParam
, plValues
[0]);
804 case AL_AUXILIARY_SEND_FILTER
:
805 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
809 alSetError(pContext
, AL_INVALID_ENUM
);
814 alSetError(pContext
, AL_INVALID_NAME
);
817 alSetError(pContext
, AL_INVALID_VALUE
);
819 ProcessContext(pContext
);
823 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
825 ALCcontext
*pContext
;
830 pContext
= GetContextSuspended();
831 if(!pContext
) return;
835 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
840 *pflValue
= Source
->flPitch
;
844 *pflValue
= Source
->flGain
;
848 *pflValue
= Source
->flMinGain
;
852 *pflValue
= Source
->flMaxGain
;
855 case AL_MAX_DISTANCE
:
856 *pflValue
= Source
->flMaxDistance
;
859 case AL_ROLLOFF_FACTOR
:
860 *pflValue
= Source
->flRollOffFactor
;
863 case AL_CONE_OUTER_GAIN
:
864 *pflValue
= Source
->flOuterGain
;
867 case AL_CONE_OUTER_GAINHF
:
868 *pflValue
= Source
->OuterGainHF
;
872 case AL_SAMPLE_OFFSET
:
874 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
875 pContext
->Device
->Frequency
;
876 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
877 *pflValue
= Offsets
[0];
880 case AL_CONE_INNER_ANGLE
:
881 *pflValue
= Source
->flInnerAngle
;
884 case AL_CONE_OUTER_ANGLE
:
885 *pflValue
= Source
->flOuterAngle
;
888 case AL_REFERENCE_DISTANCE
:
889 *pflValue
= Source
->flRefDistance
;
892 case AL_AIR_ABSORPTION_FACTOR
:
893 *pflValue
= Source
->AirAbsorptionFactor
;
896 case AL_ROOM_ROLLOFF_FACTOR
:
897 *pflValue
= Source
->RoomRolloffFactor
;
900 case AL_DOPPLER_FACTOR
:
901 *pflValue
= Source
->DopplerFactor
;
905 alSetError(pContext
, AL_INVALID_ENUM
);
910 alSetError(pContext
, AL_INVALID_NAME
);
913 alSetError(pContext
, AL_INVALID_VALUE
);
915 ProcessContext(pContext
);
919 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
921 ALCcontext
*pContext
;
924 pContext
= GetContextSuspended();
925 if(!pContext
) return;
927 if(pflValue1
&& pflValue2
&& pflValue3
)
929 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
934 *pflValue1
= Source
->vPosition
[0];
935 *pflValue2
= Source
->vPosition
[1];
936 *pflValue3
= Source
->vPosition
[2];
940 *pflValue1
= Source
->vVelocity
[0];
941 *pflValue2
= Source
->vVelocity
[1];
942 *pflValue3
= Source
->vVelocity
[2];
946 *pflValue1
= Source
->vOrientation
[0];
947 *pflValue2
= Source
->vOrientation
[1];
948 *pflValue3
= Source
->vOrientation
[2];
952 alSetError(pContext
, AL_INVALID_ENUM
);
957 alSetError(pContext
, AL_INVALID_NAME
);
960 alSetError(pContext
, AL_INVALID_VALUE
);
962 ProcessContext(pContext
);
966 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
968 ALCcontext
*pContext
;
973 pContext
= GetContextSuspended();
974 if(!pContext
) return;
978 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
986 case AL_MAX_DISTANCE
:
987 case AL_ROLLOFF_FACTOR
:
988 case AL_DOPPLER_FACTOR
:
989 case AL_CONE_OUTER_GAIN
:
991 case AL_SAMPLE_OFFSET
:
993 case AL_CONE_INNER_ANGLE
:
994 case AL_CONE_OUTER_ANGLE
:
995 case AL_REFERENCE_DISTANCE
:
996 case AL_CONE_OUTER_GAINHF
:
997 case AL_AIR_ABSORPTION_FACTOR
:
998 case AL_ROOM_ROLLOFF_FACTOR
:
999 alGetSourcef(source
, eParam
, pflValues
);
1002 case AL_SAMPLE_RW_OFFSETS_EXT
:
1003 case AL_BYTE_RW_OFFSETS_EXT
:
1004 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1005 pContext
->Device
->Frequency
;
1006 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1007 pflValues
[0] = Offsets
[0];
1008 pflValues
[1] = Offsets
[1];
1012 pflValues
[0] = Source
->vPosition
[0];
1013 pflValues
[1] = Source
->vPosition
[1];
1014 pflValues
[2] = Source
->vPosition
[2];
1018 pflValues
[0] = Source
->vVelocity
[0];
1019 pflValues
[1] = Source
->vVelocity
[1];
1020 pflValues
[2] = Source
->vVelocity
[2];
1024 pflValues
[0] = Source
->vOrientation
[0];
1025 pflValues
[1] = Source
->vOrientation
[1];
1026 pflValues
[2] = Source
->vOrientation
[2];
1030 alSetError(pContext
, AL_INVALID_ENUM
);
1035 alSetError(pContext
, AL_INVALID_NAME
);
1038 alSetError(pContext
, AL_INVALID_VALUE
);
1040 ProcessContext(pContext
);
1044 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1046 ALCcontext
*pContext
;
1048 ALdouble Offsets
[2];
1051 pContext
= GetContextSuspended();
1052 if(!pContext
) return;
1056 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1060 case AL_MAX_DISTANCE
:
1061 *plValue
= (ALint
)Source
->flMaxDistance
;
1064 case AL_ROLLOFF_FACTOR
:
1065 *plValue
= (ALint
)Source
->flRollOffFactor
;
1068 case AL_REFERENCE_DISTANCE
:
1069 *plValue
= (ALint
)Source
->flRefDistance
;
1072 case AL_SOURCE_RELATIVE
:
1073 *plValue
= Source
->bHeadRelative
;
1076 case AL_CONE_INNER_ANGLE
:
1077 *plValue
= (ALint
)Source
->flInnerAngle
;
1080 case AL_CONE_OUTER_ANGLE
:
1081 *plValue
= (ALint
)Source
->flOuterAngle
;
1085 *plValue
= Source
->bLooping
;
1089 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1092 case AL_SOURCE_STATE
:
1093 *plValue
= Source
->state
;
1096 case AL_BUFFERS_QUEUED
:
1097 *plValue
= Source
->BuffersInQueue
;
1100 case AL_BUFFERS_PROCESSED
:
1101 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1103 /* Buffers on a looping source are in a perpetual state
1104 * of PENDING, so don't report any as PROCESSED */
1108 *plValue
= Source
->BuffersPlayed
;
1111 case AL_SOURCE_TYPE
:
1112 *plValue
= Source
->lSourceType
;
1116 case AL_SAMPLE_OFFSET
:
1117 case AL_BYTE_OFFSET
:
1118 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1119 pContext
->Device
->Frequency
;
1120 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1121 *plValue
= (ALint
)Offsets
[0];
1124 case AL_DIRECT_FILTER
:
1125 *plValue
= Source
->DirectFilter
.filter
;
1128 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1129 *plValue
= Source
->DryGainHFAuto
;
1132 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1133 *plValue
= Source
->WetGainAuto
;
1136 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1137 *plValue
= Source
->WetGainHFAuto
;
1140 case AL_DOPPLER_FACTOR
:
1141 *plValue
= (ALint
)Source
->DopplerFactor
;
1144 case AL_DISTANCE_MODEL
:
1145 *plValue
= Source
->DistanceModel
;
1149 alSetError(pContext
, AL_INVALID_ENUM
);
1154 alSetError(pContext
, AL_INVALID_NAME
);
1157 alSetError(pContext
, AL_INVALID_VALUE
);
1159 ProcessContext(pContext
);
1163 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1165 ALCcontext
*pContext
;
1168 pContext
= GetContextSuspended();
1169 if(!pContext
) return;
1171 if(plValue1
&& plValue2
&& plValue3
)
1173 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1178 *plValue1
= (ALint
)Source
->vPosition
[0];
1179 *plValue2
= (ALint
)Source
->vPosition
[1];
1180 *plValue3
= (ALint
)Source
->vPosition
[2];
1184 *plValue1
= (ALint
)Source
->vVelocity
[0];
1185 *plValue2
= (ALint
)Source
->vVelocity
[1];
1186 *plValue3
= (ALint
)Source
->vVelocity
[2];
1190 *plValue1
= (ALint
)Source
->vOrientation
[0];
1191 *plValue2
= (ALint
)Source
->vOrientation
[1];
1192 *plValue3
= (ALint
)Source
->vOrientation
[2];
1196 alSetError(pContext
, AL_INVALID_ENUM
);
1201 alSetError(pContext
, AL_INVALID_NAME
);
1204 alSetError(pContext
, AL_INVALID_VALUE
);
1206 ProcessContext(pContext
);
1210 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1212 ALCcontext
*pContext
;
1214 ALdouble Offsets
[2];
1217 pContext
= GetContextSuspended();
1218 if(!pContext
) return;
1222 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1226 case AL_SOURCE_RELATIVE
:
1227 case AL_CONE_INNER_ANGLE
:
1228 case AL_CONE_OUTER_ANGLE
:
1231 case AL_SOURCE_STATE
:
1232 case AL_BUFFERS_QUEUED
:
1233 case AL_BUFFERS_PROCESSED
:
1235 case AL_SAMPLE_OFFSET
:
1236 case AL_BYTE_OFFSET
:
1237 case AL_MAX_DISTANCE
:
1238 case AL_ROLLOFF_FACTOR
:
1239 case AL_DOPPLER_FACTOR
:
1240 case AL_REFERENCE_DISTANCE
:
1241 case AL_SOURCE_TYPE
:
1242 case AL_DIRECT_FILTER
:
1243 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1244 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1245 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1246 case AL_DISTANCE_MODEL
:
1247 alGetSourcei(source
, eParam
, plValues
);
1250 case AL_SAMPLE_RW_OFFSETS_EXT
:
1251 case AL_BYTE_RW_OFFSETS_EXT
:
1252 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1253 pContext
->Device
->Frequency
;
1254 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1255 plValues
[0] = (ALint
)Offsets
[0];
1256 plValues
[1] = (ALint
)Offsets
[1];
1260 plValues
[0] = (ALint
)Source
->vPosition
[0];
1261 plValues
[1] = (ALint
)Source
->vPosition
[1];
1262 plValues
[2] = (ALint
)Source
->vPosition
[2];
1266 plValues
[0] = (ALint
)Source
->vVelocity
[0];
1267 plValues
[1] = (ALint
)Source
->vVelocity
[1];
1268 plValues
[2] = (ALint
)Source
->vVelocity
[2];
1272 plValues
[0] = (ALint
)Source
->vOrientation
[0];
1273 plValues
[1] = (ALint
)Source
->vOrientation
[1];
1274 plValues
[2] = (ALint
)Source
->vOrientation
[2];
1278 alSetError(pContext
, AL_INVALID_ENUM
);
1283 alSetError(pContext
, AL_INVALID_NAME
);
1286 alSetError(pContext
, AL_INVALID_VALUE
);
1288 ProcessContext(pContext
);
1292 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1294 alSourcePlayv(1, &source
);
1297 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1299 ALCcontext
*Context
;
1301 ALbufferlistitem
*BufferList
;
1304 Context
= GetContextSuspended();
1305 if(!Context
) return;
1309 alSetError(Context
, AL_INVALID_VALUE
);
1313 // Check that all the Sources are valid
1314 for(i
= 0;i
< n
;i
++)
1316 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1318 alSetError(Context
, AL_INVALID_NAME
);
1323 if(Context
->ActiveSourceCount
+n
< n
)
1325 alSetError(Context
, AL_OUT_OF_MEMORY
);
1329 while(Context
->MaxActiveSources
< Context
->ActiveSourceCount
+n
)
1334 newcount
= Context
->MaxActiveSources
<< 1;
1336 temp
= realloc(Context
->ActiveSources
,
1337 sizeof(*Context
->ActiveSources
) * newcount
);
1340 alSetError(Context
, AL_OUT_OF_MEMORY
);
1344 Context
->ActiveSources
= temp
;
1345 Context
->MaxActiveSources
= newcount
;
1348 for(i
= 0;i
< n
;i
++)
1350 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1352 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1353 BufferList
= Source
->queue
;
1356 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1358 BufferList
= BufferList
->next
;
1363 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1367 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1368 Source
->DryGains
[j
] = 0.0f
;
1369 for(j
= 0;j
< MAX_SENDS
;j
++)
1370 Source
->WetGains
[j
] = 0.0f
;
1372 if(Source
->state
!= AL_PAUSED
)
1374 Source
->state
= AL_PLAYING
;
1375 Source
->position
= 0;
1376 Source
->position_fraction
= 0;
1377 Source
->BuffersPlayed
= 0;
1379 Source
->Buffer
= Source
->queue
->buffer
;
1382 Source
->state
= AL_PLAYING
;
1384 // Check if an Offset has been set
1386 ApplyOffset(Source
);
1388 if(Source
->BuffersPlayed
== 0 && Source
->position
== 0 &&
1389 Source
->position_fraction
== 0)
1390 Source
->FirstStart
= AL_TRUE
;
1392 Source
->FirstStart
= AL_FALSE
;
1394 // If device is disconnected, go right to stopped
1395 if(!Context
->Device
->Connected
)
1397 Source
->state
= AL_STOPPED
;
1398 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1399 Source
->position
= 0;
1400 Source
->position_fraction
= 0;
1404 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1406 if(Context
->ActiveSources
[j
] == Source
)
1409 if(j
== Context
->ActiveSourceCount
)
1410 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1415 ProcessContext(Context
);
1418 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1420 alSourcePausev(1, &source
);
1423 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1425 ALCcontext
*Context
;
1429 Context
= GetContextSuspended();
1430 if(!Context
) return;
1434 alSetError(Context
, AL_INVALID_VALUE
);
1438 // Check all the Sources are valid
1439 for(i
= 0;i
< n
;i
++)
1441 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1443 alSetError(Context
, AL_INVALID_NAME
);
1448 for(i
= 0;i
< n
;i
++)
1450 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1451 if(Source
->state
== AL_PLAYING
)
1452 Source
->state
= AL_PAUSED
;
1456 ProcessContext(Context
);
1459 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1461 alSourceStopv(1, &source
);
1464 AL_API ALvoid AL_APIENTRY
alSourceStopv(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_STOPPED
;
1495 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1497 Source
->lOffset
= 0;
1501 ProcessContext(Context
);
1504 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1506 alSourceRewindv(1, &source
);
1509 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1511 ALCcontext
*Context
;
1515 Context
= GetContextSuspended();
1516 if(!Context
) return;
1520 alSetError(Context
, AL_INVALID_VALUE
);
1524 // Check all the Sources are valid
1525 for(i
= 0;i
< n
;i
++)
1527 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1529 alSetError(Context
, AL_INVALID_NAME
);
1534 for(i
= 0;i
< n
;i
++)
1536 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1537 if(Source
->state
!= AL_INITIAL
)
1539 Source
->state
= AL_INITIAL
;
1540 Source
->position
= 0;
1541 Source
->position_fraction
= 0;
1542 Source
->BuffersPlayed
= 0;
1544 Source
->Buffer
= Source
->queue
->buffer
;
1546 Source
->lOffset
= 0;
1550 ProcessContext(Context
);
1554 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1556 ALCcontext
*Context
;
1561 ALbufferlistitem
*BufferListStart
;
1562 ALbufferlistitem
*BufferList
;
1563 ALboolean HadFormat
;
1570 Context
= GetContextSuspended();
1571 if(!Context
) return;
1573 // Check that all buffers are valid or zero and that the source is valid
1575 // Check that this is a valid source
1576 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1578 alSetError(Context
, AL_INVALID_NAME
);
1582 // Check that this is not a STATIC Source
1583 if(Source
->lSourceType
== AL_STATIC
)
1585 // Invalid Source Type (can't queue on a Static Source)
1586 alSetError(Context
, AL_INVALID_OPERATION
);
1590 device
= Context
->Device
;
1594 HadFormat
= AL_FALSE
;
1596 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1597 BufferList
= Source
->queue
;
1600 if(BufferList
->buffer
)
1602 Frequency
= BufferList
->buffer
->frequency
;
1603 Format
= BufferList
->buffer
->eOriginalFormat
;
1604 HadFormat
= AL_TRUE
;
1607 BufferList
= BufferList
->next
;
1610 for(i
= 0;i
< n
;i
++)
1615 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1617 alSetError(Context
, AL_INVALID_NAME
);
1621 if(Frequency
== -1 && Format
== -1)
1623 Frequency
= buffer
->frequency
;
1624 Format
= buffer
->eOriginalFormat
;
1626 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1628 alSetError(Context
, AL_INVALID_OPERATION
);
1633 // Change Source Type
1634 Source
->lSourceType
= AL_STREAMING
;
1636 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1638 // All buffers are valid - so add them to the list
1639 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1640 BufferListStart
->buffer
= buffer
;
1641 BufferListStart
->next
= NULL
;
1643 // Increment reference counter for buffer
1644 if(buffer
) buffer
->refcount
++;
1646 BufferList
= BufferListStart
;
1648 for(i
= 1;i
< n
;i
++)
1650 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1652 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1653 BufferList
->next
->buffer
= buffer
;
1654 BufferList
->next
->next
= NULL
;
1656 // Increment reference counter for buffer
1657 if(buffer
) buffer
->refcount
++;
1659 BufferList
= BufferList
->next
;
1662 if(Source
->queue
== NULL
)
1664 Source
->queue
= BufferListStart
;
1665 // Update Current Buffer
1666 Source
->Buffer
= BufferListStart
->buffer
;
1670 // Find end of queue
1671 BufferList
= Source
->queue
;
1672 while(BufferList
->next
!= NULL
)
1673 BufferList
= BufferList
->next
;
1675 BufferList
->next
= BufferListStart
;
1678 // Update number of buffers in queue
1679 Source
->BuffersInQueue
+= n
;
1680 // If no previous format, mark the source dirty now that it may have one
1682 Source
->NeedsUpdate
= AL_TRUE
;
1685 ProcessContext(Context
);
1689 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1690 // an array of buffer IDs that are to be filled with the names of the buffers removed
1691 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1693 ALCcontext
*Context
;
1696 ALbufferlistitem
*BufferList
;
1701 Context
= GetContextSuspended();
1702 if(!Context
) return;
1704 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1706 alSetError(Context
, AL_INVALID_NAME
);
1710 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1711 (ALuint
)n
> Source
->BuffersPlayed
)
1713 // Some buffers can't be unqueue because they have not been processed
1714 alSetError(Context
, AL_INVALID_VALUE
);
1718 for(i
= 0;i
< n
;i
++)
1720 BufferList
= Source
->queue
;
1721 Source
->queue
= BufferList
->next
;
1723 if(BufferList
->buffer
)
1725 // Record name of buffer
1726 buffers
[i
] = BufferList
->buffer
->buffer
;
1727 // Decrement buffer reference counter
1728 BufferList
->buffer
->refcount
--;
1733 // Release memory for buffer list item
1735 Source
->BuffersInQueue
--;
1738 if(Source
->state
!= AL_PLAYING
)
1741 Source
->Buffer
= Source
->queue
->buffer
;
1743 Source
->Buffer
= NULL
;
1745 Source
->BuffersPlayed
-= n
;
1748 ProcessContext(Context
);
1752 static ALvoid
InitSourceParams(ALsource
*Source
)
1754 Source
->flInnerAngle
= 360.0f
;
1755 Source
->flOuterAngle
= 360.0f
;
1756 Source
->flPitch
= 1.0f
;
1757 Source
->vPosition
[0] = 0.0f
;
1758 Source
->vPosition
[1] = 0.0f
;
1759 Source
->vPosition
[2] = 0.0f
;
1760 Source
->vOrientation
[0] = 0.0f
;
1761 Source
->vOrientation
[1] = 0.0f
;
1762 Source
->vOrientation
[2] = 0.0f
;
1763 Source
->vVelocity
[0] = 0.0f
;
1764 Source
->vVelocity
[1] = 0.0f
;
1765 Source
->vVelocity
[2] = 0.0f
;
1766 Source
->flRefDistance
= 1.0f
;
1767 Source
->flMaxDistance
= FLT_MAX
;
1768 Source
->flRollOffFactor
= 1.0f
;
1769 Source
->bLooping
= AL_FALSE
;
1770 Source
->flGain
= 1.0f
;
1771 Source
->flMinGain
= 0.0f
;
1772 Source
->flMaxGain
= 1.0f
;
1773 Source
->flOuterGain
= 0.0f
;
1774 Source
->OuterGainHF
= 1.0f
;
1776 Source
->DryGainHFAuto
= AL_TRUE
;
1777 Source
->WetGainAuto
= AL_TRUE
;
1778 Source
->WetGainHFAuto
= AL_TRUE
;
1779 Source
->AirAbsorptionFactor
= 0.0f
;
1780 Source
->RoomRolloffFactor
= 0.0f
;
1781 Source
->DopplerFactor
= 1.0f
;
1783 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1785 Source
->Resampler
= DefaultResampler
;
1787 Source
->state
= AL_INITIAL
;
1788 Source
->lSourceType
= AL_UNDETERMINED
;
1790 Source
->NeedsUpdate
= AL_TRUE
;
1792 Source
->Buffer
= NULL
;
1799 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1800 The offset is relative to the start of the queue (not the start of the current buffer)
1802 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1804 ALbufferlistitem
*BufferList
;
1805 ALbuffer
*Buffer
= NULL
;
1807 ALint Channels
, Bytes
;
1808 ALuint readPos
, writePos
;
1809 ALenum OriginalFormat
;
1810 ALuint TotalBufferDataSize
;
1813 // Find the first non-NULL Buffer in the Queue
1814 BufferList
= Source
->queue
;
1817 if(BufferList
->buffer
)
1819 Buffer
= BufferList
->buffer
;
1822 BufferList
= BufferList
->next
;
1825 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1832 // Get Current Buffer Size and frequency (in milliseconds)
1833 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1834 OriginalFormat
= Buffer
->eOriginalFormat
;
1835 Channels
= aluChannelsFromFormat(Buffer
->format
);
1836 Bytes
= aluBytesFromFormat(Buffer
->format
);
1838 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1839 readPos
= Source
->position
* Channels
* Bytes
;
1840 // Add byte length of any processed buffers in the queue
1841 TotalBufferDataSize
= 0;
1842 BufferList
= Source
->queue
;
1843 for(i
= 0;BufferList
;i
++)
1845 if(BufferList
->buffer
)
1847 if(i
< Source
->BuffersPlayed
)
1848 readPos
+= BufferList
->buffer
->size
;
1849 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1851 BufferList
= BufferList
->next
;
1853 if(Source
->state
== AL_PLAYING
)
1854 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1858 if(Source
->bLooping
)
1860 readPos
%= TotalBufferDataSize
;
1861 writePos
%= TotalBufferDataSize
;
1865 // Clamp positions to TotalBufferDataSize
1866 if(readPos
> TotalBufferDataSize
)
1867 readPos
= TotalBufferDataSize
;
1868 if(writePos
> TotalBufferDataSize
)
1869 writePos
= TotalBufferDataSize
;
1875 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1876 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1878 case AL_SAMPLE_OFFSET
:
1879 case AL_SAMPLE_RW_OFFSETS_EXT
:
1880 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1881 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1883 case AL_BYTE_OFFSET
:
1884 case AL_BYTE_RW_OFFSETS_EXT
:
1885 // Take into account the original format of the Buffer
1886 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1887 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1889 // Round down to nearest ADPCM block
1890 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1891 if(Source
->state
== AL_PLAYING
)
1893 // Round up to nearest ADPCM block
1894 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1897 offset
[1] = offset
[0];
1899 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1900 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1901 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1902 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1903 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1904 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1906 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1907 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1909 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1911 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1912 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1914 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1916 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1917 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1919 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1921 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1922 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1924 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1926 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1927 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1931 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1932 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1933 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1943 Apply a playback offset to the Source. This function will update the queue (to correctly
1944 mark buffers as 'pending' or 'processed' depending upon the new offset.
1946 static ALboolean
ApplyOffset(ALsource
*Source
)
1948 ALbufferlistitem
*BufferList
;
1950 ALint lBufferSize
, lTotalBufferSize
;
1951 ALint BuffersPlayed
;
1954 // Get true byte offset
1955 lByteOffset
= GetByteOffset(Source
);
1957 // If the offset is invalid, don't apply it
1958 if(lByteOffset
== -1)
1961 // Sort out the queue (pending and processed states)
1962 BufferList
= Source
->queue
;
1963 lTotalBufferSize
= 0;
1968 Buffer
= BufferList
->buffer
;
1969 lBufferSize
= Buffer
? Buffer
->size
: 0;
1971 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1973 // Offset is past this buffer so increment BuffersPlayed
1976 else if(lTotalBufferSize
<= lByteOffset
)
1978 // Offset is within this buffer
1979 // Set Current Buffer
1980 Source
->Buffer
= BufferList
->buffer
;
1981 Source
->BuffersPlayed
= BuffersPlayed
;
1983 // SW Mixer Positions are in Samples
1984 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1985 aluFrameSizeFromFormat(Buffer
->format
);
1989 // Increment the TotalBufferSize
1990 lTotalBufferSize
+= lBufferSize
;
1992 // Move on to next buffer in the Queue
1993 BufferList
= BufferList
->next
;
1995 // Offset is out of range of the buffer queue
2003 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2004 offset supplied by the application). This takes into account the fact that the buffer format
2005 may have been modifed by AL (e.g 8bit samples are converted to float)
2007 static ALint
GetByteOffset(ALsource
*Source
)
2009 ALbuffer
*Buffer
= NULL
;
2010 ALbufferlistitem
*BufferList
;
2012 ALint Channels
, Bytes
;
2013 ALint ByteOffset
= -1;
2015 // Find the first non-NULL Buffer in the Queue
2016 BufferList
= Source
->queue
;
2019 if(BufferList
->buffer
)
2021 Buffer
= BufferList
->buffer
;
2024 BufferList
= BufferList
->next
;
2029 Source
->lOffset
= 0;
2033 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
2034 Channels
= aluChannelsFromFormat(Buffer
->format
);
2035 Bytes
= aluBytesFromFormat(Buffer
->format
);
2037 // Determine the ByteOffset (and ensure it is block aligned)
2038 switch(Source
->lOffsetType
)
2040 case AL_BYTE_OFFSET
:
2041 // Take into consideration the original format
2042 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2044 ByteOffset
*= Channels
* Bytes
;
2047 case AL_SAMPLE_OFFSET
:
2048 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2052 // Note - lOffset is internally stored as Milliseconds
2053 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2054 ByteOffset
*= Channels
* Bytes
;
2058 Source
->lOffset
= 0;
2063 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2065 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2067 // Round down to nearest ADPCM block
2068 offset
/= 36 * channels
;
2069 // Multiply by compression rate (65 sample frames per block)
2072 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2073 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2074 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2076 /* muLaw has 1 byte per sample */
2077 offset
/= 1 * channels
;
2079 else if(format
== AL_FORMAT_REAR_MULAW
)
2081 /* Rear is 2 channels */
2084 else if(format
== AL_FORMAT_REAR8
)
2086 else if(format
== AL_FORMAT_REAR16
)
2088 else if(format
== AL_FORMAT_REAR32
)
2092 ALuint bytes
= aluBytesFromFormat(format
);
2093 offset
/= bytes
* channels
;
2099 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2103 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2105 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2106 Context
->SourceMap
.array
[pos
].value
= NULL
;
2108 // For each buffer in the source's queue, decrement its reference counter and remove it
2109 while(temp
->queue
!= NULL
)
2111 ALbufferlistitem
*BufferList
= temp
->queue
;
2112 // Decrement buffer's reference counter
2113 if(BufferList
->buffer
!= NULL
)
2114 BufferList
->buffer
->refcount
--;
2115 // Update queue to point to next element in list
2116 temp
->queue
= BufferList
->next
;
2117 // Release memory allocated for buffer list item
2121 for(j
= 0;j
< MAX_SENDS
;++j
)
2123 if(temp
->Send
[j
].Slot
)
2124 temp
->Send
[j
].Slot
->refcount
--;
2127 // Release source structure
2128 ALTHUNK_REMOVEENTRY(temp
->source
);
2129 memset(temp
, 0, sizeof(ALsource
));