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 if(Source
->flPitch
< 0.001f
)
223 Source
->flPitch
= 0.001f
;
224 Source
->NeedsUpdate
= AL_TRUE
;
227 alSetError(pContext
, AL_INVALID_VALUE
);
230 case AL_CONE_INNER_ANGLE
:
231 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
233 Source
->flInnerAngle
= flValue
;
234 Source
->NeedsUpdate
= AL_TRUE
;
237 alSetError(pContext
, AL_INVALID_VALUE
);
240 case AL_CONE_OUTER_ANGLE
:
241 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
243 Source
->flOuterAngle
= flValue
;
244 Source
->NeedsUpdate
= AL_TRUE
;
247 alSetError(pContext
, AL_INVALID_VALUE
);
253 Source
->flGain
= flValue
;
254 Source
->NeedsUpdate
= AL_TRUE
;
257 alSetError(pContext
, AL_INVALID_VALUE
);
260 case AL_MAX_DISTANCE
:
263 Source
->flMaxDistance
= flValue
;
264 Source
->NeedsUpdate
= AL_TRUE
;
267 alSetError(pContext
, AL_INVALID_VALUE
);
270 case AL_ROLLOFF_FACTOR
:
273 Source
->flRollOffFactor
= flValue
;
274 Source
->NeedsUpdate
= AL_TRUE
;
277 alSetError(pContext
, AL_INVALID_VALUE
);
280 case AL_REFERENCE_DISTANCE
:
283 Source
->flRefDistance
= flValue
;
284 Source
->NeedsUpdate
= AL_TRUE
;
287 alSetError(pContext
, AL_INVALID_VALUE
);
291 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
293 Source
->flMinGain
= flValue
;
294 Source
->NeedsUpdate
= AL_TRUE
;
297 alSetError(pContext
, AL_INVALID_VALUE
);
301 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
303 Source
->flMaxGain
= flValue
;
304 Source
->NeedsUpdate
= AL_TRUE
;
307 alSetError(pContext
, AL_INVALID_VALUE
);
310 case AL_CONE_OUTER_GAIN
:
311 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
313 Source
->flOuterGain
= flValue
;
314 Source
->NeedsUpdate
= AL_TRUE
;
317 alSetError(pContext
, AL_INVALID_VALUE
);
320 case AL_CONE_OUTER_GAINHF
:
321 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
323 Source
->OuterGainHF
= flValue
;
324 Source
->NeedsUpdate
= AL_TRUE
;
327 alSetError(pContext
, AL_INVALID_VALUE
);
330 case AL_AIR_ABSORPTION_FACTOR
:
331 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
333 Source
->AirAbsorptionFactor
= flValue
;
334 Source
->NeedsUpdate
= AL_TRUE
;
337 alSetError(pContext
, AL_INVALID_VALUE
);
340 case AL_ROOM_ROLLOFF_FACTOR
:
341 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
343 Source
->RoomRolloffFactor
= flValue
;
344 Source
->NeedsUpdate
= AL_TRUE
;
347 alSetError(pContext
, AL_INVALID_VALUE
);
350 case AL_DOPPLER_FACTOR
:
351 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
353 Source
->DopplerFactor
= flValue
;
354 Source
->NeedsUpdate
= AL_TRUE
;
357 alSetError(pContext
, AL_INVALID_VALUE
);
361 case AL_SAMPLE_OFFSET
:
365 Source
->lOffsetType
= eParam
;
367 // Store Offset (convert Seconds into Milliseconds)
368 if(eParam
== AL_SEC_OFFSET
)
369 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
371 Source
->lOffset
= (ALint
)flValue
;
373 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
375 if(ApplyOffset(Source
) == AL_FALSE
)
376 alSetError(pContext
, AL_INVALID_VALUE
);
380 alSetError(pContext
, AL_INVALID_VALUE
);
384 alSetError(pContext
, AL_INVALID_ENUM
);
390 // Invalid Source Name
391 alSetError(pContext
, AL_INVALID_NAME
);
394 ProcessContext(pContext
);
398 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
400 ALCcontext
*pContext
;
403 pContext
= GetContextSuspended();
404 if(!pContext
) return;
406 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
411 Source
->vPosition
[0] = flValue1
;
412 Source
->vPosition
[1] = flValue2
;
413 Source
->vPosition
[2] = flValue3
;
414 Source
->NeedsUpdate
= AL_TRUE
;
418 Source
->vVelocity
[0] = flValue1
;
419 Source
->vVelocity
[1] = flValue2
;
420 Source
->vVelocity
[2] = flValue3
;
421 Source
->NeedsUpdate
= AL_TRUE
;
425 Source
->vOrientation
[0] = flValue1
;
426 Source
->vOrientation
[1] = flValue2
;
427 Source
->vOrientation
[2] = flValue3
;
428 Source
->NeedsUpdate
= AL_TRUE
;
432 alSetError(pContext
, AL_INVALID_ENUM
);
437 alSetError(pContext
, AL_INVALID_NAME
);
439 ProcessContext(pContext
);
443 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
445 ALCcontext
*pContext
;
447 pContext
= GetContextSuspended();
448 if(!pContext
) return;
452 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
457 case AL_CONE_INNER_ANGLE
:
458 case AL_CONE_OUTER_ANGLE
:
460 case AL_MAX_DISTANCE
:
461 case AL_ROLLOFF_FACTOR
:
462 case AL_REFERENCE_DISTANCE
:
465 case AL_CONE_OUTER_GAIN
:
466 case AL_CONE_OUTER_GAINHF
:
468 case AL_SAMPLE_OFFSET
:
470 case AL_AIR_ABSORPTION_FACTOR
:
471 case AL_ROOM_ROLLOFF_FACTOR
:
472 alSourcef(source
, eParam
, pflValues
[0]);
478 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
482 alSetError(pContext
, AL_INVALID_ENUM
);
487 alSetError(pContext
, AL_INVALID_NAME
);
490 alSetError(pContext
, AL_INVALID_VALUE
);
492 ProcessContext(pContext
);
496 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
498 ALCcontext
*pContext
;
500 ALbufferlistitem
*BufferListItem
;
502 pContext
= GetContextSuspended();
503 if(!pContext
) return;
505 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
507 ALCdevice
*device
= pContext
->Device
;
511 case AL_MAX_DISTANCE
:
512 case AL_ROLLOFF_FACTOR
:
513 case AL_CONE_INNER_ANGLE
:
514 case AL_CONE_OUTER_ANGLE
:
515 case AL_REFERENCE_DISTANCE
:
516 alSourcef(source
, eParam
, (ALfloat
)lValue
);
519 case AL_SOURCE_RELATIVE
:
520 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
522 Source
->bHeadRelative
= (ALboolean
)lValue
;
523 Source
->NeedsUpdate
= AL_TRUE
;
526 alSetError(pContext
, AL_INVALID_VALUE
);
530 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
531 Source
->bLooping
= (ALboolean
)lValue
;
533 alSetError(pContext
, AL_INVALID_VALUE
);
537 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
539 ALbuffer
*buffer
= NULL
;
542 (buffer
=LookupBuffer(device
->BufferMap
, lValue
)) != NULL
)
544 // Remove all elements in the queue
545 while(Source
->queue
!= NULL
)
547 BufferListItem
= Source
->queue
;
548 Source
->queue
= BufferListItem
->next
;
550 if(BufferListItem
->buffer
)
551 BufferListItem
->buffer
->refcount
--;
552 free(BufferListItem
);
554 Source
->BuffersInQueue
= 0;
556 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
559 // Source is now in STATIC mode
560 Source
->lSourceType
= AL_STATIC
;
562 // Add the selected buffer to the queue
563 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
564 BufferListItem
->buffer
= buffer
;
565 BufferListItem
->next
= NULL
;
566 BufferListItem
->prev
= NULL
;
568 Source
->queue
= BufferListItem
;
569 Source
->BuffersInQueue
= 1;
571 if(buffer
->FmtChannels
== FmtMono
)
572 Source
->Update
= CalcSourceParams
;
574 Source
->Update
= CalcNonAttnSourceParams
;
576 // Increment reference counter for buffer
581 // Source is now in UNDETERMINED mode
582 Source
->lSourceType
= AL_UNDETERMINED
;
584 Source
->BuffersPlayed
= 0;
586 // Update AL_BUFFER parameter
587 Source
->Buffer
= buffer
;
588 Source
->NeedsUpdate
= AL_TRUE
;
591 alSetError(pContext
, AL_INVALID_VALUE
);
594 alSetError(pContext
, AL_INVALID_OPERATION
);
597 case AL_SOURCE_STATE
:
599 alSetError(pContext
, AL_INVALID_OPERATION
);
603 case AL_SAMPLE_OFFSET
:
607 Source
->lOffsetType
= eParam
;
609 // Store Offset (convert Seconds into Milliseconds)
610 if(eParam
== AL_SEC_OFFSET
)
611 Source
->lOffset
= lValue
* 1000;
613 Source
->lOffset
= lValue
;
615 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
617 if(ApplyOffset(Source
) == AL_FALSE
)
618 alSetError(pContext
, AL_INVALID_VALUE
);
622 alSetError(pContext
, AL_INVALID_VALUE
);
625 case AL_DIRECT_FILTER
: {
626 ALfilter
*filter
= NULL
;
629 (filter
=LookupFilter(pContext
->Device
->FilterMap
, lValue
)) != NULL
)
633 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
634 Source
->DirectFilter
.filter
= 0;
637 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
638 Source
->NeedsUpdate
= AL_TRUE
;
641 alSetError(pContext
, AL_INVALID_VALUE
);
644 case AL_DIRECT_FILTER_GAINHF_AUTO
:
645 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
647 Source
->DryGainHFAuto
= lValue
;
648 Source
->NeedsUpdate
= AL_TRUE
;
651 alSetError(pContext
, AL_INVALID_VALUE
);
654 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
655 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
657 Source
->WetGainAuto
= lValue
;
658 Source
->NeedsUpdate
= AL_TRUE
;
661 alSetError(pContext
, AL_INVALID_VALUE
);
664 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
665 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
667 Source
->WetGainHFAuto
= lValue
;
668 Source
->NeedsUpdate
= AL_TRUE
;
671 alSetError(pContext
, AL_INVALID_VALUE
);
674 case AL_DISTANCE_MODEL
:
675 if(lValue
== AL_NONE
||
676 lValue
== AL_INVERSE_DISTANCE
||
677 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
678 lValue
== AL_LINEAR_DISTANCE
||
679 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
680 lValue
== AL_EXPONENT_DISTANCE
||
681 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
683 Source
->DistanceModel
= lValue
;
684 if(pContext
->SourceDistanceModel
)
685 Source
->NeedsUpdate
= AL_TRUE
;
688 alSetError(pContext
, AL_INVALID_VALUE
);
692 alSetError(pContext
, AL_INVALID_ENUM
);
697 alSetError(pContext
, AL_INVALID_NAME
);
699 ProcessContext(pContext
);
703 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
705 ALCcontext
*pContext
;
708 pContext
= GetContextSuspended();
709 if(!pContext
) return;
711 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
713 ALCdevice
*device
= pContext
->Device
;
720 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
723 case AL_AUXILIARY_SEND_FILTER
: {
724 ALeffectslot
*ALEffectSlot
= NULL
;
725 ALfilter
*ALFilter
= NULL
;
727 if((ALuint
)lValue2
< device
->NumAuxSends
&&
729 (ALEffectSlot
=LookupEffectSlot(pContext
->EffectSlotMap
, lValue1
)) != NULL
) &&
731 (ALFilter
=LookupFilter(device
->FilterMap
, lValue3
)) != NULL
))
733 /* Release refcount on the previous slot, and add one for
735 if(Source
->Send
[lValue2
].Slot
)
736 Source
->Send
[lValue2
].Slot
->refcount
--;
737 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
738 if(Source
->Send
[lValue2
].Slot
)
739 Source
->Send
[lValue2
].Slot
->refcount
++;
744 Source
->Send
[lValue2
].WetFilter
.type
= 0;
745 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
748 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
749 Source
->NeedsUpdate
= AL_TRUE
;
752 alSetError(pContext
, AL_INVALID_VALUE
);
756 alSetError(pContext
, AL_INVALID_ENUM
);
761 alSetError(pContext
, AL_INVALID_NAME
);
763 ProcessContext(pContext
);
767 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
769 ALCcontext
*pContext
;
771 pContext
= GetContextSuspended();
772 if(!pContext
) return;
776 if(LookupSource(pContext
->SourceMap
, source
) != NULL
)
780 case AL_SOURCE_RELATIVE
:
781 case AL_CONE_INNER_ANGLE
:
782 case AL_CONE_OUTER_ANGLE
:
785 case AL_SOURCE_STATE
:
787 case AL_SAMPLE_OFFSET
:
789 case AL_MAX_DISTANCE
:
790 case AL_ROLLOFF_FACTOR
:
791 case AL_REFERENCE_DISTANCE
:
792 case AL_DIRECT_FILTER
:
793 case AL_DIRECT_FILTER_GAINHF_AUTO
:
794 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
795 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
796 case AL_DISTANCE_MODEL
:
797 alSourcei(source
, eParam
, plValues
[0]);
803 case AL_AUXILIARY_SEND_FILTER
:
804 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
808 alSetError(pContext
, AL_INVALID_ENUM
);
813 alSetError(pContext
, AL_INVALID_NAME
);
816 alSetError(pContext
, AL_INVALID_VALUE
);
818 ProcessContext(pContext
);
822 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
824 ALCcontext
*pContext
;
829 pContext
= GetContextSuspended();
830 if(!pContext
) return;
834 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
839 *pflValue
= Source
->flPitch
;
843 *pflValue
= Source
->flGain
;
847 *pflValue
= Source
->flMinGain
;
851 *pflValue
= Source
->flMaxGain
;
854 case AL_MAX_DISTANCE
:
855 *pflValue
= Source
->flMaxDistance
;
858 case AL_ROLLOFF_FACTOR
:
859 *pflValue
= Source
->flRollOffFactor
;
862 case AL_CONE_OUTER_GAIN
:
863 *pflValue
= Source
->flOuterGain
;
866 case AL_CONE_OUTER_GAINHF
:
867 *pflValue
= Source
->OuterGainHF
;
871 case AL_SAMPLE_OFFSET
:
873 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
874 pContext
->Device
->Frequency
;
875 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
876 *pflValue
= Offsets
[0];
879 case AL_CONE_INNER_ANGLE
:
880 *pflValue
= Source
->flInnerAngle
;
883 case AL_CONE_OUTER_ANGLE
:
884 *pflValue
= Source
->flOuterAngle
;
887 case AL_REFERENCE_DISTANCE
:
888 *pflValue
= Source
->flRefDistance
;
891 case AL_AIR_ABSORPTION_FACTOR
:
892 *pflValue
= Source
->AirAbsorptionFactor
;
895 case AL_ROOM_ROLLOFF_FACTOR
:
896 *pflValue
= Source
->RoomRolloffFactor
;
899 case AL_DOPPLER_FACTOR
:
900 *pflValue
= Source
->DopplerFactor
;
904 alSetError(pContext
, AL_INVALID_ENUM
);
909 alSetError(pContext
, AL_INVALID_NAME
);
912 alSetError(pContext
, AL_INVALID_VALUE
);
914 ProcessContext(pContext
);
918 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
920 ALCcontext
*pContext
;
923 pContext
= GetContextSuspended();
924 if(!pContext
) return;
926 if(pflValue1
&& pflValue2
&& pflValue3
)
928 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
933 *pflValue1
= Source
->vPosition
[0];
934 *pflValue2
= Source
->vPosition
[1];
935 *pflValue3
= Source
->vPosition
[2];
939 *pflValue1
= Source
->vVelocity
[0];
940 *pflValue2
= Source
->vVelocity
[1];
941 *pflValue3
= Source
->vVelocity
[2];
945 *pflValue1
= Source
->vOrientation
[0];
946 *pflValue2
= Source
->vOrientation
[1];
947 *pflValue3
= Source
->vOrientation
[2];
951 alSetError(pContext
, AL_INVALID_ENUM
);
956 alSetError(pContext
, AL_INVALID_NAME
);
959 alSetError(pContext
, AL_INVALID_VALUE
);
961 ProcessContext(pContext
);
965 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
967 ALCcontext
*pContext
;
972 pContext
= GetContextSuspended();
973 if(!pContext
) return;
977 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
985 case AL_MAX_DISTANCE
:
986 case AL_ROLLOFF_FACTOR
:
987 case AL_DOPPLER_FACTOR
:
988 case AL_CONE_OUTER_GAIN
:
990 case AL_SAMPLE_OFFSET
:
992 case AL_CONE_INNER_ANGLE
:
993 case AL_CONE_OUTER_ANGLE
:
994 case AL_REFERENCE_DISTANCE
:
995 case AL_CONE_OUTER_GAINHF
:
996 case AL_AIR_ABSORPTION_FACTOR
:
997 case AL_ROOM_ROLLOFF_FACTOR
:
998 alGetSourcef(source
, eParam
, pflValues
);
1004 alGetSource3f(source
, eParam
, pflValues
+0, pflValues
+1, pflValues
+2);
1007 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1008 case AL_BYTE_RW_OFFSETS_SOFT
:
1009 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1010 pContext
->Device
->Frequency
;
1011 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1012 pflValues
[0] = Offsets
[0];
1013 pflValues
[1] = Offsets
[1];
1017 alSetError(pContext
, AL_INVALID_ENUM
);
1022 alSetError(pContext
, AL_INVALID_NAME
);
1025 alSetError(pContext
, AL_INVALID_VALUE
);
1027 ProcessContext(pContext
);
1031 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1033 ALCcontext
*pContext
;
1035 ALdouble Offsets
[2];
1038 pContext
= GetContextSuspended();
1039 if(!pContext
) return;
1043 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1047 case AL_MAX_DISTANCE
:
1048 *plValue
= (ALint
)Source
->flMaxDistance
;
1051 case AL_ROLLOFF_FACTOR
:
1052 *plValue
= (ALint
)Source
->flRollOffFactor
;
1055 case AL_REFERENCE_DISTANCE
:
1056 *plValue
= (ALint
)Source
->flRefDistance
;
1059 case AL_SOURCE_RELATIVE
:
1060 *plValue
= Source
->bHeadRelative
;
1063 case AL_CONE_INNER_ANGLE
:
1064 *plValue
= (ALint
)Source
->flInnerAngle
;
1067 case AL_CONE_OUTER_ANGLE
:
1068 *plValue
= (ALint
)Source
->flOuterAngle
;
1072 *plValue
= Source
->bLooping
;
1076 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1079 case AL_SOURCE_STATE
:
1080 *plValue
= Source
->state
;
1083 case AL_BUFFERS_QUEUED
:
1084 *plValue
= Source
->BuffersInQueue
;
1087 case AL_BUFFERS_PROCESSED
:
1088 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
)
1090 /* Buffers on a looping source are in a perpetual state
1091 * of PENDING, so don't report any as PROCESSED */
1095 *plValue
= Source
->BuffersPlayed
;
1098 case AL_SOURCE_TYPE
:
1099 *plValue
= Source
->lSourceType
;
1103 case AL_SAMPLE_OFFSET
:
1104 case AL_BYTE_OFFSET
:
1105 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1106 pContext
->Device
->Frequency
;
1107 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1108 *plValue
= (ALint
)Offsets
[0];
1111 case AL_DIRECT_FILTER
:
1112 *plValue
= Source
->DirectFilter
.filter
;
1115 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1116 *plValue
= Source
->DryGainHFAuto
;
1119 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1120 *plValue
= Source
->WetGainAuto
;
1123 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1124 *plValue
= Source
->WetGainHFAuto
;
1127 case AL_DOPPLER_FACTOR
:
1128 *plValue
= (ALint
)Source
->DopplerFactor
;
1131 case AL_DISTANCE_MODEL
:
1132 *plValue
= Source
->DistanceModel
;
1136 alSetError(pContext
, AL_INVALID_ENUM
);
1141 alSetError(pContext
, AL_INVALID_NAME
);
1144 alSetError(pContext
, AL_INVALID_VALUE
);
1146 ProcessContext(pContext
);
1150 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1152 ALCcontext
*pContext
;
1155 pContext
= GetContextSuspended();
1156 if(!pContext
) return;
1158 if(plValue1
&& plValue2
&& plValue3
)
1160 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1165 *plValue1
= (ALint
)Source
->vPosition
[0];
1166 *plValue2
= (ALint
)Source
->vPosition
[1];
1167 *plValue3
= (ALint
)Source
->vPosition
[2];
1171 *plValue1
= (ALint
)Source
->vVelocity
[0];
1172 *plValue2
= (ALint
)Source
->vVelocity
[1];
1173 *plValue3
= (ALint
)Source
->vVelocity
[2];
1177 *plValue1
= (ALint
)Source
->vOrientation
[0];
1178 *plValue2
= (ALint
)Source
->vOrientation
[1];
1179 *plValue3
= (ALint
)Source
->vOrientation
[2];
1183 alSetError(pContext
, AL_INVALID_ENUM
);
1188 alSetError(pContext
, AL_INVALID_NAME
);
1191 alSetError(pContext
, AL_INVALID_VALUE
);
1193 ProcessContext(pContext
);
1197 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1199 ALCcontext
*pContext
;
1201 ALdouble Offsets
[2];
1204 pContext
= GetContextSuspended();
1205 if(!pContext
) return;
1209 if((Source
=LookupSource(pContext
->SourceMap
, source
)) != NULL
)
1213 case AL_SOURCE_RELATIVE
:
1214 case AL_CONE_INNER_ANGLE
:
1215 case AL_CONE_OUTER_ANGLE
:
1218 case AL_SOURCE_STATE
:
1219 case AL_BUFFERS_QUEUED
:
1220 case AL_BUFFERS_PROCESSED
:
1222 case AL_SAMPLE_OFFSET
:
1223 case AL_BYTE_OFFSET
:
1224 case AL_MAX_DISTANCE
:
1225 case AL_ROLLOFF_FACTOR
:
1226 case AL_DOPPLER_FACTOR
:
1227 case AL_REFERENCE_DISTANCE
:
1228 case AL_SOURCE_TYPE
:
1229 case AL_DIRECT_FILTER
:
1230 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1231 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1232 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1233 case AL_DISTANCE_MODEL
:
1234 alGetSourcei(source
, eParam
, plValues
);
1240 alGetSource3i(source
, eParam
, plValues
+0, plValues
+1, plValues
+2);
1243 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1244 case AL_BYTE_RW_OFFSETS_SOFT
:
1245 updateLen
= (ALdouble
)pContext
->Device
->UpdateSize
/
1246 pContext
->Device
->Frequency
;
1247 GetSourceOffset(Source
, eParam
, Offsets
, updateLen
);
1248 plValues
[0] = (ALint
)Offsets
[0];
1249 plValues
[1] = (ALint
)Offsets
[1];
1253 alSetError(pContext
, AL_INVALID_ENUM
);
1258 alSetError(pContext
, AL_INVALID_NAME
);
1261 alSetError(pContext
, AL_INVALID_VALUE
);
1263 ProcessContext(pContext
);
1267 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1269 alSourcePlayv(1, &source
);
1272 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1274 ALCcontext
*Context
;
1276 ALbufferlistitem
*BufferList
;
1279 Context
= GetContextSuspended();
1280 if(!Context
) return;
1284 alSetError(Context
, AL_INVALID_VALUE
);
1287 if(n
> 0 && !sources
)
1289 alSetError(Context
, AL_INVALID_VALUE
);
1293 // Check that all the Sources are valid
1294 for(i
= 0;i
< n
;i
++)
1296 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1298 alSetError(Context
, AL_INVALID_NAME
);
1303 while(Context
->MaxActiveSources
-Context
->ActiveSourceCount
< n
)
1308 newcount
= Context
->MaxActiveSources
<< 1;
1310 temp
= realloc(Context
->ActiveSources
,
1311 sizeof(*Context
->ActiveSources
) * newcount
);
1314 alSetError(Context
, AL_OUT_OF_MEMORY
);
1318 Context
->ActiveSources
= temp
;
1319 Context
->MaxActiveSources
= newcount
;
1322 for(i
= 0;i
< n
;i
++)
1324 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1326 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1327 BufferList
= Source
->queue
;
1330 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1332 BufferList
= BufferList
->next
;
1337 Source
->state
= AL_STOPPED
;
1338 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1339 Source
->position
= 0;
1340 Source
->position_fraction
= 0;
1341 Source
->lOffset
= 0;
1345 if(Source
->state
!= AL_PAUSED
)
1347 Source
->state
= AL_PLAYING
;
1348 Source
->position
= 0;
1349 Source
->position_fraction
= 0;
1350 Source
->BuffersPlayed
= 0;
1352 Source
->Buffer
= Source
->queue
->buffer
;
1355 Source
->state
= AL_PLAYING
;
1357 // Check if an Offset has been set
1359 ApplyOffset(Source
);
1361 // If device is disconnected, go right to stopped
1362 if(!Context
->Device
->Connected
)
1364 Source
->state
= AL_STOPPED
;
1365 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1366 Source
->position
= 0;
1367 Source
->position_fraction
= 0;
1371 for(j
= 0;j
< Context
->ActiveSourceCount
;j
++)
1373 if(Context
->ActiveSources
[j
] == Source
)
1376 if(j
== Context
->ActiveSourceCount
)
1377 Context
->ActiveSources
[Context
->ActiveSourceCount
++] = Source
;
1382 ProcessContext(Context
);
1385 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1387 alSourcePausev(1, &source
);
1390 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1392 ALCcontext
*Context
;
1396 Context
= GetContextSuspended();
1397 if(!Context
) return;
1401 alSetError(Context
, AL_INVALID_VALUE
);
1404 if(n
> 0 && !sources
)
1406 alSetError(Context
, AL_INVALID_VALUE
);
1410 // Check all the Sources are valid
1411 for(i
= 0;i
< n
;i
++)
1413 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1415 alSetError(Context
, AL_INVALID_NAME
);
1420 for(i
= 0;i
< n
;i
++)
1422 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1423 if(Source
->state
== AL_PLAYING
)
1424 Source
->state
= AL_PAUSED
;
1428 ProcessContext(Context
);
1431 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1433 alSourceStopv(1, &source
);
1436 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1438 ALCcontext
*Context
;
1442 Context
= GetContextSuspended();
1443 if(!Context
) return;
1447 alSetError(Context
, AL_INVALID_VALUE
);
1450 if(n
> 0 && !sources
)
1452 alSetError(Context
, AL_INVALID_VALUE
);
1456 // Check all the Sources are valid
1457 for(i
= 0;i
< n
;i
++)
1459 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1461 alSetError(Context
, AL_INVALID_NAME
);
1466 for(i
= 0;i
< n
;i
++)
1468 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1469 if(Source
->state
!= AL_INITIAL
)
1471 Source
->state
= AL_STOPPED
;
1472 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1474 Source
->lOffset
= 0;
1478 ProcessContext(Context
);
1481 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1483 alSourceRewindv(1, &source
);
1486 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1488 ALCcontext
*Context
;
1492 Context
= GetContextSuspended();
1493 if(!Context
) return;
1497 alSetError(Context
, AL_INVALID_VALUE
);
1500 if(n
> 0 && !sources
)
1502 alSetError(Context
, AL_INVALID_VALUE
);
1506 // Check all the Sources are valid
1507 for(i
= 0;i
< n
;i
++)
1509 if(!LookupSource(Context
->SourceMap
, sources
[i
]))
1511 alSetError(Context
, AL_INVALID_NAME
);
1516 for(i
= 0;i
< n
;i
++)
1518 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1519 if(Source
->state
!= AL_INITIAL
)
1521 Source
->state
= AL_INITIAL
;
1522 Source
->position
= 0;
1523 Source
->position_fraction
= 0;
1524 Source
->BuffersPlayed
= 0;
1526 Source
->Buffer
= Source
->queue
->buffer
;
1528 Source
->lOffset
= 0;
1532 ProcessContext(Context
);
1536 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1538 ALCcontext
*Context
;
1543 ALbufferlistitem
*BufferListStart
;
1544 ALbufferlistitem
*BufferList
;
1545 ALbuffer
*BufferFmt
;
1550 Context
= GetContextSuspended();
1551 if(!Context
) return;
1555 alSetError(Context
, AL_INVALID_VALUE
);
1559 // Check that all buffers are valid or zero and that the source is valid
1561 // Check that this is a valid source
1562 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1564 alSetError(Context
, AL_INVALID_NAME
);
1568 // Check that this is not a STATIC Source
1569 if(Source
->lSourceType
== AL_STATIC
)
1571 // Invalid Source Type (can't queue on a Static Source)
1572 alSetError(Context
, AL_INVALID_OPERATION
);
1576 device
= Context
->Device
;
1580 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1581 BufferList
= Source
->queue
;
1584 if(BufferList
->buffer
)
1586 BufferFmt
= BufferList
->buffer
;
1589 BufferList
= BufferList
->next
;
1592 for(i
= 0;i
< n
;i
++)
1597 if((buffer
=LookupBuffer(device
->BufferMap
, buffers
[i
])) == NULL
)
1599 alSetError(Context
, AL_INVALID_NAME
);
1603 if(BufferFmt
== NULL
)
1607 if(buffer
->FmtChannels
== FmtMono
)
1608 Source
->Update
= CalcSourceParams
;
1610 Source
->Update
= CalcNonAttnSourceParams
;
1612 Source
->NeedsUpdate
= AL_TRUE
;
1614 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
1615 BufferFmt
->OriginalChannels
!= buffer
->OriginalChannels
||
1616 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
1618 alSetError(Context
, AL_INVALID_OPERATION
);
1623 // Change Source Type
1624 Source
->lSourceType
= AL_STREAMING
;
1626 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1628 // All buffers are valid - so add them to the list
1629 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1630 BufferListStart
->buffer
= buffer
;
1631 BufferListStart
->next
= NULL
;
1632 BufferListStart
->prev
= NULL
;
1634 // Increment reference counter for buffer
1635 if(buffer
) buffer
->refcount
++;
1637 BufferList
= BufferListStart
;
1639 for(i
= 1;i
< n
;i
++)
1641 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1643 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1644 BufferList
->next
->buffer
= buffer
;
1645 BufferList
->next
->next
= NULL
;
1646 BufferList
->next
->prev
= BufferList
;
1648 // Increment reference counter for buffer
1649 if(buffer
) buffer
->refcount
++;
1651 BufferList
= BufferList
->next
;
1654 if(Source
->queue
== NULL
)
1656 Source
->queue
= BufferListStart
;
1657 // Update Current Buffer
1658 Source
->Buffer
= BufferListStart
->buffer
;
1662 // Find end of queue
1663 BufferList
= Source
->queue
;
1664 while(BufferList
->next
!= NULL
)
1665 BufferList
= BufferList
->next
;
1667 BufferList
->next
= BufferListStart
;
1668 BufferList
->next
->prev
= BufferList
;
1671 // Update number of buffers in queue
1672 Source
->BuffersInQueue
+= n
;
1675 ProcessContext(Context
);
1679 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1680 // an array of buffer IDs that are to be filled with the names of the buffers removed
1681 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1683 ALCcontext
*Context
;
1686 ALbufferlistitem
*BufferList
;
1691 Context
= GetContextSuspended();
1692 if(!Context
) return;
1696 alSetError(Context
, AL_INVALID_VALUE
);
1700 if((Source
=LookupSource(Context
->SourceMap
, source
)) == NULL
)
1702 alSetError(Context
, AL_INVALID_NAME
);
1706 if(Source
->bLooping
|| Source
->lSourceType
!= AL_STREAMING
||
1707 (ALuint
)n
> Source
->BuffersPlayed
)
1709 // Some buffers can't be unqueue because they have not been processed
1710 alSetError(Context
, AL_INVALID_VALUE
);
1714 for(i
= 0;i
< n
;i
++)
1716 BufferList
= Source
->queue
;
1717 Source
->queue
= BufferList
->next
;
1719 if(BufferList
->buffer
)
1721 // Record name of buffer
1722 buffers
[i
] = BufferList
->buffer
->buffer
;
1723 // Decrement buffer reference counter
1724 BufferList
->buffer
->refcount
--;
1729 // Release memory for buffer list item
1731 Source
->BuffersInQueue
--;
1734 Source
->queue
->prev
= NULL
;
1736 if(Source
->state
!= AL_PLAYING
)
1739 Source
->Buffer
= Source
->queue
->buffer
;
1741 Source
->Buffer
= NULL
;
1743 Source
->BuffersPlayed
-= n
;
1746 ProcessContext(Context
);
1750 static ALvoid
InitSourceParams(ALsource
*Source
)
1752 Source
->flInnerAngle
= 360.0f
;
1753 Source
->flOuterAngle
= 360.0f
;
1754 Source
->flPitch
= 1.0f
;
1755 Source
->vPosition
[0] = 0.0f
;
1756 Source
->vPosition
[1] = 0.0f
;
1757 Source
->vPosition
[2] = 0.0f
;
1758 Source
->vOrientation
[0] = 0.0f
;
1759 Source
->vOrientation
[1] = 0.0f
;
1760 Source
->vOrientation
[2] = 0.0f
;
1761 Source
->vVelocity
[0] = 0.0f
;
1762 Source
->vVelocity
[1] = 0.0f
;
1763 Source
->vVelocity
[2] = 0.0f
;
1764 Source
->flRefDistance
= 1.0f
;
1765 Source
->flMaxDistance
= FLT_MAX
;
1766 Source
->flRollOffFactor
= 1.0f
;
1767 Source
->bLooping
= AL_FALSE
;
1768 Source
->flGain
= 1.0f
;
1769 Source
->flMinGain
= 0.0f
;
1770 Source
->flMaxGain
= 1.0f
;
1771 Source
->flOuterGain
= 0.0f
;
1772 Source
->OuterGainHF
= 1.0f
;
1774 Source
->DryGainHFAuto
= AL_TRUE
;
1775 Source
->WetGainAuto
= AL_TRUE
;
1776 Source
->WetGainHFAuto
= AL_TRUE
;
1777 Source
->AirAbsorptionFactor
= 0.0f
;
1778 Source
->RoomRolloffFactor
= 0.0f
;
1779 Source
->DopplerFactor
= 1.0f
;
1781 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1783 Source
->Resampler
= DefaultResampler
;
1785 Source
->state
= AL_INITIAL
;
1786 Source
->lSourceType
= AL_UNDETERMINED
;
1788 Source
->NeedsUpdate
= AL_TRUE
;
1790 Source
->Buffer
= NULL
;
1797 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1798 The offset is relative to the start of the queue (not the start of the current buffer)
1800 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALdouble
*offset
, ALdouble updateLen
)
1802 ALbufferlistitem
*BufferList
;
1803 ALbuffer
*Buffer
= NULL
;
1805 ALint Channels
, Bytes
;
1806 ALuint readPos
, writePos
;
1807 enum SrcFmtType OriginalType
;
1808 ALuint TotalBufferDataSize
;
1811 // Find the first non-NULL Buffer in the Queue
1812 BufferList
= Source
->queue
;
1815 if(BufferList
->buffer
)
1817 Buffer
= BufferList
->buffer
;
1820 BufferList
= BufferList
->next
;
1823 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) || !Buffer
)
1830 // Get Current Buffer Size and frequency (in milliseconds)
1831 BufferFreq
= (ALfloat
)Buffer
->Frequency
;
1832 OriginalType
= Buffer
->OriginalType
;
1833 Channels
= ChannelsFromFmt(Buffer
->FmtChannels
);
1834 Bytes
= BytesFromFmt(Buffer
->FmtType
);
1836 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1837 readPos
= Source
->position
* Channels
* Bytes
;
1838 // Add byte length of any processed buffers in the queue
1839 TotalBufferDataSize
= 0;
1840 BufferList
= Source
->queue
;
1841 for(i
= 0;BufferList
;i
++)
1843 if(BufferList
->buffer
)
1845 if(i
< Source
->BuffersPlayed
)
1846 readPos
+= BufferList
->buffer
->size
;
1847 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1849 BufferList
= BufferList
->next
;
1851 if(Source
->state
== AL_PLAYING
)
1852 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1856 if(Source
->bLooping
)
1858 readPos
%= TotalBufferDataSize
;
1859 writePos
%= TotalBufferDataSize
;
1863 // Wrap positions back to 0
1864 if(readPos
>= TotalBufferDataSize
)
1866 if(writePos
>= TotalBufferDataSize
)
1873 offset
[0] = (ALdouble
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1874 offset
[1] = (ALdouble
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1876 case AL_SAMPLE_OFFSET
:
1877 case AL_SAMPLE_RW_OFFSETS_SOFT
:
1878 offset
[0] = (ALdouble
)(readPos
/ (Channels
* Bytes
));
1879 offset
[1] = (ALdouble
)(writePos
/ (Channels
* Bytes
));
1881 case AL_BYTE_OFFSET
:
1882 case AL_BYTE_RW_OFFSETS_SOFT
:
1883 // Take into account the original format of the Buffer
1884 if(OriginalType
== SrcFmtIMA4
)
1886 ALuint FrameBlockSize
= 65 * Bytes
* Channels
;
1887 ALuint BlockSize
= 36 * Channels
;
1889 // Round down to nearest ADPCM block
1890 offset
[0] = (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
1891 if(Source
->state
!= AL_PLAYING
)
1892 offset
[1] = offset
[0];
1895 // Round up to nearest ADPCM block
1896 offset
[1] = (ALdouble
)((writePos
+FrameBlockSize
-1) /
1897 FrameBlockSize
* BlockSize
);
1902 ALuint OrigBytes
= BytesFromSrcFmt(OriginalType
);
1903 offset
[0] = (ALdouble
)(readPos
/ Bytes
* OrigBytes
);
1904 offset
[1] = (ALdouble
)(writePos
/ Bytes
* OrigBytes
);
1914 Apply a playback offset to the Source. This function will update the queue (to correctly
1915 mark buffers as 'pending' or 'processed' depending upon the new offset.
1917 static ALboolean
ApplyOffset(ALsource
*Source
)
1919 ALbufferlistitem
*BufferList
;
1921 ALint lBufferSize
, lTotalBufferSize
;
1922 ALint BuffersPlayed
;
1925 // Get true byte offset
1926 lByteOffset
= GetByteOffset(Source
);
1928 // If the offset is invalid, don't apply it
1929 if(lByteOffset
== -1)
1932 // Sort out the queue (pending and processed states)
1933 BufferList
= Source
->queue
;
1934 lTotalBufferSize
= 0;
1939 Buffer
= BufferList
->buffer
;
1940 lBufferSize
= Buffer
? Buffer
->size
: 0;
1942 if(lBufferSize
<= lByteOffset
-lTotalBufferSize
)
1944 // Offset is past this buffer so increment BuffersPlayed
1947 else if(lTotalBufferSize
<= lByteOffset
)
1949 // Offset is within this buffer
1950 // Set Current Buffer
1951 Source
->Buffer
= BufferList
->buffer
;
1952 Source
->BuffersPlayed
= BuffersPlayed
;
1954 // SW Mixer Positions are in Samples
1955 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1956 FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
1960 // Increment the TotalBufferSize
1961 lTotalBufferSize
+= lBufferSize
;
1963 // Move on to next buffer in the Queue
1964 BufferList
= BufferList
->next
;
1966 // Offset is out of range of the buffer queue
1974 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1975 offset supplied by the application). This takes into account the fact that the buffer format
1976 may have been modifed by AL (e.g 8bit samples are converted to float)
1978 static ALint
GetByteOffset(ALsource
*Source
)
1980 ALbuffer
*Buffer
= NULL
;
1981 ALbufferlistitem
*BufferList
;
1982 ALint ByteOffset
= -1;
1984 // Find the first non-NULL Buffer in the Queue
1985 BufferList
= Source
->queue
;
1988 if(BufferList
->buffer
)
1990 Buffer
= BufferList
->buffer
;
1993 BufferList
= BufferList
->next
;
1998 Source
->lOffset
= 0;
2002 // Determine the ByteOffset (and ensure it is block aligned)
2003 switch(Source
->lOffsetType
)
2005 case AL_BYTE_OFFSET
:
2006 // Take into consideration the original format
2007 ByteOffset
= Source
->lOffset
;
2008 if(Buffer
->OriginalType
== SrcFmtIMA4
)
2010 // Round down to nearest ADPCM block
2011 ByteOffset
/= 36 * ChannelsFromSrcFmt(Buffer
->OriginalChannels
);
2012 // Multiply by compression rate (65 sample frames per block)
2016 ByteOffset
/= FrameSizeFromSrcFmt(Buffer
->OriginalChannels
, Buffer
->OriginalType
);
2017 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2020 case AL_SAMPLE_OFFSET
:
2021 ByteOffset
= Source
->lOffset
* FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2025 // Note - lOffset is internally stored as Milliseconds
2026 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0 * Buffer
->Frequency
);
2027 ByteOffset
*= FrameSizeFromFmt(Buffer
->FmtChannels
, Buffer
->FmtType
);
2031 Source
->lOffset
= 0;
2037 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2041 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
2043 ALsource
*temp
= Context
->SourceMap
.array
[pos
].value
;
2044 Context
->SourceMap
.array
[pos
].value
= NULL
;
2046 // For each buffer in the source's queue, decrement its reference counter and remove it
2047 while(temp
->queue
!= NULL
)
2049 ALbufferlistitem
*BufferList
= temp
->queue
;
2050 temp
->queue
= BufferList
->next
;
2052 if(BufferList
->buffer
!= NULL
)
2053 BufferList
->buffer
->refcount
--;
2057 for(j
= 0;j
< MAX_SENDS
;++j
)
2059 if(temp
->Send
[j
].Slot
)
2060 temp
->Send
[j
].Slot
->refcount
--;
2061 temp
->Send
[j
].Slot
= NULL
;
2064 // Release source structure
2065 ALTHUNK_REMOVEENTRY(temp
->source
);
2066 memset(temp
, 0, sizeof(ALsource
));