Set AL_STOPPED after setting AL_PLAYING when a source has nothing to play
[openal-soft/android.git] / OpenAL32 / alSource.c
blob7d0aa9782732274e30ed36c7ffcb44cf76812c37
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 enum Resampler DefaultResampler = RESAMPLER_DEFAULT;
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 ALint GetSampleOffset(ALsource *Source);
54 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
56 ALCcontext *Context;
57 ALCdevice *Device;
59 Context = GetContextRef();
60 if(!Context) return;
62 Device = Context->Device;
63 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
64 alSetError(Context, AL_INVALID_VALUE);
65 else
67 ALenum err;
68 ALsizei i;
70 // Add additional sources to the list
71 i = 0;
72 while(i < n)
74 ALsource *source = calloc(1, sizeof(ALsource));
75 if(!source)
77 alSetError(Context, AL_OUT_OF_MEMORY);
78 alDeleteSources(i, sources);
79 break;
81 InitSourceParams(source);
83 err = NewThunkEntry(&source->source);
84 if(err == AL_NO_ERROR)
85 err = InsertUIntMapEntry(&Context->SourceMap, source->source, source);
86 if(err != AL_NO_ERROR)
88 FreeThunkEntry(source->source);
89 memset(source, 0, sizeof(ALsource));
90 free(source);
92 alSetError(Context, err);
93 alDeleteSources(i, sources);
94 break;
97 sources[i++] = source->source;
101 ALCcontext_DecRef(Context);
105 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
107 ALCcontext *Context;
108 ALsource *Source;
109 ALsizei i, j;
110 ALbufferlistitem *BufferList;
112 Context = GetContextRef();
113 if(!Context) return;
115 if(n < 0)
116 alSetError(Context, AL_INVALID_VALUE);
117 else
119 // Check that all Sources are valid (and can therefore be deleted)
120 for(i = 0;i < n;i++)
122 if(LookupSource(Context, sources[i]) == NULL)
124 alSetError(Context, AL_INVALID_NAME);
125 n = 0;
126 break;
130 // All Sources are valid, and can be deleted
131 for(i = 0;i < n;i++)
133 ALsource **srclist, **srclistend;
135 // Remove Source from list of Sources
136 if((Source=RemoveSource(Context, sources[i])) == NULL)
137 continue;
139 FreeThunkEntry(Source->source);
141 LockContext(Context);
142 srclist = Context->ActiveSources;
143 srclistend = srclist + Context->ActiveSourceCount;
144 while(srclist != srclistend)
146 if(*srclist == Source)
148 Context->ActiveSourceCount--;
149 *srclist = *(--srclistend);
150 break;
152 srclist++;
154 UnlockContext(Context);
156 // For each buffer in the source's queue...
157 while(Source->queue != NULL)
159 BufferList = Source->queue;
160 Source->queue = BufferList->next;
162 if(BufferList->buffer != NULL)
163 DecrementRef(&BufferList->buffer->ref);
164 free(BufferList);
167 for(j = 0;j < MAX_SENDS;++j)
169 if(Source->Send[j].Slot)
170 DecrementRef(&Source->Send[j].Slot->ref);
171 Source->Send[j].Slot = NULL;
174 memset(Source,0,sizeof(ALsource));
175 free(Source);
179 ALCcontext_DecRef(Context);
183 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
185 ALCcontext *Context;
186 ALboolean result;
188 Context = GetContextRef();
189 if(!Context) return AL_FALSE;
191 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
193 ALCcontext_DecRef(Context);
195 return result;
199 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
201 ALCcontext *pContext;
202 ALsource *Source;
204 pContext = GetContextRef();
205 if(!pContext) return;
207 if((Source=LookupSource(pContext, source)) != NULL)
209 switch(eParam)
211 case AL_PITCH:
212 if(flValue >= 0.0f)
214 Source->flPitch = flValue;
215 Source->NeedsUpdate = AL_TRUE;
217 else
218 alSetError(pContext, AL_INVALID_VALUE);
219 break;
221 case AL_CONE_INNER_ANGLE:
222 if(flValue >= 0.0f && flValue <= 360.0f)
224 Source->flInnerAngle = flValue;
225 Source->NeedsUpdate = AL_TRUE;
227 else
228 alSetError(pContext, AL_INVALID_VALUE);
229 break;
231 case AL_CONE_OUTER_ANGLE:
232 if(flValue >= 0.0f && flValue <= 360.0f)
234 Source->flOuterAngle = flValue;
235 Source->NeedsUpdate = AL_TRUE;
237 else
238 alSetError(pContext, AL_INVALID_VALUE);
239 break;
241 case AL_GAIN:
242 if(flValue >= 0.0f)
244 Source->flGain = flValue;
245 Source->NeedsUpdate = AL_TRUE;
247 else
248 alSetError(pContext, AL_INVALID_VALUE);
249 break;
251 case AL_MAX_DISTANCE:
252 if(flValue >= 0.0f)
254 Source->flMaxDistance = flValue;
255 Source->NeedsUpdate = AL_TRUE;
257 else
258 alSetError(pContext, AL_INVALID_VALUE);
259 break;
261 case AL_ROLLOFF_FACTOR:
262 if(flValue >= 0.0f)
264 Source->flRollOffFactor = flValue;
265 Source->NeedsUpdate = AL_TRUE;
267 else
268 alSetError(pContext, AL_INVALID_VALUE);
269 break;
271 case AL_REFERENCE_DISTANCE:
272 if(flValue >= 0.0f)
274 Source->flRefDistance = flValue;
275 Source->NeedsUpdate = AL_TRUE;
277 else
278 alSetError(pContext, AL_INVALID_VALUE);
279 break;
281 case AL_MIN_GAIN:
282 if(flValue >= 0.0f && flValue <= 1.0f)
284 Source->flMinGain = flValue;
285 Source->NeedsUpdate = AL_TRUE;
287 else
288 alSetError(pContext, AL_INVALID_VALUE);
289 break;
291 case AL_MAX_GAIN:
292 if(flValue >= 0.0f && flValue <= 1.0f)
294 Source->flMaxGain = flValue;
295 Source->NeedsUpdate = AL_TRUE;
297 else
298 alSetError(pContext, AL_INVALID_VALUE);
299 break;
301 case AL_CONE_OUTER_GAIN:
302 if(flValue >= 0.0f && flValue <= 1.0f)
304 Source->flOuterGain = flValue;
305 Source->NeedsUpdate = AL_TRUE;
307 else
308 alSetError(pContext, AL_INVALID_VALUE);
309 break;
311 case AL_CONE_OUTER_GAINHF:
312 if(flValue >= 0.0f && flValue <= 1.0f)
314 Source->OuterGainHF = flValue;
315 Source->NeedsUpdate = AL_TRUE;
317 else
318 alSetError(pContext, AL_INVALID_VALUE);
319 break;
321 case AL_AIR_ABSORPTION_FACTOR:
322 if(flValue >= 0.0f && flValue <= 10.0f)
324 Source->AirAbsorptionFactor = flValue;
325 Source->NeedsUpdate = AL_TRUE;
327 else
328 alSetError(pContext, AL_INVALID_VALUE);
329 break;
331 case AL_ROOM_ROLLOFF_FACTOR:
332 if(flValue >= 0.0f && flValue <= 10.0f)
334 Source->RoomRolloffFactor = flValue;
335 Source->NeedsUpdate = AL_TRUE;
337 else
338 alSetError(pContext, AL_INVALID_VALUE);
339 break;
341 case AL_DOPPLER_FACTOR:
342 if(flValue >= 0.0f && flValue <= 1.0f)
344 Source->DopplerFactor = flValue;
345 Source->NeedsUpdate = AL_TRUE;
347 else
348 alSetError(pContext, AL_INVALID_VALUE);
349 break;
351 case AL_SEC_OFFSET:
352 case AL_SAMPLE_OFFSET:
353 case AL_BYTE_OFFSET:
354 if(flValue >= 0.0f)
356 LockContext(pContext);
357 Source->lOffsetType = eParam;
359 // Store Offset (convert Seconds into Milliseconds)
360 if(eParam == AL_SEC_OFFSET)
361 Source->lOffset = (ALint)(flValue * 1000.0f);
362 else
363 Source->lOffset = (ALint)flValue;
365 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
366 !pContext->DeferUpdates)
368 if(ApplyOffset(Source) == AL_FALSE)
369 alSetError(pContext, AL_INVALID_VALUE);
371 UnlockContext(pContext);
373 else
374 alSetError(pContext, AL_INVALID_VALUE);
375 break;
377 default:
378 alSetError(pContext, AL_INVALID_ENUM);
379 break;
382 else
384 // Invalid Source Name
385 alSetError(pContext, AL_INVALID_NAME);
388 ALCcontext_DecRef(pContext);
392 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
394 ALCcontext *pContext;
395 ALsource *Source;
397 pContext = GetContextRef();
398 if(!pContext) return;
400 if((Source=LookupSource(pContext, source)) != NULL)
402 switch(eParam)
404 case AL_POSITION:
405 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
407 LockContext(pContext);
408 Source->vPosition[0] = flValue1;
409 Source->vPosition[1] = flValue2;
410 Source->vPosition[2] = flValue3;
411 UnlockContext(pContext);
412 Source->NeedsUpdate = AL_TRUE;
414 else
415 alSetError(pContext, AL_INVALID_VALUE);
416 break;
418 case AL_VELOCITY:
419 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
421 LockContext(pContext);
422 Source->vVelocity[0] = flValue1;
423 Source->vVelocity[1] = flValue2;
424 Source->vVelocity[2] = flValue3;
425 UnlockContext(pContext);
426 Source->NeedsUpdate = AL_TRUE;
428 else
429 alSetError(pContext, AL_INVALID_VALUE);
430 break;
432 case AL_DIRECTION:
433 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
435 LockContext(pContext);
436 Source->vOrientation[0] = flValue1;
437 Source->vOrientation[1] = flValue2;
438 Source->vOrientation[2] = flValue3;
439 UnlockContext(pContext);
440 Source->NeedsUpdate = AL_TRUE;
442 else
443 alSetError(pContext, AL_INVALID_VALUE);
444 break;
446 default:
447 alSetError(pContext, AL_INVALID_ENUM);
448 break;
451 else
452 alSetError(pContext, AL_INVALID_NAME);
454 ALCcontext_DecRef(pContext);
458 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
460 ALCcontext *pContext;
462 if(pflValues)
464 switch(eParam)
466 case AL_PITCH:
467 case AL_CONE_INNER_ANGLE:
468 case AL_CONE_OUTER_ANGLE:
469 case AL_GAIN:
470 case AL_MAX_DISTANCE:
471 case AL_ROLLOFF_FACTOR:
472 case AL_REFERENCE_DISTANCE:
473 case AL_MIN_GAIN:
474 case AL_MAX_GAIN:
475 case AL_CONE_OUTER_GAIN:
476 case AL_CONE_OUTER_GAINHF:
477 case AL_SEC_OFFSET:
478 case AL_SAMPLE_OFFSET:
479 case AL_BYTE_OFFSET:
480 case AL_AIR_ABSORPTION_FACTOR:
481 case AL_ROOM_ROLLOFF_FACTOR:
482 alSourcef(source, eParam, pflValues[0]);
483 return;
485 case AL_POSITION:
486 case AL_VELOCITY:
487 case AL_DIRECTION:
488 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
489 return;
493 pContext = GetContextRef();
494 if(!pContext) return;
496 if(pflValues)
498 if(LookupSource(pContext, source) != NULL)
500 switch(eParam)
502 default:
503 alSetError(pContext, AL_INVALID_ENUM);
504 break;
507 else
508 alSetError(pContext, AL_INVALID_NAME);
510 else
511 alSetError(pContext, AL_INVALID_VALUE);
513 ALCcontext_DecRef(pContext);
517 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
519 ALCcontext *pContext;
520 ALsource *Source;
521 ALbufferlistitem *BufferListItem;
523 switch(eParam)
525 case AL_MAX_DISTANCE:
526 case AL_ROLLOFF_FACTOR:
527 case AL_CONE_INNER_ANGLE:
528 case AL_CONE_OUTER_ANGLE:
529 case AL_REFERENCE_DISTANCE:
530 alSourcef(source, eParam, (ALfloat)lValue);
531 return;
534 pContext = GetContextRef();
535 if(!pContext) return;
537 if((Source=LookupSource(pContext, source)) != NULL)
539 ALCdevice *device = pContext->Device;
541 switch(eParam)
543 case AL_SOURCE_RELATIVE:
544 if(lValue == AL_FALSE || lValue == AL_TRUE)
546 Source->bHeadRelative = (ALboolean)lValue;
547 Source->NeedsUpdate = AL_TRUE;
549 else
550 alSetError(pContext, AL_INVALID_VALUE);
551 break;
553 case AL_LOOPING:
554 if(lValue == AL_FALSE || lValue == AL_TRUE)
555 Source->bLooping = (ALboolean)lValue;
556 else
557 alSetError(pContext, AL_INVALID_VALUE);
558 break;
560 case AL_BUFFER:
561 LockContext(pContext);
562 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
564 ALbufferlistitem *oldlist;
565 ALbuffer *buffer = NULL;
567 if(lValue == 0 || (buffer=LookupBuffer(device, lValue)) != NULL)
569 Source->BuffersInQueue = 0;
570 Source->BuffersPlayed = 0;
572 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
573 if(buffer != NULL)
575 // Source is now in STATIC mode
576 Source->lSourceType = AL_STATIC;
578 // Add the selected buffer to the queue
579 BufferListItem = malloc(sizeof(ALbufferlistitem));
580 BufferListItem->buffer = buffer;
581 BufferListItem->next = NULL;
582 BufferListItem->prev = NULL;
583 // Increment reference counter for buffer
584 IncrementRef(&buffer->ref);
586 oldlist = ExchangePtr((void**)&Source->queue, BufferListItem);
587 Source->BuffersInQueue = 1;
589 ReadLock(&buffer->lock);
590 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
591 Source->SampleSize = BytesFromFmt(buffer->FmtType);
592 ReadUnlock(&buffer->lock);
593 if(buffer->FmtChannels == FmtMono)
594 Source->Update = CalcSourceParams;
595 else
596 Source->Update = CalcNonAttnSourceParams;
597 Source->NeedsUpdate = AL_TRUE;
599 else
601 // Source is now in UNDETERMINED mode
602 Source->lSourceType = AL_UNDETERMINED;
603 oldlist = ExchangePtr((void**)&Source->queue, NULL);
606 // Delete all previous elements in the queue
607 while(oldlist != NULL)
609 BufferListItem = oldlist;
610 oldlist = BufferListItem->next;
612 if(BufferListItem->buffer)
613 DecrementRef(&BufferListItem->buffer->ref);
614 free(BufferListItem);
617 else
618 alSetError(pContext, AL_INVALID_VALUE);
620 else
621 alSetError(pContext, AL_INVALID_OPERATION);
622 UnlockContext(pContext);
623 break;
625 case AL_SOURCE_STATE:
626 // Query only
627 alSetError(pContext, AL_INVALID_OPERATION);
628 break;
630 case AL_SEC_OFFSET:
631 case AL_SAMPLE_OFFSET:
632 case AL_BYTE_OFFSET:
633 if(lValue >= 0)
635 LockContext(pContext);
636 Source->lOffsetType = eParam;
638 // Store Offset (convert Seconds into Milliseconds)
639 if(eParam == AL_SEC_OFFSET)
640 Source->lOffset = lValue * 1000;
641 else
642 Source->lOffset = lValue;
644 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
645 !pContext->DeferUpdates)
647 if(ApplyOffset(Source) == AL_FALSE)
648 alSetError(pContext, AL_INVALID_VALUE);
650 UnlockContext(pContext);
652 else
653 alSetError(pContext, AL_INVALID_VALUE);
654 break;
656 case AL_DIRECT_FILTER: {
657 ALfilter *filter = NULL;
659 if(lValue == 0 || (filter=LookupFilter(pContext->Device, lValue)) != NULL)
661 LockContext(pContext);
662 if(!filter)
664 Source->DirectGain = 1.0f;
665 Source->DirectGainHF = 1.0f;
667 else
669 Source->DirectGain = filter->Gain;
670 Source->DirectGainHF = filter->GainHF;
672 UnlockContext(pContext);
673 Source->NeedsUpdate = AL_TRUE;
675 else
676 alSetError(pContext, AL_INVALID_VALUE);
677 } break;
679 case AL_DIRECT_FILTER_GAINHF_AUTO:
680 if(lValue == AL_TRUE || lValue == AL_FALSE)
682 Source->DryGainHFAuto = lValue;
683 Source->NeedsUpdate = AL_TRUE;
685 else
686 alSetError(pContext, AL_INVALID_VALUE);
687 break;
689 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
690 if(lValue == AL_TRUE || lValue == AL_FALSE)
692 Source->WetGainAuto = lValue;
693 Source->NeedsUpdate = AL_TRUE;
695 else
696 alSetError(pContext, AL_INVALID_VALUE);
697 break;
699 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
700 if(lValue == AL_TRUE || lValue == AL_FALSE)
702 Source->WetGainHFAuto = lValue;
703 Source->NeedsUpdate = AL_TRUE;
705 else
706 alSetError(pContext, AL_INVALID_VALUE);
707 break;
709 case AL_VIRTUAL_CHANNELS_SOFT:
710 if(lValue == AL_TRUE || lValue == AL_FALSE)
712 Source->VirtualChannels = lValue;
713 Source->NeedsUpdate = AL_TRUE;
715 else
716 alSetError(pContext, AL_INVALID_VALUE);
717 break;
719 case AL_DISTANCE_MODEL:
720 if(lValue == AL_NONE ||
721 lValue == AL_INVERSE_DISTANCE ||
722 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
723 lValue == AL_LINEAR_DISTANCE ||
724 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
725 lValue == AL_EXPONENT_DISTANCE ||
726 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
728 Source->DistanceModel = lValue;
729 if(pContext->SourceDistanceModel)
730 Source->NeedsUpdate = AL_TRUE;
732 else
733 alSetError(pContext, AL_INVALID_VALUE);
734 break;
736 default:
737 alSetError(pContext, AL_INVALID_ENUM);
738 break;
741 else
742 alSetError(pContext, AL_INVALID_NAME);
744 ALCcontext_DecRef(pContext);
748 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
750 ALCcontext *pContext;
751 ALsource *Source;
753 switch(eParam)
755 case AL_POSITION:
756 case AL_VELOCITY:
757 case AL_DIRECTION:
758 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
759 return;
762 pContext = GetContextRef();
763 if(!pContext) return;
765 if((Source=LookupSource(pContext, source)) != NULL)
767 ALCdevice *device = pContext->Device;
769 switch(eParam)
771 case AL_AUXILIARY_SEND_FILTER: {
772 ALeffectslot *ALEffectSlot = NULL;
773 ALfilter *ALFilter = NULL;
775 LockContext(pContext);
776 if((ALuint)lValue2 < device->NumAuxSends &&
777 (lValue1 == 0 || (ALEffectSlot=LookupEffectSlot(pContext, lValue1)) != NULL) &&
778 (lValue3 == 0 || (ALFilter=LookupFilter(device, lValue3)) != NULL))
780 /* Release refcount on the previous slot, and add one for
781 * the new slot */
782 if(ALEffectSlot) IncrementRef(&ALEffectSlot->ref);
783 ALEffectSlot = ExchangePtr((void**)&Source->Send[lValue2].Slot, ALEffectSlot);
784 if(ALEffectSlot) DecrementRef(&ALEffectSlot->ref);
786 if(!ALFilter)
788 /* Disable filter */
789 Source->Send[lValue2].WetGain = 1.0f;
790 Source->Send[lValue2].WetGainHF = 1.0f;
792 else
794 Source->Send[lValue2].WetGain = ALFilter->Gain;
795 Source->Send[lValue2].WetGainHF = ALFilter->GainHF;
797 Source->NeedsUpdate = AL_TRUE;
799 else
800 alSetError(pContext, AL_INVALID_VALUE);
801 UnlockContext(pContext);
802 } break;
804 default:
805 alSetError(pContext, AL_INVALID_ENUM);
806 break;
809 else
810 alSetError(pContext, AL_INVALID_NAME);
812 ALCcontext_DecRef(pContext);
816 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
818 ALCcontext *pContext;
820 if(plValues)
822 switch(eParam)
824 case AL_SOURCE_RELATIVE:
825 case AL_CONE_INNER_ANGLE:
826 case AL_CONE_OUTER_ANGLE:
827 case AL_LOOPING:
828 case AL_BUFFER:
829 case AL_SOURCE_STATE:
830 case AL_SEC_OFFSET:
831 case AL_SAMPLE_OFFSET:
832 case AL_BYTE_OFFSET:
833 case AL_MAX_DISTANCE:
834 case AL_ROLLOFF_FACTOR:
835 case AL_REFERENCE_DISTANCE:
836 case AL_DIRECT_FILTER:
837 case AL_DIRECT_FILTER_GAINHF_AUTO:
838 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
839 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
840 case AL_DISTANCE_MODEL:
841 case AL_VIRTUAL_CHANNELS_SOFT:
842 alSourcei(source, eParam, plValues[0]);
843 return;
845 case AL_POSITION:
846 case AL_VELOCITY:
847 case AL_DIRECTION:
848 case AL_AUXILIARY_SEND_FILTER:
849 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
850 return;
854 pContext = GetContextRef();
855 if(!pContext) return;
857 if(plValues)
859 if(LookupSource(pContext, source) != NULL)
861 switch(eParam)
863 default:
864 alSetError(pContext, AL_INVALID_ENUM);
865 break;
868 else
869 alSetError(pContext, AL_INVALID_NAME);
871 else
872 alSetError(pContext, AL_INVALID_VALUE);
874 ALCcontext_DecRef(pContext);
878 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
880 ALCcontext *pContext;
881 ALsource *Source;
882 ALdouble Offsets[2];
883 ALdouble updateLen;
885 pContext = GetContextRef();
886 if(!pContext) return;
888 if(pflValue)
890 if((Source=LookupSource(pContext, source)) != NULL)
892 switch(eParam)
894 case AL_PITCH:
895 *pflValue = Source->flPitch;
896 break;
898 case AL_GAIN:
899 *pflValue = Source->flGain;
900 break;
902 case AL_MIN_GAIN:
903 *pflValue = Source->flMinGain;
904 break;
906 case AL_MAX_GAIN:
907 *pflValue = Source->flMaxGain;
908 break;
910 case AL_MAX_DISTANCE:
911 *pflValue = Source->flMaxDistance;
912 break;
914 case AL_ROLLOFF_FACTOR:
915 *pflValue = Source->flRollOffFactor;
916 break;
918 case AL_CONE_OUTER_GAIN:
919 *pflValue = Source->flOuterGain;
920 break;
922 case AL_CONE_OUTER_GAINHF:
923 *pflValue = Source->OuterGainHF;
924 break;
926 case AL_SEC_OFFSET:
927 case AL_SAMPLE_OFFSET:
928 case AL_BYTE_OFFSET:
929 LockContext(pContext);
930 updateLen = (ALdouble)pContext->Device->UpdateSize /
931 pContext->Device->Frequency;
932 GetSourceOffset(Source, eParam, Offsets, updateLen);
933 UnlockContext(pContext);
934 *pflValue = (ALfloat)Offsets[0];
935 break;
937 case AL_CONE_INNER_ANGLE:
938 *pflValue = Source->flInnerAngle;
939 break;
941 case AL_CONE_OUTER_ANGLE:
942 *pflValue = Source->flOuterAngle;
943 break;
945 case AL_REFERENCE_DISTANCE:
946 *pflValue = Source->flRefDistance;
947 break;
949 case AL_AIR_ABSORPTION_FACTOR:
950 *pflValue = Source->AirAbsorptionFactor;
951 break;
953 case AL_ROOM_ROLLOFF_FACTOR:
954 *pflValue = Source->RoomRolloffFactor;
955 break;
957 case AL_DOPPLER_FACTOR:
958 *pflValue = Source->DopplerFactor;
959 break;
961 default:
962 alSetError(pContext, AL_INVALID_ENUM);
963 break;
966 else
967 alSetError(pContext, AL_INVALID_NAME);
969 else
970 alSetError(pContext, AL_INVALID_VALUE);
972 ALCcontext_DecRef(pContext);
976 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
978 ALCcontext *pContext;
979 ALsource *Source;
981 pContext = GetContextRef();
982 if(!pContext) return;
984 if(pflValue1 && pflValue2 && pflValue3)
986 if((Source=LookupSource(pContext, source)) != NULL)
988 switch(eParam)
990 case AL_POSITION:
991 LockContext(pContext);
992 *pflValue1 = Source->vPosition[0];
993 *pflValue2 = Source->vPosition[1];
994 *pflValue3 = Source->vPosition[2];
995 UnlockContext(pContext);
996 break;
998 case AL_VELOCITY:
999 LockContext(pContext);
1000 *pflValue1 = Source->vVelocity[0];
1001 *pflValue2 = Source->vVelocity[1];
1002 *pflValue3 = Source->vVelocity[2];
1003 UnlockContext(pContext);
1004 break;
1006 case AL_DIRECTION:
1007 LockContext(pContext);
1008 *pflValue1 = Source->vOrientation[0];
1009 *pflValue2 = Source->vOrientation[1];
1010 *pflValue3 = Source->vOrientation[2];
1011 UnlockContext(pContext);
1012 break;
1014 default:
1015 alSetError(pContext, AL_INVALID_ENUM);
1016 break;
1019 else
1020 alSetError(pContext, AL_INVALID_NAME);
1022 else
1023 alSetError(pContext, AL_INVALID_VALUE);
1025 ALCcontext_DecRef(pContext);
1029 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1031 ALCcontext *pContext;
1032 ALsource *Source;
1033 ALdouble Offsets[2];
1034 ALdouble updateLen;
1036 switch(eParam)
1038 case AL_PITCH:
1039 case AL_GAIN:
1040 case AL_MIN_GAIN:
1041 case AL_MAX_GAIN:
1042 case AL_MAX_DISTANCE:
1043 case AL_ROLLOFF_FACTOR:
1044 case AL_DOPPLER_FACTOR:
1045 case AL_CONE_OUTER_GAIN:
1046 case AL_SEC_OFFSET:
1047 case AL_SAMPLE_OFFSET:
1048 case AL_BYTE_OFFSET:
1049 case AL_CONE_INNER_ANGLE:
1050 case AL_CONE_OUTER_ANGLE:
1051 case AL_REFERENCE_DISTANCE:
1052 case AL_CONE_OUTER_GAINHF:
1053 case AL_AIR_ABSORPTION_FACTOR:
1054 case AL_ROOM_ROLLOFF_FACTOR:
1055 alGetSourcef(source, eParam, pflValues);
1056 return;
1058 case AL_POSITION:
1059 case AL_VELOCITY:
1060 case AL_DIRECTION:
1061 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1062 return;
1065 pContext = GetContextRef();
1066 if(!pContext) return;
1068 if(pflValues)
1070 if((Source=LookupSource(pContext, source)) != NULL)
1072 switch(eParam)
1074 case AL_SAMPLE_RW_OFFSETS_SOFT:
1075 case AL_BYTE_RW_OFFSETS_SOFT:
1076 LockContext(pContext);
1077 updateLen = (ALdouble)pContext->Device->UpdateSize /
1078 pContext->Device->Frequency;
1079 GetSourceOffset(Source, eParam, Offsets, updateLen);
1080 UnlockContext(pContext);
1081 pflValues[0] = (ALfloat)Offsets[0];
1082 pflValues[1] = (ALfloat)Offsets[1];
1083 break;
1085 default:
1086 alSetError(pContext, AL_INVALID_ENUM);
1087 break;
1090 else
1091 alSetError(pContext, AL_INVALID_NAME);
1093 else
1094 alSetError(pContext, AL_INVALID_VALUE);
1096 ALCcontext_DecRef(pContext);
1100 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1102 ALbufferlistitem *BufferList;
1103 ALCcontext *pContext;
1104 ALsource *Source;
1105 ALdouble Offsets[2];
1106 ALdouble updateLen;
1108 pContext = GetContextRef();
1109 if(!pContext) return;
1111 if(plValue)
1113 if((Source=LookupSource(pContext, source)) != NULL)
1115 switch(eParam)
1117 case AL_MAX_DISTANCE:
1118 *plValue = (ALint)Source->flMaxDistance;
1119 break;
1121 case AL_ROLLOFF_FACTOR:
1122 *plValue = (ALint)Source->flRollOffFactor;
1123 break;
1125 case AL_REFERENCE_DISTANCE:
1126 *plValue = (ALint)Source->flRefDistance;
1127 break;
1129 case AL_SOURCE_RELATIVE:
1130 *plValue = Source->bHeadRelative;
1131 break;
1133 case AL_CONE_INNER_ANGLE:
1134 *plValue = (ALint)Source->flInnerAngle;
1135 break;
1137 case AL_CONE_OUTER_ANGLE:
1138 *plValue = (ALint)Source->flOuterAngle;
1139 break;
1141 case AL_LOOPING:
1142 *plValue = Source->bLooping;
1143 break;
1145 case AL_BUFFER:
1146 LockContext(pContext);
1147 BufferList = Source->queue;
1148 if(Source->lSourceType != AL_STATIC)
1150 ALuint i = Source->BuffersPlayed;
1151 while(i > 0)
1153 BufferList = BufferList->next;
1154 i--;
1157 *plValue = ((BufferList && BufferList->buffer) ?
1158 BufferList->buffer->buffer : 0);
1159 UnlockContext(pContext);
1160 break;
1162 case AL_SOURCE_STATE:
1163 *plValue = Source->state;
1164 break;
1166 case AL_BUFFERS_QUEUED:
1167 *plValue = Source->BuffersInQueue;
1168 break;
1170 case AL_BUFFERS_PROCESSED:
1171 LockContext(pContext);
1172 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1174 /* Buffers on a looping source are in a perpetual state
1175 * of PENDING, so don't report any as PROCESSED */
1176 *plValue = 0;
1178 else
1179 *plValue = Source->BuffersPlayed;
1180 UnlockContext(pContext);
1181 break;
1183 case AL_SOURCE_TYPE:
1184 *plValue = Source->lSourceType;
1185 break;
1187 case AL_SEC_OFFSET:
1188 case AL_SAMPLE_OFFSET:
1189 case AL_BYTE_OFFSET:
1190 LockContext(pContext);
1191 updateLen = (ALdouble)pContext->Device->UpdateSize /
1192 pContext->Device->Frequency;
1193 GetSourceOffset(Source, eParam, Offsets, updateLen);
1194 UnlockContext(pContext);
1195 *plValue = (ALint)Offsets[0];
1196 break;
1198 case AL_DIRECT_FILTER_GAINHF_AUTO:
1199 *plValue = Source->DryGainHFAuto;
1200 break;
1202 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1203 *plValue = Source->WetGainAuto;
1204 break;
1206 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1207 *plValue = Source->WetGainHFAuto;
1208 break;
1210 case AL_DOPPLER_FACTOR:
1211 *plValue = (ALint)Source->DopplerFactor;
1212 break;
1214 case AL_VIRTUAL_CHANNELS_SOFT:
1215 *plValue = Source->VirtualChannels;
1216 break;
1218 case AL_DISTANCE_MODEL:
1219 *plValue = Source->DistanceModel;
1220 break;
1222 default:
1223 alSetError(pContext, AL_INVALID_ENUM);
1224 break;
1227 else
1228 alSetError(pContext, AL_INVALID_NAME);
1230 else
1231 alSetError(pContext, AL_INVALID_VALUE);
1233 ALCcontext_DecRef(pContext);
1237 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1239 ALCcontext *pContext;
1240 ALsource *Source;
1242 pContext = GetContextRef();
1243 if(!pContext) return;
1245 if(plValue1 && plValue2 && plValue3)
1247 if((Source=LookupSource(pContext, source)) != NULL)
1249 switch(eParam)
1251 case AL_POSITION:
1252 LockContext(pContext);
1253 *plValue1 = (ALint)Source->vPosition[0];
1254 *plValue2 = (ALint)Source->vPosition[1];
1255 *plValue3 = (ALint)Source->vPosition[2];
1256 UnlockContext(pContext);
1257 break;
1259 case AL_VELOCITY:
1260 LockContext(pContext);
1261 *plValue1 = (ALint)Source->vVelocity[0];
1262 *plValue2 = (ALint)Source->vVelocity[1];
1263 *plValue3 = (ALint)Source->vVelocity[2];
1264 UnlockContext(pContext);
1265 break;
1267 case AL_DIRECTION:
1268 LockContext(pContext);
1269 *plValue1 = (ALint)Source->vOrientation[0];
1270 *plValue2 = (ALint)Source->vOrientation[1];
1271 *plValue3 = (ALint)Source->vOrientation[2];
1272 UnlockContext(pContext);
1273 break;
1275 default:
1276 alSetError(pContext, AL_INVALID_ENUM);
1277 break;
1280 else
1281 alSetError(pContext, AL_INVALID_NAME);
1283 else
1284 alSetError(pContext, AL_INVALID_VALUE);
1286 ALCcontext_DecRef(pContext);
1290 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1292 ALCcontext *pContext;
1293 ALsource *Source;
1294 ALdouble Offsets[2];
1295 ALdouble updateLen;
1297 switch(eParam)
1299 case AL_SOURCE_RELATIVE:
1300 case AL_CONE_INNER_ANGLE:
1301 case AL_CONE_OUTER_ANGLE:
1302 case AL_LOOPING:
1303 case AL_BUFFER:
1304 case AL_SOURCE_STATE:
1305 case AL_BUFFERS_QUEUED:
1306 case AL_BUFFERS_PROCESSED:
1307 case AL_SEC_OFFSET:
1308 case AL_SAMPLE_OFFSET:
1309 case AL_BYTE_OFFSET:
1310 case AL_MAX_DISTANCE:
1311 case AL_ROLLOFF_FACTOR:
1312 case AL_DOPPLER_FACTOR:
1313 case AL_REFERENCE_DISTANCE:
1314 case AL_SOURCE_TYPE:
1315 case AL_DIRECT_FILTER:
1316 case AL_DIRECT_FILTER_GAINHF_AUTO:
1317 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1318 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1319 case AL_DISTANCE_MODEL:
1320 case AL_VIRTUAL_CHANNELS_SOFT:
1321 alGetSourcei(source, eParam, plValues);
1322 return;
1324 case AL_POSITION:
1325 case AL_VELOCITY:
1326 case AL_DIRECTION:
1327 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1328 return;
1331 pContext = GetContextRef();
1332 if(!pContext) return;
1334 if(plValues)
1336 if((Source=LookupSource(pContext, source)) != NULL)
1338 switch(eParam)
1340 case AL_SAMPLE_RW_OFFSETS_SOFT:
1341 case AL_BYTE_RW_OFFSETS_SOFT:
1342 LockContext(pContext);
1343 updateLen = (ALdouble)pContext->Device->UpdateSize /
1344 pContext->Device->Frequency;
1345 GetSourceOffset(Source, eParam, Offsets, updateLen);
1346 UnlockContext(pContext);
1347 plValues[0] = (ALint)Offsets[0];
1348 plValues[1] = (ALint)Offsets[1];
1349 break;
1351 default:
1352 alSetError(pContext, AL_INVALID_ENUM);
1353 break;
1356 else
1357 alSetError(pContext, AL_INVALID_NAME);
1359 else
1360 alSetError(pContext, AL_INVALID_VALUE);
1362 ALCcontext_DecRef(pContext);
1366 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1368 alSourcePlayv(1, &source);
1371 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1373 ALCcontext *Context;
1374 ALsource *Source;
1375 ALsizei i;
1377 Context = GetContextRef();
1378 if(!Context) return;
1380 if(n < 0)
1382 alSetError(Context, AL_INVALID_VALUE);
1383 goto done;
1385 if(n > 0 && !sources)
1387 alSetError(Context, AL_INVALID_VALUE);
1388 goto done;
1391 // Check that all the Sources are valid
1392 for(i = 0;i < n;i++)
1394 if(!LookupSource(Context, sources[i]))
1396 alSetError(Context, AL_INVALID_NAME);
1397 goto done;
1401 LockContext(Context);
1402 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1404 void *temp = NULL;
1405 ALsizei newcount;
1407 newcount = Context->MaxActiveSources << 1;
1408 if(newcount > 0)
1409 temp = realloc(Context->ActiveSources,
1410 sizeof(*Context->ActiveSources) * newcount);
1411 if(!temp)
1413 UnlockContext(Context);
1414 alSetError(Context, AL_OUT_OF_MEMORY);
1415 goto done;
1418 Context->ActiveSources = temp;
1419 Context->MaxActiveSources = newcount;
1422 for(i = 0;i < n;i++)
1424 Source = LookupSource(Context, sources[i]);
1425 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1426 else SetSourceState(Source, Context, AL_PLAYING);
1428 UnlockContext(Context);
1430 done:
1431 ALCcontext_DecRef(Context);
1434 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1436 alSourcePausev(1, &source);
1439 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1441 ALCcontext *Context;
1442 ALsource *Source;
1443 ALsizei i;
1445 Context = GetContextRef();
1446 if(!Context) return;
1448 if(n < 0)
1450 alSetError(Context, AL_INVALID_VALUE);
1451 goto done;
1453 if(n > 0 && !sources)
1455 alSetError(Context, AL_INVALID_VALUE);
1456 goto done;
1459 // Check all the Sources are valid
1460 for(i = 0;i < n;i++)
1462 if(!LookupSource(Context, sources[i]))
1464 alSetError(Context, AL_INVALID_NAME);
1465 goto done;
1469 LockContext(Context);
1470 for(i = 0;i < n;i++)
1472 Source = LookupSource(Context, sources[i]);
1473 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1474 else SetSourceState(Source, Context, AL_PAUSED);
1476 UnlockContext(Context);
1478 done:
1479 ALCcontext_DecRef(Context);
1482 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1484 alSourceStopv(1, &source);
1487 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1489 ALCcontext *Context;
1490 ALsource *Source;
1491 ALsizei i;
1493 Context = GetContextRef();
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, sources[i]))
1512 alSetError(Context, AL_INVALID_NAME);
1513 goto done;
1517 LockContext(Context);
1518 for(i = 0;i < n;i++)
1520 Source = LookupSource(Context, sources[i]);
1521 Source->new_state = AL_NONE;
1522 SetSourceState(Source, Context, AL_STOPPED);
1524 UnlockContext(Context);
1526 done:
1527 ALCcontext_DecRef(Context);
1530 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1532 alSourceRewindv(1, &source);
1535 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1537 ALCcontext *Context;
1538 ALsource *Source;
1539 ALsizei i;
1541 Context = GetContextRef();
1542 if(!Context) return;
1544 if(n < 0)
1546 alSetError(Context, AL_INVALID_VALUE);
1547 goto done;
1549 if(n > 0 && !sources)
1551 alSetError(Context, AL_INVALID_VALUE);
1552 goto done;
1555 // Check all the Sources are valid
1556 for(i = 0;i < n;i++)
1558 if(!LookupSource(Context, sources[i]))
1560 alSetError(Context, AL_INVALID_NAME);
1561 goto done;
1565 LockContext(Context);
1566 for(i = 0;i < n;i++)
1568 Source = LookupSource(Context, sources[i]);
1569 Source->new_state = AL_NONE;
1570 SetSourceState(Source, Context, AL_INITIAL);
1572 UnlockContext(Context);
1574 done:
1575 ALCcontext_DecRef(Context);
1579 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1581 ALCcontext *Context;
1582 ALCdevice *device;
1583 ALsource *Source;
1584 ALsizei i;
1585 ALbufferlistitem *BufferListStart = NULL;
1586 ALbufferlistitem *BufferList;
1587 ALbuffer *BufferFmt;
1589 if(n == 0)
1590 return;
1592 Context = GetContextRef();
1593 if(!Context) return;
1595 if(n < 0)
1597 alSetError(Context, AL_INVALID_VALUE);
1598 goto error;
1601 // Check that all buffers are valid or zero and that the source is valid
1603 // Check that this is a valid source
1604 if((Source=LookupSource(Context, source)) == NULL)
1606 alSetError(Context, AL_INVALID_NAME);
1607 goto error;
1610 LockContext(Context);
1611 // Check that this is not a STATIC Source
1612 if(Source->lSourceType == AL_STATIC)
1614 UnlockContext(Context);
1615 // Invalid Source Type (can't queue on a Static Source)
1616 alSetError(Context, AL_INVALID_OPERATION);
1617 goto error;
1620 device = Context->Device;
1622 BufferFmt = NULL;
1624 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1625 BufferList = Source->queue;
1626 while(BufferList)
1628 if(BufferList->buffer)
1630 BufferFmt = BufferList->buffer;
1631 break;
1633 BufferList = BufferList->next;
1636 for(i = 0;i < n;i++)
1638 ALbuffer *buffer = NULL;
1639 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1641 UnlockContext(Context);
1642 alSetError(Context, AL_INVALID_NAME);
1643 goto error;
1646 if(!BufferListStart)
1648 BufferListStart = malloc(sizeof(ALbufferlistitem));
1649 BufferListStart->buffer = buffer;
1650 BufferListStart->next = NULL;
1651 BufferListStart->prev = NULL;
1652 BufferList = BufferListStart;
1654 else
1656 BufferList->next = malloc(sizeof(ALbufferlistitem));
1657 BufferList->next->buffer = buffer;
1658 BufferList->next->next = NULL;
1659 BufferList->next->prev = BufferList;
1660 BufferList = BufferList->next;
1662 if(!buffer) continue;
1664 // Increment reference counter for buffer
1665 IncrementRef(&buffer->ref);
1666 ReadLock(&buffer->lock);
1667 if(BufferFmt == NULL)
1669 BufferFmt = buffer;
1671 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1672 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1673 if(buffer->FmtChannels == FmtMono)
1674 Source->Update = CalcSourceParams;
1675 else
1676 Source->Update = CalcNonAttnSourceParams;
1678 Source->NeedsUpdate = AL_TRUE;
1680 else if(BufferFmt->Frequency != buffer->Frequency ||
1681 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1682 BufferFmt->OriginalType != buffer->OriginalType)
1684 ReadUnlock(&buffer->lock);
1685 UnlockContext(Context);
1686 alSetError(Context, AL_INVALID_OPERATION);
1687 goto error;
1689 ReadUnlock(&buffer->lock);
1692 // Change Source Type
1693 Source->lSourceType = AL_STREAMING;
1695 if(Source->queue == NULL)
1696 Source->queue = BufferListStart;
1697 else
1699 // Find end of queue
1700 BufferList = Source->queue;
1701 while(BufferList->next != NULL)
1702 BufferList = BufferList->next;
1704 BufferListStart->prev = BufferList;
1705 BufferList->next = BufferListStart;
1708 // Update number of buffers in queue
1709 Source->BuffersInQueue += n;
1711 UnlockContext(Context);
1712 ALCcontext_DecRef(Context);
1713 return;
1715 error:
1716 while(BufferListStart)
1718 BufferList = BufferListStart;
1719 BufferListStart = BufferList->next;
1721 if(BufferList->buffer)
1722 DecrementRef(&BufferList->buffer->ref);
1723 free(BufferList);
1725 ALCcontext_DecRef(Context);
1729 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1730 // an array of buffer IDs that are to be filled with the names of the buffers removed
1731 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1733 ALCcontext *Context;
1734 ALsource *Source;
1735 ALsizei i;
1736 ALbufferlistitem *BufferList;
1738 if(n == 0)
1739 return;
1741 Context = GetContextRef();
1742 if(!Context) return;
1744 if(n < 0)
1746 alSetError(Context, AL_INVALID_VALUE);
1747 goto done;
1750 if((Source=LookupSource(Context, source)) == NULL)
1752 alSetError(Context, AL_INVALID_NAME);
1753 goto done;
1756 LockContext(Context);
1757 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1758 (ALuint)n > Source->BuffersPlayed)
1760 UnlockContext(Context);
1761 // Some buffers can't be unqueue because they have not been processed
1762 alSetError(Context, AL_INVALID_VALUE);
1763 goto done;
1766 for(i = 0;i < n;i++)
1768 BufferList = Source->queue;
1769 Source->queue = BufferList->next;
1770 Source->BuffersInQueue--;
1771 Source->BuffersPlayed--;
1773 if(BufferList->buffer)
1775 // Record name of buffer
1776 buffers[i] = BufferList->buffer->buffer;
1777 // Decrement buffer reference counter
1778 DecrementRef(&BufferList->buffer->ref);
1780 else
1781 buffers[i] = 0;
1783 // Release memory for buffer list item
1784 free(BufferList);
1786 if(Source->queue)
1787 Source->queue->prev = NULL;
1788 UnlockContext(Context);
1790 done:
1791 ALCcontext_DecRef(Context);
1795 static ALvoid InitSourceParams(ALsource *Source)
1797 ALuint i;
1799 Source->flInnerAngle = 360.0f;
1800 Source->flOuterAngle = 360.0f;
1801 Source->flPitch = 1.0f;
1802 Source->vPosition[0] = 0.0f;
1803 Source->vPosition[1] = 0.0f;
1804 Source->vPosition[2] = 0.0f;
1805 Source->vOrientation[0] = 0.0f;
1806 Source->vOrientation[1] = 0.0f;
1807 Source->vOrientation[2] = 0.0f;
1808 Source->vVelocity[0] = 0.0f;
1809 Source->vVelocity[1] = 0.0f;
1810 Source->vVelocity[2] = 0.0f;
1811 Source->flRefDistance = 1.0f;
1812 Source->flMaxDistance = FLT_MAX;
1813 Source->flRollOffFactor = 1.0f;
1814 Source->bLooping = AL_FALSE;
1815 Source->flGain = 1.0f;
1816 Source->flMinGain = 0.0f;
1817 Source->flMaxGain = 1.0f;
1818 Source->flOuterGain = 0.0f;
1819 Source->OuterGainHF = 1.0f;
1821 Source->DryGainHFAuto = AL_TRUE;
1822 Source->WetGainAuto = AL_TRUE;
1823 Source->WetGainHFAuto = AL_TRUE;
1824 Source->AirAbsorptionFactor = 0.0f;
1825 Source->RoomRolloffFactor = 0.0f;
1826 Source->DopplerFactor = 1.0f;
1827 Source->VirtualChannels = AL_TRUE;
1829 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1831 Source->Resampler = DefaultResampler;
1833 Source->state = AL_INITIAL;
1834 Source->new_state = AL_NONE;
1835 Source->lSourceType = AL_UNDETERMINED;
1836 Source->lOffset = -1;
1838 Source->DirectGain = 1.0f;
1839 Source->DirectGainHF = 1.0f;
1840 for(i = 0;i < MAX_SENDS;i++)
1842 Source->Send[i].WetGain = 1.0f;
1843 Source->Send[i].WetGainHF = 1.0f;
1846 Source->NeedsUpdate = AL_TRUE;
1848 Source->HrtfMoving = AL_FALSE;
1849 Source->HrtfCounter = 0;
1854 * SetSourceState
1856 * Sets the source's new play state given its current state
1858 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1860 if(state == AL_PLAYING)
1862 ALbufferlistitem *BufferList;
1863 ALsizei j, k;
1865 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
1866 BufferList = Source->queue;
1867 while(BufferList)
1869 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1870 break;
1871 BufferList = BufferList->next;
1874 if(Source->state != AL_PLAYING)
1876 for(j = 0;j < MAXCHANNELS;j++)
1878 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1879 Source->HrtfHistory[j][k] = 0.0f;
1880 for(k = 0;k < HRIR_LENGTH;k++)
1882 Source->HrtfValues[j][k][0] = 0.0f;
1883 Source->HrtfValues[j][k][1] = 0.0f;
1888 if(Source->state != AL_PAUSED)
1890 Source->state = AL_PLAYING;
1891 Source->position = 0;
1892 Source->position_fraction = 0;
1893 Source->BuffersPlayed = 0;
1895 else
1896 Source->state = AL_PLAYING;
1898 // Check if an Offset has been set
1899 if(Source->lOffset != -1)
1900 ApplyOffset(Source);
1902 /* If there's nothing to play, or device is disconnected, go right to
1903 * stopped */
1904 if(!BufferList || !Context->Device->Connected)
1906 SetSourceState(Source, Context, AL_STOPPED);
1907 return;
1910 for(j = 0;j < Context->ActiveSourceCount;j++)
1912 if(Context->ActiveSources[j] == Source)
1913 break;
1915 if(j == Context->ActiveSourceCount)
1916 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1918 else if(state == AL_PAUSED)
1920 if(Source->state == AL_PLAYING)
1922 Source->state = AL_PAUSED;
1923 Source->HrtfMoving = AL_FALSE;
1924 Source->HrtfCounter = 0;
1927 else if(state == AL_STOPPED)
1929 if(Source->state != AL_INITIAL)
1931 Source->state = AL_STOPPED;
1932 Source->BuffersPlayed = Source->BuffersInQueue;
1933 Source->HrtfMoving = AL_FALSE;
1934 Source->HrtfCounter = 0;
1936 Source->lOffset = -1;
1938 else if(state == AL_INITIAL)
1940 if(Source->state != AL_INITIAL)
1942 Source->state = AL_INITIAL;
1943 Source->position = 0;
1944 Source->position_fraction = 0;
1945 Source->BuffersPlayed = 0;
1946 Source->HrtfMoving = AL_FALSE;
1947 Source->HrtfCounter = 0;
1949 Source->lOffset = -1;
1954 GetSourceOffset
1956 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1957 The offset is relative to the start of the queue (not the start of the current buffer)
1959 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1961 const ALbufferlistitem *BufferList;
1962 const ALbuffer *Buffer = NULL;
1963 ALuint BufferFreq = 0;
1964 ALuint readPos, writePos;
1965 ALuint totalBufferLen;
1966 ALuint i;
1968 // Find the first non-NULL Buffer in the Queue
1969 BufferList = Source->queue;
1970 while(BufferList)
1972 if(BufferList->buffer)
1974 Buffer = BufferList->buffer;
1975 BufferFreq = Buffer->Frequency;
1976 break;
1978 BufferList = BufferList->next;
1981 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1983 offset[0] = 0.0;
1984 offset[1] = 0.0;
1985 return;
1988 // Get Current SamplesPlayed (NOTE : This is the offset into the *current* buffer)
1989 readPos = Source->position;
1990 // Add length of any processed buffers in the queue
1991 totalBufferLen = 0;
1992 BufferList = Source->queue;
1993 for(i = 0;BufferList;i++)
1995 if(BufferList->buffer)
1997 if(i < Source->BuffersPlayed)
1998 readPos += BufferList->buffer->SampleLen;
1999 totalBufferLen += BufferList->buffer->SampleLen;
2001 BufferList = BufferList->next;
2003 if(Source->state == AL_PLAYING)
2004 writePos = readPos + (ALuint)(updateLen*BufferFreq);
2005 else
2006 writePos = readPos;
2008 if(Source->bLooping)
2010 readPos %= totalBufferLen;
2011 writePos %= totalBufferLen;
2013 else
2015 // Wrap positions back to 0
2016 if(readPos >= totalBufferLen)
2017 readPos = 0;
2018 if(writePos >= totalBufferLen)
2019 writePos = 0;
2022 switch(name)
2024 case AL_SEC_OFFSET:
2025 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2026 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2027 break;
2028 case AL_SAMPLE_OFFSET:
2029 case AL_SAMPLE_RW_OFFSETS_SOFT:
2030 offset[0] = (ALdouble)readPos;
2031 offset[1] = (ALdouble)writePos;
2032 break;
2033 case AL_BYTE_OFFSET:
2034 case AL_BYTE_RW_OFFSETS_SOFT:
2035 // Take into account the original format of the Buffer
2036 if(Buffer->OriginalType == UserFmtIMA4)
2038 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2039 ALuint FrameBlockSize = 65;
2041 // Round down to nearest ADPCM block
2042 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2043 if(Source->state != AL_PLAYING)
2044 offset[1] = offset[0];
2045 else
2047 // Round up to nearest ADPCM block
2048 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2049 FrameBlockSize * BlockSize);
2052 else
2054 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2055 offset[0] = (ALdouble)(readPos * FrameSize);
2056 offset[1] = (ALdouble)(writePos * FrameSize);
2058 break;
2064 ApplyOffset
2066 Apply a playback offset to the Source. This function will update the queue (to correctly
2067 mark buffers as 'pending' or 'processed' depending upon the new offset.
2069 ALboolean ApplyOffset(ALsource *Source)
2071 const ALbufferlistitem *BufferList;
2072 const ALbuffer *Buffer;
2073 ALint bufferLen, totalBufferLen;
2074 ALint buffersPlayed;
2075 ALint offset;
2077 // Get true byte offset
2078 offset = GetSampleOffset(Source);
2080 // If the offset is invalid, don't apply it
2081 if(offset == -1)
2082 return AL_FALSE;
2084 // Sort out the queue (pending and processed states)
2085 BufferList = Source->queue;
2086 totalBufferLen = 0;
2087 buffersPlayed = 0;
2089 while(BufferList)
2091 Buffer = BufferList->buffer;
2092 bufferLen = Buffer ? Buffer->SampleLen : 0;
2094 if(bufferLen <= offset-totalBufferLen)
2096 // Offset is past this buffer so increment BuffersPlayed
2097 buffersPlayed++;
2099 else if(totalBufferLen <= offset)
2101 // Offset is within this buffer
2102 Source->BuffersPlayed = buffersPlayed;
2104 // SW Mixer Positions are in Samples
2105 Source->position = offset - totalBufferLen;
2106 return AL_TRUE;
2109 // Increment the TotalBufferSize
2110 totalBufferLen += bufferLen;
2112 // Move on to next buffer in the Queue
2113 BufferList = BufferList->next;
2115 // Offset is out of range of the buffer queue
2116 return AL_FALSE;
2121 GetSampleOffset
2123 Returns the sample offset into the Source's queue (from the Sample, Byte or Millisecond offset
2124 supplied by the application). This takes into account the fact that the buffer format may have
2125 been modifed by AL
2127 static ALint GetSampleOffset(ALsource *Source)
2129 const ALbuffer *Buffer = NULL;
2130 const ALbufferlistitem *BufferList;
2131 ALint Offset = -1;
2133 // Find the first non-NULL Buffer in the Queue
2134 BufferList = Source->queue;
2135 while(BufferList)
2137 if(BufferList->buffer)
2139 Buffer = BufferList->buffer;
2140 break;
2142 BufferList = BufferList->next;
2145 if(!Buffer)
2147 Source->lOffset = -1;
2148 return -1;
2151 // Determine the ByteOffset (and ensure it is block aligned)
2152 switch(Source->lOffsetType)
2154 case AL_BYTE_OFFSET:
2155 // Take into consideration the original format
2156 Offset = Source->lOffset;
2157 if(Buffer->OriginalType == UserFmtIMA4)
2159 // Round down to nearest ADPCM block
2160 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2161 // Multiply by compression rate (65 sample frames per block)
2162 Offset *= 65;
2164 else
2165 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2166 break;
2168 case AL_SAMPLE_OFFSET:
2169 Offset = Source->lOffset;
2170 break;
2172 case AL_SEC_OFFSET:
2173 // Note - lOffset is internally stored as Milliseconds
2174 Offset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2175 break;
2177 // Clear Offset
2178 Source->lOffset = -1;
2180 return Offset;
2184 ALvoid ReleaseALSources(ALCcontext *Context)
2186 ALsizei pos;
2187 ALuint j;
2188 for(pos = 0;pos < Context->SourceMap.size;pos++)
2190 ALsource *temp = Context->SourceMap.array[pos].value;
2191 Context->SourceMap.array[pos].value = NULL;
2193 // For each buffer in the source's queue, decrement its reference counter and remove it
2194 while(temp->queue != NULL)
2196 ALbufferlistitem *BufferList = temp->queue;
2197 temp->queue = BufferList->next;
2199 if(BufferList->buffer != NULL)
2200 DecrementRef(&BufferList->buffer->ref);
2201 free(BufferList);
2204 for(j = 0;j < MAX_SENDS;++j)
2206 if(temp->Send[j].Slot)
2207 DecrementRef(&temp->Send[j].Slot->ref);
2208 temp->Send[j].Slot = NULL;
2211 // Release source structure
2212 FreeThunkEntry(temp->source);
2213 memset(temp, 0, sizeof(ALsource));
2214 free(temp);