Removed project files that are generated by "android update project" step.
[openal-soft/android.git] / OpenAL32 / alSource.c
blob5d7cecedecdc930c864bfa0523ac9bc465506bc2
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *Source);
36 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
37 static ALboolean ApplyOffset(ALsource *Source);
38 static ALint GetByteOffset(ALsource *Source);
39 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels);
41 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
42 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
43 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
44 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
46 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
48 ALCcontext *Context;
49 ALCdevice *Device;
50 ALsizei i=0;
52 Context = GetContextSuspended();
53 if(!Context) return;
55 if(n > 0)
57 Device = Context->Device;
59 // Check that enough memory has been allocted in the 'sources' array for n Sources
60 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
62 // Check that the requested number of sources can be generated
63 if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources)
65 ALenum err;
67 // Add additional sources to the list
68 while(i < n)
70 ALsource *source = calloc(1, sizeof(ALsource));
71 if(!source)
73 alSetError(Context, AL_OUT_OF_MEMORY);
74 alDeleteSources(i, sources);
75 break;
78 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
79 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
80 source);
81 if(err != AL_NO_ERROR)
83 ALTHUNK_REMOVEENTRY(source->source);
84 memset(source, 0, sizeof(ALsource));
85 free(source);
87 alSetError(Context, err);
88 alDeleteSources(i, sources);
89 break;
92 sources[i++] = source->source;
93 InitSourceParams(source);
96 else
98 // Not enough resources to create the Sources
99 alSetError(Context, AL_INVALID_VALUE);
102 else
104 // Bad pointer
105 alSetError(Context, AL_INVALID_VALUE);
109 ProcessContext(Context);
113 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
115 ALCcontext *Context;
116 ALCdevice *Device;
117 ALsource *Source;
118 ALsizei i, j;
119 ALbufferlistitem *BufferList;
120 ALboolean bSourcesValid = AL_TRUE;
122 Context = GetContextSuspended();
123 if(!Context) return;
125 if(n >= 0)
127 Device = Context->Device;
129 // Check that all Sources are valid (and can therefore be deleted)
130 for (i = 0; i < n; i++)
132 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
134 alSetError(Context, AL_INVALID_NAME);
135 bSourcesValid = AL_FALSE;
136 break;
140 if(bSourcesValid)
142 // All Sources are valid, and can be deleted
143 for(i = 0; i < n; i++)
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL)
148 for(j = 0;j < Context->ActiveSourceCount;j++)
150 if(Context->ActiveSources[j] == Source)
152 ALsizei end = --(Context->ActiveSourceCount);
153 Context->ActiveSources[j] = Context->ActiveSources[end];
154 break;
158 // For each buffer in the source's queue, decrement its reference counter and remove it
159 while(Source->queue != NULL)
161 BufferList = Source->queue;
162 // Decrement buffer's reference counter
163 if(BufferList->buffer != NULL)
164 BufferList->buffer->refcount--;
165 // Update queue to point to next element in list
166 Source->queue = BufferList->next;
167 // Release memory allocated for buffer list item
168 free(BufferList);
171 for(j = 0;j < MAX_SENDS;++j)
173 if(Source->Send[j].Slot)
174 Source->Send[j].Slot->refcount--;
175 Source->Send[j].Slot = NULL;
178 // Remove Source from list of Sources
179 RemoveUIntMapKey(&Context->SourceMap, Source->source);
180 ALTHUNK_REMOVEENTRY(Source->source);
182 memset(Source,0,sizeof(ALsource));
183 free(Source);
188 else
189 alSetError(Context, AL_INVALID_VALUE);
191 ProcessContext(Context);
195 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
197 ALCcontext *Context;
198 ALboolean result;
200 Context = GetContextSuspended();
201 if(!Context) return AL_FALSE;
203 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
205 ProcessContext(Context);
207 return result;
211 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
213 ALCcontext *pContext;
214 ALsource *Source;
216 pContext = GetContextSuspended();
217 if(!pContext) return;
219 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
221 switch(eParam)
223 case AL_PITCH:
224 if(flValue >= 0.0f)
226 Source->flPitch = flValue;
227 if(Source->flPitch < 0.001f)
228 Source->flPitch = 0.001f;
229 Source->NeedsUpdate = AL_TRUE;
231 else
232 alSetError(pContext, AL_INVALID_VALUE);
233 break;
235 case AL_CONE_INNER_ANGLE:
236 if(flValue >= 0.0f && flValue <= 360.0f)
238 Source->flInnerAngle = flValue;
239 Source->NeedsUpdate = AL_TRUE;
241 else
242 alSetError(pContext, AL_INVALID_VALUE);
243 break;
245 case AL_CONE_OUTER_ANGLE:
246 if(flValue >= 0.0f && flValue <= 360.0f)
248 Source->flOuterAngle = flValue;
249 Source->NeedsUpdate = AL_TRUE;
251 else
252 alSetError(pContext, AL_INVALID_VALUE);
253 break;
255 case AL_GAIN:
256 if(flValue >= 0.0f)
258 Source->flGain = flValue;
259 Source->NeedsUpdate = AL_TRUE;
261 else
262 alSetError(pContext, AL_INVALID_VALUE);
263 break;
265 case AL_MAX_DISTANCE:
266 if(flValue >= 0.0f)
268 Source->flMaxDistance = flValue;
269 Source->NeedsUpdate = AL_TRUE;
271 else
272 alSetError(pContext, AL_INVALID_VALUE);
273 break;
275 case AL_ROLLOFF_FACTOR:
276 if(flValue >= 0.0f)
278 Source->flRollOffFactor = flValue;
279 Source->NeedsUpdate = AL_TRUE;
281 else
282 alSetError(pContext, AL_INVALID_VALUE);
283 break;
285 case AL_REFERENCE_DISTANCE:
286 if(flValue >= 0.0f)
288 Source->flRefDistance = flValue;
289 Source->NeedsUpdate = AL_TRUE;
291 else
292 alSetError(pContext, AL_INVALID_VALUE);
293 break;
295 case AL_MIN_GAIN:
296 if(flValue >= 0.0f && flValue <= 1.0f)
298 Source->flMinGain = flValue;
299 Source->NeedsUpdate = AL_TRUE;
301 else
302 alSetError(pContext, AL_INVALID_VALUE);
303 break;
305 case AL_MAX_GAIN:
306 if(flValue >= 0.0f && flValue <= 1.0f)
308 Source->flMaxGain = flValue;
309 Source->NeedsUpdate = AL_TRUE;
311 else
312 alSetError(pContext, AL_INVALID_VALUE);
313 break;
315 case AL_CONE_OUTER_GAIN:
316 if(flValue >= 0.0f && flValue <= 1.0f)
318 Source->flOuterGain = flValue;
319 Source->NeedsUpdate = AL_TRUE;
321 else
322 alSetError(pContext, AL_INVALID_VALUE);
323 break;
325 case AL_CONE_OUTER_GAINHF:
326 if(flValue >= 0.0f && flValue <= 1.0f)
328 Source->OuterGainHF = flValue;
329 Source->NeedsUpdate = AL_TRUE;
331 else
332 alSetError(pContext, AL_INVALID_VALUE);
333 break;
335 case AL_AIR_ABSORPTION_FACTOR:
336 if(flValue >= 0.0f && flValue <= 10.0f)
338 Source->AirAbsorptionFactor = flValue;
339 Source->NeedsUpdate = AL_TRUE;
341 else
342 alSetError(pContext, AL_INVALID_VALUE);
343 break;
345 case AL_ROOM_ROLLOFF_FACTOR:
346 if(flValue >= 0.0f && flValue <= 10.0f)
348 Source->RoomRolloffFactor = flValue;
349 Source->NeedsUpdate = AL_TRUE;
351 else
352 alSetError(pContext, AL_INVALID_VALUE);
353 break;
355 case AL_DOPPLER_FACTOR:
356 if(flValue >= 0.0f && flValue <= 1.0f)
358 Source->DopplerFactor = flValue;
359 Source->NeedsUpdate = AL_TRUE;
361 else
362 alSetError(pContext, AL_INVALID_VALUE);
363 break;
365 case AL_SEC_OFFSET:
366 case AL_SAMPLE_OFFSET:
367 case AL_BYTE_OFFSET:
368 if(flValue >= 0.0f)
370 Source->lOffsetType = eParam;
372 // Store Offset (convert Seconds into Milliseconds)
373 if(eParam == AL_SEC_OFFSET)
374 Source->lOffset = (ALint)(flValue * 1000.0f);
375 else
376 Source->lOffset = (ALint)flValue;
378 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
380 if(ApplyOffset(Source) == AL_FALSE)
381 alSetError(pContext, AL_INVALID_VALUE);
384 else
385 alSetError(pContext, AL_INVALID_VALUE);
386 break;
388 default:
389 alSetError(pContext, AL_INVALID_ENUM);
390 break;
393 else
395 // Invalid Source Name
396 alSetError(pContext, AL_INVALID_NAME);
399 ProcessContext(pContext);
403 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
405 ALCcontext *pContext;
406 ALsource *Source;
408 pContext = GetContextSuspended();
409 if(!pContext) return;
411 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
413 switch(eParam)
415 case AL_POSITION:
416 Source->vPosition[0] = flValue1;
417 Source->vPosition[1] = flValue2;
418 Source->vPosition[2] = flValue3;
419 Source->NeedsUpdate = AL_TRUE;
420 break;
422 case AL_VELOCITY:
423 Source->vVelocity[0] = flValue1;
424 Source->vVelocity[1] = flValue2;
425 Source->vVelocity[2] = flValue3;
426 Source->NeedsUpdate = AL_TRUE;
427 break;
429 case AL_DIRECTION:
430 Source->vOrientation[0] = flValue1;
431 Source->vOrientation[1] = flValue2;
432 Source->vOrientation[2] = flValue3;
433 Source->NeedsUpdate = AL_TRUE;
434 break;
436 default:
437 alSetError(pContext, AL_INVALID_ENUM);
438 break;
441 else
442 alSetError(pContext, AL_INVALID_NAME);
444 ProcessContext(pContext);
448 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
450 ALCcontext *pContext;
452 pContext = GetContextSuspended();
453 if(!pContext) return;
455 if(pflValues)
457 if(LookupSource(pContext->SourceMap, source) != NULL)
459 switch(eParam)
461 case AL_PITCH:
462 case AL_CONE_INNER_ANGLE:
463 case AL_CONE_OUTER_ANGLE:
464 case AL_GAIN:
465 case AL_MAX_DISTANCE:
466 case AL_ROLLOFF_FACTOR:
467 case AL_REFERENCE_DISTANCE:
468 case AL_MIN_GAIN:
469 case AL_MAX_GAIN:
470 case AL_CONE_OUTER_GAIN:
471 case AL_CONE_OUTER_GAINHF:
472 case AL_SEC_OFFSET:
473 case AL_SAMPLE_OFFSET:
474 case AL_BYTE_OFFSET:
475 case AL_AIR_ABSORPTION_FACTOR:
476 case AL_ROOM_ROLLOFF_FACTOR:
477 alSourcef(source, eParam, pflValues[0]);
478 break;
480 case AL_POSITION:
481 case AL_VELOCITY:
482 case AL_DIRECTION:
483 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
484 break;
486 default:
487 alSetError(pContext, AL_INVALID_ENUM);
488 break;
491 else
492 alSetError(pContext, AL_INVALID_NAME);
494 else
495 alSetError(pContext, AL_INVALID_VALUE);
497 ProcessContext(pContext);
501 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
503 ALCcontext *pContext;
504 ALsource *Source;
505 ALbufferlistitem *BufferListItem;
507 pContext = GetContextSuspended();
508 if(!pContext) return;
510 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
512 ALCdevice *device = pContext->Device;
514 switch(eParam)
516 case AL_MAX_DISTANCE:
517 case AL_ROLLOFF_FACTOR:
518 case AL_CONE_INNER_ANGLE:
519 case AL_CONE_OUTER_ANGLE:
520 case AL_REFERENCE_DISTANCE:
521 alSourcef(source, eParam, (ALfloat)lValue);
522 break;
524 case AL_SOURCE_RELATIVE:
525 if(lValue == AL_FALSE || lValue == AL_TRUE)
527 Source->bHeadRelative = (ALboolean)lValue;
528 Source->NeedsUpdate = AL_TRUE;
530 else
531 alSetError(pContext, AL_INVALID_VALUE);
532 break;
534 case AL_LOOPING:
535 if(lValue == AL_FALSE || lValue == AL_TRUE)
536 Source->bLooping = (ALboolean)lValue;
537 else
538 alSetError(pContext, AL_INVALID_VALUE);
539 break;
541 case AL_BUFFER:
542 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
544 ALbuffer *buffer = NULL;
546 if(lValue == 0 ||
547 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
549 // Remove all elements in the queue
550 while(Source->queue != NULL)
552 BufferListItem = Source->queue;
553 Source->queue = BufferListItem->next;
554 // Decrement reference counter for buffer
555 if(BufferListItem->buffer)
556 BufferListItem->buffer->refcount--;
557 // Release memory for buffer list item
558 free(BufferListItem);
559 // Decrement the number of buffers in the queue
560 Source->BuffersInQueue--;
563 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
564 if(lValue != 0)
566 // Source is now in STATIC mode
567 Source->lSourceType = AL_STATIC;
569 // Add the selected buffer to the queue
570 BufferListItem = malloc(sizeof(ALbufferlistitem));
571 BufferListItem->buffer = buffer;
572 BufferListItem->next = NULL;
574 Source->queue = BufferListItem;
575 Source->BuffersInQueue = 1;
577 // Increment reference counter for buffer
578 buffer->refcount++;
580 else
582 // Source is now in UNDETERMINED mode
583 Source->lSourceType = AL_UNDETERMINED;
585 Source->BuffersPlayed = 0;
587 // Update AL_BUFFER parameter
588 Source->Buffer = buffer;
589 Source->NeedsUpdate = AL_TRUE;
591 else
592 alSetError(pContext, AL_INVALID_VALUE);
594 else
595 alSetError(pContext, AL_INVALID_OPERATION);
596 break;
598 case AL_SOURCE_STATE:
599 // Query only
600 alSetError(pContext, AL_INVALID_OPERATION);
601 break;
603 case AL_SEC_OFFSET:
604 case AL_SAMPLE_OFFSET:
605 case AL_BYTE_OFFSET:
606 if(lValue >= 0)
608 Source->lOffsetType = eParam;
610 // Store Offset (convert Seconds into Milliseconds)
611 if(eParam == AL_SEC_OFFSET)
612 Source->lOffset = lValue * 1000;
613 else
614 Source->lOffset = lValue;
616 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
618 if(ApplyOffset(Source) == AL_FALSE)
619 alSetError(pContext, AL_INVALID_VALUE);
622 else
623 alSetError(pContext, AL_INVALID_VALUE);
624 break;
626 case AL_DIRECT_FILTER: {
627 ALfilter *filter = NULL;
629 if(lValue == 0 ||
630 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
632 if(!filter)
634 Source->DirectFilter.type = AL_FILTER_NULL;
635 Source->DirectFilter.filter = 0;
637 else
638 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
639 Source->NeedsUpdate = AL_TRUE;
641 else
642 alSetError(pContext, AL_INVALID_VALUE);
643 } break;
645 case AL_DIRECT_FILTER_GAINHF_AUTO:
646 if(lValue == AL_TRUE || lValue == AL_FALSE)
648 Source->DryGainHFAuto = lValue;
649 Source->NeedsUpdate = AL_TRUE;
651 else
652 alSetError(pContext, AL_INVALID_VALUE);
653 break;
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
656 if(lValue == AL_TRUE || lValue == AL_FALSE)
658 Source->WetGainAuto = lValue;
659 Source->NeedsUpdate = AL_TRUE;
661 else
662 alSetError(pContext, AL_INVALID_VALUE);
663 break;
665 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
666 if(lValue == AL_TRUE || lValue == AL_FALSE)
668 Source->WetGainHFAuto = lValue;
669 Source->NeedsUpdate = AL_TRUE;
671 else
672 alSetError(pContext, AL_INVALID_VALUE);
673 break;
675 case AL_DISTANCE_MODEL:
676 if(lValue == AL_NONE ||
677 lValue == AL_INVERSE_DISTANCE ||
678 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
679 lValue == AL_LINEAR_DISTANCE ||
680 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
681 lValue == AL_EXPONENT_DISTANCE ||
682 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
684 Source->DistanceModel = lValue;
685 if(pContext->SourceDistanceModel)
686 Source->NeedsUpdate = AL_TRUE;
688 else
689 alSetError(pContext, AL_INVALID_VALUE);
690 break;
692 default:
693 alSetError(pContext, AL_INVALID_ENUM);
694 break;
697 else
698 alSetError(pContext, AL_INVALID_NAME);
700 ProcessContext(pContext);
704 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
706 ALCcontext *pContext;
707 ALsource *Source;
709 pContext = GetContextSuspended();
710 if(!pContext) return;
712 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
714 ALCdevice *device = pContext->Device;
716 switch (eParam)
718 case AL_POSITION:
719 case AL_VELOCITY:
720 case AL_DIRECTION:
721 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
722 break;
724 case AL_AUXILIARY_SEND_FILTER: {
725 ALeffectslot *ALEffectSlot = NULL;
726 ALfilter *ALFilter = NULL;
728 if((ALuint)lValue2 < device->NumAuxSends &&
729 (lValue1 == 0 ||
730 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
731 (lValue3 == 0 ||
732 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
734 /* Release refcount on the previous slot, and add one for
735 * the new slot */
736 if(Source->Send[lValue2].Slot)
737 Source->Send[lValue2].Slot->refcount--;
738 Source->Send[lValue2].Slot = ALEffectSlot;
739 if(Source->Send[lValue2].Slot)
740 Source->Send[lValue2].Slot->refcount++;
742 if(!ALFilter)
744 /* Disable filter */
745 Source->Send[lValue2].WetFilter.type = 0;
746 Source->Send[lValue2].WetFilter.filter = 0;
748 else
749 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
750 Source->NeedsUpdate = AL_TRUE;
752 else
753 alSetError(pContext, AL_INVALID_VALUE);
754 } break;
756 default:
757 alSetError(pContext, AL_INVALID_ENUM);
758 break;
761 else
762 alSetError(pContext, AL_INVALID_NAME);
764 ProcessContext(pContext);
768 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
770 ALCcontext *pContext;
772 pContext = GetContextSuspended();
773 if(!pContext) return;
775 if(plValues)
777 if(LookupSource(pContext->SourceMap, source) != NULL)
779 switch(eParam)
781 case AL_SOURCE_RELATIVE:
782 case AL_CONE_INNER_ANGLE:
783 case AL_CONE_OUTER_ANGLE:
784 case AL_LOOPING:
785 case AL_BUFFER:
786 case AL_SOURCE_STATE:
787 case AL_SEC_OFFSET:
788 case AL_SAMPLE_OFFSET:
789 case AL_BYTE_OFFSET:
790 case AL_MAX_DISTANCE:
791 case AL_ROLLOFF_FACTOR:
792 case AL_REFERENCE_DISTANCE:
793 case AL_DIRECT_FILTER:
794 case AL_DIRECT_FILTER_GAINHF_AUTO:
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
796 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
797 case AL_DISTANCE_MODEL:
798 alSourcei(source, eParam, plValues[0]);
799 break;
801 case AL_POSITION:
802 case AL_VELOCITY:
803 case AL_DIRECTION:
804 case AL_AUXILIARY_SEND_FILTER:
805 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
806 break;
808 default:
809 alSetError(pContext, AL_INVALID_ENUM);
810 break;
813 else
814 alSetError(pContext, AL_INVALID_NAME);
816 else
817 alSetError(pContext, AL_INVALID_VALUE);
819 ProcessContext(pContext);
823 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
825 ALCcontext *pContext;
826 ALsource *Source;
827 ALdouble Offsets[2];
828 ALdouble updateLen;
830 pContext = GetContextSuspended();
831 if(!pContext) return;
833 if(pflValue)
835 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
837 switch(eParam)
839 case AL_PITCH:
840 *pflValue = Source->flPitch;
841 break;
843 case AL_GAIN:
844 *pflValue = Source->flGain;
845 break;
847 case AL_MIN_GAIN:
848 *pflValue = Source->flMinGain;
849 break;
851 case AL_MAX_GAIN:
852 *pflValue = Source->flMaxGain;
853 break;
855 case AL_MAX_DISTANCE:
856 *pflValue = Source->flMaxDistance;
857 break;
859 case AL_ROLLOFF_FACTOR:
860 *pflValue = Source->flRollOffFactor;
861 break;
863 case AL_CONE_OUTER_GAIN:
864 *pflValue = Source->flOuterGain;
865 break;
867 case AL_CONE_OUTER_GAINHF:
868 *pflValue = Source->OuterGainHF;
869 break;
871 case AL_SEC_OFFSET:
872 case AL_SAMPLE_OFFSET:
873 case AL_BYTE_OFFSET:
874 updateLen = (ALdouble)pContext->Device->UpdateSize /
875 pContext->Device->Frequency;
876 GetSourceOffset(Source, eParam, Offsets, updateLen);
877 *pflValue = Offsets[0];
878 break;
880 case AL_CONE_INNER_ANGLE:
881 *pflValue = Source->flInnerAngle;
882 break;
884 case AL_CONE_OUTER_ANGLE:
885 *pflValue = Source->flOuterAngle;
886 break;
888 case AL_REFERENCE_DISTANCE:
889 *pflValue = Source->flRefDistance;
890 break;
892 case AL_AIR_ABSORPTION_FACTOR:
893 *pflValue = Source->AirAbsorptionFactor;
894 break;
896 case AL_ROOM_ROLLOFF_FACTOR:
897 *pflValue = Source->RoomRolloffFactor;
898 break;
900 case AL_DOPPLER_FACTOR:
901 *pflValue = Source->DopplerFactor;
902 break;
904 default:
905 alSetError(pContext, AL_INVALID_ENUM);
906 break;
909 else
910 alSetError(pContext, AL_INVALID_NAME);
912 else
913 alSetError(pContext, AL_INVALID_VALUE);
915 ProcessContext(pContext);
919 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
921 ALCcontext *pContext;
922 ALsource *Source;
924 pContext = GetContextSuspended();
925 if(!pContext) return;
927 if(pflValue1 && pflValue2 && pflValue3)
929 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
931 switch(eParam)
933 case AL_POSITION:
934 *pflValue1 = Source->vPosition[0];
935 *pflValue2 = Source->vPosition[1];
936 *pflValue3 = Source->vPosition[2];
937 break;
939 case AL_VELOCITY:
940 *pflValue1 = Source->vVelocity[0];
941 *pflValue2 = Source->vVelocity[1];
942 *pflValue3 = Source->vVelocity[2];
943 break;
945 case AL_DIRECTION:
946 *pflValue1 = Source->vOrientation[0];
947 *pflValue2 = Source->vOrientation[1];
948 *pflValue3 = Source->vOrientation[2];
949 break;
951 default:
952 alSetError(pContext, AL_INVALID_ENUM);
953 break;
956 else
957 alSetError(pContext, AL_INVALID_NAME);
959 else
960 alSetError(pContext, AL_INVALID_VALUE);
962 ProcessContext(pContext);
966 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
968 ALCcontext *pContext;
969 ALsource *Source;
970 ALdouble Offsets[2];
971 ALdouble updateLen;
973 pContext = GetContextSuspended();
974 if(!pContext) return;
976 if(pflValues)
978 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
980 switch(eParam)
982 case AL_PITCH:
983 case AL_GAIN:
984 case AL_MIN_GAIN:
985 case AL_MAX_GAIN:
986 case AL_MAX_DISTANCE:
987 case AL_ROLLOFF_FACTOR:
988 case AL_DOPPLER_FACTOR:
989 case AL_CONE_OUTER_GAIN:
990 case AL_SEC_OFFSET:
991 case AL_SAMPLE_OFFSET:
992 case AL_BYTE_OFFSET:
993 case AL_CONE_INNER_ANGLE:
994 case AL_CONE_OUTER_ANGLE:
995 case AL_REFERENCE_DISTANCE:
996 case AL_CONE_OUTER_GAINHF:
997 case AL_AIR_ABSORPTION_FACTOR:
998 case AL_ROOM_ROLLOFF_FACTOR:
999 alGetSourcef(source, eParam, pflValues);
1000 break;
1002 case AL_SAMPLE_RW_OFFSETS_EXT:
1003 case AL_BYTE_RW_OFFSETS_EXT:
1004 updateLen = (ALdouble)pContext->Device->UpdateSize /
1005 pContext->Device->Frequency;
1006 GetSourceOffset(Source, eParam, Offsets, updateLen);
1007 pflValues[0] = Offsets[0];
1008 pflValues[1] = Offsets[1];
1009 break;
1011 case AL_POSITION:
1012 pflValues[0] = Source->vPosition[0];
1013 pflValues[1] = Source->vPosition[1];
1014 pflValues[2] = Source->vPosition[2];
1015 break;
1017 case AL_VELOCITY:
1018 pflValues[0] = Source->vVelocity[0];
1019 pflValues[1] = Source->vVelocity[1];
1020 pflValues[2] = Source->vVelocity[2];
1021 break;
1023 case AL_DIRECTION:
1024 pflValues[0] = Source->vOrientation[0];
1025 pflValues[1] = Source->vOrientation[1];
1026 pflValues[2] = Source->vOrientation[2];
1027 break;
1029 default:
1030 alSetError(pContext, AL_INVALID_ENUM);
1031 break;
1034 else
1035 alSetError(pContext, AL_INVALID_NAME);
1037 else
1038 alSetError(pContext, AL_INVALID_VALUE);
1040 ProcessContext(pContext);
1044 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1046 ALCcontext *pContext;
1047 ALsource *Source;
1048 ALdouble Offsets[2];
1049 ALdouble updateLen;
1051 pContext = GetContextSuspended();
1052 if(!pContext) return;
1054 if(plValue)
1056 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1058 switch(eParam)
1060 case AL_MAX_DISTANCE:
1061 *plValue = (ALint)Source->flMaxDistance;
1062 break;
1064 case AL_ROLLOFF_FACTOR:
1065 *plValue = (ALint)Source->flRollOffFactor;
1066 break;
1068 case AL_REFERENCE_DISTANCE:
1069 *plValue = (ALint)Source->flRefDistance;
1070 break;
1072 case AL_SOURCE_RELATIVE:
1073 *plValue = Source->bHeadRelative;
1074 break;
1076 case AL_CONE_INNER_ANGLE:
1077 *plValue = (ALint)Source->flInnerAngle;
1078 break;
1080 case AL_CONE_OUTER_ANGLE:
1081 *plValue = (ALint)Source->flOuterAngle;
1082 break;
1084 case AL_LOOPING:
1085 *plValue = Source->bLooping;
1086 break;
1088 case AL_BUFFER:
1089 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1090 break;
1092 case AL_SOURCE_STATE:
1093 *plValue = Source->state;
1094 break;
1096 case AL_BUFFERS_QUEUED:
1097 *plValue = Source->BuffersInQueue;
1098 break;
1100 case AL_BUFFERS_PROCESSED:
1101 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1103 /* Buffers on a looping source are in a perpetual state
1104 * of PENDING, so don't report any as PROCESSED */
1105 *plValue = 0;
1107 else
1108 *plValue = Source->BuffersPlayed;
1109 break;
1111 case AL_SOURCE_TYPE:
1112 *plValue = Source->lSourceType;
1113 break;
1115 case AL_SEC_OFFSET:
1116 case AL_SAMPLE_OFFSET:
1117 case AL_BYTE_OFFSET:
1118 updateLen = (ALdouble)pContext->Device->UpdateSize /
1119 pContext->Device->Frequency;
1120 GetSourceOffset(Source, eParam, Offsets, updateLen);
1121 *plValue = (ALint)Offsets[0];
1122 break;
1124 case AL_DIRECT_FILTER:
1125 *plValue = Source->DirectFilter.filter;
1126 break;
1128 case AL_DIRECT_FILTER_GAINHF_AUTO:
1129 *plValue = Source->DryGainHFAuto;
1130 break;
1132 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1133 *plValue = Source->WetGainAuto;
1134 break;
1136 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1137 *plValue = Source->WetGainHFAuto;
1138 break;
1140 case AL_DOPPLER_FACTOR:
1141 *plValue = (ALint)Source->DopplerFactor;
1142 break;
1144 case AL_DISTANCE_MODEL:
1145 *plValue = Source->DistanceModel;
1146 break;
1148 default:
1149 alSetError(pContext, AL_INVALID_ENUM);
1150 break;
1153 else
1154 alSetError(pContext, AL_INVALID_NAME);
1156 else
1157 alSetError(pContext, AL_INVALID_VALUE);
1159 ProcessContext(pContext);
1163 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1165 ALCcontext *pContext;
1166 ALsource *Source;
1168 pContext = GetContextSuspended();
1169 if(!pContext) return;
1171 if(plValue1 && plValue2 && plValue3)
1173 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1175 switch(eParam)
1177 case AL_POSITION:
1178 *plValue1 = (ALint)Source->vPosition[0];
1179 *plValue2 = (ALint)Source->vPosition[1];
1180 *plValue3 = (ALint)Source->vPosition[2];
1181 break;
1183 case AL_VELOCITY:
1184 *plValue1 = (ALint)Source->vVelocity[0];
1185 *plValue2 = (ALint)Source->vVelocity[1];
1186 *plValue3 = (ALint)Source->vVelocity[2];
1187 break;
1189 case AL_DIRECTION:
1190 *plValue1 = (ALint)Source->vOrientation[0];
1191 *plValue2 = (ALint)Source->vOrientation[1];
1192 *plValue3 = (ALint)Source->vOrientation[2];
1193 break;
1195 default:
1196 alSetError(pContext, AL_INVALID_ENUM);
1197 break;
1200 else
1201 alSetError(pContext, AL_INVALID_NAME);
1203 else
1204 alSetError(pContext, AL_INVALID_VALUE);
1206 ProcessContext(pContext);
1210 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1212 ALCcontext *pContext;
1213 ALsource *Source;
1214 ALdouble Offsets[2];
1215 ALdouble updateLen;
1217 pContext = GetContextSuspended();
1218 if(!pContext) return;
1220 if(plValues)
1222 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1224 switch(eParam)
1226 case AL_SOURCE_RELATIVE:
1227 case AL_CONE_INNER_ANGLE:
1228 case AL_CONE_OUTER_ANGLE:
1229 case AL_LOOPING:
1230 case AL_BUFFER:
1231 case AL_SOURCE_STATE:
1232 case AL_BUFFERS_QUEUED:
1233 case AL_BUFFERS_PROCESSED:
1234 case AL_SEC_OFFSET:
1235 case AL_SAMPLE_OFFSET:
1236 case AL_BYTE_OFFSET:
1237 case AL_MAX_DISTANCE:
1238 case AL_ROLLOFF_FACTOR:
1239 case AL_DOPPLER_FACTOR:
1240 case AL_REFERENCE_DISTANCE:
1241 case AL_SOURCE_TYPE:
1242 case AL_DIRECT_FILTER:
1243 case AL_DIRECT_FILTER_GAINHF_AUTO:
1244 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1245 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1246 case AL_DISTANCE_MODEL:
1247 alGetSourcei(source, eParam, plValues);
1248 break;
1250 case AL_SAMPLE_RW_OFFSETS_EXT:
1251 case AL_BYTE_RW_OFFSETS_EXT:
1252 updateLen = (ALdouble)pContext->Device->UpdateSize /
1253 pContext->Device->Frequency;
1254 GetSourceOffset(Source, eParam, Offsets, updateLen);
1255 plValues[0] = (ALint)Offsets[0];
1256 plValues[1] = (ALint)Offsets[1];
1257 break;
1259 case AL_POSITION:
1260 plValues[0] = (ALint)Source->vPosition[0];
1261 plValues[1] = (ALint)Source->vPosition[1];
1262 plValues[2] = (ALint)Source->vPosition[2];
1263 break;
1265 case AL_VELOCITY:
1266 plValues[0] = (ALint)Source->vVelocity[0];
1267 plValues[1] = (ALint)Source->vVelocity[1];
1268 plValues[2] = (ALint)Source->vVelocity[2];
1269 break;
1271 case AL_DIRECTION:
1272 plValues[0] = (ALint)Source->vOrientation[0];
1273 plValues[1] = (ALint)Source->vOrientation[1];
1274 plValues[2] = (ALint)Source->vOrientation[2];
1275 break;
1277 default:
1278 alSetError(pContext, AL_INVALID_ENUM);
1279 break;
1282 else
1283 alSetError(pContext, AL_INVALID_NAME);
1285 else
1286 alSetError(pContext, AL_INVALID_VALUE);
1288 ProcessContext(pContext);
1292 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1294 alSourcePlayv(1, &source);
1297 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1299 ALCcontext *Context;
1300 ALsource *Source;
1301 ALbufferlistitem *BufferList;
1302 ALsizei i, j;
1304 Context = GetContextSuspended();
1305 if(!Context) return;
1307 if(!sources)
1309 alSetError(Context, AL_INVALID_VALUE);
1310 goto done;
1313 // Check that all the Sources are valid
1314 for(i = 0;i < n;i++)
1316 if(!LookupSource(Context->SourceMap, sources[i]))
1318 alSetError(Context, AL_INVALID_NAME);
1319 goto done;
1323 if(Context->ActiveSourceCount+n < n)
1325 alSetError(Context, AL_OUT_OF_MEMORY);
1326 goto done;
1329 while(Context->MaxActiveSources < Context->ActiveSourceCount+n)
1331 void *temp = NULL;
1332 ALsizei newcount;
1334 newcount = Context->MaxActiveSources << 1;
1335 if(newcount > 0)
1336 temp = realloc(Context->ActiveSources,
1337 sizeof(*Context->ActiveSources) * newcount);
1338 if(!temp)
1340 alSetError(Context, AL_OUT_OF_MEMORY);
1341 goto done;
1344 Context->ActiveSources = temp;
1345 Context->MaxActiveSources = newcount;
1348 for(i = 0;i < n;i++)
1350 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1352 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1353 BufferList = Source->queue;
1354 while(BufferList)
1356 if(BufferList->buffer != NULL && BufferList->buffer->size)
1357 break;
1358 BufferList = BufferList->next;
1361 if(!BufferList)
1363 Source->BuffersPlayed = Source->BuffersInQueue;
1364 continue;
1367 for(j = 0;j < OUTPUTCHANNELS;j++)
1368 Source->DryGains[j] = 0.0f;
1369 for(j = 0;j < MAX_SENDS;j++)
1370 Source->WetGains[j] = 0.0f;
1372 if(Source->state != AL_PAUSED)
1374 Source->state = AL_PLAYING;
1375 Source->position = 0;
1376 Source->position_fraction = 0;
1377 Source->BuffersPlayed = 0;
1379 Source->Buffer = Source->queue->buffer;
1381 else
1382 Source->state = AL_PLAYING;
1384 // Check if an Offset has been set
1385 if(Source->lOffset)
1386 ApplyOffset(Source);
1388 if(Source->BuffersPlayed == 0 && Source->position == 0 &&
1389 Source->position_fraction == 0)
1390 Source->FirstStart = AL_TRUE;
1391 else
1392 Source->FirstStart = AL_FALSE;
1394 // If device is disconnected, go right to stopped
1395 if(!Context->Device->Connected)
1397 Source->state = AL_STOPPED;
1398 Source->BuffersPlayed = Source->BuffersInQueue;
1399 Source->position = 0;
1400 Source->position_fraction = 0;
1402 else
1404 for(j = 0;j < Context->ActiveSourceCount;j++)
1406 if(Context->ActiveSources[j] == Source)
1407 break;
1409 if(j == Context->ActiveSourceCount)
1410 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1414 done:
1415 ProcessContext(Context);
1418 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1420 alSourcePausev(1, &source);
1423 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1425 ALCcontext *Context;
1426 ALsource *Source;
1427 ALsizei i;
1429 Context = GetContextSuspended();
1430 if(!Context) return;
1432 if(!sources)
1434 alSetError(Context, AL_INVALID_VALUE);
1435 goto done;
1438 // Check all the Sources are valid
1439 for(i = 0;i < n;i++)
1441 if(!LookupSource(Context->SourceMap, sources[i]))
1443 alSetError(Context, AL_INVALID_NAME);
1444 goto done;
1448 for(i = 0;i < n;i++)
1450 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1451 if(Source->state == AL_PLAYING)
1452 Source->state = AL_PAUSED;
1455 done:
1456 ProcessContext(Context);
1459 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1461 alSourceStopv(1, &source);
1464 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1466 ALCcontext *Context;
1467 ALsource *Source;
1468 ALsizei i;
1470 Context = GetContextSuspended();
1471 if(!Context) return;
1473 if(!sources)
1475 alSetError(Context, AL_INVALID_VALUE);
1476 goto done;
1479 // Check all the Sources are valid
1480 for(i = 0;i < n;i++)
1482 if(!LookupSource(Context->SourceMap, sources[i]))
1484 alSetError(Context, AL_INVALID_NAME);
1485 goto done;
1489 for(i = 0;i < n;i++)
1491 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1492 if(Source->state != AL_INITIAL)
1494 Source->state = AL_STOPPED;
1495 Source->BuffersPlayed = Source->BuffersInQueue;
1497 Source->lOffset = 0;
1500 done:
1501 ProcessContext(Context);
1504 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1506 alSourceRewindv(1, &source);
1509 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1511 ALCcontext *Context;
1512 ALsource *Source;
1513 ALsizei i;
1515 Context = GetContextSuspended();
1516 if(!Context) return;
1518 if(!sources)
1520 alSetError(Context, AL_INVALID_VALUE);
1521 goto done;
1524 // Check all the Sources are valid
1525 for(i = 0;i < n;i++)
1527 if(!LookupSource(Context->SourceMap, sources[i]))
1529 alSetError(Context, AL_INVALID_NAME);
1530 goto done;
1534 for(i = 0;i < n;i++)
1536 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1537 if(Source->state != AL_INITIAL)
1539 Source->state = AL_INITIAL;
1540 Source->position = 0;
1541 Source->position_fraction = 0;
1542 Source->BuffersPlayed = 0;
1543 if(Source->queue)
1544 Source->Buffer = Source->queue->buffer;
1546 Source->lOffset = 0;
1549 done:
1550 ProcessContext(Context);
1554 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1556 ALCcontext *Context;
1557 ALCdevice *device;
1558 ALsource *Source;
1559 ALbuffer *buffer;
1560 ALsizei i;
1561 ALbufferlistitem *BufferListStart;
1562 ALbufferlistitem *BufferList;
1563 ALboolean HadFormat;
1564 ALint Frequency;
1565 ALint Format;
1567 if(n == 0)
1568 return;
1570 Context = GetContextSuspended();
1571 if(!Context) return;
1573 // Check that all buffers are valid or zero and that the source is valid
1575 // Check that this is a valid source
1576 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1578 alSetError(Context, AL_INVALID_NAME);
1579 goto done;
1582 // Check that this is not a STATIC Source
1583 if(Source->lSourceType == AL_STATIC)
1585 // Invalid Source Type (can't queue on a Static Source)
1586 alSetError(Context, AL_INVALID_OPERATION);
1587 goto done;
1590 device = Context->Device;
1592 Frequency = -1;
1593 Format = -1;
1594 HadFormat = AL_FALSE;
1596 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1597 BufferList = Source->queue;
1598 while(BufferList)
1600 if(BufferList->buffer)
1602 Frequency = BufferList->buffer->frequency;
1603 Format = BufferList->buffer->format;
1604 HadFormat = AL_TRUE;
1605 break;
1607 BufferList = BufferList->next;
1610 for(i = 0;i < n;i++)
1612 if(!buffers[i])
1613 continue;
1615 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1617 alSetError(Context, AL_INVALID_NAME);
1618 goto done;
1621 if(Frequency == -1 && Format == -1)
1623 Frequency = buffer->frequency;
1624 Format = buffer->format;
1626 else if(Frequency != buffer->frequency || Format != buffer->format)
1628 alSetError(Context, AL_INVALID_OPERATION);
1629 goto done;
1633 // Change Source Type
1634 Source->lSourceType = AL_STREAMING;
1636 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1638 // All buffers are valid - so add them to the list
1639 BufferListStart = malloc(sizeof(ALbufferlistitem));
1640 BufferListStart->buffer = buffer;
1641 BufferListStart->next = NULL;
1643 // Increment reference counter for buffer
1644 if(buffer) buffer->refcount++;
1646 BufferList = BufferListStart;
1648 for(i = 1;i < n;i++)
1650 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1652 BufferList->next = malloc(sizeof(ALbufferlistitem));
1653 BufferList->next->buffer = buffer;
1654 BufferList->next->next = NULL;
1656 // Increment reference counter for buffer
1657 if(buffer) buffer->refcount++;
1659 BufferList = BufferList->next;
1662 if(Source->queue == NULL)
1664 Source->queue = BufferListStart;
1665 // Update Current Buffer
1666 Source->Buffer = BufferListStart->buffer;
1668 else
1670 // Find end of queue
1671 BufferList = Source->queue;
1672 while(BufferList->next != NULL)
1673 BufferList = BufferList->next;
1675 BufferList->next = BufferListStart;
1678 // Update number of buffers in queue
1679 Source->BuffersInQueue += n;
1680 // If no previous format, mark the source dirty now that it may have one
1681 if(!HadFormat)
1682 Source->NeedsUpdate = AL_TRUE;
1684 done:
1685 ProcessContext(Context);
1689 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1690 // an array of buffer IDs that are to be filled with the names of the buffers removed
1691 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1693 ALCcontext *Context;
1694 ALsource *Source;
1695 ALsizei i;
1696 ALbufferlistitem *BufferList;
1698 if(n == 0)
1699 return;
1701 Context = GetContextSuspended();
1702 if(!Context) return;
1704 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1706 alSetError(Context, AL_INVALID_NAME);
1707 goto done;
1710 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1711 (ALuint)n > Source->BuffersPlayed)
1713 // Some buffers can't be unqueue because they have not been processed
1714 alSetError(Context, AL_INVALID_VALUE);
1715 goto done;
1718 for(i = 0;i < n;i++)
1720 BufferList = Source->queue;
1721 Source->queue = BufferList->next;
1723 if(BufferList->buffer)
1725 // Record name of buffer
1726 buffers[i] = BufferList->buffer->buffer;
1727 // Decrement buffer reference counter
1728 BufferList->buffer->refcount--;
1730 else
1731 buffers[i] = 0;
1733 // Release memory for buffer list item
1734 free(BufferList);
1735 Source->BuffersInQueue--;
1738 if(Source->state != AL_PLAYING)
1740 if(Source->queue)
1741 Source->Buffer = Source->queue->buffer;
1742 else
1743 Source->Buffer = NULL;
1745 Source->BuffersPlayed -= n;
1747 done:
1748 ProcessContext(Context);
1752 static ALvoid InitSourceParams(ALsource *Source)
1754 Source->flInnerAngle = 360.0f;
1755 Source->flOuterAngle = 360.0f;
1756 Source->flPitch = 1.0f;
1757 Source->vPosition[0] = 0.0f;
1758 Source->vPosition[1] = 0.0f;
1759 Source->vPosition[2] = 0.0f;
1760 Source->vOrientation[0] = 0.0f;
1761 Source->vOrientation[1] = 0.0f;
1762 Source->vOrientation[2] = 0.0f;
1763 Source->vVelocity[0] = 0.0f;
1764 Source->vVelocity[1] = 0.0f;
1765 Source->vVelocity[2] = 0.0f;
1766 Source->flRefDistance = 1.0f;
1767 Source->flMaxDistance = FLT_MAX;
1768 Source->flRollOffFactor = 1.0f;
1769 Source->bLooping = AL_FALSE;
1770 Source->flGain = 1.0f;
1771 Source->flMinGain = 0.0f;
1772 Source->flMaxGain = 1.0f;
1773 Source->flOuterGain = 0.0f;
1774 Source->OuterGainHF = 1.0f;
1776 Source->DryGainHFAuto = AL_TRUE;
1777 Source->WetGainAuto = AL_TRUE;
1778 Source->WetGainHFAuto = AL_TRUE;
1779 Source->AirAbsorptionFactor = 0.0f;
1780 Source->RoomRolloffFactor = 0.0f;
1781 Source->DopplerFactor = 1.0f;
1783 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1785 Source->Resampler = DefaultResampler;
1787 Source->state = AL_INITIAL;
1788 Source->lSourceType = AL_UNDETERMINED;
1790 Source->NeedsUpdate = AL_TRUE;
1792 Source->Buffer = NULL;
1797 GetSourceOffset
1799 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1800 The offset is relative to the start of the queue (not the start of the current buffer)
1802 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1804 ALbufferlistitem *BufferList;
1805 ALbuffer *Buffer = NULL;
1806 ALfloat BufferFreq;
1807 ALint Channels, Bytes;
1808 ALuint readPos, writePos;
1809 ALenum OriginalFormat;
1810 ALuint TotalBufferDataSize;
1811 ALuint i;
1813 // Find the first non-NULL Buffer in the Queue
1814 BufferList = Source->queue;
1815 while(BufferList)
1817 if(BufferList->buffer)
1819 Buffer = BufferList->buffer;
1820 break;
1822 BufferList = BufferList->next;
1825 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1827 offset[0] = 0.0;
1828 offset[1] = 0.0;
1829 return;
1832 // Get Current Buffer Size and frequency (in milliseconds)
1833 BufferFreq = (ALfloat)Buffer->frequency;
1834 OriginalFormat = Buffer->eOriginalFormat;
1835 Channels = aluChannelsFromFormat(Buffer->format);
1836 Bytes = aluBytesFromFormat(Buffer->format);
1838 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1839 readPos = Source->position * Channels * Bytes;
1840 // Add byte length of any processed buffers in the queue
1841 TotalBufferDataSize = 0;
1842 BufferList = Source->queue;
1843 for(i = 0;BufferList;i++)
1845 if(BufferList->buffer)
1847 if(i < Source->BuffersPlayed)
1848 readPos += BufferList->buffer->size;
1849 TotalBufferDataSize += BufferList->buffer->size;
1851 BufferList = BufferList->next;
1853 if(Source->state == AL_PLAYING)
1854 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1855 else
1856 writePos = readPos;
1858 if(Source->bLooping)
1860 readPos %= TotalBufferDataSize;
1861 writePos %= TotalBufferDataSize;
1863 else
1865 // Clamp positions to TotalBufferDataSize
1866 if(readPos > TotalBufferDataSize)
1867 readPos = TotalBufferDataSize;
1868 if(writePos > TotalBufferDataSize)
1869 writePos = TotalBufferDataSize;
1872 switch(name)
1874 case AL_SEC_OFFSET:
1875 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1876 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1877 break;
1878 case AL_SAMPLE_OFFSET:
1879 case AL_SAMPLE_RW_OFFSETS_EXT:
1880 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1881 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1882 break;
1883 case AL_BYTE_OFFSET:
1884 case AL_BYTE_RW_OFFSETS_EXT:
1885 // Take into account the original format of the Buffer
1886 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1887 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1889 // Round down to nearest ADPCM block
1890 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1891 if(Source->state == AL_PLAYING)
1893 // Round up to nearest ADPCM block
1894 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1896 else
1897 offset[1] = offset[0];
1899 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1900 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1901 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1902 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1903 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1904 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1906 offset[0] = (ALdouble)(readPos / Bytes * 1);
1907 offset[1] = (ALdouble)(writePos / Bytes * 1);
1909 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1911 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1912 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1914 else if(OriginalFormat == AL_FORMAT_REAR8)
1916 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1917 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1919 else if(OriginalFormat == AL_FORMAT_REAR16)
1921 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1922 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1924 else if(OriginalFormat == AL_FORMAT_REAR32)
1926 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1927 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1929 else
1931 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1932 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1933 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1935 break;
1941 ApplyOffset
1943 Apply a playback offset to the Source. This function will update the queue (to correctly
1944 mark buffers as 'pending' or 'processed' depending upon the new offset.
1946 static ALboolean ApplyOffset(ALsource *Source)
1948 ALbufferlistitem *BufferList;
1949 ALbuffer *Buffer;
1950 ALint lBufferSize, lTotalBufferSize;
1951 ALint BuffersPlayed;
1952 ALint lByteOffset;
1954 // Get true byte offset
1955 lByteOffset = GetByteOffset(Source);
1957 // If the offset is invalid, don't apply it
1958 if(lByteOffset == -1)
1959 return AL_FALSE;
1961 // Sort out the queue (pending and processed states)
1962 BufferList = Source->queue;
1963 lTotalBufferSize = 0;
1964 BuffersPlayed = 0;
1966 while(BufferList)
1968 Buffer = BufferList->buffer;
1969 lBufferSize = Buffer ? Buffer->size : 0;
1971 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1973 // Offset is past this buffer so increment BuffersPlayed
1974 BuffersPlayed++;
1976 else if(lTotalBufferSize <= lByteOffset)
1978 // Offset is within this buffer
1979 // Set Current Buffer
1980 Source->Buffer = BufferList->buffer;
1981 Source->BuffersPlayed = BuffersPlayed;
1983 // SW Mixer Positions are in Samples
1984 Source->position = (lByteOffset - lTotalBufferSize) /
1985 aluFrameSizeFromFormat(Buffer->format);
1986 return AL_TRUE;
1989 // Increment the TotalBufferSize
1990 lTotalBufferSize += lBufferSize;
1992 // Move on to next buffer in the Queue
1993 BufferList = BufferList->next;
1995 // Offset is out of range of the buffer queue
1996 return AL_FALSE;
2001 GetByteOffset
2003 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2004 offset supplied by the application). This takes into account the fact that the buffer format
2005 may have been modifed by AL (e.g 8bit samples are converted to float)
2007 static ALint GetByteOffset(ALsource *Source)
2009 ALbuffer *Buffer = NULL;
2010 ALbufferlistitem *BufferList;
2011 ALfloat BufferFreq;
2012 ALint Channels, Bytes;
2013 ALint ByteOffset = -1;
2015 // Find the first non-NULL Buffer in the Queue
2016 BufferList = Source->queue;
2017 while(BufferList)
2019 if(BufferList->buffer)
2021 Buffer = BufferList->buffer;
2022 break;
2024 BufferList = BufferList->next;
2027 if(!Buffer)
2029 Source->lOffset = 0;
2030 return -1;
2033 BufferFreq = ((ALfloat)Buffer->frequency);
2034 Channels = aluChannelsFromFormat(Buffer->format);
2035 Bytes = aluBytesFromFormat(Buffer->format);
2037 // Determine the ByteOffset (and ensure it is block aligned)
2038 switch(Source->lOffsetType)
2040 case AL_BYTE_OFFSET:
2041 // Take into consideration the original format
2042 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2043 Channels);
2044 ByteOffset *= Channels * Bytes;
2045 break;
2047 case AL_SAMPLE_OFFSET:
2048 ByteOffset = Source->lOffset * Channels * Bytes;
2049 break;
2051 case AL_SEC_OFFSET:
2052 // Note - lOffset is internally stored as Milliseconds
2053 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2054 ByteOffset *= Channels * Bytes;
2055 break;
2057 // Clear Offset
2058 Source->lOffset = 0;
2060 return ByteOffset;
2063 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2065 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2067 // Round down to nearest ADPCM block
2068 offset /= 36 * channels;
2069 // Multiply by compression rate (65 sample frames per block)
2070 offset *= 65;
2072 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2073 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2074 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2076 /* muLaw has 1 byte per sample */
2077 offset /= 1 * channels;
2079 else if(format == AL_FORMAT_REAR_MULAW)
2081 /* Rear is 2 channels */
2082 offset /= 1 * 2;
2084 else if(format == AL_FORMAT_REAR8)
2085 offset /= 1 * 2;
2086 else if(format == AL_FORMAT_REAR16)
2087 offset /= 2 * 2;
2088 else if(format == AL_FORMAT_REAR32)
2089 offset /= 4 * 2;
2090 else
2092 ALuint bytes = aluBytesFromFormat(format);
2093 offset /= bytes * channels;
2095 return offset;
2099 ALvoid ReleaseALSources(ALCcontext *Context)
2101 ALsizei pos;
2102 ALuint j;
2103 for(pos = 0;pos < Context->SourceMap.size;pos++)
2105 ALsource *temp = Context->SourceMap.array[pos].value;
2106 Context->SourceMap.array[pos].value = NULL;
2108 // For each buffer in the source's queue, decrement its reference counter and remove it
2109 while(temp->queue != NULL)
2111 ALbufferlistitem *BufferList = temp->queue;
2112 // Decrement buffer's reference counter
2113 if(BufferList->buffer != NULL)
2114 BufferList->buffer->refcount--;
2115 // Update queue to point to next element in list
2116 temp->queue = BufferList->next;
2117 // Release memory allocated for buffer list item
2118 free(BufferList);
2121 for(j = 0;j < MAX_SENDS;++j)
2123 if(temp->Send[j].Slot)
2124 temp->Send[j].Slot->refcount--;
2127 // Release source structure
2128 ALTHUNK_REMOVEENTRY(temp->source);
2129 memset(temp, 0, sizeof(ALsource));
2130 free(temp);