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();
56 alSetError(Context
, AL_INVALID_VALUE
);
59 Device
= Context
->Device
;
61 // Check that enough memory has been allocted in the 'sources' array for n Sources
62 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
64 // Check that the requested number of sources can be generated
65 if((Context
->SourceMap
.size
+ n
) <= (ALsizei
)Device
->MaxNoOfSources
)
69 // Add additional sources to the list
72 ALsource
*source
= calloc(1, sizeof(ALsource
));
75 alSetError(Context
, AL_OUT_OF_MEMORY
);
76 alDeleteSources(i
, sources
);
80 source
->source
= (ALuint
)ALTHUNK_ADDENTRY(source
);
81 err
= InsertUIntMapEntry(&Context
->SourceMap
, source
->source
,
83 if(err
!= AL_NO_ERROR
)
85 ALTHUNK_REMOVEENTRY(source
->source
);
86 memset(source
, 0, sizeof(ALsource
));
89 alSetError(Context
, err
);
90 alDeleteSources(i
, sources
);
94 sources
[i
++] = source
->source
;
95 InitSourceParams(source
);
100 // Not enough resources to create the Sources
101 alSetError(Context
, AL_INVALID_VALUE
);
107 alSetError(Context
, AL_INVALID_VALUE
);
111 ProcessContext(Context
);
115 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
121 ALbufferlistitem
*BufferList
;
122 ALboolean bSourcesValid
= AL_TRUE
;
124 Context
= GetContextSuspended();
128 alSetError(Context
, AL_INVALID_VALUE
);
131 Device
= Context
->Device
;
133 // Check that all Sources are valid (and can therefore be deleted)
136 if(LookupSource(Context
->SourceMap
, sources
[i
]) == NULL
)
138 alSetError(Context
, AL_INVALID_NAME
);
139 bSourcesValid
= AL_FALSE
;
146 // All Sources are valid, and can be deleted
149 // Recheck that the Source is valid, because there could be duplicated Source names
150 if((Source
=LookupSource(Context
->SourceMap
, sources
[i
])) != NULL
)
152 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
154 if(Context
->ActiveSources
[j
] == Source
)
156 ALsizei end
= --(Context
->ActiveSourceCount
);
157 Context
->ActiveSources
[j
] = Context
->ActiveSources
[end
];
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while(Source
->queue
!= NULL
)
165 BufferList
= Source
->queue
;
166 // Decrement buffer's reference counter
167 if(BufferList
->buffer
!= NULL
)
168 BufferList
->buffer
->refcount
--;
169 // Update queue to point to next element in list
170 Source
->queue
= BufferList
->next
;
171 // Release memory allocated for buffer list item
175 for(j
= 0;j
< MAX_SENDS
;++j
)
177 if(Source
->Send
[j
].Slot
)
178 Source
->Send
[j
].Slot
->refcount
--;
179 Source
->Send
[j
].Slot
= NULL
;
182 // Remove Source from list of Sources
183 RemoveUIntMapKey(&Context
->SourceMap
, Source
->source
);
184 ALTHUNK_REMOVEENTRY(Source
->source
);
186 memset(Source
,0,sizeof(ALsource
));
193 ProcessContext(Context
);
197 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
202 Context
= GetContextSuspended();
203 if(!Context
) return AL_FALSE
;
205 result
= (LookupSource(Context
->SourceMap
, source
) ? AL_TRUE
: AL_FALSE
);
207 ProcessContext(Context
);
213 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
215 ALCcontext
*pContext
;
218 pContext
= GetContextSuspended();
219 if(!pContext
) return;
221 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
228 Source
->flPitch
= flValue
;
229 if(Source
->flPitch
< 0.001f
)
230 Source
->flPitch
= 0.001f
;
231 Source
->NeedsUpdate
= AL_TRUE
;
234 alSetError(pContext
, AL_INVALID_VALUE
);
237 case AL_CONE_INNER_ANGLE
:
238 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
240 Source
->flInnerAngle
= flValue
;
241 Source
->NeedsUpdate
= AL_TRUE
;
244 alSetError(pContext
, AL_INVALID_VALUE
);
247 case AL_CONE_OUTER_ANGLE
:
248 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
250 Source
->flOuterAngle
= flValue
;
251 Source
->NeedsUpdate
= AL_TRUE
;
254 alSetError(pContext
, AL_INVALID_VALUE
);
260 Source
->flGain
= flValue
;
261 Source
->NeedsUpdate
= AL_TRUE
;
264 alSetError(pContext
, AL_INVALID_VALUE
);
267 case AL_MAX_DISTANCE
:
270 Source
->flMaxDistance
= flValue
;
271 Source
->NeedsUpdate
= AL_TRUE
;
274 alSetError(pContext
, AL_INVALID_VALUE
);
277 case AL_ROLLOFF_FACTOR
:
280 Source
->flRollOffFactor
= flValue
;
281 Source
->NeedsUpdate
= AL_TRUE
;
284 alSetError(pContext
, AL_INVALID_VALUE
);
287 case AL_REFERENCE_DISTANCE
:
290 Source
->flRefDistance
= flValue
;
291 Source
->NeedsUpdate
= AL_TRUE
;
294 alSetError(pContext
, AL_INVALID_VALUE
);
298 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
300 Source
->flMinGain
= flValue
;
301 Source
->NeedsUpdate
= AL_TRUE
;
304 alSetError(pContext
, AL_INVALID_VALUE
);
308 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
310 Source
->flMaxGain
= flValue
;
311 Source
->NeedsUpdate
= AL_TRUE
;
314 alSetError(pContext
, AL_INVALID_VALUE
);
317 case AL_CONE_OUTER_GAIN
:
318 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
320 Source
->flOuterGain
= flValue
;
321 Source
->NeedsUpdate
= AL_TRUE
;
324 alSetError(pContext
, AL_INVALID_VALUE
);
327 case AL_CONE_OUTER_GAINHF
:
328 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
330 Source
->OuterGainHF
= flValue
;
331 Source
->NeedsUpdate
= AL_TRUE
;
334 alSetError(pContext
, AL_INVALID_VALUE
);
337 case AL_AIR_ABSORPTION_FACTOR
:
338 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
340 Source
->AirAbsorptionFactor
= flValue
;
341 Source
->NeedsUpdate
= AL_TRUE
;
344 alSetError(pContext
, AL_INVALID_VALUE
);
347 case AL_ROOM_ROLLOFF_FACTOR
:
348 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
350 Source
->RoomRolloffFactor
= flValue
;
351 Source
->NeedsUpdate
= AL_TRUE
;
354 alSetError(pContext
, AL_INVALID_VALUE
);
357 case AL_DOPPLER_FACTOR
:
358 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
360 Source
->DopplerFactor
= flValue
;
361 Source
->NeedsUpdate
= AL_TRUE
;
364 alSetError(pContext
, AL_INVALID_VALUE
);
368 case AL_SAMPLE_OFFSET
:
372 Source
->lOffsetType
= eParam
;
374 // Store Offset (convert Seconds into Milliseconds)
375 if(eParam
== AL_SEC_OFFSET
)
376 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
378 Source
->lOffset
= (ALint
)flValue
;
380 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
382 if(ApplyOffset(Source
) == AL_FALSE
)
383 alSetError(pContext
, AL_INVALID_VALUE
);
387 alSetError(pContext
, AL_INVALID_VALUE
);
391 alSetError(pContext
, AL_INVALID_ENUM
);
397 // Invalid Source Name
398 alSetError(pContext
, AL_INVALID_NAME
);
401 ProcessContext(pContext
);
405 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
407 ALCcontext
*pContext
;
410 pContext
= GetContextSuspended();
411 if(!pContext
) return;
413 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
418 Source
->vPosition
[0] = flValue1
;
419 Source
->vPosition
[1] = flValue2
;
420 Source
->vPosition
[2] = flValue3
;
421 Source
->NeedsUpdate
= AL_TRUE
;
425 Source
->vVelocity
[0] = flValue1
;
426 Source
->vVelocity
[1] = flValue2
;
427 Source
->vVelocity
[2] = flValue3
;
428 Source
->NeedsUpdate
= AL_TRUE
;
432 Source
->vOrientation
[0] = flValue1
;
433 Source
->vOrientation
[1] = flValue2
;
434 Source
->vOrientation
[2] = flValue3
;
435 Source
->NeedsUpdate
= AL_TRUE
;
439 alSetError(pContext
, AL_INVALID_ENUM
);
444 alSetError(pContext
, AL_INVALID_NAME
);
446 ProcessContext(pContext
);
450 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
452 ALCcontext
*pContext
;
454 pContext
= GetContextSuspended();
455 if(!pContext
) return;
459 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
464 case AL_CONE_INNER_ANGLE
:
465 case AL_CONE_OUTER_ANGLE
:
467 case AL_MAX_DISTANCE
:
468 case AL_ROLLOFF_FACTOR
:
469 case AL_REFERENCE_DISTANCE
:
472 case AL_CONE_OUTER_GAIN
:
473 case AL_CONE_OUTER_GAINHF
:
475 case AL_SAMPLE_OFFSET
:
477 case AL_AIR_ABSORPTION_FACTOR
:
478 case AL_ROOM_ROLLOFF_FACTOR
:
479 alSourcef(source
, eParam
, pflValues
[0]);
485 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
489 alSetError(pContext
, AL_INVALID_ENUM
);
494 alSetError(pContext
, AL_INVALID_NAME
);
497 alSetError(pContext
, AL_INVALID_VALUE
);
499 ProcessContext(pContext
);
503 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
505 ALCcontext
*pContext
;
507 ALbufferlistitem
*BufferListItem
;
509 pContext
= GetContextSuspended();
510 if(!pContext
) return;
512 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
514 ALCdevice
*device
= pContext
->Device
;
518 case AL_MAX_DISTANCE
:
519 case AL_ROLLOFF_FACTOR
:
520 case AL_CONE_INNER_ANGLE
:
521 case AL_CONE_OUTER_ANGLE
:
522 case AL_REFERENCE_DISTANCE
:
523 alSourcef(source
, eParam
, (ALfloat
)lValue
);
526 case AL_SOURCE_RELATIVE
:
527 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
529 Source
->bHeadRelative
= (ALboolean
)lValue
;
530 Source
->NeedsUpdate
= AL_TRUE
;
533 alSetError(pContext
, AL_INVALID_VALUE
);
537 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
538 Source
->bLooping
= (ALboolean
)lValue
;
540 alSetError(pContext
, AL_INVALID_VALUE
);
544 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
546 ALbuffer
*buffer
= NULL
;
549 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
551 // Remove all elements in the queue
552 while(Source
->queue
!= NULL
)
554 BufferListItem
= Source
->queue
;
555 Source
->queue
= BufferListItem
->next
;
556 // Decrement reference counter for buffer
557 if(BufferListItem
->buffer
)
558 BufferListItem
->buffer
->refcount
--;
559 // Release memory for buffer list item
560 free(BufferListItem
);
561 // Decrement the number of buffers in the queue
562 Source
->BuffersInQueue
--;
565 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
568 // Source is now in STATIC mode
569 Source
->lSourceType
= AL_STATIC
;
571 // Add the selected buffer to the queue
572 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
573 BufferListItem
->buffer
= buffer
;
574 BufferListItem
->next
= NULL
;
576 Source
->queue
= BufferListItem
;
577 Source
->BuffersInQueue
= 1;
579 if(aluChannelsFromFormat(buffer
->format
) == 1)
580 Source
->Update
= CalcSourceParams
;
582 Source
->Update
= CalcNonAttnSourceParams
;
584 // Increment reference counter for buffer
589 // Source is now in UNDETERMINED mode
590 Source
->lSourceType
= AL_UNDETERMINED
;
592 Source
->BuffersPlayed
= 0;
594 // Update AL_BUFFER parameter
595 Source
->Buffer
= buffer
;
596 Source
->NeedsUpdate
= AL_TRUE
;
599 alSetError(pContext
, AL_INVALID_VALUE
);
602 alSetError(pContext
, AL_INVALID_OPERATION
);
605 case AL_SOURCE_STATE
:
607 alSetError(pContext
, AL_INVALID_OPERATION
);
611 case AL_SAMPLE_OFFSET
:
615 Source
->lOffsetType
= eParam
;
617 // Store Offset (convert Seconds into Milliseconds)
618 if(eParam
== AL_SEC_OFFSET
)
619 Source
->lOffset
= lValue
* 1000;
621 Source
->lOffset
= lValue
;
623 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
625 if(ApplyOffset(Source
) == AL_FALSE
)
626 alSetError(pContext
, AL_INVALID_VALUE
);
630 alSetError(pContext
, AL_INVALID_VALUE
);
633 case AL_DIRECT_FILTER
: {
634 ALfilter
*filter
= NULL
;
637 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
641 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
642 Source
->DirectFilter
.filter
= 0;
645 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
646 Source
->NeedsUpdate
= AL_TRUE
;
649 alSetError(pContext
, AL_INVALID_VALUE
);
652 case AL_DIRECT_FILTER_GAINHF_AUTO
:
653 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
655 Source
->DryGainHFAuto
= lValue
;
656 Source
->NeedsUpdate
= AL_TRUE
;
659 alSetError(pContext
, AL_INVALID_VALUE
);
662 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
663 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
665 Source
->WetGainAuto
= lValue
;
666 Source
->NeedsUpdate
= AL_TRUE
;
669 alSetError(pContext
, AL_INVALID_VALUE
);
672 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
673 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
675 Source
->WetGainHFAuto
= lValue
;
676 Source
->NeedsUpdate
= AL_TRUE
;
679 alSetError(pContext
, AL_INVALID_VALUE
);
682 case AL_DISTANCE_MODEL
:
683 if(lValue
== AL_NONE
||
684 lValue
== AL_INVERSE_DISTANCE
||
685 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
686 lValue
== AL_LINEAR_DISTANCE
||
687 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
688 lValue
== AL_EXPONENT_DISTANCE
||
689 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
691 Source
->DistanceModel
= lValue
;
692 if(pContext
->SourceDistanceModel
)
693 Source
->NeedsUpdate
= AL_TRUE
;
696 alSetError(pContext
, AL_INVALID_VALUE
);
700 alSetError(pContext
, AL_INVALID_ENUM
);
705 alSetError(pContext
, AL_INVALID_NAME
);
707 ProcessContext(pContext
);
711 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
713 ALCcontext
*pContext
;
716 pContext
= GetContextSuspended();
717 if(!pContext
) return;
719 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
721 ALCdevice
*device
= pContext
->Device
;
728 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
731 case AL_AUXILIARY_SEND_FILTER
: {
732 ALeffectslot
*ALEffectSlot
= NULL
;
733 ALfilter
*ALFilter
= NULL
;
735 if((ALuint
)lValue2
< device
->NumAuxSends
&&
737 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
739 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
741 /* Release refcount on the previous slot, and add one for
743 if(Source
->Send
[lValue2
].Slot
)
744 Source
->Send
[lValue2
].Slot
->refcount
--;
745 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
746 if(Source
->Send
[lValue2
].Slot
)
747 Source
->Send
[lValue2
].Slot
->refcount
++;
752 Source
->Send
[lValue2
].WetFilter
.type
= 0;
753 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
756 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
757 Source
->NeedsUpdate
= AL_TRUE
;
760 alSetError(pContext
, AL_INVALID_VALUE
);
764 alSetError(pContext
, AL_INVALID_ENUM
);
769 alSetError(pContext
, AL_INVALID_NAME
);
771 ProcessContext(pContext
);
775 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
777 ALCcontext
*pContext
;
779 pContext
= GetContextSuspended();
780 if(!pContext
) return;
784 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
788 case AL_SOURCE_RELATIVE
:
789 case AL_CONE_INNER_ANGLE
:
790 case AL_CONE_OUTER_ANGLE
:
793 case AL_SOURCE_STATE
:
795 case AL_SAMPLE_OFFSET
:
797 case AL_MAX_DISTANCE
:
798 case AL_ROLLOFF_FACTOR
:
799 case AL_REFERENCE_DISTANCE
:
800 case AL_DIRECT_FILTER
:
801 case AL_DIRECT_FILTER_GAINHF_AUTO
:
802 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
803 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
804 case AL_DISTANCE_MODEL
:
805 alSourcei(source
, eParam
, plValues
[0]);
811 case AL_AUXILIARY_SEND_FILTER
:
812 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
816 alSetError(pContext
, AL_INVALID_ENUM
);
821 alSetError(pContext
, AL_INVALID_NAME
);
824 alSetError(pContext
, AL_INVALID_VALUE
);
826 ProcessContext(pContext
);
830 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
832 ALCcontext
*pContext
;
837 pContext
= GetContextSuspended();
838 if(!pContext
) return;
842 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
847 *pflValue
= Source
->flPitch
;
851 *pflValue
= Source
->flGain
;
855 *pflValue
= Source
->flMinGain
;
859 *pflValue
= Source
->flMaxGain
;
862 case AL_MAX_DISTANCE
:
863 *pflValue
= Source
->flMaxDistance
;
866 case AL_ROLLOFF_FACTOR
:
867 *pflValue
= Source
->flRollOffFactor
;
870 case AL_CONE_OUTER_GAIN
:
871 *pflValue
= Source
->flOuterGain
;
874 case AL_CONE_OUTER_GAINHF
:
875 *pflValue
= Source
->OuterGainHF
;
879 case AL_SAMPLE_OFFSET
:
881 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
882 pContext
->Device
->Frequency
;
883 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
884 *pflValue
= Offsets
[0];
887 case AL_CONE_INNER_ANGLE
:
888 *pflValue
= Source
->flInnerAngle
;
891 case AL_CONE_OUTER_ANGLE
:
892 *pflValue
= Source
->flOuterAngle
;
895 case AL_REFERENCE_DISTANCE
:
896 *pflValue
= Source
->flRefDistance
;
899 case AL_AIR_ABSORPTION_FACTOR
:
900 *pflValue
= Source
->AirAbsorptionFactor
;
903 case AL_ROOM_ROLLOFF_FACTOR
:
904 *pflValue
= Source
->RoomRolloffFactor
;
907 case AL_DOPPLER_FACTOR
:
908 *pflValue
= Source
->DopplerFactor
;
912 alSetError(pContext
, AL_INVALID_ENUM
);
917 alSetError(pContext
, AL_INVALID_NAME
);
920 alSetError(pContext
, AL_INVALID_VALUE
);
922 ProcessContext(pContext
);
926 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
928 ALCcontext
*pContext
;
931 pContext
= GetContextSuspended();
932 if(!pContext
) return;
934 if(pflValue1
&& pflValue2
&& pflValue3
)
936 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
941 *pflValue1
= Source
->vPosition
[0];
942 *pflValue2
= Source
->vPosition
[1];
943 *pflValue3
= Source
->vPosition
[2];
947 *pflValue1
= Source
->vVelocity
[0];
948 *pflValue2
= Source
->vVelocity
[1];
949 *pflValue3
= Source
->vVelocity
[2];
953 *pflValue1
= Source
->vOrientation
[0];
954 *pflValue2
= Source
->vOrientation
[1];
955 *pflValue3
= Source
->vOrientation
[2];
959 alSetError(pContext
, AL_INVALID_ENUM
);
964 alSetError(pContext
, AL_INVALID_NAME
);
967 alSetError(pContext
, AL_INVALID_VALUE
);
969 ProcessContext(pContext
);
973 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
975 ALCcontext
*pContext
;
980 pContext
= GetContextSuspended();
981 if(!pContext
) return;
985 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
993 case AL_MAX_DISTANCE
:
994 case AL_ROLLOFF_FACTOR
:
995 case AL_DOPPLER_FACTOR
:
996 case AL_CONE_OUTER_GAIN
:
998 case AL_SAMPLE_OFFSET
:
1000 case AL_CONE_INNER_ANGLE
:
1001 case AL_CONE_OUTER_ANGLE
:
1002 case AL_REFERENCE_DISTANCE
:
1003 case AL_CONE_OUTER_GAINHF
:
1004 case AL_AIR_ABSORPTION_FACTOR
:
1005 case AL_ROOM_ROLLOFF_FACTOR
:
1006 alGetSourcef(source
, eParam
, pflValues
);
1012 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
1015 case AL_SAMPLE_RW_OFFSETS_EXT
:
1016 case AL_BYTE_RW_OFFSETS_EXT
:
1017 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1018 pContext
->Device
->Frequency
;
1019 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1020 pflValues
[0] = Offsets
[0];
1021 pflValues
[1] = Offsets
[1];
1025 alSetError(pContext
, AL_INVALID_ENUM
);
1030 alSetError(pContext
, AL_INVALID_NAME
);
1033 alSetError(pContext
, AL_INVALID_VALUE
);
1035 ProcessContext(pContext
);
1039 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1041 ALCcontext
*pContext
;
1043 ALdouble Offsets
[2];
1046 pContext
= GetContextSuspended();
1047 if(!pContext
) return;
1051 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1055 case AL_MAX_DISTANCE
:
1056 *plValue
= (ALint
)Source
->flMaxDistance
;
1059 case AL_ROLLOFF_FACTOR
:
1060 *plValue
= (ALint
)Source
->flRollOffFactor
;
1063 case AL_REFERENCE_DISTANCE
:
1064 *plValue
= (ALint
)Source
->flRefDistance
;
1067 case AL_SOURCE_RELATIVE
:
1068 *plValue
= Source
->bHeadRelative
;
1071 case AL_CONE_INNER_ANGLE
:
1072 *plValue
= (ALint
)Source
->flInnerAngle
;
1075 case AL_CONE_OUTER_ANGLE
:
1076 *plValue
= (ALint
)Source
->flOuterAngle
;
1080 *plValue
= Source
->bLooping
;
1084 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1087 case AL_SOURCE_STATE
:
1088 *plValue
= Source
->state
;
1091 case AL_BUFFERS_QUEUED
:
1092 *plValue
= Source
->BuffersInQueue
;
1095 case AL_BUFFERS_PROCESSED
:
1096 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1098 /* Buffers on a looping source are in a perpetual state
1099 * of PENDING, so don't report any as PROCESSED */
1103 *plValue
= Source
->BuffersPlayed
;
1106 case AL_SOURCE_TYPE
:
1107 *plValue
= Source
->lSourceType
;
1111 case AL_SAMPLE_OFFSET
:
1112 case AL_BYTE_OFFSET
:
1113 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1114 pContext
->Device
->Frequency
;
1115 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1116 *plValue
= (ALint
)Offsets
[0];
1119 case AL_DIRECT_FILTER
:
1120 *plValue
= Source
->DirectFilter
.filter
;
1123 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1124 *plValue
= Source
->DryGainHFAuto
;
1127 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1128 *plValue
= Source
->WetGainAuto
;
1131 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1132 *plValue
= Source
->WetGainHFAuto
;
1135 case AL_DOPPLER_FACTOR
:
1136 *plValue
= (ALint
)Source
->DopplerFactor
;
1139 case AL_DISTANCE_MODEL
:
1140 *plValue
= Source
->DistanceModel
;
1144 alSetError(pContext
, AL_INVALID_ENUM
);
1149 alSetError(pContext
, AL_INVALID_NAME
);
1152 alSetError(pContext
, AL_INVALID_VALUE
);
1154 ProcessContext(pContext
);
1158 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1160 ALCcontext
*pContext
;
1163 pContext
= GetContextSuspended();
1164 if(!pContext
) return;
1166 if(plValue1
&& plValue2
&& plValue3
)
1168 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1173 *plValue1
= (ALint
)Source
->vPosition
[0];
1174 *plValue2
= (ALint
)Source
->vPosition
[1];
1175 *plValue3
= (ALint
)Source
->vPosition
[2];
1179 *plValue1
= (ALint
)Source
->vVelocity
[0];
1180 *plValue2
= (ALint
)Source
->vVelocity
[1];
1181 *plValue3
= (ALint
)Source
->vVelocity
[2];
1185 *plValue1
= (ALint
)Source
->vOrientation
[0];
1186 *plValue2
= (ALint
)Source
->vOrientation
[1];
1187 *plValue3
= (ALint
)Source
->vOrientation
[2];
1191 alSetError(pContext
, AL_INVALID_ENUM
);
1196 alSetError(pContext
, AL_INVALID_NAME
);
1199 alSetError(pContext
, AL_INVALID_VALUE
);
1201 ProcessContext(pContext
);
1205 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1207 ALCcontext
*pContext
;
1209 ALdouble Offsets
[2];
1212 pContext
= GetContextSuspended();
1213 if(!pContext
) return;
1217 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1221 case AL_SOURCE_RELATIVE
:
1222 case AL_CONE_INNER_ANGLE
:
1223 case AL_CONE_OUTER_ANGLE
:
1226 case AL_SOURCE_STATE
:
1227 case AL_BUFFERS_QUEUED
:
1228 case AL_BUFFERS_PROCESSED
:
1230 case AL_SAMPLE_OFFSET
:
1231 case AL_BYTE_OFFSET
:
1232 case AL_MAX_DISTANCE
:
1233 case AL_ROLLOFF_FACTOR
:
1234 case AL_DOPPLER_FACTOR
:
1235 case AL_REFERENCE_DISTANCE
:
1236 case AL_SOURCE_TYPE
:
1237 case AL_DIRECT_FILTER
:
1238 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1239 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1240 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1241 case AL_DISTANCE_MODEL
:
1242 alGetSourcei(source
, eParam
, plValues
);
1248 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1251 case AL_SAMPLE_RW_OFFSETS_EXT
:
1252 case AL_BYTE_RW_OFFSETS_EXT
:
1253 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1254 pContext
->Device
->Frequency
;
1255 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1256 plValues
[0] = (ALint
)Offsets
[0];
1257 plValues
[1] = (ALint
)Offsets
[1];
1261 alSetError(pContext
, AL_INVALID_ENUM
);
1266 alSetError(pContext
, AL_INVALID_NAME
);
1269 alSetError(pContext
, AL_INVALID_VALUE
);
1271 ProcessContext(pContext
);
1275 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1277 alSourcePlayv(1, &source
);
1280 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1282 ALCcontext
*Context
;
1284 ALbufferlistitem
*BufferList
;
1287 Context
= GetContextSuspended();
1288 if(!Context
) return;
1292 alSetError(Context
, AL_INVALID_VALUE
);
1295 if(n
> 0 && !sources
)
1297 alSetError(Context
, AL_INVALID_VALUE
);
1301 // Check that all the Sources are valid
1302 for(i
= 0;i
< n
;i
++)
1304 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1306 alSetError(Context
, AL_INVALID_NAME
);
1311 if(Context
->ActiveSourceCount
+n
< n
)
1313 alSetError(Context
, AL_OUT_OF_MEMORY
);
1317 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
> n
)
1322 newcount
= Context
->MaxActiveSources
<< 1;
1324 temp
= realloc(Context
->ActiveSources
,
1325 sizeof(*Context
->ActiveSources
) * newcount
);
1328 alSetError(Context
, AL_OUT_OF_MEMORY
);
1332 Context
->ActiveSources
= temp
;
1333 Context
->MaxActiveSources
= newcount
;
1336 for(i
= 0;i
< n
;i
++)
1338 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1340 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1341 BufferList
= Source
->queue
;
1344 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1346 BufferList
= BufferList
->next
;
1351 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1355 if(Source
->state
!= AL_PAUSED
)
1357 Source
->state
= AL_PLAYING
;
1358 Source
->position
= 0;
1359 Source
->position_fraction
= 0;
1360 Source
->BuffersPlayed
= 0;
1362 Source
->Buffer
= Source
->queue
->buffer
;
1365 Source
->state
= AL_PLAYING
;
1367 // Check if an Offset has been set
1369 ApplyOffset(Source
);
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
);
1414 if(n
> 0 && !sources
)
1416 alSetError(Context
, AL_INVALID_VALUE
);
1420 // Check all the Sources are valid
1421 for(i
= 0;i
< n
;i
++)
1423 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1425 alSetError(Context
, AL_INVALID_NAME
);
1430 for(i
= 0;i
< n
;i
++)
1432 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1433 if(Source
->state
== AL_PLAYING
)
1434 Source
->state
= AL_PAUSED
;
1438 ProcessContext(Context
);
1441 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1443 alSourceStopv(1, &source
);
1446 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1448 ALCcontext
*Context
;
1452 Context
= GetContextSuspended();
1453 if(!Context
) return;
1457 alSetError(Context
, AL_INVALID_VALUE
);
1460 if(n
> 0 && !sources
)
1462 alSetError(Context
, AL_INVALID_VALUE
);
1466 // Check all the Sources are valid
1467 for(i
= 0;i
< n
;i
++)
1469 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1471 alSetError(Context
, AL_INVALID_NAME
);
1476 for(i
= 0;i
< n
;i
++)
1478 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1479 if(Source
->state
!= AL_INITIAL
)
1481 Source
->state
= AL_STOPPED
;
1482 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1484 Source
->lOffset
= 0;
1488 ProcessContext(Context
);
1491 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1493 alSourceRewindv(1, &source
);
1496 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1498 ALCcontext
*Context
;
1502 Context
= GetContextSuspended();
1503 if(!Context
) return;
1507 alSetError(Context
, AL_INVALID_VALUE
);
1510 if(n
> 0 && !sources
)
1512 alSetError(Context
, AL_INVALID_VALUE
);
1516 // Check all the Sources are valid
1517 for(i
= 0;i
< n
;i
++)
1519 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1521 alSetError(Context
, AL_INVALID_NAME
);
1526 for(i
= 0;i
< n
;i
++)
1528 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1529 if(Source
->state
!= AL_INITIAL
)
1531 Source
->state
= AL_INITIAL
;
1532 Source
->position
= 0;
1533 Source
->position_fraction
= 0;
1534 Source
->BuffersPlayed
= 0;
1536 Source
->Buffer
= Source
->queue
->buffer
;
1538 Source
->lOffset
= 0;
1542 ProcessContext(Context
);
1546 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1548 ALCcontext
*Context
;
1553 ALbufferlistitem
*BufferListStart
;
1554 ALbufferlistitem
*BufferList
;
1561 Context
= GetContextSuspended();
1562 if(!Context
) return;
1566 alSetError(Context
, AL_INVALID_VALUE
);
1570 // Check that all buffers are valid or zero and that the source is valid
1572 // Check that this is a valid source
1573 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1575 alSetError(Context
, AL_INVALID_NAME
);
1579 // Check that this is not a STATIC Source
1580 if(Source
->lSourceType
== AL_STATIC
)
1582 // Invalid Source Type (can't queue on a Static Source)
1583 alSetError(Context
, AL_INVALID_OPERATION
);
1587 device
= Context
->Device
;
1592 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1593 BufferList
= Source
->queue
;
1596 if(BufferList
->buffer
)
1598 Frequency
= BufferList
->buffer
->frequency
;
1599 Format
= BufferList
->buffer
->eOriginalFormat
;
1602 BufferList
= BufferList
->next
;
1605 for(i
= 0;i
< n
;i
++)
1610 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1612 alSetError(Context
, AL_INVALID_NAME
);
1616 if(Frequency
== -1 && Format
== -1)
1618 Frequency
= buffer
->frequency
;
1619 Format
= buffer
->eOriginalFormat
;
1620 if(aluChannelsFromFormat(buffer
->format
) == 1)
1621 Source
->Update
= CalcSourceParams
;
1623 Source
->Update
= CalcNonAttnSourceParams
;
1624 Source
->NeedsUpdate
= AL_TRUE
;
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
;
1682 ProcessContext(Context
);
1686 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1687 // an array of buffer IDs that are to be filled with the names of the buffers removed
1688 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1690 ALCcontext
*Context
;
1693 ALbufferlistitem
*BufferList
;
1698 Context
= GetContextSuspended();
1699 if(!Context
) return;
1703 alSetError(Context
, AL_INVALID_VALUE
);
1707 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1709 alSetError(Context
, AL_INVALID_NAME
);
1713 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1714 (ALuint
)n
> Source
->BuffersPlayed
)
1716 // Some buffers can't be unqueue because they have not been processed
1717 alSetError(Context
, AL_INVALID_VALUE
);
1721 for(i
= 0;i
< n
;i
++)
1723 BufferList
= Source
->queue
;
1724 Source
->queue
= BufferList
->next
;
1726 if(BufferList
->buffer
)
1728 // Record name of buffer
1729 buffers
[i
] = BufferList
->buffer
->buffer
;
1730 // Decrement buffer reference counter
1731 BufferList
->buffer
->refcount
--;
1736 // Release memory for buffer list item
1738 Source
->BuffersInQueue
--;
1741 if(Source
->state
!= AL_PLAYING
)
1744 Source
->Buffer
= Source
->queue
->buffer
;
1746 Source
->Buffer
= NULL
;
1748 Source
->BuffersPlayed
-= n
;
1751 ProcessContext(Context
);
1755 static ALvoid
InitSourceParams(ALsource
*Source
)
1757 Source
->flInnerAngle
= 360.0f
;
1758 Source
->flOuterAngle
= 360.0f
;
1759 Source
->flPitch
= 1.0f
;
1760 Source
->vPosition
[0] = 0.0f
;
1761 Source
->vPosition
[1] = 0.0f
;
1762 Source
->vPosition
[2] = 0.0f
;
1763 Source
->vOrientation
[0] = 0.0f
;
1764 Source
->vOrientation
[1] = 0.0f
;
1765 Source
->vOrientation
[2] = 0.0f
;
1766 Source
->vVelocity
[0] = 0.0f
;
1767 Source
->vVelocity
[1] = 0.0f
;
1768 Source
->vVelocity
[2] = 0.0f
;
1769 Source
->flRefDistance
= 1.0f
;
1770 Source
->flMaxDistance
= FLT_MAX
;
1771 Source
->flRollOffFactor
= 1.0f
;
1772 Source
->bLooping
= AL_FALSE
;
1773 Source
->flGain
= 1.0f
;
1774 Source
->flMinGain
= 0.0f
;
1775 Source
->flMaxGain
= 1.0f
;
1776 Source
->flOuterGain
= 0.0f
;
1777 Source
->OuterGainHF
= 1.0f
;
1779 Source
->DryGainHFAuto
= AL_TRUE
;
1780 Source
->WetGainAuto
= AL_TRUE
;
1781 Source
->WetGainHFAuto
= AL_TRUE
;
1782 Source
->AirAbsorptionFactor
= 0.0f
;
1783 Source
->RoomRolloffFactor
= 0.0f
;
1784 Source
->DopplerFactor
= 1.0f
;
1786 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1788 Source
->Resampler
= DefaultResampler
;
1790 Source
->state
= AL_INITIAL
;
1791 Source
->lSourceType
= AL_UNDETERMINED
;
1793 Source
->NeedsUpdate
= AL_TRUE
;
1795 Source
->Buffer
= NULL
;
1802 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1803 The offset is relative to the start of the queue (not the start of the current buffer)
1805 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1807 ALbufferlistitem
*BufferList
;
1808 ALbuffer
*Buffer
= NULL
;
1810 ALint Channels
, Bytes
;
1811 ALuint readPos
, writePos
;
1812 ALenum OriginalFormat
;
1813 ALuint TotalBufferDataSize
;
1816 // Find the first non-NULL Buffer in the Queue
1817 BufferList
= Source
->queue
;
1820 if(BufferList
->buffer
)
1822 Buffer
= BufferList
->buffer
;
1825 BufferList
= BufferList
->next
;
1828 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1835 // Get Current Buffer Size and frequency (in milliseconds)
1836 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1837 OriginalFormat
= Buffer
->eOriginalFormat
;
1838 Channels
= aluChannelsFromFormat(Buffer
->format
);
1839 Bytes
= aluBytesFromFormat(Buffer
->format
);
1841 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1842 readPos
= Source
->position
* Channels
* Bytes
;
1843 // Add byte length of any processed buffers in the queue
1844 TotalBufferDataSize
= 0;
1845 BufferList
= Source
->queue
;
1846 for(i
= 0;BufferList
;i
++)
1848 if(BufferList
->buffer
)
1850 if(i
< Source
->BuffersPlayed
)
1851 readPos
+= BufferList
->buffer
->size
;
1852 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1854 BufferList
= BufferList
->next
;
1856 if(Source
->state
== AL_PLAYING
)
1857 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1861 if(Source
->bLooping
)
1863 readPos
%= TotalBufferDataSize
;
1864 writePos
%= TotalBufferDataSize
;
1868 // Clamp positions to TotalBufferDataSize
1869 if(readPos
> TotalBufferDataSize
)
1870 readPos
= TotalBufferDataSize
;
1871 if(writePos
> TotalBufferDataSize
)
1872 writePos
= TotalBufferDataSize
;
1878 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1879 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1881 case AL_SAMPLE_OFFSET
:
1882 case AL_SAMPLE_RW_OFFSETS_EXT
:
1883 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1884 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1886 case AL_BYTE_OFFSET
:
1887 case AL_BYTE_RW_OFFSETS_EXT
:
1888 // Take into account the original format of the Buffer
1889 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1890 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1892 // Round down to nearest ADPCM block
1893 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1894 if(Source
->state
== AL_PLAYING
)
1896 // Round up to nearest ADPCM block
1897 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1900 offset
[1] = offset
[0];
1902 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1903 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1904 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1905 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1906 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1907 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1909 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1910 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1912 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1914 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1915 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1917 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1919 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1920 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1922 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1924 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1925 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1927 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1929 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1930 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1934 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1935 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1936 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1946 Apply a playback offset to the Source. This function will update the queue (to correctly
1947 mark buffers as 'pending' or 'processed' depending upon the new offset.
1949 static ALboolean
ApplyOffset(ALsource
*Source
)
1951 ALbufferlistitem
*BufferList
;
1953 ALint lBufferSize
, lTotalBufferSize
;
1954 ALint BuffersPlayed
;
1957 // Get true byte offset
1958 lByteOffset
= GetByteOffset(Source
);
1960 // If the offset is invalid, don't apply it
1961 if(lByteOffset
== -1)
1964 // Sort out the queue (pending and processed states)
1965 BufferList
= Source
->queue
;
1966 lTotalBufferSize
= 0;
1971 Buffer
= BufferList
->buffer
;
1972 lBufferSize
= Buffer
? Buffer
->size
: 0;
1974 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1976 // Offset is past this buffer so increment BuffersPlayed
1979 else if(lTotalBufferSize
<= lByteOffset
)
1981 // Offset is within this buffer
1982 // Set Current Buffer
1983 Source
->Buffer
= BufferList
->buffer
;
1984 Source
->BuffersPlayed
= BuffersPlayed
;
1986 // SW Mixer Positions are in Samples
1987 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1988 aluFrameSizeFromFormat(Buffer
->format
);
1992 // Increment the TotalBufferSize
1993 lTotalBufferSize
+= lBufferSize
;
1995 // Move on to next buffer in the Queue
1996 BufferList
= BufferList
->next
;
1998 // Offset is out of range of the buffer queue
2006 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2007 offset supplied by the application). This takes into account the fact that the buffer format
2008 may have been modifed by AL (e.g 8bit samples are converted to float)
2010 static ALint
GetByteOffset(ALsource
*Source
)
2012 ALbuffer
*Buffer
= NULL
;
2013 ALbufferlistitem
*BufferList
;
2015 ALint Channels
, Bytes
;
2016 ALint ByteOffset
= -1;
2018 // Find the first non-NULL Buffer in the Queue
2019 BufferList
= Source
->queue
;
2022 if(BufferList
->buffer
)
2024 Buffer
= BufferList
->buffer
;
2027 BufferList
= BufferList
->next
;
2032 Source
->lOffset
= 0;
2036 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
2037 Channels
= aluChannelsFromFormat(Buffer
->format
);
2038 Bytes
= aluBytesFromFormat(Buffer
->format
);
2040 // Determine the ByteOffset (and ensure it is block aligned)
2041 switch(Source
->lOffsetType
)
2043 case AL_BYTE_OFFSET
:
2044 // Take into consideration the original format
2045 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2047 ByteOffset
*= Channels
* Bytes
;
2050 case AL_SAMPLE_OFFSET
:
2051 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2055 // Note - lOffset is internally stored as Milliseconds
2056 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2057 ByteOffset
*= Channels
* Bytes
;
2061 Source
->lOffset
= 0;
2066 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2068 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2070 // Round down to nearest ADPCM block
2071 offset
/= 36 * channels
;
2072 // Multiply by compression rate (65 sample frames per block)
2075 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2076 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2077 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2079 /* muLaw has 1 byte per sample */
2080 offset
/= 1 * channels
;
2082 else if(format
== AL_FORMAT_REAR_MULAW
)
2084 /* Rear is 2 channels */
2087 else if(format
== AL_FORMAT_REAR8
)
2089 else if(format
== AL_FORMAT_REAR16
)
2091 else if(format
== AL_FORMAT_REAR32
)
2095 ALuint bytes
= aluBytesFromFormat(format
);
2096 offset
/= bytes
* channels
;
2102 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2106 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2108 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2109 Context
->SourceMap
.array
[pos
].value
= NULL
;
2111 // For each buffer in the source's queue, decrement its reference counter and remove it
2112 while(temp
->queue
!= NULL
)
2114 ALbufferlistitem
*BufferList
= temp
->queue
;
2115 // Decrement buffer's reference counter
2116 if(BufferList
->buffer
!= NULL
)
2117 BufferList
->buffer
->refcount
--;
2118 // Update queue to point to next element in list
2119 temp
->queue
= BufferList
->next
;
2120 // Release memory allocated for buffer list item
2124 for(j
= 0;j
< MAX_SENDS
;++j
)
2126 if(temp
->Send
[j
].Slot
)
2127 temp
->Send
[j
].Slot
->refcount
--;
2130 // Release source structure
2131 ALTHUNK_REMOVEENTRY(temp
->source
);
2132 memset(temp
, 0, sizeof(ALsource
));