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_SOFT
:
1016 case AL_BYTE_RW_OFFSETS_SOFT
:
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_SOFT
:
1252 case AL_BYTE_RW_OFFSETS_SOFT
:
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 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1316 newcount
= Context
->MaxActiveSources
<< 1;
1318 temp
= realloc(Context
->ActiveSources
,
1319 sizeof(*Context
->ActiveSources
) * newcount
);
1322 alSetError(Context
, AL_OUT_OF_MEMORY
);
1326 Context
->ActiveSources
= temp
;
1327 Context
->MaxActiveSources
= newcount
;
1330 for(i
= 0;i
< n
;i
++)
1332 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1334 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1335 BufferList
= Source
->queue
;
1338 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1340 BufferList
= BufferList
->next
;
1345 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1349 if(Source
->state
!= AL_PAUSED
)
1351 Source
->state
= AL_PLAYING
;
1352 Source
->position
= 0;
1353 Source
->position_fraction
= 0;
1354 Source
->BuffersPlayed
= 0;
1356 Source
->Buffer
= Source
->queue
->buffer
;
1359 Source
->state
= AL_PLAYING
;
1361 // Check if an Offset has been set
1363 ApplyOffset(Source
);
1365 // If device is disconnected, go right to stopped
1366 if(!Context
->Device
->Connected
)
1368 Source
->state
= AL_STOPPED
;
1369 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1370 Source
->position
= 0;
1371 Source
->position_fraction
= 0;
1375 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1377 if(Context
->ActiveSources
[j
] == Source
)
1380 if(j
== Context
->ActiveSourceCount
)
1381 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1386 ProcessContext(Context
);
1389 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1391 alSourcePausev(1, &source
);
1394 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1396 ALCcontext
*Context
;
1400 Context
= GetContextSuspended();
1401 if(!Context
) return;
1405 alSetError(Context
, AL_INVALID_VALUE
);
1408 if(n
> 0 && !sources
)
1410 alSetError(Context
, AL_INVALID_VALUE
);
1414 // Check all the Sources are valid
1415 for(i
= 0;i
< n
;i
++)
1417 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1419 alSetError(Context
, AL_INVALID_NAME
);
1424 for(i
= 0;i
< n
;i
++)
1426 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1427 if(Source
->state
== AL_PLAYING
)
1428 Source
->state
= AL_PAUSED
;
1432 ProcessContext(Context
);
1435 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1437 alSourceStopv(1, &source
);
1440 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1442 ALCcontext
*Context
;
1446 Context
= GetContextSuspended();
1447 if(!Context
) return;
1451 alSetError(Context
, AL_INVALID_VALUE
);
1454 if(n
> 0 && !sources
)
1456 alSetError(Context
, AL_INVALID_VALUE
);
1460 // Check all the Sources are valid
1461 for(i
= 0;i
< n
;i
++)
1463 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1465 alSetError(Context
, AL_INVALID_NAME
);
1470 for(i
= 0;i
< n
;i
++)
1472 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1473 if(Source
->state
!= AL_INITIAL
)
1475 Source
->state
= AL_STOPPED
;
1476 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1478 Source
->lOffset
= 0;
1482 ProcessContext(Context
);
1485 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1487 alSourceRewindv(1, &source
);
1490 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1492 ALCcontext
*Context
;
1496 Context
= GetContextSuspended();
1497 if(!Context
) return;
1501 alSetError(Context
, AL_INVALID_VALUE
);
1504 if(n
> 0 && !sources
)
1506 alSetError(Context
, AL_INVALID_VALUE
);
1510 // Check all the Sources are valid
1511 for(i
= 0;i
< n
;i
++)
1513 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1515 alSetError(Context
, AL_INVALID_NAME
);
1520 for(i
= 0;i
< n
;i
++)
1522 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1523 if(Source
->state
!= AL_INITIAL
)
1525 Source
->state
= AL_INITIAL
;
1526 Source
->position
= 0;
1527 Source
->position_fraction
= 0;
1528 Source
->BuffersPlayed
= 0;
1530 Source
->Buffer
= Source
->queue
->buffer
;
1532 Source
->lOffset
= 0;
1536 ProcessContext(Context
);
1540 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1542 ALCcontext
*Context
;
1547 ALbufferlistitem
*BufferListStart
;
1548 ALbufferlistitem
*BufferList
;
1555 Context
= GetContextSuspended();
1556 if(!Context
) return;
1560 alSetError(Context
, AL_INVALID_VALUE
);
1564 // Check that all buffers are valid or zero and that the source is valid
1566 // Check that this is a valid source
1567 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1569 alSetError(Context
, AL_INVALID_NAME
);
1573 // Check that this is not a STATIC Source
1574 if(Source
->lSourceType
== AL_STATIC
)
1576 // Invalid Source Type (can't queue on a Static Source)
1577 alSetError(Context
, AL_INVALID_OPERATION
);
1581 device
= Context
->Device
;
1586 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1587 BufferList
= Source
->queue
;
1590 if(BufferList
->buffer
)
1592 Frequency
= BufferList
->buffer
->frequency
;
1593 Format
= BufferList
->buffer
->eOriginalFormat
;
1596 BufferList
= BufferList
->next
;
1599 for(i
= 0;i
< n
;i
++)
1604 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1606 alSetError(Context
, AL_INVALID_NAME
);
1610 if(Frequency
== -1 && Format
== -1)
1612 Frequency
= buffer
->frequency
;
1613 Format
= buffer
->eOriginalFormat
;
1614 if(aluChannelsFromFormat(buffer
->format
) == 1)
1615 Source
->Update
= CalcSourceParams
;
1617 Source
->Update
= CalcNonAttnSourceParams
;
1618 Source
->NeedsUpdate
= AL_TRUE
;
1620 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->eOriginalFormat
)
1622 alSetError(Context
, AL_INVALID_OPERATION
);
1627 // Change Source Type
1628 Source
->lSourceType
= AL_STREAMING
;
1630 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1632 // All buffers are valid - so add them to the list
1633 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1634 BufferListStart
->buffer
= buffer
;
1635 BufferListStart
->next
= NULL
;
1637 // Increment reference counter for buffer
1638 if(buffer
) buffer
->refcount
++;
1640 BufferList
= BufferListStart
;
1642 for(i
= 1;i
< n
;i
++)
1644 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1646 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1647 BufferList
->next
->buffer
= buffer
;
1648 BufferList
->next
->next
= NULL
;
1650 // Increment reference counter for buffer
1651 if(buffer
) buffer
->refcount
++;
1653 BufferList
= BufferList
->next
;
1656 if(Source
->queue
== NULL
)
1658 Source
->queue
= BufferListStart
;
1659 // Update Current Buffer
1660 Source
->Buffer
= BufferListStart
->buffer
;
1664 // Find end of queue
1665 BufferList
= Source
->queue
;
1666 while(BufferList
->next
!= NULL
)
1667 BufferList
= BufferList
->next
;
1669 BufferList
->next
= BufferListStart
;
1672 // Update number of buffers in queue
1673 Source
->BuffersInQueue
+= n
;
1676 ProcessContext(Context
);
1680 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1681 // an array of buffer IDs that are to be filled with the names of the buffers removed
1682 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1684 ALCcontext
*Context
;
1687 ALbufferlistitem
*BufferList
;
1692 Context
= GetContextSuspended();
1693 if(!Context
) return;
1697 alSetError(Context
, AL_INVALID_VALUE
);
1701 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1703 alSetError(Context
, AL_INVALID_NAME
);
1707 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1708 (ALuint
)n
> Source
->BuffersPlayed
)
1710 // Some buffers can't be unqueue because they have not been processed
1711 alSetError(Context
, AL_INVALID_VALUE
);
1715 for(i
= 0;i
< n
;i
++)
1717 BufferList
= Source
->queue
;
1718 Source
->queue
= BufferList
->next
;
1720 if(BufferList
->buffer
)
1722 // Record name of buffer
1723 buffers
[i
] = BufferList
->buffer
->buffer
;
1724 // Decrement buffer reference counter
1725 BufferList
->buffer
->refcount
--;
1730 // Release memory for buffer list item
1732 Source
->BuffersInQueue
--;
1735 if(Source
->state
!= AL_PLAYING
)
1738 Source
->Buffer
= Source
->queue
->buffer
;
1740 Source
->Buffer
= NULL
;
1742 Source
->BuffersPlayed
-= n
;
1745 ProcessContext(Context
);
1749 static ALvoid
InitSourceParams(ALsource
*Source
)
1751 Source
->flInnerAngle
= 360.0f
;
1752 Source
->flOuterAngle
= 360.0f
;
1753 Source
->flPitch
= 1.0f
;
1754 Source
->vPosition
[0] = 0.0f
;
1755 Source
->vPosition
[1] = 0.0f
;
1756 Source
->vPosition
[2] = 0.0f
;
1757 Source
->vOrientation
[0] = 0.0f
;
1758 Source
->vOrientation
[1] = 0.0f
;
1759 Source
->vOrientation
[2] = 0.0f
;
1760 Source
->vVelocity
[0] = 0.0f
;
1761 Source
->vVelocity
[1] = 0.0f
;
1762 Source
->vVelocity
[2] = 0.0f
;
1763 Source
->flRefDistance
= 1.0f
;
1764 Source
->flMaxDistance
= FLT_MAX
;
1765 Source
->flRollOffFactor
= 1.0f
;
1766 Source
->bLooping
= AL_FALSE
;
1767 Source
->flGain
= 1.0f
;
1768 Source
->flMinGain
= 0.0f
;
1769 Source
->flMaxGain
= 1.0f
;
1770 Source
->flOuterGain
= 0.0f
;
1771 Source
->OuterGainHF
= 1.0f
;
1773 Source
->DryGainHFAuto
= AL_TRUE
;
1774 Source
->WetGainAuto
= AL_TRUE
;
1775 Source
->WetGainHFAuto
= AL_TRUE
;
1776 Source
->AirAbsorptionFactor
= 0.0f
;
1777 Source
->RoomRolloffFactor
= 0.0f
;
1778 Source
->DopplerFactor
= 1.0f
;
1780 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1782 Source
->Resampler
= DefaultResampler
;
1784 Source
->state
= AL_INITIAL
;
1785 Source
->lSourceType
= AL_UNDETERMINED
;
1787 Source
->NeedsUpdate
= AL_TRUE
;
1789 Source
->Buffer
= NULL
;
1796 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1797 The offset is relative to the start of the queue (not the start of the current buffer)
1799 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1801 ALbufferlistitem
*BufferList
;
1802 ALbuffer
*Buffer
= NULL
;
1804 ALint Channels
, Bytes
;
1805 ALuint readPos
, writePos
;
1806 ALenum OriginalFormat
;
1807 ALuint TotalBufferDataSize
;
1810 // Find the first non-NULL Buffer in the Queue
1811 BufferList
= Source
->queue
;
1814 if(BufferList
->buffer
)
1816 Buffer
= BufferList
->buffer
;
1819 BufferList
= BufferList
->next
;
1822 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1829 // Get Current Buffer Size and frequency (in milliseconds)
1830 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1831 OriginalFormat
= Buffer
->eOriginalFormat
;
1832 Channels
= aluChannelsFromFormat(Buffer
->format
);
1833 Bytes
= aluBytesFromFormat(Buffer
->format
);
1835 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1836 readPos
= Source
->position
* Channels
* Bytes
;
1837 // Add byte length of any processed buffers in the queue
1838 TotalBufferDataSize
= 0;
1839 BufferList
= Source
->queue
;
1840 for(i
= 0;BufferList
;i
++)
1842 if(BufferList
->buffer
)
1844 if(i
< Source
->BuffersPlayed
)
1845 readPos
+= BufferList
->buffer
->size
;
1846 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1848 BufferList
= BufferList
->next
;
1850 if(Source
->state
== AL_PLAYING
)
1851 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1855 if(Source
->bLooping
)
1857 readPos
%= TotalBufferDataSize
;
1858 writePos
%= TotalBufferDataSize
;
1862 // Wrap positions back to 0
1863 if(readPos
>= TotalBufferDataSize
)
1865 if(writePos
>= TotalBufferDataSize
)
1872 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1873 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1875 case AL_SAMPLE_OFFSET
:
1876 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1877 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1878 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1880 case AL_BYTE_OFFSET
:
1881 case AL_BYTE_RW_OFFSETS_SOFT
:
1882 // Take into account the original format of the Buffer
1883 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1884 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1886 // Round down to nearest ADPCM block
1887 offset
[0] = (ALdouble
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1888 if(Source
->state
== AL_PLAYING
)
1890 // Round up to nearest ADPCM block
1891 offset
[1] = (ALdouble
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1894 offset
[1] = offset
[0];
1896 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1897 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1898 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1899 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1900 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1901 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1903 offset
[0] = (ALdouble
)(readPos
/ Bytes
* 1);
1904 offset
[1] = (ALdouble
)(writePos
/ Bytes
* 1);
1906 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1908 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1909 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1911 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1913 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 1);
1914 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 1);
1916 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1918 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 2);
1919 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 2);
1921 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1923 offset
[0] = (ALdouble
)(readPos
/ 2 / Bytes
* 4);
1924 offset
[1] = (ALdouble
)(writePos
/ 2 / Bytes
* 4);
1928 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1929 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1930 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1940 Apply a playback offset to the Source. This function will update the queue (to correctly
1941 mark buffers as 'pending' or 'processed' depending upon the new offset.
1943 static ALboolean
ApplyOffset(ALsource
*Source
)
1945 ALbufferlistitem
*BufferList
;
1947 ALint lBufferSize
, lTotalBufferSize
;
1948 ALint BuffersPlayed
;
1951 // Get true byte offset
1952 lByteOffset
= GetByteOffset(Source
);
1954 // If the offset is invalid, don't apply it
1955 if(lByteOffset
== -1)
1958 // Sort out the queue (pending and processed states)
1959 BufferList
= Source
->queue
;
1960 lTotalBufferSize
= 0;
1965 Buffer
= BufferList
->buffer
;
1966 lBufferSize
= Buffer
? Buffer
->size
: 0;
1968 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1970 // Offset is past this buffer so increment BuffersPlayed
1973 else if(lTotalBufferSize
<= lByteOffset
)
1975 // Offset is within this buffer
1976 // Set Current Buffer
1977 Source
->Buffer
= BufferList
->buffer
;
1978 Source
->BuffersPlayed
= BuffersPlayed
;
1980 // SW Mixer Positions are in Samples
1981 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1982 aluFrameSizeFromFormat(Buffer
->format
);
1986 // Increment the TotalBufferSize
1987 lTotalBufferSize
+= lBufferSize
;
1989 // Move on to next buffer in the Queue
1990 BufferList
= BufferList
->next
;
1992 // Offset is out of range of the buffer queue
2000 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2001 offset supplied by the application). This takes into account the fact that the buffer format
2002 may have been modifed by AL (e.g 8bit samples are converted to float)
2004 static ALint
GetByteOffset(ALsource
*Source
)
2006 ALbuffer
*Buffer
= NULL
;
2007 ALbufferlistitem
*BufferList
;
2009 ALint Channels
, Bytes
;
2010 ALint ByteOffset
= -1;
2012 // Find the first non-NULL Buffer in the Queue
2013 BufferList
= Source
->queue
;
2016 if(BufferList
->buffer
)
2018 Buffer
= BufferList
->buffer
;
2021 BufferList
= BufferList
->next
;
2026 Source
->lOffset
= 0;
2030 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
2031 Channels
= aluChannelsFromFormat(Buffer
->format
);
2032 Bytes
= aluBytesFromFormat(Buffer
->format
);
2034 // Determine the ByteOffset (and ensure it is block aligned)
2035 switch(Source
->lOffsetType
)
2037 case AL_BYTE_OFFSET
:
2038 // Take into consideration the original format
2039 ByteOffset
= FramesFromBytes(Source
->lOffset
, Buffer
->eOriginalFormat
,
2041 ByteOffset
*= Channels
* Bytes
;
2044 case AL_SAMPLE_OFFSET
:
2045 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2049 // Note - lOffset is internally stored as Milliseconds
2050 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2051 ByteOffset
*= Channels
* Bytes
;
2055 Source
->lOffset
= 0;
2060 static ALint
FramesFromBytes(ALint offset
, ALenum format
, ALint channels
)
2062 if(format
==AL_FORMAT_MONO_IMA4
|| format
==AL_FORMAT_STEREO_IMA4
)
2064 // Round down to nearest ADPCM block
2065 offset
/= 36 * channels
;
2066 // Multiply by compression rate (65 sample frames per block)
2069 else if(format
==AL_FORMAT_MONO_MULAW
|| format
==AL_FORMAT_STEREO_MULAW
||
2070 format
==AL_FORMAT_QUAD_MULAW
|| format
==AL_FORMAT_51CHN_MULAW
||
2071 format
==AL_FORMAT_61CHN_MULAW
|| format
==AL_FORMAT_71CHN_MULAW
)
2073 /* muLaw has 1 byte per sample */
2074 offset
/= 1 * channels
;
2076 else if(format
== AL_FORMAT_REAR_MULAW
)
2078 /* Rear is 2 channels */
2081 else if(format
== AL_FORMAT_REAR8
)
2083 else if(format
== AL_FORMAT_REAR16
)
2085 else if(format
== AL_FORMAT_REAR32
)
2089 ALuint bytes
= aluBytesFromFormat(format
);
2090 offset
/= bytes
* channels
;
2096 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2100 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2102 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2103 Context
->SourceMap
.array
[pos
].value
= NULL
;
2105 // For each buffer in the source's queue, decrement its reference counter and remove it
2106 while(temp
->queue
!= NULL
)
2108 ALbufferlistitem
*BufferList
= temp
->queue
;
2109 // Decrement buffer's reference counter
2110 if(BufferList
->buffer
!= NULL
)
2111 BufferList
->buffer
->refcount
--;
2112 // Update queue to point to next element in list
2113 temp
->queue
= BufferList
->next
;
2114 // Release memory allocated for buffer list item
2118 for(j
= 0;j
< MAX_SENDS
;++j
)
2120 if(temp
->Send
[j
].Slot
)
2121 temp
->Send
[j
].Slot
->refcount
--;
2124 // Release source structure
2125 ALTHUNK_REMOVEENTRY(temp
->source
);
2126 memset(temp
, 0, sizeof(ALsource
));