Make the buffer queue a double-linked list
[openal-soft.git] / OpenAL32 / alSource.c
blob4182ee159e6122ccec730015cb9e655e0931a27b
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;
553 BufferListItem->prev = NULL;
555 Source->queue = BufferListItem;
556 Source->BuffersInQueue = 1;
558 if(aluChannelsFromFormat(buffer->format) == 1)
559 Source->Update = CalcSourceParams;
560 else
561 Source->Update = CalcNonAttnSourceParams;
563 Source->Mix = MixSource;
565 // Increment reference counter for buffer
566 buffer->refcount++;
568 else
570 // Source is now in UNDETERMINED mode
571 Source->lSourceType = AL_UNDETERMINED;
573 Source->BuffersPlayed = 0;
575 // Update AL_BUFFER parameter
576 Source->Buffer = buffer;
577 Source->NeedsUpdate = AL_TRUE;
579 else
580 alSetError(pContext, AL_INVALID_VALUE);
582 else
583 alSetError(pContext, AL_INVALID_OPERATION);
584 break;
586 case AL_SOURCE_STATE:
587 // Query only
588 alSetError(pContext, AL_INVALID_OPERATION);
589 break;
591 case AL_SEC_OFFSET:
592 case AL_SAMPLE_OFFSET:
593 case AL_BYTE_OFFSET:
594 if(lValue >= 0)
596 Source->lOffsetType = eParam;
598 // Store Offset (convert Seconds into Milliseconds)
599 if(eParam == AL_SEC_OFFSET)
600 Source->lOffset = lValue * 1000;
601 else
602 Source->lOffset = lValue;
604 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
606 if(ApplyOffset(Source) == AL_FALSE)
607 alSetError(pContext, AL_INVALID_VALUE);
610 else
611 alSetError(pContext, AL_INVALID_VALUE);
612 break;
614 case AL_DIRECT_FILTER: {
615 ALfilter *filter = NULL;
617 if(lValue == 0 ||
618 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
620 if(!filter)
622 Source->DirectFilter.type = AL_FILTER_NULL;
623 Source->DirectFilter.filter = 0;
625 else
626 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
627 Source->NeedsUpdate = AL_TRUE;
629 else
630 alSetError(pContext, AL_INVALID_VALUE);
631 } break;
633 case AL_DIRECT_FILTER_GAINHF_AUTO:
634 if(lValue == AL_TRUE || lValue == AL_FALSE)
636 Source->DryGainHFAuto = lValue;
637 Source->NeedsUpdate = AL_TRUE;
639 else
640 alSetError(pContext, AL_INVALID_VALUE);
641 break;
643 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
644 if(lValue == AL_TRUE || lValue == AL_FALSE)
646 Source->WetGainAuto = lValue;
647 Source->NeedsUpdate = AL_TRUE;
649 else
650 alSetError(pContext, AL_INVALID_VALUE);
651 break;
653 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
654 if(lValue == AL_TRUE || lValue == AL_FALSE)
656 Source->WetGainHFAuto = lValue;
657 Source->NeedsUpdate = AL_TRUE;
659 else
660 alSetError(pContext, AL_INVALID_VALUE);
661 break;
663 case AL_DISTANCE_MODEL:
664 if(lValue == AL_NONE ||
665 lValue == AL_INVERSE_DISTANCE ||
666 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
667 lValue == AL_LINEAR_DISTANCE ||
668 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
669 lValue == AL_EXPONENT_DISTANCE ||
670 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
672 Source->DistanceModel = lValue;
673 if(pContext->SourceDistanceModel)
674 Source->NeedsUpdate = AL_TRUE;
676 else
677 alSetError(pContext, AL_INVALID_VALUE);
678 break;
680 default:
681 alSetError(pContext, AL_INVALID_ENUM);
682 break;
685 else
686 alSetError(pContext, AL_INVALID_NAME);
688 ProcessContext(pContext);
692 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
694 ALCcontext *pContext;
695 ALsource *Source;
697 pContext = GetContextSuspended();
698 if(!pContext) return;
700 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
702 ALCdevice *device = pContext->Device;
704 switch (eParam)
706 case AL_POSITION:
707 case AL_VELOCITY:
708 case AL_DIRECTION:
709 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
710 break;
712 case AL_AUXILIARY_SEND_FILTER: {
713 ALeffectslot *ALEffectSlot = NULL;
714 ALfilter *ALFilter = NULL;
716 if((ALuint)lValue2 < device->NumAuxSends &&
717 (lValue1 == 0 ||
718 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
719 (lValue3 == 0 ||
720 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
722 /* Release refcount on the previous slot, and add one for
723 * the new slot */
724 if(Source->Send[lValue2].Slot)
725 Source->Send[lValue2].Slot->refcount--;
726 Source->Send[lValue2].Slot = ALEffectSlot;
727 if(Source->Send[lValue2].Slot)
728 Source->Send[lValue2].Slot->refcount++;
730 if(!ALFilter)
732 /* Disable filter */
733 Source->Send[lValue2].WetFilter.type = 0;
734 Source->Send[lValue2].WetFilter.filter = 0;
736 else
737 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
738 Source->NeedsUpdate = AL_TRUE;
740 else
741 alSetError(pContext, AL_INVALID_VALUE);
742 } break;
744 default:
745 alSetError(pContext, AL_INVALID_ENUM);
746 break;
749 else
750 alSetError(pContext, AL_INVALID_NAME);
752 ProcessContext(pContext);
756 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
758 ALCcontext *pContext;
760 pContext = GetContextSuspended();
761 if(!pContext) return;
763 if(plValues)
765 if(LookupSource(pContext->SourceMap, source) != NULL)
767 switch(eParam)
769 case AL_SOURCE_RELATIVE:
770 case AL_CONE_INNER_ANGLE:
771 case AL_CONE_OUTER_ANGLE:
772 case AL_LOOPING:
773 case AL_BUFFER:
774 case AL_SOURCE_STATE:
775 case AL_SEC_OFFSET:
776 case AL_SAMPLE_OFFSET:
777 case AL_BYTE_OFFSET:
778 case AL_MAX_DISTANCE:
779 case AL_ROLLOFF_FACTOR:
780 case AL_REFERENCE_DISTANCE:
781 case AL_DIRECT_FILTER:
782 case AL_DIRECT_FILTER_GAINHF_AUTO:
783 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
784 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
785 case AL_DISTANCE_MODEL:
786 alSourcei(source, eParam, plValues[0]);
787 break;
789 case AL_POSITION:
790 case AL_VELOCITY:
791 case AL_DIRECTION:
792 case AL_AUXILIARY_SEND_FILTER:
793 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
794 break;
796 default:
797 alSetError(pContext, AL_INVALID_ENUM);
798 break;
801 else
802 alSetError(pContext, AL_INVALID_NAME);
804 else
805 alSetError(pContext, AL_INVALID_VALUE);
807 ProcessContext(pContext);
811 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
813 ALCcontext *pContext;
814 ALsource *Source;
815 ALdouble Offsets[2];
816 ALdouble updateLen;
818 pContext = GetContextSuspended();
819 if(!pContext) return;
821 if(pflValue)
823 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
825 switch(eParam)
827 case AL_PITCH:
828 *pflValue = Source->flPitch;
829 break;
831 case AL_GAIN:
832 *pflValue = Source->flGain;
833 break;
835 case AL_MIN_GAIN:
836 *pflValue = Source->flMinGain;
837 break;
839 case AL_MAX_GAIN:
840 *pflValue = Source->flMaxGain;
841 break;
843 case AL_MAX_DISTANCE:
844 *pflValue = Source->flMaxDistance;
845 break;
847 case AL_ROLLOFF_FACTOR:
848 *pflValue = Source->flRollOffFactor;
849 break;
851 case AL_CONE_OUTER_GAIN:
852 *pflValue = Source->flOuterGain;
853 break;
855 case AL_CONE_OUTER_GAINHF:
856 *pflValue = Source->OuterGainHF;
857 break;
859 case AL_SEC_OFFSET:
860 case AL_SAMPLE_OFFSET:
861 case AL_BYTE_OFFSET:
862 updateLen = (ALdouble)pContext->Device->UpdateSize /
863 pContext->Device->Frequency;
864 GetSourceOffset(Source, eParam, Offsets, updateLen);
865 *pflValue = Offsets[0];
866 break;
868 case AL_CONE_INNER_ANGLE:
869 *pflValue = Source->flInnerAngle;
870 break;
872 case AL_CONE_OUTER_ANGLE:
873 *pflValue = Source->flOuterAngle;
874 break;
876 case AL_REFERENCE_DISTANCE:
877 *pflValue = Source->flRefDistance;
878 break;
880 case AL_AIR_ABSORPTION_FACTOR:
881 *pflValue = Source->AirAbsorptionFactor;
882 break;
884 case AL_ROOM_ROLLOFF_FACTOR:
885 *pflValue = Source->RoomRolloffFactor;
886 break;
888 case AL_DOPPLER_FACTOR:
889 *pflValue = Source->DopplerFactor;
890 break;
892 default:
893 alSetError(pContext, AL_INVALID_ENUM);
894 break;
897 else
898 alSetError(pContext, AL_INVALID_NAME);
900 else
901 alSetError(pContext, AL_INVALID_VALUE);
903 ProcessContext(pContext);
907 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
909 ALCcontext *pContext;
910 ALsource *Source;
912 pContext = GetContextSuspended();
913 if(!pContext) return;
915 if(pflValue1 && pflValue2 && pflValue3)
917 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
919 switch(eParam)
921 case AL_POSITION:
922 *pflValue1 = Source->vPosition[0];
923 *pflValue2 = Source->vPosition[1];
924 *pflValue3 = Source->vPosition[2];
925 break;
927 case AL_VELOCITY:
928 *pflValue1 = Source->vVelocity[0];
929 *pflValue2 = Source->vVelocity[1];
930 *pflValue3 = Source->vVelocity[2];
931 break;
933 case AL_DIRECTION:
934 *pflValue1 = Source->vOrientation[0];
935 *pflValue2 = Source->vOrientation[1];
936 *pflValue3 = Source->vOrientation[2];
937 break;
939 default:
940 alSetError(pContext, AL_INVALID_ENUM);
941 break;
944 else
945 alSetError(pContext, AL_INVALID_NAME);
947 else
948 alSetError(pContext, AL_INVALID_VALUE);
950 ProcessContext(pContext);
954 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
956 ALCcontext *pContext;
957 ALsource *Source;
958 ALdouble Offsets[2];
959 ALdouble updateLen;
961 pContext = GetContextSuspended();
962 if(!pContext) return;
964 if(pflValues)
966 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
968 switch(eParam)
970 case AL_PITCH:
971 case AL_GAIN:
972 case AL_MIN_GAIN:
973 case AL_MAX_GAIN:
974 case AL_MAX_DISTANCE:
975 case AL_ROLLOFF_FACTOR:
976 case AL_DOPPLER_FACTOR:
977 case AL_CONE_OUTER_GAIN:
978 case AL_SEC_OFFSET:
979 case AL_SAMPLE_OFFSET:
980 case AL_BYTE_OFFSET:
981 case AL_CONE_INNER_ANGLE:
982 case AL_CONE_OUTER_ANGLE:
983 case AL_REFERENCE_DISTANCE:
984 case AL_CONE_OUTER_GAINHF:
985 case AL_AIR_ABSORPTION_FACTOR:
986 case AL_ROOM_ROLLOFF_FACTOR:
987 alGetSourcef(source, eParam, pflValues);
988 break;
990 case AL_POSITION:
991 case AL_VELOCITY:
992 case AL_DIRECTION:
993 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
994 break;
996 case AL_SAMPLE_RW_OFFSETS_SOFT:
997 case AL_BYTE_RW_OFFSETS_SOFT:
998 updateLen = (ALdouble)pContext->Device->UpdateSize /
999 pContext->Device->Frequency;
1000 GetSourceOffset(Source, eParam, Offsets, updateLen);
1001 pflValues[0] = Offsets[0];
1002 pflValues[1] = Offsets[1];
1003 break;
1005 default:
1006 alSetError(pContext, AL_INVALID_ENUM);
1007 break;
1010 else
1011 alSetError(pContext, AL_INVALID_NAME);
1013 else
1014 alSetError(pContext, AL_INVALID_VALUE);
1016 ProcessContext(pContext);
1020 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1022 ALCcontext *pContext;
1023 ALsource *Source;
1024 ALdouble Offsets[2];
1025 ALdouble updateLen;
1027 pContext = GetContextSuspended();
1028 if(!pContext) return;
1030 if(plValue)
1032 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1034 switch(eParam)
1036 case AL_MAX_DISTANCE:
1037 *plValue = (ALint)Source->flMaxDistance;
1038 break;
1040 case AL_ROLLOFF_FACTOR:
1041 *plValue = (ALint)Source->flRollOffFactor;
1042 break;
1044 case AL_REFERENCE_DISTANCE:
1045 *plValue = (ALint)Source->flRefDistance;
1046 break;
1048 case AL_SOURCE_RELATIVE:
1049 *plValue = Source->bHeadRelative;
1050 break;
1052 case AL_CONE_INNER_ANGLE:
1053 *plValue = (ALint)Source->flInnerAngle;
1054 break;
1056 case AL_CONE_OUTER_ANGLE:
1057 *plValue = (ALint)Source->flOuterAngle;
1058 break;
1060 case AL_LOOPING:
1061 *plValue = Source->bLooping;
1062 break;
1064 case AL_BUFFER:
1065 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1066 break;
1068 case AL_SOURCE_STATE:
1069 *plValue = Source->state;
1070 break;
1072 case AL_BUFFERS_QUEUED:
1073 *plValue = Source->BuffersInQueue;
1074 break;
1076 case AL_BUFFERS_PROCESSED:
1077 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1079 /* Buffers on a looping source are in a perpetual state
1080 * of PENDING, so don't report any as PROCESSED */
1081 *plValue = 0;
1083 else
1084 *plValue = Source->BuffersPlayed;
1085 break;
1087 case AL_SOURCE_TYPE:
1088 *plValue = Source->lSourceType;
1089 break;
1091 case AL_SEC_OFFSET:
1092 case AL_SAMPLE_OFFSET:
1093 case AL_BYTE_OFFSET:
1094 updateLen = (ALdouble)pContext->Device->UpdateSize /
1095 pContext->Device->Frequency;
1096 GetSourceOffset(Source, eParam, Offsets, updateLen);
1097 *plValue = (ALint)Offsets[0];
1098 break;
1100 case AL_DIRECT_FILTER:
1101 *plValue = Source->DirectFilter.filter;
1102 break;
1104 case AL_DIRECT_FILTER_GAINHF_AUTO:
1105 *plValue = Source->DryGainHFAuto;
1106 break;
1108 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1109 *plValue = Source->WetGainAuto;
1110 break;
1112 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1113 *plValue = Source->WetGainHFAuto;
1114 break;
1116 case AL_DOPPLER_FACTOR:
1117 *plValue = (ALint)Source->DopplerFactor;
1118 break;
1120 case AL_DISTANCE_MODEL:
1121 *plValue = Source->DistanceModel;
1122 break;
1124 default:
1125 alSetError(pContext, AL_INVALID_ENUM);
1126 break;
1129 else
1130 alSetError(pContext, AL_INVALID_NAME);
1132 else
1133 alSetError(pContext, AL_INVALID_VALUE);
1135 ProcessContext(pContext);
1139 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1141 ALCcontext *pContext;
1142 ALsource *Source;
1144 pContext = GetContextSuspended();
1145 if(!pContext) return;
1147 if(plValue1 && plValue2 && plValue3)
1149 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1151 switch(eParam)
1153 case AL_POSITION:
1154 *plValue1 = (ALint)Source->vPosition[0];
1155 *plValue2 = (ALint)Source->vPosition[1];
1156 *plValue3 = (ALint)Source->vPosition[2];
1157 break;
1159 case AL_VELOCITY:
1160 *plValue1 = (ALint)Source->vVelocity[0];
1161 *plValue2 = (ALint)Source->vVelocity[1];
1162 *plValue3 = (ALint)Source->vVelocity[2];
1163 break;
1165 case AL_DIRECTION:
1166 *plValue1 = (ALint)Source->vOrientation[0];
1167 *plValue2 = (ALint)Source->vOrientation[1];
1168 *plValue3 = (ALint)Source->vOrientation[2];
1169 break;
1171 default:
1172 alSetError(pContext, AL_INVALID_ENUM);
1173 break;
1176 else
1177 alSetError(pContext, AL_INVALID_NAME);
1179 else
1180 alSetError(pContext, AL_INVALID_VALUE);
1182 ProcessContext(pContext);
1186 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1188 ALCcontext *pContext;
1189 ALsource *Source;
1190 ALdouble Offsets[2];
1191 ALdouble updateLen;
1193 pContext = GetContextSuspended();
1194 if(!pContext) return;
1196 if(plValues)
1198 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1200 switch(eParam)
1202 case AL_SOURCE_RELATIVE:
1203 case AL_CONE_INNER_ANGLE:
1204 case AL_CONE_OUTER_ANGLE:
1205 case AL_LOOPING:
1206 case AL_BUFFER:
1207 case AL_SOURCE_STATE:
1208 case AL_BUFFERS_QUEUED:
1209 case AL_BUFFERS_PROCESSED:
1210 case AL_SEC_OFFSET:
1211 case AL_SAMPLE_OFFSET:
1212 case AL_BYTE_OFFSET:
1213 case AL_MAX_DISTANCE:
1214 case AL_ROLLOFF_FACTOR:
1215 case AL_DOPPLER_FACTOR:
1216 case AL_REFERENCE_DISTANCE:
1217 case AL_SOURCE_TYPE:
1218 case AL_DIRECT_FILTER:
1219 case AL_DIRECT_FILTER_GAINHF_AUTO:
1220 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1221 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1222 case AL_DISTANCE_MODEL:
1223 alGetSourcei(source, eParam, plValues);
1224 break;
1226 case AL_POSITION:
1227 case AL_VELOCITY:
1228 case AL_DIRECTION:
1229 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1230 break;
1232 case AL_SAMPLE_RW_OFFSETS_SOFT:
1233 case AL_BYTE_RW_OFFSETS_SOFT:
1234 updateLen = (ALdouble)pContext->Device->UpdateSize /
1235 pContext->Device->Frequency;
1236 GetSourceOffset(Source, eParam, Offsets, updateLen);
1237 plValues[0] = (ALint)Offsets[0];
1238 plValues[1] = (ALint)Offsets[1];
1239 break;
1241 default:
1242 alSetError(pContext, AL_INVALID_ENUM);
1243 break;
1246 else
1247 alSetError(pContext, AL_INVALID_NAME);
1249 else
1250 alSetError(pContext, AL_INVALID_VALUE);
1252 ProcessContext(pContext);
1256 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1258 alSourcePlayv(1, &source);
1261 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1263 ALCcontext *Context;
1264 ALsource *Source;
1265 ALbufferlistitem *BufferList;
1266 ALsizei i, j;
1268 Context = GetContextSuspended();
1269 if(!Context) return;
1271 if(n < 0)
1273 alSetError(Context, AL_INVALID_VALUE);
1274 goto done;
1276 if(n > 0 && !sources)
1278 alSetError(Context, AL_INVALID_VALUE);
1279 goto done;
1282 // Check that all the Sources are valid
1283 for(i = 0;i < n;i++)
1285 if(!LookupSource(Context->SourceMap, sources[i]))
1287 alSetError(Context, AL_INVALID_NAME);
1288 goto done;
1292 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1294 void *temp = NULL;
1295 ALsizei newcount;
1297 newcount = Context->MaxActiveSources << 1;
1298 if(newcount > 0)
1299 temp = realloc(Context->ActiveSources,
1300 sizeof(*Context->ActiveSources) * newcount);
1301 if(!temp)
1303 alSetError(Context, AL_OUT_OF_MEMORY);
1304 goto done;
1307 Context->ActiveSources = temp;
1308 Context->MaxActiveSources = newcount;
1311 for(i = 0;i < n;i++)
1313 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1315 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1316 BufferList = Source->queue;
1317 while(BufferList)
1319 if(BufferList->buffer != NULL && BufferList->buffer->size)
1320 break;
1321 BufferList = BufferList->next;
1324 if(!BufferList)
1326 Source->state = AL_STOPPED;
1327 Source->BuffersPlayed = Source->BuffersInQueue;
1328 Source->position = 0;
1329 Source->position_fraction = 0;
1330 Source->lOffset = 0;
1331 continue;
1334 if(Source->state != AL_PAUSED)
1336 Source->state = AL_PLAYING;
1337 Source->position = 0;
1338 Source->position_fraction = 0;
1339 Source->BuffersPlayed = 0;
1341 Source->Buffer = Source->queue->buffer;
1343 else
1344 Source->state = AL_PLAYING;
1346 // Check if an Offset has been set
1347 if(Source->lOffset)
1348 ApplyOffset(Source);
1350 // If device is disconnected, go right to stopped
1351 if(!Context->Device->Connected)
1353 Source->state = AL_STOPPED;
1354 Source->BuffersPlayed = Source->BuffersInQueue;
1355 Source->position = 0;
1356 Source->position_fraction = 0;
1358 else
1360 for(j = 0;j < Context->ActiveSourceCount;j++)
1362 if(Context->ActiveSources[j] == Source)
1363 break;
1365 if(j == Context->ActiveSourceCount)
1366 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1370 done:
1371 ProcessContext(Context);
1374 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1376 alSourcePausev(1, &source);
1379 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1381 ALCcontext *Context;
1382 ALsource *Source;
1383 ALsizei i;
1385 Context = GetContextSuspended();
1386 if(!Context) return;
1388 if(n < 0)
1390 alSetError(Context, AL_INVALID_VALUE);
1391 goto done;
1393 if(n > 0 && !sources)
1395 alSetError(Context, AL_INVALID_VALUE);
1396 goto done;
1399 // Check all the Sources are valid
1400 for(i = 0;i < n;i++)
1402 if(!LookupSource(Context->SourceMap, sources[i]))
1404 alSetError(Context, AL_INVALID_NAME);
1405 goto done;
1409 for(i = 0;i < n;i++)
1411 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1412 if(Source->state == AL_PLAYING)
1413 Source->state = AL_PAUSED;
1416 done:
1417 ProcessContext(Context);
1420 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1422 alSourceStopv(1, &source);
1425 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1427 ALCcontext *Context;
1428 ALsource *Source;
1429 ALsizei i;
1431 Context = GetContextSuspended();
1432 if(!Context) return;
1434 if(n < 0)
1436 alSetError(Context, AL_INVALID_VALUE);
1437 goto done;
1439 if(n > 0 && !sources)
1441 alSetError(Context, AL_INVALID_VALUE);
1442 goto done;
1445 // Check all the Sources are valid
1446 for(i = 0;i < n;i++)
1448 if(!LookupSource(Context->SourceMap, sources[i]))
1450 alSetError(Context, AL_INVALID_NAME);
1451 goto done;
1455 for(i = 0;i < n;i++)
1457 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1458 if(Source->state != AL_INITIAL)
1460 Source->state = AL_STOPPED;
1461 Source->BuffersPlayed = Source->BuffersInQueue;
1463 Source->lOffset = 0;
1466 done:
1467 ProcessContext(Context);
1470 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1472 alSourceRewindv(1, &source);
1475 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1477 ALCcontext *Context;
1478 ALsource *Source;
1479 ALsizei i;
1481 Context = GetContextSuspended();
1482 if(!Context) return;
1484 if(n < 0)
1486 alSetError(Context, AL_INVALID_VALUE);
1487 goto done;
1489 if(n > 0 && !sources)
1491 alSetError(Context, AL_INVALID_VALUE);
1492 goto done;
1495 // Check all the Sources are valid
1496 for(i = 0;i < n;i++)
1498 if(!LookupSource(Context->SourceMap, sources[i]))
1500 alSetError(Context, AL_INVALID_NAME);
1501 goto done;
1505 for(i = 0;i < n;i++)
1507 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1508 if(Source->state != AL_INITIAL)
1510 Source->state = AL_INITIAL;
1511 Source->position = 0;
1512 Source->position_fraction = 0;
1513 Source->BuffersPlayed = 0;
1514 if(Source->queue)
1515 Source->Buffer = Source->queue->buffer;
1517 Source->lOffset = 0;
1520 done:
1521 ProcessContext(Context);
1525 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1527 ALCcontext *Context;
1528 ALCdevice *device;
1529 ALsource *Source;
1530 ALbuffer *buffer;
1531 ALsizei i;
1532 ALbufferlistitem *BufferListStart;
1533 ALbufferlistitem *BufferList;
1534 ALint Frequency;
1535 ALint Format;
1537 if(n == 0)
1538 return;
1540 Context = GetContextSuspended();
1541 if(!Context) return;
1543 if(n < 0)
1545 alSetError(Context, AL_INVALID_VALUE);
1546 goto done;
1549 // Check that all buffers are valid or zero and that the source is valid
1551 // Check that this is a valid source
1552 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1554 alSetError(Context, AL_INVALID_NAME);
1555 goto done;
1558 // Check that this is not a STATIC Source
1559 if(Source->lSourceType == AL_STATIC)
1561 // Invalid Source Type (can't queue on a Static Source)
1562 alSetError(Context, AL_INVALID_OPERATION);
1563 goto done;
1566 device = Context->Device;
1568 Frequency = -1;
1569 Format = -1;
1571 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1572 BufferList = Source->queue;
1573 while(BufferList)
1575 if(BufferList->buffer)
1577 Frequency = BufferList->buffer->frequency;
1578 Format = BufferList->buffer->eOriginalFormat;
1579 break;
1581 BufferList = BufferList->next;
1584 for(i = 0;i < n;i++)
1586 if(!buffers[i])
1587 continue;
1589 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1591 alSetError(Context, AL_INVALID_NAME);
1592 goto done;
1595 if(Frequency == -1 && Format == -1)
1597 Frequency = buffer->frequency;
1598 Format = buffer->eOriginalFormat;
1600 if(aluChannelsFromFormat(buffer->format) == 1)
1601 Source->Update = CalcSourceParams;
1602 else
1603 Source->Update = CalcNonAttnSourceParams;
1605 Source->Mix = MixSource;
1607 Source->NeedsUpdate = AL_TRUE;
1609 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1611 alSetError(Context, AL_INVALID_OPERATION);
1612 goto done;
1616 // Change Source Type
1617 Source->lSourceType = AL_STREAMING;
1619 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1621 // All buffers are valid - so add them to the list
1622 BufferListStart = malloc(sizeof(ALbufferlistitem));
1623 BufferListStart->buffer = buffer;
1624 BufferListStart->next = NULL;
1625 BufferListStart->prev = NULL;
1627 // Increment reference counter for buffer
1628 if(buffer) buffer->refcount++;
1630 BufferList = BufferListStart;
1632 for(i = 1;i < n;i++)
1634 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1636 BufferList->next = malloc(sizeof(ALbufferlistitem));
1637 BufferList->next->buffer = buffer;
1638 BufferList->next->next = NULL;
1639 BufferList->next->prev = BufferList;
1641 // Increment reference counter for buffer
1642 if(buffer) buffer->refcount++;
1644 BufferList = BufferList->next;
1647 if(Source->queue == NULL)
1649 Source->queue = BufferListStart;
1650 // Update Current Buffer
1651 Source->Buffer = BufferListStart->buffer;
1653 else
1655 // Find end of queue
1656 BufferList = Source->queue;
1657 while(BufferList->next != NULL)
1658 BufferList = BufferList->next;
1660 BufferList->next = BufferListStart;
1661 BufferList->next->prev = BufferList;
1664 // Update number of buffers in queue
1665 Source->BuffersInQueue += n;
1667 done:
1668 ProcessContext(Context);
1672 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1673 // an array of buffer IDs that are to be filled with the names of the buffers removed
1674 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1676 ALCcontext *Context;
1677 ALsource *Source;
1678 ALsizei i;
1679 ALbufferlistitem *BufferList;
1681 if(n == 0)
1682 return;
1684 Context = GetContextSuspended();
1685 if(!Context) return;
1687 if(n < 0)
1689 alSetError(Context, AL_INVALID_VALUE);
1690 goto done;
1693 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1695 alSetError(Context, AL_INVALID_NAME);
1696 goto done;
1699 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1700 (ALuint)n > Source->BuffersPlayed)
1702 // Some buffers can't be unqueue because they have not been processed
1703 alSetError(Context, AL_INVALID_VALUE);
1704 goto done;
1707 for(i = 0;i < n;i++)
1709 BufferList = Source->queue;
1710 Source->queue = BufferList->next;
1712 if(BufferList->buffer)
1714 // Record name of buffer
1715 buffers[i] = BufferList->buffer->buffer;
1716 // Decrement buffer reference counter
1717 BufferList->buffer->refcount--;
1719 else
1720 buffers[i] = 0;
1722 // Release memory for buffer list item
1723 free(BufferList);
1724 Source->BuffersInQueue--;
1726 if(Source->queue)
1727 Source->queue->prev = NULL;
1729 if(Source->state != AL_PLAYING)
1731 if(Source->queue)
1732 Source->Buffer = Source->queue->buffer;
1733 else
1734 Source->Buffer = NULL;
1736 Source->BuffersPlayed -= n;
1738 done:
1739 ProcessContext(Context);
1743 static ALvoid InitSourceParams(ALsource *Source)
1745 Source->flInnerAngle = 360.0f;
1746 Source->flOuterAngle = 360.0f;
1747 Source->flPitch = 1.0f;
1748 Source->vPosition[0] = 0.0f;
1749 Source->vPosition[1] = 0.0f;
1750 Source->vPosition[2] = 0.0f;
1751 Source->vOrientation[0] = 0.0f;
1752 Source->vOrientation[1] = 0.0f;
1753 Source->vOrientation[2] = 0.0f;
1754 Source->vVelocity[0] = 0.0f;
1755 Source->vVelocity[1] = 0.0f;
1756 Source->vVelocity[2] = 0.0f;
1757 Source->flRefDistance = 1.0f;
1758 Source->flMaxDistance = FLT_MAX;
1759 Source->flRollOffFactor = 1.0f;
1760 Source->bLooping = AL_FALSE;
1761 Source->flGain = 1.0f;
1762 Source->flMinGain = 0.0f;
1763 Source->flMaxGain = 1.0f;
1764 Source->flOuterGain = 0.0f;
1765 Source->OuterGainHF = 1.0f;
1767 Source->DryGainHFAuto = AL_TRUE;
1768 Source->WetGainAuto = AL_TRUE;
1769 Source->WetGainHFAuto = AL_TRUE;
1770 Source->AirAbsorptionFactor = 0.0f;
1771 Source->RoomRolloffFactor = 0.0f;
1772 Source->DopplerFactor = 1.0f;
1774 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1776 Source->Resampler = DefaultResampler;
1778 Source->state = AL_INITIAL;
1779 Source->lSourceType = AL_UNDETERMINED;
1781 Source->NeedsUpdate = AL_TRUE;
1783 Source->Buffer = NULL;
1788 GetSourceOffset
1790 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1791 The offset is relative to the start of the queue (not the start of the current buffer)
1793 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1795 ALbufferlistitem *BufferList;
1796 ALbuffer *Buffer = NULL;
1797 ALfloat BufferFreq;
1798 ALint Channels, Bytes;
1799 ALuint readPos, writePos;
1800 ALenum OriginalFormat;
1801 ALuint TotalBufferDataSize;
1802 ALuint i;
1804 // Find the first non-NULL Buffer in the Queue
1805 BufferList = Source->queue;
1806 while(BufferList)
1808 if(BufferList->buffer)
1810 Buffer = BufferList->buffer;
1811 break;
1813 BufferList = BufferList->next;
1816 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1818 offset[0] = 0.0;
1819 offset[1] = 0.0;
1820 return;
1823 // Get Current Buffer Size and frequency (in milliseconds)
1824 BufferFreq = (ALfloat)Buffer->frequency;
1825 OriginalFormat = Buffer->eOriginalFormat;
1826 Channels = aluChannelsFromFormat(Buffer->format);
1827 Bytes = aluBytesFromFormat(Buffer->format);
1829 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1830 readPos = Source->position * Channels * Bytes;
1831 // Add byte length of any processed buffers in the queue
1832 TotalBufferDataSize = 0;
1833 BufferList = Source->queue;
1834 for(i = 0;BufferList;i++)
1836 if(BufferList->buffer)
1838 if(i < Source->BuffersPlayed)
1839 readPos += BufferList->buffer->size;
1840 TotalBufferDataSize += BufferList->buffer->size;
1842 BufferList = BufferList->next;
1844 if(Source->state == AL_PLAYING)
1845 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1846 else
1847 writePos = readPos;
1849 if(Source->bLooping)
1851 readPos %= TotalBufferDataSize;
1852 writePos %= TotalBufferDataSize;
1854 else
1856 // Wrap positions back to 0
1857 if(readPos >= TotalBufferDataSize)
1858 readPos = 0;
1859 if(writePos >= TotalBufferDataSize)
1860 writePos = 0;
1863 switch(name)
1865 case AL_SEC_OFFSET:
1866 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1867 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1868 break;
1869 case AL_SAMPLE_OFFSET:
1870 case AL_SAMPLE_RW_OFFSETS_SOFT:
1871 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1872 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1873 break;
1874 case AL_BYTE_OFFSET:
1875 case AL_BYTE_RW_OFFSETS_SOFT:
1876 // Take into account the original format of the Buffer
1877 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1878 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1880 // Round down to nearest ADPCM block
1881 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1882 if(Source->state == AL_PLAYING)
1884 // Round up to nearest ADPCM block
1885 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1887 else
1888 offset[1] = offset[0];
1890 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1891 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1892 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1893 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1894 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1895 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1897 offset[0] = (ALdouble)(readPos / Bytes * 1);
1898 offset[1] = (ALdouble)(writePos / Bytes * 1);
1900 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1902 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1903 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1905 else if(OriginalFormat == AL_FORMAT_REAR8)
1907 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1908 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1910 else if(OriginalFormat == AL_FORMAT_REAR16)
1912 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1913 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1915 else if(OriginalFormat == AL_FORMAT_REAR32)
1917 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1918 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1920 else
1922 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1923 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1924 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1926 break;
1932 ApplyOffset
1934 Apply a playback offset to the Source. This function will update the queue (to correctly
1935 mark buffers as 'pending' or 'processed' depending upon the new offset.
1937 static ALboolean ApplyOffset(ALsource *Source)
1939 ALbufferlistitem *BufferList;
1940 ALbuffer *Buffer;
1941 ALint lBufferSize, lTotalBufferSize;
1942 ALint BuffersPlayed;
1943 ALint lByteOffset;
1945 // Get true byte offset
1946 lByteOffset = GetByteOffset(Source);
1948 // If the offset is invalid, don't apply it
1949 if(lByteOffset == -1)
1950 return AL_FALSE;
1952 // Sort out the queue (pending and processed states)
1953 BufferList = Source->queue;
1954 lTotalBufferSize = 0;
1955 BuffersPlayed = 0;
1957 while(BufferList)
1959 Buffer = BufferList->buffer;
1960 lBufferSize = Buffer ? Buffer->size : 0;
1962 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1964 // Offset is past this buffer so increment BuffersPlayed
1965 BuffersPlayed++;
1967 else if(lTotalBufferSize <= lByteOffset)
1969 // Offset is within this buffer
1970 // Set Current Buffer
1971 Source->Buffer = BufferList->buffer;
1972 Source->BuffersPlayed = BuffersPlayed;
1974 // SW Mixer Positions are in Samples
1975 Source->position = (lByteOffset - lTotalBufferSize) /
1976 aluFrameSizeFromFormat(Buffer->format);
1977 return AL_TRUE;
1980 // Increment the TotalBufferSize
1981 lTotalBufferSize += lBufferSize;
1983 // Move on to next buffer in the Queue
1984 BufferList = BufferList->next;
1986 // Offset is out of range of the buffer queue
1987 return AL_FALSE;
1992 GetByteOffset
1994 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1995 offset supplied by the application). This takes into account the fact that the buffer format
1996 may have been modifed by AL (e.g 8bit samples are converted to float)
1998 static ALint GetByteOffset(ALsource *Source)
2000 ALbuffer *Buffer = NULL;
2001 ALbufferlistitem *BufferList;
2002 ALdouble BufferFreq;
2003 ALint Channels, Bytes;
2004 ALint ByteOffset = -1;
2006 // Find the first non-NULL Buffer in the Queue
2007 BufferList = Source->queue;
2008 while(BufferList)
2010 if(BufferList->buffer)
2012 Buffer = BufferList->buffer;
2013 break;
2015 BufferList = BufferList->next;
2018 if(!Buffer)
2020 Source->lOffset = 0;
2021 return -1;
2024 BufferFreq = ((ALdouble)Buffer->frequency);
2025 Channels = aluChannelsFromFormat(Buffer->format);
2026 Bytes = aluBytesFromFormat(Buffer->format);
2028 // Determine the ByteOffset (and ensure it is block aligned)
2029 switch(Source->lOffsetType)
2031 case AL_BYTE_OFFSET:
2032 // Take into consideration the original format
2033 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2034 Channels);
2035 ByteOffset *= Channels * Bytes;
2036 break;
2038 case AL_SAMPLE_OFFSET:
2039 ByteOffset = Source->lOffset * Channels * Bytes;
2040 break;
2042 case AL_SEC_OFFSET:
2043 // Note - lOffset is internally stored as Milliseconds
2044 ByteOffset = (ALint)(Source->lOffset / 1000.0 * BufferFreq);
2045 ByteOffset *= Channels * Bytes;
2046 break;
2048 // Clear Offset
2049 Source->lOffset = 0;
2051 return ByteOffset;
2054 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2056 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2058 // Round down to nearest ADPCM block
2059 offset /= 36 * channels;
2060 // Multiply by compression rate (65 sample frames per block)
2061 offset *= 65;
2063 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2064 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2065 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2067 /* muLaw has 1 byte per sample */
2068 offset /= 1 * channels;
2070 else if(format == AL_FORMAT_REAR_MULAW)
2072 /* Rear is 2 channels */
2073 offset /= 1 * 2;
2075 else if(format == AL_FORMAT_REAR8)
2076 offset /= 1 * 2;
2077 else if(format == AL_FORMAT_REAR16)
2078 offset /= 2 * 2;
2079 else if(format == AL_FORMAT_REAR32)
2080 offset /= 4 * 2;
2081 else
2083 ALuint bytes = aluBytesFromFormat(format);
2084 offset /= bytes * channels;
2086 return offset;
2090 ALvoid ReleaseALSources(ALCcontext *Context)
2092 ALsizei pos;
2093 ALuint j;
2094 for(pos = 0;pos < Context->SourceMap.size;pos++)
2096 ALsource *temp = Context->SourceMap.array[pos].value;
2097 Context->SourceMap.array[pos].value = NULL;
2099 // For each buffer in the source's queue, decrement its reference counter and remove it
2100 while(temp->queue != NULL)
2102 ALbufferlistitem *BufferList = temp->queue;
2103 temp->queue = BufferList->next;
2105 if(BufferList->buffer != NULL)
2106 BufferList->buffer->refcount--;
2107 free(BufferList);
2110 for(j = 0;j < MAX_SENDS;++j)
2112 if(temp->Send[j].Slot)
2113 temp->Send[j].Slot->refcount--;
2114 temp->Send[j].Slot = NULL;
2117 // Release source structure
2118 ALTHUNK_REMOVEENTRY(temp->source);
2119 memset(temp, 0, sizeof(ALsource));
2120 free(temp);