Don't needlessly expose a variable for the backends
[openal-soft/android/lowlatency.git] / OpenAL32 / alSource.c
blobba79f03f7d66d5300e97333471511ca5a8c442ff
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 DECL_VERIFIER(Filter, ALfilter, filter)
43 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
44 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
45 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
47 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
49 ALCcontext *Context;
50 ALCdevice *Device;
51 ALsizei i=0;
53 Context = GetContextSuspended();
54 if(!Context) return;
56 if(n > 0)
58 Device = Context->Device;
60 // Check that enough memory has been allocted in the 'sources' array for n Sources
61 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
63 // Check that the requested number of sources can be generated
64 if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources)
66 ALenum err;
68 // Add additional sources to the list
69 while(i < n)
71 ALsource *source = calloc(1, sizeof(ALsource));
72 if(!source)
74 alSetError(Context, AL_OUT_OF_MEMORY);
75 alDeleteSources(i, sources);
76 break;
79 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
80 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
81 source);
82 if(err != AL_NO_ERROR)
84 ALTHUNK_REMOVEENTRY(source->source);
85 memset(source, 0, sizeof(ALsource));
86 free(source);
88 alSetError(Context, err);
89 alDeleteSources(i, sources);
90 break;
93 sources[i++] = source->source;
94 InitSourceParams(source);
97 else
99 // Not enough resources to create the Sources
100 alSetError(Context, AL_INVALID_VALUE);
103 else
105 // Bad pointer
106 alSetError(Context, AL_INVALID_VALUE);
110 ProcessContext(Context);
114 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
116 ALCcontext *Context;
117 ALCdevice *Device;
118 ALsource *Source;
119 ALsizei i, j;
120 ALbufferlistitem *BufferList;
121 ALboolean bSourcesValid = AL_TRUE;
123 Context = GetContextSuspended();
124 if(!Context) return;
126 if(n >= 0)
128 Device = Context->Device;
130 // Check that all Sources are valid (and can therefore be deleted)
131 for (i = 0; i < n; i++)
133 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
135 alSetError(Context, AL_INVALID_NAME);
136 bSourcesValid = AL_FALSE;
137 break;
141 if(bSourcesValid)
143 // All Sources are valid, and can be deleted
144 for(i = 0; i < n; i++)
146 // Recheck that the Source is valid, because there could be duplicated Source names
147 if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL)
149 // For each buffer in the source's queue, decrement its reference counter and remove it
150 while(Source->queue != NULL)
152 BufferList = Source->queue;
153 // Decrement buffer's reference counter
154 if(BufferList->buffer != NULL)
155 BufferList->buffer->refcount--;
156 // Update queue to point to next element in list
157 Source->queue = BufferList->next;
158 // Release memory allocated for buffer list item
159 free(BufferList);
162 for(j = 0;j < MAX_SENDS;++j)
164 if(Source->Send[j].Slot)
165 Source->Send[j].Slot->refcount--;
166 Source->Send[j].Slot = NULL;
169 // Remove Source from list of Sources
170 RemoveUIntMapKey(&Context->SourceMap, Source->source);
171 ALTHUNK_REMOVEENTRY(Source->source);
173 memset(Source,0,sizeof(ALsource));
174 free(Source);
179 else
180 alSetError(Context, AL_INVALID_VALUE);
182 ProcessContext(Context);
186 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
188 ALCcontext *Context;
189 ALboolean result;
191 Context = GetContextSuspended();
192 if(!Context) return AL_FALSE;
194 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
196 ProcessContext(Context);
198 return result;
202 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
204 ALCcontext *pContext;
205 ALsource *Source;
207 pContext = GetContextSuspended();
208 if(!pContext) return;
210 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
212 switch(eParam)
214 case AL_PITCH:
215 if(flValue >= 0.0f)
217 Source->flPitch = flValue;
218 if(Source->flPitch < 0.001f)
219 Source->flPitch = 0.001f;
220 Source->NeedsUpdate = AL_TRUE;
222 else
223 alSetError(pContext, AL_INVALID_VALUE);
224 break;
226 case AL_CONE_INNER_ANGLE:
227 if(flValue >= 0.0f && flValue <= 360.0f)
229 Source->flInnerAngle = flValue;
230 Source->NeedsUpdate = AL_TRUE;
232 else
233 alSetError(pContext, AL_INVALID_VALUE);
234 break;
236 case AL_CONE_OUTER_ANGLE:
237 if(flValue >= 0.0f && flValue <= 360.0f)
239 Source->flOuterAngle = flValue;
240 Source->NeedsUpdate = AL_TRUE;
242 else
243 alSetError(pContext, AL_INVALID_VALUE);
244 break;
246 case AL_GAIN:
247 if(flValue >= 0.0f)
249 Source->flGain = flValue;
250 Source->NeedsUpdate = AL_TRUE;
252 else
253 alSetError(pContext, AL_INVALID_VALUE);
254 break;
256 case AL_MAX_DISTANCE:
257 if(flValue >= 0.0f)
259 Source->flMaxDistance = flValue;
260 Source->NeedsUpdate = AL_TRUE;
262 else
263 alSetError(pContext, AL_INVALID_VALUE);
264 break;
266 case AL_ROLLOFF_FACTOR:
267 if(flValue >= 0.0f)
269 Source->flRollOffFactor = flValue;
270 Source->NeedsUpdate = AL_TRUE;
272 else
273 alSetError(pContext, AL_INVALID_VALUE);
274 break;
276 case AL_REFERENCE_DISTANCE:
277 if(flValue >= 0.0f)
279 Source->flRefDistance = flValue;
280 Source->NeedsUpdate = AL_TRUE;
282 else
283 alSetError(pContext, AL_INVALID_VALUE);
284 break;
286 case AL_MIN_GAIN:
287 if(flValue >= 0.0f && flValue <= 1.0f)
289 Source->flMinGain = flValue;
290 Source->NeedsUpdate = AL_TRUE;
292 else
293 alSetError(pContext, AL_INVALID_VALUE);
294 break;
296 case AL_MAX_GAIN:
297 if(flValue >= 0.0f && flValue <= 1.0f)
299 Source->flMaxGain = flValue;
300 Source->NeedsUpdate = AL_TRUE;
302 else
303 alSetError(pContext, AL_INVALID_VALUE);
304 break;
306 case AL_CONE_OUTER_GAIN:
307 if(flValue >= 0.0f && flValue <= 1.0f)
309 Source->flOuterGain = flValue;
310 Source->NeedsUpdate = AL_TRUE;
312 else
313 alSetError(pContext, AL_INVALID_VALUE);
314 break;
316 case AL_CONE_OUTER_GAINHF:
317 if(flValue >= 0.0f && flValue <= 1.0f)
319 Source->OuterGainHF = flValue;
320 Source->NeedsUpdate = AL_TRUE;
322 else
323 alSetError(pContext, AL_INVALID_VALUE);
324 break;
326 case AL_AIR_ABSORPTION_FACTOR:
327 if(flValue >= 0.0f && flValue <= 10.0f)
329 Source->AirAbsorptionFactor = flValue;
330 Source->NeedsUpdate = AL_TRUE;
332 else
333 alSetError(pContext, AL_INVALID_VALUE);
334 break;
336 case AL_ROOM_ROLLOFF_FACTOR:
337 if(flValue >= 0.0f && flValue <= 10.0f)
339 Source->RoomRolloffFactor = flValue;
340 Source->NeedsUpdate = AL_TRUE;
342 else
343 alSetError(pContext, AL_INVALID_VALUE);
344 break;
346 case AL_DOPPLER_FACTOR:
347 if(flValue >= 0.0f && flValue <= 1.0f)
349 Source->DopplerFactor = flValue;
350 Source->NeedsUpdate = AL_TRUE;
352 else
353 alSetError(pContext, AL_INVALID_VALUE);
354 break;
356 case AL_SEC_OFFSET:
357 case AL_SAMPLE_OFFSET:
358 case AL_BYTE_OFFSET:
359 if(flValue >= 0.0f)
361 Source->lOffsetType = eParam;
363 // Store Offset (convert Seconds into Milliseconds)
364 if(eParam == AL_SEC_OFFSET)
365 Source->lOffset = (ALint)(flValue * 1000.0f);
366 else
367 Source->lOffset = (ALint)flValue;
369 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
371 if(ApplyOffset(Source) == AL_FALSE)
372 alSetError(pContext, AL_INVALID_VALUE);
375 else
376 alSetError(pContext, AL_INVALID_VALUE);
377 break;
379 default:
380 alSetError(pContext, AL_INVALID_ENUM);
381 break;
384 else
386 // Invalid Source Name
387 alSetError(pContext, AL_INVALID_NAME);
390 ProcessContext(pContext);
394 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
396 ALCcontext *pContext;
397 ALsource *Source;
399 pContext = GetContextSuspended();
400 if(!pContext) return;
402 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
404 switch(eParam)
406 case AL_POSITION:
407 Source->vPosition[0] = flValue1;
408 Source->vPosition[1] = flValue2;
409 Source->vPosition[2] = flValue3;
410 Source->NeedsUpdate = AL_TRUE;
411 break;
413 case AL_VELOCITY:
414 Source->vVelocity[0] = flValue1;
415 Source->vVelocity[1] = flValue2;
416 Source->vVelocity[2] = flValue3;
417 Source->NeedsUpdate = AL_TRUE;
418 break;
420 case AL_DIRECTION:
421 Source->vOrientation[0] = flValue1;
422 Source->vOrientation[1] = flValue2;
423 Source->vOrientation[2] = flValue3;
424 Source->NeedsUpdate = AL_TRUE;
425 break;
427 default:
428 alSetError(pContext, AL_INVALID_ENUM);
429 break;
432 else
433 alSetError(pContext, AL_INVALID_NAME);
435 ProcessContext(pContext);
439 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
441 ALCcontext *pContext;
443 pContext = GetContextSuspended();
444 if(!pContext) return;
446 if(pflValues)
448 if(LookupSource(pContext->SourceMap, source) != NULL)
450 switch(eParam)
452 case AL_PITCH:
453 case AL_CONE_INNER_ANGLE:
454 case AL_CONE_OUTER_ANGLE:
455 case AL_GAIN:
456 case AL_MAX_DISTANCE:
457 case AL_ROLLOFF_FACTOR:
458 case AL_REFERENCE_DISTANCE:
459 case AL_MIN_GAIN:
460 case AL_MAX_GAIN:
461 case AL_CONE_OUTER_GAIN:
462 case AL_CONE_OUTER_GAINHF:
463 case AL_SEC_OFFSET:
464 case AL_SAMPLE_OFFSET:
465 case AL_BYTE_OFFSET:
466 case AL_AIR_ABSORPTION_FACTOR:
467 case AL_ROOM_ROLLOFF_FACTOR:
468 alSourcef(source, eParam, pflValues[0]);
469 break;
471 case AL_POSITION:
472 case AL_VELOCITY:
473 case AL_DIRECTION:
474 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
475 break;
477 default:
478 alSetError(pContext, AL_INVALID_ENUM);
479 break;
482 else
483 alSetError(pContext, AL_INVALID_NAME);
485 else
486 alSetError(pContext, AL_INVALID_VALUE);
488 ProcessContext(pContext);
492 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
494 ALCcontext *pContext;
495 ALsource *Source;
496 ALbufferlistitem *BufferListItem;
498 pContext = GetContextSuspended();
499 if(!pContext) return;
501 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
503 ALCdevice *device = pContext->Device;
505 switch(eParam)
507 case AL_MAX_DISTANCE:
508 case AL_ROLLOFF_FACTOR:
509 case AL_CONE_INNER_ANGLE:
510 case AL_CONE_OUTER_ANGLE:
511 case AL_REFERENCE_DISTANCE:
512 alSourcef(source, eParam, (ALfloat)lValue);
513 break;
515 case AL_SOURCE_RELATIVE:
516 if(lValue == AL_FALSE || lValue == AL_TRUE)
518 Source->bHeadRelative = (ALboolean)lValue;
519 Source->NeedsUpdate = AL_TRUE;
521 else
522 alSetError(pContext, AL_INVALID_VALUE);
523 break;
525 case AL_LOOPING:
526 if(lValue == AL_FALSE || lValue == AL_TRUE)
527 Source->bLooping = (ALboolean)lValue;
528 else
529 alSetError(pContext, AL_INVALID_VALUE);
530 break;
532 case AL_BUFFER:
533 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
535 ALbuffer *buffer = NULL;
537 if(lValue == 0 ||
538 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
540 // Remove all elements in the queue
541 while(Source->queue != NULL)
543 BufferListItem = Source->queue;
544 Source->queue = BufferListItem->next;
545 // Decrement reference counter for buffer
546 if(BufferListItem->buffer)
547 BufferListItem->buffer->refcount--;
548 // Release memory for buffer list item
549 free(BufferListItem);
550 // Decrement the number of buffers in the queue
551 Source->BuffersInQueue--;
554 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
555 if(lValue != 0)
557 // Source is now in STATIC mode
558 Source->lSourceType = AL_STATIC;
560 // Add the selected buffer to the queue
561 BufferListItem = malloc(sizeof(ALbufferlistitem));
562 BufferListItem->buffer = buffer;
563 BufferListItem->next = NULL;
565 Source->queue = BufferListItem;
566 Source->BuffersInQueue = 1;
568 // Increment reference counter for buffer
569 buffer->refcount++;
571 else
573 // Source is now in UNDETERMINED mode
574 Source->lSourceType = AL_UNDETERMINED;
576 Source->BuffersPlayed = 0;
578 // Update AL_BUFFER parameter
579 Source->Buffer = buffer;
580 Source->NeedsUpdate = AL_TRUE;
582 else
583 alSetError(pContext, AL_INVALID_VALUE);
585 else
586 alSetError(pContext, AL_INVALID_OPERATION);
587 break;
589 case AL_SOURCE_STATE:
590 // Query only
591 alSetError(pContext, AL_INVALID_OPERATION);
592 break;
594 case AL_SEC_OFFSET:
595 case AL_SAMPLE_OFFSET:
596 case AL_BYTE_OFFSET:
597 if(lValue >= 0)
599 Source->lOffsetType = eParam;
601 // Store Offset (convert Seconds into Milliseconds)
602 if(eParam == AL_SEC_OFFSET)
603 Source->lOffset = lValue * 1000;
604 else
605 Source->lOffset = lValue;
607 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
609 if(ApplyOffset(Source) == AL_FALSE)
610 alSetError(pContext, AL_INVALID_VALUE);
613 else
614 alSetError(pContext, AL_INVALID_VALUE);
615 break;
617 case AL_DIRECT_FILTER: {
618 ALfilter *filter = NULL;
620 if(lValue == 0 ||
621 (filter=VerifyFilter(pContext->Device->FilterList, lValue)) != NULL)
623 if(!filter)
625 Source->DirectFilter.type = AL_FILTER_NULL;
626 Source->DirectFilter.filter = 0;
628 else
629 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
630 Source->NeedsUpdate = AL_TRUE;
632 else
633 alSetError(pContext, AL_INVALID_VALUE);
634 } break;
636 case AL_DIRECT_FILTER_GAINHF_AUTO:
637 if(lValue == AL_TRUE || lValue == AL_FALSE)
639 Source->DryGainHFAuto = lValue;
640 Source->NeedsUpdate = AL_TRUE;
642 else
643 alSetError(pContext, AL_INVALID_VALUE);
644 break;
646 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
647 if(lValue == AL_TRUE || lValue == AL_FALSE)
649 Source->WetGainAuto = lValue;
650 Source->NeedsUpdate = AL_TRUE;
652 else
653 alSetError(pContext, AL_INVALID_VALUE);
654 break;
656 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
657 if(lValue == AL_TRUE || lValue == AL_FALSE)
659 Source->WetGainHFAuto = lValue;
660 Source->NeedsUpdate = AL_TRUE;
662 else
663 alSetError(pContext, AL_INVALID_VALUE);
664 break;
666 case AL_DISTANCE_MODEL:
667 if(lValue == AL_NONE ||
668 lValue == AL_INVERSE_DISTANCE ||
669 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
670 lValue == AL_LINEAR_DISTANCE ||
671 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
672 lValue == AL_EXPONENT_DISTANCE ||
673 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
675 Source->DistanceModel = lValue;
676 if(pContext->SourceDistanceModel)
677 Source->NeedsUpdate = AL_TRUE;
679 else
680 alSetError(pContext, AL_INVALID_VALUE);
681 break;
683 default:
684 alSetError(pContext, AL_INVALID_ENUM);
685 break;
688 else
689 alSetError(pContext, AL_INVALID_NAME);
691 ProcessContext(pContext);
695 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
697 ALCcontext *pContext;
698 ALsource *Source;
700 pContext = GetContextSuspended();
701 if(!pContext) return;
703 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
705 ALCdevice *device = pContext->Device;
707 switch (eParam)
709 case AL_POSITION:
710 case AL_VELOCITY:
711 case AL_DIRECTION:
712 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
713 break;
715 case AL_AUXILIARY_SEND_FILTER: {
716 ALeffectslot *ALEffectSlot = NULL;
717 ALfilter *ALFilter = NULL;
719 if((ALuint)lValue2 < device->NumAuxSends &&
720 (lValue1 == 0 ||
721 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
722 (lValue3 == 0 ||
723 (ALFilter=VerifyFilter(device->FilterList, lValue3)) != NULL))
725 /* Release refcount on the previous slot, and add one for
726 * the new slot */
727 if(Source->Send[lValue2].Slot)
728 Source->Send[lValue2].Slot->refcount--;
729 Source->Send[lValue2].Slot = ALEffectSlot;
730 if(Source->Send[lValue2].Slot)
731 Source->Send[lValue2].Slot->refcount++;
733 if(!ALFilter)
735 /* Disable filter */
736 Source->Send[lValue2].WetFilter.type = 0;
737 Source->Send[lValue2].WetFilter.filter = 0;
739 else
740 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
741 Source->NeedsUpdate = AL_TRUE;
743 else
744 alSetError(pContext, AL_INVALID_VALUE);
745 } break;
747 default:
748 alSetError(pContext, AL_INVALID_ENUM);
749 break;
752 else
753 alSetError(pContext, AL_INVALID_NAME);
755 ProcessContext(pContext);
759 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
761 ALCcontext *pContext;
763 pContext = GetContextSuspended();
764 if(!pContext) return;
766 if(plValues)
768 if(LookupSource(pContext->SourceMap, source) != NULL)
770 switch(eParam)
772 case AL_SOURCE_RELATIVE:
773 case AL_CONE_INNER_ANGLE:
774 case AL_CONE_OUTER_ANGLE:
775 case AL_LOOPING:
776 case AL_BUFFER:
777 case AL_SOURCE_STATE:
778 case AL_SEC_OFFSET:
779 case AL_SAMPLE_OFFSET:
780 case AL_BYTE_OFFSET:
781 case AL_MAX_DISTANCE:
782 case AL_ROLLOFF_FACTOR:
783 case AL_REFERENCE_DISTANCE:
784 case AL_DIRECT_FILTER:
785 case AL_DIRECT_FILTER_GAINHF_AUTO:
786 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
787 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
788 case AL_DISTANCE_MODEL:
789 alSourcei(source, eParam, plValues[0]);
790 break;
792 case AL_POSITION:
793 case AL_VELOCITY:
794 case AL_DIRECTION:
795 case AL_AUXILIARY_SEND_FILTER:
796 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
797 break;
799 default:
800 alSetError(pContext, AL_INVALID_ENUM);
801 break;
804 else
805 alSetError(pContext, AL_INVALID_NAME);
807 else
808 alSetError(pContext, AL_INVALID_VALUE);
810 ProcessContext(pContext);
814 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
816 ALCcontext *pContext;
817 ALsource *Source;
818 ALdouble Offsets[2];
819 ALdouble updateLen;
821 pContext = GetContextSuspended();
822 if(!pContext) return;
824 if(pflValue)
826 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
828 switch(eParam)
830 case AL_PITCH:
831 *pflValue = Source->flPitch;
832 break;
834 case AL_GAIN:
835 *pflValue = Source->flGain;
836 break;
838 case AL_MIN_GAIN:
839 *pflValue = Source->flMinGain;
840 break;
842 case AL_MAX_GAIN:
843 *pflValue = Source->flMaxGain;
844 break;
846 case AL_MAX_DISTANCE:
847 *pflValue = Source->flMaxDistance;
848 break;
850 case AL_ROLLOFF_FACTOR:
851 *pflValue = Source->flRollOffFactor;
852 break;
854 case AL_CONE_OUTER_GAIN:
855 *pflValue = Source->flOuterGain;
856 break;
858 case AL_CONE_OUTER_GAINHF:
859 *pflValue = Source->OuterGainHF;
860 break;
862 case AL_SEC_OFFSET:
863 case AL_SAMPLE_OFFSET:
864 case AL_BYTE_OFFSET:
865 updateLen = (ALdouble)pContext->Device->UpdateSize /
866 pContext->Device->Frequency;
867 GetSourceOffset(Source, eParam, Offsets, updateLen);
868 *pflValue = Offsets[0];
869 break;
871 case AL_CONE_INNER_ANGLE:
872 *pflValue = Source->flInnerAngle;
873 break;
875 case AL_CONE_OUTER_ANGLE:
876 *pflValue = Source->flOuterAngle;
877 break;
879 case AL_REFERENCE_DISTANCE:
880 *pflValue = Source->flRefDistance;
881 break;
883 case AL_AIR_ABSORPTION_FACTOR:
884 *pflValue = Source->AirAbsorptionFactor;
885 break;
887 case AL_ROOM_ROLLOFF_FACTOR:
888 *pflValue = Source->RoomRolloffFactor;
889 break;
891 case AL_DOPPLER_FACTOR:
892 *pflValue = Source->DopplerFactor;
893 break;
895 default:
896 alSetError(pContext, AL_INVALID_ENUM);
897 break;
900 else
901 alSetError(pContext, AL_INVALID_NAME);
903 else
904 alSetError(pContext, AL_INVALID_VALUE);
906 ProcessContext(pContext);
910 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
912 ALCcontext *pContext;
913 ALsource *Source;
915 pContext = GetContextSuspended();
916 if(!pContext) return;
918 if(pflValue1 && pflValue2 && pflValue3)
920 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
922 switch(eParam)
924 case AL_POSITION:
925 *pflValue1 = Source->vPosition[0];
926 *pflValue2 = Source->vPosition[1];
927 *pflValue3 = Source->vPosition[2];
928 break;
930 case AL_VELOCITY:
931 *pflValue1 = Source->vVelocity[0];
932 *pflValue2 = Source->vVelocity[1];
933 *pflValue3 = Source->vVelocity[2];
934 break;
936 case AL_DIRECTION:
937 *pflValue1 = Source->vOrientation[0];
938 *pflValue2 = Source->vOrientation[1];
939 *pflValue3 = Source->vOrientation[2];
940 break;
942 default:
943 alSetError(pContext, AL_INVALID_ENUM);
944 break;
947 else
948 alSetError(pContext, AL_INVALID_NAME);
950 else
951 alSetError(pContext, AL_INVALID_VALUE);
953 ProcessContext(pContext);
957 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
959 ALCcontext *pContext;
960 ALsource *Source;
961 ALdouble Offsets[2];
962 ALdouble updateLen;
964 pContext = GetContextSuspended();
965 if(!pContext) return;
967 if(pflValues)
969 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
971 switch(eParam)
973 case AL_PITCH:
974 case AL_GAIN:
975 case AL_MIN_GAIN:
976 case AL_MAX_GAIN:
977 case AL_MAX_DISTANCE:
978 case AL_ROLLOFF_FACTOR:
979 case AL_DOPPLER_FACTOR:
980 case AL_CONE_OUTER_GAIN:
981 case AL_SEC_OFFSET:
982 case AL_SAMPLE_OFFSET:
983 case AL_BYTE_OFFSET:
984 case AL_CONE_INNER_ANGLE:
985 case AL_CONE_OUTER_ANGLE:
986 case AL_REFERENCE_DISTANCE:
987 case AL_CONE_OUTER_GAINHF:
988 case AL_AIR_ABSORPTION_FACTOR:
989 case AL_ROOM_ROLLOFF_FACTOR:
990 alGetSourcef(source, eParam, pflValues);
991 break;
993 case AL_SAMPLE_RW_OFFSETS_EXT:
994 case AL_BYTE_RW_OFFSETS_EXT:
995 updateLen = (ALdouble)pContext->Device->UpdateSize /
996 pContext->Device->Frequency;
997 GetSourceOffset(Source, eParam, Offsets, updateLen);
998 pflValues[0] = Offsets[0];
999 pflValues[1] = Offsets[1];
1000 break;
1002 case AL_POSITION:
1003 pflValues[0] = Source->vPosition[0];
1004 pflValues[1] = Source->vPosition[1];
1005 pflValues[2] = Source->vPosition[2];
1006 break;
1008 case AL_VELOCITY:
1009 pflValues[0] = Source->vVelocity[0];
1010 pflValues[1] = Source->vVelocity[1];
1011 pflValues[2] = Source->vVelocity[2];
1012 break;
1014 case AL_DIRECTION:
1015 pflValues[0] = Source->vOrientation[0];
1016 pflValues[1] = Source->vOrientation[1];
1017 pflValues[2] = Source->vOrientation[2];
1018 break;
1020 default:
1021 alSetError(pContext, AL_INVALID_ENUM);
1022 break;
1025 else
1026 alSetError(pContext, AL_INVALID_NAME);
1028 else
1029 alSetError(pContext, AL_INVALID_VALUE);
1031 ProcessContext(pContext);
1035 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1037 ALCcontext *pContext;
1038 ALsource *Source;
1039 ALdouble Offsets[2];
1040 ALdouble updateLen;
1042 pContext = GetContextSuspended();
1043 if(!pContext) return;
1045 if(plValue)
1047 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1049 switch(eParam)
1051 case AL_MAX_DISTANCE:
1052 *plValue = (ALint)Source->flMaxDistance;
1053 break;
1055 case AL_ROLLOFF_FACTOR:
1056 *plValue = (ALint)Source->flRollOffFactor;
1057 break;
1059 case AL_REFERENCE_DISTANCE:
1060 *plValue = (ALint)Source->flRefDistance;
1061 break;
1063 case AL_SOURCE_RELATIVE:
1064 *plValue = Source->bHeadRelative;
1065 break;
1067 case AL_CONE_INNER_ANGLE:
1068 *plValue = (ALint)Source->flInnerAngle;
1069 break;
1071 case AL_CONE_OUTER_ANGLE:
1072 *plValue = (ALint)Source->flOuterAngle;
1073 break;
1075 case AL_LOOPING:
1076 *plValue = Source->bLooping;
1077 break;
1079 case AL_BUFFER:
1080 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1081 break;
1083 case AL_SOURCE_STATE:
1084 *plValue = Source->state;
1085 break;
1087 case AL_BUFFERS_QUEUED:
1088 *plValue = Source->BuffersInQueue;
1089 break;
1091 case AL_BUFFERS_PROCESSED:
1092 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1094 /* Buffers on a looping source are in a perpetual state
1095 * of PENDING, so don't report any as PROCESSED */
1096 *plValue = 0;
1098 else
1099 *plValue = Source->BuffersPlayed;
1100 break;
1102 case AL_SOURCE_TYPE:
1103 *plValue = Source->lSourceType;
1104 break;
1106 case AL_SEC_OFFSET:
1107 case AL_SAMPLE_OFFSET:
1108 case AL_BYTE_OFFSET:
1109 updateLen = (ALdouble)pContext->Device->UpdateSize /
1110 pContext->Device->Frequency;
1111 GetSourceOffset(Source, eParam, Offsets, updateLen);
1112 *plValue = (ALint)Offsets[0];
1113 break;
1115 case AL_DIRECT_FILTER:
1116 *plValue = Source->DirectFilter.filter;
1117 break;
1119 case AL_DIRECT_FILTER_GAINHF_AUTO:
1120 *plValue = Source->DryGainHFAuto;
1121 break;
1123 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1124 *plValue = Source->WetGainAuto;
1125 break;
1127 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1128 *plValue = Source->WetGainHFAuto;
1129 break;
1131 case AL_DOPPLER_FACTOR:
1132 *plValue = (ALint)Source->DopplerFactor;
1133 break;
1135 case AL_DISTANCE_MODEL:
1136 *plValue = Source->DistanceModel;
1137 break;
1139 default:
1140 alSetError(pContext, AL_INVALID_ENUM);
1141 break;
1144 else
1145 alSetError(pContext, AL_INVALID_NAME);
1147 else
1148 alSetError(pContext, AL_INVALID_VALUE);
1150 ProcessContext(pContext);
1154 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1156 ALCcontext *pContext;
1157 ALsource *Source;
1159 pContext = GetContextSuspended();
1160 if(!pContext) return;
1162 if(plValue1 && plValue2 && plValue3)
1164 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1166 switch(eParam)
1168 case AL_POSITION:
1169 *plValue1 = (ALint)Source->vPosition[0];
1170 *plValue2 = (ALint)Source->vPosition[1];
1171 *plValue3 = (ALint)Source->vPosition[2];
1172 break;
1174 case AL_VELOCITY:
1175 *plValue1 = (ALint)Source->vVelocity[0];
1176 *plValue2 = (ALint)Source->vVelocity[1];
1177 *plValue3 = (ALint)Source->vVelocity[2];
1178 break;
1180 case AL_DIRECTION:
1181 *plValue1 = (ALint)Source->vOrientation[0];
1182 *plValue2 = (ALint)Source->vOrientation[1];
1183 *plValue3 = (ALint)Source->vOrientation[2];
1184 break;
1186 default:
1187 alSetError(pContext, AL_INVALID_ENUM);
1188 break;
1191 else
1192 alSetError(pContext, AL_INVALID_NAME);
1194 else
1195 alSetError(pContext, AL_INVALID_VALUE);
1197 ProcessContext(pContext);
1201 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1203 ALCcontext *pContext;
1204 ALsource *Source;
1205 ALdouble Offsets[2];
1206 ALdouble updateLen;
1208 pContext = GetContextSuspended();
1209 if(!pContext) return;
1211 if(plValues)
1213 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1215 switch(eParam)
1217 case AL_SOURCE_RELATIVE:
1218 case AL_CONE_INNER_ANGLE:
1219 case AL_CONE_OUTER_ANGLE:
1220 case AL_LOOPING:
1221 case AL_BUFFER:
1222 case AL_SOURCE_STATE:
1223 case AL_BUFFERS_QUEUED:
1224 case AL_BUFFERS_PROCESSED:
1225 case AL_SEC_OFFSET:
1226 case AL_SAMPLE_OFFSET:
1227 case AL_BYTE_OFFSET:
1228 case AL_MAX_DISTANCE:
1229 case AL_ROLLOFF_FACTOR:
1230 case AL_DOPPLER_FACTOR:
1231 case AL_REFERENCE_DISTANCE:
1232 case AL_SOURCE_TYPE:
1233 case AL_DIRECT_FILTER:
1234 case AL_DIRECT_FILTER_GAINHF_AUTO:
1235 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1236 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1237 case AL_DISTANCE_MODEL:
1238 alGetSourcei(source, eParam, plValues);
1239 break;
1241 case AL_SAMPLE_RW_OFFSETS_EXT:
1242 case AL_BYTE_RW_OFFSETS_EXT:
1243 updateLen = (ALdouble)pContext->Device->UpdateSize /
1244 pContext->Device->Frequency;
1245 GetSourceOffset(Source, eParam, Offsets, updateLen);
1246 plValues[0] = (ALint)Offsets[0];
1247 plValues[1] = (ALint)Offsets[1];
1248 break;
1250 case AL_POSITION:
1251 plValues[0] = (ALint)Source->vPosition[0];
1252 plValues[1] = (ALint)Source->vPosition[1];
1253 plValues[2] = (ALint)Source->vPosition[2];
1254 break;
1256 case AL_VELOCITY:
1257 plValues[0] = (ALint)Source->vVelocity[0];
1258 plValues[1] = (ALint)Source->vVelocity[1];
1259 plValues[2] = (ALint)Source->vVelocity[2];
1260 break;
1262 case AL_DIRECTION:
1263 plValues[0] = (ALint)Source->vOrientation[0];
1264 plValues[1] = (ALint)Source->vOrientation[1];
1265 plValues[2] = (ALint)Source->vOrientation[2];
1266 break;
1268 default:
1269 alSetError(pContext, AL_INVALID_ENUM);
1270 break;
1273 else
1274 alSetError(pContext, AL_INVALID_NAME);
1276 else
1277 alSetError(pContext, AL_INVALID_VALUE);
1279 ProcessContext(pContext);
1283 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1285 alSourcePlayv(1, &source);
1288 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1290 ALCcontext *Context;
1291 ALsource *Source;
1292 ALbufferlistitem *BufferList;
1293 ALsizei i, j;
1295 Context = GetContextSuspended();
1296 if(!Context) return;
1298 if(!sources)
1300 alSetError(Context, AL_INVALID_VALUE);
1301 goto done;
1304 // Check that all the Sources are valid
1305 for(i = 0;i < n;i++)
1307 if(!LookupSource(Context->SourceMap, sources[i]))
1309 alSetError(Context, AL_INVALID_NAME);
1310 goto done;
1314 for(i = 0;i < n;i++)
1316 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1318 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1319 BufferList = Source->queue;
1320 while(BufferList)
1322 if(BufferList->buffer != NULL && BufferList->buffer->size)
1323 break;
1324 BufferList = BufferList->next;
1327 if(!BufferList)
1329 Source->BuffersPlayed = Source->BuffersInQueue;
1330 continue;
1333 for(j = 0;j < OUTPUTCHANNELS;j++)
1334 Source->DryGains[j] = 0.0f;
1335 for(j = 0;j < MAX_SENDS;j++)
1336 Source->WetGains[j] = 0.0f;
1338 if(Source->state != AL_PAUSED)
1340 Source->state = AL_PLAYING;
1341 Source->position = 0;
1342 Source->position_fraction = 0;
1343 Source->BuffersPlayed = 0;
1345 Source->Buffer = Source->queue->buffer;
1347 else
1348 Source->state = AL_PLAYING;
1350 // Check if an Offset has been set
1351 if(Source->lOffset)
1352 ApplyOffset(Source);
1354 if(Source->BuffersPlayed == 0 && Source->position == 0 &&
1355 Source->position_fraction == 0)
1356 Source->FirstStart = AL_TRUE;
1357 else
1358 Source->FirstStart = AL_FALSE;
1360 // If device is disconnected, go right to stopped
1361 if(!Context->Device->Connected)
1363 Source->state = AL_STOPPED;
1364 Source->BuffersPlayed = Source->BuffersInQueue;
1365 Source->position = 0;
1366 Source->position_fraction = 0;
1370 done:
1371 ProcessContext(Context);
1374 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1376 alSourcePausev(1, &source);
1379 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1381 ALCcontext *Context;
1382 ALsource *Source;
1383 ALsizei i;
1385 Context = GetContextSuspended();
1386 if(!Context) return;
1388 if(!sources)
1390 alSetError(Context, AL_INVALID_VALUE);
1391 goto done;
1394 // Check all the Sources are valid
1395 for(i = 0;i < n;i++)
1397 if(!LookupSource(Context->SourceMap, sources[i]))
1399 alSetError(Context, AL_INVALID_NAME);
1400 goto done;
1404 for(i = 0;i < n;i++)
1406 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1407 if(Source->state == AL_PLAYING)
1408 Source->state = AL_PAUSED;
1411 done:
1412 ProcessContext(Context);
1415 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1417 alSourceStopv(1, &source);
1420 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1422 ALCcontext *Context;
1423 ALsource *Source;
1424 ALsizei i;
1426 Context = GetContextSuspended();
1427 if(!Context) return;
1429 if(!sources)
1431 alSetError(Context, AL_INVALID_VALUE);
1432 goto done;
1435 // Check all the Sources are valid
1436 for(i = 0;i < n;i++)
1438 if(!LookupSource(Context->SourceMap, sources[i]))
1440 alSetError(Context, AL_INVALID_NAME);
1441 goto done;
1445 for(i = 0;i < n;i++)
1447 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1448 if(Source->state != AL_INITIAL)
1450 Source->state = AL_STOPPED;
1451 Source->BuffersPlayed = Source->BuffersInQueue;
1453 Source->lOffset = 0;
1456 done:
1457 ProcessContext(Context);
1460 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1462 alSourceRewindv(1, &source);
1465 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1467 ALCcontext *Context;
1468 ALsource *Source;
1469 ALsizei i;
1471 Context = GetContextSuspended();
1472 if(!Context) return;
1474 if(!sources)
1476 alSetError(Context, AL_INVALID_VALUE);
1477 goto done;
1480 // Check all the Sources are valid
1481 for(i = 0;i < n;i++)
1483 if(!LookupSource(Context->SourceMap, sources[i]))
1485 alSetError(Context, AL_INVALID_NAME);
1486 goto done;
1490 for(i = 0;i < n;i++)
1492 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1493 if(Source->state != AL_INITIAL)
1495 Source->state = AL_INITIAL;
1496 Source->position = 0;
1497 Source->position_fraction = 0;
1498 Source->BuffersPlayed = 0;
1499 if(Source->queue)
1500 Source->Buffer = Source->queue->buffer;
1502 Source->lOffset = 0;
1505 done:
1506 ProcessContext(Context);
1510 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1512 ALCcontext *Context;
1513 ALCdevice *device;
1514 ALsource *Source;
1515 ALbuffer *buffer;
1516 ALsizei i;
1517 ALbufferlistitem *BufferListStart;
1518 ALbufferlistitem *BufferList;
1519 ALboolean HadFormat;
1520 ALint Frequency;
1521 ALint Format;
1523 if(n == 0)
1524 return;
1526 Context = GetContextSuspended();
1527 if(!Context) return;
1529 // Check that all buffers are valid or zero and that the source is valid
1531 // Check that this is a valid source
1532 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1534 alSetError(Context, AL_INVALID_NAME);
1535 goto done;
1538 // Check that this is not a STATIC Source
1539 if(Source->lSourceType == AL_STATIC)
1541 // Invalid Source Type (can't queue on a Static Source)
1542 alSetError(Context, AL_INVALID_OPERATION);
1543 goto done;
1546 device = Context->Device;
1548 Frequency = -1;
1549 Format = -1;
1550 HadFormat = AL_FALSE;
1552 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1553 BufferList = Source->queue;
1554 while(BufferList)
1556 if(BufferList->buffer)
1558 Frequency = BufferList->buffer->frequency;
1559 Format = BufferList->buffer->format;
1560 HadFormat = AL_TRUE;
1561 break;
1563 BufferList = BufferList->next;
1566 for(i = 0;i < n;i++)
1568 if(!buffers[i])
1569 continue;
1571 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1573 alSetError(Context, AL_INVALID_NAME);
1574 goto done;
1577 if(Frequency == -1 && Format == -1)
1579 Frequency = buffer->frequency;
1580 Format = buffer->format;
1582 else if(Frequency != buffer->frequency || Format != buffer->format)
1584 alSetError(Context, AL_INVALID_OPERATION);
1585 goto done;
1589 // Change Source Type
1590 Source->lSourceType = AL_STREAMING;
1592 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1594 // All buffers are valid - so add them to the list
1595 BufferListStart = malloc(sizeof(ALbufferlistitem));
1596 BufferListStart->buffer = buffer;
1597 BufferListStart->next = NULL;
1599 // Increment reference counter for buffer
1600 if(buffer) buffer->refcount++;
1602 BufferList = BufferListStart;
1604 for(i = 1;i < n;i++)
1606 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1608 BufferList->next = malloc(sizeof(ALbufferlistitem));
1609 BufferList->next->buffer = buffer;
1610 BufferList->next->next = NULL;
1612 // Increment reference counter for buffer
1613 if(buffer) buffer->refcount++;
1615 BufferList = BufferList->next;
1618 if(Source->queue == NULL)
1620 Source->queue = BufferListStart;
1621 // Update Current Buffer
1622 Source->Buffer = BufferListStart->buffer;
1624 else
1626 // Find end of queue
1627 BufferList = Source->queue;
1628 while(BufferList->next != NULL)
1629 BufferList = BufferList->next;
1631 BufferList->next = BufferListStart;
1634 // Update number of buffers in queue
1635 Source->BuffersInQueue += n;
1636 // If no previous format, mark the source dirty now that it may have one
1637 if(!HadFormat)
1638 Source->NeedsUpdate = AL_TRUE;
1640 done:
1641 ProcessContext(Context);
1645 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1646 // an array of buffer IDs that are to be filled with the names of the buffers removed
1647 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1649 ALCcontext *Context;
1650 ALsource *Source;
1651 ALsizei i;
1652 ALbufferlistitem *BufferList;
1654 if(n == 0)
1655 return;
1657 Context = GetContextSuspended();
1658 if(!Context) return;
1660 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1662 alSetError(Context, AL_INVALID_NAME);
1663 goto done;
1666 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1667 (ALuint)n > Source->BuffersPlayed)
1669 // Some buffers can't be unqueue because they have not been processed
1670 alSetError(Context, AL_INVALID_VALUE);
1671 goto done;
1674 for(i = 0;i < n;i++)
1676 BufferList = Source->queue;
1677 Source->queue = BufferList->next;
1679 if(BufferList->buffer)
1681 // Record name of buffer
1682 buffers[i] = BufferList->buffer->buffer;
1683 // Decrement buffer reference counter
1684 BufferList->buffer->refcount--;
1686 else
1687 buffers[i] = 0;
1689 // Release memory for buffer list item
1690 free(BufferList);
1691 Source->BuffersInQueue--;
1694 if(Source->state != AL_PLAYING)
1696 if(Source->queue)
1697 Source->Buffer = Source->queue->buffer;
1698 else
1699 Source->Buffer = NULL;
1701 Source->BuffersPlayed -= n;
1703 done:
1704 ProcessContext(Context);
1708 static ALvoid InitSourceParams(ALsource *Source)
1710 Source->flInnerAngle = 360.0f;
1711 Source->flOuterAngle = 360.0f;
1712 Source->flPitch = 1.0f;
1713 Source->vPosition[0] = 0.0f;
1714 Source->vPosition[1] = 0.0f;
1715 Source->vPosition[2] = 0.0f;
1716 Source->vOrientation[0] = 0.0f;
1717 Source->vOrientation[1] = 0.0f;
1718 Source->vOrientation[2] = 0.0f;
1719 Source->vVelocity[0] = 0.0f;
1720 Source->vVelocity[1] = 0.0f;
1721 Source->vVelocity[2] = 0.0f;
1722 Source->flRefDistance = 1.0f;
1723 Source->flMaxDistance = FLT_MAX;
1724 Source->flRollOffFactor = 1.0f;
1725 Source->bLooping = AL_FALSE;
1726 Source->flGain = 1.0f;
1727 Source->flMinGain = 0.0f;
1728 Source->flMaxGain = 1.0f;
1729 Source->flOuterGain = 0.0f;
1730 Source->OuterGainHF = 1.0f;
1732 Source->DryGainHFAuto = AL_TRUE;
1733 Source->WetGainAuto = AL_TRUE;
1734 Source->WetGainHFAuto = AL_TRUE;
1735 Source->AirAbsorptionFactor = 0.0f;
1736 Source->RoomRolloffFactor = 0.0f;
1737 Source->DopplerFactor = 1.0f;
1739 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1741 Source->Resampler = DefaultResampler;
1743 Source->state = AL_INITIAL;
1744 Source->lSourceType = AL_UNDETERMINED;
1746 Source->NeedsUpdate = AL_TRUE;
1748 Source->Buffer = NULL;
1753 GetSourceOffset
1755 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1756 The offset is relative to the start of the queue (not the start of the current buffer)
1758 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1760 ALbufferlistitem *BufferList;
1761 ALbuffer *Buffer = NULL;
1762 ALfloat BufferFreq;
1763 ALint Channels, Bytes;
1764 ALint readPos, writePos;
1765 ALenum OriginalFormat;
1766 ALint TotalBufferDataSize;
1767 ALuint i;
1769 // Find the first non-NULL Buffer in the Queue
1770 BufferList = Source->queue;
1771 while(BufferList)
1773 if(BufferList->buffer)
1775 Buffer = BufferList->buffer;
1776 break;
1778 BufferList = BufferList->next;
1781 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1783 offset[0] = 0.0f;
1784 offset[1] = 0.0f;
1785 return;
1788 // Get Current Buffer Size and frequency (in milliseconds)
1789 BufferFreq = (ALfloat)Buffer->frequency;
1790 OriginalFormat = Buffer->eOriginalFormat;
1791 Channels = aluChannelsFromFormat(Buffer->format);
1792 Bytes = aluBytesFromFormat(Buffer->format);
1794 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1795 readPos = Source->position * Channels * Bytes;
1796 // Add byte length of any processed buffers in the queue
1797 TotalBufferDataSize = 0;
1798 BufferList = Source->queue;
1799 for(i = 0;BufferList;i++)
1801 if(BufferList->buffer)
1803 if(i < Source->BuffersPlayed)
1804 readPos += BufferList->buffer->size;
1805 TotalBufferDataSize += BufferList->buffer->size;
1807 BufferList = BufferList->next;
1809 if(Source->state == AL_PLAYING)
1810 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1811 else
1812 writePos = readPos;
1814 if(Source->bLooping)
1816 readPos %= TotalBufferDataSize;
1817 writePos %= TotalBufferDataSize;
1819 else
1821 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1822 if(readPos < 0)
1823 readPos = 0;
1824 else if(readPos > TotalBufferDataSize)
1825 readPos = TotalBufferDataSize;
1826 if(writePos < 0)
1827 writePos = 0;
1828 else if(writePos > TotalBufferDataSize)
1829 writePos = TotalBufferDataSize;
1832 switch(name)
1834 case AL_SEC_OFFSET:
1835 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1836 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1837 break;
1838 case AL_SAMPLE_OFFSET:
1839 case AL_SAMPLE_RW_OFFSETS_EXT:
1840 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1841 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1842 break;
1843 case AL_BYTE_OFFSET:
1844 case AL_BYTE_RW_OFFSETS_EXT:
1845 // Take into account the original format of the Buffer
1846 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1847 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1849 // Round down to nearest ADPCM block
1850 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1851 if(Source->state == AL_PLAYING)
1853 // Round up to nearest ADPCM block
1854 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1856 else
1857 offset[1] = offset[0];
1859 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1860 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1861 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1862 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1863 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1864 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1866 offset[0] = (ALdouble)(readPos / Bytes * 1);
1867 offset[1] = (ALdouble)(writePos / Bytes * 1);
1869 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1871 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1872 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1874 else if(OriginalFormat == AL_FORMAT_REAR8)
1876 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1877 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1879 else if(OriginalFormat == AL_FORMAT_REAR16)
1881 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1882 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1884 else if(OriginalFormat == AL_FORMAT_REAR32)
1886 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1887 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1889 else
1891 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1892 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1893 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1895 break;
1901 ApplyOffset
1903 Apply a playback offset to the Source. This function will update the queue (to correctly
1904 mark buffers as 'pending' or 'processed' depending upon the new offset.
1906 static ALboolean ApplyOffset(ALsource *Source)
1908 ALbufferlistitem *BufferList;
1909 ALbuffer *Buffer;
1910 ALint lBufferSize, lTotalBufferSize;
1911 ALint BuffersPlayed;
1912 ALint lByteOffset;
1914 // Get true byte offset
1915 lByteOffset = GetByteOffset(Source);
1917 // If the offset is invalid, don't apply it
1918 if(lByteOffset == -1)
1919 return AL_FALSE;
1921 // Sort out the queue (pending and processed states)
1922 BufferList = Source->queue;
1923 lTotalBufferSize = 0;
1924 BuffersPlayed = 0;
1926 while(BufferList)
1928 Buffer = BufferList->buffer;
1929 lBufferSize = Buffer ? Buffer->size : 0;
1931 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1933 // Offset is past this buffer so increment BuffersPlayed
1934 BuffersPlayed++;
1936 else if(lTotalBufferSize <= lByteOffset)
1939 // Offset is within this buffer
1940 // Set Current Buffer
1941 Source->Buffer = BufferList->buffer;
1942 Source->BuffersPlayed = BuffersPlayed;
1944 // SW Mixer Positions are in Samples
1945 Source->position = (lByteOffset - lTotalBufferSize) /
1946 aluBytesFromFormat(Buffer->format) /
1947 aluChannelsFromFormat(Buffer->format);
1948 return AL_TRUE;
1951 // Increment the TotalBufferSize
1952 lTotalBufferSize += lBufferSize;
1954 // Move on to next buffer in the Queue
1955 BufferList = BufferList->next;
1957 // Offset is out of range of the buffer queue
1958 return AL_FALSE;
1963 GetByteOffset
1965 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1966 offset supplied by the application). This takes into account the fact that the buffer format
1967 may have been modifed by AL (e.g 8bit samples are converted to float)
1969 static ALint GetByteOffset(ALsource *Source)
1971 ALbuffer *Buffer = NULL;
1972 ALbufferlistitem *BufferList;
1973 ALfloat BufferFreq;
1974 ALint Channels, Bytes;
1975 ALint ByteOffset = -1;
1977 // Find the first non-NULL Buffer in the Queue
1978 BufferList = Source->queue;
1979 while(BufferList)
1981 if(BufferList->buffer)
1983 Buffer = BufferList->buffer;
1984 break;
1986 BufferList = BufferList->next;
1989 if(!Buffer)
1991 Source->lOffset = 0;
1992 return -1;
1995 BufferFreq = ((ALfloat)Buffer->frequency);
1996 Channels = aluChannelsFromFormat(Buffer->format);
1997 Bytes = aluBytesFromFormat(Buffer->format);
1999 // Determine the ByteOffset (and ensure it is block aligned)
2000 switch(Source->lOffsetType)
2002 case AL_BYTE_OFFSET:
2003 // Take into consideration the original format
2004 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2005 Channels);
2006 ByteOffset *= Channels * Bytes;
2007 break;
2009 case AL_SAMPLE_OFFSET:
2010 ByteOffset = Source->lOffset * Channels * Bytes;
2011 break;
2013 case AL_SEC_OFFSET:
2014 // Note - lOffset is internally stored as Milliseconds
2015 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2016 ByteOffset *= Channels * Bytes;
2017 break;
2019 // Clear Offset
2020 Source->lOffset = 0;
2022 return ByteOffset;
2025 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2027 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2029 // Round down to nearest ADPCM block
2030 offset /= 36 * channels;
2031 // Multiply by compression rate (65 sample frames per block)
2032 offset *= 65;
2034 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2035 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2036 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2038 /* muLaw has 1 byte per sample */
2039 offset /= 1 * channels;
2041 else if(format == AL_FORMAT_REAR_MULAW)
2043 /* Rear is 2 channels */
2044 offset /= 1 * 2;
2046 else if(format == AL_FORMAT_REAR8)
2047 offset /= 1 * 2;
2048 else if(format == AL_FORMAT_REAR16)
2049 offset /= 2 * 2;
2050 else if(format == AL_FORMAT_REAR32)
2051 offset /= 4 * 2;
2052 else
2054 ALuint bytes = aluBytesFromFormat(format);
2055 offset /= bytes * channels;
2057 return offset;
2061 ALvoid ReleaseALSources(ALCcontext *Context)
2063 ALsizei pos;
2064 ALuint j;
2065 for(pos = 0;pos < Context->SourceMap.size;pos++)
2067 ALsource *temp = Context->SourceMap.array[pos].value;
2068 Context->SourceMap.array[pos].value = NULL;
2070 // For each buffer in the source's queue, decrement its reference counter and remove it
2071 while(temp->queue != NULL)
2073 ALbufferlistitem *BufferList = temp->queue;
2074 // Decrement buffer's reference counter
2075 if(BufferList->buffer != NULL)
2076 BufferList->buffer->refcount--;
2077 // Update queue to point to next element in list
2078 temp->queue = BufferList->next;
2079 // Release memory allocated for buffer list item
2080 free(BufferList);
2083 for(j = 0;j < MAX_SENDS;++j)
2085 if(temp->Send[j].Slot)
2086 temp->Send[j].Slot->refcount--;
2089 // Release source structure
2090 ALTHUNK_REMOVEENTRY(temp->source);
2091 memset(temp, 0, sizeof(ALsource));
2092 free(temp);