Add a Null Output device
[openal-soft/android/lowlatency.git] / OpenAL32 / alSource.c
blobd470f027672d899adba4de34e64e127d31612030
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 each buffer in the source's queue, decrement its reference counter and remove it
149 while(Source->queue != NULL)
151 BufferList = Source->queue;
152 // Decrement buffer's reference counter
153 if(BufferList->buffer != NULL)
154 BufferList->buffer->refcount--;
155 // Update queue to point to next element in list
156 Source->queue = BufferList->next;
157 // Release memory allocated for buffer list item
158 free(BufferList);
161 for(j = 0;j < MAX_SENDS;++j)
163 if(Source->Send[j].Slot)
164 Source->Send[j].Slot->refcount--;
165 Source->Send[j].Slot = NULL;
168 // Remove Source from list of Sources
169 RemoveUIntMapKey(&Context->SourceMap, Source->source);
170 ALTHUNK_REMOVEENTRY(Source->source);
172 memset(Source,0,sizeof(ALsource));
173 free(Source);
178 else
179 alSetError(Context, AL_INVALID_VALUE);
181 ProcessContext(Context);
185 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
187 ALCcontext *Context;
188 ALboolean result;
190 Context = GetContextSuspended();
191 if(!Context) return AL_FALSE;
193 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
195 ProcessContext(Context);
197 return result;
201 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
203 ALCcontext *pContext;
204 ALsource *Source;
206 pContext = GetContextSuspended();
207 if(!pContext) return;
209 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
211 switch(eParam)
213 case AL_PITCH:
214 if(flValue >= 0.0f)
216 Source->flPitch = flValue;
217 if(Source->flPitch < 0.001f)
218 Source->flPitch = 0.001f;
219 Source->NeedsUpdate = AL_TRUE;
221 else
222 alSetError(pContext, AL_INVALID_VALUE);
223 break;
225 case AL_CONE_INNER_ANGLE:
226 if(flValue >= 0.0f && flValue <= 360.0f)
228 Source->flInnerAngle = flValue;
229 Source->NeedsUpdate = AL_TRUE;
231 else
232 alSetError(pContext, AL_INVALID_VALUE);
233 break;
235 case AL_CONE_OUTER_ANGLE:
236 if(flValue >= 0.0f && flValue <= 360.0f)
238 Source->flOuterAngle = flValue;
239 Source->NeedsUpdate = AL_TRUE;
241 else
242 alSetError(pContext, AL_INVALID_VALUE);
243 break;
245 case AL_GAIN:
246 if(flValue >= 0.0f)
248 Source->flGain = flValue;
249 Source->NeedsUpdate = AL_TRUE;
251 else
252 alSetError(pContext, AL_INVALID_VALUE);
253 break;
255 case AL_MAX_DISTANCE:
256 if(flValue >= 0.0f)
258 Source->flMaxDistance = flValue;
259 Source->NeedsUpdate = AL_TRUE;
261 else
262 alSetError(pContext, AL_INVALID_VALUE);
263 break;
265 case AL_ROLLOFF_FACTOR:
266 if(flValue >= 0.0f)
268 Source->flRollOffFactor = flValue;
269 Source->NeedsUpdate = AL_TRUE;
271 else
272 alSetError(pContext, AL_INVALID_VALUE);
273 break;
275 case AL_REFERENCE_DISTANCE:
276 if(flValue >= 0.0f)
278 Source->flRefDistance = flValue;
279 Source->NeedsUpdate = AL_TRUE;
281 else
282 alSetError(pContext, AL_INVALID_VALUE);
283 break;
285 case AL_MIN_GAIN:
286 if(flValue >= 0.0f && flValue <= 1.0f)
288 Source->flMinGain = flValue;
289 Source->NeedsUpdate = AL_TRUE;
291 else
292 alSetError(pContext, AL_INVALID_VALUE);
293 break;
295 case AL_MAX_GAIN:
296 if(flValue >= 0.0f && flValue <= 1.0f)
298 Source->flMaxGain = flValue;
299 Source->NeedsUpdate = AL_TRUE;
301 else
302 alSetError(pContext, AL_INVALID_VALUE);
303 break;
305 case AL_CONE_OUTER_GAIN:
306 if(flValue >= 0.0f && flValue <= 1.0f)
308 Source->flOuterGain = flValue;
309 Source->NeedsUpdate = AL_TRUE;
311 else
312 alSetError(pContext, AL_INVALID_VALUE);
313 break;
315 case AL_CONE_OUTER_GAINHF:
316 if(flValue >= 0.0f && flValue <= 1.0f)
318 Source->OuterGainHF = flValue;
319 Source->NeedsUpdate = AL_TRUE;
321 else
322 alSetError(pContext, AL_INVALID_VALUE);
323 break;
325 case AL_AIR_ABSORPTION_FACTOR:
326 if(flValue >= 0.0f && flValue <= 10.0f)
328 Source->AirAbsorptionFactor = flValue;
329 Source->NeedsUpdate = AL_TRUE;
331 else
332 alSetError(pContext, AL_INVALID_VALUE);
333 break;
335 case AL_ROOM_ROLLOFF_FACTOR:
336 if(flValue >= 0.0f && flValue <= 10.0f)
338 Source->RoomRolloffFactor = flValue;
339 Source->NeedsUpdate = AL_TRUE;
341 else
342 alSetError(pContext, AL_INVALID_VALUE);
343 break;
345 case AL_DOPPLER_FACTOR:
346 if(flValue >= 0.0f && flValue <= 1.0f)
348 Source->DopplerFactor = flValue;
349 Source->NeedsUpdate = AL_TRUE;
351 else
352 alSetError(pContext, AL_INVALID_VALUE);
353 break;
355 case AL_SEC_OFFSET:
356 case AL_SAMPLE_OFFSET:
357 case AL_BYTE_OFFSET:
358 if(flValue >= 0.0f)
360 Source->lOffsetType = eParam;
362 // Store Offset (convert Seconds into Milliseconds)
363 if(eParam == AL_SEC_OFFSET)
364 Source->lOffset = (ALint)(flValue * 1000.0f);
365 else
366 Source->lOffset = (ALint)flValue;
368 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
370 if(ApplyOffset(Source) == AL_FALSE)
371 alSetError(pContext, AL_INVALID_VALUE);
374 else
375 alSetError(pContext, AL_INVALID_VALUE);
376 break;
378 default:
379 alSetError(pContext, AL_INVALID_ENUM);
380 break;
383 else
385 // Invalid Source Name
386 alSetError(pContext, AL_INVALID_NAME);
389 ProcessContext(pContext);
393 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
395 ALCcontext *pContext;
396 ALsource *Source;
398 pContext = GetContextSuspended();
399 if(!pContext) return;
401 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
403 switch(eParam)
405 case AL_POSITION:
406 Source->vPosition[0] = flValue1;
407 Source->vPosition[1] = flValue2;
408 Source->vPosition[2] = flValue3;
409 Source->NeedsUpdate = AL_TRUE;
410 break;
412 case AL_VELOCITY:
413 Source->vVelocity[0] = flValue1;
414 Source->vVelocity[1] = flValue2;
415 Source->vVelocity[2] = flValue3;
416 Source->NeedsUpdate = AL_TRUE;
417 break;
419 case AL_DIRECTION:
420 Source->vOrientation[0] = flValue1;
421 Source->vOrientation[1] = flValue2;
422 Source->vOrientation[2] = flValue3;
423 Source->NeedsUpdate = AL_TRUE;
424 break;
426 default:
427 alSetError(pContext, AL_INVALID_ENUM);
428 break;
431 else
432 alSetError(pContext, AL_INVALID_NAME);
434 ProcessContext(pContext);
438 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
440 ALCcontext *pContext;
442 pContext = GetContextSuspended();
443 if(!pContext) return;
445 if(pflValues)
447 if(LookupSource(pContext->SourceMap, source) != NULL)
449 switch(eParam)
451 case AL_PITCH:
452 case AL_CONE_INNER_ANGLE:
453 case AL_CONE_OUTER_ANGLE:
454 case AL_GAIN:
455 case AL_MAX_DISTANCE:
456 case AL_ROLLOFF_FACTOR:
457 case AL_REFERENCE_DISTANCE:
458 case AL_MIN_GAIN:
459 case AL_MAX_GAIN:
460 case AL_CONE_OUTER_GAIN:
461 case AL_CONE_OUTER_GAINHF:
462 case AL_SEC_OFFSET:
463 case AL_SAMPLE_OFFSET:
464 case AL_BYTE_OFFSET:
465 case AL_AIR_ABSORPTION_FACTOR:
466 case AL_ROOM_ROLLOFF_FACTOR:
467 alSourcef(source, eParam, pflValues[0]);
468 break;
470 case AL_POSITION:
471 case AL_VELOCITY:
472 case AL_DIRECTION:
473 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
474 break;
476 default:
477 alSetError(pContext, AL_INVALID_ENUM);
478 break;
481 else
482 alSetError(pContext, AL_INVALID_NAME);
484 else
485 alSetError(pContext, AL_INVALID_VALUE);
487 ProcessContext(pContext);
491 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
493 ALCcontext *pContext;
494 ALsource *Source;
495 ALbufferlistitem *BufferListItem;
497 pContext = GetContextSuspended();
498 if(!pContext) return;
500 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
502 ALCdevice *device = pContext->Device;
504 switch(eParam)
506 case AL_MAX_DISTANCE:
507 case AL_ROLLOFF_FACTOR:
508 case AL_CONE_INNER_ANGLE:
509 case AL_CONE_OUTER_ANGLE:
510 case AL_REFERENCE_DISTANCE:
511 alSourcef(source, eParam, (ALfloat)lValue);
512 break;
514 case AL_SOURCE_RELATIVE:
515 if(lValue == AL_FALSE || lValue == AL_TRUE)
517 Source->bHeadRelative = (ALboolean)lValue;
518 Source->NeedsUpdate = AL_TRUE;
520 else
521 alSetError(pContext, AL_INVALID_VALUE);
522 break;
524 case AL_LOOPING:
525 if(lValue == AL_FALSE || lValue == AL_TRUE)
526 Source->bLooping = (ALboolean)lValue;
527 else
528 alSetError(pContext, AL_INVALID_VALUE);
529 break;
531 case AL_BUFFER:
532 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
534 ALbuffer *buffer = NULL;
536 if(lValue == 0 ||
537 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
539 // Remove all elements in the queue
540 while(Source->queue != NULL)
542 BufferListItem = Source->queue;
543 Source->queue = BufferListItem->next;
544 // Decrement reference counter for buffer
545 if(BufferListItem->buffer)
546 BufferListItem->buffer->refcount--;
547 // Release memory for buffer list item
548 free(BufferListItem);
549 // Decrement the number of buffers in the queue
550 Source->BuffersInQueue--;
553 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
554 if(lValue != 0)
556 // Source is now in STATIC mode
557 Source->lSourceType = AL_STATIC;
559 // Add the selected buffer to the queue
560 BufferListItem = malloc(sizeof(ALbufferlistitem));
561 BufferListItem->buffer = buffer;
562 BufferListItem->next = NULL;
564 Source->queue = BufferListItem;
565 Source->BuffersInQueue = 1;
567 // Increment reference counter for buffer
568 buffer->refcount++;
570 else
572 // Source is now in UNDETERMINED mode
573 Source->lSourceType = AL_UNDETERMINED;
575 Source->BuffersPlayed = 0;
577 // Update AL_BUFFER parameter
578 Source->Buffer = buffer;
579 Source->NeedsUpdate = AL_TRUE;
581 else
582 alSetError(pContext, AL_INVALID_VALUE);
584 else
585 alSetError(pContext, AL_INVALID_OPERATION);
586 break;
588 case AL_SOURCE_STATE:
589 // Query only
590 alSetError(pContext, AL_INVALID_OPERATION);
591 break;
593 case AL_SEC_OFFSET:
594 case AL_SAMPLE_OFFSET:
595 case AL_BYTE_OFFSET:
596 if(lValue >= 0)
598 Source->lOffsetType = eParam;
600 // Store Offset (convert Seconds into Milliseconds)
601 if(eParam == AL_SEC_OFFSET)
602 Source->lOffset = lValue * 1000;
603 else
604 Source->lOffset = lValue;
606 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
608 if(ApplyOffset(Source) == AL_FALSE)
609 alSetError(pContext, AL_INVALID_VALUE);
612 else
613 alSetError(pContext, AL_INVALID_VALUE);
614 break;
616 case AL_DIRECT_FILTER: {
617 ALfilter *filter = NULL;
619 if(lValue == 0 ||
620 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
622 if(!filter)
624 Source->DirectFilter.type = AL_FILTER_NULL;
625 Source->DirectFilter.filter = 0;
627 else
628 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
629 Source->NeedsUpdate = AL_TRUE;
631 else
632 alSetError(pContext, AL_INVALID_VALUE);
633 } break;
635 case AL_DIRECT_FILTER_GAINHF_AUTO:
636 if(lValue == AL_TRUE || lValue == AL_FALSE)
638 Source->DryGainHFAuto = lValue;
639 Source->NeedsUpdate = AL_TRUE;
641 else
642 alSetError(pContext, AL_INVALID_VALUE);
643 break;
645 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
646 if(lValue == AL_TRUE || lValue == AL_FALSE)
648 Source->WetGainAuto = lValue;
649 Source->NeedsUpdate = AL_TRUE;
651 else
652 alSetError(pContext, AL_INVALID_VALUE);
653 break;
655 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
656 if(lValue == AL_TRUE || lValue == AL_FALSE)
658 Source->WetGainHFAuto = lValue;
659 Source->NeedsUpdate = AL_TRUE;
661 else
662 alSetError(pContext, AL_INVALID_VALUE);
663 break;
665 case AL_DISTANCE_MODEL:
666 if(lValue == AL_NONE ||
667 lValue == AL_INVERSE_DISTANCE ||
668 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
669 lValue == AL_LINEAR_DISTANCE ||
670 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
671 lValue == AL_EXPONENT_DISTANCE ||
672 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
674 Source->DistanceModel = lValue;
675 if(pContext->SourceDistanceModel)
676 Source->NeedsUpdate = AL_TRUE;
678 else
679 alSetError(pContext, AL_INVALID_VALUE);
680 break;
682 default:
683 alSetError(pContext, AL_INVALID_ENUM);
684 break;
687 else
688 alSetError(pContext, AL_INVALID_NAME);
690 ProcessContext(pContext);
694 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
696 ALCcontext *pContext;
697 ALsource *Source;
699 pContext = GetContextSuspended();
700 if(!pContext) return;
702 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
704 ALCdevice *device = pContext->Device;
706 switch (eParam)
708 case AL_POSITION:
709 case AL_VELOCITY:
710 case AL_DIRECTION:
711 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
712 break;
714 case AL_AUXILIARY_SEND_FILTER: {
715 ALeffectslot *ALEffectSlot = NULL;
716 ALfilter *ALFilter = NULL;
718 if((ALuint)lValue2 < device->NumAuxSends &&
719 (lValue1 == 0 ||
720 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
721 (lValue3 == 0 ||
722 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
724 /* Release refcount on the previous slot, and add one for
725 * the new slot */
726 if(Source->Send[lValue2].Slot)
727 Source->Send[lValue2].Slot->refcount--;
728 Source->Send[lValue2].Slot = ALEffectSlot;
729 if(Source->Send[lValue2].Slot)
730 Source->Send[lValue2].Slot->refcount++;
732 if(!ALFilter)
734 /* Disable filter */
735 Source->Send[lValue2].WetFilter.type = 0;
736 Source->Send[lValue2].WetFilter.filter = 0;
738 else
739 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
740 Source->NeedsUpdate = AL_TRUE;
742 else
743 alSetError(pContext, AL_INVALID_VALUE);
744 } break;
746 default:
747 alSetError(pContext, AL_INVALID_ENUM);
748 break;
751 else
752 alSetError(pContext, AL_INVALID_NAME);
754 ProcessContext(pContext);
758 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
760 ALCcontext *pContext;
762 pContext = GetContextSuspended();
763 if(!pContext) return;
765 if(plValues)
767 if(LookupSource(pContext->SourceMap, source) != NULL)
769 switch(eParam)
771 case AL_SOURCE_RELATIVE:
772 case AL_CONE_INNER_ANGLE:
773 case AL_CONE_OUTER_ANGLE:
774 case AL_LOOPING:
775 case AL_BUFFER:
776 case AL_SOURCE_STATE:
777 case AL_SEC_OFFSET:
778 case AL_SAMPLE_OFFSET:
779 case AL_BYTE_OFFSET:
780 case AL_MAX_DISTANCE:
781 case AL_ROLLOFF_FACTOR:
782 case AL_REFERENCE_DISTANCE:
783 case AL_DIRECT_FILTER:
784 case AL_DIRECT_FILTER_GAINHF_AUTO:
785 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
786 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
787 case AL_DISTANCE_MODEL:
788 alSourcei(source, eParam, plValues[0]);
789 break;
791 case AL_POSITION:
792 case AL_VELOCITY:
793 case AL_DIRECTION:
794 case AL_AUXILIARY_SEND_FILTER:
795 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
796 break;
798 default:
799 alSetError(pContext, AL_INVALID_ENUM);
800 break;
803 else
804 alSetError(pContext, AL_INVALID_NAME);
806 else
807 alSetError(pContext, AL_INVALID_VALUE);
809 ProcessContext(pContext);
813 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
815 ALCcontext *pContext;
816 ALsource *Source;
817 ALdouble Offsets[2];
818 ALdouble updateLen;
820 pContext = GetContextSuspended();
821 if(!pContext) return;
823 if(pflValue)
825 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
827 switch(eParam)
829 case AL_PITCH:
830 *pflValue = Source->flPitch;
831 break;
833 case AL_GAIN:
834 *pflValue = Source->flGain;
835 break;
837 case AL_MIN_GAIN:
838 *pflValue = Source->flMinGain;
839 break;
841 case AL_MAX_GAIN:
842 *pflValue = Source->flMaxGain;
843 break;
845 case AL_MAX_DISTANCE:
846 *pflValue = Source->flMaxDistance;
847 break;
849 case AL_ROLLOFF_FACTOR:
850 *pflValue = Source->flRollOffFactor;
851 break;
853 case AL_CONE_OUTER_GAIN:
854 *pflValue = Source->flOuterGain;
855 break;
857 case AL_CONE_OUTER_GAINHF:
858 *pflValue = Source->OuterGainHF;
859 break;
861 case AL_SEC_OFFSET:
862 case AL_SAMPLE_OFFSET:
863 case AL_BYTE_OFFSET:
864 updateLen = (ALdouble)pContext->Device->UpdateSize /
865 pContext->Device->Frequency;
866 GetSourceOffset(Source, eParam, Offsets, updateLen);
867 *pflValue = Offsets[0];
868 break;
870 case AL_CONE_INNER_ANGLE:
871 *pflValue = Source->flInnerAngle;
872 break;
874 case AL_CONE_OUTER_ANGLE:
875 *pflValue = Source->flOuterAngle;
876 break;
878 case AL_REFERENCE_DISTANCE:
879 *pflValue = Source->flRefDistance;
880 break;
882 case AL_AIR_ABSORPTION_FACTOR:
883 *pflValue = Source->AirAbsorptionFactor;
884 break;
886 case AL_ROOM_ROLLOFF_FACTOR:
887 *pflValue = Source->RoomRolloffFactor;
888 break;
890 case AL_DOPPLER_FACTOR:
891 *pflValue = Source->DopplerFactor;
892 break;
894 default:
895 alSetError(pContext, AL_INVALID_ENUM);
896 break;
899 else
900 alSetError(pContext, AL_INVALID_NAME);
902 else
903 alSetError(pContext, AL_INVALID_VALUE);
905 ProcessContext(pContext);
909 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
911 ALCcontext *pContext;
912 ALsource *Source;
914 pContext = GetContextSuspended();
915 if(!pContext) return;
917 if(pflValue1 && pflValue2 && pflValue3)
919 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
921 switch(eParam)
923 case AL_POSITION:
924 *pflValue1 = Source->vPosition[0];
925 *pflValue2 = Source->vPosition[1];
926 *pflValue3 = Source->vPosition[2];
927 break;
929 case AL_VELOCITY:
930 *pflValue1 = Source->vVelocity[0];
931 *pflValue2 = Source->vVelocity[1];
932 *pflValue3 = Source->vVelocity[2];
933 break;
935 case AL_DIRECTION:
936 *pflValue1 = Source->vOrientation[0];
937 *pflValue2 = Source->vOrientation[1];
938 *pflValue3 = Source->vOrientation[2];
939 break;
941 default:
942 alSetError(pContext, AL_INVALID_ENUM);
943 break;
946 else
947 alSetError(pContext, AL_INVALID_NAME);
949 else
950 alSetError(pContext, AL_INVALID_VALUE);
952 ProcessContext(pContext);
956 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
958 ALCcontext *pContext;
959 ALsource *Source;
960 ALdouble Offsets[2];
961 ALdouble updateLen;
963 pContext = GetContextSuspended();
964 if(!pContext) return;
966 if(pflValues)
968 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
970 switch(eParam)
972 case AL_PITCH:
973 case AL_GAIN:
974 case AL_MIN_GAIN:
975 case AL_MAX_GAIN:
976 case AL_MAX_DISTANCE:
977 case AL_ROLLOFF_FACTOR:
978 case AL_DOPPLER_FACTOR:
979 case AL_CONE_OUTER_GAIN:
980 case AL_SEC_OFFSET:
981 case AL_SAMPLE_OFFSET:
982 case AL_BYTE_OFFSET:
983 case AL_CONE_INNER_ANGLE:
984 case AL_CONE_OUTER_ANGLE:
985 case AL_REFERENCE_DISTANCE:
986 case AL_CONE_OUTER_GAINHF:
987 case AL_AIR_ABSORPTION_FACTOR:
988 case AL_ROOM_ROLLOFF_FACTOR:
989 alGetSourcef(source, eParam, pflValues);
990 break;
992 case AL_SAMPLE_RW_OFFSETS_EXT:
993 case AL_BYTE_RW_OFFSETS_EXT:
994 updateLen = (ALdouble)pContext->Device->UpdateSize /
995 pContext->Device->Frequency;
996 GetSourceOffset(Source, eParam, Offsets, updateLen);
997 pflValues[0] = Offsets[0];
998 pflValues[1] = Offsets[1];
999 break;
1001 case AL_POSITION:
1002 pflValues[0] = Source->vPosition[0];
1003 pflValues[1] = Source->vPosition[1];
1004 pflValues[2] = Source->vPosition[2];
1005 break;
1007 case AL_VELOCITY:
1008 pflValues[0] = Source->vVelocity[0];
1009 pflValues[1] = Source->vVelocity[1];
1010 pflValues[2] = Source->vVelocity[2];
1011 break;
1013 case AL_DIRECTION:
1014 pflValues[0] = Source->vOrientation[0];
1015 pflValues[1] = Source->vOrientation[1];
1016 pflValues[2] = Source->vOrientation[2];
1017 break;
1019 default:
1020 alSetError(pContext, AL_INVALID_ENUM);
1021 break;
1024 else
1025 alSetError(pContext, AL_INVALID_NAME);
1027 else
1028 alSetError(pContext, AL_INVALID_VALUE);
1030 ProcessContext(pContext);
1034 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1036 ALCcontext *pContext;
1037 ALsource *Source;
1038 ALdouble Offsets[2];
1039 ALdouble updateLen;
1041 pContext = GetContextSuspended();
1042 if(!pContext) return;
1044 if(plValue)
1046 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1048 switch(eParam)
1050 case AL_MAX_DISTANCE:
1051 *plValue = (ALint)Source->flMaxDistance;
1052 break;
1054 case AL_ROLLOFF_FACTOR:
1055 *plValue = (ALint)Source->flRollOffFactor;
1056 break;
1058 case AL_REFERENCE_DISTANCE:
1059 *plValue = (ALint)Source->flRefDistance;
1060 break;
1062 case AL_SOURCE_RELATIVE:
1063 *plValue = Source->bHeadRelative;
1064 break;
1066 case AL_CONE_INNER_ANGLE:
1067 *plValue = (ALint)Source->flInnerAngle;
1068 break;
1070 case AL_CONE_OUTER_ANGLE:
1071 *plValue = (ALint)Source->flOuterAngle;
1072 break;
1074 case AL_LOOPING:
1075 *plValue = Source->bLooping;
1076 break;
1078 case AL_BUFFER:
1079 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1080 break;
1082 case AL_SOURCE_STATE:
1083 *plValue = Source->state;
1084 break;
1086 case AL_BUFFERS_QUEUED:
1087 *plValue = Source->BuffersInQueue;
1088 break;
1090 case AL_BUFFERS_PROCESSED:
1091 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1093 /* Buffers on a looping source are in a perpetual state
1094 * of PENDING, so don't report any as PROCESSED */
1095 *plValue = 0;
1097 else
1098 *plValue = Source->BuffersPlayed;
1099 break;
1101 case AL_SOURCE_TYPE:
1102 *plValue = Source->lSourceType;
1103 break;
1105 case AL_SEC_OFFSET:
1106 case AL_SAMPLE_OFFSET:
1107 case AL_BYTE_OFFSET:
1108 updateLen = (ALdouble)pContext->Device->UpdateSize /
1109 pContext->Device->Frequency;
1110 GetSourceOffset(Source, eParam, Offsets, updateLen);
1111 *plValue = (ALint)Offsets[0];
1112 break;
1114 case AL_DIRECT_FILTER:
1115 *plValue = Source->DirectFilter.filter;
1116 break;
1118 case AL_DIRECT_FILTER_GAINHF_AUTO:
1119 *plValue = Source->DryGainHFAuto;
1120 break;
1122 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1123 *plValue = Source->WetGainAuto;
1124 break;
1126 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1127 *plValue = Source->WetGainHFAuto;
1128 break;
1130 case AL_DOPPLER_FACTOR:
1131 *plValue = (ALint)Source->DopplerFactor;
1132 break;
1134 case AL_DISTANCE_MODEL:
1135 *plValue = Source->DistanceModel;
1136 break;
1138 default:
1139 alSetError(pContext, AL_INVALID_ENUM);
1140 break;
1143 else
1144 alSetError(pContext, AL_INVALID_NAME);
1146 else
1147 alSetError(pContext, AL_INVALID_VALUE);
1149 ProcessContext(pContext);
1153 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1155 ALCcontext *pContext;
1156 ALsource *Source;
1158 pContext = GetContextSuspended();
1159 if(!pContext) return;
1161 if(plValue1 && plValue2 && plValue3)
1163 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1165 switch(eParam)
1167 case AL_POSITION:
1168 *plValue1 = (ALint)Source->vPosition[0];
1169 *plValue2 = (ALint)Source->vPosition[1];
1170 *plValue3 = (ALint)Source->vPosition[2];
1171 break;
1173 case AL_VELOCITY:
1174 *plValue1 = (ALint)Source->vVelocity[0];
1175 *plValue2 = (ALint)Source->vVelocity[1];
1176 *plValue3 = (ALint)Source->vVelocity[2];
1177 break;
1179 case AL_DIRECTION:
1180 *plValue1 = (ALint)Source->vOrientation[0];
1181 *plValue2 = (ALint)Source->vOrientation[1];
1182 *plValue3 = (ALint)Source->vOrientation[2];
1183 break;
1185 default:
1186 alSetError(pContext, AL_INVALID_ENUM);
1187 break;
1190 else
1191 alSetError(pContext, AL_INVALID_NAME);
1193 else
1194 alSetError(pContext, AL_INVALID_VALUE);
1196 ProcessContext(pContext);
1200 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1202 ALCcontext *pContext;
1203 ALsource *Source;
1204 ALdouble Offsets[2];
1205 ALdouble updateLen;
1207 pContext = GetContextSuspended();
1208 if(!pContext) return;
1210 if(plValues)
1212 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1214 switch(eParam)
1216 case AL_SOURCE_RELATIVE:
1217 case AL_CONE_INNER_ANGLE:
1218 case AL_CONE_OUTER_ANGLE:
1219 case AL_LOOPING:
1220 case AL_BUFFER:
1221 case AL_SOURCE_STATE:
1222 case AL_BUFFERS_QUEUED:
1223 case AL_BUFFERS_PROCESSED:
1224 case AL_SEC_OFFSET:
1225 case AL_SAMPLE_OFFSET:
1226 case AL_BYTE_OFFSET:
1227 case AL_MAX_DISTANCE:
1228 case AL_ROLLOFF_FACTOR:
1229 case AL_DOPPLER_FACTOR:
1230 case AL_REFERENCE_DISTANCE:
1231 case AL_SOURCE_TYPE:
1232 case AL_DIRECT_FILTER:
1233 case AL_DIRECT_FILTER_GAINHF_AUTO:
1234 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1235 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1236 case AL_DISTANCE_MODEL:
1237 alGetSourcei(source, eParam, plValues);
1238 break;
1240 case AL_SAMPLE_RW_OFFSETS_EXT:
1241 case AL_BYTE_RW_OFFSETS_EXT:
1242 updateLen = (ALdouble)pContext->Device->UpdateSize /
1243 pContext->Device->Frequency;
1244 GetSourceOffset(Source, eParam, Offsets, updateLen);
1245 plValues[0] = (ALint)Offsets[0];
1246 plValues[1] = (ALint)Offsets[1];
1247 break;
1249 case AL_POSITION:
1250 plValues[0] = (ALint)Source->vPosition[0];
1251 plValues[1] = (ALint)Source->vPosition[1];
1252 plValues[2] = (ALint)Source->vPosition[2];
1253 break;
1255 case AL_VELOCITY:
1256 plValues[0] = (ALint)Source->vVelocity[0];
1257 plValues[1] = (ALint)Source->vVelocity[1];
1258 plValues[2] = (ALint)Source->vVelocity[2];
1259 break;
1261 case AL_DIRECTION:
1262 plValues[0] = (ALint)Source->vOrientation[0];
1263 plValues[1] = (ALint)Source->vOrientation[1];
1264 plValues[2] = (ALint)Source->vOrientation[2];
1265 break;
1267 default:
1268 alSetError(pContext, AL_INVALID_ENUM);
1269 break;
1272 else
1273 alSetError(pContext, AL_INVALID_NAME);
1275 else
1276 alSetError(pContext, AL_INVALID_VALUE);
1278 ProcessContext(pContext);
1282 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1284 alSourcePlayv(1, &source);
1287 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1289 ALCcontext *Context;
1290 ALsource *Source;
1291 ALbufferlistitem *BufferList;
1292 ALsizei i, j;
1294 Context = GetContextSuspended();
1295 if(!Context) return;
1297 if(!sources)
1299 alSetError(Context, AL_INVALID_VALUE);
1300 goto done;
1303 // Check that all the Sources are valid
1304 for(i = 0;i < n;i++)
1306 if(!LookupSource(Context->SourceMap, sources[i]))
1308 alSetError(Context, AL_INVALID_NAME);
1309 goto done;
1313 for(i = 0;i < n;i++)
1315 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1317 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1318 BufferList = Source->queue;
1319 while(BufferList)
1321 if(BufferList->buffer != NULL && BufferList->buffer->size)
1322 break;
1323 BufferList = BufferList->next;
1326 if(!BufferList)
1328 Source->BuffersPlayed = Source->BuffersInQueue;
1329 continue;
1332 for(j = 0;j < OUTPUTCHANNELS;j++)
1333 Source->DryGains[j] = 0.0f;
1334 for(j = 0;j < MAX_SENDS;j++)
1335 Source->WetGains[j] = 0.0f;
1337 if(Source->state != AL_PAUSED)
1339 Source->state = AL_PLAYING;
1340 Source->position = 0;
1341 Source->position_fraction = 0;
1342 Source->BuffersPlayed = 0;
1344 Source->Buffer = Source->queue->buffer;
1346 else
1347 Source->state = AL_PLAYING;
1349 // Check if an Offset has been set
1350 if(Source->lOffset)
1351 ApplyOffset(Source);
1353 if(Source->BuffersPlayed == 0 && Source->position == 0 &&
1354 Source->position_fraction == 0)
1355 Source->FirstStart = AL_TRUE;
1356 else
1357 Source->FirstStart = AL_FALSE;
1359 // If device is disconnected, go right to stopped
1360 if(!Context->Device->Connected)
1362 Source->state = AL_STOPPED;
1363 Source->BuffersPlayed = Source->BuffersInQueue;
1364 Source->position = 0;
1365 Source->position_fraction = 0;
1369 done:
1370 ProcessContext(Context);
1373 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1375 alSourcePausev(1, &source);
1378 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1380 ALCcontext *Context;
1381 ALsource *Source;
1382 ALsizei i;
1384 Context = GetContextSuspended();
1385 if(!Context) return;
1387 if(!sources)
1389 alSetError(Context, AL_INVALID_VALUE);
1390 goto done;
1393 // Check all the Sources are valid
1394 for(i = 0;i < n;i++)
1396 if(!LookupSource(Context->SourceMap, sources[i]))
1398 alSetError(Context, AL_INVALID_NAME);
1399 goto done;
1403 for(i = 0;i < n;i++)
1405 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1406 if(Source->state == AL_PLAYING)
1407 Source->state = AL_PAUSED;
1410 done:
1411 ProcessContext(Context);
1414 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1416 alSourceStopv(1, &source);
1419 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1421 ALCcontext *Context;
1422 ALsource *Source;
1423 ALsizei i;
1425 Context = GetContextSuspended();
1426 if(!Context) return;
1428 if(!sources)
1430 alSetError(Context, AL_INVALID_VALUE);
1431 goto done;
1434 // Check all the Sources are valid
1435 for(i = 0;i < n;i++)
1437 if(!LookupSource(Context->SourceMap, sources[i]))
1439 alSetError(Context, AL_INVALID_NAME);
1440 goto done;
1444 for(i = 0;i < n;i++)
1446 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1447 if(Source->state != AL_INITIAL)
1449 Source->state = AL_STOPPED;
1450 Source->BuffersPlayed = Source->BuffersInQueue;
1452 Source->lOffset = 0;
1455 done:
1456 ProcessContext(Context);
1459 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1461 alSourceRewindv(1, &source);
1464 AL_API ALvoid AL_APIENTRY alSourceRewindv(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_INITIAL;
1495 Source->position = 0;
1496 Source->position_fraction = 0;
1497 Source->BuffersPlayed = 0;
1498 if(Source->queue)
1499 Source->Buffer = Source->queue->buffer;
1501 Source->lOffset = 0;
1504 done:
1505 ProcessContext(Context);
1509 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1511 ALCcontext *Context;
1512 ALCdevice *device;
1513 ALsource *Source;
1514 ALbuffer *buffer;
1515 ALsizei i;
1516 ALbufferlistitem *BufferListStart;
1517 ALbufferlistitem *BufferList;
1518 ALboolean HadFormat;
1519 ALint Frequency;
1520 ALint Format;
1522 if(n == 0)
1523 return;
1525 Context = GetContextSuspended();
1526 if(!Context) return;
1528 // Check that all buffers are valid or zero and that the source is valid
1530 // Check that this is a valid source
1531 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1533 alSetError(Context, AL_INVALID_NAME);
1534 goto done;
1537 // Check that this is not a STATIC Source
1538 if(Source->lSourceType == AL_STATIC)
1540 // Invalid Source Type (can't queue on a Static Source)
1541 alSetError(Context, AL_INVALID_OPERATION);
1542 goto done;
1545 device = Context->Device;
1547 Frequency = -1;
1548 Format = -1;
1549 HadFormat = AL_FALSE;
1551 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1552 BufferList = Source->queue;
1553 while(BufferList)
1555 if(BufferList->buffer)
1557 Frequency = BufferList->buffer->frequency;
1558 Format = BufferList->buffer->format;
1559 HadFormat = AL_TRUE;
1560 break;
1562 BufferList = BufferList->next;
1565 for(i = 0;i < n;i++)
1567 if(!buffers[i])
1568 continue;
1570 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1572 alSetError(Context, AL_INVALID_NAME);
1573 goto done;
1576 if(Frequency == -1 && Format == -1)
1578 Frequency = buffer->frequency;
1579 Format = buffer->format;
1581 else if(Frequency != buffer->frequency || Format != buffer->format)
1583 alSetError(Context, AL_INVALID_OPERATION);
1584 goto done;
1588 // Change Source Type
1589 Source->lSourceType = AL_STREAMING;
1591 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1593 // All buffers are valid - so add them to the list
1594 BufferListStart = malloc(sizeof(ALbufferlistitem));
1595 BufferListStart->buffer = buffer;
1596 BufferListStart->next = NULL;
1598 // Increment reference counter for buffer
1599 if(buffer) buffer->refcount++;
1601 BufferList = BufferListStart;
1603 for(i = 1;i < n;i++)
1605 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1607 BufferList->next = malloc(sizeof(ALbufferlistitem));
1608 BufferList->next->buffer = buffer;
1609 BufferList->next->next = NULL;
1611 // Increment reference counter for buffer
1612 if(buffer) buffer->refcount++;
1614 BufferList = BufferList->next;
1617 if(Source->queue == NULL)
1619 Source->queue = BufferListStart;
1620 // Update Current Buffer
1621 Source->Buffer = BufferListStart->buffer;
1623 else
1625 // Find end of queue
1626 BufferList = Source->queue;
1627 while(BufferList->next != NULL)
1628 BufferList = BufferList->next;
1630 BufferList->next = BufferListStart;
1633 // Update number of buffers in queue
1634 Source->BuffersInQueue += n;
1635 // If no previous format, mark the source dirty now that it may have one
1636 if(!HadFormat)
1637 Source->NeedsUpdate = AL_TRUE;
1639 done:
1640 ProcessContext(Context);
1644 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1645 // an array of buffer IDs that are to be filled with the names of the buffers removed
1646 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1648 ALCcontext *Context;
1649 ALsource *Source;
1650 ALsizei i;
1651 ALbufferlistitem *BufferList;
1653 if(n == 0)
1654 return;
1656 Context = GetContextSuspended();
1657 if(!Context) return;
1659 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1661 alSetError(Context, AL_INVALID_NAME);
1662 goto done;
1665 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1666 (ALuint)n > Source->BuffersPlayed)
1668 // Some buffers can't be unqueue because they have not been processed
1669 alSetError(Context, AL_INVALID_VALUE);
1670 goto done;
1673 for(i = 0;i < n;i++)
1675 BufferList = Source->queue;
1676 Source->queue = BufferList->next;
1678 if(BufferList->buffer)
1680 // Record name of buffer
1681 buffers[i] = BufferList->buffer->buffer;
1682 // Decrement buffer reference counter
1683 BufferList->buffer->refcount--;
1685 else
1686 buffers[i] = 0;
1688 // Release memory for buffer list item
1689 free(BufferList);
1690 Source->BuffersInQueue--;
1693 if(Source->state != AL_PLAYING)
1695 if(Source->queue)
1696 Source->Buffer = Source->queue->buffer;
1697 else
1698 Source->Buffer = NULL;
1700 Source->BuffersPlayed -= n;
1702 done:
1703 ProcessContext(Context);
1707 static ALvoid InitSourceParams(ALsource *Source)
1709 Source->flInnerAngle = 360.0f;
1710 Source->flOuterAngle = 360.0f;
1711 Source->flPitch = 1.0f;
1712 Source->vPosition[0] = 0.0f;
1713 Source->vPosition[1] = 0.0f;
1714 Source->vPosition[2] = 0.0f;
1715 Source->vOrientation[0] = 0.0f;
1716 Source->vOrientation[1] = 0.0f;
1717 Source->vOrientation[2] = 0.0f;
1718 Source->vVelocity[0] = 0.0f;
1719 Source->vVelocity[1] = 0.0f;
1720 Source->vVelocity[2] = 0.0f;
1721 Source->flRefDistance = 1.0f;
1722 Source->flMaxDistance = FLT_MAX;
1723 Source->flRollOffFactor = 1.0f;
1724 Source->bLooping = AL_FALSE;
1725 Source->flGain = 1.0f;
1726 Source->flMinGain = 0.0f;
1727 Source->flMaxGain = 1.0f;
1728 Source->flOuterGain = 0.0f;
1729 Source->OuterGainHF = 1.0f;
1731 Source->DryGainHFAuto = AL_TRUE;
1732 Source->WetGainAuto = AL_TRUE;
1733 Source->WetGainHFAuto = AL_TRUE;
1734 Source->AirAbsorptionFactor = 0.0f;
1735 Source->RoomRolloffFactor = 0.0f;
1736 Source->DopplerFactor = 1.0f;
1738 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1740 Source->Resampler = DefaultResampler;
1742 Source->state = AL_INITIAL;
1743 Source->lSourceType = AL_UNDETERMINED;
1745 Source->NeedsUpdate = AL_TRUE;
1747 Source->Buffer = NULL;
1752 GetSourceOffset
1754 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1755 The offset is relative to the start of the queue (not the start of the current buffer)
1757 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1759 ALbufferlistitem *BufferList;
1760 ALbuffer *Buffer = NULL;
1761 ALfloat BufferFreq;
1762 ALint Channels, Bytes;
1763 ALuint readPos, writePos;
1764 ALenum OriginalFormat;
1765 ALuint TotalBufferDataSize;
1766 ALuint i;
1768 // Find the first non-NULL Buffer in the Queue
1769 BufferList = Source->queue;
1770 while(BufferList)
1772 if(BufferList->buffer)
1774 Buffer = BufferList->buffer;
1775 break;
1777 BufferList = BufferList->next;
1780 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1782 offset[0] = 0.0;
1783 offset[1] = 0.0;
1784 return;
1787 // Get Current Buffer Size and frequency (in milliseconds)
1788 BufferFreq = (ALfloat)Buffer->frequency;
1789 OriginalFormat = Buffer->eOriginalFormat;
1790 Channels = aluChannelsFromFormat(Buffer->format);
1791 Bytes = aluBytesFromFormat(Buffer->format);
1793 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1794 readPos = Source->position * Channels * Bytes;
1795 // Add byte length of any processed buffers in the queue
1796 TotalBufferDataSize = 0;
1797 BufferList = Source->queue;
1798 for(i = 0;BufferList;i++)
1800 if(BufferList->buffer)
1802 if(i < Source->BuffersPlayed)
1803 readPos += BufferList->buffer->size;
1804 TotalBufferDataSize += BufferList->buffer->size;
1806 BufferList = BufferList->next;
1808 if(Source->state == AL_PLAYING)
1809 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1810 else
1811 writePos = readPos;
1813 if(Source->bLooping)
1815 readPos %= TotalBufferDataSize;
1816 writePos %= TotalBufferDataSize;
1818 else
1820 // Clamp positions to TotalBufferDataSize
1821 if(readPos > TotalBufferDataSize)
1822 readPos = TotalBufferDataSize;
1823 if(writePos > TotalBufferDataSize)
1824 writePos = TotalBufferDataSize;
1827 switch(name)
1829 case AL_SEC_OFFSET:
1830 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1831 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1832 break;
1833 case AL_SAMPLE_OFFSET:
1834 case AL_SAMPLE_RW_OFFSETS_EXT:
1835 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1836 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1837 break;
1838 case AL_BYTE_OFFSET:
1839 case AL_BYTE_RW_OFFSETS_EXT:
1840 // Take into account the original format of the Buffer
1841 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1842 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1844 // Round down to nearest ADPCM block
1845 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1846 if(Source->state == AL_PLAYING)
1848 // Round up to nearest ADPCM block
1849 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1851 else
1852 offset[1] = offset[0];
1854 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1855 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1856 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1857 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1858 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1859 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1861 offset[0] = (ALdouble)(readPos / Bytes * 1);
1862 offset[1] = (ALdouble)(writePos / Bytes * 1);
1864 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1866 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1867 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1869 else if(OriginalFormat == AL_FORMAT_REAR8)
1871 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1872 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1874 else if(OriginalFormat == AL_FORMAT_REAR16)
1876 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1877 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1879 else if(OriginalFormat == AL_FORMAT_REAR32)
1881 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1882 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1884 else
1886 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1887 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1888 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1890 break;
1896 ApplyOffset
1898 Apply a playback offset to the Source. This function will update the queue (to correctly
1899 mark buffers as 'pending' or 'processed' depending upon the new offset.
1901 static ALboolean ApplyOffset(ALsource *Source)
1903 ALbufferlistitem *BufferList;
1904 ALbuffer *Buffer;
1905 ALint lBufferSize, lTotalBufferSize;
1906 ALint BuffersPlayed;
1907 ALint lByteOffset;
1909 // Get true byte offset
1910 lByteOffset = GetByteOffset(Source);
1912 // If the offset is invalid, don't apply it
1913 if(lByteOffset == -1)
1914 return AL_FALSE;
1916 // Sort out the queue (pending and processed states)
1917 BufferList = Source->queue;
1918 lTotalBufferSize = 0;
1919 BuffersPlayed = 0;
1921 while(BufferList)
1923 Buffer = BufferList->buffer;
1924 lBufferSize = Buffer ? Buffer->size : 0;
1926 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1928 // Offset is past this buffer so increment BuffersPlayed
1929 BuffersPlayed++;
1931 else if(lTotalBufferSize <= lByteOffset)
1933 // Offset is within this buffer
1934 // Set Current Buffer
1935 Source->Buffer = BufferList->buffer;
1936 Source->BuffersPlayed = BuffersPlayed;
1938 // SW Mixer Positions are in Samples
1939 Source->position = (lByteOffset - lTotalBufferSize) /
1940 aluFrameSizeFromFormat(Buffer->format);
1941 return AL_TRUE;
1944 // Increment the TotalBufferSize
1945 lTotalBufferSize += lBufferSize;
1947 // Move on to next buffer in the Queue
1948 BufferList = BufferList->next;
1950 // Offset is out of range of the buffer queue
1951 return AL_FALSE;
1956 GetByteOffset
1958 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1959 offset supplied by the application). This takes into account the fact that the buffer format
1960 may have been modifed by AL (e.g 8bit samples are converted to float)
1962 static ALint GetByteOffset(ALsource *Source)
1964 ALbuffer *Buffer = NULL;
1965 ALbufferlistitem *BufferList;
1966 ALfloat BufferFreq;
1967 ALint Channels, Bytes;
1968 ALint ByteOffset = -1;
1970 // Find the first non-NULL Buffer in the Queue
1971 BufferList = Source->queue;
1972 while(BufferList)
1974 if(BufferList->buffer)
1976 Buffer = BufferList->buffer;
1977 break;
1979 BufferList = BufferList->next;
1982 if(!Buffer)
1984 Source->lOffset = 0;
1985 return -1;
1988 BufferFreq = ((ALfloat)Buffer->frequency);
1989 Channels = aluChannelsFromFormat(Buffer->format);
1990 Bytes = aluBytesFromFormat(Buffer->format);
1992 // Determine the ByteOffset (and ensure it is block aligned)
1993 switch(Source->lOffsetType)
1995 case AL_BYTE_OFFSET:
1996 // Take into consideration the original format
1997 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
1998 Channels);
1999 ByteOffset *= Channels * Bytes;
2000 break;
2002 case AL_SAMPLE_OFFSET:
2003 ByteOffset = Source->lOffset * Channels * Bytes;
2004 break;
2006 case AL_SEC_OFFSET:
2007 // Note - lOffset is internally stored as Milliseconds
2008 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2009 ByteOffset *= Channels * Bytes;
2010 break;
2012 // Clear Offset
2013 Source->lOffset = 0;
2015 return ByteOffset;
2018 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2020 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2022 // Round down to nearest ADPCM block
2023 offset /= 36 * channels;
2024 // Multiply by compression rate (65 sample frames per block)
2025 offset *= 65;
2027 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2028 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2029 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2031 /* muLaw has 1 byte per sample */
2032 offset /= 1 * channels;
2034 else if(format == AL_FORMAT_REAR_MULAW)
2036 /* Rear is 2 channels */
2037 offset /= 1 * 2;
2039 else if(format == AL_FORMAT_REAR8)
2040 offset /= 1 * 2;
2041 else if(format == AL_FORMAT_REAR16)
2042 offset /= 2 * 2;
2043 else if(format == AL_FORMAT_REAR32)
2044 offset /= 4 * 2;
2045 else
2047 ALuint bytes = aluBytesFromFormat(format);
2048 offset /= bytes * channels;
2050 return offset;
2054 ALvoid ReleaseALSources(ALCcontext *Context)
2056 ALsizei pos;
2057 ALuint j;
2058 for(pos = 0;pos < Context->SourceMap.size;pos++)
2060 ALsource *temp = Context->SourceMap.array[pos].value;
2061 Context->SourceMap.array[pos].value = NULL;
2063 // For each buffer in the source's queue, decrement its reference counter and remove it
2064 while(temp->queue != NULL)
2066 ALbufferlistitem *BufferList = temp->queue;
2067 // Decrement buffer's reference counter
2068 if(BufferList->buffer != NULL)
2069 BufferList->buffer->refcount--;
2070 // Update queue to point to next element in list
2071 temp->queue = BufferList->next;
2072 // Release memory allocated for buffer list item
2073 free(BufferList);
2076 for(j = 0;j < MAX_SENDS;++j)
2078 if(temp->Send[j].Slot)
2079 temp->Send[j].Slot->refcount--;
2082 // Release source structure
2083 ALTHUNK_REMOVEENTRY(temp->source);
2084 memset(temp, 0, sizeof(ALsource));
2085 free(temp);