Use a double when converting millisecond offsets to byte offsets
[openal-soft.git] / OpenAL32 / alSource.c
blob2270a2460112954c3796872faf9bdba9ae7e56d3
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
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)
48 ALCcontext *Context;
49 ALCdevice *Device;
51 Context = GetContextSuspended();
52 if(!Context) return;
54 Device = Context->Device;
55 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
56 alSetError(Context, AL_INVALID_VALUE);
57 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
58 alSetError(Context, AL_INVALID_VALUE);
59 else
61 ALenum err;
62 ALsizei i;
64 // Add additional sources to the list
65 i = 0;
66 while(i < n)
68 ALsource *source = calloc(1, sizeof(ALsource));
69 if(!source)
71 alSetError(Context, AL_OUT_OF_MEMORY);
72 alDeleteSources(i, sources);
73 break;
76 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
77 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
78 source);
79 if(err != AL_NO_ERROR)
81 ALTHUNK_REMOVEENTRY(source->source);
82 memset(source, 0, sizeof(ALsource));
83 free(source);
85 alSetError(Context, err);
86 alDeleteSources(i, sources);
87 break;
90 sources[i++] = source->source;
91 InitSourceParams(source);
95 ProcessContext(Context);
99 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
101 ALCcontext *Context;
102 ALsource *Source;
103 ALsizei i, j;
104 ALbufferlistitem *BufferList;
105 ALboolean SourcesValid = AL_FALSE;
107 Context = GetContextSuspended();
108 if(!Context) return;
110 if(n < 0)
111 alSetError(Context, AL_INVALID_VALUE);
112 else
114 SourcesValid = AL_TRUE;
115 // Check that all Sources are valid (and can therefore be deleted)
116 for(i = 0;i < n;i++)
118 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
120 alSetError(Context, AL_INVALID_NAME);
121 SourcesValid = AL_FALSE;
122 break;
127 if(SourcesValid)
129 // All Sources are valid, and can be deleted
130 for(i = 0;i < n;i++)
132 // Recheck that the Source is valid, because there could be duplicated Source names
133 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
134 continue;
136 for(j = 0;j < Context->ActiveSourceCount;j++)
138 if(Context->ActiveSources[j] == Source)
140 ALsizei end = --(Context->ActiveSourceCount);
141 Context->ActiveSources[j] = Context->ActiveSources[end];
142 break;
146 // For each buffer in the source's queue...
147 while(Source->queue != NULL)
149 BufferList = Source->queue;
150 Source->queue = BufferList->next;
152 if(BufferList->buffer != NULL)
153 BufferList->buffer->refcount--;
154 free(BufferList);
157 for(j = 0;j < MAX_SENDS;++j)
159 if(Source->Send[j].Slot)
160 Source->Send[j].Slot->refcount--;
161 Source->Send[j].Slot = NULL;
164 // Remove Source from list of Sources
165 RemoveUIntMapKey(&Context->SourceMap, Source->source);
166 ALTHUNK_REMOVEENTRY(Source->source);
168 memset(Source,0,sizeof(ALsource));
169 free(Source);
173 ProcessContext(Context);
177 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
179 ALCcontext *Context;
180 ALboolean result;
182 Context = GetContextSuspended();
183 if(!Context) return AL_FALSE;
185 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
187 ProcessContext(Context);
189 return result;
193 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
195 ALCcontext *pContext;
196 ALsource *Source;
198 pContext = GetContextSuspended();
199 if(!pContext) return;
201 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
203 switch(eParam)
205 case AL_PITCH:
206 if(flValue >= 0.0f)
208 Source->flPitch = flValue;
209 if(Source->flPitch < 0.001f)
210 Source->flPitch = 0.001f;
211 Source->NeedsUpdate = AL_TRUE;
213 else
214 alSetError(pContext, AL_INVALID_VALUE);
215 break;
217 case AL_CONE_INNER_ANGLE:
218 if(flValue >= 0.0f && flValue <= 360.0f)
220 Source->flInnerAngle = flValue;
221 Source->NeedsUpdate = AL_TRUE;
223 else
224 alSetError(pContext, AL_INVALID_VALUE);
225 break;
227 case AL_CONE_OUTER_ANGLE:
228 if(flValue >= 0.0f && flValue <= 360.0f)
230 Source->flOuterAngle = flValue;
231 Source->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_GAIN:
238 if(flValue >= 0.0f)
240 Source->flGain = flValue;
241 Source->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_MAX_DISTANCE:
248 if(flValue >= 0.0f)
250 Source->flMaxDistance = flValue;
251 Source->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_ROLLOFF_FACTOR:
258 if(flValue >= 0.0f)
260 Source->flRollOffFactor = flValue;
261 Source->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_REFERENCE_DISTANCE:
268 if(flValue >= 0.0f)
270 Source->flRefDistance = flValue;
271 Source->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_MIN_GAIN:
278 if(flValue >= 0.0f && flValue <= 1.0f)
280 Source->flMinGain = flValue;
281 Source->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_MAX_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
290 Source->flMaxGain = flValue;
291 Source->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_CONE_OUTER_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 Source->flOuterGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_CONE_OUTER_GAINHF:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 Source->OuterGainHF = flValue;
311 Source->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_AIR_ABSORPTION_FACTOR:
318 if(flValue >= 0.0f && flValue <= 10.0f)
320 Source->AirAbsorptionFactor = flValue;
321 Source->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_ROOM_ROLLOFF_FACTOR:
328 if(flValue >= 0.0f && flValue <= 10.0f)
330 Source->RoomRolloffFactor = flValue;
331 Source->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_DOPPLER_FACTOR:
338 if(flValue >= 0.0f && flValue <= 1.0f)
340 Source->DopplerFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_SEC_OFFSET:
348 case AL_SAMPLE_OFFSET:
349 case AL_BYTE_OFFSET:
350 if(flValue >= 0.0f)
352 Source->lOffsetType = eParam;
354 // Store Offset (convert Seconds into Milliseconds)
355 if(eParam == AL_SEC_OFFSET)
356 Source->lOffset = (ALint)(flValue * 1000.0f);
357 else
358 Source->lOffset = (ALint)flValue;
360 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
362 if(ApplyOffset(Source) == AL_FALSE)
363 alSetError(pContext, AL_INVALID_VALUE);
366 else
367 alSetError(pContext, AL_INVALID_VALUE);
368 break;
370 default:
371 alSetError(pContext, AL_INVALID_ENUM);
372 break;
375 else
377 // Invalid Source Name
378 alSetError(pContext, AL_INVALID_NAME);
381 ProcessContext(pContext);
385 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
387 ALCcontext *pContext;
388 ALsource *Source;
390 pContext = GetContextSuspended();
391 if(!pContext) return;
393 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
395 switch(eParam)
397 case AL_POSITION:
398 Source->vPosition[0] = flValue1;
399 Source->vPosition[1] = flValue2;
400 Source->vPosition[2] = flValue3;
401 Source->NeedsUpdate = AL_TRUE;
402 break;
404 case AL_VELOCITY:
405 Source->vVelocity[0] = flValue1;
406 Source->vVelocity[1] = flValue2;
407 Source->vVelocity[2] = flValue3;
408 Source->NeedsUpdate = AL_TRUE;
409 break;
411 case AL_DIRECTION:
412 Source->vOrientation[0] = flValue1;
413 Source->vOrientation[1] = flValue2;
414 Source->vOrientation[2] = flValue3;
415 Source->NeedsUpdate = AL_TRUE;
416 break;
418 default:
419 alSetError(pContext, AL_INVALID_ENUM);
420 break;
423 else
424 alSetError(pContext, AL_INVALID_NAME);
426 ProcessContext(pContext);
430 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
432 ALCcontext *pContext;
434 pContext = GetContextSuspended();
435 if(!pContext) return;
437 if(pflValues)
439 if(LookupSource(pContext->SourceMap, source) != NULL)
441 switch(eParam)
443 case AL_PITCH:
444 case AL_CONE_INNER_ANGLE:
445 case AL_CONE_OUTER_ANGLE:
446 case AL_GAIN:
447 case AL_MAX_DISTANCE:
448 case AL_ROLLOFF_FACTOR:
449 case AL_REFERENCE_DISTANCE:
450 case AL_MIN_GAIN:
451 case AL_MAX_GAIN:
452 case AL_CONE_OUTER_GAIN:
453 case AL_CONE_OUTER_GAINHF:
454 case AL_SEC_OFFSET:
455 case AL_SAMPLE_OFFSET:
456 case AL_BYTE_OFFSET:
457 case AL_AIR_ABSORPTION_FACTOR:
458 case AL_ROOM_ROLLOFF_FACTOR:
459 alSourcef(source, eParam, pflValues[0]);
460 break;
462 case AL_POSITION:
463 case AL_VELOCITY:
464 case AL_DIRECTION:
465 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
466 break;
468 default:
469 alSetError(pContext, AL_INVALID_ENUM);
470 break;
473 else
474 alSetError(pContext, AL_INVALID_NAME);
476 else
477 alSetError(pContext, AL_INVALID_VALUE);
479 ProcessContext(pContext);
483 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
485 ALCcontext *pContext;
486 ALsource *Source;
487 ALbufferlistitem *BufferListItem;
489 pContext = GetContextSuspended();
490 if(!pContext) return;
492 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
494 ALCdevice *device = pContext->Device;
496 switch(eParam)
498 case AL_MAX_DISTANCE:
499 case AL_ROLLOFF_FACTOR:
500 case AL_CONE_INNER_ANGLE:
501 case AL_CONE_OUTER_ANGLE:
502 case AL_REFERENCE_DISTANCE:
503 alSourcef(source, eParam, (ALfloat)lValue);
504 break;
506 case AL_SOURCE_RELATIVE:
507 if(lValue == AL_FALSE || lValue == AL_TRUE)
509 Source->bHeadRelative = (ALboolean)lValue;
510 Source->NeedsUpdate = AL_TRUE;
512 else
513 alSetError(pContext, AL_INVALID_VALUE);
514 break;
516 case AL_LOOPING:
517 if(lValue == AL_FALSE || lValue == AL_TRUE)
518 Source->bLooping = (ALboolean)lValue;
519 else
520 alSetError(pContext, AL_INVALID_VALUE);
521 break;
523 case AL_BUFFER:
524 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
526 ALbuffer *buffer = NULL;
528 if(lValue == 0 ||
529 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
531 // Remove all elements in the queue
532 while(Source->queue != NULL)
534 BufferListItem = Source->queue;
535 Source->queue = BufferListItem->next;
537 if(BufferListItem->buffer)
538 BufferListItem->buffer->refcount--;
539 free(BufferListItem);
541 Source->BuffersInQueue = 0;
543 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
544 if(buffer != NULL)
546 // Source is now in STATIC mode
547 Source->lSourceType = AL_STATIC;
549 // Add the selected buffer to the queue
550 BufferListItem = malloc(sizeof(ALbufferlistitem));
551 BufferListItem->buffer = buffer;
552 BufferListItem->next = NULL;
554 Source->queue = BufferListItem;
555 Source->BuffersInQueue = 1;
557 if(aluChannelsFromFormat(buffer->format) == 1)
558 Source->Update = CalcSourceParams;
559 else
560 Source->Update = CalcNonAttnSourceParams;
562 Source->Mix = MixSource;
564 // Increment reference counter for buffer
565 buffer->refcount++;
567 else
569 // Source is now in UNDETERMINED mode
570 Source->lSourceType = AL_UNDETERMINED;
572 Source->BuffersPlayed = 0;
574 // Update AL_BUFFER parameter
575 Source->Buffer = buffer;
576 Source->NeedsUpdate = AL_TRUE;
578 else
579 alSetError(pContext, AL_INVALID_VALUE);
581 else
582 alSetError(pContext, AL_INVALID_OPERATION);
583 break;
585 case AL_SOURCE_STATE:
586 // Query only
587 alSetError(pContext, AL_INVALID_OPERATION);
588 break;
590 case AL_SEC_OFFSET:
591 case AL_SAMPLE_OFFSET:
592 case AL_BYTE_OFFSET:
593 if(lValue >= 0)
595 Source->lOffsetType = eParam;
597 // Store Offset (convert Seconds into Milliseconds)
598 if(eParam == AL_SEC_OFFSET)
599 Source->lOffset = lValue * 1000;
600 else
601 Source->lOffset = lValue;
603 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
605 if(ApplyOffset(Source) == AL_FALSE)
606 alSetError(pContext, AL_INVALID_VALUE);
609 else
610 alSetError(pContext, AL_INVALID_VALUE);
611 break;
613 case AL_DIRECT_FILTER: {
614 ALfilter *filter = NULL;
616 if(lValue == 0 ||
617 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
619 if(!filter)
621 Source->DirectFilter.type = AL_FILTER_NULL;
622 Source->DirectFilter.filter = 0;
624 else
625 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
626 Source->NeedsUpdate = AL_TRUE;
628 else
629 alSetError(pContext, AL_INVALID_VALUE);
630 } break;
632 case AL_DIRECT_FILTER_GAINHF_AUTO:
633 if(lValue == AL_TRUE || lValue == AL_FALSE)
635 Source->DryGainHFAuto = lValue;
636 Source->NeedsUpdate = AL_TRUE;
638 else
639 alSetError(pContext, AL_INVALID_VALUE);
640 break;
642 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
643 if(lValue == AL_TRUE || lValue == AL_FALSE)
645 Source->WetGainAuto = lValue;
646 Source->NeedsUpdate = AL_TRUE;
648 else
649 alSetError(pContext, AL_INVALID_VALUE);
650 break;
652 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
653 if(lValue == AL_TRUE || lValue == AL_FALSE)
655 Source->WetGainHFAuto = lValue;
656 Source->NeedsUpdate = AL_TRUE;
658 else
659 alSetError(pContext, AL_INVALID_VALUE);
660 break;
662 case AL_DISTANCE_MODEL:
663 if(lValue == AL_NONE ||
664 lValue == AL_INVERSE_DISTANCE ||
665 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
666 lValue == AL_LINEAR_DISTANCE ||
667 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
668 lValue == AL_EXPONENT_DISTANCE ||
669 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
671 Source->DistanceModel = lValue;
672 if(pContext->SourceDistanceModel)
673 Source->NeedsUpdate = AL_TRUE;
675 else
676 alSetError(pContext, AL_INVALID_VALUE);
677 break;
679 default:
680 alSetError(pContext, AL_INVALID_ENUM);
681 break;
684 else
685 alSetError(pContext, AL_INVALID_NAME);
687 ProcessContext(pContext);
691 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
693 ALCcontext *pContext;
694 ALsource *Source;
696 pContext = GetContextSuspended();
697 if(!pContext) return;
699 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
701 ALCdevice *device = pContext->Device;
703 switch (eParam)
705 case AL_POSITION:
706 case AL_VELOCITY:
707 case AL_DIRECTION:
708 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
709 break;
711 case AL_AUXILIARY_SEND_FILTER: {
712 ALeffectslot *ALEffectSlot = NULL;
713 ALfilter *ALFilter = NULL;
715 if((ALuint)lValue2 < device->NumAuxSends &&
716 (lValue1 == 0 ||
717 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
718 (lValue3 == 0 ||
719 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
721 /* Release refcount on the previous slot, and add one for
722 * the new slot */
723 if(Source->Send[lValue2].Slot)
724 Source->Send[lValue2].Slot->refcount--;
725 Source->Send[lValue2].Slot = ALEffectSlot;
726 if(Source->Send[lValue2].Slot)
727 Source->Send[lValue2].Slot->refcount++;
729 if(!ALFilter)
731 /* Disable filter */
732 Source->Send[lValue2].WetFilter.type = 0;
733 Source->Send[lValue2].WetFilter.filter = 0;
735 else
736 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
737 Source->NeedsUpdate = AL_TRUE;
739 else
740 alSetError(pContext, AL_INVALID_VALUE);
741 } break;
743 default:
744 alSetError(pContext, AL_INVALID_ENUM);
745 break;
748 else
749 alSetError(pContext, AL_INVALID_NAME);
751 ProcessContext(pContext);
755 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
757 ALCcontext *pContext;
759 pContext = GetContextSuspended();
760 if(!pContext) return;
762 if(plValues)
764 if(LookupSource(pContext->SourceMap, source) != NULL)
766 switch(eParam)
768 case AL_SOURCE_RELATIVE:
769 case AL_CONE_INNER_ANGLE:
770 case AL_CONE_OUTER_ANGLE:
771 case AL_LOOPING:
772 case AL_BUFFER:
773 case AL_SOURCE_STATE:
774 case AL_SEC_OFFSET:
775 case AL_SAMPLE_OFFSET:
776 case AL_BYTE_OFFSET:
777 case AL_MAX_DISTANCE:
778 case AL_ROLLOFF_FACTOR:
779 case AL_REFERENCE_DISTANCE:
780 case AL_DIRECT_FILTER:
781 case AL_DIRECT_FILTER_GAINHF_AUTO:
782 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
783 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
784 case AL_DISTANCE_MODEL:
785 alSourcei(source, eParam, plValues[0]);
786 break;
788 case AL_POSITION:
789 case AL_VELOCITY:
790 case AL_DIRECTION:
791 case AL_AUXILIARY_SEND_FILTER:
792 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
793 break;
795 default:
796 alSetError(pContext, AL_INVALID_ENUM);
797 break;
800 else
801 alSetError(pContext, AL_INVALID_NAME);
803 else
804 alSetError(pContext, AL_INVALID_VALUE);
806 ProcessContext(pContext);
810 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
812 ALCcontext *pContext;
813 ALsource *Source;
814 ALdouble Offsets[2];
815 ALdouble updateLen;
817 pContext = GetContextSuspended();
818 if(!pContext) return;
820 if(pflValue)
822 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
824 switch(eParam)
826 case AL_PITCH:
827 *pflValue = Source->flPitch;
828 break;
830 case AL_GAIN:
831 *pflValue = Source->flGain;
832 break;
834 case AL_MIN_GAIN:
835 *pflValue = Source->flMinGain;
836 break;
838 case AL_MAX_GAIN:
839 *pflValue = Source->flMaxGain;
840 break;
842 case AL_MAX_DISTANCE:
843 *pflValue = Source->flMaxDistance;
844 break;
846 case AL_ROLLOFF_FACTOR:
847 *pflValue = Source->flRollOffFactor;
848 break;
850 case AL_CONE_OUTER_GAIN:
851 *pflValue = Source->flOuterGain;
852 break;
854 case AL_CONE_OUTER_GAINHF:
855 *pflValue = Source->OuterGainHF;
856 break;
858 case AL_SEC_OFFSET:
859 case AL_SAMPLE_OFFSET:
860 case AL_BYTE_OFFSET:
861 updateLen = (ALdouble)pContext->Device->UpdateSize /
862 pContext->Device->Frequency;
863 GetSourceOffset(Source, eParam, Offsets, updateLen);
864 *pflValue = Offsets[0];
865 break;
867 case AL_CONE_INNER_ANGLE:
868 *pflValue = Source->flInnerAngle;
869 break;
871 case AL_CONE_OUTER_ANGLE:
872 *pflValue = Source->flOuterAngle;
873 break;
875 case AL_REFERENCE_DISTANCE:
876 *pflValue = Source->flRefDistance;
877 break;
879 case AL_AIR_ABSORPTION_FACTOR:
880 *pflValue = Source->AirAbsorptionFactor;
881 break;
883 case AL_ROOM_ROLLOFF_FACTOR:
884 *pflValue = Source->RoomRolloffFactor;
885 break;
887 case AL_DOPPLER_FACTOR:
888 *pflValue = Source->DopplerFactor;
889 break;
891 default:
892 alSetError(pContext, AL_INVALID_ENUM);
893 break;
896 else
897 alSetError(pContext, AL_INVALID_NAME);
899 else
900 alSetError(pContext, AL_INVALID_VALUE);
902 ProcessContext(pContext);
906 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
908 ALCcontext *pContext;
909 ALsource *Source;
911 pContext = GetContextSuspended();
912 if(!pContext) return;
914 if(pflValue1 && pflValue2 && pflValue3)
916 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
918 switch(eParam)
920 case AL_POSITION:
921 *pflValue1 = Source->vPosition[0];
922 *pflValue2 = Source->vPosition[1];
923 *pflValue3 = Source->vPosition[2];
924 break;
926 case AL_VELOCITY:
927 *pflValue1 = Source->vVelocity[0];
928 *pflValue2 = Source->vVelocity[1];
929 *pflValue3 = Source->vVelocity[2];
930 break;
932 case AL_DIRECTION:
933 *pflValue1 = Source->vOrientation[0];
934 *pflValue2 = Source->vOrientation[1];
935 *pflValue3 = Source->vOrientation[2];
936 break;
938 default:
939 alSetError(pContext, AL_INVALID_ENUM);
940 break;
943 else
944 alSetError(pContext, AL_INVALID_NAME);
946 else
947 alSetError(pContext, AL_INVALID_VALUE);
949 ProcessContext(pContext);
953 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
955 ALCcontext *pContext;
956 ALsource *Source;
957 ALdouble Offsets[2];
958 ALdouble updateLen;
960 pContext = GetContextSuspended();
961 if(!pContext) return;
963 if(pflValues)
965 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
967 switch(eParam)
969 case AL_PITCH:
970 case AL_GAIN:
971 case AL_MIN_GAIN:
972 case AL_MAX_GAIN:
973 case AL_MAX_DISTANCE:
974 case AL_ROLLOFF_FACTOR:
975 case AL_DOPPLER_FACTOR:
976 case AL_CONE_OUTER_GAIN:
977 case AL_SEC_OFFSET:
978 case AL_SAMPLE_OFFSET:
979 case AL_BYTE_OFFSET:
980 case AL_CONE_INNER_ANGLE:
981 case AL_CONE_OUTER_ANGLE:
982 case AL_REFERENCE_DISTANCE:
983 case AL_CONE_OUTER_GAINHF:
984 case AL_AIR_ABSORPTION_FACTOR:
985 case AL_ROOM_ROLLOFF_FACTOR:
986 alGetSourcef(source, eParam, pflValues);
987 break;
989 case AL_POSITION:
990 case AL_VELOCITY:
991 case AL_DIRECTION:
992 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
993 break;
995 case AL_SAMPLE_RW_OFFSETS_SOFT:
996 case AL_BYTE_RW_OFFSETS_SOFT:
997 updateLen = (ALdouble)pContext->Device->UpdateSize /
998 pContext->Device->Frequency;
999 GetSourceOffset(Source, eParam, Offsets, updateLen);
1000 pflValues[0] = Offsets[0];
1001 pflValues[1] = Offsets[1];
1002 break;
1004 default:
1005 alSetError(pContext, AL_INVALID_ENUM);
1006 break;
1009 else
1010 alSetError(pContext, AL_INVALID_NAME);
1012 else
1013 alSetError(pContext, AL_INVALID_VALUE);
1015 ProcessContext(pContext);
1019 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1021 ALCcontext *pContext;
1022 ALsource *Source;
1023 ALdouble Offsets[2];
1024 ALdouble updateLen;
1026 pContext = GetContextSuspended();
1027 if(!pContext) return;
1029 if(plValue)
1031 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1033 switch(eParam)
1035 case AL_MAX_DISTANCE:
1036 *plValue = (ALint)Source->flMaxDistance;
1037 break;
1039 case AL_ROLLOFF_FACTOR:
1040 *plValue = (ALint)Source->flRollOffFactor;
1041 break;
1043 case AL_REFERENCE_DISTANCE:
1044 *plValue = (ALint)Source->flRefDistance;
1045 break;
1047 case AL_SOURCE_RELATIVE:
1048 *plValue = Source->bHeadRelative;
1049 break;
1051 case AL_CONE_INNER_ANGLE:
1052 *plValue = (ALint)Source->flInnerAngle;
1053 break;
1055 case AL_CONE_OUTER_ANGLE:
1056 *plValue = (ALint)Source->flOuterAngle;
1057 break;
1059 case AL_LOOPING:
1060 *plValue = Source->bLooping;
1061 break;
1063 case AL_BUFFER:
1064 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1065 break;
1067 case AL_SOURCE_STATE:
1068 *plValue = Source->state;
1069 break;
1071 case AL_BUFFERS_QUEUED:
1072 *plValue = Source->BuffersInQueue;
1073 break;
1075 case AL_BUFFERS_PROCESSED:
1076 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1078 /* Buffers on a looping source are in a perpetual state
1079 * of PENDING, so don't report any as PROCESSED */
1080 *plValue = 0;
1082 else
1083 *plValue = Source->BuffersPlayed;
1084 break;
1086 case AL_SOURCE_TYPE:
1087 *plValue = Source->lSourceType;
1088 break;
1090 case AL_SEC_OFFSET:
1091 case AL_SAMPLE_OFFSET:
1092 case AL_BYTE_OFFSET:
1093 updateLen = (ALdouble)pContext->Device->UpdateSize /
1094 pContext->Device->Frequency;
1095 GetSourceOffset(Source, eParam, Offsets, updateLen);
1096 *plValue = (ALint)Offsets[0];
1097 break;
1099 case AL_DIRECT_FILTER:
1100 *plValue = Source->DirectFilter.filter;
1101 break;
1103 case AL_DIRECT_FILTER_GAINHF_AUTO:
1104 *plValue = Source->DryGainHFAuto;
1105 break;
1107 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1108 *plValue = Source->WetGainAuto;
1109 break;
1111 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1112 *plValue = Source->WetGainHFAuto;
1113 break;
1115 case AL_DOPPLER_FACTOR:
1116 *plValue = (ALint)Source->DopplerFactor;
1117 break;
1119 case AL_DISTANCE_MODEL:
1120 *plValue = Source->DistanceModel;
1121 break;
1123 default:
1124 alSetError(pContext, AL_INVALID_ENUM);
1125 break;
1128 else
1129 alSetError(pContext, AL_INVALID_NAME);
1131 else
1132 alSetError(pContext, AL_INVALID_VALUE);
1134 ProcessContext(pContext);
1138 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1140 ALCcontext *pContext;
1141 ALsource *Source;
1143 pContext = GetContextSuspended();
1144 if(!pContext) return;
1146 if(plValue1 && plValue2 && plValue3)
1148 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1150 switch(eParam)
1152 case AL_POSITION:
1153 *plValue1 = (ALint)Source->vPosition[0];
1154 *plValue2 = (ALint)Source->vPosition[1];
1155 *plValue3 = (ALint)Source->vPosition[2];
1156 break;
1158 case AL_VELOCITY:
1159 *plValue1 = (ALint)Source->vVelocity[0];
1160 *plValue2 = (ALint)Source->vVelocity[1];
1161 *plValue3 = (ALint)Source->vVelocity[2];
1162 break;
1164 case AL_DIRECTION:
1165 *plValue1 = (ALint)Source->vOrientation[0];
1166 *plValue2 = (ALint)Source->vOrientation[1];
1167 *plValue3 = (ALint)Source->vOrientation[2];
1168 break;
1170 default:
1171 alSetError(pContext, AL_INVALID_ENUM);
1172 break;
1175 else
1176 alSetError(pContext, AL_INVALID_NAME);
1178 else
1179 alSetError(pContext, AL_INVALID_VALUE);
1181 ProcessContext(pContext);
1185 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1187 ALCcontext *pContext;
1188 ALsource *Source;
1189 ALdouble Offsets[2];
1190 ALdouble updateLen;
1192 pContext = GetContextSuspended();
1193 if(!pContext) return;
1195 if(plValues)
1197 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1199 switch(eParam)
1201 case AL_SOURCE_RELATIVE:
1202 case AL_CONE_INNER_ANGLE:
1203 case AL_CONE_OUTER_ANGLE:
1204 case AL_LOOPING:
1205 case AL_BUFFER:
1206 case AL_SOURCE_STATE:
1207 case AL_BUFFERS_QUEUED:
1208 case AL_BUFFERS_PROCESSED:
1209 case AL_SEC_OFFSET:
1210 case AL_SAMPLE_OFFSET:
1211 case AL_BYTE_OFFSET:
1212 case AL_MAX_DISTANCE:
1213 case AL_ROLLOFF_FACTOR:
1214 case AL_DOPPLER_FACTOR:
1215 case AL_REFERENCE_DISTANCE:
1216 case AL_SOURCE_TYPE:
1217 case AL_DIRECT_FILTER:
1218 case AL_DIRECT_FILTER_GAINHF_AUTO:
1219 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1220 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1221 case AL_DISTANCE_MODEL:
1222 alGetSourcei(source, eParam, plValues);
1223 break;
1225 case AL_POSITION:
1226 case AL_VELOCITY:
1227 case AL_DIRECTION:
1228 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1229 break;
1231 case AL_SAMPLE_RW_OFFSETS_SOFT:
1232 case AL_BYTE_RW_OFFSETS_SOFT:
1233 updateLen = (ALdouble)pContext->Device->UpdateSize /
1234 pContext->Device->Frequency;
1235 GetSourceOffset(Source, eParam, Offsets, updateLen);
1236 plValues[0] = (ALint)Offsets[0];
1237 plValues[1] = (ALint)Offsets[1];
1238 break;
1240 default:
1241 alSetError(pContext, AL_INVALID_ENUM);
1242 break;
1245 else
1246 alSetError(pContext, AL_INVALID_NAME);
1248 else
1249 alSetError(pContext, AL_INVALID_VALUE);
1251 ProcessContext(pContext);
1255 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1257 alSourcePlayv(1, &source);
1260 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1262 ALCcontext *Context;
1263 ALsource *Source;
1264 ALbufferlistitem *BufferList;
1265 ALsizei i, j;
1267 Context = GetContextSuspended();
1268 if(!Context) return;
1270 if(n < 0)
1272 alSetError(Context, AL_INVALID_VALUE);
1273 goto done;
1275 if(n > 0 && !sources)
1277 alSetError(Context, AL_INVALID_VALUE);
1278 goto done;
1281 // Check that all the Sources are valid
1282 for(i = 0;i < n;i++)
1284 if(!LookupSource(Context->SourceMap, sources[i]))
1286 alSetError(Context, AL_INVALID_NAME);
1287 goto done;
1291 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1293 void *temp = NULL;
1294 ALsizei newcount;
1296 newcount = Context->MaxActiveSources << 1;
1297 if(newcount > 0)
1298 temp = realloc(Context->ActiveSources,
1299 sizeof(*Context->ActiveSources) * newcount);
1300 if(!temp)
1302 alSetError(Context, AL_OUT_OF_MEMORY);
1303 goto done;
1306 Context->ActiveSources = temp;
1307 Context->MaxActiveSources = newcount;
1310 for(i = 0;i < n;i++)
1312 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1314 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1315 BufferList = Source->queue;
1316 while(BufferList)
1318 if(BufferList->buffer != NULL && BufferList->buffer->size)
1319 break;
1320 BufferList = BufferList->next;
1323 if(!BufferList)
1325 Source->BuffersPlayed = Source->BuffersInQueue;
1326 continue;
1329 if(Source->state != AL_PAUSED)
1331 Source->state = AL_PLAYING;
1332 Source->position = 0;
1333 Source->position_fraction = 0;
1334 Source->BuffersPlayed = 0;
1336 Source->Buffer = Source->queue->buffer;
1338 else
1339 Source->state = AL_PLAYING;
1341 // Check if an Offset has been set
1342 if(Source->lOffset)
1343 ApplyOffset(Source);
1345 // If device is disconnected, go right to stopped
1346 if(!Context->Device->Connected)
1348 Source->state = AL_STOPPED;
1349 Source->BuffersPlayed = Source->BuffersInQueue;
1350 Source->position = 0;
1351 Source->position_fraction = 0;
1353 else
1355 for(j = 0;j < Context->ActiveSourceCount;j++)
1357 if(Context->ActiveSources[j] == Source)
1358 break;
1360 if(j == Context->ActiveSourceCount)
1361 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1365 done:
1366 ProcessContext(Context);
1369 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1371 alSourcePausev(1, &source);
1374 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1376 ALCcontext *Context;
1377 ALsource *Source;
1378 ALsizei i;
1380 Context = GetContextSuspended();
1381 if(!Context) return;
1383 if(n < 0)
1385 alSetError(Context, AL_INVALID_VALUE);
1386 goto done;
1388 if(n > 0 && !sources)
1390 alSetError(Context, AL_INVALID_VALUE);
1391 goto done;
1394 // Check all the Sources are valid
1395 for(i = 0;i < n;i++)
1397 if(!LookupSource(Context->SourceMap, sources[i]))
1399 alSetError(Context, AL_INVALID_NAME);
1400 goto done;
1404 for(i = 0;i < n;i++)
1406 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1407 if(Source->state == AL_PLAYING)
1408 Source->state = AL_PAUSED;
1411 done:
1412 ProcessContext(Context);
1415 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1417 alSourceStopv(1, &source);
1420 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1422 ALCcontext *Context;
1423 ALsource *Source;
1424 ALsizei i;
1426 Context = GetContextSuspended();
1427 if(!Context) return;
1429 if(n < 0)
1431 alSetError(Context, AL_INVALID_VALUE);
1432 goto done;
1434 if(n > 0 && !sources)
1436 alSetError(Context, AL_INVALID_VALUE);
1437 goto done;
1440 // Check all the Sources are valid
1441 for(i = 0;i < n;i++)
1443 if(!LookupSource(Context->SourceMap, sources[i]))
1445 alSetError(Context, AL_INVALID_NAME);
1446 goto done;
1450 for(i = 0;i < n;i++)
1452 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1453 if(Source->state != AL_INITIAL)
1455 Source->state = AL_STOPPED;
1456 Source->BuffersPlayed = Source->BuffersInQueue;
1458 Source->lOffset = 0;
1461 done:
1462 ProcessContext(Context);
1465 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1467 alSourceRewindv(1, &source);
1470 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1472 ALCcontext *Context;
1473 ALsource *Source;
1474 ALsizei i;
1476 Context = GetContextSuspended();
1477 if(!Context) return;
1479 if(n < 0)
1481 alSetError(Context, AL_INVALID_VALUE);
1482 goto done;
1484 if(n > 0 && !sources)
1486 alSetError(Context, AL_INVALID_VALUE);
1487 goto done;
1490 // Check all the Sources are valid
1491 for(i = 0;i < n;i++)
1493 if(!LookupSource(Context->SourceMap, sources[i]))
1495 alSetError(Context, AL_INVALID_NAME);
1496 goto done;
1500 for(i = 0;i < n;i++)
1502 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1503 if(Source->state != AL_INITIAL)
1505 Source->state = AL_INITIAL;
1506 Source->position = 0;
1507 Source->position_fraction = 0;
1508 Source->BuffersPlayed = 0;
1509 if(Source->queue)
1510 Source->Buffer = Source->queue->buffer;
1512 Source->lOffset = 0;
1515 done:
1516 ProcessContext(Context);
1520 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1522 ALCcontext *Context;
1523 ALCdevice *device;
1524 ALsource *Source;
1525 ALbuffer *buffer;
1526 ALsizei i;
1527 ALbufferlistitem *BufferListStart;
1528 ALbufferlistitem *BufferList;
1529 ALint Frequency;
1530 ALint Format;
1532 if(n == 0)
1533 return;
1535 Context = GetContextSuspended();
1536 if(!Context) return;
1538 if(n < 0)
1540 alSetError(Context, AL_INVALID_VALUE);
1541 goto done;
1544 // Check that all buffers are valid or zero and that the source is valid
1546 // Check that this is a valid source
1547 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1549 alSetError(Context, AL_INVALID_NAME);
1550 goto done;
1553 // Check that this is not a STATIC Source
1554 if(Source->lSourceType == AL_STATIC)
1556 // Invalid Source Type (can't queue on a Static Source)
1557 alSetError(Context, AL_INVALID_OPERATION);
1558 goto done;
1561 device = Context->Device;
1563 Frequency = -1;
1564 Format = -1;
1566 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1567 BufferList = Source->queue;
1568 while(BufferList)
1570 if(BufferList->buffer)
1572 Frequency = BufferList->buffer->frequency;
1573 Format = BufferList->buffer->eOriginalFormat;
1574 break;
1576 BufferList = BufferList->next;
1579 for(i = 0;i < n;i++)
1581 if(!buffers[i])
1582 continue;
1584 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1586 alSetError(Context, AL_INVALID_NAME);
1587 goto done;
1590 if(Frequency == -1 && Format == -1)
1592 Frequency = buffer->frequency;
1593 Format = buffer->eOriginalFormat;
1595 if(aluChannelsFromFormat(buffer->format) == 1)
1596 Source->Update = CalcSourceParams;
1597 else
1598 Source->Update = CalcNonAttnSourceParams;
1600 Source->Mix = MixSource;
1602 Source->NeedsUpdate = AL_TRUE;
1604 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1606 alSetError(Context, AL_INVALID_OPERATION);
1607 goto done;
1611 // Change Source Type
1612 Source->lSourceType = AL_STREAMING;
1614 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1616 // All buffers are valid - so add them to the list
1617 BufferListStart = malloc(sizeof(ALbufferlistitem));
1618 BufferListStart->buffer = buffer;
1619 BufferListStart->next = NULL;
1621 // Increment reference counter for buffer
1622 if(buffer) buffer->refcount++;
1624 BufferList = BufferListStart;
1626 for(i = 1;i < n;i++)
1628 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1630 BufferList->next = malloc(sizeof(ALbufferlistitem));
1631 BufferList->next->buffer = buffer;
1632 BufferList->next->next = NULL;
1634 // Increment reference counter for buffer
1635 if(buffer) buffer->refcount++;
1637 BufferList = BufferList->next;
1640 if(Source->queue == NULL)
1642 Source->queue = BufferListStart;
1643 // Update Current Buffer
1644 Source->Buffer = BufferListStart->buffer;
1646 else
1648 // Find end of queue
1649 BufferList = Source->queue;
1650 while(BufferList->next != NULL)
1651 BufferList = BufferList->next;
1653 BufferList->next = BufferListStart;
1656 // Update number of buffers in queue
1657 Source->BuffersInQueue += n;
1659 done:
1660 ProcessContext(Context);
1664 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1665 // an array of buffer IDs that are to be filled with the names of the buffers removed
1666 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1668 ALCcontext *Context;
1669 ALsource *Source;
1670 ALsizei i;
1671 ALbufferlistitem *BufferList;
1673 if(n == 0)
1674 return;
1676 Context = GetContextSuspended();
1677 if(!Context) return;
1679 if(n < 0)
1681 alSetError(Context, AL_INVALID_VALUE);
1682 goto done;
1685 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1687 alSetError(Context, AL_INVALID_NAME);
1688 goto done;
1691 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1692 (ALuint)n > Source->BuffersPlayed)
1694 // Some buffers can't be unqueue because they have not been processed
1695 alSetError(Context, AL_INVALID_VALUE);
1696 goto done;
1699 for(i = 0;i < n;i++)
1701 BufferList = Source->queue;
1702 Source->queue = BufferList->next;
1704 if(BufferList->buffer)
1706 // Record name of buffer
1707 buffers[i] = BufferList->buffer->buffer;
1708 // Decrement buffer reference counter
1709 BufferList->buffer->refcount--;
1711 else
1712 buffers[i] = 0;
1714 // Release memory for buffer list item
1715 free(BufferList);
1716 Source->BuffersInQueue--;
1719 if(Source->state != AL_PLAYING)
1721 if(Source->queue)
1722 Source->Buffer = Source->queue->buffer;
1723 else
1724 Source->Buffer = NULL;
1726 Source->BuffersPlayed -= n;
1728 done:
1729 ProcessContext(Context);
1733 static ALvoid InitSourceParams(ALsource *Source)
1735 Source->flInnerAngle = 360.0f;
1736 Source->flOuterAngle = 360.0f;
1737 Source->flPitch = 1.0f;
1738 Source->vPosition[0] = 0.0f;
1739 Source->vPosition[1] = 0.0f;
1740 Source->vPosition[2] = 0.0f;
1741 Source->vOrientation[0] = 0.0f;
1742 Source->vOrientation[1] = 0.0f;
1743 Source->vOrientation[2] = 0.0f;
1744 Source->vVelocity[0] = 0.0f;
1745 Source->vVelocity[1] = 0.0f;
1746 Source->vVelocity[2] = 0.0f;
1747 Source->flRefDistance = 1.0f;
1748 Source->flMaxDistance = FLT_MAX;
1749 Source->flRollOffFactor = 1.0f;
1750 Source->bLooping = AL_FALSE;
1751 Source->flGain = 1.0f;
1752 Source->flMinGain = 0.0f;
1753 Source->flMaxGain = 1.0f;
1754 Source->flOuterGain = 0.0f;
1755 Source->OuterGainHF = 1.0f;
1757 Source->DryGainHFAuto = AL_TRUE;
1758 Source->WetGainAuto = AL_TRUE;
1759 Source->WetGainHFAuto = AL_TRUE;
1760 Source->AirAbsorptionFactor = 0.0f;
1761 Source->RoomRolloffFactor = 0.0f;
1762 Source->DopplerFactor = 1.0f;
1764 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1766 Source->Resampler = DefaultResampler;
1768 Source->state = AL_INITIAL;
1769 Source->lSourceType = AL_UNDETERMINED;
1771 Source->NeedsUpdate = AL_TRUE;
1773 Source->Buffer = NULL;
1778 GetSourceOffset
1780 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1781 The offset is relative to the start of the queue (not the start of the current buffer)
1783 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1785 ALbufferlistitem *BufferList;
1786 ALbuffer *Buffer = NULL;
1787 ALfloat BufferFreq;
1788 ALint Channels, Bytes;
1789 ALuint readPos, writePos;
1790 ALenum OriginalFormat;
1791 ALuint TotalBufferDataSize;
1792 ALuint i;
1794 // Find the first non-NULL Buffer in the Queue
1795 BufferList = Source->queue;
1796 while(BufferList)
1798 if(BufferList->buffer)
1800 Buffer = BufferList->buffer;
1801 break;
1803 BufferList = BufferList->next;
1806 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1808 offset[0] = 0.0;
1809 offset[1] = 0.0;
1810 return;
1813 // Get Current Buffer Size and frequency (in milliseconds)
1814 BufferFreq = (ALfloat)Buffer->frequency;
1815 OriginalFormat = Buffer->eOriginalFormat;
1816 Channels = aluChannelsFromFormat(Buffer->format);
1817 Bytes = aluBytesFromFormat(Buffer->format);
1819 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1820 readPos = Source->position * Channels * Bytes;
1821 // Add byte length of any processed buffers in the queue
1822 TotalBufferDataSize = 0;
1823 BufferList = Source->queue;
1824 for(i = 0;BufferList;i++)
1826 if(BufferList->buffer)
1828 if(i < Source->BuffersPlayed)
1829 readPos += BufferList->buffer->size;
1830 TotalBufferDataSize += BufferList->buffer->size;
1832 BufferList = BufferList->next;
1834 if(Source->state == AL_PLAYING)
1835 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1836 else
1837 writePos = readPos;
1839 if(Source->bLooping)
1841 readPos %= TotalBufferDataSize;
1842 writePos %= TotalBufferDataSize;
1844 else
1846 // Wrap positions back to 0
1847 if(readPos >= TotalBufferDataSize)
1848 readPos = 0;
1849 if(writePos >= TotalBufferDataSize)
1850 writePos = 0;
1853 switch(name)
1855 case AL_SEC_OFFSET:
1856 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1857 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1858 break;
1859 case AL_SAMPLE_OFFSET:
1860 case AL_SAMPLE_RW_OFFSETS_SOFT:
1861 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1862 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1863 break;
1864 case AL_BYTE_OFFSET:
1865 case AL_BYTE_RW_OFFSETS_SOFT:
1866 // Take into account the original format of the Buffer
1867 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1868 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1870 // Round down to nearest ADPCM block
1871 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1872 if(Source->state == AL_PLAYING)
1874 // Round up to nearest ADPCM block
1875 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1877 else
1878 offset[1] = offset[0];
1880 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1881 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1882 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1883 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1884 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1885 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1887 offset[0] = (ALdouble)(readPos / Bytes * 1);
1888 offset[1] = (ALdouble)(writePos / Bytes * 1);
1890 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1892 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1893 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1895 else if(OriginalFormat == AL_FORMAT_REAR8)
1897 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1898 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1900 else if(OriginalFormat == AL_FORMAT_REAR16)
1902 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1903 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1905 else if(OriginalFormat == AL_FORMAT_REAR32)
1907 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1908 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1910 else
1912 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1913 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1914 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1916 break;
1922 ApplyOffset
1924 Apply a playback offset to the Source. This function will update the queue (to correctly
1925 mark buffers as 'pending' or 'processed' depending upon the new offset.
1927 static ALboolean ApplyOffset(ALsource *Source)
1929 ALbufferlistitem *BufferList;
1930 ALbuffer *Buffer;
1931 ALint lBufferSize, lTotalBufferSize;
1932 ALint BuffersPlayed;
1933 ALint lByteOffset;
1935 // Get true byte offset
1936 lByteOffset = GetByteOffset(Source);
1938 // If the offset is invalid, don't apply it
1939 if(lByteOffset == -1)
1940 return AL_FALSE;
1942 // Sort out the queue (pending and processed states)
1943 BufferList = Source->queue;
1944 lTotalBufferSize = 0;
1945 BuffersPlayed = 0;
1947 while(BufferList)
1949 Buffer = BufferList->buffer;
1950 lBufferSize = Buffer ? Buffer->size : 0;
1952 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1954 // Offset is past this buffer so increment BuffersPlayed
1955 BuffersPlayed++;
1957 else if(lTotalBufferSize <= lByteOffset)
1959 // Offset is within this buffer
1960 // Set Current Buffer
1961 Source->Buffer = BufferList->buffer;
1962 Source->BuffersPlayed = BuffersPlayed;
1964 // SW Mixer Positions are in Samples
1965 Source->position = (lByteOffset - lTotalBufferSize) /
1966 aluFrameSizeFromFormat(Buffer->format);
1967 return AL_TRUE;
1970 // Increment the TotalBufferSize
1971 lTotalBufferSize += lBufferSize;
1973 // Move on to next buffer in the Queue
1974 BufferList = BufferList->next;
1976 // Offset is out of range of the buffer queue
1977 return AL_FALSE;
1982 GetByteOffset
1984 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1985 offset supplied by the application). This takes into account the fact that the buffer format
1986 may have been modifed by AL (e.g 8bit samples are converted to float)
1988 static ALint GetByteOffset(ALsource *Source)
1990 ALbuffer *Buffer = NULL;
1991 ALbufferlistitem *BufferList;
1992 ALdouble BufferFreq;
1993 ALint Channels, Bytes;
1994 ALint ByteOffset = -1;
1996 // Find the first non-NULL Buffer in the Queue
1997 BufferList = Source->queue;
1998 while(BufferList)
2000 if(BufferList->buffer)
2002 Buffer = BufferList->buffer;
2003 break;
2005 BufferList = BufferList->next;
2008 if(!Buffer)
2010 Source->lOffset = 0;
2011 return -1;
2014 BufferFreq = ((ALdouble)Buffer->frequency);
2015 Channels = aluChannelsFromFormat(Buffer->format);
2016 Bytes = aluBytesFromFormat(Buffer->format);
2018 // Determine the ByteOffset (and ensure it is block aligned)
2019 switch(Source->lOffsetType)
2021 case AL_BYTE_OFFSET:
2022 // Take into consideration the original format
2023 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2024 Channels);
2025 ByteOffset *= Channels * Bytes;
2026 break;
2028 case AL_SAMPLE_OFFSET:
2029 ByteOffset = Source->lOffset * Channels * Bytes;
2030 break;
2032 case AL_SEC_OFFSET:
2033 // Note - lOffset is internally stored as Milliseconds
2034 ByteOffset = (ALint)(Source->lOffset / 1000.0 * BufferFreq);
2035 ByteOffset *= Channels * Bytes;
2036 break;
2038 // Clear Offset
2039 Source->lOffset = 0;
2041 return ByteOffset;
2044 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2046 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2048 // Round down to nearest ADPCM block
2049 offset /= 36 * channels;
2050 // Multiply by compression rate (65 sample frames per block)
2051 offset *= 65;
2053 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2054 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2055 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2057 /* muLaw has 1 byte per sample */
2058 offset /= 1 * channels;
2060 else if(format == AL_FORMAT_REAR_MULAW)
2062 /* Rear is 2 channels */
2063 offset /= 1 * 2;
2065 else if(format == AL_FORMAT_REAR8)
2066 offset /= 1 * 2;
2067 else if(format == AL_FORMAT_REAR16)
2068 offset /= 2 * 2;
2069 else if(format == AL_FORMAT_REAR32)
2070 offset /= 4 * 2;
2071 else
2073 ALuint bytes = aluBytesFromFormat(format);
2074 offset /= bytes * channels;
2076 return offset;
2080 ALvoid ReleaseALSources(ALCcontext *Context)
2082 ALsizei pos;
2083 ALuint j;
2084 for(pos = 0;pos < Context->SourceMap.size;pos++)
2086 ALsource *temp = Context->SourceMap.array[pos].value;
2087 Context->SourceMap.array[pos].value = NULL;
2089 // For each buffer in the source's queue, decrement its reference counter and remove it
2090 while(temp->queue != NULL)
2092 ALbufferlistitem *BufferList = temp->queue;
2093 temp->queue = BufferList->next;
2095 if(BufferList->buffer != NULL)
2096 BufferList->buffer->refcount--;
2097 free(BufferList);
2100 for(j = 0;j < MAX_SENDS;++j)
2102 if(temp->Send[j].Slot)
2103 temp->Send[j].Slot->refcount--;
2104 temp->Send[j].Slot = NULL;
2107 // Release source structure
2108 ALTHUNK_REMOVEENTRY(temp->source);
2109 memset(temp, 0, sizeof(ALsource));
2110 free(temp);