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"
36 resampler_t DefaultResampler
;
37 const ALsizei ResamplerPadding
[RESAMPLER_MAX
] = {
42 const ALsizei ResamplerPrePadding
[RESAMPLER_MAX
] = {
49 static ALvoid
InitSourceParams(ALsource
*Source
);
50 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum eName
, ALdouble
*Offsets
, ALdouble updateLen
);
51 static ALboolean
ApplyOffset(ALsource
*Source
);
52 static ALint
GetByteOffset(ALsource
*Source
);
54 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
55 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
56 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
57 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
59 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
64 Context
= GetContextSuspended();
67 Device
= Context
->Device
;
68 if(n
< 0 || IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
69 alSetError(Context
, AL_INVALID_VALUE
);
70 else if((ALuint
)n
> Device
->MaxNoOfSources
- Context
->SourceMap
.size
)
71 alSetError(Context
, AL_INVALID_VALUE
);
77 // Add additional sources to the list
81 ALsource
*source
= calloc(1, sizeof(ALsource
));
84 alSetError(Context
, AL_OUT_OF_MEMORY
);
85 alDeleteSources(i
, sources
);
89 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
90 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
92 if(err
!= AL_NO_ERROR
)
94 ALTHUNK_REMOVEENTRY(source
->source
);
95 memset(source
, 0, sizeof(ALsource
));
98 alSetError(Context
, err
);
99 alDeleteSources(i
, sources
);
103 sources
[i
++] = source
->source
;
104 InitSourceParams(source
);
108 ProcessContext(Context
);
112 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
117 ALbufferlistitem
*BufferList
;
118 ALboolean SourcesValid
= AL_FALSE
;
120 Context
= GetContextSuspended();
124 alSetError(Context
, AL_INVALID_VALUE
);
127 SourcesValid
= AL_TRUE
;
128 // Check that all Sources are valid (and can therefore be deleted)
131 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
133 alSetError(Context
, AL_INVALID_NAME
);
134 SourcesValid
= AL_FALSE
;
142 // All Sources are valid, and can be deleted
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) == NULL
)
149 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
151 if(Context
->ActiveSources
[j
] == Source
)
153 ALsizei end
= --(Context
->ActiveSourceCount
);
154 Context
->ActiveSources
[j
] = Context
->ActiveSources
[end
];
159 // For each buffer in the source's queue...
160 while(Source
->queue
!= NULL
)
162 BufferList
= Source
->queue
;
163 Source
->queue
= BufferList
->next
;
165 if(BufferList
->buffer
!= NULL
)
166 BufferList
->buffer
->refcount
--;
170 for(j
= 0;j
< MAX_SENDS
;++j
)
172 if(Source
->Send
[j
].Slot
)
173 Source
->Send
[j
].Slot
->refcount
--;
174 Source
->Send
[j
].Slot
= NULL
;
177 // Remove Source from list of Sources
178 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
179 ALTHUNK_REMOVEENTRY(Source
->source
);
181 memset(Source
,0,sizeof(ALsource
));
186 ProcessContext(Context
);
190 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
195 Context
= GetContextSuspended();
196 if(!Context
) return AL_FALSE
;
198 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
200 ProcessContext(Context
);
206 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
208 ALCcontext
*pContext
;
211 pContext
= GetContextSuspended();
212 if(!pContext
) return;
214 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
221 Source
->flPitch
= flValue
;
222 Source
->NeedsUpdate
= AL_TRUE
;
225 alSetError(pContext
, AL_INVALID_VALUE
);
228 case AL_CONE_INNER_ANGLE
:
229 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
231 Source
->flInnerAngle
= flValue
;
232 Source
->NeedsUpdate
= AL_TRUE
;
235 alSetError(pContext
, AL_INVALID_VALUE
);
238 case AL_CONE_OUTER_ANGLE
:
239 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
241 Source
->flOuterAngle
= flValue
;
242 Source
->NeedsUpdate
= AL_TRUE
;
245 alSetError(pContext
, AL_INVALID_VALUE
);
251 Source
->flGain
= flValue
;
252 Source
->NeedsUpdate
= AL_TRUE
;
255 alSetError(pContext
, AL_INVALID_VALUE
);
258 case AL_MAX_DISTANCE
:
261 Source
->flMaxDistance
= flValue
;
262 Source
->NeedsUpdate
= AL_TRUE
;
265 alSetError(pContext
, AL_INVALID_VALUE
);
268 case AL_ROLLOFF_FACTOR
:
271 Source
->flRollOffFactor
= flValue
;
272 Source
->NeedsUpdate
= AL_TRUE
;
275 alSetError(pContext
, AL_INVALID_VALUE
);
278 case AL_REFERENCE_DISTANCE
:
281 Source
->flRefDistance
= flValue
;
282 Source
->NeedsUpdate
= AL_TRUE
;
285 alSetError(pContext
, AL_INVALID_VALUE
);
289 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
291 Source
->flMinGain
= flValue
;
292 Source
->NeedsUpdate
= AL_TRUE
;
295 alSetError(pContext
, AL_INVALID_VALUE
);
299 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
301 Source
->flMaxGain
= flValue
;
302 Source
->NeedsUpdate
= AL_TRUE
;
305 alSetError(pContext
, AL_INVALID_VALUE
);
308 case AL_CONE_OUTER_GAIN
:
309 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
311 Source
->flOuterGain
= flValue
;
312 Source
->NeedsUpdate
= AL_TRUE
;
315 alSetError(pContext
, AL_INVALID_VALUE
);
318 case AL_CONE_OUTER_GAINHF
:
319 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
321 Source
->OuterGainHF
= flValue
;
322 Source
->NeedsUpdate
= AL_TRUE
;
325 alSetError(pContext
, AL_INVALID_VALUE
);
328 case AL_AIR_ABSORPTION_FACTOR
:
329 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
331 Source
->AirAbsorptionFactor
= flValue
;
332 Source
->NeedsUpdate
= AL_TRUE
;
335 alSetError(pContext
, AL_INVALID_VALUE
);
338 case AL_ROOM_ROLLOFF_FACTOR
:
339 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
341 Source
->RoomRolloffFactor
= flValue
;
342 Source
->NeedsUpdate
= AL_TRUE
;
345 alSetError(pContext
, AL_INVALID_VALUE
);
348 case AL_DOPPLER_FACTOR
:
349 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
351 Source
->DopplerFactor
= flValue
;
352 Source
->NeedsUpdate
= AL_TRUE
;
355 alSetError(pContext
, AL_INVALID_VALUE
);
359 case AL_SAMPLE_OFFSET
:
363 Source
->lOffsetType
= eParam
;
365 // Store Offset (convert Seconds into Milliseconds)
366 if(eParam
== AL_SEC_OFFSET
)
367 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
369 Source
->lOffset
= (ALint
)flValue
;
371 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
373 if(ApplyOffset(Source
) == AL_FALSE
)
374 alSetError(pContext
, AL_INVALID_VALUE
);
378 alSetError(pContext
, AL_INVALID_VALUE
);
382 alSetError(pContext
, AL_INVALID_ENUM
);
388 // Invalid Source Name
389 alSetError(pContext
, AL_INVALID_NAME
);
392 ProcessContext(pContext
);
396 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
398 ALCcontext
*pContext
;
401 pContext
= GetContextSuspended();
402 if(!pContext
) return;
404 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
409 Source
->vPosition
[0] = flValue1
;
410 Source
->vPosition
[1] = flValue2
;
411 Source
->vPosition
[2] = flValue3
;
412 Source
->NeedsUpdate
= AL_TRUE
;
416 Source
->vVelocity
[0] = flValue1
;
417 Source
->vVelocity
[1] = flValue2
;
418 Source
->vVelocity
[2] = flValue3
;
419 Source
->NeedsUpdate
= AL_TRUE
;
423 Source
->vOrientation
[0] = flValue1
;
424 Source
->vOrientation
[1] = flValue2
;
425 Source
->vOrientation
[2] = flValue3
;
426 Source
->NeedsUpdate
= AL_TRUE
;
430 alSetError(pContext
, AL_INVALID_ENUM
);
435 alSetError(pContext
, AL_INVALID_NAME
);
437 ProcessContext(pContext
);
441 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
443 ALCcontext
*pContext
;
445 pContext
= GetContextSuspended();
446 if(!pContext
) return;
450 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
455 case AL_CONE_INNER_ANGLE
:
456 case AL_CONE_OUTER_ANGLE
:
458 case AL_MAX_DISTANCE
:
459 case AL_ROLLOFF_FACTOR
:
460 case AL_REFERENCE_DISTANCE
:
463 case AL_CONE_OUTER_GAIN
:
464 case AL_CONE_OUTER_GAINHF
:
466 case AL_SAMPLE_OFFSET
:
468 case AL_AIR_ABSORPTION_FACTOR
:
469 case AL_ROOM_ROLLOFF_FACTOR
:
470 alSourcef(source
, eParam
, pflValues
[0]);
476 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
480 alSetError(pContext
, AL_INVALID_ENUM
);
485 alSetError(pContext
, AL_INVALID_NAME
);
488 alSetError(pContext
, AL_INVALID_VALUE
);
490 ProcessContext(pContext
);
494 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
496 ALCcontext
*pContext
;
498 ALbufferlistitem
*BufferListItem
;
500 pContext
= GetContextSuspended();
501 if(!pContext
) return;
503 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
505 ALCdevice
*device
= pContext
->Device
;
509 case AL_MAX_DISTANCE
:
510 case AL_ROLLOFF_FACTOR
:
511 case AL_CONE_INNER_ANGLE
:
512 case AL_CONE_OUTER_ANGLE
:
513 case AL_REFERENCE_DISTANCE
:
514 alSourcef(source
, eParam
, (ALfloat
)lValue
);
517 case AL_SOURCE_RELATIVE
:
518 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
520 Source
->bHeadRelative
= (ALboolean
)lValue
;
521 Source
->NeedsUpdate
= AL_TRUE
;
524 alSetError(pContext
, AL_INVALID_VALUE
);
528 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
529 Source
->bLooping
= (ALboolean
)lValue
;
531 alSetError(pContext
, AL_INVALID_VALUE
);
535 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
537 ALbuffer
*buffer
= NULL
;
540 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
542 // Remove all elements in the queue
543 while(Source
->queue
!= NULL
)
545 BufferListItem
= Source
->queue
;
546 Source
->queue
= BufferListItem
->next
;
548 if(BufferListItem
->buffer
)
549 BufferListItem
->buffer
->refcount
--;
550 free(BufferListItem
);
552 Source
->BuffersInQueue
= 0;
554 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
557 // Source is now in STATIC mode
558 Source
->lSourceType
= AL_STATIC
;
560 // Add the selected buffer to the queue
561 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
562 BufferListItem
->buffer
= buffer
;
563 BufferListItem
->next
= NULL
;
564 BufferListItem
->prev
= NULL
;
566 Source
->queue
= BufferListItem
;
567 Source
->BuffersInQueue
= 1;
569 if(buffer
->FmtChannels
== FmtMono
)
570 Source
->Update
= CalcSourceParams
;
572 Source
->Update
= CalcNonAttnSourceParams
;
574 // Increment reference counter for buffer
579 // Source is now in UNDETERMINED mode
580 Source
->lSourceType
= AL_UNDETERMINED
;
582 Source
->BuffersPlayed
= 0;
584 // Update AL_BUFFER parameter
585 Source
->Buffer
= buffer
;
586 Source
->NeedsUpdate
= AL_TRUE
;
589 alSetError(pContext
, AL_INVALID_VALUE
);
592 alSetError(pContext
, AL_INVALID_OPERATION
);
595 case AL_SOURCE_STATE
:
597 alSetError(pContext
, AL_INVALID_OPERATION
);
601 case AL_SAMPLE_OFFSET
:
605 Source
->lOffsetType
= eParam
;
607 // Store Offset (convert Seconds into Milliseconds)
608 if(eParam
== AL_SEC_OFFSET
)
609 Source
->lOffset
= lValue
* 1000;
611 Source
->lOffset
= lValue
;
613 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
615 if(ApplyOffset(Source
) == AL_FALSE
)
616 alSetError(pContext
, AL_INVALID_VALUE
);
620 alSetError(pContext
, AL_INVALID_VALUE
);
623 case AL_DIRECT_FILTER
: {
624 ALfilter
*filter
= NULL
;
627 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
631 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
632 Source
->DirectFilter
.filter
= 0;
635 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
636 Source
->NeedsUpdate
= AL_TRUE
;
639 alSetError(pContext
, AL_INVALID_VALUE
);
642 case AL_DIRECT_FILTER_GAINHF_AUTO
:
643 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
645 Source
->DryGainHFAuto
= lValue
;
646 Source
->NeedsUpdate
= AL_TRUE
;
649 alSetError(pContext
, AL_INVALID_VALUE
);
652 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
653 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
655 Source
->WetGainAuto
= lValue
;
656 Source
->NeedsUpdate
= AL_TRUE
;
659 alSetError(pContext
, AL_INVALID_VALUE
);
662 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
663 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
665 Source
->WetGainHFAuto
= lValue
;
666 Source
->NeedsUpdate
= AL_TRUE
;
669 alSetError(pContext
, AL_INVALID_VALUE
);
672 case AL_DISTANCE_MODEL
:
673 if(lValue
== AL_NONE
||
674 lValue
== AL_INVERSE_DISTANCE
||
675 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
676 lValue
== AL_LINEAR_DISTANCE
||
677 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
678 lValue
== AL_EXPONENT_DISTANCE
||
679 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
681 Source
->DistanceModel
= lValue
;
682 if(pContext
->SourceDistanceModel
)
683 Source
->NeedsUpdate
= AL_TRUE
;
686 alSetError(pContext
, AL_INVALID_VALUE
);
690 alSetError(pContext
, AL_INVALID_ENUM
);
695 alSetError(pContext
, AL_INVALID_NAME
);
697 ProcessContext(pContext
);
701 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
703 ALCcontext
*pContext
;
706 pContext
= GetContextSuspended();
707 if(!pContext
) return;
709 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
711 ALCdevice
*device
= pContext
->Device
;
718 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
721 case AL_AUXILIARY_SEND_FILTER
: {
722 ALeffectslot
*ALEffectSlot
= NULL
;
723 ALfilter
*ALFilter
= NULL
;
725 if((ALuint
)lValue2
< device
->NumAuxSends
&&
727 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
729 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
731 /* Release refcount on the previous slot, and add one for
733 if(Source
->Send
[lValue2
].Slot
)
734 Source
->Send
[lValue2
].Slot
->refcount
--;
735 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
736 if(Source
->Send
[lValue2
].Slot
)
737 Source
->Send
[lValue2
].Slot
->refcount
++;
742 Source
->Send
[lValue2
].WetFilter
.type
= 0;
743 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
746 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
747 Source
->NeedsUpdate
= AL_TRUE
;
750 alSetError(pContext
, AL_INVALID_VALUE
);
754 alSetError(pContext
, AL_INVALID_ENUM
);
759 alSetError(pContext
, AL_INVALID_NAME
);
761 ProcessContext(pContext
);
765 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
767 ALCcontext
*pContext
;
769 pContext
= GetContextSuspended();
770 if(!pContext
) return;
774 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
778 case AL_SOURCE_RELATIVE
:
779 case AL_CONE_INNER_ANGLE
:
780 case AL_CONE_OUTER_ANGLE
:
783 case AL_SOURCE_STATE
:
785 case AL_SAMPLE_OFFSET
:
787 case AL_MAX_DISTANCE
:
788 case AL_ROLLOFF_FACTOR
:
789 case AL_REFERENCE_DISTANCE
:
790 case AL_DIRECT_FILTER
:
791 case AL_DIRECT_FILTER_GAINHF_AUTO
:
792 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
793 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
794 case AL_DISTANCE_MODEL
:
795 alSourcei(source
, eParam
, plValues
[0]);
801 case AL_AUXILIARY_SEND_FILTER
:
802 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
806 alSetError(pContext
, AL_INVALID_ENUM
);
811 alSetError(pContext
, AL_INVALID_NAME
);
814 alSetError(pContext
, AL_INVALID_VALUE
);
816 ProcessContext(pContext
);
820 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
822 ALCcontext
*pContext
;
827 pContext
= GetContextSuspended();
828 if(!pContext
) return;
832 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
837 *pflValue
= Source
->flPitch
;
841 *pflValue
= Source
->flGain
;
845 *pflValue
= Source
->flMinGain
;
849 *pflValue
= Source
->flMaxGain
;
852 case AL_MAX_DISTANCE
:
853 *pflValue
= Source
->flMaxDistance
;
856 case AL_ROLLOFF_FACTOR
:
857 *pflValue
= Source
->flRollOffFactor
;
860 case AL_CONE_OUTER_GAIN
:
861 *pflValue
= Source
->flOuterGain
;
864 case AL_CONE_OUTER_GAINHF
:
865 *pflValue
= Source
->OuterGainHF
;
869 case AL_SAMPLE_OFFSET
:
871 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
872 pContext
->Device
->Frequency
;
873 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
874 *pflValue
= Offsets
[0];
877 case AL_CONE_INNER_ANGLE
:
878 *pflValue
= Source
->flInnerAngle
;
881 case AL_CONE_OUTER_ANGLE
:
882 *pflValue
= Source
->flOuterAngle
;
885 case AL_REFERENCE_DISTANCE
:
886 *pflValue
= Source
->flRefDistance
;
889 case AL_AIR_ABSORPTION_FACTOR
:
890 *pflValue
= Source
->AirAbsorptionFactor
;
893 case AL_ROOM_ROLLOFF_FACTOR
:
894 *pflValue
= Source
->RoomRolloffFactor
;
897 case AL_DOPPLER_FACTOR
:
898 *pflValue
= Source
->DopplerFactor
;
902 alSetError(pContext
, AL_INVALID_ENUM
);
907 alSetError(pContext
, AL_INVALID_NAME
);
910 alSetError(pContext
, AL_INVALID_VALUE
);
912 ProcessContext(pContext
);
916 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
918 ALCcontext
*pContext
;
921 pContext
= GetContextSuspended();
922 if(!pContext
) return;
924 if(pflValue1
&& pflValue2
&& pflValue3
)
926 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
931 *pflValue1
= Source
->vPosition
[0];
932 *pflValue2
= Source
->vPosition
[1];
933 *pflValue3
= Source
->vPosition
[2];
937 *pflValue1
= Source
->vVelocity
[0];
938 *pflValue2
= Source
->vVelocity
[1];
939 *pflValue3
= Source
->vVelocity
[2];
943 *pflValue1
= Source
->vOrientation
[0];
944 *pflValue2
= Source
->vOrientation
[1];
945 *pflValue3
= Source
->vOrientation
[2];
949 alSetError(pContext
, AL_INVALID_ENUM
);
954 alSetError(pContext
, AL_INVALID_NAME
);
957 alSetError(pContext
, AL_INVALID_VALUE
);
959 ProcessContext(pContext
);
963 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
965 ALCcontext
*pContext
;
970 pContext
= GetContextSuspended();
971 if(!pContext
) return;
975 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
983 case AL_MAX_DISTANCE
:
984 case AL_ROLLOFF_FACTOR
:
985 case AL_DOPPLER_FACTOR
:
986 case AL_CONE_OUTER_GAIN
:
988 case AL_SAMPLE_OFFSET
:
990 case AL_CONE_INNER_ANGLE
:
991 case AL_CONE_OUTER_ANGLE
:
992 case AL_REFERENCE_DISTANCE
:
993 case AL_CONE_OUTER_GAINHF
:
994 case AL_AIR_ABSORPTION_FACTOR
:
995 case AL_ROOM_ROLLOFF_FACTOR
:
996 alGetSourcef(source
, eParam
, pflValues
);
1002 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
1005 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1006 case AL_BYTE_RW_OFFSETS_SOFT
:
1007 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1008 pContext
->Device
->Frequency
;
1009 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1010 pflValues
[0] = Offsets
[0];
1011 pflValues
[1] = Offsets
[1];
1015 alSetError(pContext
, AL_INVALID_ENUM
);
1020 alSetError(pContext
, AL_INVALID_NAME
);
1023 alSetError(pContext
, AL_INVALID_VALUE
);
1025 ProcessContext(pContext
);
1029 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1031 ALCcontext
*pContext
;
1033 ALdouble Offsets
[2];
1036 pContext
= GetContextSuspended();
1037 if(!pContext
) return;
1041 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1045 case AL_MAX_DISTANCE
:
1046 *plValue
= (ALint
)Source
->flMaxDistance
;
1049 case AL_ROLLOFF_FACTOR
:
1050 *plValue
= (ALint
)Source
->flRollOffFactor
;
1053 case AL_REFERENCE_DISTANCE
:
1054 *plValue
= (ALint
)Source
->flRefDistance
;
1057 case AL_SOURCE_RELATIVE
:
1058 *plValue
= Source
->bHeadRelative
;
1061 case AL_CONE_INNER_ANGLE
:
1062 *plValue
= (ALint
)Source
->flInnerAngle
;
1065 case AL_CONE_OUTER_ANGLE
:
1066 *plValue
= (ALint
)Source
->flOuterAngle
;
1070 *plValue
= Source
->bLooping
;
1074 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1077 case AL_SOURCE_STATE
:
1078 *plValue
= Source
->state
;
1081 case AL_BUFFERS_QUEUED
:
1082 *plValue
= Source
->BuffersInQueue
;
1085 case AL_BUFFERS_PROCESSED
:
1086 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1088 /* Buffers on a looping source are in a perpetual state
1089 * of PENDING, so don't report any as PROCESSED */
1093 *plValue
= Source
->BuffersPlayed
;
1096 case AL_SOURCE_TYPE
:
1097 *plValue
= Source
->lSourceType
;
1101 case AL_SAMPLE_OFFSET
:
1102 case AL_BYTE_OFFSET
:
1103 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1104 pContext
->Device
->Frequency
;
1105 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1106 *plValue
= (ALint
)Offsets
[0];
1109 case AL_DIRECT_FILTER
:
1110 *plValue
= Source
->DirectFilter
.filter
;
1113 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1114 *plValue
= Source
->DryGainHFAuto
;
1117 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1118 *plValue
= Source
->WetGainAuto
;
1121 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1122 *plValue
= Source
->WetGainHFAuto
;
1125 case AL_DOPPLER_FACTOR
:
1126 *plValue
= (ALint
)Source
->DopplerFactor
;
1129 case AL_DISTANCE_MODEL
:
1130 *plValue
= Source
->DistanceModel
;
1134 alSetError(pContext
, AL_INVALID_ENUM
);
1139 alSetError(pContext
, AL_INVALID_NAME
);
1142 alSetError(pContext
, AL_INVALID_VALUE
);
1144 ProcessContext(pContext
);
1148 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1150 ALCcontext
*pContext
;
1153 pContext
= GetContextSuspended();
1154 if(!pContext
) return;
1156 if(plValue1
&& plValue2
&& plValue3
)
1158 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1163 *plValue1
= (ALint
)Source
->vPosition
[0];
1164 *plValue2
= (ALint
)Source
->vPosition
[1];
1165 *plValue3
= (ALint
)Source
->vPosition
[2];
1169 *plValue1
= (ALint
)Source
->vVelocity
[0];
1170 *plValue2
= (ALint
)Source
->vVelocity
[1];
1171 *plValue3
= (ALint
)Source
->vVelocity
[2];
1175 *plValue1
= (ALint
)Source
->vOrientation
[0];
1176 *plValue2
= (ALint
)Source
->vOrientation
[1];
1177 *plValue3
= (ALint
)Source
->vOrientation
[2];
1181 alSetError(pContext
, AL_INVALID_ENUM
);
1186 alSetError(pContext
, AL_INVALID_NAME
);
1189 alSetError(pContext
, AL_INVALID_VALUE
);
1191 ProcessContext(pContext
);
1195 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1197 ALCcontext
*pContext
;
1199 ALdouble Offsets
[2];
1202 pContext
= GetContextSuspended();
1203 if(!pContext
) return;
1207 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1211 case AL_SOURCE_RELATIVE
:
1212 case AL_CONE_INNER_ANGLE
:
1213 case AL_CONE_OUTER_ANGLE
:
1216 case AL_SOURCE_STATE
:
1217 case AL_BUFFERS_QUEUED
:
1218 case AL_BUFFERS_PROCESSED
:
1220 case AL_SAMPLE_OFFSET
:
1221 case AL_BYTE_OFFSET
:
1222 case AL_MAX_DISTANCE
:
1223 case AL_ROLLOFF_FACTOR
:
1224 case AL_DOPPLER_FACTOR
:
1225 case AL_REFERENCE_DISTANCE
:
1226 case AL_SOURCE_TYPE
:
1227 case AL_DIRECT_FILTER
:
1228 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1229 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1230 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1231 case AL_DISTANCE_MODEL
:
1232 alGetSourcei(source
, eParam
, plValues
);
1238 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1241 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1242 case AL_BYTE_RW_OFFSETS_SOFT
:
1243 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1244 pContext
->Device
->Frequency
;
1245 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1246 plValues
[0] = (ALint
)Offsets
[0];
1247 plValues
[1] = (ALint
)Offsets
[1];
1251 alSetError(pContext
, AL_INVALID_ENUM
);
1256 alSetError(pContext
, AL_INVALID_NAME
);
1259 alSetError(pContext
, AL_INVALID_VALUE
);
1261 ProcessContext(pContext
);
1265 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1267 alSourcePlayv(1, &source
);
1270 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1272 ALCcontext
*Context
;
1274 ALbufferlistitem
*BufferList
;
1277 Context
= GetContextSuspended();
1278 if(!Context
) return;
1282 alSetError(Context
, AL_INVALID_VALUE
);
1285 if(n
> 0 && !sources
)
1287 alSetError(Context
, AL_INVALID_VALUE
);
1291 // Check that all the Sources are valid
1292 for(i
= 0;i
< n
;i
++)
1294 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1296 alSetError(Context
, AL_INVALID_NAME
);
1301 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1306 newcount
= Context
->MaxActiveSources
<< 1;
1308 temp
= realloc(Context
->ActiveSources
,
1309 sizeof(*Context
->ActiveSources
) * newcount
);
1312 alSetError(Context
, AL_OUT_OF_MEMORY
);
1316 Context
->ActiveSources
= temp
;
1317 Context
->MaxActiveSources
= newcount
;
1320 for(i
= 0;i
< n
;i
++)
1322 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1324 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1325 BufferList
= Source
->queue
;
1328 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1330 BufferList
= BufferList
->next
;
1335 Source
->state
= AL_STOPPED
;
1336 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1337 Source
->position
= 0;
1338 Source
->position_fraction
= 0;
1339 Source
->lOffset
= 0;
1343 if(Source
->state
!= AL_PAUSED
)
1345 Source
->state
= AL_PLAYING
;
1346 Source
->position
= 0;
1347 Source
->position_fraction
= 0;
1348 Source
->BuffersPlayed
= 0;
1350 Source
->Buffer
= Source
->queue
->buffer
;
1353 Source
->state
= AL_PLAYING
;
1355 // Check if an Offset has been set
1357 ApplyOffset(Source
);
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;
1369 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1371 if(Context
->ActiveSources
[j
] == Source
)
1374 if(j
== Context
->ActiveSourceCount
)
1375 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1380 ProcessContext(Context
);
1383 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1385 alSourcePausev(1, &source
);
1388 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1390 ALCcontext
*Context
;
1394 Context
= GetContextSuspended();
1395 if(!Context
) return;
1399 alSetError(Context
, AL_INVALID_VALUE
);
1402 if(n
> 0 && !sources
)
1404 alSetError(Context
, AL_INVALID_VALUE
);
1408 // Check all the Sources are valid
1409 for(i
= 0;i
< n
;i
++)
1411 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1413 alSetError(Context
, AL_INVALID_NAME
);
1418 for(i
= 0;i
< n
;i
++)
1420 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1421 if(Source
->state
== AL_PLAYING
)
1422 Source
->state
= AL_PAUSED
;
1426 ProcessContext(Context
);
1429 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1431 alSourceStopv(1, &source
);
1434 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1436 ALCcontext
*Context
;
1440 Context
= GetContextSuspended();
1441 if(!Context
) return;
1445 alSetError(Context
, AL_INVALID_VALUE
);
1448 if(n
> 0 && !sources
)
1450 alSetError(Context
, AL_INVALID_VALUE
);
1454 // Check all the Sources are valid
1455 for(i
= 0;i
< n
;i
++)
1457 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1459 alSetError(Context
, AL_INVALID_NAME
);
1464 for(i
= 0;i
< n
;i
++)
1466 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1467 if(Source
->state
!= AL_INITIAL
)
1469 Source
->state
= AL_STOPPED
;
1470 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1472 Source
->lOffset
= 0;
1476 ProcessContext(Context
);
1479 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1481 alSourceRewindv(1, &source
);
1484 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1486 ALCcontext
*Context
;
1490 Context
= GetContextSuspended();
1491 if(!Context
) return;
1495 alSetError(Context
, AL_INVALID_VALUE
);
1498 if(n
> 0 && !sources
)
1500 alSetError(Context
, AL_INVALID_VALUE
);
1504 // Check all the Sources are valid
1505 for(i
= 0;i
< n
;i
++)
1507 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1509 alSetError(Context
, AL_INVALID_NAME
);
1514 for(i
= 0;i
< n
;i
++)
1516 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1517 if(Source
->state
!= AL_INITIAL
)
1519 Source
->state
= AL_INITIAL
;
1520 Source
->position
= 0;
1521 Source
->position_fraction
= 0;
1522 Source
->BuffersPlayed
= 0;
1524 Source
->Buffer
= Source
->queue
->buffer
;
1526 Source
->lOffset
= 0;
1530 ProcessContext(Context
);
1534 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1536 ALCcontext
*Context
;
1541 ALbufferlistitem
*BufferListStart
;
1542 ALbufferlistitem
*BufferList
;
1543 ALbuffer
*BufferFmt
;
1548 Context
= GetContextSuspended();
1549 if(!Context
) return;
1553 alSetError(Context
, AL_INVALID_VALUE
);
1557 // Check that all buffers are valid or zero and that the source is valid
1559 // Check that this is a valid source
1560 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1562 alSetError(Context
, AL_INVALID_NAME
);
1566 // Check that this is not a STATIC Source
1567 if(Source
->lSourceType
== AL_STATIC
)
1569 // Invalid Source Type (can't queue on a Static Source)
1570 alSetError(Context
, AL_INVALID_OPERATION
);
1574 device
= Context
->Device
;
1578 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1579 BufferList
= Source
->queue
;
1582 if(BufferList
->buffer
)
1584 BufferFmt
= BufferList
->buffer
;
1587 BufferList
= BufferList
->next
;
1590 for(i
= 0;i
< n
;i
++)
1595 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1597 alSetError(Context
, AL_INVALID_NAME
);
1601 if(BufferFmt
== NULL
)
1605 if(buffer
->FmtChannels
== FmtMono
)
1606 Source
->Update
= CalcSourceParams
;
1608 Source
->Update
= CalcNonAttnSourceParams
;
1610 Source
->NeedsUpdate
= AL_TRUE
;
1612 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
1613 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
1614 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
1616 alSetError(Context
, AL_INVALID_OPERATION
);
1621 // Change Source Type
1622 Source
->lSourceType
= AL_STREAMING
;
1624 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1626 // All buffers are valid - so add them to the list
1627 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1628 BufferListStart
->buffer
= buffer
;
1629 BufferListStart
->next
= NULL
;
1630 BufferListStart
->prev
= NULL
;
1632 // Increment reference counter for buffer
1633 if(buffer
) buffer
->refcount
++;
1635 BufferList
= BufferListStart
;
1637 for(i
= 1;i
< n
;i
++)
1639 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1641 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1642 BufferList
->next
->buffer
= buffer
;
1643 BufferList
->next
->next
= NULL
;
1644 BufferList
->next
->prev
= BufferList
;
1646 // Increment reference counter for buffer
1647 if(buffer
) buffer
->refcount
++;
1649 BufferList
= BufferList
->next
;
1652 if(Source
->queue
== NULL
)
1654 Source
->queue
= BufferListStart
;
1655 // Update Current Buffer
1656 Source
->Buffer
= BufferListStart
->buffer
;
1660 // Find end of queue
1661 BufferList
= Source
->queue
;
1662 while(BufferList
->next
!= NULL
)
1663 BufferList
= BufferList
->next
;
1665 BufferList
->next
= BufferListStart
;
1666 BufferList
->next
->prev
= BufferList
;
1669 // Update number of buffers in queue
1670 Source
->BuffersInQueue
+= n
;
1673 ProcessContext(Context
);
1677 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1678 // an array of buffer IDs that are to be filled with the names of the buffers removed
1679 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1681 ALCcontext
*Context
;
1684 ALbufferlistitem
*BufferList
;
1689 Context
= GetContextSuspended();
1690 if(!Context
) return;
1694 alSetError(Context
, AL_INVALID_VALUE
);
1698 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1700 alSetError(Context
, AL_INVALID_NAME
);
1704 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1705 (ALuint
)n
> Source
->BuffersPlayed
)
1707 // Some buffers can't be unqueue because they have not been processed
1708 alSetError(Context
, AL_INVALID_VALUE
);
1712 for(i
= 0;i
< n
;i
++)
1714 BufferList
= Source
->queue
;
1715 Source
->queue
= BufferList
->next
;
1717 if(BufferList
->buffer
)
1719 // Record name of buffer
1720 buffers
[i
] = BufferList
->buffer
->buffer
;
1721 // Decrement buffer reference counter
1722 BufferList
->buffer
->refcount
--;
1727 // Release memory for buffer list item
1729 Source
->BuffersInQueue
--;
1732 Source
->queue
->prev
= NULL
;
1734 if(Source
->state
!= AL_PLAYING
)
1737 Source
->Buffer
= Source
->queue
->buffer
;
1739 Source
->Buffer
= NULL
;
1741 Source
->BuffersPlayed
-= n
;
1744 ProcessContext(Context
);
1748 static ALvoid
InitSourceParams(ALsource
*Source
)
1750 Source
->flInnerAngle
= 360.0f
;
1751 Source
->flOuterAngle
= 360.0f
;
1752 Source
->flPitch
= 1.0f
;
1753 Source
->vPosition
[0] = 0.0f
;
1754 Source
->vPosition
[1] = 0.0f
;
1755 Source
->vPosition
[2] = 0.0f
;
1756 Source
->vOrientation
[0] = 0.0f
;
1757 Source
->vOrientation
[1] = 0.0f
;
1758 Source
->vOrientation
[2] = 0.0f
;
1759 Source
->vVelocity
[0] = 0.0f
;
1760 Source
->vVelocity
[1] = 0.0f
;
1761 Source
->vVelocity
[2] = 0.0f
;
1762 Source
->flRefDistance
= 1.0f
;
1763 Source
->flMaxDistance
= FLT_MAX
;
1764 Source
->flRollOffFactor
= 1.0f
;
1765 Source
->bLooping
= AL_FALSE
;
1766 Source
->flGain
= 1.0f
;
1767 Source
->flMinGain
= 0.0f
;
1768 Source
->flMaxGain
= 1.0f
;
1769 Source
->flOuterGain
= 0.0f
;
1770 Source
->OuterGainHF
= 1.0f
;
1772 Source
->DryGainHFAuto
= AL_TRUE
;
1773 Source
->WetGainAuto
= AL_TRUE
;
1774 Source
->WetGainHFAuto
= AL_TRUE
;
1775 Source
->AirAbsorptionFactor
= 0.0f
;
1776 Source
->RoomRolloffFactor
= 0.0f
;
1777 Source
->DopplerFactor
= 1.0f
;
1779 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1781 Source
->Resampler
= DefaultResampler
;
1783 Source
->state
= AL_INITIAL
;
1784 Source
->lSourceType
= AL_UNDETERMINED
;
1786 Source
->NeedsUpdate
= AL_TRUE
;
1788 Source
->Buffer
= NULL
;
1795 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1796 The offset is relative to the start of the queue (not the start of the current buffer)
1798 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1800 const ALbufferlistitem
*BufferList
;
1801 const ALbuffer
*Buffer
= NULL
;
1802 enum UserFmtType OriginalType
;
1804 ALint Channels
, Bytes
;
1805 ALuint readPos
, writePos
;
1806 ALuint TotalBufferDataSize
;
1809 // Find the first non-NULL Buffer in the Queue
1810 BufferList
= Source
->queue
;
1813 if(BufferList
->buffer
)
1815 Buffer
= BufferList
->buffer
;
1818 BufferList
= BufferList
->next
;
1821 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1828 // Get Current Buffer Size and frequency (in milliseconds)
1829 BufferFreq
= (ALfloat
)Buffer
->Frequency
;
1830 OriginalType
= Buffer
->OriginalType
;
1831 Channels
= ChannelsFromFmt(Buffer
->FmtChannels
);
1832 Bytes
= BytesFromFmt(Buffer
->FmtType
);
1834 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1835 readPos
= Source
->position
* Channels
* Bytes
;
1836 // Add byte length of any processed buffers in the queue
1837 TotalBufferDataSize
= 0;
1838 BufferList
= Source
->queue
;
1839 for(i
= 0;BufferList
;i
++)
1841 if(BufferList
->buffer
)
1843 if(i
< Source
->BuffersPlayed
)
1844 readPos
+= BufferList
->buffer
->size
;
1845 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1847 BufferList
= BufferList
->next
;
1849 if(Source
->state
== AL_PLAYING
)
1850 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1854 if(Source
->bLooping
)
1856 readPos
%= TotalBufferDataSize
;
1857 writePos
%= TotalBufferDataSize
;
1861 // Wrap positions back to 0
1862 if(readPos
>= TotalBufferDataSize
)
1864 if(writePos
>= TotalBufferDataSize
)
1871 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1872 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1874 case AL_SAMPLE_OFFSET
:
1875 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1876 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1877 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1879 case AL_BYTE_OFFSET
:
1880 case AL_BYTE_RW_OFFSETS_SOFT
:
1881 // Take into account the original format of the Buffer
1882 if(OriginalType
== UserFmtIMA4
)
1884 ALuint FrameBlockSize
= 65 * Bytes
* Channels
;
1885 ALuint BlockSize
= 36 * Channels
;
1887 // Round down to nearest ADPCM block
1888 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1889 if(Source
->state
!= AL_PLAYING
)
1890 offset
[1] = offset
[0];
1893 // Round up to nearest ADPCM block
1894 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1895 FrameBlockSize
* BlockSize
);
1900 ALuint OrigBytes
= BytesFromUserFmt(OriginalType
);
1901 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1902 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1912 Apply a playback offset to the Source. This function will update the queue (to correctly
1913 mark buffers as 'pending' or 'processed' depending upon the new offset.
1915 static ALboolean
ApplyOffset(ALsource
*Source
)
1917 const ALbufferlistitem
*BufferList
;
1918 const ALbuffer
*Buffer
;
1919 ALint lBufferSize
, lTotalBufferSize
;
1920 ALint BuffersPlayed
;
1923 // Get true byte offset
1924 lByteOffset
= GetByteOffset(Source
);
1926 // If the offset is invalid, don't apply it
1927 if(lByteOffset
== -1)
1930 // Sort out the queue (pending and processed states)
1931 BufferList
= Source
->queue
;
1932 lTotalBufferSize
= 0;
1937 Buffer
= BufferList
->buffer
;
1938 lBufferSize
= Buffer
? Buffer
->size
: 0;
1940 if(lBufferSize
<= lByteOffset
-lTotalBufferSize
)
1942 // Offset is past this buffer so increment BuffersPlayed
1945 else if(lTotalBufferSize
<= lByteOffset
)
1947 // Offset is within this buffer
1948 // Set Current Buffer
1949 Source
->Buffer
= BufferList
->buffer
;
1950 Source
->BuffersPlayed
= BuffersPlayed
;
1952 // SW Mixer Positions are in Samples
1953 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1954 FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
1958 // Increment the TotalBufferSize
1959 lTotalBufferSize
+= lBufferSize
;
1961 // Move on to next buffer in the Queue
1962 BufferList
= BufferList
->next
;
1964 // Offset is out of range of the buffer queue
1972 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1973 offset supplied by the application). This takes into account the fact that the buffer format
1974 may have been modifed by AL (e.g 8bit samples are converted to float)
1976 static ALint
GetByteOffset(ALsource
*Source
)
1978 const ALbuffer
*Buffer
= NULL
;
1979 const ALbufferlistitem
*BufferList
;
1980 ALint ByteOffset
= -1;
1982 // Find the first non-NULL Buffer in the Queue
1983 BufferList
= Source
->queue
;
1986 if(BufferList
->buffer
)
1988 Buffer
= BufferList
->buffer
;
1991 BufferList
= BufferList
->next
;
1996 Source
->lOffset
= 0;
2000 // Determine the ByteOffset (and ensure it is block aligned)
2001 switch(Source
->lOffsetType
)
2003 case AL_BYTE_OFFSET
:
2004 // Take into consideration the original format
2005 ByteOffset
= Source
->lOffset
;
2006 if(Buffer
->OriginalType
== UserFmtIMA4
)
2008 // Round down to nearest ADPCM block
2009 ByteOffset
/= 36 * ChannelsFromUserFmt(Buffer
->OriginalChannels
);
2010 // Multiply by compression rate (65 sample frames per block)
2014 ByteOffset
/= FrameSizeFromUserFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
2015 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2018 case AL_SAMPLE_OFFSET
:
2019 ByteOffset
= Source
->lOffset
* FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2023 // Note - lOffset is internally stored as Milliseconds
2024 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * Buffer
->Frequency
);
2025 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2029 Source
->lOffset
= 0;
2035 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2039 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2041 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2042 Context
->SourceMap
.array
[pos
].value
= NULL
;
2044 // For each buffer in the source's queue, decrement its reference counter and remove it
2045 while(temp
->queue
!= NULL
)
2047 ALbufferlistitem
*BufferList
= temp
->queue
;
2048 temp
->queue
= BufferList
->next
;
2050 if(BufferList
->buffer
!= NULL
)
2051 BufferList
->buffer
->refcount
--;
2055 for(j
= 0;j
< MAX_SENDS
;++j
)
2057 if(temp
->Send
[j
].Slot
)
2058 temp
->Send
[j
].Slot
->refcount
--;
2059 temp
->Send
[j
].Slot
= NULL
;
2062 // Release source structure
2063 ALTHUNK_REMOVEENTRY(temp
->source
);
2064 memset(temp
, 0, sizeof(ALsource
));