Fix source offset calculations
[openal-soft.git] / OpenAL32 / alSource.c
blob1f0594b28d38b8c6554fb7a5d26c8b946e8ddf99
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"
36 resampler_t DefaultResampler;
37 const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
38 0, /* Point */
39 1, /* Linear */
40 2, /* Cubic */
42 const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
43 0, /* Point */
44 0, /* Linear */
45 1, /* Cubic */
49 static ALvoid InitSourceParams(ALsource *Source);
50 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
51 static ALboolean ApplyOffset(ALsource *Source);
52 static ALint GetByteOffset(ALsource *Source);
54 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
55 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
56 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
57 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
59 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
61 ALCcontext *Context;
62 ALCdevice *Device;
64 Context = GetContextSuspended();
65 if(!Context) return;
67 Device = Context->Device;
68 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
69 alSetError(Context, AL_INVALID_VALUE);
70 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
71 alSetError(Context, AL_INVALID_VALUE);
72 else
74 ALenum err;
75 ALsizei i;
77 // Add additional sources to the list
78 i = 0;
79 while(i < n)
81 ALsource *source = calloc(1, sizeof(ALsource));
82 if(!source)
84 alSetError(Context, AL_OUT_OF_MEMORY);
85 alDeleteSources(i, sources);
86 break;
89 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
90 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
91 source);
92 if(err != AL_NO_ERROR)
94 ALTHUNK_REMOVEENTRY(source->source);
95 memset(source, 0, sizeof(ALsource));
96 free(source);
98 alSetError(Context, err);
99 alDeleteSources(i, sources);
100 break;
103 sources[i++] = source->source;
104 InitSourceParams(source);
108 ProcessContext(Context);
112 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
114 ALCcontext *Context;
115 ALsource *Source;
116 ALsizei i, j;
117 ALbufferlistitem *BufferList;
118 ALboolean SourcesValid = AL_FALSE;
120 Context = GetContextSuspended();
121 if(!Context) return;
123 if(n < 0)
124 alSetError(Context, AL_INVALID_VALUE);
125 else
127 SourcesValid = AL_TRUE;
128 // Check that all Sources are valid (and can therefore be deleted)
129 for(i = 0;i < n;i++)
131 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
133 alSetError(Context, AL_INVALID_NAME);
134 SourcesValid = AL_FALSE;
135 break;
140 if(SourcesValid)
142 // All Sources are valid, and can be deleted
143 for(i = 0;i < n;i++)
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
147 continue;
149 for(j = 0;j < Context->ActiveSourceCount;j++)
151 if(Context->ActiveSources[j] == Source)
153 ALsizei end = --(Context->ActiveSourceCount);
154 Context->ActiveSources[j] = Context->ActiveSources[end];
155 break;
159 // For each buffer in the source's queue...
160 while(Source->queue != NULL)
162 BufferList = Source->queue;
163 Source->queue = BufferList->next;
165 if(BufferList->buffer != NULL)
166 BufferList->buffer->refcount--;
167 free(BufferList);
170 for(j = 0;j < MAX_SENDS;++j)
172 if(Source->Send[j].Slot)
173 Source->Send[j].Slot->refcount--;
174 Source->Send[j].Slot = NULL;
177 // Remove Source from list of Sources
178 RemoveUIntMapKey(&Context->SourceMap, Source->source);
179 ALTHUNK_REMOVEENTRY(Source->source);
181 memset(Source,0,sizeof(ALsource));
182 free(Source);
186 ProcessContext(Context);
190 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
192 ALCcontext *Context;
193 ALboolean result;
195 Context = GetContextSuspended();
196 if(!Context) return AL_FALSE;
198 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
200 ProcessContext(Context);
202 return result;
206 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
208 ALCcontext *pContext;
209 ALsource *Source;
211 pContext = GetContextSuspended();
212 if(!pContext) return;
214 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
216 switch(eParam)
218 case AL_PITCH:
219 if(flValue >= 0.0f)
221 Source->flPitch = flValue;
222 if(Source->flPitch < 0.001f)
223 Source->flPitch = 0.001f;
224 Source->NeedsUpdate = AL_TRUE;
226 else
227 alSetError(pContext, AL_INVALID_VALUE);
228 break;
230 case AL_CONE_INNER_ANGLE:
231 if(flValue >= 0.0f && flValue <= 360.0f)
233 Source->flInnerAngle = flValue;
234 Source->NeedsUpdate = AL_TRUE;
236 else
237 alSetError(pContext, AL_INVALID_VALUE);
238 break;
240 case AL_CONE_OUTER_ANGLE:
241 if(flValue >= 0.0f && flValue <= 360.0f)
243 Source->flOuterAngle = flValue;
244 Source->NeedsUpdate = AL_TRUE;
246 else
247 alSetError(pContext, AL_INVALID_VALUE);
248 break;
250 case AL_GAIN:
251 if(flValue >= 0.0f)
253 Source->flGain = flValue;
254 Source->NeedsUpdate = AL_TRUE;
256 else
257 alSetError(pContext, AL_INVALID_VALUE);
258 break;
260 case AL_MAX_DISTANCE:
261 if(flValue >= 0.0f)
263 Source->flMaxDistance = flValue;
264 Source->NeedsUpdate = AL_TRUE;
266 else
267 alSetError(pContext, AL_INVALID_VALUE);
268 break;
270 case AL_ROLLOFF_FACTOR:
271 if(flValue >= 0.0f)
273 Source->flRollOffFactor = flValue;
274 Source->NeedsUpdate = AL_TRUE;
276 else
277 alSetError(pContext, AL_INVALID_VALUE);
278 break;
280 case AL_REFERENCE_DISTANCE:
281 if(flValue >= 0.0f)
283 Source->flRefDistance = flValue;
284 Source->NeedsUpdate = AL_TRUE;
286 else
287 alSetError(pContext, AL_INVALID_VALUE);
288 break;
290 case AL_MIN_GAIN:
291 if(flValue >= 0.0f && flValue <= 1.0f)
293 Source->flMinGain = flValue;
294 Source->NeedsUpdate = AL_TRUE;
296 else
297 alSetError(pContext, AL_INVALID_VALUE);
298 break;
300 case AL_MAX_GAIN:
301 if(flValue >= 0.0f && flValue <= 1.0f)
303 Source->flMaxGain = flValue;
304 Source->NeedsUpdate = AL_TRUE;
306 else
307 alSetError(pContext, AL_INVALID_VALUE);
308 break;
310 case AL_CONE_OUTER_GAIN:
311 if(flValue >= 0.0f && flValue <= 1.0f)
313 Source->flOuterGain = flValue;
314 Source->NeedsUpdate = AL_TRUE;
316 else
317 alSetError(pContext, AL_INVALID_VALUE);
318 break;
320 case AL_CONE_OUTER_GAINHF:
321 if(flValue >= 0.0f && flValue <= 1.0f)
323 Source->OuterGainHF = flValue;
324 Source->NeedsUpdate = AL_TRUE;
326 else
327 alSetError(pContext, AL_INVALID_VALUE);
328 break;
330 case AL_AIR_ABSORPTION_FACTOR:
331 if(flValue >= 0.0f && flValue <= 10.0f)
333 Source->AirAbsorptionFactor = flValue;
334 Source->NeedsUpdate = AL_TRUE;
336 else
337 alSetError(pContext, AL_INVALID_VALUE);
338 break;
340 case AL_ROOM_ROLLOFF_FACTOR:
341 if(flValue >= 0.0f && flValue <= 10.0f)
343 Source->RoomRolloffFactor = flValue;
344 Source->NeedsUpdate = AL_TRUE;
346 else
347 alSetError(pContext, AL_INVALID_VALUE);
348 break;
350 case AL_DOPPLER_FACTOR:
351 if(flValue >= 0.0f && flValue <= 1.0f)
353 Source->DopplerFactor = flValue;
354 Source->NeedsUpdate = AL_TRUE;
356 else
357 alSetError(pContext, AL_INVALID_VALUE);
358 break;
360 case AL_SEC_OFFSET:
361 case AL_SAMPLE_OFFSET:
362 case AL_BYTE_OFFSET:
363 if(flValue >= 0.0f)
365 Source->lOffsetType = eParam;
367 // Store Offset (convert Seconds into Milliseconds)
368 if(eParam == AL_SEC_OFFSET)
369 Source->lOffset = (ALint)(flValue * 1000.0f);
370 else
371 Source->lOffset = (ALint)flValue;
373 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
375 if(ApplyOffset(Source) == AL_FALSE)
376 alSetError(pContext, AL_INVALID_VALUE);
379 else
380 alSetError(pContext, AL_INVALID_VALUE);
381 break;
383 default:
384 alSetError(pContext, AL_INVALID_ENUM);
385 break;
388 else
390 // Invalid Source Name
391 alSetError(pContext, AL_INVALID_NAME);
394 ProcessContext(pContext);
398 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
400 ALCcontext *pContext;
401 ALsource *Source;
403 pContext = GetContextSuspended();
404 if(!pContext) return;
406 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
408 switch(eParam)
410 case AL_POSITION:
411 Source->vPosition[0] = flValue1;
412 Source->vPosition[1] = flValue2;
413 Source->vPosition[2] = flValue3;
414 Source->NeedsUpdate = AL_TRUE;
415 break;
417 case AL_VELOCITY:
418 Source->vVelocity[0] = flValue1;
419 Source->vVelocity[1] = flValue2;
420 Source->vVelocity[2] = flValue3;
421 Source->NeedsUpdate = AL_TRUE;
422 break;
424 case AL_DIRECTION:
425 Source->vOrientation[0] = flValue1;
426 Source->vOrientation[1] = flValue2;
427 Source->vOrientation[2] = flValue3;
428 Source->NeedsUpdate = AL_TRUE;
429 break;
431 default:
432 alSetError(pContext, AL_INVALID_ENUM);
433 break;
436 else
437 alSetError(pContext, AL_INVALID_NAME);
439 ProcessContext(pContext);
443 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
445 ALCcontext *pContext;
447 pContext = GetContextSuspended();
448 if(!pContext) return;
450 if(pflValues)
452 if(LookupSource(pContext->SourceMap, source) != NULL)
454 switch(eParam)
456 case AL_PITCH:
457 case AL_CONE_INNER_ANGLE:
458 case AL_CONE_OUTER_ANGLE:
459 case AL_GAIN:
460 case AL_MAX_DISTANCE:
461 case AL_ROLLOFF_FACTOR:
462 case AL_REFERENCE_DISTANCE:
463 case AL_MIN_GAIN:
464 case AL_MAX_GAIN:
465 case AL_CONE_OUTER_GAIN:
466 case AL_CONE_OUTER_GAINHF:
467 case AL_SEC_OFFSET:
468 case AL_SAMPLE_OFFSET:
469 case AL_BYTE_OFFSET:
470 case AL_AIR_ABSORPTION_FACTOR:
471 case AL_ROOM_ROLLOFF_FACTOR:
472 alSourcef(source, eParam, pflValues[0]);
473 break;
475 case AL_POSITION:
476 case AL_VELOCITY:
477 case AL_DIRECTION:
478 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
479 break;
481 default:
482 alSetError(pContext, AL_INVALID_ENUM);
483 break;
486 else
487 alSetError(pContext, AL_INVALID_NAME);
489 else
490 alSetError(pContext, AL_INVALID_VALUE);
492 ProcessContext(pContext);
496 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
498 ALCcontext *pContext;
499 ALsource *Source;
500 ALbufferlistitem *BufferListItem;
502 pContext = GetContextSuspended();
503 if(!pContext) return;
505 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
507 ALCdevice *device = pContext->Device;
509 switch(eParam)
511 case AL_MAX_DISTANCE:
512 case AL_ROLLOFF_FACTOR:
513 case AL_CONE_INNER_ANGLE:
514 case AL_CONE_OUTER_ANGLE:
515 case AL_REFERENCE_DISTANCE:
516 alSourcef(source, eParam, (ALfloat)lValue);
517 break;
519 case AL_SOURCE_RELATIVE:
520 if(lValue == AL_FALSE || lValue == AL_TRUE)
522 Source->bHeadRelative = (ALboolean)lValue;
523 Source->NeedsUpdate = AL_TRUE;
525 else
526 alSetError(pContext, AL_INVALID_VALUE);
527 break;
529 case AL_LOOPING:
530 if(lValue == AL_FALSE || lValue == AL_TRUE)
531 Source->bLooping = (ALboolean)lValue;
532 else
533 alSetError(pContext, AL_INVALID_VALUE);
534 break;
536 case AL_BUFFER:
537 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
539 ALbuffer *buffer = NULL;
541 if(lValue == 0 ||
542 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
544 // Remove all elements in the queue
545 while(Source->queue != NULL)
547 BufferListItem = Source->queue;
548 Source->queue = BufferListItem->next;
550 if(BufferListItem->buffer)
551 BufferListItem->buffer->refcount--;
552 free(BufferListItem);
554 Source->BuffersInQueue = 0;
556 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
557 if(buffer != NULL)
559 // Source is now in STATIC mode
560 Source->lSourceType = AL_STATIC;
562 // Add the selected buffer to the queue
563 BufferListItem = malloc(sizeof(ALbufferlistitem));
564 BufferListItem->buffer = buffer;
565 BufferListItem->next = NULL;
566 BufferListItem->prev = NULL;
568 Source->queue = BufferListItem;
569 Source->BuffersInQueue = 1;
571 if(buffer->FmtChannels == FmtMono)
572 Source->Update = CalcSourceParams;
573 else
574 Source->Update = CalcNonAttnSourceParams;
576 // Increment reference counter for buffer
577 buffer->refcount++;
579 else
581 // Source is now in UNDETERMINED mode
582 Source->lSourceType = AL_UNDETERMINED;
584 Source->BuffersPlayed = 0;
586 // Update AL_BUFFER parameter
587 Source->Buffer = buffer;
588 Source->NeedsUpdate = AL_TRUE;
590 else
591 alSetError(pContext, AL_INVALID_VALUE);
593 else
594 alSetError(pContext, AL_INVALID_OPERATION);
595 break;
597 case AL_SOURCE_STATE:
598 // Query only
599 alSetError(pContext, AL_INVALID_OPERATION);
600 break;
602 case AL_SEC_OFFSET:
603 case AL_SAMPLE_OFFSET:
604 case AL_BYTE_OFFSET:
605 if(lValue >= 0)
607 Source->lOffsetType = eParam;
609 // Store Offset (convert Seconds into Milliseconds)
610 if(eParam == AL_SEC_OFFSET)
611 Source->lOffset = lValue * 1000;
612 else
613 Source->lOffset = lValue;
615 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
617 if(ApplyOffset(Source) == AL_FALSE)
618 alSetError(pContext, AL_INVALID_VALUE);
621 else
622 alSetError(pContext, AL_INVALID_VALUE);
623 break;
625 case AL_DIRECT_FILTER: {
626 ALfilter *filter = NULL;
628 if(lValue == 0 ||
629 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
631 if(!filter)
633 Source->DirectFilter.type = AL_FILTER_NULL;
634 Source->DirectFilter.filter = 0;
636 else
637 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
638 Source->NeedsUpdate = AL_TRUE;
640 else
641 alSetError(pContext, AL_INVALID_VALUE);
642 } break;
644 case AL_DIRECT_FILTER_GAINHF_AUTO:
645 if(lValue == AL_TRUE || lValue == AL_FALSE)
647 Source->DryGainHFAuto = lValue;
648 Source->NeedsUpdate = AL_TRUE;
650 else
651 alSetError(pContext, AL_INVALID_VALUE);
652 break;
654 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
655 if(lValue == AL_TRUE || lValue == AL_FALSE)
657 Source->WetGainAuto = lValue;
658 Source->NeedsUpdate = AL_TRUE;
660 else
661 alSetError(pContext, AL_INVALID_VALUE);
662 break;
664 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
665 if(lValue == AL_TRUE || lValue == AL_FALSE)
667 Source->WetGainHFAuto = lValue;
668 Source->NeedsUpdate = AL_TRUE;
670 else
671 alSetError(pContext, AL_INVALID_VALUE);
672 break;
674 case AL_DISTANCE_MODEL:
675 if(lValue == AL_NONE ||
676 lValue == AL_INVERSE_DISTANCE ||
677 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
678 lValue == AL_LINEAR_DISTANCE ||
679 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
680 lValue == AL_EXPONENT_DISTANCE ||
681 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
683 Source->DistanceModel = lValue;
684 if(pContext->SourceDistanceModel)
685 Source->NeedsUpdate = AL_TRUE;
687 else
688 alSetError(pContext, AL_INVALID_VALUE);
689 break;
691 default:
692 alSetError(pContext, AL_INVALID_ENUM);
693 break;
696 else
697 alSetError(pContext, AL_INVALID_NAME);
699 ProcessContext(pContext);
703 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
705 ALCcontext *pContext;
706 ALsource *Source;
708 pContext = GetContextSuspended();
709 if(!pContext) return;
711 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
713 ALCdevice *device = pContext->Device;
715 switch (eParam)
717 case AL_POSITION:
718 case AL_VELOCITY:
719 case AL_DIRECTION:
720 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
721 break;
723 case AL_AUXILIARY_SEND_FILTER: {
724 ALeffectslot *ALEffectSlot = NULL;
725 ALfilter *ALFilter = NULL;
727 if((ALuint)lValue2 < device->NumAuxSends &&
728 (lValue1 == 0 ||
729 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
730 (lValue3 == 0 ||
731 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
733 /* Release refcount on the previous slot, and add one for
734 * the new slot */
735 if(Source->Send[lValue2].Slot)
736 Source->Send[lValue2].Slot->refcount--;
737 Source->Send[lValue2].Slot = ALEffectSlot;
738 if(Source->Send[lValue2].Slot)
739 Source->Send[lValue2].Slot->refcount++;
741 if(!ALFilter)
743 /* Disable filter */
744 Source->Send[lValue2].WetFilter.type = 0;
745 Source->Send[lValue2].WetFilter.filter = 0;
747 else
748 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
749 Source->NeedsUpdate = AL_TRUE;
751 else
752 alSetError(pContext, AL_INVALID_VALUE);
753 } break;
755 default:
756 alSetError(pContext, AL_INVALID_ENUM);
757 break;
760 else
761 alSetError(pContext, AL_INVALID_NAME);
763 ProcessContext(pContext);
767 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
769 ALCcontext *pContext;
771 pContext = GetContextSuspended();
772 if(!pContext) return;
774 if(plValues)
776 if(LookupSource(pContext->SourceMap, source) != NULL)
778 switch(eParam)
780 case AL_SOURCE_RELATIVE:
781 case AL_CONE_INNER_ANGLE:
782 case AL_CONE_OUTER_ANGLE:
783 case AL_LOOPING:
784 case AL_BUFFER:
785 case AL_SOURCE_STATE:
786 case AL_SEC_OFFSET:
787 case AL_SAMPLE_OFFSET:
788 case AL_BYTE_OFFSET:
789 case AL_MAX_DISTANCE:
790 case AL_ROLLOFF_FACTOR:
791 case AL_REFERENCE_DISTANCE:
792 case AL_DIRECT_FILTER:
793 case AL_DIRECT_FILTER_GAINHF_AUTO:
794 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
795 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
796 case AL_DISTANCE_MODEL:
797 alSourcei(source, eParam, plValues[0]);
798 break;
800 case AL_POSITION:
801 case AL_VELOCITY:
802 case AL_DIRECTION:
803 case AL_AUXILIARY_SEND_FILTER:
804 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
805 break;
807 default:
808 alSetError(pContext, AL_INVALID_ENUM);
809 break;
812 else
813 alSetError(pContext, AL_INVALID_NAME);
815 else
816 alSetError(pContext, AL_INVALID_VALUE);
818 ProcessContext(pContext);
822 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
824 ALCcontext *pContext;
825 ALsource *Source;
826 ALdouble Offsets[2];
827 ALdouble updateLen;
829 pContext = GetContextSuspended();
830 if(!pContext) return;
832 if(pflValue)
834 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
836 switch(eParam)
838 case AL_PITCH:
839 *pflValue = Source->flPitch;
840 break;
842 case AL_GAIN:
843 *pflValue = Source->flGain;
844 break;
846 case AL_MIN_GAIN:
847 *pflValue = Source->flMinGain;
848 break;
850 case AL_MAX_GAIN:
851 *pflValue = Source->flMaxGain;
852 break;
854 case AL_MAX_DISTANCE:
855 *pflValue = Source->flMaxDistance;
856 break;
858 case AL_ROLLOFF_FACTOR:
859 *pflValue = Source->flRollOffFactor;
860 break;
862 case AL_CONE_OUTER_GAIN:
863 *pflValue = Source->flOuterGain;
864 break;
866 case AL_CONE_OUTER_GAINHF:
867 *pflValue = Source->OuterGainHF;
868 break;
870 case AL_SEC_OFFSET:
871 case AL_SAMPLE_OFFSET:
872 case AL_BYTE_OFFSET:
873 updateLen = (ALdouble)pContext->Device->UpdateSize /
874 pContext->Device->Frequency;
875 GetSourceOffset(Source, eParam, Offsets, updateLen);
876 *pflValue = Offsets[0];
877 break;
879 case AL_CONE_INNER_ANGLE:
880 *pflValue = Source->flInnerAngle;
881 break;
883 case AL_CONE_OUTER_ANGLE:
884 *pflValue = Source->flOuterAngle;
885 break;
887 case AL_REFERENCE_DISTANCE:
888 *pflValue = Source->flRefDistance;
889 break;
891 case AL_AIR_ABSORPTION_FACTOR:
892 *pflValue = Source->AirAbsorptionFactor;
893 break;
895 case AL_ROOM_ROLLOFF_FACTOR:
896 *pflValue = Source->RoomRolloffFactor;
897 break;
899 case AL_DOPPLER_FACTOR:
900 *pflValue = Source->DopplerFactor;
901 break;
903 default:
904 alSetError(pContext, AL_INVALID_ENUM);
905 break;
908 else
909 alSetError(pContext, AL_INVALID_NAME);
911 else
912 alSetError(pContext, AL_INVALID_VALUE);
914 ProcessContext(pContext);
918 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
920 ALCcontext *pContext;
921 ALsource *Source;
923 pContext = GetContextSuspended();
924 if(!pContext) return;
926 if(pflValue1 && pflValue2 && pflValue3)
928 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
930 switch(eParam)
932 case AL_POSITION:
933 *pflValue1 = Source->vPosition[0];
934 *pflValue2 = Source->vPosition[1];
935 *pflValue3 = Source->vPosition[2];
936 break;
938 case AL_VELOCITY:
939 *pflValue1 = Source->vVelocity[0];
940 *pflValue2 = Source->vVelocity[1];
941 *pflValue3 = Source->vVelocity[2];
942 break;
944 case AL_DIRECTION:
945 *pflValue1 = Source->vOrientation[0];
946 *pflValue2 = Source->vOrientation[1];
947 *pflValue3 = Source->vOrientation[2];
948 break;
950 default:
951 alSetError(pContext, AL_INVALID_ENUM);
952 break;
955 else
956 alSetError(pContext, AL_INVALID_NAME);
958 else
959 alSetError(pContext, AL_INVALID_VALUE);
961 ProcessContext(pContext);
965 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
967 ALCcontext *pContext;
968 ALsource *Source;
969 ALdouble Offsets[2];
970 ALdouble updateLen;
972 pContext = GetContextSuspended();
973 if(!pContext) return;
975 if(pflValues)
977 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
979 switch(eParam)
981 case AL_PITCH:
982 case AL_GAIN:
983 case AL_MIN_GAIN:
984 case AL_MAX_GAIN:
985 case AL_MAX_DISTANCE:
986 case AL_ROLLOFF_FACTOR:
987 case AL_DOPPLER_FACTOR:
988 case AL_CONE_OUTER_GAIN:
989 case AL_SEC_OFFSET:
990 case AL_SAMPLE_OFFSET:
991 case AL_BYTE_OFFSET:
992 case AL_CONE_INNER_ANGLE:
993 case AL_CONE_OUTER_ANGLE:
994 case AL_REFERENCE_DISTANCE:
995 case AL_CONE_OUTER_GAINHF:
996 case AL_AIR_ABSORPTION_FACTOR:
997 case AL_ROOM_ROLLOFF_FACTOR:
998 alGetSourcef(source, eParam, pflValues);
999 break;
1001 case AL_POSITION:
1002 case AL_VELOCITY:
1003 case AL_DIRECTION:
1004 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1005 break;
1007 case AL_SAMPLE_RW_OFFSETS_SOFT:
1008 case AL_BYTE_RW_OFFSETS_SOFT:
1009 updateLen = (ALdouble)pContext->Device->UpdateSize /
1010 pContext->Device->Frequency;
1011 GetSourceOffset(Source, eParam, Offsets, updateLen);
1012 pflValues[0] = Offsets[0];
1013 pflValues[1] = Offsets[1];
1014 break;
1016 default:
1017 alSetError(pContext, AL_INVALID_ENUM);
1018 break;
1021 else
1022 alSetError(pContext, AL_INVALID_NAME);
1024 else
1025 alSetError(pContext, AL_INVALID_VALUE);
1027 ProcessContext(pContext);
1031 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1033 ALCcontext *pContext;
1034 ALsource *Source;
1035 ALdouble Offsets[2];
1036 ALdouble updateLen;
1038 pContext = GetContextSuspended();
1039 if(!pContext) return;
1041 if(plValue)
1043 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1045 switch(eParam)
1047 case AL_MAX_DISTANCE:
1048 *plValue = (ALint)Source->flMaxDistance;
1049 break;
1051 case AL_ROLLOFF_FACTOR:
1052 *plValue = (ALint)Source->flRollOffFactor;
1053 break;
1055 case AL_REFERENCE_DISTANCE:
1056 *plValue = (ALint)Source->flRefDistance;
1057 break;
1059 case AL_SOURCE_RELATIVE:
1060 *plValue = Source->bHeadRelative;
1061 break;
1063 case AL_CONE_INNER_ANGLE:
1064 *plValue = (ALint)Source->flInnerAngle;
1065 break;
1067 case AL_CONE_OUTER_ANGLE:
1068 *plValue = (ALint)Source->flOuterAngle;
1069 break;
1071 case AL_LOOPING:
1072 *plValue = Source->bLooping;
1073 break;
1075 case AL_BUFFER:
1076 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1077 break;
1079 case AL_SOURCE_STATE:
1080 *plValue = Source->state;
1081 break;
1083 case AL_BUFFERS_QUEUED:
1084 *plValue = Source->BuffersInQueue;
1085 break;
1087 case AL_BUFFERS_PROCESSED:
1088 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1090 /* Buffers on a looping source are in a perpetual state
1091 * of PENDING, so don't report any as PROCESSED */
1092 *plValue = 0;
1094 else
1095 *plValue = Source->BuffersPlayed;
1096 break;
1098 case AL_SOURCE_TYPE:
1099 *plValue = Source->lSourceType;
1100 break;
1102 case AL_SEC_OFFSET:
1103 case AL_SAMPLE_OFFSET:
1104 case AL_BYTE_OFFSET:
1105 updateLen = (ALdouble)pContext->Device->UpdateSize /
1106 pContext->Device->Frequency;
1107 GetSourceOffset(Source, eParam, Offsets, updateLen);
1108 *plValue = (ALint)Offsets[0];
1109 break;
1111 case AL_DIRECT_FILTER:
1112 *plValue = Source->DirectFilter.filter;
1113 break;
1115 case AL_DIRECT_FILTER_GAINHF_AUTO:
1116 *plValue = Source->DryGainHFAuto;
1117 break;
1119 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1120 *plValue = Source->WetGainAuto;
1121 break;
1123 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1124 *plValue = Source->WetGainHFAuto;
1125 break;
1127 case AL_DOPPLER_FACTOR:
1128 *plValue = (ALint)Source->DopplerFactor;
1129 break;
1131 case AL_DISTANCE_MODEL:
1132 *plValue = Source->DistanceModel;
1133 break;
1135 default:
1136 alSetError(pContext, AL_INVALID_ENUM);
1137 break;
1140 else
1141 alSetError(pContext, AL_INVALID_NAME);
1143 else
1144 alSetError(pContext, AL_INVALID_VALUE);
1146 ProcessContext(pContext);
1150 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1152 ALCcontext *pContext;
1153 ALsource *Source;
1155 pContext = GetContextSuspended();
1156 if(!pContext) return;
1158 if(plValue1 && plValue2 && plValue3)
1160 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1162 switch(eParam)
1164 case AL_POSITION:
1165 *plValue1 = (ALint)Source->vPosition[0];
1166 *plValue2 = (ALint)Source->vPosition[1];
1167 *plValue3 = (ALint)Source->vPosition[2];
1168 break;
1170 case AL_VELOCITY:
1171 *plValue1 = (ALint)Source->vVelocity[0];
1172 *plValue2 = (ALint)Source->vVelocity[1];
1173 *plValue3 = (ALint)Source->vVelocity[2];
1174 break;
1176 case AL_DIRECTION:
1177 *plValue1 = (ALint)Source->vOrientation[0];
1178 *plValue2 = (ALint)Source->vOrientation[1];
1179 *plValue3 = (ALint)Source->vOrientation[2];
1180 break;
1182 default:
1183 alSetError(pContext, AL_INVALID_ENUM);
1184 break;
1187 else
1188 alSetError(pContext, AL_INVALID_NAME);
1190 else
1191 alSetError(pContext, AL_INVALID_VALUE);
1193 ProcessContext(pContext);
1197 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1199 ALCcontext *pContext;
1200 ALsource *Source;
1201 ALdouble Offsets[2];
1202 ALdouble updateLen;
1204 pContext = GetContextSuspended();
1205 if(!pContext) return;
1207 if(plValues)
1209 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1211 switch(eParam)
1213 case AL_SOURCE_RELATIVE:
1214 case AL_CONE_INNER_ANGLE:
1215 case AL_CONE_OUTER_ANGLE:
1216 case AL_LOOPING:
1217 case AL_BUFFER:
1218 case AL_SOURCE_STATE:
1219 case AL_BUFFERS_QUEUED:
1220 case AL_BUFFERS_PROCESSED:
1221 case AL_SEC_OFFSET:
1222 case AL_SAMPLE_OFFSET:
1223 case AL_BYTE_OFFSET:
1224 case AL_MAX_DISTANCE:
1225 case AL_ROLLOFF_FACTOR:
1226 case AL_DOPPLER_FACTOR:
1227 case AL_REFERENCE_DISTANCE:
1228 case AL_SOURCE_TYPE:
1229 case AL_DIRECT_FILTER:
1230 case AL_DIRECT_FILTER_GAINHF_AUTO:
1231 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1232 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1233 case AL_DISTANCE_MODEL:
1234 alGetSourcei(source, eParam, plValues);
1235 break;
1237 case AL_POSITION:
1238 case AL_VELOCITY:
1239 case AL_DIRECTION:
1240 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1241 break;
1243 case AL_SAMPLE_RW_OFFSETS_SOFT:
1244 case AL_BYTE_RW_OFFSETS_SOFT:
1245 updateLen = (ALdouble)pContext->Device->UpdateSize /
1246 pContext->Device->Frequency;
1247 GetSourceOffset(Source, eParam, Offsets, updateLen);
1248 plValues[0] = (ALint)Offsets[0];
1249 plValues[1] = (ALint)Offsets[1];
1250 break;
1252 default:
1253 alSetError(pContext, AL_INVALID_ENUM);
1254 break;
1257 else
1258 alSetError(pContext, AL_INVALID_NAME);
1260 else
1261 alSetError(pContext, AL_INVALID_VALUE);
1263 ProcessContext(pContext);
1267 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1269 alSourcePlayv(1, &source);
1272 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1274 ALCcontext *Context;
1275 ALsource *Source;
1276 ALbufferlistitem *BufferList;
1277 ALsizei i, j;
1279 Context = GetContextSuspended();
1280 if(!Context) return;
1282 if(n < 0)
1284 alSetError(Context, AL_INVALID_VALUE);
1285 goto done;
1287 if(n > 0 && !sources)
1289 alSetError(Context, AL_INVALID_VALUE);
1290 goto done;
1293 // Check that all the Sources are valid
1294 for(i = 0;i < n;i++)
1296 if(!LookupSource(Context->SourceMap, sources[i]))
1298 alSetError(Context, AL_INVALID_NAME);
1299 goto done;
1303 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1305 void *temp = NULL;
1306 ALsizei newcount;
1308 newcount = Context->MaxActiveSources << 1;
1309 if(newcount > 0)
1310 temp = realloc(Context->ActiveSources,
1311 sizeof(*Context->ActiveSources) * newcount);
1312 if(!temp)
1314 alSetError(Context, AL_OUT_OF_MEMORY);
1315 goto done;
1318 Context->ActiveSources = temp;
1319 Context->MaxActiveSources = newcount;
1322 for(i = 0;i < n;i++)
1324 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1326 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1327 BufferList = Source->queue;
1328 while(BufferList)
1330 if(BufferList->buffer != NULL && BufferList->buffer->size)
1331 break;
1332 BufferList = BufferList->next;
1335 if(!BufferList)
1337 Source->state = AL_STOPPED;
1338 Source->BuffersPlayed = Source->BuffersInQueue;
1339 Source->position = 0;
1340 Source->position_fraction = 0;
1341 Source->lOffset = 0;
1342 continue;
1345 if(Source->state != AL_PAUSED)
1347 Source->state = AL_PLAYING;
1348 Source->position = 0;
1349 Source->position_fraction = 0;
1350 Source->BuffersPlayed = 0;
1352 Source->Buffer = Source->queue->buffer;
1354 else
1355 Source->state = AL_PLAYING;
1357 // Check if an Offset has been set
1358 if(Source->lOffset)
1359 ApplyOffset(Source);
1361 // If device is disconnected, go right to stopped
1362 if(!Context->Device->Connected)
1364 Source->state = AL_STOPPED;
1365 Source->BuffersPlayed = Source->BuffersInQueue;
1366 Source->position = 0;
1367 Source->position_fraction = 0;
1369 else
1371 for(j = 0;j < Context->ActiveSourceCount;j++)
1373 if(Context->ActiveSources[j] == Source)
1374 break;
1376 if(j == Context->ActiveSourceCount)
1377 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1381 done:
1382 ProcessContext(Context);
1385 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1387 alSourcePausev(1, &source);
1390 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1392 ALCcontext *Context;
1393 ALsource *Source;
1394 ALsizei i;
1396 Context = GetContextSuspended();
1397 if(!Context) return;
1399 if(n < 0)
1401 alSetError(Context, AL_INVALID_VALUE);
1402 goto done;
1404 if(n > 0 && !sources)
1406 alSetError(Context, AL_INVALID_VALUE);
1407 goto done;
1410 // Check all the Sources are valid
1411 for(i = 0;i < n;i++)
1413 if(!LookupSource(Context->SourceMap, sources[i]))
1415 alSetError(Context, AL_INVALID_NAME);
1416 goto done;
1420 for(i = 0;i < n;i++)
1422 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1423 if(Source->state == AL_PLAYING)
1424 Source->state = AL_PAUSED;
1427 done:
1428 ProcessContext(Context);
1431 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1433 alSourceStopv(1, &source);
1436 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1438 ALCcontext *Context;
1439 ALsource *Source;
1440 ALsizei i;
1442 Context = GetContextSuspended();
1443 if(!Context) return;
1445 if(n < 0)
1447 alSetError(Context, AL_INVALID_VALUE);
1448 goto done;
1450 if(n > 0 && !sources)
1452 alSetError(Context, AL_INVALID_VALUE);
1453 goto done;
1456 // Check all the Sources are valid
1457 for(i = 0;i < n;i++)
1459 if(!LookupSource(Context->SourceMap, sources[i]))
1461 alSetError(Context, AL_INVALID_NAME);
1462 goto done;
1466 for(i = 0;i < n;i++)
1468 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1469 if(Source->state != AL_INITIAL)
1471 Source->state = AL_STOPPED;
1472 Source->BuffersPlayed = Source->BuffersInQueue;
1474 Source->lOffset = 0;
1477 done:
1478 ProcessContext(Context);
1481 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1483 alSourceRewindv(1, &source);
1486 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1488 ALCcontext *Context;
1489 ALsource *Source;
1490 ALsizei i;
1492 Context = GetContextSuspended();
1493 if(!Context) return;
1495 if(n < 0)
1497 alSetError(Context, AL_INVALID_VALUE);
1498 goto done;
1500 if(n > 0 && !sources)
1502 alSetError(Context, AL_INVALID_VALUE);
1503 goto done;
1506 // Check all the Sources are valid
1507 for(i = 0;i < n;i++)
1509 if(!LookupSource(Context->SourceMap, sources[i]))
1511 alSetError(Context, AL_INVALID_NAME);
1512 goto done;
1516 for(i = 0;i < n;i++)
1518 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1519 if(Source->state != AL_INITIAL)
1521 Source->state = AL_INITIAL;
1522 Source->position = 0;
1523 Source->position_fraction = 0;
1524 Source->BuffersPlayed = 0;
1525 if(Source->queue)
1526 Source->Buffer = Source->queue->buffer;
1528 Source->lOffset = 0;
1531 done:
1532 ProcessContext(Context);
1536 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1538 ALCcontext *Context;
1539 ALCdevice *device;
1540 ALsource *Source;
1541 ALbuffer *buffer;
1542 ALsizei i;
1543 ALbufferlistitem *BufferListStart;
1544 ALbufferlistitem *BufferList;
1545 ALbuffer *BufferFmt;
1547 if(n == 0)
1548 return;
1550 Context = GetContextSuspended();
1551 if(!Context) return;
1553 if(n < 0)
1555 alSetError(Context, AL_INVALID_VALUE);
1556 goto done;
1559 // Check that all buffers are valid or zero and that the source is valid
1561 // Check that this is a valid source
1562 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1564 alSetError(Context, AL_INVALID_NAME);
1565 goto done;
1568 // Check that this is not a STATIC Source
1569 if(Source->lSourceType == AL_STATIC)
1571 // Invalid Source Type (can't queue on a Static Source)
1572 alSetError(Context, AL_INVALID_OPERATION);
1573 goto done;
1576 device = Context->Device;
1578 BufferFmt = NULL;
1580 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1581 BufferList = Source->queue;
1582 while(BufferList)
1584 if(BufferList->buffer)
1586 BufferFmt = BufferList->buffer;
1587 break;
1589 BufferList = BufferList->next;
1592 for(i = 0;i < n;i++)
1594 if(!buffers[i])
1595 continue;
1597 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1599 alSetError(Context, AL_INVALID_NAME);
1600 goto done;
1603 if(BufferFmt == NULL)
1605 BufferFmt = buffer;
1607 if(buffer->FmtChannels == FmtMono)
1608 Source->Update = CalcSourceParams;
1609 else
1610 Source->Update = CalcNonAttnSourceParams;
1612 Source->NeedsUpdate = AL_TRUE;
1614 else if(BufferFmt->Frequency != buffer->Frequency ||
1615 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1616 BufferFmt->OriginalType != buffer->OriginalType)
1618 alSetError(Context, AL_INVALID_OPERATION);
1619 goto done;
1623 // Change Source Type
1624 Source->lSourceType = AL_STREAMING;
1626 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1628 // All buffers are valid - so add them to the list
1629 BufferListStart = malloc(sizeof(ALbufferlistitem));
1630 BufferListStart->buffer = buffer;
1631 BufferListStart->next = NULL;
1632 BufferListStart->prev = NULL;
1634 // Increment reference counter for buffer
1635 if(buffer) buffer->refcount++;
1637 BufferList = BufferListStart;
1639 for(i = 1;i < n;i++)
1641 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1643 BufferList->next = malloc(sizeof(ALbufferlistitem));
1644 BufferList->next->buffer = buffer;
1645 BufferList->next->next = NULL;
1646 BufferList->next->prev = BufferList;
1648 // Increment reference counter for buffer
1649 if(buffer) buffer->refcount++;
1651 BufferList = BufferList->next;
1654 if(Source->queue == NULL)
1656 Source->queue = BufferListStart;
1657 // Update Current Buffer
1658 Source->Buffer = BufferListStart->buffer;
1660 else
1662 // Find end of queue
1663 BufferList = Source->queue;
1664 while(BufferList->next != NULL)
1665 BufferList = BufferList->next;
1667 BufferList->next = BufferListStart;
1668 BufferList->next->prev = BufferList;
1671 // Update number of buffers in queue
1672 Source->BuffersInQueue += n;
1674 done:
1675 ProcessContext(Context);
1679 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1680 // an array of buffer IDs that are to be filled with the names of the buffers removed
1681 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1683 ALCcontext *Context;
1684 ALsource *Source;
1685 ALsizei i;
1686 ALbufferlistitem *BufferList;
1688 if(n == 0)
1689 return;
1691 Context = GetContextSuspended();
1692 if(!Context) return;
1694 if(n < 0)
1696 alSetError(Context, AL_INVALID_VALUE);
1697 goto done;
1700 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1702 alSetError(Context, AL_INVALID_NAME);
1703 goto done;
1706 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1707 (ALuint)n > Source->BuffersPlayed)
1709 // Some buffers can't be unqueue because they have not been processed
1710 alSetError(Context, AL_INVALID_VALUE);
1711 goto done;
1714 for(i = 0;i < n;i++)
1716 BufferList = Source->queue;
1717 Source->queue = BufferList->next;
1719 if(BufferList->buffer)
1721 // Record name of buffer
1722 buffers[i] = BufferList->buffer->buffer;
1723 // Decrement buffer reference counter
1724 BufferList->buffer->refcount--;
1726 else
1727 buffers[i] = 0;
1729 // Release memory for buffer list item
1730 free(BufferList);
1731 Source->BuffersInQueue--;
1733 if(Source->queue)
1734 Source->queue->prev = NULL;
1736 if(Source->state != AL_PLAYING)
1738 if(Source->queue)
1739 Source->Buffer = Source->queue->buffer;
1740 else
1741 Source->Buffer = NULL;
1743 Source->BuffersPlayed -= n;
1745 done:
1746 ProcessContext(Context);
1750 static ALvoid InitSourceParams(ALsource *Source)
1752 Source->flInnerAngle = 360.0f;
1753 Source->flOuterAngle = 360.0f;
1754 Source->flPitch = 1.0f;
1755 Source->vPosition[0] = 0.0f;
1756 Source->vPosition[1] = 0.0f;
1757 Source->vPosition[2] = 0.0f;
1758 Source->vOrientation[0] = 0.0f;
1759 Source->vOrientation[1] = 0.0f;
1760 Source->vOrientation[2] = 0.0f;
1761 Source->vVelocity[0] = 0.0f;
1762 Source->vVelocity[1] = 0.0f;
1763 Source->vVelocity[2] = 0.0f;
1764 Source->flRefDistance = 1.0f;
1765 Source->flMaxDistance = FLT_MAX;
1766 Source->flRollOffFactor = 1.0f;
1767 Source->bLooping = AL_FALSE;
1768 Source->flGain = 1.0f;
1769 Source->flMinGain = 0.0f;
1770 Source->flMaxGain = 1.0f;
1771 Source->flOuterGain = 0.0f;
1772 Source->OuterGainHF = 1.0f;
1774 Source->DryGainHFAuto = AL_TRUE;
1775 Source->WetGainAuto = AL_TRUE;
1776 Source->WetGainHFAuto = AL_TRUE;
1777 Source->AirAbsorptionFactor = 0.0f;
1778 Source->RoomRolloffFactor = 0.0f;
1779 Source->DopplerFactor = 1.0f;
1781 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1783 Source->Resampler = DefaultResampler;
1785 Source->state = AL_INITIAL;
1786 Source->lSourceType = AL_UNDETERMINED;
1788 Source->NeedsUpdate = AL_TRUE;
1790 Source->Buffer = NULL;
1795 GetSourceOffset
1797 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1798 The offset is relative to the start of the queue (not the start of the current buffer)
1800 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1802 ALbufferlistitem *BufferList;
1803 ALbuffer *Buffer = NULL;
1804 ALfloat BufferFreq;
1805 ALint Channels, Bytes;
1806 ALuint readPos, writePos;
1807 enum SrcFmtType OriginalType;
1808 ALuint TotalBufferDataSize;
1809 ALuint i;
1811 // Find the first non-NULL Buffer in the Queue
1812 BufferList = Source->queue;
1813 while(BufferList)
1815 if(BufferList->buffer)
1817 Buffer = BufferList->buffer;
1818 break;
1820 BufferList = BufferList->next;
1823 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1825 offset[0] = 0.0;
1826 offset[1] = 0.0;
1827 return;
1830 // Get Current Buffer Size and frequency (in milliseconds)
1831 BufferFreq = (ALfloat)Buffer->Frequency;
1832 OriginalType = Buffer->OriginalType;
1833 Channels = ChannelsFromFmt(Buffer->FmtChannels);
1834 Bytes = BytesFromFmt(Buffer->FmtType);
1836 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1837 readPos = Source->position * Channels * Bytes;
1838 // Add byte length of any processed buffers in the queue
1839 TotalBufferDataSize = 0;
1840 BufferList = Source->queue;
1841 for(i = 0;BufferList;i++)
1843 if(BufferList->buffer)
1845 if(i < Source->BuffersPlayed)
1846 readPos += BufferList->buffer->size;
1847 TotalBufferDataSize += BufferList->buffer->size;
1849 BufferList = BufferList->next;
1851 if(Source->state == AL_PLAYING)
1852 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1853 else
1854 writePos = readPos;
1856 if(Source->bLooping)
1858 readPos %= TotalBufferDataSize;
1859 writePos %= TotalBufferDataSize;
1861 else
1863 // Wrap positions back to 0
1864 if(readPos >= TotalBufferDataSize)
1865 readPos = 0;
1866 if(writePos >= TotalBufferDataSize)
1867 writePos = 0;
1870 switch(name)
1872 case AL_SEC_OFFSET:
1873 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1874 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1875 break;
1876 case AL_SAMPLE_OFFSET:
1877 case AL_SAMPLE_RW_OFFSETS_SOFT:
1878 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1879 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1880 break;
1881 case AL_BYTE_OFFSET:
1882 case AL_BYTE_RW_OFFSETS_SOFT:
1883 // Take into account the original format of the Buffer
1884 if(OriginalType == SrcFmtIMA4)
1886 ALuint FrameBlockSize = 65 * Bytes * Channels;
1887 ALuint BlockSize = 36 * Channels;
1889 // Round down to nearest ADPCM block
1890 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1891 if(Source->state != AL_PLAYING)
1892 offset[1] = offset[0];
1893 else
1895 // Round up to nearest ADPCM block
1896 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1897 FrameBlockSize * BlockSize);
1900 else
1902 ALuint OrigBytes = BytesFromSrcFmt(OriginalType);
1903 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1904 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1906 break;
1912 ApplyOffset
1914 Apply a playback offset to the Source. This function will update the queue (to correctly
1915 mark buffers as 'pending' or 'processed' depending upon the new offset.
1917 static ALboolean ApplyOffset(ALsource *Source)
1919 ALbufferlistitem *BufferList;
1920 ALbuffer *Buffer;
1921 ALint lBufferSize, lTotalBufferSize;
1922 ALint BuffersPlayed;
1923 ALint lByteOffset;
1925 // Get true byte offset
1926 lByteOffset = GetByteOffset(Source);
1928 // If the offset is invalid, don't apply it
1929 if(lByteOffset == -1)
1930 return AL_FALSE;
1932 // Sort out the queue (pending and processed states)
1933 BufferList = Source->queue;
1934 lTotalBufferSize = 0;
1935 BuffersPlayed = 0;
1937 while(BufferList)
1939 Buffer = BufferList->buffer;
1940 lBufferSize = Buffer ? Buffer->size : 0;
1942 if(lBufferSize <= lByteOffset-lTotalBufferSize)
1944 // Offset is past this buffer so increment BuffersPlayed
1945 BuffersPlayed++;
1947 else if(lTotalBufferSize <= lByteOffset)
1949 // Offset is within this buffer
1950 // Set Current Buffer
1951 Source->Buffer = BufferList->buffer;
1952 Source->BuffersPlayed = BuffersPlayed;
1954 // SW Mixer Positions are in Samples
1955 Source->position = (lByteOffset - lTotalBufferSize) /
1956 FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
1957 return AL_TRUE;
1960 // Increment the TotalBufferSize
1961 lTotalBufferSize += lBufferSize;
1963 // Move on to next buffer in the Queue
1964 BufferList = BufferList->next;
1966 // Offset is out of range of the buffer queue
1967 return AL_FALSE;
1972 GetByteOffset
1974 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1975 offset supplied by the application). This takes into account the fact that the buffer format
1976 may have been modifed by AL (e.g 8bit samples are converted to float)
1978 static ALint GetByteOffset(ALsource *Source)
1980 ALbuffer *Buffer = NULL;
1981 ALbufferlistitem *BufferList;
1982 ALint ByteOffset = -1;
1984 // Find the first non-NULL Buffer in the Queue
1985 BufferList = Source->queue;
1986 while(BufferList)
1988 if(BufferList->buffer)
1990 Buffer = BufferList->buffer;
1991 break;
1993 BufferList = BufferList->next;
1996 if(!Buffer)
1998 Source->lOffset = 0;
1999 return -1;
2002 // Determine the ByteOffset (and ensure it is block aligned)
2003 switch(Source->lOffsetType)
2005 case AL_BYTE_OFFSET:
2006 // Take into consideration the original format
2007 ByteOffset = Source->lOffset;
2008 if(Buffer->OriginalType == SrcFmtIMA4)
2010 // Round down to nearest ADPCM block
2011 ByteOffset /= 36 * ChannelsFromSrcFmt(Buffer->OriginalChannels);
2012 // Multiply by compression rate (65 sample frames per block)
2013 ByteOffset *= 65;
2015 else
2016 ByteOffset /= FrameSizeFromSrcFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2017 ByteOffset *= FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
2018 break;
2020 case AL_SAMPLE_OFFSET:
2021 ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
2022 break;
2024 case AL_SEC_OFFSET:
2025 // Note - lOffset is internally stored as Milliseconds
2026 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2027 ByteOffset *= FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
2028 break;
2030 // Clear Offset
2031 Source->lOffset = 0;
2033 return ByteOffset;
2037 ALvoid ReleaseALSources(ALCcontext *Context)
2039 ALsizei pos;
2040 ALuint j;
2041 for(pos = 0;pos < Context->SourceMap.size;pos++)
2043 ALsource *temp = Context->SourceMap.array[pos].value;
2044 Context->SourceMap.array[pos].value = NULL;
2046 // For each buffer in the source's queue, decrement its reference counter and remove it
2047 while(temp->queue != NULL)
2049 ALbufferlistitem *BufferList = temp->queue;
2050 temp->queue = BufferList->next;
2052 if(BufferList->buffer != NULL)
2053 BufferList->buffer->refcount--;
2054 free(BufferList);
2057 for(j = 0;j < MAX_SENDS;++j)
2059 if(temp->Send[j].Slot)
2060 temp->Send[j].Slot->refcount--;
2061 temp->Send[j].Slot = NULL;
2064 // Release source structure
2065 ALTHUNK_REMOVEENTRY(temp->source);
2066 memset(temp, 0, sizeof(ALsource));
2067 free(temp);