Add atomic functions for GCC inline asm
[openal-soft/android.git] / OpenAL32 / alSource.c
blob4941bc652148b62afece5b74e2bc3db70a543e72
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 GetByteOffset(ALsource *Source);
53 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
54 #define RemoveSource(m, k) ((ALsource*)PopUIntMapValue(&(m), (k)))
55 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
56 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
57 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
59 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
61 ALCcontext *Context;
62 ALCdevice *Device;
64 Context = GetContextRef();
65 if(!Context) return;
67 Device = Context->Device;
68 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
69 alSetError(Context, AL_INVALID_VALUE);
70 else
72 ALenum err;
73 ALsizei i;
75 // Add additional sources to the list
76 i = 0;
77 while(i < n)
79 ALsource *source = calloc(1, sizeof(ALsource));
80 if(!source)
82 alSetError(Context, AL_OUT_OF_MEMORY);
83 alDeleteSources(i, sources);
84 break;
86 InitSourceParams(source);
88 err = NewThunkEntry(&source->source);
89 if(err == AL_NO_ERROR)
90 err = InsertUIntMapEntry(&Context->SourceMap, source->source, source);
91 if(err != AL_NO_ERROR)
93 FreeThunkEntry(source->source);
94 memset(source, 0, sizeof(ALsource));
95 free(source);
97 alSetError(Context, err);
98 alDeleteSources(i, sources);
99 break;
102 sources[i++] = source->source;
106 ALCcontext_DecRef(Context);
110 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
112 ALCcontext *Context;
113 ALsource *Source;
114 ALsizei i, j;
115 ALbufferlistitem *BufferList;
117 Context = GetContextRef();
118 if(!Context) return;
120 if(n < 0)
121 alSetError(Context, AL_INVALID_VALUE);
122 else
124 // Check that all Sources are valid (and can therefore be deleted)
125 for(i = 0;i < n;i++)
127 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
129 alSetError(Context, AL_INVALID_NAME);
130 n = 0;
131 break;
135 // All Sources are valid, and can be deleted
136 for(i = 0;i < n;i++)
138 ALsource **srclist, **srclistend;
140 // Remove Source from list of Sources
141 if((Source=RemoveSource(Context->SourceMap, sources[i])) == NULL)
142 continue;
144 FreeThunkEntry(Source->source);
146 LockContext(Context);
147 srclist = Context->ActiveSources;
148 srclistend = srclist + Context->ActiveSourceCount;
149 while(srclist != srclistend)
151 if(*srclist == Source)
153 Context->ActiveSourceCount--;
154 *srclist = *(--srclistend);
155 break;
157 srclist++;
159 UnlockContext(Context);
161 // For each buffer in the source's queue...
162 while(Source->queue != NULL)
164 BufferList = Source->queue;
165 Source->queue = BufferList->next;
167 if(BufferList->buffer != NULL)
168 DecrementRef(&BufferList->buffer->ref);
169 free(BufferList);
172 for(j = 0;j < MAX_SENDS;++j)
174 if(Source->Send[j].Slot)
175 DecrementRef(&Source->Send[j].Slot->ref);
176 Source->Send[j].Slot = NULL;
179 memset(Source,0,sizeof(ALsource));
180 free(Source);
184 ALCcontext_DecRef(Context);
188 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
190 ALCcontext *Context;
191 ALboolean result;
193 Context = GetContextRef();
194 if(!Context) return AL_FALSE;
196 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
198 ALCcontext_DecRef(Context);
200 return result;
204 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
206 ALCcontext *pContext;
207 ALsource *Source;
209 pContext = GetContextRef();
210 if(!pContext) return;
212 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
214 switch(eParam)
216 case AL_PITCH:
217 if(flValue >= 0.0f)
219 Source->flPitch = flValue;
220 Source->NeedsUpdate = AL_TRUE;
222 else
223 alSetError(pContext, AL_INVALID_VALUE);
224 break;
226 case AL_CONE_INNER_ANGLE:
227 if(flValue >= 0.0f && flValue <= 360.0f)
229 Source->flInnerAngle = flValue;
230 Source->NeedsUpdate = AL_TRUE;
232 else
233 alSetError(pContext, AL_INVALID_VALUE);
234 break;
236 case AL_CONE_OUTER_ANGLE:
237 if(flValue >= 0.0f && flValue <= 360.0f)
239 Source->flOuterAngle = flValue;
240 Source->NeedsUpdate = AL_TRUE;
242 else
243 alSetError(pContext, AL_INVALID_VALUE);
244 break;
246 case AL_GAIN:
247 if(flValue >= 0.0f)
249 Source->flGain = flValue;
250 Source->NeedsUpdate = AL_TRUE;
252 else
253 alSetError(pContext, AL_INVALID_VALUE);
254 break;
256 case AL_MAX_DISTANCE:
257 if(flValue >= 0.0f)
259 Source->flMaxDistance = flValue;
260 Source->NeedsUpdate = AL_TRUE;
262 else
263 alSetError(pContext, AL_INVALID_VALUE);
264 break;
266 case AL_ROLLOFF_FACTOR:
267 if(flValue >= 0.0f)
269 Source->flRollOffFactor = flValue;
270 Source->NeedsUpdate = AL_TRUE;
272 else
273 alSetError(pContext, AL_INVALID_VALUE);
274 break;
276 case AL_REFERENCE_DISTANCE:
277 if(flValue >= 0.0f)
279 Source->flRefDistance = flValue;
280 Source->NeedsUpdate = AL_TRUE;
282 else
283 alSetError(pContext, AL_INVALID_VALUE);
284 break;
286 case AL_MIN_GAIN:
287 if(flValue >= 0.0f && flValue <= 1.0f)
289 Source->flMinGain = flValue;
290 Source->NeedsUpdate = AL_TRUE;
292 else
293 alSetError(pContext, AL_INVALID_VALUE);
294 break;
296 case AL_MAX_GAIN:
297 if(flValue >= 0.0f && flValue <= 1.0f)
299 Source->flMaxGain = flValue;
300 Source->NeedsUpdate = AL_TRUE;
302 else
303 alSetError(pContext, AL_INVALID_VALUE);
304 break;
306 case AL_CONE_OUTER_GAIN:
307 if(flValue >= 0.0f && flValue <= 1.0f)
309 Source->flOuterGain = flValue;
310 Source->NeedsUpdate = AL_TRUE;
312 else
313 alSetError(pContext, AL_INVALID_VALUE);
314 break;
316 case AL_CONE_OUTER_GAINHF:
317 if(flValue >= 0.0f && flValue <= 1.0f)
319 Source->OuterGainHF = flValue;
320 Source->NeedsUpdate = AL_TRUE;
322 else
323 alSetError(pContext, AL_INVALID_VALUE);
324 break;
326 case AL_AIR_ABSORPTION_FACTOR:
327 if(flValue >= 0.0f && flValue <= 10.0f)
329 Source->AirAbsorptionFactor = flValue;
330 Source->NeedsUpdate = AL_TRUE;
332 else
333 alSetError(pContext, AL_INVALID_VALUE);
334 break;
336 case AL_ROOM_ROLLOFF_FACTOR:
337 if(flValue >= 0.0f && flValue <= 10.0f)
339 Source->RoomRolloffFactor = flValue;
340 Source->NeedsUpdate = AL_TRUE;
342 else
343 alSetError(pContext, AL_INVALID_VALUE);
344 break;
346 case AL_DOPPLER_FACTOR:
347 if(flValue >= 0.0f && flValue <= 1.0f)
349 Source->DopplerFactor = flValue;
350 Source->NeedsUpdate = AL_TRUE;
352 else
353 alSetError(pContext, AL_INVALID_VALUE);
354 break;
356 case AL_SEC_OFFSET:
357 case AL_SAMPLE_OFFSET:
358 case AL_BYTE_OFFSET:
359 if(flValue >= 0.0f)
361 LockContext(pContext);
362 Source->lOffsetType = eParam;
364 // Store Offset (convert Seconds into Milliseconds)
365 if(eParam == AL_SEC_OFFSET)
366 Source->lOffset = (ALint)(flValue * 1000.0f);
367 else
368 Source->lOffset = (ALint)flValue;
370 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
371 !pContext->DeferUpdates)
373 if(ApplyOffset(Source) == AL_FALSE)
374 alSetError(pContext, AL_INVALID_VALUE);
376 UnlockContext(pContext);
378 else
379 alSetError(pContext, AL_INVALID_VALUE);
380 break;
382 default:
383 alSetError(pContext, AL_INVALID_ENUM);
384 break;
387 else
389 // Invalid Source Name
390 alSetError(pContext, AL_INVALID_NAME);
393 ALCcontext_DecRef(pContext);
397 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
399 ALCcontext *pContext;
400 ALsource *Source;
402 pContext = GetContextRef();
403 if(!pContext) return;
405 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
407 switch(eParam)
409 case AL_POSITION:
410 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
412 LockContext(pContext);
413 Source->vPosition[0] = flValue1;
414 Source->vPosition[1] = flValue2;
415 Source->vPosition[2] = flValue3;
416 UnlockContext(pContext);
417 Source->NeedsUpdate = AL_TRUE;
419 else
420 alSetError(pContext, AL_INVALID_VALUE);
421 break;
423 case AL_VELOCITY:
424 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
426 LockContext(pContext);
427 Source->vVelocity[0] = flValue1;
428 Source->vVelocity[1] = flValue2;
429 Source->vVelocity[2] = flValue3;
430 UnlockContext(pContext);
431 Source->NeedsUpdate = AL_TRUE;
433 else
434 alSetError(pContext, AL_INVALID_VALUE);
435 break;
437 case AL_DIRECTION:
438 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
440 LockContext(pContext);
441 Source->vOrientation[0] = flValue1;
442 Source->vOrientation[1] = flValue2;
443 Source->vOrientation[2] = flValue3;
444 UnlockContext(pContext);
445 Source->NeedsUpdate = AL_TRUE;
447 else
448 alSetError(pContext, AL_INVALID_VALUE);
449 break;
451 default:
452 alSetError(pContext, AL_INVALID_ENUM);
453 break;
456 else
457 alSetError(pContext, AL_INVALID_NAME);
459 ALCcontext_DecRef(pContext);
463 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
465 ALCcontext *pContext;
467 if(pflValues)
469 switch(eParam)
471 case AL_PITCH:
472 case AL_CONE_INNER_ANGLE:
473 case AL_CONE_OUTER_ANGLE:
474 case AL_GAIN:
475 case AL_MAX_DISTANCE:
476 case AL_ROLLOFF_FACTOR:
477 case AL_REFERENCE_DISTANCE:
478 case AL_MIN_GAIN:
479 case AL_MAX_GAIN:
480 case AL_CONE_OUTER_GAIN:
481 case AL_CONE_OUTER_GAINHF:
482 case AL_SEC_OFFSET:
483 case AL_SAMPLE_OFFSET:
484 case AL_BYTE_OFFSET:
485 case AL_AIR_ABSORPTION_FACTOR:
486 case AL_ROOM_ROLLOFF_FACTOR:
487 alSourcef(source, eParam, pflValues[0]);
488 return;
490 case AL_POSITION:
491 case AL_VELOCITY:
492 case AL_DIRECTION:
493 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
494 return;
498 pContext = GetContextRef();
499 if(!pContext) return;
501 if(pflValues)
503 if(LookupSource(pContext->SourceMap, source) != NULL)
505 switch(eParam)
507 default:
508 alSetError(pContext, AL_INVALID_ENUM);
509 break;
512 else
513 alSetError(pContext, AL_INVALID_NAME);
515 else
516 alSetError(pContext, AL_INVALID_VALUE);
518 ALCcontext_DecRef(pContext);
522 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
524 ALCcontext *pContext;
525 ALsource *Source;
526 ALbufferlistitem *BufferListItem;
528 switch(eParam)
530 case AL_MAX_DISTANCE:
531 case AL_ROLLOFF_FACTOR:
532 case AL_CONE_INNER_ANGLE:
533 case AL_CONE_OUTER_ANGLE:
534 case AL_REFERENCE_DISTANCE:
535 alSourcef(source, eParam, (ALfloat)lValue);
536 return;
539 pContext = GetContextRef();
540 if(!pContext) return;
542 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
544 ALCdevice *device = pContext->Device;
546 switch(eParam)
548 case AL_SOURCE_RELATIVE:
549 if(lValue == AL_FALSE || lValue == AL_TRUE)
551 Source->bHeadRelative = (ALboolean)lValue;
552 Source->NeedsUpdate = AL_TRUE;
554 else
555 alSetError(pContext, AL_INVALID_VALUE);
556 break;
558 case AL_LOOPING:
559 if(lValue == AL_FALSE || lValue == AL_TRUE)
560 Source->bLooping = (ALboolean)lValue;
561 else
562 alSetError(pContext, AL_INVALID_VALUE);
563 break;
565 case AL_BUFFER:
566 LockContext(pContext);
567 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
569 ALbufferlistitem *oldlist;
570 ALbuffer *buffer = NULL;
572 if(lValue == 0 ||
573 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
575 Source->BuffersInQueue = 0;
576 Source->BuffersPlayed = 0;
578 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
579 if(buffer != NULL)
581 // Source is now in STATIC mode
582 Source->lSourceType = AL_STATIC;
584 // Add the selected buffer to the queue
585 BufferListItem = malloc(sizeof(ALbufferlistitem));
586 BufferListItem->buffer = buffer;
587 BufferListItem->next = NULL;
588 BufferListItem->prev = NULL;
589 // Increment reference counter for buffer
590 IncrementRef(&buffer->ref);
592 oldlist = ExchangePtr((void**)&Source->queue, BufferListItem);
593 Source->BuffersInQueue = 1;
595 ReadLock(&buffer->lock);
596 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
597 Source->SampleSize = BytesFromFmt(buffer->FmtType);
598 ReadUnlock(&buffer->lock);
599 if(buffer->FmtChannels == FmtMono)
600 Source->Update = CalcSourceParams;
601 else
602 Source->Update = CalcNonAttnSourceParams;
603 Source->NeedsUpdate = AL_TRUE;
605 else
607 // Source is now in UNDETERMINED mode
608 Source->lSourceType = AL_UNDETERMINED;
609 oldlist = ExchangePtr((void**)&Source->queue, NULL);
612 // Delete all previous elements in the queue
613 while(oldlist != NULL)
615 BufferListItem = oldlist;
616 oldlist = BufferListItem->next;
618 if(BufferListItem->buffer)
619 DecrementRef(&BufferListItem->buffer->ref);
620 free(BufferListItem);
623 else
624 alSetError(pContext, AL_INVALID_VALUE);
626 else
627 alSetError(pContext, AL_INVALID_OPERATION);
628 UnlockContext(pContext);
629 break;
631 case AL_SOURCE_STATE:
632 // Query only
633 alSetError(pContext, AL_INVALID_OPERATION);
634 break;
636 case AL_SEC_OFFSET:
637 case AL_SAMPLE_OFFSET:
638 case AL_BYTE_OFFSET:
639 if(lValue >= 0)
641 LockContext(pContext);
642 Source->lOffsetType = eParam;
644 // Store Offset (convert Seconds into Milliseconds)
645 if(eParam == AL_SEC_OFFSET)
646 Source->lOffset = lValue * 1000;
647 else
648 Source->lOffset = lValue;
650 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
651 !pContext->DeferUpdates)
653 if(ApplyOffset(Source) == AL_FALSE)
654 alSetError(pContext, AL_INVALID_VALUE);
656 UnlockContext(pContext);
658 else
659 alSetError(pContext, AL_INVALID_VALUE);
660 break;
662 case AL_DIRECT_FILTER: {
663 ALfilter *filter = NULL;
665 if(lValue == 0 ||
666 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
668 LockContext(pContext);
669 if(!filter)
671 Source->DirectGain = 1.0f;
672 Source->DirectGainHF = 1.0f;
674 else
676 Source->DirectGain = filter->Gain;
677 Source->DirectGainHF = filter->GainHF;
679 UnlockContext(pContext);
680 Source->NeedsUpdate = AL_TRUE;
682 else
683 alSetError(pContext, AL_INVALID_VALUE);
684 } break;
686 case AL_DIRECT_FILTER_GAINHF_AUTO:
687 if(lValue == AL_TRUE || lValue == AL_FALSE)
689 Source->DryGainHFAuto = lValue;
690 Source->NeedsUpdate = AL_TRUE;
692 else
693 alSetError(pContext, AL_INVALID_VALUE);
694 break;
696 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
697 if(lValue == AL_TRUE || lValue == AL_FALSE)
699 Source->WetGainAuto = lValue;
700 Source->NeedsUpdate = AL_TRUE;
702 else
703 alSetError(pContext, AL_INVALID_VALUE);
704 break;
706 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
707 if(lValue == AL_TRUE || lValue == AL_FALSE)
709 Source->WetGainHFAuto = lValue;
710 Source->NeedsUpdate = AL_TRUE;
712 else
713 alSetError(pContext, AL_INVALID_VALUE);
714 break;
716 case AL_VIRTUAL_CHANNELS_SOFT:
717 if(lValue == AL_TRUE || lValue == AL_FALSE)
719 Source->VirtualChannels = lValue;
720 Source->NeedsUpdate = AL_TRUE;
722 else
723 alSetError(pContext, AL_INVALID_VALUE);
724 break;
726 case AL_DISTANCE_MODEL:
727 if(lValue == AL_NONE ||
728 lValue == AL_INVERSE_DISTANCE ||
729 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
730 lValue == AL_LINEAR_DISTANCE ||
731 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
732 lValue == AL_EXPONENT_DISTANCE ||
733 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
735 Source->DistanceModel = lValue;
736 if(pContext->SourceDistanceModel)
737 Source->NeedsUpdate = AL_TRUE;
739 else
740 alSetError(pContext, AL_INVALID_VALUE);
741 break;
743 default:
744 alSetError(pContext, AL_INVALID_ENUM);
745 break;
748 else
749 alSetError(pContext, AL_INVALID_NAME);
751 ALCcontext_DecRef(pContext);
755 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
757 ALCcontext *pContext;
758 ALsource *Source;
760 switch(eParam)
762 case AL_POSITION:
763 case AL_VELOCITY:
764 case AL_DIRECTION:
765 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
766 return;
769 pContext = GetContextRef();
770 if(!pContext) return;
772 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
774 ALCdevice *device = pContext->Device;
776 switch(eParam)
778 case AL_AUXILIARY_SEND_FILTER: {
779 ALeffectslot *ALEffectSlot = NULL;
780 ALfilter *ALFilter = NULL;
782 LockContext(pContext);
783 if((ALuint)lValue2 < device->NumAuxSends &&
784 (lValue1 == 0 ||
785 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
786 (lValue3 == 0 ||
787 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
789 /* Release refcount on the previous slot, and add one for
790 * the new slot */
791 if(ALEffectSlot) IncrementRef(&ALEffectSlot->ref);
792 ALEffectSlot = ExchangePtr((void**)&Source->Send[lValue2].Slot, ALEffectSlot);
793 if(ALEffectSlot) DecrementRef(&ALEffectSlot->ref);
795 if(!ALFilter)
797 /* Disable filter */
798 Source->Send[lValue2].WetGain = 1.0f;
799 Source->Send[lValue2].WetGainHF = 1.0f;
801 else
803 Source->Send[lValue2].WetGain = ALFilter->Gain;
804 Source->Send[lValue2].WetGainHF = ALFilter->GainHF;
806 Source->NeedsUpdate = AL_TRUE;
808 else
809 alSetError(pContext, AL_INVALID_VALUE);
810 UnlockContext(pContext);
811 } break;
813 default:
814 alSetError(pContext, AL_INVALID_ENUM);
815 break;
818 else
819 alSetError(pContext, AL_INVALID_NAME);
821 ALCcontext_DecRef(pContext);
825 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
827 ALCcontext *pContext;
829 if(plValues)
831 switch(eParam)
833 case AL_SOURCE_RELATIVE:
834 case AL_CONE_INNER_ANGLE:
835 case AL_CONE_OUTER_ANGLE:
836 case AL_LOOPING:
837 case AL_BUFFER:
838 case AL_SOURCE_STATE:
839 case AL_SEC_OFFSET:
840 case AL_SAMPLE_OFFSET:
841 case AL_BYTE_OFFSET:
842 case AL_MAX_DISTANCE:
843 case AL_ROLLOFF_FACTOR:
844 case AL_REFERENCE_DISTANCE:
845 case AL_DIRECT_FILTER:
846 case AL_DIRECT_FILTER_GAINHF_AUTO:
847 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
848 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
849 case AL_DISTANCE_MODEL:
850 case AL_VIRTUAL_CHANNELS_SOFT:
851 alSourcei(source, eParam, plValues[0]);
852 return;
854 case AL_POSITION:
855 case AL_VELOCITY:
856 case AL_DIRECTION:
857 case AL_AUXILIARY_SEND_FILTER:
858 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
859 return;
863 pContext = GetContextRef();
864 if(!pContext) return;
866 if(plValues)
868 if(LookupSource(pContext->SourceMap, source) != NULL)
870 switch(eParam)
872 default:
873 alSetError(pContext, AL_INVALID_ENUM);
874 break;
877 else
878 alSetError(pContext, AL_INVALID_NAME);
880 else
881 alSetError(pContext, AL_INVALID_VALUE);
883 ALCcontext_DecRef(pContext);
887 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
889 ALCcontext *pContext;
890 ALsource *Source;
891 ALdouble Offsets[2];
892 ALdouble updateLen;
894 pContext = GetContextRef();
895 if(!pContext) return;
897 if(pflValue)
899 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
901 switch(eParam)
903 case AL_PITCH:
904 *pflValue = Source->flPitch;
905 break;
907 case AL_GAIN:
908 *pflValue = Source->flGain;
909 break;
911 case AL_MIN_GAIN:
912 *pflValue = Source->flMinGain;
913 break;
915 case AL_MAX_GAIN:
916 *pflValue = Source->flMaxGain;
917 break;
919 case AL_MAX_DISTANCE:
920 *pflValue = Source->flMaxDistance;
921 break;
923 case AL_ROLLOFF_FACTOR:
924 *pflValue = Source->flRollOffFactor;
925 break;
927 case AL_CONE_OUTER_GAIN:
928 *pflValue = Source->flOuterGain;
929 break;
931 case AL_CONE_OUTER_GAINHF:
932 *pflValue = Source->OuterGainHF;
933 break;
935 case AL_SEC_OFFSET:
936 case AL_SAMPLE_OFFSET:
937 case AL_BYTE_OFFSET:
938 LockContext(pContext);
939 updateLen = (ALdouble)pContext->Device->UpdateSize /
940 pContext->Device->Frequency;
941 GetSourceOffset(Source, eParam, Offsets, updateLen);
942 UnlockContext(pContext);
943 *pflValue = (ALfloat)Offsets[0];
944 break;
946 case AL_CONE_INNER_ANGLE:
947 *pflValue = Source->flInnerAngle;
948 break;
950 case AL_CONE_OUTER_ANGLE:
951 *pflValue = Source->flOuterAngle;
952 break;
954 case AL_REFERENCE_DISTANCE:
955 *pflValue = Source->flRefDistance;
956 break;
958 case AL_AIR_ABSORPTION_FACTOR:
959 *pflValue = Source->AirAbsorptionFactor;
960 break;
962 case AL_ROOM_ROLLOFF_FACTOR:
963 *pflValue = Source->RoomRolloffFactor;
964 break;
966 case AL_DOPPLER_FACTOR:
967 *pflValue = Source->DopplerFactor;
968 break;
970 default:
971 alSetError(pContext, AL_INVALID_ENUM);
972 break;
975 else
976 alSetError(pContext, AL_INVALID_NAME);
978 else
979 alSetError(pContext, AL_INVALID_VALUE);
981 ALCcontext_DecRef(pContext);
985 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
987 ALCcontext *pContext;
988 ALsource *Source;
990 pContext = GetContextRef();
991 if(!pContext) return;
993 if(pflValue1 && pflValue2 && pflValue3)
995 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
997 switch(eParam)
999 case AL_POSITION:
1000 LockContext(pContext);
1001 *pflValue1 = Source->vPosition[0];
1002 *pflValue2 = Source->vPosition[1];
1003 *pflValue3 = Source->vPosition[2];
1004 UnlockContext(pContext);
1005 break;
1007 case AL_VELOCITY:
1008 LockContext(pContext);
1009 *pflValue1 = Source->vVelocity[0];
1010 *pflValue2 = Source->vVelocity[1];
1011 *pflValue3 = Source->vVelocity[2];
1012 UnlockContext(pContext);
1013 break;
1015 case AL_DIRECTION:
1016 LockContext(pContext);
1017 *pflValue1 = Source->vOrientation[0];
1018 *pflValue2 = Source->vOrientation[1];
1019 *pflValue3 = Source->vOrientation[2];
1020 UnlockContext(pContext);
1021 break;
1023 default:
1024 alSetError(pContext, AL_INVALID_ENUM);
1025 break;
1028 else
1029 alSetError(pContext, AL_INVALID_NAME);
1031 else
1032 alSetError(pContext, AL_INVALID_VALUE);
1034 ALCcontext_DecRef(pContext);
1038 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1040 ALCcontext *pContext;
1041 ALsource *Source;
1042 ALdouble Offsets[2];
1043 ALdouble updateLen;
1045 switch(eParam)
1047 case AL_PITCH:
1048 case AL_GAIN:
1049 case AL_MIN_GAIN:
1050 case AL_MAX_GAIN:
1051 case AL_MAX_DISTANCE:
1052 case AL_ROLLOFF_FACTOR:
1053 case AL_DOPPLER_FACTOR:
1054 case AL_CONE_OUTER_GAIN:
1055 case AL_SEC_OFFSET:
1056 case AL_SAMPLE_OFFSET:
1057 case AL_BYTE_OFFSET:
1058 case AL_CONE_INNER_ANGLE:
1059 case AL_CONE_OUTER_ANGLE:
1060 case AL_REFERENCE_DISTANCE:
1061 case AL_CONE_OUTER_GAINHF:
1062 case AL_AIR_ABSORPTION_FACTOR:
1063 case AL_ROOM_ROLLOFF_FACTOR:
1064 alGetSourcef(source, eParam, pflValues);
1065 return;
1067 case AL_POSITION:
1068 case AL_VELOCITY:
1069 case AL_DIRECTION:
1070 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1071 return;
1074 pContext = GetContextRef();
1075 if(!pContext) return;
1077 if(pflValues)
1079 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1081 switch(eParam)
1083 case AL_SAMPLE_RW_OFFSETS_SOFT:
1084 case AL_BYTE_RW_OFFSETS_SOFT:
1085 LockContext(pContext);
1086 updateLen = (ALdouble)pContext->Device->UpdateSize /
1087 pContext->Device->Frequency;
1088 GetSourceOffset(Source, eParam, Offsets, updateLen);
1089 UnlockContext(pContext);
1090 pflValues[0] = (ALfloat)Offsets[0];
1091 pflValues[1] = (ALfloat)Offsets[1];
1092 break;
1094 default:
1095 alSetError(pContext, AL_INVALID_ENUM);
1096 break;
1099 else
1100 alSetError(pContext, AL_INVALID_NAME);
1102 else
1103 alSetError(pContext, AL_INVALID_VALUE);
1105 ALCcontext_DecRef(pContext);
1109 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1111 ALbufferlistitem *BufferList;
1112 ALCcontext *pContext;
1113 ALsource *Source;
1114 ALdouble Offsets[2];
1115 ALdouble updateLen;
1117 pContext = GetContextRef();
1118 if(!pContext) return;
1120 if(plValue)
1122 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1124 switch(eParam)
1126 case AL_MAX_DISTANCE:
1127 *plValue = (ALint)Source->flMaxDistance;
1128 break;
1130 case AL_ROLLOFF_FACTOR:
1131 *plValue = (ALint)Source->flRollOffFactor;
1132 break;
1134 case AL_REFERENCE_DISTANCE:
1135 *plValue = (ALint)Source->flRefDistance;
1136 break;
1138 case AL_SOURCE_RELATIVE:
1139 *plValue = Source->bHeadRelative;
1140 break;
1142 case AL_CONE_INNER_ANGLE:
1143 *plValue = (ALint)Source->flInnerAngle;
1144 break;
1146 case AL_CONE_OUTER_ANGLE:
1147 *plValue = (ALint)Source->flOuterAngle;
1148 break;
1150 case AL_LOOPING:
1151 *plValue = Source->bLooping;
1152 break;
1154 case AL_BUFFER:
1155 LockContext(pContext);
1156 BufferList = Source->queue;
1157 if(Source->lSourceType != AL_STATIC)
1159 ALuint i = Source->BuffersPlayed;
1160 while(i > 0)
1162 BufferList = BufferList->next;
1163 i--;
1166 *plValue = ((BufferList && BufferList->buffer) ?
1167 BufferList->buffer->buffer : 0);
1168 UnlockContext(pContext);
1169 break;
1171 case AL_SOURCE_STATE:
1172 *plValue = Source->state;
1173 break;
1175 case AL_BUFFERS_QUEUED:
1176 *plValue = Source->BuffersInQueue;
1177 break;
1179 case AL_BUFFERS_PROCESSED:
1180 LockContext(pContext);
1181 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1183 /* Buffers on a looping source are in a perpetual state
1184 * of PENDING, so don't report any as PROCESSED */
1185 *plValue = 0;
1187 else
1188 *plValue = Source->BuffersPlayed;
1189 UnlockContext(pContext);
1190 break;
1192 case AL_SOURCE_TYPE:
1193 *plValue = Source->lSourceType;
1194 break;
1196 case AL_SEC_OFFSET:
1197 case AL_SAMPLE_OFFSET:
1198 case AL_BYTE_OFFSET:
1199 LockContext(pContext);
1200 updateLen = (ALdouble)pContext->Device->UpdateSize /
1201 pContext->Device->Frequency;
1202 GetSourceOffset(Source, eParam, Offsets, updateLen);
1203 UnlockContext(pContext);
1204 *plValue = (ALint)Offsets[0];
1205 break;
1207 case AL_DIRECT_FILTER_GAINHF_AUTO:
1208 *plValue = Source->DryGainHFAuto;
1209 break;
1211 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1212 *plValue = Source->WetGainAuto;
1213 break;
1215 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1216 *plValue = Source->WetGainHFAuto;
1217 break;
1219 case AL_DOPPLER_FACTOR:
1220 *plValue = (ALint)Source->DopplerFactor;
1221 break;
1223 case AL_VIRTUAL_CHANNELS_SOFT:
1224 *plValue = Source->VirtualChannels;
1225 break;
1227 case AL_DISTANCE_MODEL:
1228 *plValue = Source->DistanceModel;
1229 break;
1231 default:
1232 alSetError(pContext, AL_INVALID_ENUM);
1233 break;
1236 else
1237 alSetError(pContext, AL_INVALID_NAME);
1239 else
1240 alSetError(pContext, AL_INVALID_VALUE);
1242 ALCcontext_DecRef(pContext);
1246 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1248 ALCcontext *pContext;
1249 ALsource *Source;
1251 pContext = GetContextRef();
1252 if(!pContext) return;
1254 if(plValue1 && plValue2 && plValue3)
1256 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1258 switch(eParam)
1260 case AL_POSITION:
1261 LockContext(pContext);
1262 *plValue1 = (ALint)Source->vPosition[0];
1263 *plValue2 = (ALint)Source->vPosition[1];
1264 *plValue3 = (ALint)Source->vPosition[2];
1265 UnlockContext(pContext);
1266 break;
1268 case AL_VELOCITY:
1269 LockContext(pContext);
1270 *plValue1 = (ALint)Source->vVelocity[0];
1271 *plValue2 = (ALint)Source->vVelocity[1];
1272 *plValue3 = (ALint)Source->vVelocity[2];
1273 UnlockContext(pContext);
1274 break;
1276 case AL_DIRECTION:
1277 LockContext(pContext);
1278 *plValue1 = (ALint)Source->vOrientation[0];
1279 *plValue2 = (ALint)Source->vOrientation[1];
1280 *plValue3 = (ALint)Source->vOrientation[2];
1281 UnlockContext(pContext);
1282 break;
1284 default:
1285 alSetError(pContext, AL_INVALID_ENUM);
1286 break;
1289 else
1290 alSetError(pContext, AL_INVALID_NAME);
1292 else
1293 alSetError(pContext, AL_INVALID_VALUE);
1295 ALCcontext_DecRef(pContext);
1299 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1301 ALCcontext *pContext;
1302 ALsource *Source;
1303 ALdouble Offsets[2];
1304 ALdouble updateLen;
1306 switch(eParam)
1308 case AL_SOURCE_RELATIVE:
1309 case AL_CONE_INNER_ANGLE:
1310 case AL_CONE_OUTER_ANGLE:
1311 case AL_LOOPING:
1312 case AL_BUFFER:
1313 case AL_SOURCE_STATE:
1314 case AL_BUFFERS_QUEUED:
1315 case AL_BUFFERS_PROCESSED:
1316 case AL_SEC_OFFSET:
1317 case AL_SAMPLE_OFFSET:
1318 case AL_BYTE_OFFSET:
1319 case AL_MAX_DISTANCE:
1320 case AL_ROLLOFF_FACTOR:
1321 case AL_DOPPLER_FACTOR:
1322 case AL_REFERENCE_DISTANCE:
1323 case AL_SOURCE_TYPE:
1324 case AL_DIRECT_FILTER:
1325 case AL_DIRECT_FILTER_GAINHF_AUTO:
1326 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1327 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1328 case AL_DISTANCE_MODEL:
1329 case AL_VIRTUAL_CHANNELS_SOFT:
1330 alGetSourcei(source, eParam, plValues);
1331 return;
1333 case AL_POSITION:
1334 case AL_VELOCITY:
1335 case AL_DIRECTION:
1336 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1337 return;
1340 pContext = GetContextRef();
1341 if(!pContext) return;
1343 if(plValues)
1345 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1347 switch(eParam)
1349 case AL_SAMPLE_RW_OFFSETS_SOFT:
1350 case AL_BYTE_RW_OFFSETS_SOFT:
1351 LockContext(pContext);
1352 updateLen = (ALdouble)pContext->Device->UpdateSize /
1353 pContext->Device->Frequency;
1354 GetSourceOffset(Source, eParam, Offsets, updateLen);
1355 UnlockContext(pContext);
1356 plValues[0] = (ALint)Offsets[0];
1357 plValues[1] = (ALint)Offsets[1];
1358 break;
1360 default:
1361 alSetError(pContext, AL_INVALID_ENUM);
1362 break;
1365 else
1366 alSetError(pContext, AL_INVALID_NAME);
1368 else
1369 alSetError(pContext, AL_INVALID_VALUE);
1371 ALCcontext_DecRef(pContext);
1375 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1377 alSourcePlayv(1, &source);
1380 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1382 ALCcontext *Context;
1383 ALsource *Source;
1384 ALsizei i;
1386 Context = GetContextRef();
1387 if(!Context) return;
1389 if(n < 0)
1391 alSetError(Context, AL_INVALID_VALUE);
1392 goto done;
1394 if(n > 0 && !sources)
1396 alSetError(Context, AL_INVALID_VALUE);
1397 goto done;
1400 // Check that all the Sources are valid
1401 for(i = 0;i < n;i++)
1403 if(!LookupSource(Context->SourceMap, sources[i]))
1405 alSetError(Context, AL_INVALID_NAME);
1406 goto done;
1410 LockContext(Context);
1411 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1413 void *temp = NULL;
1414 ALsizei newcount;
1416 newcount = Context->MaxActiveSources << 1;
1417 if(newcount > 0)
1418 temp = realloc(Context->ActiveSources,
1419 sizeof(*Context->ActiveSources) * newcount);
1420 if(!temp)
1422 UnlockContext(Context);
1423 alSetError(Context, AL_OUT_OF_MEMORY);
1424 goto done;
1427 Context->ActiveSources = temp;
1428 Context->MaxActiveSources = newcount;
1431 for(i = 0;i < n;i++)
1433 Source = LookupSource(Context->SourceMap, sources[i]);
1434 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1435 else SetSourceState(Source, Context, AL_PLAYING);
1437 UnlockContext(Context);
1439 done:
1440 ALCcontext_DecRef(Context);
1443 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1445 alSourcePausev(1, &source);
1448 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1450 ALCcontext *Context;
1451 ALsource *Source;
1452 ALsizei i;
1454 Context = GetContextRef();
1455 if(!Context) return;
1457 if(n < 0)
1459 alSetError(Context, AL_INVALID_VALUE);
1460 goto done;
1462 if(n > 0 && !sources)
1464 alSetError(Context, AL_INVALID_VALUE);
1465 goto done;
1468 // Check all the Sources are valid
1469 for(i = 0;i < n;i++)
1471 if(!LookupSource(Context->SourceMap, sources[i]))
1473 alSetError(Context, AL_INVALID_NAME);
1474 goto done;
1478 LockContext(Context);
1479 for(i = 0;i < n;i++)
1481 Source = LookupSource(Context->SourceMap, sources[i]);
1482 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1483 else SetSourceState(Source, Context, AL_PAUSED);
1485 UnlockContext(Context);
1487 done:
1488 ALCcontext_DecRef(Context);
1491 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1493 alSourceStopv(1, &source);
1496 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1498 ALCcontext *Context;
1499 ALsource *Source;
1500 ALsizei i;
1502 Context = GetContextRef();
1503 if(!Context) return;
1505 if(n < 0)
1507 alSetError(Context, AL_INVALID_VALUE);
1508 goto done;
1510 if(n > 0 && !sources)
1512 alSetError(Context, AL_INVALID_VALUE);
1513 goto done;
1516 // Check all the Sources are valid
1517 for(i = 0;i < n;i++)
1519 if(!LookupSource(Context->SourceMap, sources[i]))
1521 alSetError(Context, AL_INVALID_NAME);
1522 goto done;
1526 LockContext(Context);
1527 for(i = 0;i < n;i++)
1529 Source = LookupSource(Context->SourceMap, sources[i]);
1530 Source->new_state = AL_NONE;
1531 SetSourceState(Source, Context, AL_STOPPED);
1533 UnlockContext(Context);
1535 done:
1536 ALCcontext_DecRef(Context);
1539 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1541 alSourceRewindv(1, &source);
1544 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1546 ALCcontext *Context;
1547 ALsource *Source;
1548 ALsizei i;
1550 Context = GetContextRef();
1551 if(!Context) return;
1553 if(n < 0)
1555 alSetError(Context, AL_INVALID_VALUE);
1556 goto done;
1558 if(n > 0 && !sources)
1560 alSetError(Context, AL_INVALID_VALUE);
1561 goto done;
1564 // Check all the Sources are valid
1565 for(i = 0;i < n;i++)
1567 if(!LookupSource(Context->SourceMap, sources[i]))
1569 alSetError(Context, AL_INVALID_NAME);
1570 goto done;
1574 LockContext(Context);
1575 for(i = 0;i < n;i++)
1577 Source = LookupSource(Context->SourceMap, sources[i]);
1578 Source->new_state = AL_NONE;
1579 SetSourceState(Source, Context, AL_INITIAL);
1581 UnlockContext(Context);
1583 done:
1584 ALCcontext_DecRef(Context);
1588 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1590 ALCcontext *Context;
1591 ALCdevice *device;
1592 ALsource *Source;
1593 ALsizei i;
1594 ALbufferlistitem *BufferListStart = NULL;
1595 ALbufferlistitem *BufferList;
1596 ALbuffer *BufferFmt;
1598 if(n == 0)
1599 return;
1601 Context = GetContextRef();
1602 if(!Context) return;
1604 if(n < 0)
1606 alSetError(Context, AL_INVALID_VALUE);
1607 goto error;
1610 // Check that all buffers are valid or zero and that the source is valid
1612 // Check that this is a valid source
1613 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1615 alSetError(Context, AL_INVALID_NAME);
1616 goto error;
1619 LockContext(Context);
1620 // Check that this is not a STATIC Source
1621 if(Source->lSourceType == AL_STATIC)
1623 UnlockContext(Context);
1624 // Invalid Source Type (can't queue on a Static Source)
1625 alSetError(Context, AL_INVALID_OPERATION);
1626 goto error;
1629 device = Context->Device;
1631 BufferFmt = NULL;
1633 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1634 BufferList = Source->queue;
1635 while(BufferList)
1637 if(BufferList->buffer)
1639 BufferFmt = BufferList->buffer;
1640 break;
1642 BufferList = BufferList->next;
1645 for(i = 0;i < n;i++)
1647 ALbuffer *buffer = NULL;
1648 if(buffers[i] && (buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1650 UnlockContext(Context);
1651 alSetError(Context, AL_INVALID_NAME);
1652 goto error;
1655 if(!BufferListStart)
1657 BufferListStart = malloc(sizeof(ALbufferlistitem));
1658 BufferListStart->buffer = buffer;
1659 BufferListStart->next = NULL;
1660 BufferListStart->prev = NULL;
1661 BufferList = BufferListStart;
1663 else
1665 BufferList->next = malloc(sizeof(ALbufferlistitem));
1666 BufferList->next->buffer = buffer;
1667 BufferList->next->next = NULL;
1668 BufferList->next->prev = BufferList;
1669 BufferList = BufferList->next;
1671 if(!buffer) continue;
1673 // Increment reference counter for buffer
1674 IncrementRef(&buffer->ref);
1675 ReadLock(&buffer->lock);
1676 if(BufferFmt == NULL)
1678 BufferFmt = buffer;
1680 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1681 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1682 if(buffer->FmtChannels == FmtMono)
1683 Source->Update = CalcSourceParams;
1684 else
1685 Source->Update = CalcNonAttnSourceParams;
1687 Source->NeedsUpdate = AL_TRUE;
1689 else if(BufferFmt->Frequency != buffer->Frequency ||
1690 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1691 BufferFmt->OriginalType != buffer->OriginalType)
1693 ReadUnlock(&buffer->lock);
1694 UnlockContext(Context);
1695 alSetError(Context, AL_INVALID_OPERATION);
1696 goto error;
1698 ReadUnlock(&buffer->lock);
1701 // Change Source Type
1702 Source->lSourceType = AL_STREAMING;
1704 if(Source->queue == NULL)
1705 Source->queue = BufferListStart;
1706 else
1708 // Find end of queue
1709 BufferList = Source->queue;
1710 while(BufferList->next != NULL)
1711 BufferList = BufferList->next;
1713 BufferListStart->prev = BufferList;
1714 BufferList->next = BufferListStart;
1717 // Update number of buffers in queue
1718 Source->BuffersInQueue += n;
1720 UnlockContext(Context);
1721 ALCcontext_DecRef(Context);
1722 return;
1724 error:
1725 while(BufferListStart)
1727 BufferList = BufferListStart;
1728 BufferListStart = BufferList->next;
1730 if(BufferList->buffer)
1731 DecrementRef(&BufferList->buffer->ref);
1732 free(BufferList);
1734 ALCcontext_DecRef(Context);
1738 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1739 // an array of buffer IDs that are to be filled with the names of the buffers removed
1740 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1742 ALCcontext *Context;
1743 ALsource *Source;
1744 ALsizei i;
1745 ALbufferlistitem *BufferList;
1747 if(n == 0)
1748 return;
1750 Context = GetContextRef();
1751 if(!Context) return;
1753 if(n < 0)
1755 alSetError(Context, AL_INVALID_VALUE);
1756 goto done;
1759 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1761 alSetError(Context, AL_INVALID_NAME);
1762 goto done;
1765 LockContext(Context);
1766 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1767 (ALuint)n > Source->BuffersPlayed)
1769 UnlockContext(Context);
1770 // Some buffers can't be unqueue because they have not been processed
1771 alSetError(Context, AL_INVALID_VALUE);
1772 goto done;
1775 for(i = 0;i < n;i++)
1777 BufferList = Source->queue;
1778 Source->queue = BufferList->next;
1779 Source->BuffersInQueue--;
1780 Source->BuffersPlayed--;
1782 if(BufferList->buffer)
1784 // Record name of buffer
1785 buffers[i] = BufferList->buffer->buffer;
1786 // Decrement buffer reference counter
1787 DecrementRef(&BufferList->buffer->ref);
1789 else
1790 buffers[i] = 0;
1792 // Release memory for buffer list item
1793 free(BufferList);
1795 if(Source->queue)
1796 Source->queue->prev = NULL;
1797 UnlockContext(Context);
1799 done:
1800 ALCcontext_DecRef(Context);
1804 static ALvoid InitSourceParams(ALsource *Source)
1806 ALuint i;
1808 Source->flInnerAngle = 360.0f;
1809 Source->flOuterAngle = 360.0f;
1810 Source->flPitch = 1.0f;
1811 Source->vPosition[0] = 0.0f;
1812 Source->vPosition[1] = 0.0f;
1813 Source->vPosition[2] = 0.0f;
1814 Source->vOrientation[0] = 0.0f;
1815 Source->vOrientation[1] = 0.0f;
1816 Source->vOrientation[2] = 0.0f;
1817 Source->vVelocity[0] = 0.0f;
1818 Source->vVelocity[1] = 0.0f;
1819 Source->vVelocity[2] = 0.0f;
1820 Source->flRefDistance = 1.0f;
1821 Source->flMaxDistance = FLT_MAX;
1822 Source->flRollOffFactor = 1.0f;
1823 Source->bLooping = AL_FALSE;
1824 Source->flGain = 1.0f;
1825 Source->flMinGain = 0.0f;
1826 Source->flMaxGain = 1.0f;
1827 Source->flOuterGain = 0.0f;
1828 Source->OuterGainHF = 1.0f;
1830 Source->DryGainHFAuto = AL_TRUE;
1831 Source->WetGainAuto = AL_TRUE;
1832 Source->WetGainHFAuto = AL_TRUE;
1833 Source->AirAbsorptionFactor = 0.0f;
1834 Source->RoomRolloffFactor = 0.0f;
1835 Source->DopplerFactor = 1.0f;
1836 Source->VirtualChannels = AL_TRUE;
1838 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1840 Source->Resampler = DefaultResampler;
1842 Source->state = AL_INITIAL;
1843 Source->new_state = AL_NONE;
1844 Source->lSourceType = AL_UNDETERMINED;
1845 Source->lOffset = -1;
1847 Source->DirectGain = 1.0f;
1848 Source->DirectGainHF = 1.0f;
1849 for(i = 0;i < MAX_SENDS;i++)
1851 Source->Send[i].WetGain = 1.0f;
1852 Source->Send[i].WetGainHF = 1.0f;
1855 Source->NeedsUpdate = AL_TRUE;
1857 Source->HrtfMoving = AL_FALSE;
1858 Source->HrtfCounter = 0;
1863 * SetSourceState
1865 * Sets the source's new play state given its current state
1867 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1869 if(state == AL_PLAYING)
1871 ALbufferlistitem *BufferList;
1872 ALsizei j, k;
1874 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
1875 BufferList = Source->queue;
1876 while(BufferList)
1878 if(BufferList->buffer != NULL && BufferList->buffer->size)
1879 break;
1880 BufferList = BufferList->next;
1883 /* If there's nothing to play, or device is disconnected, go right to
1884 * stopped */
1885 if(!BufferList || !Context->Device->Connected)
1887 SetSourceState(Source, Context, AL_STOPPED);
1888 return;
1891 if(Source->state != AL_PLAYING)
1893 for(j = 0;j < MAXCHANNELS;j++)
1895 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1896 Source->HrtfHistory[j][k] = 0.0f;
1897 for(k = 0;k < HRIR_LENGTH;k++)
1899 Source->HrtfValues[j][k][0] = 0.0f;
1900 Source->HrtfValues[j][k][1] = 0.0f;
1905 if(Source->state != AL_PAUSED)
1907 Source->state = AL_PLAYING;
1908 Source->position = 0;
1909 Source->position_fraction = 0;
1910 Source->BuffersPlayed = 0;
1912 else
1913 Source->state = AL_PLAYING;
1915 // Check if an Offset has been set
1916 if(Source->lOffset != -1)
1917 ApplyOffset(Source);
1919 for(j = 0;j < Context->ActiveSourceCount;j++)
1921 if(Context->ActiveSources[j] == Source)
1922 break;
1924 if(j == Context->ActiveSourceCount)
1925 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1927 else if(state == AL_PAUSED)
1929 if(Source->state == AL_PLAYING)
1931 Source->state = AL_PAUSED;
1932 Source->HrtfMoving = AL_FALSE;
1933 Source->HrtfCounter = 0;
1936 else if(state == AL_STOPPED)
1938 if(Source->state != AL_INITIAL)
1940 Source->state = AL_STOPPED;
1941 Source->BuffersPlayed = Source->BuffersInQueue;
1942 Source->HrtfMoving = AL_FALSE;
1943 Source->HrtfCounter = 0;
1945 Source->lOffset = -1;
1947 else if(state == AL_INITIAL)
1949 if(Source->state != AL_INITIAL)
1951 Source->state = AL_INITIAL;
1952 Source->position = 0;
1953 Source->position_fraction = 0;
1954 Source->BuffersPlayed = 0;
1955 Source->HrtfMoving = AL_FALSE;
1956 Source->HrtfCounter = 0;
1958 Source->lOffset = -1;
1963 GetSourceOffset
1965 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1966 The offset is relative to the start of the queue (not the start of the current buffer)
1968 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1970 const ALbufferlistitem *BufferList;
1971 const ALbuffer *Buffer = NULL;
1972 enum UserFmtType OriginalType;
1973 ALsizei BufferFreq;
1974 ALint Channels, Bytes;
1975 ALuint readPos, writePos;
1976 ALuint TotalBufferDataSize;
1977 ALuint i;
1979 // Find the first non-NULL Buffer in the Queue
1980 BufferList = Source->queue;
1981 while(BufferList)
1983 if(BufferList->buffer)
1985 Buffer = BufferList->buffer;
1986 break;
1988 BufferList = BufferList->next;
1991 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1993 offset[0] = 0.0;
1994 offset[1] = 0.0;
1995 return;
1998 // Get Current Buffer Size and frequency (in milliseconds)
1999 BufferFreq = Buffer->Frequency;
2000 OriginalType = Buffer->OriginalType;
2001 Channels = ChannelsFromFmt(Buffer->FmtChannels);
2002 Bytes = BytesFromFmt(Buffer->FmtType);
2004 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
2005 readPos = Source->position * Channels * Bytes;
2006 // Add byte length of any processed buffers in the queue
2007 TotalBufferDataSize = 0;
2008 BufferList = Source->queue;
2009 for(i = 0;BufferList;i++)
2011 if(BufferList->buffer)
2013 if(i < Source->BuffersPlayed)
2014 readPos += BufferList->buffer->size;
2015 TotalBufferDataSize += BufferList->buffer->size;
2017 BufferList = BufferList->next;
2019 if(Source->state == AL_PLAYING)
2020 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
2021 else
2022 writePos = readPos;
2024 if(Source->bLooping)
2026 readPos %= TotalBufferDataSize;
2027 writePos %= TotalBufferDataSize;
2029 else
2031 // Wrap positions back to 0
2032 if(readPos >= TotalBufferDataSize)
2033 readPos = 0;
2034 if(writePos >= TotalBufferDataSize)
2035 writePos = 0;
2038 switch(name)
2040 case AL_SEC_OFFSET:
2041 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
2042 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
2043 break;
2044 case AL_SAMPLE_OFFSET:
2045 case AL_SAMPLE_RW_OFFSETS_SOFT:
2046 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
2047 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
2048 break;
2049 case AL_BYTE_OFFSET:
2050 case AL_BYTE_RW_OFFSETS_SOFT:
2051 // Take into account the original format of the Buffer
2052 if(OriginalType == UserFmtIMA4)
2054 ALuint FrameBlockSize = 65 * Bytes * Channels;
2055 ALuint BlockSize = 36 * Channels;
2057 // Round down to nearest ADPCM block
2058 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2059 if(Source->state != AL_PLAYING)
2060 offset[1] = offset[0];
2061 else
2063 // Round up to nearest ADPCM block
2064 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2065 FrameBlockSize * BlockSize);
2068 else
2070 ALuint OrigBytes = BytesFromUserFmt(OriginalType);
2071 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
2072 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
2074 break;
2080 ApplyOffset
2082 Apply a playback offset to the Source. This function will update the queue (to correctly
2083 mark buffers as 'pending' or 'processed' depending upon the new offset.
2085 ALboolean ApplyOffset(ALsource *Source)
2087 const ALbufferlistitem *BufferList;
2088 const ALbuffer *Buffer;
2089 ALint lBufferSize, lTotalBufferSize;
2090 ALint BuffersPlayed;
2091 ALint lByteOffset;
2093 // Get true byte offset
2094 lByteOffset = GetByteOffset(Source);
2096 // If the offset is invalid, don't apply it
2097 if(lByteOffset == -1)
2098 return AL_FALSE;
2100 // Sort out the queue (pending and processed states)
2101 BufferList = Source->queue;
2102 lTotalBufferSize = 0;
2103 BuffersPlayed = 0;
2105 while(BufferList)
2107 Buffer = BufferList->buffer;
2108 lBufferSize = Buffer ? Buffer->size : 0;
2110 if(lBufferSize <= lByteOffset-lTotalBufferSize)
2112 // Offset is past this buffer so increment BuffersPlayed
2113 BuffersPlayed++;
2115 else if(lTotalBufferSize <= lByteOffset)
2117 // Offset is within this buffer
2118 Source->BuffersPlayed = BuffersPlayed;
2120 // SW Mixer Positions are in Samples
2121 Source->position = (lByteOffset - lTotalBufferSize) /
2122 FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2123 return AL_TRUE;
2126 // Increment the TotalBufferSize
2127 lTotalBufferSize += lBufferSize;
2129 // Move on to next buffer in the Queue
2130 BufferList = BufferList->next;
2132 // Offset is out of range of the buffer queue
2133 return AL_FALSE;
2138 GetByteOffset
2140 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2141 offset supplied by the application). This takes into account the fact that the buffer format
2142 may have been modifed by AL (e.g 8bit samples are converted to float)
2144 static ALint GetByteOffset(ALsource *Source)
2146 const ALbuffer *Buffer = NULL;
2147 const ALbufferlistitem *BufferList;
2148 ALint ByteOffset = -1;
2150 // Find the first non-NULL Buffer in the Queue
2151 BufferList = Source->queue;
2152 while(BufferList)
2154 if(BufferList->buffer)
2156 Buffer = BufferList->buffer;
2157 break;
2159 BufferList = BufferList->next;
2162 if(!Buffer)
2164 Source->lOffset = -1;
2165 return -1;
2168 // Determine the ByteOffset (and ensure it is block aligned)
2169 switch(Source->lOffsetType)
2171 case AL_BYTE_OFFSET:
2172 // Take into consideration the original format
2173 ByteOffset = Source->lOffset;
2174 if(Buffer->OriginalType == UserFmtIMA4)
2176 // Round down to nearest ADPCM block
2177 ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2178 // Multiply by compression rate (65 sample frames per block)
2179 ByteOffset *= 65;
2181 else
2182 ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2183 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2184 break;
2186 case AL_SAMPLE_OFFSET:
2187 ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2188 break;
2190 case AL_SEC_OFFSET:
2191 // Note - lOffset is internally stored as Milliseconds
2192 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2193 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2194 break;
2196 // Clear Offset
2197 Source->lOffset = -1;
2199 return ByteOffset;
2203 ALvoid ReleaseALSources(ALCcontext *Context)
2205 ALsizei pos;
2206 ALuint j;
2207 for(pos = 0;pos < Context->SourceMap.size;pos++)
2209 ALsource *temp = Context->SourceMap.array[pos].value;
2210 Context->SourceMap.array[pos].value = NULL;
2212 // For each buffer in the source's queue, decrement its reference counter and remove it
2213 while(temp->queue != NULL)
2215 ALbufferlistitem *BufferList = temp->queue;
2216 temp->queue = BufferList->next;
2218 if(BufferList->buffer != NULL)
2219 DecrementRef(&BufferList->buffer->ref);
2220 free(BufferList);
2223 for(j = 0;j < MAX_SENDS;++j)
2225 if(temp->Send[j].Slot)
2226 DecrementRef(&temp->Send[j].Slot->ref);
2227 temp->Send[j].Slot = NULL;
2230 // Release source structure
2231 FreeThunkEntry(temp->source);
2232 memset(temp, 0, sizeof(ALsource));
2233 free(temp);