Loop points should be specified in sample offsets
[openal-soft/android/lowlatency.git] / OpenAL32 / alSource.c
blob139eb75b117143b60332a163fbf809099b6abc6e
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 Source->LoopStart = buffer->LoopStart;
568 Source->LoopEnd = buffer->LoopEnd;
570 // Increment reference counter for buffer
571 buffer->refcount++;
573 else
575 // Source is now in UNDETERMINED mode
576 Source->lSourceType = AL_UNDETERMINED;
578 Source->BuffersPlayed = 0;
580 // Update AL_BUFFER parameter
581 Source->Buffer = buffer;
582 Source->NeedsUpdate = AL_TRUE;
584 else
585 alSetError(pContext, AL_INVALID_VALUE);
587 else
588 alSetError(pContext, AL_INVALID_OPERATION);
589 break;
591 case AL_SOURCE_STATE:
592 // Query only
593 alSetError(pContext, AL_INVALID_OPERATION);
594 break;
596 case AL_SEC_OFFSET:
597 case AL_SAMPLE_OFFSET:
598 case AL_BYTE_OFFSET:
599 if(lValue >= 0)
601 Source->lOffsetType = eParam;
603 // Store Offset (convert Seconds into Milliseconds)
604 if(eParam == AL_SEC_OFFSET)
605 Source->lOffset = lValue * 1000;
606 else
607 Source->lOffset = lValue;
609 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
611 if(ApplyOffset(Source) == AL_FALSE)
612 alSetError(pContext, AL_INVALID_VALUE);
615 else
616 alSetError(pContext, AL_INVALID_VALUE);
617 break;
619 case AL_DIRECT_FILTER: {
620 ALfilter *filter = NULL;
622 if(lValue == 0 ||
623 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
625 if(!filter)
627 Source->DirectFilter.type = AL_FILTER_NULL;
628 Source->DirectFilter.filter = 0;
630 else
631 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
632 Source->NeedsUpdate = AL_TRUE;
634 else
635 alSetError(pContext, AL_INVALID_VALUE);
636 } break;
638 case AL_DIRECT_FILTER_GAINHF_AUTO:
639 if(lValue == AL_TRUE || lValue == AL_FALSE)
641 Source->DryGainHFAuto = lValue;
642 Source->NeedsUpdate = AL_TRUE;
644 else
645 alSetError(pContext, AL_INVALID_VALUE);
646 break;
648 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
649 if(lValue == AL_TRUE || lValue == AL_FALSE)
651 Source->WetGainAuto = lValue;
652 Source->NeedsUpdate = AL_TRUE;
654 else
655 alSetError(pContext, AL_INVALID_VALUE);
656 break;
658 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
659 if(lValue == AL_TRUE || lValue == AL_FALSE)
661 Source->WetGainHFAuto = lValue;
662 Source->NeedsUpdate = AL_TRUE;
664 else
665 alSetError(pContext, AL_INVALID_VALUE);
666 break;
668 case AL_DISTANCE_MODEL:
669 if(lValue == AL_NONE ||
670 lValue == AL_INVERSE_DISTANCE ||
671 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
672 lValue == AL_LINEAR_DISTANCE ||
673 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
674 lValue == AL_EXPONENT_DISTANCE ||
675 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
677 Source->DistanceModel = lValue;
678 if(pContext->SourceDistanceModel)
679 Source->NeedsUpdate = AL_TRUE;
681 else
682 alSetError(pContext, AL_INVALID_VALUE);
683 break;
685 default:
686 alSetError(pContext, AL_INVALID_ENUM);
687 break;
690 else
691 alSetError(pContext, AL_INVALID_NAME);
693 ProcessContext(pContext);
697 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
699 ALCcontext *pContext;
700 ALsource *Source;
702 pContext = GetContextSuspended();
703 if(!pContext) return;
705 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
707 ALCdevice *device = pContext->Device;
709 switch (eParam)
711 case AL_POSITION:
712 case AL_VELOCITY:
713 case AL_DIRECTION:
714 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
715 break;
717 case AL_AUXILIARY_SEND_FILTER: {
718 ALeffectslot *ALEffectSlot = NULL;
719 ALfilter *ALFilter = NULL;
721 if((ALuint)lValue2 < device->NumAuxSends &&
722 (lValue1 == 0 ||
723 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
724 (lValue3 == 0 ||
725 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
727 /* Release refcount on the previous slot, and add one for
728 * the new slot */
729 if(Source->Send[lValue2].Slot)
730 Source->Send[lValue2].Slot->refcount--;
731 Source->Send[lValue2].Slot = ALEffectSlot;
732 if(Source->Send[lValue2].Slot)
733 Source->Send[lValue2].Slot->refcount++;
735 if(!ALFilter)
737 /* Disable filter */
738 Source->Send[lValue2].WetFilter.type = 0;
739 Source->Send[lValue2].WetFilter.filter = 0;
741 else
742 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
743 Source->NeedsUpdate = AL_TRUE;
745 else
746 alSetError(pContext, AL_INVALID_VALUE);
747 } break;
749 default:
750 alSetError(pContext, AL_INVALID_ENUM);
751 break;
754 else
755 alSetError(pContext, AL_INVALID_NAME);
757 ProcessContext(pContext);
761 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
763 ALCcontext *pContext;
765 pContext = GetContextSuspended();
766 if(!pContext) return;
768 if(plValues)
770 if(LookupSource(pContext->SourceMap, source) != NULL)
772 switch(eParam)
774 case AL_SOURCE_RELATIVE:
775 case AL_CONE_INNER_ANGLE:
776 case AL_CONE_OUTER_ANGLE:
777 case AL_LOOPING:
778 case AL_BUFFER:
779 case AL_SOURCE_STATE:
780 case AL_SEC_OFFSET:
781 case AL_SAMPLE_OFFSET:
782 case AL_BYTE_OFFSET:
783 case AL_MAX_DISTANCE:
784 case AL_ROLLOFF_FACTOR:
785 case AL_REFERENCE_DISTANCE:
786 case AL_DIRECT_FILTER:
787 case AL_DIRECT_FILTER_GAINHF_AUTO:
788 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
789 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
790 case AL_DISTANCE_MODEL:
791 alSourcei(source, eParam, plValues[0]);
792 break;
794 case AL_POSITION:
795 case AL_VELOCITY:
796 case AL_DIRECTION:
797 case AL_AUXILIARY_SEND_FILTER:
798 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
799 break;
801 default:
802 alSetError(pContext, AL_INVALID_ENUM);
803 break;
806 else
807 alSetError(pContext, AL_INVALID_NAME);
809 else
810 alSetError(pContext, AL_INVALID_VALUE);
812 ProcessContext(pContext);
816 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
818 ALCcontext *pContext;
819 ALsource *Source;
820 ALdouble Offsets[2];
821 ALdouble updateLen;
823 pContext = GetContextSuspended();
824 if(!pContext) return;
826 if(pflValue)
828 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
830 switch(eParam)
832 case AL_PITCH:
833 *pflValue = Source->flPitch;
834 break;
836 case AL_GAIN:
837 *pflValue = Source->flGain;
838 break;
840 case AL_MIN_GAIN:
841 *pflValue = Source->flMinGain;
842 break;
844 case AL_MAX_GAIN:
845 *pflValue = Source->flMaxGain;
846 break;
848 case AL_MAX_DISTANCE:
849 *pflValue = Source->flMaxDistance;
850 break;
852 case AL_ROLLOFF_FACTOR:
853 *pflValue = Source->flRollOffFactor;
854 break;
856 case AL_CONE_OUTER_GAIN:
857 *pflValue = Source->flOuterGain;
858 break;
860 case AL_CONE_OUTER_GAINHF:
861 *pflValue = Source->OuterGainHF;
862 break;
864 case AL_SEC_OFFSET:
865 case AL_SAMPLE_OFFSET:
866 case AL_BYTE_OFFSET:
867 updateLen = (ALdouble)pContext->Device->UpdateSize /
868 pContext->Device->Frequency;
869 GetSourceOffset(Source, eParam, Offsets, updateLen);
870 *pflValue = Offsets[0];
871 break;
873 case AL_CONE_INNER_ANGLE:
874 *pflValue = Source->flInnerAngle;
875 break;
877 case AL_CONE_OUTER_ANGLE:
878 *pflValue = Source->flOuterAngle;
879 break;
881 case AL_REFERENCE_DISTANCE:
882 *pflValue = Source->flRefDistance;
883 break;
885 case AL_AIR_ABSORPTION_FACTOR:
886 *pflValue = Source->AirAbsorptionFactor;
887 break;
889 case AL_ROOM_ROLLOFF_FACTOR:
890 *pflValue = Source->RoomRolloffFactor;
891 break;
893 case AL_DOPPLER_FACTOR:
894 *pflValue = Source->DopplerFactor;
895 break;
897 default:
898 alSetError(pContext, AL_INVALID_ENUM);
899 break;
902 else
903 alSetError(pContext, AL_INVALID_NAME);
905 else
906 alSetError(pContext, AL_INVALID_VALUE);
908 ProcessContext(pContext);
912 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
914 ALCcontext *pContext;
915 ALsource *Source;
917 pContext = GetContextSuspended();
918 if(!pContext) return;
920 if(pflValue1 && pflValue2 && pflValue3)
922 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
924 switch(eParam)
926 case AL_POSITION:
927 *pflValue1 = Source->vPosition[0];
928 *pflValue2 = Source->vPosition[1];
929 *pflValue3 = Source->vPosition[2];
930 break;
932 case AL_VELOCITY:
933 *pflValue1 = Source->vVelocity[0];
934 *pflValue2 = Source->vVelocity[1];
935 *pflValue3 = Source->vVelocity[2];
936 break;
938 case AL_DIRECTION:
939 *pflValue1 = Source->vOrientation[0];
940 *pflValue2 = Source->vOrientation[1];
941 *pflValue3 = Source->vOrientation[2];
942 break;
944 default:
945 alSetError(pContext, AL_INVALID_ENUM);
946 break;
949 else
950 alSetError(pContext, AL_INVALID_NAME);
952 else
953 alSetError(pContext, AL_INVALID_VALUE);
955 ProcessContext(pContext);
959 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
961 ALCcontext *pContext;
962 ALsource *Source;
963 ALdouble Offsets[2];
964 ALdouble updateLen;
966 pContext = GetContextSuspended();
967 if(!pContext) return;
969 if(pflValues)
971 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
973 switch(eParam)
975 case AL_PITCH:
976 case AL_GAIN:
977 case AL_MIN_GAIN:
978 case AL_MAX_GAIN:
979 case AL_MAX_DISTANCE:
980 case AL_ROLLOFF_FACTOR:
981 case AL_DOPPLER_FACTOR:
982 case AL_CONE_OUTER_GAIN:
983 case AL_SEC_OFFSET:
984 case AL_SAMPLE_OFFSET:
985 case AL_BYTE_OFFSET:
986 case AL_CONE_INNER_ANGLE:
987 case AL_CONE_OUTER_ANGLE:
988 case AL_REFERENCE_DISTANCE:
989 case AL_CONE_OUTER_GAINHF:
990 case AL_AIR_ABSORPTION_FACTOR:
991 case AL_ROOM_ROLLOFF_FACTOR:
992 alGetSourcef(source, eParam, pflValues);
993 break;
995 case AL_SAMPLE_RW_OFFSETS_EXT:
996 case AL_BYTE_RW_OFFSETS_EXT:
997 updateLen = (ALdouble)pContext->Device->UpdateSize /
998 pContext->Device->Frequency;
999 GetSourceOffset(Source, eParam, Offsets, updateLen);
1000 pflValues[0] = Offsets[0];
1001 pflValues[1] = Offsets[1];
1002 break;
1004 case AL_POSITION:
1005 pflValues[0] = Source->vPosition[0];
1006 pflValues[1] = Source->vPosition[1];
1007 pflValues[2] = Source->vPosition[2];
1008 break;
1010 case AL_VELOCITY:
1011 pflValues[0] = Source->vVelocity[0];
1012 pflValues[1] = Source->vVelocity[1];
1013 pflValues[2] = Source->vVelocity[2];
1014 break;
1016 case AL_DIRECTION:
1017 pflValues[0] = Source->vOrientation[0];
1018 pflValues[1] = Source->vOrientation[1];
1019 pflValues[2] = Source->vOrientation[2];
1020 break;
1022 default:
1023 alSetError(pContext, AL_INVALID_ENUM);
1024 break;
1027 else
1028 alSetError(pContext, AL_INVALID_NAME);
1030 else
1031 alSetError(pContext, AL_INVALID_VALUE);
1033 ProcessContext(pContext);
1037 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1039 ALCcontext *pContext;
1040 ALsource *Source;
1041 ALdouble Offsets[2];
1042 ALdouble updateLen;
1044 pContext = GetContextSuspended();
1045 if(!pContext) return;
1047 if(plValue)
1049 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1051 switch(eParam)
1053 case AL_MAX_DISTANCE:
1054 *plValue = (ALint)Source->flMaxDistance;
1055 break;
1057 case AL_ROLLOFF_FACTOR:
1058 *plValue = (ALint)Source->flRollOffFactor;
1059 break;
1061 case AL_REFERENCE_DISTANCE:
1062 *plValue = (ALint)Source->flRefDistance;
1063 break;
1065 case AL_SOURCE_RELATIVE:
1066 *plValue = Source->bHeadRelative;
1067 break;
1069 case AL_CONE_INNER_ANGLE:
1070 *plValue = (ALint)Source->flInnerAngle;
1071 break;
1073 case AL_CONE_OUTER_ANGLE:
1074 *plValue = (ALint)Source->flOuterAngle;
1075 break;
1077 case AL_LOOPING:
1078 *plValue = Source->bLooping;
1079 break;
1081 case AL_BUFFER:
1082 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1083 break;
1085 case AL_SOURCE_STATE:
1086 *plValue = Source->state;
1087 break;
1089 case AL_BUFFERS_QUEUED:
1090 *plValue = Source->BuffersInQueue;
1091 break;
1093 case AL_BUFFERS_PROCESSED:
1094 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1096 /* Buffers on a looping source are in a perpetual state
1097 * of PENDING, so don't report any as PROCESSED */
1098 *plValue = 0;
1100 else
1101 *plValue = Source->BuffersPlayed;
1102 break;
1104 case AL_SOURCE_TYPE:
1105 *plValue = Source->lSourceType;
1106 break;
1108 case AL_SEC_OFFSET:
1109 case AL_SAMPLE_OFFSET:
1110 case AL_BYTE_OFFSET:
1111 updateLen = (ALdouble)pContext->Device->UpdateSize /
1112 pContext->Device->Frequency;
1113 GetSourceOffset(Source, eParam, Offsets, updateLen);
1114 *plValue = (ALint)Offsets[0];
1115 break;
1117 case AL_DIRECT_FILTER:
1118 *plValue = Source->DirectFilter.filter;
1119 break;
1121 case AL_DIRECT_FILTER_GAINHF_AUTO:
1122 *plValue = Source->DryGainHFAuto;
1123 break;
1125 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1126 *plValue = Source->WetGainAuto;
1127 break;
1129 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1130 *plValue = Source->WetGainHFAuto;
1131 break;
1133 case AL_DOPPLER_FACTOR:
1134 *plValue = (ALint)Source->DopplerFactor;
1135 break;
1137 case AL_DISTANCE_MODEL:
1138 *plValue = Source->DistanceModel;
1139 break;
1141 default:
1142 alSetError(pContext, AL_INVALID_ENUM);
1143 break;
1146 else
1147 alSetError(pContext, AL_INVALID_NAME);
1149 else
1150 alSetError(pContext, AL_INVALID_VALUE);
1152 ProcessContext(pContext);
1156 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1158 ALCcontext *pContext;
1159 ALsource *Source;
1161 pContext = GetContextSuspended();
1162 if(!pContext) return;
1164 if(plValue1 && plValue2 && plValue3)
1166 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1168 switch(eParam)
1170 case AL_POSITION:
1171 *plValue1 = (ALint)Source->vPosition[0];
1172 *plValue2 = (ALint)Source->vPosition[1];
1173 *plValue3 = (ALint)Source->vPosition[2];
1174 break;
1176 case AL_VELOCITY:
1177 *plValue1 = (ALint)Source->vVelocity[0];
1178 *plValue2 = (ALint)Source->vVelocity[1];
1179 *plValue3 = (ALint)Source->vVelocity[2];
1180 break;
1182 case AL_DIRECTION:
1183 *plValue1 = (ALint)Source->vOrientation[0];
1184 *plValue2 = (ALint)Source->vOrientation[1];
1185 *plValue3 = (ALint)Source->vOrientation[2];
1186 break;
1188 default:
1189 alSetError(pContext, AL_INVALID_ENUM);
1190 break;
1193 else
1194 alSetError(pContext, AL_INVALID_NAME);
1196 else
1197 alSetError(pContext, AL_INVALID_VALUE);
1199 ProcessContext(pContext);
1203 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1205 ALCcontext *pContext;
1206 ALsource *Source;
1207 ALdouble Offsets[2];
1208 ALdouble updateLen;
1210 pContext = GetContextSuspended();
1211 if(!pContext) return;
1213 if(plValues)
1215 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1217 switch(eParam)
1219 case AL_SOURCE_RELATIVE:
1220 case AL_CONE_INNER_ANGLE:
1221 case AL_CONE_OUTER_ANGLE:
1222 case AL_LOOPING:
1223 case AL_BUFFER:
1224 case AL_SOURCE_STATE:
1225 case AL_BUFFERS_QUEUED:
1226 case AL_BUFFERS_PROCESSED:
1227 case AL_SEC_OFFSET:
1228 case AL_SAMPLE_OFFSET:
1229 case AL_BYTE_OFFSET:
1230 case AL_MAX_DISTANCE:
1231 case AL_ROLLOFF_FACTOR:
1232 case AL_DOPPLER_FACTOR:
1233 case AL_REFERENCE_DISTANCE:
1234 case AL_SOURCE_TYPE:
1235 case AL_DIRECT_FILTER:
1236 case AL_DIRECT_FILTER_GAINHF_AUTO:
1237 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1238 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1239 case AL_DISTANCE_MODEL:
1240 alGetSourcei(source, eParam, plValues);
1241 break;
1243 case AL_SAMPLE_RW_OFFSETS_EXT:
1244 case AL_BYTE_RW_OFFSETS_EXT:
1245 updateLen = (ALdouble)pContext->Device->UpdateSize /
1246 pContext->Device->Frequency;
1247 GetSourceOffset(Source, eParam, Offsets, updateLen);
1248 plValues[0] = (ALint)Offsets[0];
1249 plValues[1] = (ALint)Offsets[1];
1250 break;
1252 case AL_POSITION:
1253 plValues[0] = (ALint)Source->vPosition[0];
1254 plValues[1] = (ALint)Source->vPosition[1];
1255 plValues[2] = (ALint)Source->vPosition[2];
1256 break;
1258 case AL_VELOCITY:
1259 plValues[0] = (ALint)Source->vVelocity[0];
1260 plValues[1] = (ALint)Source->vVelocity[1];
1261 plValues[2] = (ALint)Source->vVelocity[2];
1262 break;
1264 case AL_DIRECTION:
1265 plValues[0] = (ALint)Source->vOrientation[0];
1266 plValues[1] = (ALint)Source->vOrientation[1];
1267 plValues[2] = (ALint)Source->vOrientation[2];
1268 break;
1270 default:
1271 alSetError(pContext, AL_INVALID_ENUM);
1272 break;
1275 else
1276 alSetError(pContext, AL_INVALID_NAME);
1278 else
1279 alSetError(pContext, AL_INVALID_VALUE);
1281 ProcessContext(pContext);
1285 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1287 alSourcePlayv(1, &source);
1290 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1292 ALCcontext *Context;
1293 ALsource *Source;
1294 ALbufferlistitem *BufferList;
1295 ALsizei i, j;
1297 Context = GetContextSuspended();
1298 if(!Context) return;
1300 if(!sources)
1302 alSetError(Context, AL_INVALID_VALUE);
1303 goto done;
1306 // Check that all the Sources are valid
1307 for(i = 0;i < n;i++)
1309 if(!LookupSource(Context->SourceMap, sources[i]))
1311 alSetError(Context, AL_INVALID_NAME);
1312 goto done;
1316 for(i = 0;i < n;i++)
1318 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1320 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1321 BufferList = Source->queue;
1322 while(BufferList)
1324 if(BufferList->buffer != NULL && BufferList->buffer->size)
1325 break;
1326 BufferList = BufferList->next;
1329 if(!BufferList)
1331 Source->BuffersPlayed = Source->BuffersInQueue;
1332 continue;
1335 for(j = 0;j < OUTPUTCHANNELS;j++)
1336 Source->DryGains[j] = 0.0f;
1337 for(j = 0;j < MAX_SENDS;j++)
1338 Source->WetGains[j] = 0.0f;
1340 if(Source->state != AL_PAUSED)
1342 Source->state = AL_PLAYING;
1343 Source->position = 0;
1344 Source->position_fraction = 0;
1345 Source->BuffersPlayed = 0;
1347 Source->Buffer = Source->queue->buffer;
1349 else
1350 Source->state = AL_PLAYING;
1352 // Check if an Offset has been set
1353 if(Source->lOffset)
1354 ApplyOffset(Source);
1356 if(Source->BuffersPlayed == 0 && Source->position == 0 &&
1357 Source->position_fraction == 0)
1358 Source->FirstStart = AL_TRUE;
1359 else
1360 Source->FirstStart = AL_FALSE;
1362 // If device is disconnected, go right to stopped
1363 if(!Context->Device->Connected)
1365 Source->state = AL_STOPPED;
1366 Source->BuffersPlayed = Source->BuffersInQueue;
1367 Source->position = 0;
1368 Source->position_fraction = 0;
1372 done:
1373 ProcessContext(Context);
1376 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1378 alSourcePausev(1, &source);
1381 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1383 ALCcontext *Context;
1384 ALsource *Source;
1385 ALsizei i;
1387 Context = GetContextSuspended();
1388 if(!Context) return;
1390 if(!sources)
1392 alSetError(Context, AL_INVALID_VALUE);
1393 goto done;
1396 // Check all the Sources are valid
1397 for(i = 0;i < n;i++)
1399 if(!LookupSource(Context->SourceMap, sources[i]))
1401 alSetError(Context, AL_INVALID_NAME);
1402 goto done;
1406 for(i = 0;i < n;i++)
1408 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1409 if(Source->state == AL_PLAYING)
1410 Source->state = AL_PAUSED;
1413 done:
1414 ProcessContext(Context);
1417 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1419 alSourceStopv(1, &source);
1422 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1424 ALCcontext *Context;
1425 ALsource *Source;
1426 ALsizei i;
1428 Context = GetContextSuspended();
1429 if(!Context) return;
1431 if(!sources)
1433 alSetError(Context, AL_INVALID_VALUE);
1434 goto done;
1437 // Check all the Sources are valid
1438 for(i = 0;i < n;i++)
1440 if(!LookupSource(Context->SourceMap, sources[i]))
1442 alSetError(Context, AL_INVALID_NAME);
1443 goto done;
1447 for(i = 0;i < n;i++)
1449 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1450 if(Source->state != AL_INITIAL)
1452 Source->state = AL_STOPPED;
1453 Source->BuffersPlayed = Source->BuffersInQueue;
1455 Source->lOffset = 0;
1458 done:
1459 ProcessContext(Context);
1462 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1464 alSourceRewindv(1, &source);
1467 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1469 ALCcontext *Context;
1470 ALsource *Source;
1471 ALsizei i;
1473 Context = GetContextSuspended();
1474 if(!Context) return;
1476 if(!sources)
1478 alSetError(Context, AL_INVALID_VALUE);
1479 goto done;
1482 // Check all the Sources are valid
1483 for(i = 0;i < n;i++)
1485 if(!LookupSource(Context->SourceMap, sources[i]))
1487 alSetError(Context, AL_INVALID_NAME);
1488 goto done;
1492 for(i = 0;i < n;i++)
1494 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1495 if(Source->state != AL_INITIAL)
1497 Source->state = AL_INITIAL;
1498 Source->position = 0;
1499 Source->position_fraction = 0;
1500 Source->BuffersPlayed = 0;
1501 if(Source->queue)
1502 Source->Buffer = Source->queue->buffer;
1504 Source->lOffset = 0;
1507 done:
1508 ProcessContext(Context);
1512 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1514 ALCcontext *Context;
1515 ALCdevice *device;
1516 ALsource *Source;
1517 ALbuffer *buffer;
1518 ALsizei i;
1519 ALbufferlistitem *BufferListStart;
1520 ALbufferlistitem *BufferList;
1521 ALboolean HadFormat;
1522 ALint Frequency;
1523 ALint Format;
1525 if(n == 0)
1526 return;
1528 Context = GetContextSuspended();
1529 if(!Context) return;
1531 // Check that all buffers are valid or zero and that the source is valid
1533 // Check that this is a valid source
1534 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1536 alSetError(Context, AL_INVALID_NAME);
1537 goto done;
1540 // Check that this is not a STATIC Source
1541 if(Source->lSourceType == AL_STATIC)
1543 // Invalid Source Type (can't queue on a Static Source)
1544 alSetError(Context, AL_INVALID_OPERATION);
1545 goto done;
1548 device = Context->Device;
1550 Frequency = -1;
1551 Format = -1;
1552 HadFormat = AL_FALSE;
1554 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1555 BufferList = Source->queue;
1556 while(BufferList)
1558 if(BufferList->buffer)
1560 Frequency = BufferList->buffer->frequency;
1561 Format = BufferList->buffer->format;
1562 HadFormat = AL_TRUE;
1563 break;
1565 BufferList = BufferList->next;
1568 for(i = 0;i < n;i++)
1570 if(!buffers[i])
1571 continue;
1573 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1575 alSetError(Context, AL_INVALID_NAME);
1576 goto done;
1579 if(Frequency == -1 && Format == -1)
1581 Frequency = buffer->frequency;
1582 Format = buffer->format;
1584 else if(Frequency != buffer->frequency || Format != buffer->format)
1586 alSetError(Context, AL_INVALID_OPERATION);
1587 goto done;
1591 // Change Source Type
1592 Source->lSourceType = AL_STREAMING;
1594 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1596 // All buffers are valid - so add them to the list
1597 BufferListStart = malloc(sizeof(ALbufferlistitem));
1598 BufferListStart->buffer = buffer;
1599 BufferListStart->next = NULL;
1601 // Increment reference counter for buffer
1602 if(buffer) buffer->refcount++;
1604 BufferList = BufferListStart;
1606 for(i = 1;i < n;i++)
1608 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1610 BufferList->next = malloc(sizeof(ALbufferlistitem));
1611 BufferList->next->buffer = buffer;
1612 BufferList->next->next = NULL;
1614 // Increment reference counter for buffer
1615 if(buffer) buffer->refcount++;
1617 BufferList = BufferList->next;
1620 if(Source->queue == NULL)
1622 Source->queue = BufferListStart;
1623 // Update Current Buffer
1624 Source->Buffer = BufferListStart->buffer;
1626 else
1628 // Find end of queue
1629 BufferList = Source->queue;
1630 while(BufferList->next != NULL)
1631 BufferList = BufferList->next;
1633 BufferList->next = BufferListStart;
1636 // Update number of buffers in queue
1637 Source->BuffersInQueue += n;
1638 // If no previous format, mark the source dirty now that it may have one
1639 if(!HadFormat)
1640 Source->NeedsUpdate = AL_TRUE;
1642 done:
1643 ProcessContext(Context);
1647 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1648 // an array of buffer IDs that are to be filled with the names of the buffers removed
1649 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1651 ALCcontext *Context;
1652 ALsource *Source;
1653 ALsizei i;
1654 ALbufferlistitem *BufferList;
1656 if(n == 0)
1657 return;
1659 Context = GetContextSuspended();
1660 if(!Context) return;
1662 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1664 alSetError(Context, AL_INVALID_NAME);
1665 goto done;
1668 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1669 (ALuint)n > Source->BuffersPlayed)
1671 // Some buffers can't be unqueue because they have not been processed
1672 alSetError(Context, AL_INVALID_VALUE);
1673 goto done;
1676 for(i = 0;i < n;i++)
1678 BufferList = Source->queue;
1679 Source->queue = BufferList->next;
1681 if(BufferList->buffer)
1683 // Record name of buffer
1684 buffers[i] = BufferList->buffer->buffer;
1685 // Decrement buffer reference counter
1686 BufferList->buffer->refcount--;
1688 else
1689 buffers[i] = 0;
1691 // Release memory for buffer list item
1692 free(BufferList);
1693 Source->BuffersInQueue--;
1696 if(Source->state != AL_PLAYING)
1698 if(Source->queue)
1699 Source->Buffer = Source->queue->buffer;
1700 else
1701 Source->Buffer = NULL;
1703 Source->BuffersPlayed -= n;
1705 done:
1706 ProcessContext(Context);
1710 static ALvoid InitSourceParams(ALsource *Source)
1712 Source->flInnerAngle = 360.0f;
1713 Source->flOuterAngle = 360.0f;
1714 Source->flPitch = 1.0f;
1715 Source->vPosition[0] = 0.0f;
1716 Source->vPosition[1] = 0.0f;
1717 Source->vPosition[2] = 0.0f;
1718 Source->vOrientation[0] = 0.0f;
1719 Source->vOrientation[1] = 0.0f;
1720 Source->vOrientation[2] = 0.0f;
1721 Source->vVelocity[0] = 0.0f;
1722 Source->vVelocity[1] = 0.0f;
1723 Source->vVelocity[2] = 0.0f;
1724 Source->flRefDistance = 1.0f;
1725 Source->flMaxDistance = FLT_MAX;
1726 Source->flRollOffFactor = 1.0f;
1727 Source->bLooping = AL_FALSE;
1728 Source->flGain = 1.0f;
1729 Source->flMinGain = 0.0f;
1730 Source->flMaxGain = 1.0f;
1731 Source->flOuterGain = 0.0f;
1732 Source->OuterGainHF = 1.0f;
1734 Source->DryGainHFAuto = AL_TRUE;
1735 Source->WetGainAuto = AL_TRUE;
1736 Source->WetGainHFAuto = AL_TRUE;
1737 Source->AirAbsorptionFactor = 0.0f;
1738 Source->RoomRolloffFactor = 0.0f;
1739 Source->DopplerFactor = 1.0f;
1741 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1743 Source->Resampler = DefaultResampler;
1745 Source->state = AL_INITIAL;
1746 Source->lSourceType = AL_UNDETERMINED;
1748 Source->NeedsUpdate = AL_TRUE;
1750 Source->Buffer = NULL;
1755 GetSourceOffset
1757 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1758 The offset is relative to the start of the queue (not the start of the current buffer)
1760 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1762 ALbufferlistitem *BufferList;
1763 ALbuffer *Buffer = NULL;
1764 ALfloat BufferFreq;
1765 ALint Channels, Bytes;
1766 ALuint readPos, writePos;
1767 ALenum OriginalFormat;
1768 ALuint TotalBufferDataSize;
1769 ALuint i;
1771 // Find the first non-NULL Buffer in the Queue
1772 BufferList = Source->queue;
1773 while(BufferList)
1775 if(BufferList->buffer)
1777 Buffer = BufferList->buffer;
1778 break;
1780 BufferList = BufferList->next;
1783 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1785 offset[0] = 0.0;
1786 offset[1] = 0.0;
1787 return;
1790 // Get Current Buffer Size and frequency (in milliseconds)
1791 BufferFreq = (ALfloat)Buffer->frequency;
1792 OriginalFormat = Buffer->eOriginalFormat;
1793 Channels = aluChannelsFromFormat(Buffer->format);
1794 Bytes = aluBytesFromFormat(Buffer->format);
1796 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1797 readPos = Source->position * Channels * Bytes;
1798 // Add byte length of any processed buffers in the queue
1799 TotalBufferDataSize = 0;
1800 BufferList = Source->queue;
1801 for(i = 0;BufferList;i++)
1803 if(BufferList->buffer)
1805 if(i < Source->BuffersPlayed)
1806 readPos += BufferList->buffer->size;
1807 TotalBufferDataSize += BufferList->buffer->size;
1809 BufferList = BufferList->next;
1811 if(Source->state == AL_PLAYING)
1812 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1813 else
1814 writePos = readPos;
1816 if(Source->bLooping)
1818 readPos %= TotalBufferDataSize;
1819 writePos %= TotalBufferDataSize;
1821 else
1823 // Clamp positions to TotalBufferDataSize
1824 if(readPos > TotalBufferDataSize)
1825 readPos = TotalBufferDataSize;
1826 if(writePos > TotalBufferDataSize)
1827 writePos = TotalBufferDataSize;
1830 switch(name)
1832 case AL_SEC_OFFSET:
1833 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1834 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1835 break;
1836 case AL_SAMPLE_OFFSET:
1837 case AL_SAMPLE_RW_OFFSETS_EXT:
1838 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1839 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1840 break;
1841 case AL_BYTE_OFFSET:
1842 case AL_BYTE_RW_OFFSETS_EXT:
1843 // Take into account the original format of the Buffer
1844 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1845 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1847 // Round down to nearest ADPCM block
1848 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1849 if(Source->state == AL_PLAYING)
1851 // Round up to nearest ADPCM block
1852 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1854 else
1855 offset[1] = offset[0];
1857 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1858 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1859 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1860 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1861 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1862 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1864 offset[0] = (ALdouble)(readPos / Bytes * 1);
1865 offset[1] = (ALdouble)(writePos / Bytes * 1);
1867 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1869 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1870 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1872 else if(OriginalFormat == AL_FORMAT_REAR8)
1874 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1875 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1877 else if(OriginalFormat == AL_FORMAT_REAR16)
1879 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1880 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1882 else if(OriginalFormat == AL_FORMAT_REAR32)
1884 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1885 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1887 else
1889 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1890 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1891 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1893 break;
1899 ApplyOffset
1901 Apply a playback offset to the Source. This function will update the queue (to correctly
1902 mark buffers as 'pending' or 'processed' depending upon the new offset.
1904 static ALboolean ApplyOffset(ALsource *Source)
1906 ALbufferlistitem *BufferList;
1907 ALbuffer *Buffer;
1908 ALint lBufferSize, lTotalBufferSize;
1909 ALint BuffersPlayed;
1910 ALint lByteOffset;
1912 // Get true byte offset
1913 lByteOffset = GetByteOffset(Source);
1915 // If the offset is invalid, don't apply it
1916 if(lByteOffset == -1)
1917 return AL_FALSE;
1919 // Sort out the queue (pending and processed states)
1920 BufferList = Source->queue;
1921 lTotalBufferSize = 0;
1922 BuffersPlayed = 0;
1924 while(BufferList)
1926 Buffer = BufferList->buffer;
1927 lBufferSize = Buffer ? Buffer->size : 0;
1929 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1931 // Offset is past this buffer so increment BuffersPlayed
1932 BuffersPlayed++;
1934 else if(lTotalBufferSize <= lByteOffset)
1936 // Offset is within this buffer
1937 // Set Current Buffer
1938 Source->Buffer = BufferList->buffer;
1939 Source->BuffersPlayed = BuffersPlayed;
1941 // SW Mixer Positions are in Samples
1942 Source->position = (lByteOffset - lTotalBufferSize) /
1943 aluBytesFromFormat(Buffer->format) /
1944 aluChannelsFromFormat(Buffer->format);
1945 return AL_TRUE;
1948 // Increment the TotalBufferSize
1949 lTotalBufferSize += lBufferSize;
1951 // Move on to next buffer in the Queue
1952 BufferList = BufferList->next;
1954 // Offset is out of range of the buffer queue
1955 return AL_FALSE;
1960 GetByteOffset
1962 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1963 offset supplied by the application). This takes into account the fact that the buffer format
1964 may have been modifed by AL (e.g 8bit samples are converted to float)
1966 static ALint GetByteOffset(ALsource *Source)
1968 ALbuffer *Buffer = NULL;
1969 ALbufferlistitem *BufferList;
1970 ALfloat BufferFreq;
1971 ALint Channels, Bytes;
1972 ALint ByteOffset = -1;
1974 // Find the first non-NULL Buffer in the Queue
1975 BufferList = Source->queue;
1976 while(BufferList)
1978 if(BufferList->buffer)
1980 Buffer = BufferList->buffer;
1981 break;
1983 BufferList = BufferList->next;
1986 if(!Buffer)
1988 Source->lOffset = 0;
1989 return -1;
1992 BufferFreq = ((ALfloat)Buffer->frequency);
1993 Channels = aluChannelsFromFormat(Buffer->format);
1994 Bytes = aluBytesFromFormat(Buffer->format);
1996 // Determine the ByteOffset (and ensure it is block aligned)
1997 switch(Source->lOffsetType)
1999 case AL_BYTE_OFFSET:
2000 // Take into consideration the original format
2001 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2002 Channels);
2003 ByteOffset *= Channels * Bytes;
2004 break;
2006 case AL_SAMPLE_OFFSET:
2007 ByteOffset = Source->lOffset * Channels * Bytes;
2008 break;
2010 case AL_SEC_OFFSET:
2011 // Note - lOffset is internally stored as Milliseconds
2012 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2013 ByteOffset *= Channels * Bytes;
2014 break;
2016 // Clear Offset
2017 Source->lOffset = 0;
2019 return ByteOffset;
2022 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2024 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2026 // Round down to nearest ADPCM block
2027 offset /= 36 * channels;
2028 // Multiply by compression rate (65 sample frames per block)
2029 offset *= 65;
2031 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2032 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2033 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2035 /* muLaw has 1 byte per sample */
2036 offset /= 1 * channels;
2038 else if(format == AL_FORMAT_REAR_MULAW)
2040 /* Rear is 2 channels */
2041 offset /= 1 * 2;
2043 else if(format == AL_FORMAT_REAR8)
2044 offset /= 1 * 2;
2045 else if(format == AL_FORMAT_REAR16)
2046 offset /= 2 * 2;
2047 else if(format == AL_FORMAT_REAR32)
2048 offset /= 4 * 2;
2049 else
2051 ALuint bytes = aluBytesFromFormat(format);
2052 offset /= bytes * channels;
2054 return offset;
2058 ALvoid ReleaseALSources(ALCcontext *Context)
2060 ALsizei pos;
2061 ALuint j;
2062 for(pos = 0;pos < Context->SourceMap.size;pos++)
2064 ALsource *temp = Context->SourceMap.array[pos].value;
2065 Context->SourceMap.array[pos].value = NULL;
2067 // For each buffer in the source's queue, decrement its reference counter and remove it
2068 while(temp->queue != NULL)
2070 ALbufferlistitem *BufferList = temp->queue;
2071 // Decrement buffer's reference counter
2072 if(BufferList->buffer != NULL)
2073 BufferList->buffer->refcount--;
2074 // Update queue to point to next element in list
2075 temp->queue = BufferList->next;
2076 // Release memory allocated for buffer list item
2077 free(BufferList);
2080 for(j = 0;j < MAX_SENDS;++j)
2082 if(temp->Send[j].Slot)
2083 temp->Send[j].Slot->refcount--;
2086 // Release source structure
2087 ALTHUNK_REMOVEENTRY(temp->source);
2088 memset(temp, 0, sizeof(ALsource));
2089 free(temp);