Be less wave-in-specific in the winmm backend
[openal-soft.git] / OpenAL32 / alSource.c
blob440bd859ce67f11dd6ad997099a733aca2998230
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->state = AL_STOPPED;
1326 Source->BuffersPlayed = Source->BuffersInQueue;
1327 Source->position = 0;
1328 Source->position_fraction = 0;
1329 Source->lOffset = 0;
1330 continue;
1333 if(Source->state != AL_PAUSED)
1335 Source->state = AL_PLAYING;
1336 Source->position = 0;
1337 Source->position_fraction = 0;
1338 Source->BuffersPlayed = 0;
1340 Source->Buffer = Source->queue->buffer;
1342 else
1343 Source->state = AL_PLAYING;
1345 // Check if an Offset has been set
1346 if(Source->lOffset)
1347 ApplyOffset(Source);
1349 // If device is disconnected, go right to stopped
1350 if(!Context->Device->Connected)
1352 Source->state = AL_STOPPED;
1353 Source->BuffersPlayed = Source->BuffersInQueue;
1354 Source->position = 0;
1355 Source->position_fraction = 0;
1357 else
1359 for(j = 0;j < Context->ActiveSourceCount;j++)
1361 if(Context->ActiveSources[j] == Source)
1362 break;
1364 if(j == Context->ActiveSourceCount)
1365 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1369 done:
1370 ProcessContext(Context);
1373 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1375 alSourcePausev(1, &source);
1378 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1380 ALCcontext *Context;
1381 ALsource *Source;
1382 ALsizei i;
1384 Context = GetContextSuspended();
1385 if(!Context) return;
1387 if(n < 0)
1389 alSetError(Context, AL_INVALID_VALUE);
1390 goto done;
1392 if(n > 0 && !sources)
1394 alSetError(Context, AL_INVALID_VALUE);
1395 goto done;
1398 // Check all the Sources are valid
1399 for(i = 0;i < n;i++)
1401 if(!LookupSource(Context->SourceMap, sources[i]))
1403 alSetError(Context, AL_INVALID_NAME);
1404 goto done;
1408 for(i = 0;i < n;i++)
1410 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1411 if(Source->state == AL_PLAYING)
1412 Source->state = AL_PAUSED;
1415 done:
1416 ProcessContext(Context);
1419 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1421 alSourceStopv(1, &source);
1424 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1426 ALCcontext *Context;
1427 ALsource *Source;
1428 ALsizei i;
1430 Context = GetContextSuspended();
1431 if(!Context) return;
1433 if(n < 0)
1435 alSetError(Context, AL_INVALID_VALUE);
1436 goto done;
1438 if(n > 0 && !sources)
1440 alSetError(Context, AL_INVALID_VALUE);
1441 goto done;
1444 // Check all the Sources are valid
1445 for(i = 0;i < n;i++)
1447 if(!LookupSource(Context->SourceMap, sources[i]))
1449 alSetError(Context, AL_INVALID_NAME);
1450 goto done;
1454 for(i = 0;i < n;i++)
1456 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1457 if(Source->state != AL_INITIAL)
1459 Source->state = AL_STOPPED;
1460 Source->BuffersPlayed = Source->BuffersInQueue;
1462 Source->lOffset = 0;
1465 done:
1466 ProcessContext(Context);
1469 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1471 alSourceRewindv(1, &source);
1474 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1476 ALCcontext *Context;
1477 ALsource *Source;
1478 ALsizei i;
1480 Context = GetContextSuspended();
1481 if(!Context) return;
1483 if(n < 0)
1485 alSetError(Context, AL_INVALID_VALUE);
1486 goto done;
1488 if(n > 0 && !sources)
1490 alSetError(Context, AL_INVALID_VALUE);
1491 goto done;
1494 // Check all the Sources are valid
1495 for(i = 0;i < n;i++)
1497 if(!LookupSource(Context->SourceMap, sources[i]))
1499 alSetError(Context, AL_INVALID_NAME);
1500 goto done;
1504 for(i = 0;i < n;i++)
1506 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1507 if(Source->state != AL_INITIAL)
1509 Source->state = AL_INITIAL;
1510 Source->position = 0;
1511 Source->position_fraction = 0;
1512 Source->BuffersPlayed = 0;
1513 if(Source->queue)
1514 Source->Buffer = Source->queue->buffer;
1516 Source->lOffset = 0;
1519 done:
1520 ProcessContext(Context);
1524 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1526 ALCcontext *Context;
1527 ALCdevice *device;
1528 ALsource *Source;
1529 ALbuffer *buffer;
1530 ALsizei i;
1531 ALbufferlistitem *BufferListStart;
1532 ALbufferlistitem *BufferList;
1533 ALint Frequency;
1534 ALint Format;
1536 if(n == 0)
1537 return;
1539 Context = GetContextSuspended();
1540 if(!Context) return;
1542 if(n < 0)
1544 alSetError(Context, AL_INVALID_VALUE);
1545 goto done;
1548 // Check that all buffers are valid or zero and that the source is valid
1550 // Check that this is a valid source
1551 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1553 alSetError(Context, AL_INVALID_NAME);
1554 goto done;
1557 // Check that this is not a STATIC Source
1558 if(Source->lSourceType == AL_STATIC)
1560 // Invalid Source Type (can't queue on a Static Source)
1561 alSetError(Context, AL_INVALID_OPERATION);
1562 goto done;
1565 device = Context->Device;
1567 Frequency = -1;
1568 Format = -1;
1570 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1571 BufferList = Source->queue;
1572 while(BufferList)
1574 if(BufferList->buffer)
1576 Frequency = BufferList->buffer->frequency;
1577 Format = BufferList->buffer->eOriginalFormat;
1578 break;
1580 BufferList = BufferList->next;
1583 for(i = 0;i < n;i++)
1585 if(!buffers[i])
1586 continue;
1588 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1590 alSetError(Context, AL_INVALID_NAME);
1591 goto done;
1594 if(Frequency == -1 && Format == -1)
1596 Frequency = buffer->frequency;
1597 Format = buffer->eOriginalFormat;
1599 if(aluChannelsFromFormat(buffer->format) == 1)
1600 Source->Update = CalcSourceParams;
1601 else
1602 Source->Update = CalcNonAttnSourceParams;
1604 Source->Mix = MixSource;
1606 Source->NeedsUpdate = AL_TRUE;
1608 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1610 alSetError(Context, AL_INVALID_OPERATION);
1611 goto done;
1615 // Change Source Type
1616 Source->lSourceType = AL_STREAMING;
1618 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1620 // All buffers are valid - so add them to the list
1621 BufferListStart = malloc(sizeof(ALbufferlistitem));
1622 BufferListStart->buffer = buffer;
1623 BufferListStart->next = NULL;
1625 // Increment reference counter for buffer
1626 if(buffer) buffer->refcount++;
1628 BufferList = BufferListStart;
1630 for(i = 1;i < n;i++)
1632 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1634 BufferList->next = malloc(sizeof(ALbufferlistitem));
1635 BufferList->next->buffer = buffer;
1636 BufferList->next->next = NULL;
1638 // Increment reference counter for buffer
1639 if(buffer) buffer->refcount++;
1641 BufferList = BufferList->next;
1644 if(Source->queue == NULL)
1646 Source->queue = BufferListStart;
1647 // Update Current Buffer
1648 Source->Buffer = BufferListStart->buffer;
1650 else
1652 // Find end of queue
1653 BufferList = Source->queue;
1654 while(BufferList->next != NULL)
1655 BufferList = BufferList->next;
1657 BufferList->next = BufferListStart;
1660 // Update number of buffers in queue
1661 Source->BuffersInQueue += n;
1663 done:
1664 ProcessContext(Context);
1668 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1669 // an array of buffer IDs that are to be filled with the names of the buffers removed
1670 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1672 ALCcontext *Context;
1673 ALsource *Source;
1674 ALsizei i;
1675 ALbufferlistitem *BufferList;
1677 if(n == 0)
1678 return;
1680 Context = GetContextSuspended();
1681 if(!Context) return;
1683 if(n < 0)
1685 alSetError(Context, AL_INVALID_VALUE);
1686 goto done;
1689 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 goto done;
1695 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1696 (ALuint)n > Source->BuffersPlayed)
1698 // Some buffers can't be unqueue because they have not been processed
1699 alSetError(Context, AL_INVALID_VALUE);
1700 goto done;
1703 for(i = 0;i < n;i++)
1705 BufferList = Source->queue;
1706 Source->queue = BufferList->next;
1708 if(BufferList->buffer)
1710 // Record name of buffer
1711 buffers[i] = BufferList->buffer->buffer;
1712 // Decrement buffer reference counter
1713 BufferList->buffer->refcount--;
1715 else
1716 buffers[i] = 0;
1718 // Release memory for buffer list item
1719 free(BufferList);
1720 Source->BuffersInQueue--;
1723 if(Source->state != AL_PLAYING)
1725 if(Source->queue)
1726 Source->Buffer = Source->queue->buffer;
1727 else
1728 Source->Buffer = NULL;
1730 Source->BuffersPlayed -= n;
1732 done:
1733 ProcessContext(Context);
1737 static ALvoid InitSourceParams(ALsource *Source)
1739 Source->flInnerAngle = 360.0f;
1740 Source->flOuterAngle = 360.0f;
1741 Source->flPitch = 1.0f;
1742 Source->vPosition[0] = 0.0f;
1743 Source->vPosition[1] = 0.0f;
1744 Source->vPosition[2] = 0.0f;
1745 Source->vOrientation[0] = 0.0f;
1746 Source->vOrientation[1] = 0.0f;
1747 Source->vOrientation[2] = 0.0f;
1748 Source->vVelocity[0] = 0.0f;
1749 Source->vVelocity[1] = 0.0f;
1750 Source->vVelocity[2] = 0.0f;
1751 Source->flRefDistance = 1.0f;
1752 Source->flMaxDistance = FLT_MAX;
1753 Source->flRollOffFactor = 1.0f;
1754 Source->bLooping = AL_FALSE;
1755 Source->flGain = 1.0f;
1756 Source->flMinGain = 0.0f;
1757 Source->flMaxGain = 1.0f;
1758 Source->flOuterGain = 0.0f;
1759 Source->OuterGainHF = 1.0f;
1761 Source->DryGainHFAuto = AL_TRUE;
1762 Source->WetGainAuto = AL_TRUE;
1763 Source->WetGainHFAuto = AL_TRUE;
1764 Source->AirAbsorptionFactor = 0.0f;
1765 Source->RoomRolloffFactor = 0.0f;
1766 Source->DopplerFactor = 1.0f;
1768 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1770 Source->Resampler = DefaultResampler;
1772 Source->state = AL_INITIAL;
1773 Source->lSourceType = AL_UNDETERMINED;
1775 Source->NeedsUpdate = AL_TRUE;
1777 Source->Buffer = NULL;
1782 GetSourceOffset
1784 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1785 The offset is relative to the start of the queue (not the start of the current buffer)
1787 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1789 ALbufferlistitem *BufferList;
1790 ALbuffer *Buffer = NULL;
1791 ALfloat BufferFreq;
1792 ALint Channels, Bytes;
1793 ALuint readPos, writePos;
1794 ALenum OriginalFormat;
1795 ALuint TotalBufferDataSize;
1796 ALuint i;
1798 // Find the first non-NULL Buffer in the Queue
1799 BufferList = Source->queue;
1800 while(BufferList)
1802 if(BufferList->buffer)
1804 Buffer = BufferList->buffer;
1805 break;
1807 BufferList = BufferList->next;
1810 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1812 offset[0] = 0.0;
1813 offset[1] = 0.0;
1814 return;
1817 // Get Current Buffer Size and frequency (in milliseconds)
1818 BufferFreq = (ALfloat)Buffer->frequency;
1819 OriginalFormat = Buffer->eOriginalFormat;
1820 Channels = aluChannelsFromFormat(Buffer->format);
1821 Bytes = aluBytesFromFormat(Buffer->format);
1823 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1824 readPos = Source->position * Channels * Bytes;
1825 // Add byte length of any processed buffers in the queue
1826 TotalBufferDataSize = 0;
1827 BufferList = Source->queue;
1828 for(i = 0;BufferList;i++)
1830 if(BufferList->buffer)
1832 if(i < Source->BuffersPlayed)
1833 readPos += BufferList->buffer->size;
1834 TotalBufferDataSize += BufferList->buffer->size;
1836 BufferList = BufferList->next;
1838 if(Source->state == AL_PLAYING)
1839 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1840 else
1841 writePos = readPos;
1843 if(Source->bLooping)
1845 readPos %= TotalBufferDataSize;
1846 writePos %= TotalBufferDataSize;
1848 else
1850 // Wrap positions back to 0
1851 if(readPos >= TotalBufferDataSize)
1852 readPos = 0;
1853 if(writePos >= TotalBufferDataSize)
1854 writePos = 0;
1857 switch(name)
1859 case AL_SEC_OFFSET:
1860 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1861 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1862 break;
1863 case AL_SAMPLE_OFFSET:
1864 case AL_SAMPLE_RW_OFFSETS_SOFT:
1865 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1866 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1867 break;
1868 case AL_BYTE_OFFSET:
1869 case AL_BYTE_RW_OFFSETS_SOFT:
1870 // Take into account the original format of the Buffer
1871 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1872 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1874 // Round down to nearest ADPCM block
1875 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1876 if(Source->state == AL_PLAYING)
1878 // Round up to nearest ADPCM block
1879 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1881 else
1882 offset[1] = offset[0];
1884 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1885 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1886 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1887 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1888 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1889 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1891 offset[0] = (ALdouble)(readPos / Bytes * 1);
1892 offset[1] = (ALdouble)(writePos / Bytes * 1);
1894 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1896 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1897 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1899 else if(OriginalFormat == AL_FORMAT_REAR8)
1901 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1902 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1904 else if(OriginalFormat == AL_FORMAT_REAR16)
1906 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1907 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1909 else if(OriginalFormat == AL_FORMAT_REAR32)
1911 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1912 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1914 else
1916 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1917 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1918 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1920 break;
1926 ApplyOffset
1928 Apply a playback offset to the Source. This function will update the queue (to correctly
1929 mark buffers as 'pending' or 'processed' depending upon the new offset.
1931 static ALboolean ApplyOffset(ALsource *Source)
1933 ALbufferlistitem *BufferList;
1934 ALbuffer *Buffer;
1935 ALint lBufferSize, lTotalBufferSize;
1936 ALint BuffersPlayed;
1937 ALint lByteOffset;
1939 // Get true byte offset
1940 lByteOffset = GetByteOffset(Source);
1942 // If the offset is invalid, don't apply it
1943 if(lByteOffset == -1)
1944 return AL_FALSE;
1946 // Sort out the queue (pending and processed states)
1947 BufferList = Source->queue;
1948 lTotalBufferSize = 0;
1949 BuffersPlayed = 0;
1951 while(BufferList)
1953 Buffer = BufferList->buffer;
1954 lBufferSize = Buffer ? Buffer->size : 0;
1956 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1958 // Offset is past this buffer so increment BuffersPlayed
1959 BuffersPlayed++;
1961 else if(lTotalBufferSize <= lByteOffset)
1963 // Offset is within this buffer
1964 // Set Current Buffer
1965 Source->Buffer = BufferList->buffer;
1966 Source->BuffersPlayed = BuffersPlayed;
1968 // SW Mixer Positions are in Samples
1969 Source->position = (lByteOffset - lTotalBufferSize) /
1970 aluFrameSizeFromFormat(Buffer->format);
1971 return AL_TRUE;
1974 // Increment the TotalBufferSize
1975 lTotalBufferSize += lBufferSize;
1977 // Move on to next buffer in the Queue
1978 BufferList = BufferList->next;
1980 // Offset is out of range of the buffer queue
1981 return AL_FALSE;
1986 GetByteOffset
1988 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1989 offset supplied by the application). This takes into account the fact that the buffer format
1990 may have been modifed by AL (e.g 8bit samples are converted to float)
1992 static ALint GetByteOffset(ALsource *Source)
1994 ALbuffer *Buffer = NULL;
1995 ALbufferlistitem *BufferList;
1996 ALdouble BufferFreq;
1997 ALint Channels, Bytes;
1998 ALint ByteOffset = -1;
2000 // Find the first non-NULL Buffer in the Queue
2001 BufferList = Source->queue;
2002 while(BufferList)
2004 if(BufferList->buffer)
2006 Buffer = BufferList->buffer;
2007 break;
2009 BufferList = BufferList->next;
2012 if(!Buffer)
2014 Source->lOffset = 0;
2015 return -1;
2018 BufferFreq = ((ALdouble)Buffer->frequency);
2019 Channels = aluChannelsFromFormat(Buffer->format);
2020 Bytes = aluBytesFromFormat(Buffer->format);
2022 // Determine the ByteOffset (and ensure it is block aligned)
2023 switch(Source->lOffsetType)
2025 case AL_BYTE_OFFSET:
2026 // Take into consideration the original format
2027 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2028 Channels);
2029 ByteOffset *= Channels * Bytes;
2030 break;
2032 case AL_SAMPLE_OFFSET:
2033 ByteOffset = Source->lOffset * Channels * Bytes;
2034 break;
2036 case AL_SEC_OFFSET:
2037 // Note - lOffset is internally stored as Milliseconds
2038 ByteOffset = (ALint)(Source->lOffset / 1000.0 * BufferFreq);
2039 ByteOffset *= Channels * Bytes;
2040 break;
2042 // Clear Offset
2043 Source->lOffset = 0;
2045 return ByteOffset;
2048 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2050 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2052 // Round down to nearest ADPCM block
2053 offset /= 36 * channels;
2054 // Multiply by compression rate (65 sample frames per block)
2055 offset *= 65;
2057 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2058 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2059 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2061 /* muLaw has 1 byte per sample */
2062 offset /= 1 * channels;
2064 else if(format == AL_FORMAT_REAR_MULAW)
2066 /* Rear is 2 channels */
2067 offset /= 1 * 2;
2069 else if(format == AL_FORMAT_REAR8)
2070 offset /= 1 * 2;
2071 else if(format == AL_FORMAT_REAR16)
2072 offset /= 2 * 2;
2073 else if(format == AL_FORMAT_REAR32)
2074 offset /= 4 * 2;
2075 else
2077 ALuint bytes = aluBytesFromFormat(format);
2078 offset /= bytes * channels;
2080 return offset;
2084 ALvoid ReleaseALSources(ALCcontext *Context)
2086 ALsizei pos;
2087 ALuint j;
2088 for(pos = 0;pos < Context->SourceMap.size;pos++)
2090 ALsource *temp = Context->SourceMap.array[pos].value;
2091 Context->SourceMap.array[pos].value = NULL;
2093 // For each buffer in the source's queue, decrement its reference counter and remove it
2094 while(temp->queue != NULL)
2096 ALbufferlistitem *BufferList = temp->queue;
2097 temp->queue = BufferList->next;
2099 if(BufferList->buffer != NULL)
2100 BufferList->buffer->refcount--;
2101 free(BufferList);
2104 for(j = 0;j < MAX_SENDS;++j)
2106 if(temp->Send[j].Slot)
2107 temp->Send[j].Slot->refcount--;
2108 temp->Send[j].Slot = NULL;
2111 // Release source structure
2112 ALTHUNK_REMOVEENTRY(temp->source);
2113 memset(temp, 0, sizeof(ALsource));
2114 free(temp);