Keep a handle on the buffer with the format when queueing new buffers
[openal-soft.git] / OpenAL32 / alSource.c
blob34830766769e4f69d132b81323d45cfe66bddf68
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);
53 static ALint FramesFromBytes(ALint offset, ALenum format);
55 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
56 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
57 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
58 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
60 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
62 ALCcontext *Context;
63 ALCdevice *Device;
65 Context = GetContextSuspended();
66 if(!Context) return;
68 Device = Context->Device;
69 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
70 alSetError(Context, AL_INVALID_VALUE);
71 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
72 alSetError(Context, AL_INVALID_VALUE);
73 else
75 ALenum err;
76 ALsizei i;
78 // Add additional sources to the list
79 i = 0;
80 while(i < n)
82 ALsource *source = calloc(1, sizeof(ALsource));
83 if(!source)
85 alSetError(Context, AL_OUT_OF_MEMORY);
86 alDeleteSources(i, sources);
87 break;
90 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
91 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
92 source);
93 if(err != AL_NO_ERROR)
95 ALTHUNK_REMOVEENTRY(source->source);
96 memset(source, 0, sizeof(ALsource));
97 free(source);
99 alSetError(Context, err);
100 alDeleteSources(i, sources);
101 break;
104 sources[i++] = source->source;
105 InitSourceParams(source);
109 ProcessContext(Context);
113 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
115 ALCcontext *Context;
116 ALsource *Source;
117 ALsizei i, j;
118 ALbufferlistitem *BufferList;
119 ALboolean SourcesValid = AL_FALSE;
121 Context = GetContextSuspended();
122 if(!Context) return;
124 if(n < 0)
125 alSetError(Context, AL_INVALID_VALUE);
126 else
128 SourcesValid = AL_TRUE;
129 // Check that all Sources are valid (and can therefore be deleted)
130 for(i = 0;i < n;i++)
132 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
134 alSetError(Context, AL_INVALID_NAME);
135 SourcesValid = AL_FALSE;
136 break;
141 if(SourcesValid)
143 // All Sources are valid, and can be deleted
144 for(i = 0;i < n;i++)
146 // Recheck that the Source is valid, because there could be duplicated Source names
147 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
148 continue;
150 for(j = 0;j < Context->ActiveSourceCount;j++)
152 if(Context->ActiveSources[j] == Source)
154 ALsizei end = --(Context->ActiveSourceCount);
155 Context->ActiveSources[j] = Context->ActiveSources[end];
156 break;
160 // For each buffer in the source's queue...
161 while(Source->queue != NULL)
163 BufferList = Source->queue;
164 Source->queue = BufferList->next;
166 if(BufferList->buffer != NULL)
167 BufferList->buffer->refcount--;
168 free(BufferList);
171 for(j = 0;j < MAX_SENDS;++j)
173 if(Source->Send[j].Slot)
174 Source->Send[j].Slot->refcount--;
175 Source->Send[j].Slot = NULL;
178 // Remove Source from list of Sources
179 RemoveUIntMapKey(&Context->SourceMap, Source->source);
180 ALTHUNK_REMOVEENTRY(Source->source);
182 memset(Source,0,sizeof(ALsource));
183 free(Source);
187 ProcessContext(Context);
191 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
193 ALCcontext *Context;
194 ALboolean result;
196 Context = GetContextSuspended();
197 if(!Context) return AL_FALSE;
199 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
201 ProcessContext(Context);
203 return result;
207 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
209 ALCcontext *pContext;
210 ALsource *Source;
212 pContext = GetContextSuspended();
213 if(!pContext) return;
215 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
217 switch(eParam)
219 case AL_PITCH:
220 if(flValue >= 0.0f)
222 Source->flPitch = flValue;
223 if(Source->flPitch < 0.001f)
224 Source->flPitch = 0.001f;
225 Source->NeedsUpdate = AL_TRUE;
227 else
228 alSetError(pContext, AL_INVALID_VALUE);
229 break;
231 case AL_CONE_INNER_ANGLE:
232 if(flValue >= 0.0f && flValue <= 360.0f)
234 Source->flInnerAngle = flValue;
235 Source->NeedsUpdate = AL_TRUE;
237 else
238 alSetError(pContext, AL_INVALID_VALUE);
239 break;
241 case AL_CONE_OUTER_ANGLE:
242 if(flValue >= 0.0f && flValue <= 360.0f)
244 Source->flOuterAngle = flValue;
245 Source->NeedsUpdate = AL_TRUE;
247 else
248 alSetError(pContext, AL_INVALID_VALUE);
249 break;
251 case AL_GAIN:
252 if(flValue >= 0.0f)
254 Source->flGain = flValue;
255 Source->NeedsUpdate = AL_TRUE;
257 else
258 alSetError(pContext, AL_INVALID_VALUE);
259 break;
261 case AL_MAX_DISTANCE:
262 if(flValue >= 0.0f)
264 Source->flMaxDistance = flValue;
265 Source->NeedsUpdate = AL_TRUE;
267 else
268 alSetError(pContext, AL_INVALID_VALUE);
269 break;
271 case AL_ROLLOFF_FACTOR:
272 if(flValue >= 0.0f)
274 Source->flRollOffFactor = flValue;
275 Source->NeedsUpdate = AL_TRUE;
277 else
278 alSetError(pContext, AL_INVALID_VALUE);
279 break;
281 case AL_REFERENCE_DISTANCE:
282 if(flValue >= 0.0f)
284 Source->flRefDistance = flValue;
285 Source->NeedsUpdate = AL_TRUE;
287 else
288 alSetError(pContext, AL_INVALID_VALUE);
289 break;
291 case AL_MIN_GAIN:
292 if(flValue >= 0.0f && flValue <= 1.0f)
294 Source->flMinGain = flValue;
295 Source->NeedsUpdate = AL_TRUE;
297 else
298 alSetError(pContext, AL_INVALID_VALUE);
299 break;
301 case AL_MAX_GAIN:
302 if(flValue >= 0.0f && flValue <= 1.0f)
304 Source->flMaxGain = flValue;
305 Source->NeedsUpdate = AL_TRUE;
307 else
308 alSetError(pContext, AL_INVALID_VALUE);
309 break;
311 case AL_CONE_OUTER_GAIN:
312 if(flValue >= 0.0f && flValue <= 1.0f)
314 Source->flOuterGain = flValue;
315 Source->NeedsUpdate = AL_TRUE;
317 else
318 alSetError(pContext, AL_INVALID_VALUE);
319 break;
321 case AL_CONE_OUTER_GAINHF:
322 if(flValue >= 0.0f && flValue <= 1.0f)
324 Source->OuterGainHF = flValue;
325 Source->NeedsUpdate = AL_TRUE;
327 else
328 alSetError(pContext, AL_INVALID_VALUE);
329 break;
331 case AL_AIR_ABSORPTION_FACTOR:
332 if(flValue >= 0.0f && flValue <= 10.0f)
334 Source->AirAbsorptionFactor = flValue;
335 Source->NeedsUpdate = AL_TRUE;
337 else
338 alSetError(pContext, AL_INVALID_VALUE);
339 break;
341 case AL_ROOM_ROLLOFF_FACTOR:
342 if(flValue >= 0.0f && flValue <= 10.0f)
344 Source->RoomRolloffFactor = flValue;
345 Source->NeedsUpdate = AL_TRUE;
347 else
348 alSetError(pContext, AL_INVALID_VALUE);
349 break;
351 case AL_DOPPLER_FACTOR:
352 if(flValue >= 0.0f && flValue <= 1.0f)
354 Source->DopplerFactor = flValue;
355 Source->NeedsUpdate = AL_TRUE;
357 else
358 alSetError(pContext, AL_INVALID_VALUE);
359 break;
361 case AL_SEC_OFFSET:
362 case AL_SAMPLE_OFFSET:
363 case AL_BYTE_OFFSET:
364 if(flValue >= 0.0f)
366 Source->lOffsetType = eParam;
368 // Store Offset (convert Seconds into Milliseconds)
369 if(eParam == AL_SEC_OFFSET)
370 Source->lOffset = (ALint)(flValue * 1000.0f);
371 else
372 Source->lOffset = (ALint)flValue;
374 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
376 if(ApplyOffset(Source) == AL_FALSE)
377 alSetError(pContext, AL_INVALID_VALUE);
380 else
381 alSetError(pContext, AL_INVALID_VALUE);
382 break;
384 default:
385 alSetError(pContext, AL_INVALID_ENUM);
386 break;
389 else
391 // Invalid Source Name
392 alSetError(pContext, AL_INVALID_NAME);
395 ProcessContext(pContext);
399 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
401 ALCcontext *pContext;
402 ALsource *Source;
404 pContext = GetContextSuspended();
405 if(!pContext) return;
407 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
409 switch(eParam)
411 case AL_POSITION:
412 Source->vPosition[0] = flValue1;
413 Source->vPosition[1] = flValue2;
414 Source->vPosition[2] = flValue3;
415 Source->NeedsUpdate = AL_TRUE;
416 break;
418 case AL_VELOCITY:
419 Source->vVelocity[0] = flValue1;
420 Source->vVelocity[1] = flValue2;
421 Source->vVelocity[2] = flValue3;
422 Source->NeedsUpdate = AL_TRUE;
423 break;
425 case AL_DIRECTION:
426 Source->vOrientation[0] = flValue1;
427 Source->vOrientation[1] = flValue2;
428 Source->vOrientation[2] = flValue3;
429 Source->NeedsUpdate = AL_TRUE;
430 break;
432 default:
433 alSetError(pContext, AL_INVALID_ENUM);
434 break;
437 else
438 alSetError(pContext, AL_INVALID_NAME);
440 ProcessContext(pContext);
444 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
446 ALCcontext *pContext;
448 pContext = GetContextSuspended();
449 if(!pContext) return;
451 if(pflValues)
453 if(LookupSource(pContext->SourceMap, source) != NULL)
455 switch(eParam)
457 case AL_PITCH:
458 case AL_CONE_INNER_ANGLE:
459 case AL_CONE_OUTER_ANGLE:
460 case AL_GAIN:
461 case AL_MAX_DISTANCE:
462 case AL_ROLLOFF_FACTOR:
463 case AL_REFERENCE_DISTANCE:
464 case AL_MIN_GAIN:
465 case AL_MAX_GAIN:
466 case AL_CONE_OUTER_GAIN:
467 case AL_CONE_OUTER_GAINHF:
468 case AL_SEC_OFFSET:
469 case AL_SAMPLE_OFFSET:
470 case AL_BYTE_OFFSET:
471 case AL_AIR_ABSORPTION_FACTOR:
472 case AL_ROOM_ROLLOFF_FACTOR:
473 alSourcef(source, eParam, pflValues[0]);
474 break;
476 case AL_POSITION:
477 case AL_VELOCITY:
478 case AL_DIRECTION:
479 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
480 break;
482 default:
483 alSetError(pContext, AL_INVALID_ENUM);
484 break;
487 else
488 alSetError(pContext, AL_INVALID_NAME);
490 else
491 alSetError(pContext, AL_INVALID_VALUE);
493 ProcessContext(pContext);
497 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
499 ALCcontext *pContext;
500 ALsource *Source;
501 ALbufferlistitem *BufferListItem;
503 pContext = GetContextSuspended();
504 if(!pContext) return;
506 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
508 ALCdevice *device = pContext->Device;
510 switch(eParam)
512 case AL_MAX_DISTANCE:
513 case AL_ROLLOFF_FACTOR:
514 case AL_CONE_INNER_ANGLE:
515 case AL_CONE_OUTER_ANGLE:
516 case AL_REFERENCE_DISTANCE:
517 alSourcef(source, eParam, (ALfloat)lValue);
518 break;
520 case AL_SOURCE_RELATIVE:
521 if(lValue == AL_FALSE || lValue == AL_TRUE)
523 Source->bHeadRelative = (ALboolean)lValue;
524 Source->NeedsUpdate = AL_TRUE;
526 else
527 alSetError(pContext, AL_INVALID_VALUE);
528 break;
530 case AL_LOOPING:
531 if(lValue == AL_FALSE || lValue == AL_TRUE)
532 Source->bLooping = (ALboolean)lValue;
533 else
534 alSetError(pContext, AL_INVALID_VALUE);
535 break;
537 case AL_BUFFER:
538 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
540 ALbuffer *buffer = NULL;
542 if(lValue == 0 ||
543 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
545 // Remove all elements in the queue
546 while(Source->queue != NULL)
548 BufferListItem = Source->queue;
549 Source->queue = BufferListItem->next;
551 if(BufferListItem->buffer)
552 BufferListItem->buffer->refcount--;
553 free(BufferListItem);
555 Source->BuffersInQueue = 0;
557 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
558 if(buffer != NULL)
560 // Source is now in STATIC mode
561 Source->lSourceType = AL_STATIC;
563 // Add the selected buffer to the queue
564 BufferListItem = malloc(sizeof(ALbufferlistitem));
565 BufferListItem->buffer = buffer;
566 BufferListItem->next = NULL;
567 BufferListItem->prev = NULL;
569 Source->queue = BufferListItem;
570 Source->BuffersInQueue = 1;
572 if(buffer->FmtChannels == FmtMono)
573 Source->Update = CalcSourceParams;
574 else
575 Source->Update = CalcNonAttnSourceParams;
577 // Increment reference counter for buffer
578 buffer->refcount++;
580 else
582 // Source is now in UNDETERMINED mode
583 Source->lSourceType = AL_UNDETERMINED;
585 Source->BuffersPlayed = 0;
587 // Update AL_BUFFER parameter
588 Source->Buffer = buffer;
589 Source->NeedsUpdate = AL_TRUE;
591 else
592 alSetError(pContext, AL_INVALID_VALUE);
594 else
595 alSetError(pContext, AL_INVALID_OPERATION);
596 break;
598 case AL_SOURCE_STATE:
599 // Query only
600 alSetError(pContext, AL_INVALID_OPERATION);
601 break;
603 case AL_SEC_OFFSET:
604 case AL_SAMPLE_OFFSET:
605 case AL_BYTE_OFFSET:
606 if(lValue >= 0)
608 Source->lOffsetType = eParam;
610 // Store Offset (convert Seconds into Milliseconds)
611 if(eParam == AL_SEC_OFFSET)
612 Source->lOffset = lValue * 1000;
613 else
614 Source->lOffset = lValue;
616 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
618 if(ApplyOffset(Source) == AL_FALSE)
619 alSetError(pContext, AL_INVALID_VALUE);
622 else
623 alSetError(pContext, AL_INVALID_VALUE);
624 break;
626 case AL_DIRECT_FILTER: {
627 ALfilter *filter = NULL;
629 if(lValue == 0 ||
630 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
632 if(!filter)
634 Source->DirectFilter.type = AL_FILTER_NULL;
635 Source->DirectFilter.filter = 0;
637 else
638 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
639 Source->NeedsUpdate = AL_TRUE;
641 else
642 alSetError(pContext, AL_INVALID_VALUE);
643 } break;
645 case AL_DIRECT_FILTER_GAINHF_AUTO:
646 if(lValue == AL_TRUE || lValue == AL_FALSE)
648 Source->DryGainHFAuto = lValue;
649 Source->NeedsUpdate = AL_TRUE;
651 else
652 alSetError(pContext, AL_INVALID_VALUE);
653 break;
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
656 if(lValue == AL_TRUE || lValue == AL_FALSE)
658 Source->WetGainAuto = lValue;
659 Source->NeedsUpdate = AL_TRUE;
661 else
662 alSetError(pContext, AL_INVALID_VALUE);
663 break;
665 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
666 if(lValue == AL_TRUE || lValue == AL_FALSE)
668 Source->WetGainHFAuto = lValue;
669 Source->NeedsUpdate = AL_TRUE;
671 else
672 alSetError(pContext, AL_INVALID_VALUE);
673 break;
675 case AL_DISTANCE_MODEL:
676 if(lValue == AL_NONE ||
677 lValue == AL_INVERSE_DISTANCE ||
678 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
679 lValue == AL_LINEAR_DISTANCE ||
680 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
681 lValue == AL_EXPONENT_DISTANCE ||
682 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
684 Source->DistanceModel = lValue;
685 if(pContext->SourceDistanceModel)
686 Source->NeedsUpdate = AL_TRUE;
688 else
689 alSetError(pContext, AL_INVALID_VALUE);
690 break;
692 default:
693 alSetError(pContext, AL_INVALID_ENUM);
694 break;
697 else
698 alSetError(pContext, AL_INVALID_NAME);
700 ProcessContext(pContext);
704 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
706 ALCcontext *pContext;
707 ALsource *Source;
709 pContext = GetContextSuspended();
710 if(!pContext) return;
712 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
714 ALCdevice *device = pContext->Device;
716 switch (eParam)
718 case AL_POSITION:
719 case AL_VELOCITY:
720 case AL_DIRECTION:
721 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
722 break;
724 case AL_AUXILIARY_SEND_FILTER: {
725 ALeffectslot *ALEffectSlot = NULL;
726 ALfilter *ALFilter = NULL;
728 if((ALuint)lValue2 < device->NumAuxSends &&
729 (lValue1 == 0 ||
730 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
731 (lValue3 == 0 ||
732 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
734 /* Release refcount on the previous slot, and add one for
735 * the new slot */
736 if(Source->Send[lValue2].Slot)
737 Source->Send[lValue2].Slot->refcount--;
738 Source->Send[lValue2].Slot = ALEffectSlot;
739 if(Source->Send[lValue2].Slot)
740 Source->Send[lValue2].Slot->refcount++;
742 if(!ALFilter)
744 /* Disable filter */
745 Source->Send[lValue2].WetFilter.type = 0;
746 Source->Send[lValue2].WetFilter.filter = 0;
748 else
749 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
750 Source->NeedsUpdate = AL_TRUE;
752 else
753 alSetError(pContext, AL_INVALID_VALUE);
754 } break;
756 default:
757 alSetError(pContext, AL_INVALID_ENUM);
758 break;
761 else
762 alSetError(pContext, AL_INVALID_NAME);
764 ProcessContext(pContext);
768 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
770 ALCcontext *pContext;
772 pContext = GetContextSuspended();
773 if(!pContext) return;
775 if(plValues)
777 if(LookupSource(pContext->SourceMap, source) != NULL)
779 switch(eParam)
781 case AL_SOURCE_RELATIVE:
782 case AL_CONE_INNER_ANGLE:
783 case AL_CONE_OUTER_ANGLE:
784 case AL_LOOPING:
785 case AL_BUFFER:
786 case AL_SOURCE_STATE:
787 case AL_SEC_OFFSET:
788 case AL_SAMPLE_OFFSET:
789 case AL_BYTE_OFFSET:
790 case AL_MAX_DISTANCE:
791 case AL_ROLLOFF_FACTOR:
792 case AL_REFERENCE_DISTANCE:
793 case AL_DIRECT_FILTER:
794 case AL_DIRECT_FILTER_GAINHF_AUTO:
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
796 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
797 case AL_DISTANCE_MODEL:
798 alSourcei(source, eParam, plValues[0]);
799 break;
801 case AL_POSITION:
802 case AL_VELOCITY:
803 case AL_DIRECTION:
804 case AL_AUXILIARY_SEND_FILTER:
805 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
806 break;
808 default:
809 alSetError(pContext, AL_INVALID_ENUM);
810 break;
813 else
814 alSetError(pContext, AL_INVALID_NAME);
816 else
817 alSetError(pContext, AL_INVALID_VALUE);
819 ProcessContext(pContext);
823 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
825 ALCcontext *pContext;
826 ALsource *Source;
827 ALdouble Offsets[2];
828 ALdouble updateLen;
830 pContext = GetContextSuspended();
831 if(!pContext) return;
833 if(pflValue)
835 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
837 switch(eParam)
839 case AL_PITCH:
840 *pflValue = Source->flPitch;
841 break;
843 case AL_GAIN:
844 *pflValue = Source->flGain;
845 break;
847 case AL_MIN_GAIN:
848 *pflValue = Source->flMinGain;
849 break;
851 case AL_MAX_GAIN:
852 *pflValue = Source->flMaxGain;
853 break;
855 case AL_MAX_DISTANCE:
856 *pflValue = Source->flMaxDistance;
857 break;
859 case AL_ROLLOFF_FACTOR:
860 *pflValue = Source->flRollOffFactor;
861 break;
863 case AL_CONE_OUTER_GAIN:
864 *pflValue = Source->flOuterGain;
865 break;
867 case AL_CONE_OUTER_GAINHF:
868 *pflValue = Source->OuterGainHF;
869 break;
871 case AL_SEC_OFFSET:
872 case AL_SAMPLE_OFFSET:
873 case AL_BYTE_OFFSET:
874 updateLen = (ALdouble)pContext->Device->UpdateSize /
875 pContext->Device->Frequency;
876 GetSourceOffset(Source, eParam, Offsets, updateLen);
877 *pflValue = Offsets[0];
878 break;
880 case AL_CONE_INNER_ANGLE:
881 *pflValue = Source->flInnerAngle;
882 break;
884 case AL_CONE_OUTER_ANGLE:
885 *pflValue = Source->flOuterAngle;
886 break;
888 case AL_REFERENCE_DISTANCE:
889 *pflValue = Source->flRefDistance;
890 break;
892 case AL_AIR_ABSORPTION_FACTOR:
893 *pflValue = Source->AirAbsorptionFactor;
894 break;
896 case AL_ROOM_ROLLOFF_FACTOR:
897 *pflValue = Source->RoomRolloffFactor;
898 break;
900 case AL_DOPPLER_FACTOR:
901 *pflValue = Source->DopplerFactor;
902 break;
904 default:
905 alSetError(pContext, AL_INVALID_ENUM);
906 break;
909 else
910 alSetError(pContext, AL_INVALID_NAME);
912 else
913 alSetError(pContext, AL_INVALID_VALUE);
915 ProcessContext(pContext);
919 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
921 ALCcontext *pContext;
922 ALsource *Source;
924 pContext = GetContextSuspended();
925 if(!pContext) return;
927 if(pflValue1 && pflValue2 && pflValue3)
929 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
931 switch(eParam)
933 case AL_POSITION:
934 *pflValue1 = Source->vPosition[0];
935 *pflValue2 = Source->vPosition[1];
936 *pflValue3 = Source->vPosition[2];
937 break;
939 case AL_VELOCITY:
940 *pflValue1 = Source->vVelocity[0];
941 *pflValue2 = Source->vVelocity[1];
942 *pflValue3 = Source->vVelocity[2];
943 break;
945 case AL_DIRECTION:
946 *pflValue1 = Source->vOrientation[0];
947 *pflValue2 = Source->vOrientation[1];
948 *pflValue3 = Source->vOrientation[2];
949 break;
951 default:
952 alSetError(pContext, AL_INVALID_ENUM);
953 break;
956 else
957 alSetError(pContext, AL_INVALID_NAME);
959 else
960 alSetError(pContext, AL_INVALID_VALUE);
962 ProcessContext(pContext);
966 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
968 ALCcontext *pContext;
969 ALsource *Source;
970 ALdouble Offsets[2];
971 ALdouble updateLen;
973 pContext = GetContextSuspended();
974 if(!pContext) return;
976 if(pflValues)
978 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
980 switch(eParam)
982 case AL_PITCH:
983 case AL_GAIN:
984 case AL_MIN_GAIN:
985 case AL_MAX_GAIN:
986 case AL_MAX_DISTANCE:
987 case AL_ROLLOFF_FACTOR:
988 case AL_DOPPLER_FACTOR:
989 case AL_CONE_OUTER_GAIN:
990 case AL_SEC_OFFSET:
991 case AL_SAMPLE_OFFSET:
992 case AL_BYTE_OFFSET:
993 case AL_CONE_INNER_ANGLE:
994 case AL_CONE_OUTER_ANGLE:
995 case AL_REFERENCE_DISTANCE:
996 case AL_CONE_OUTER_GAINHF:
997 case AL_AIR_ABSORPTION_FACTOR:
998 case AL_ROOM_ROLLOFF_FACTOR:
999 alGetSourcef(source, eParam, pflValues);
1000 break;
1002 case AL_POSITION:
1003 case AL_VELOCITY:
1004 case AL_DIRECTION:
1005 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1006 break;
1008 case AL_SAMPLE_RW_OFFSETS_SOFT:
1009 case AL_BYTE_RW_OFFSETS_SOFT:
1010 updateLen = (ALdouble)pContext->Device->UpdateSize /
1011 pContext->Device->Frequency;
1012 GetSourceOffset(Source, eParam, Offsets, updateLen);
1013 pflValues[0] = Offsets[0];
1014 pflValues[1] = Offsets[1];
1015 break;
1017 default:
1018 alSetError(pContext, AL_INVALID_ENUM);
1019 break;
1022 else
1023 alSetError(pContext, AL_INVALID_NAME);
1025 else
1026 alSetError(pContext, AL_INVALID_VALUE);
1028 ProcessContext(pContext);
1032 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1034 ALCcontext *pContext;
1035 ALsource *Source;
1036 ALdouble Offsets[2];
1037 ALdouble updateLen;
1039 pContext = GetContextSuspended();
1040 if(!pContext) return;
1042 if(plValue)
1044 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1046 switch(eParam)
1048 case AL_MAX_DISTANCE:
1049 *plValue = (ALint)Source->flMaxDistance;
1050 break;
1052 case AL_ROLLOFF_FACTOR:
1053 *plValue = (ALint)Source->flRollOffFactor;
1054 break;
1056 case AL_REFERENCE_DISTANCE:
1057 *plValue = (ALint)Source->flRefDistance;
1058 break;
1060 case AL_SOURCE_RELATIVE:
1061 *plValue = Source->bHeadRelative;
1062 break;
1064 case AL_CONE_INNER_ANGLE:
1065 *plValue = (ALint)Source->flInnerAngle;
1066 break;
1068 case AL_CONE_OUTER_ANGLE:
1069 *plValue = (ALint)Source->flOuterAngle;
1070 break;
1072 case AL_LOOPING:
1073 *plValue = Source->bLooping;
1074 break;
1076 case AL_BUFFER:
1077 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1078 break;
1080 case AL_SOURCE_STATE:
1081 *plValue = Source->state;
1082 break;
1084 case AL_BUFFERS_QUEUED:
1085 *plValue = Source->BuffersInQueue;
1086 break;
1088 case AL_BUFFERS_PROCESSED:
1089 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1091 /* Buffers on a looping source are in a perpetual state
1092 * of PENDING, so don't report any as PROCESSED */
1093 *plValue = 0;
1095 else
1096 *plValue = Source->BuffersPlayed;
1097 break;
1099 case AL_SOURCE_TYPE:
1100 *plValue = Source->lSourceType;
1101 break;
1103 case AL_SEC_OFFSET:
1104 case AL_SAMPLE_OFFSET:
1105 case AL_BYTE_OFFSET:
1106 updateLen = (ALdouble)pContext->Device->UpdateSize /
1107 pContext->Device->Frequency;
1108 GetSourceOffset(Source, eParam, Offsets, updateLen);
1109 *plValue = (ALint)Offsets[0];
1110 break;
1112 case AL_DIRECT_FILTER:
1113 *plValue = Source->DirectFilter.filter;
1114 break;
1116 case AL_DIRECT_FILTER_GAINHF_AUTO:
1117 *plValue = Source->DryGainHFAuto;
1118 break;
1120 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1121 *plValue = Source->WetGainAuto;
1122 break;
1124 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1125 *plValue = Source->WetGainHFAuto;
1126 break;
1128 case AL_DOPPLER_FACTOR:
1129 *plValue = (ALint)Source->DopplerFactor;
1130 break;
1132 case AL_DISTANCE_MODEL:
1133 *plValue = Source->DistanceModel;
1134 break;
1136 default:
1137 alSetError(pContext, AL_INVALID_ENUM);
1138 break;
1141 else
1142 alSetError(pContext, AL_INVALID_NAME);
1144 else
1145 alSetError(pContext, AL_INVALID_VALUE);
1147 ProcessContext(pContext);
1151 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1153 ALCcontext *pContext;
1154 ALsource *Source;
1156 pContext = GetContextSuspended();
1157 if(!pContext) return;
1159 if(plValue1 && plValue2 && plValue3)
1161 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1163 switch(eParam)
1165 case AL_POSITION:
1166 *plValue1 = (ALint)Source->vPosition[0];
1167 *plValue2 = (ALint)Source->vPosition[1];
1168 *plValue3 = (ALint)Source->vPosition[2];
1169 break;
1171 case AL_VELOCITY:
1172 *plValue1 = (ALint)Source->vVelocity[0];
1173 *plValue2 = (ALint)Source->vVelocity[1];
1174 *plValue3 = (ALint)Source->vVelocity[2];
1175 break;
1177 case AL_DIRECTION:
1178 *plValue1 = (ALint)Source->vOrientation[0];
1179 *plValue2 = (ALint)Source->vOrientation[1];
1180 *plValue3 = (ALint)Source->vOrientation[2];
1181 break;
1183 default:
1184 alSetError(pContext, AL_INVALID_ENUM);
1185 break;
1188 else
1189 alSetError(pContext, AL_INVALID_NAME);
1191 else
1192 alSetError(pContext, AL_INVALID_VALUE);
1194 ProcessContext(pContext);
1198 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1200 ALCcontext *pContext;
1201 ALsource *Source;
1202 ALdouble Offsets[2];
1203 ALdouble updateLen;
1205 pContext = GetContextSuspended();
1206 if(!pContext) return;
1208 if(plValues)
1210 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1212 switch(eParam)
1214 case AL_SOURCE_RELATIVE:
1215 case AL_CONE_INNER_ANGLE:
1216 case AL_CONE_OUTER_ANGLE:
1217 case AL_LOOPING:
1218 case AL_BUFFER:
1219 case AL_SOURCE_STATE:
1220 case AL_BUFFERS_QUEUED:
1221 case AL_BUFFERS_PROCESSED:
1222 case AL_SEC_OFFSET:
1223 case AL_SAMPLE_OFFSET:
1224 case AL_BYTE_OFFSET:
1225 case AL_MAX_DISTANCE:
1226 case AL_ROLLOFF_FACTOR:
1227 case AL_DOPPLER_FACTOR:
1228 case AL_REFERENCE_DISTANCE:
1229 case AL_SOURCE_TYPE:
1230 case AL_DIRECT_FILTER:
1231 case AL_DIRECT_FILTER_GAINHF_AUTO:
1232 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1233 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1234 case AL_DISTANCE_MODEL:
1235 alGetSourcei(source, eParam, plValues);
1236 break;
1238 case AL_POSITION:
1239 case AL_VELOCITY:
1240 case AL_DIRECTION:
1241 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1242 break;
1244 case AL_SAMPLE_RW_OFFSETS_SOFT:
1245 case AL_BYTE_RW_OFFSETS_SOFT:
1246 updateLen = (ALdouble)pContext->Device->UpdateSize /
1247 pContext->Device->Frequency;
1248 GetSourceOffset(Source, eParam, Offsets, updateLen);
1249 plValues[0] = (ALint)Offsets[0];
1250 plValues[1] = (ALint)Offsets[1];
1251 break;
1253 default:
1254 alSetError(pContext, AL_INVALID_ENUM);
1255 break;
1258 else
1259 alSetError(pContext, AL_INVALID_NAME);
1261 else
1262 alSetError(pContext, AL_INVALID_VALUE);
1264 ProcessContext(pContext);
1268 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1270 alSourcePlayv(1, &source);
1273 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1275 ALCcontext *Context;
1276 ALsource *Source;
1277 ALbufferlistitem *BufferList;
1278 ALsizei i, j;
1280 Context = GetContextSuspended();
1281 if(!Context) return;
1283 if(n < 0)
1285 alSetError(Context, AL_INVALID_VALUE);
1286 goto done;
1288 if(n > 0 && !sources)
1290 alSetError(Context, AL_INVALID_VALUE);
1291 goto done;
1294 // Check that all the Sources are valid
1295 for(i = 0;i < n;i++)
1297 if(!LookupSource(Context->SourceMap, sources[i]))
1299 alSetError(Context, AL_INVALID_NAME);
1300 goto done;
1304 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1306 void *temp = NULL;
1307 ALsizei newcount;
1309 newcount = Context->MaxActiveSources << 1;
1310 if(newcount > 0)
1311 temp = realloc(Context->ActiveSources,
1312 sizeof(*Context->ActiveSources) * newcount);
1313 if(!temp)
1315 alSetError(Context, AL_OUT_OF_MEMORY);
1316 goto done;
1319 Context->ActiveSources = temp;
1320 Context->MaxActiveSources = newcount;
1323 for(i = 0;i < n;i++)
1325 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1327 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1328 BufferList = Source->queue;
1329 while(BufferList)
1331 if(BufferList->buffer != NULL && BufferList->buffer->size)
1332 break;
1333 BufferList = BufferList->next;
1336 if(!BufferList)
1338 Source->state = AL_STOPPED;
1339 Source->BuffersPlayed = Source->BuffersInQueue;
1340 Source->position = 0;
1341 Source->position_fraction = 0;
1342 Source->lOffset = 0;
1343 continue;
1346 if(Source->state != AL_PAUSED)
1348 Source->state = AL_PLAYING;
1349 Source->position = 0;
1350 Source->position_fraction = 0;
1351 Source->BuffersPlayed = 0;
1353 Source->Buffer = Source->queue->buffer;
1355 else
1356 Source->state = AL_PLAYING;
1358 // Check if an Offset has been set
1359 if(Source->lOffset)
1360 ApplyOffset(Source);
1362 // If device is disconnected, go right to stopped
1363 if(!Context->Device->Connected)
1365 Source->state = AL_STOPPED;
1366 Source->BuffersPlayed = Source->BuffersInQueue;
1367 Source->position = 0;
1368 Source->position_fraction = 0;
1370 else
1372 for(j = 0;j < Context->ActiveSourceCount;j++)
1374 if(Context->ActiveSources[j] == Source)
1375 break;
1377 if(j == Context->ActiveSourceCount)
1378 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1382 done:
1383 ProcessContext(Context);
1386 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1388 alSourcePausev(1, &source);
1391 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1393 ALCcontext *Context;
1394 ALsource *Source;
1395 ALsizei i;
1397 Context = GetContextSuspended();
1398 if(!Context) return;
1400 if(n < 0)
1402 alSetError(Context, AL_INVALID_VALUE);
1403 goto done;
1405 if(n > 0 && !sources)
1407 alSetError(Context, AL_INVALID_VALUE);
1408 goto done;
1411 // Check all the Sources are valid
1412 for(i = 0;i < n;i++)
1414 if(!LookupSource(Context->SourceMap, sources[i]))
1416 alSetError(Context, AL_INVALID_NAME);
1417 goto done;
1421 for(i = 0;i < n;i++)
1423 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1424 if(Source->state == AL_PLAYING)
1425 Source->state = AL_PAUSED;
1428 done:
1429 ProcessContext(Context);
1432 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1434 alSourceStopv(1, &source);
1437 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1439 ALCcontext *Context;
1440 ALsource *Source;
1441 ALsizei i;
1443 Context = GetContextSuspended();
1444 if(!Context) return;
1446 if(n < 0)
1448 alSetError(Context, AL_INVALID_VALUE);
1449 goto done;
1451 if(n > 0 && !sources)
1453 alSetError(Context, AL_INVALID_VALUE);
1454 goto done;
1457 // Check all the Sources are valid
1458 for(i = 0;i < n;i++)
1460 if(!LookupSource(Context->SourceMap, sources[i]))
1462 alSetError(Context, AL_INVALID_NAME);
1463 goto done;
1467 for(i = 0;i < n;i++)
1469 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1470 if(Source->state != AL_INITIAL)
1472 Source->state = AL_STOPPED;
1473 Source->BuffersPlayed = Source->BuffersInQueue;
1475 Source->lOffset = 0;
1478 done:
1479 ProcessContext(Context);
1482 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1484 alSourceRewindv(1, &source);
1487 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1489 ALCcontext *Context;
1490 ALsource *Source;
1491 ALsizei i;
1493 Context = GetContextSuspended();
1494 if(!Context) return;
1496 if(n < 0)
1498 alSetError(Context, AL_INVALID_VALUE);
1499 goto done;
1501 if(n > 0 && !sources)
1503 alSetError(Context, AL_INVALID_VALUE);
1504 goto done;
1507 // Check all the Sources are valid
1508 for(i = 0;i < n;i++)
1510 if(!LookupSource(Context->SourceMap, sources[i]))
1512 alSetError(Context, AL_INVALID_NAME);
1513 goto done;
1517 for(i = 0;i < n;i++)
1519 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1520 if(Source->state != AL_INITIAL)
1522 Source->state = AL_INITIAL;
1523 Source->position = 0;
1524 Source->position_fraction = 0;
1525 Source->BuffersPlayed = 0;
1526 if(Source->queue)
1527 Source->Buffer = Source->queue->buffer;
1529 Source->lOffset = 0;
1532 done:
1533 ProcessContext(Context);
1537 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1539 ALCcontext *Context;
1540 ALCdevice *device;
1541 ALsource *Source;
1542 ALbuffer *buffer;
1543 ALsizei i;
1544 ALbufferlistitem *BufferListStart;
1545 ALbufferlistitem *BufferList;
1546 ALbuffer *BufferFmt;
1548 if(n == 0)
1549 return;
1551 Context = GetContextSuspended();
1552 if(!Context) return;
1554 if(n < 0)
1556 alSetError(Context, AL_INVALID_VALUE);
1557 goto done;
1560 // Check that all buffers are valid or zero and that the source is valid
1562 // Check that this is a valid source
1563 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1565 alSetError(Context, AL_INVALID_NAME);
1566 goto done;
1569 // Check that this is not a STATIC Source
1570 if(Source->lSourceType == AL_STATIC)
1572 // Invalid Source Type (can't queue on a Static Source)
1573 alSetError(Context, AL_INVALID_OPERATION);
1574 goto done;
1577 device = Context->Device;
1579 BufferFmt = NULL;
1581 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1582 BufferList = Source->queue;
1583 while(BufferList)
1585 if(BufferList->buffer)
1587 BufferFmt = BufferList->buffer;
1588 break;
1590 BufferList = BufferList->next;
1593 for(i = 0;i < n;i++)
1595 if(!buffers[i])
1596 continue;
1598 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1600 alSetError(Context, AL_INVALID_NAME);
1601 goto done;
1604 if(BufferFmt == NULL)
1606 BufferFmt = buffer;
1608 if(buffer->FmtChannels == FmtMono)
1609 Source->Update = CalcSourceParams;
1610 else
1611 Source->Update = CalcNonAttnSourceParams;
1613 Source->NeedsUpdate = AL_TRUE;
1615 else if(BufferFmt->Frequency != buffer->Frequency ||
1616 BufferFmt->OriginalFormat != buffer->OriginalFormat)
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 ALenum OriginalFormat;
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 OriginalFormat = Buffer->OriginalFormat;
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((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1885 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1887 ALuint FrameBlockSize = 65 * Bytes * Channels;
1888 ALuint BlockSize = 36 * Channels;
1890 // Round down to nearest ADPCM block
1891 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1892 if(Source->state != AL_PLAYING)
1893 offset[1] = offset[0];
1894 else
1896 // Round up to nearest ADPCM block
1897 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1898 FrameBlockSize * BlockSize);
1901 else
1903 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1904 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1905 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1907 break;
1913 ApplyOffset
1915 Apply a playback offset to the Source. This function will update the queue (to correctly
1916 mark buffers as 'pending' or 'processed' depending upon the new offset.
1918 static ALboolean ApplyOffset(ALsource *Source)
1920 ALbufferlistitem *BufferList;
1921 ALbuffer *Buffer;
1922 ALint lBufferSize, lTotalBufferSize;
1923 ALint BuffersPlayed;
1924 ALint lByteOffset;
1926 // Get true byte offset
1927 lByteOffset = GetByteOffset(Source);
1929 // If the offset is invalid, don't apply it
1930 if(lByteOffset == -1)
1931 return AL_FALSE;
1933 // Sort out the queue (pending and processed states)
1934 BufferList = Source->queue;
1935 lTotalBufferSize = 0;
1936 BuffersPlayed = 0;
1938 while(BufferList)
1940 Buffer = BufferList->buffer;
1941 lBufferSize = Buffer ? Buffer->size : 0;
1943 if(lBufferSize <= lByteOffset-lTotalBufferSize)
1945 // Offset is past this buffer so increment BuffersPlayed
1946 BuffersPlayed++;
1948 else if(lTotalBufferSize <= lByteOffset)
1950 // Offset is within this buffer
1951 // Set Current Buffer
1952 Source->Buffer = BufferList->buffer;
1953 Source->BuffersPlayed = BuffersPlayed;
1955 // SW Mixer Positions are in Samples
1956 Source->position = (lByteOffset - lTotalBufferSize) /
1957 FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
1958 return AL_TRUE;
1961 // Increment the TotalBufferSize
1962 lTotalBufferSize += lBufferSize;
1964 // Move on to next buffer in the Queue
1965 BufferList = BufferList->next;
1967 // Offset is out of range of the buffer queue
1968 return AL_FALSE;
1973 GetByteOffset
1975 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1976 offset supplied by the application). This takes into account the fact that the buffer format
1977 may have been modifed by AL (e.g 8bit samples are converted to float)
1979 static ALint GetByteOffset(ALsource *Source)
1981 ALbuffer *Buffer = NULL;
1982 ALbufferlistitem *BufferList;
1983 ALint ByteOffset = -1;
1985 // Find the first non-NULL Buffer in the Queue
1986 BufferList = Source->queue;
1987 while(BufferList)
1989 if(BufferList->buffer)
1991 Buffer = BufferList->buffer;
1992 break;
1994 BufferList = BufferList->next;
1997 if(!Buffer)
1999 Source->lOffset = 0;
2000 return -1;
2003 // Determine the ByteOffset (and ensure it is block aligned)
2004 switch(Source->lOffsetType)
2006 case AL_BYTE_OFFSET:
2007 // Take into consideration the original format
2008 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->OriginalFormat);
2009 ByteOffset *= FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
2010 break;
2012 case AL_SAMPLE_OFFSET:
2013 ByteOffset = Source->lOffset * BytesFromFmt(Buffer->FmtType);
2014 break;
2016 case AL_SEC_OFFSET:
2017 // Note - lOffset is internally stored as Milliseconds
2018 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2019 ByteOffset *= BytesFromFmt(Buffer->FmtType);
2020 break;
2022 // Clear Offset
2023 Source->lOffset = 0;
2025 return ByteOffset;
2028 static ALint FramesFromBytes(ALint offset, ALenum format)
2030 if(format==AL_FORMAT_MONO_IMA4)
2032 // Round down to nearest ADPCM block
2033 offset /= 36;
2034 // Multiply by compression rate (65 sample frames per block)
2035 offset *= 65;
2037 else if(format==AL_FORMAT_STEREO_IMA4)
2039 offset /= 36 * 2;
2040 offset *= 65;
2042 else
2043 offset /= aluFrameSizeFromFormat(format);
2044 return offset;
2048 ALvoid ReleaseALSources(ALCcontext *Context)
2050 ALsizei pos;
2051 ALuint j;
2052 for(pos = 0;pos < Context->SourceMap.size;pos++)
2054 ALsource *temp = Context->SourceMap.array[pos].value;
2055 Context->SourceMap.array[pos].value = NULL;
2057 // For each buffer in the source's queue, decrement its reference counter and remove it
2058 while(temp->queue != NULL)
2060 ALbufferlistitem *BufferList = temp->queue;
2061 temp->queue = BufferList->next;
2063 if(BufferList->buffer != NULL)
2064 BufferList->buffer->refcount--;
2065 free(BufferList);
2068 for(j = 0;j < MAX_SENDS;++j)
2070 if(temp->Send[j].Slot)
2071 temp->Send[j].Slot->refcount--;
2072 temp->Send[j].Slot = NULL;
2075 // Release source structure
2076 ALTHUNK_REMOVEENTRY(temp->source);
2077 memset(temp, 0, sizeof(ALsource));
2078 free(temp);