Constify some variables
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob9132040fc762fa888b24c93a8b12d9941d891a40
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
36 resampler_t DefaultResampler;
37 const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
38 0, /* Point */
39 1, /* Linear */
40 2, /* Cubic */
42 const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
43 0, /* Point */
44 0, /* Linear */
45 1, /* Cubic */
49 static ALvoid InitSourceParams(ALsource *Source);
50 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
51 static ALboolean ApplyOffset(ALsource *Source);
52 static ALint GetByteOffset(ALsource *Source);
54 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
55 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
56 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
57 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
59 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
61 ALCcontext *Context;
62 ALCdevice *Device;
64 Context = GetContextSuspended();
65 if(!Context) return;
67 Device = Context->Device;
68 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
69 alSetError(Context, AL_INVALID_VALUE);
70 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
71 alSetError(Context, AL_INVALID_VALUE);
72 else
74 ALenum err;
75 ALsizei i;
77 // Add additional sources to the list
78 i = 0;
79 while(i < n)
81 ALsource *source = calloc(1, sizeof(ALsource));
82 if(!source)
84 alSetError(Context, AL_OUT_OF_MEMORY);
85 alDeleteSources(i, sources);
86 break;
89 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
90 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
91 source);
92 if(err != AL_NO_ERROR)
94 ALTHUNK_REMOVEENTRY(source->source);
95 memset(source, 0, sizeof(ALsource));
96 free(source);
98 alSetError(Context, err);
99 alDeleteSources(i, sources);
100 break;
103 sources[i++] = source->source;
104 InitSourceParams(source);
108 ProcessContext(Context);
112 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
114 ALCcontext *Context;
115 ALsource *Source;
116 ALsizei i, j;
117 ALbufferlistitem *BufferList;
118 ALboolean SourcesValid = AL_FALSE;
120 Context = GetContextSuspended();
121 if(!Context) return;
123 if(n < 0)
124 alSetError(Context, AL_INVALID_VALUE);
125 else
127 SourcesValid = AL_TRUE;
128 // Check that all Sources are valid (and can therefore be deleted)
129 for(i = 0;i < n;i++)
131 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
133 alSetError(Context, AL_INVALID_NAME);
134 SourcesValid = AL_FALSE;
135 break;
140 if(SourcesValid)
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)
147 continue;
149 for(j = 0;j < Context->ActiveSourceCount;j++)
151 if(Context->ActiveSources[j] == Source)
153 ALsizei end = --(Context->ActiveSourceCount);
154 Context->ActiveSources[j] = Context->ActiveSources[end];
155 break;
159 // For each buffer in the source's queue...
160 while(Source->queue != NULL)
162 BufferList = Source->queue;
163 Source->queue = BufferList->next;
165 if(BufferList->buffer != NULL)
166 BufferList->buffer->refcount--;
167 free(BufferList);
170 for(j = 0;j < MAX_SENDS;++j)
172 if(Source->Send[j].Slot)
173 Source->Send[j].Slot->refcount--;
174 Source->Send[j].Slot = NULL;
177 // Remove Source from list of Sources
178 RemoveUIntMapKey(&Context->SourceMap, Source->source);
179 ALTHUNK_REMOVEENTRY(Source->source);
181 memset(Source,0,sizeof(ALsource));
182 free(Source);
186 ProcessContext(Context);
190 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
192 ALCcontext *Context;
193 ALboolean result;
195 Context = GetContextSuspended();
196 if(!Context) return AL_FALSE;
198 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
200 ProcessContext(Context);
202 return result;
206 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
208 ALCcontext *pContext;
209 ALsource *Source;
211 pContext = GetContextSuspended();
212 if(!pContext) return;
214 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
216 switch(eParam)
218 case AL_PITCH:
219 if(flValue >= 0.0f)
221 Source->flPitch = flValue;
222 Source->NeedsUpdate = AL_TRUE;
224 else
225 alSetError(pContext, AL_INVALID_VALUE);
226 break;
228 case AL_CONE_INNER_ANGLE:
229 if(flValue >= 0.0f && flValue <= 360.0f)
231 Source->flInnerAngle = flValue;
232 Source->NeedsUpdate = AL_TRUE;
234 else
235 alSetError(pContext, AL_INVALID_VALUE);
236 break;
238 case AL_CONE_OUTER_ANGLE:
239 if(flValue >= 0.0f && flValue <= 360.0f)
241 Source->flOuterAngle = flValue;
242 Source->NeedsUpdate = AL_TRUE;
244 else
245 alSetError(pContext, AL_INVALID_VALUE);
246 break;
248 case AL_GAIN:
249 if(flValue >= 0.0f)
251 Source->flGain = flValue;
252 Source->NeedsUpdate = AL_TRUE;
254 else
255 alSetError(pContext, AL_INVALID_VALUE);
256 break;
258 case AL_MAX_DISTANCE:
259 if(flValue >= 0.0f)
261 Source->flMaxDistance = flValue;
262 Source->NeedsUpdate = AL_TRUE;
264 else
265 alSetError(pContext, AL_INVALID_VALUE);
266 break;
268 case AL_ROLLOFF_FACTOR:
269 if(flValue >= 0.0f)
271 Source->flRollOffFactor = flValue;
272 Source->NeedsUpdate = AL_TRUE;
274 else
275 alSetError(pContext, AL_INVALID_VALUE);
276 break;
278 case AL_REFERENCE_DISTANCE:
279 if(flValue >= 0.0f)
281 Source->flRefDistance = flValue;
282 Source->NeedsUpdate = AL_TRUE;
284 else
285 alSetError(pContext, AL_INVALID_VALUE);
286 break;
288 case AL_MIN_GAIN:
289 if(flValue >= 0.0f && flValue <= 1.0f)
291 Source->flMinGain = flValue;
292 Source->NeedsUpdate = AL_TRUE;
294 else
295 alSetError(pContext, AL_INVALID_VALUE);
296 break;
298 case AL_MAX_GAIN:
299 if(flValue >= 0.0f && flValue <= 1.0f)
301 Source->flMaxGain = flValue;
302 Source->NeedsUpdate = AL_TRUE;
304 else
305 alSetError(pContext, AL_INVALID_VALUE);
306 break;
308 case AL_CONE_OUTER_GAIN:
309 if(flValue >= 0.0f && flValue <= 1.0f)
311 Source->flOuterGain = flValue;
312 Source->NeedsUpdate = AL_TRUE;
314 else
315 alSetError(pContext, AL_INVALID_VALUE);
316 break;
318 case AL_CONE_OUTER_GAINHF:
319 if(flValue >= 0.0f && flValue <= 1.0f)
321 Source->OuterGainHF = flValue;
322 Source->NeedsUpdate = AL_TRUE;
324 else
325 alSetError(pContext, AL_INVALID_VALUE);
326 break;
328 case AL_AIR_ABSORPTION_FACTOR:
329 if(flValue >= 0.0f && flValue <= 10.0f)
331 Source->AirAbsorptionFactor = flValue;
332 Source->NeedsUpdate = AL_TRUE;
334 else
335 alSetError(pContext, AL_INVALID_VALUE);
336 break;
338 case AL_ROOM_ROLLOFF_FACTOR:
339 if(flValue >= 0.0f && flValue <= 10.0f)
341 Source->RoomRolloffFactor = flValue;
342 Source->NeedsUpdate = AL_TRUE;
344 else
345 alSetError(pContext, AL_INVALID_VALUE);
346 break;
348 case AL_DOPPLER_FACTOR:
349 if(flValue >= 0.0f && flValue <= 1.0f)
351 Source->DopplerFactor = flValue;
352 Source->NeedsUpdate = AL_TRUE;
354 else
355 alSetError(pContext, AL_INVALID_VALUE);
356 break;
358 case AL_SEC_OFFSET:
359 case AL_SAMPLE_OFFSET:
360 case AL_BYTE_OFFSET:
361 if(flValue >= 0.0f)
363 Source->lOffsetType = eParam;
365 // Store Offset (convert Seconds into Milliseconds)
366 if(eParam == AL_SEC_OFFSET)
367 Source->lOffset = (ALint)(flValue * 1000.0f);
368 else
369 Source->lOffset = (ALint)flValue;
371 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
373 if(ApplyOffset(Source) == AL_FALSE)
374 alSetError(pContext, AL_INVALID_VALUE);
377 else
378 alSetError(pContext, AL_INVALID_VALUE);
379 break;
381 default:
382 alSetError(pContext, AL_INVALID_ENUM);
383 break;
386 else
388 // Invalid Source Name
389 alSetError(pContext, AL_INVALID_NAME);
392 ProcessContext(pContext);
396 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
398 ALCcontext *pContext;
399 ALsource *Source;
401 pContext = GetContextSuspended();
402 if(!pContext) return;
404 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
406 switch(eParam)
408 case AL_POSITION:
409 Source->vPosition[0] = flValue1;
410 Source->vPosition[1] = flValue2;
411 Source->vPosition[2] = flValue3;
412 Source->NeedsUpdate = AL_TRUE;
413 break;
415 case AL_VELOCITY:
416 Source->vVelocity[0] = flValue1;
417 Source->vVelocity[1] = flValue2;
418 Source->vVelocity[2] = flValue3;
419 Source->NeedsUpdate = AL_TRUE;
420 break;
422 case AL_DIRECTION:
423 Source->vOrientation[0] = flValue1;
424 Source->vOrientation[1] = flValue2;
425 Source->vOrientation[2] = flValue3;
426 Source->NeedsUpdate = AL_TRUE;
427 break;
429 default:
430 alSetError(pContext, AL_INVALID_ENUM);
431 break;
434 else
435 alSetError(pContext, AL_INVALID_NAME);
437 ProcessContext(pContext);
441 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
443 ALCcontext *pContext;
445 pContext = GetContextSuspended();
446 if(!pContext) return;
448 if(pflValues)
450 if(LookupSource(pContext->SourceMap, source) != NULL)
452 switch(eParam)
454 case AL_PITCH:
455 case AL_CONE_INNER_ANGLE:
456 case AL_CONE_OUTER_ANGLE:
457 case AL_GAIN:
458 case AL_MAX_DISTANCE:
459 case AL_ROLLOFF_FACTOR:
460 case AL_REFERENCE_DISTANCE:
461 case AL_MIN_GAIN:
462 case AL_MAX_GAIN:
463 case AL_CONE_OUTER_GAIN:
464 case AL_CONE_OUTER_GAINHF:
465 case AL_SEC_OFFSET:
466 case AL_SAMPLE_OFFSET:
467 case AL_BYTE_OFFSET:
468 case AL_AIR_ABSORPTION_FACTOR:
469 case AL_ROOM_ROLLOFF_FACTOR:
470 alSourcef(source, eParam, pflValues[0]);
471 break;
473 case AL_POSITION:
474 case AL_VELOCITY:
475 case AL_DIRECTION:
476 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
477 break;
479 default:
480 alSetError(pContext, AL_INVALID_ENUM);
481 break;
484 else
485 alSetError(pContext, AL_INVALID_NAME);
487 else
488 alSetError(pContext, AL_INVALID_VALUE);
490 ProcessContext(pContext);
494 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
496 ALCcontext *pContext;
497 ALsource *Source;
498 ALbufferlistitem *BufferListItem;
500 pContext = GetContextSuspended();
501 if(!pContext) return;
503 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
505 ALCdevice *device = pContext->Device;
507 switch(eParam)
509 case AL_MAX_DISTANCE:
510 case AL_ROLLOFF_FACTOR:
511 case AL_CONE_INNER_ANGLE:
512 case AL_CONE_OUTER_ANGLE:
513 case AL_REFERENCE_DISTANCE:
514 alSourcef(source, eParam, (ALfloat)lValue);
515 break;
517 case AL_SOURCE_RELATIVE:
518 if(lValue == AL_FALSE || lValue == AL_TRUE)
520 Source->bHeadRelative = (ALboolean)lValue;
521 Source->NeedsUpdate = AL_TRUE;
523 else
524 alSetError(pContext, AL_INVALID_VALUE);
525 break;
527 case AL_LOOPING:
528 if(lValue == AL_FALSE || lValue == AL_TRUE)
529 Source->bLooping = (ALboolean)lValue;
530 else
531 alSetError(pContext, AL_INVALID_VALUE);
532 break;
534 case AL_BUFFER:
535 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
537 ALbuffer *buffer = NULL;
539 if(lValue == 0 ||
540 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
542 // Remove all elements in the queue
543 while(Source->queue != NULL)
545 BufferListItem = Source->queue;
546 Source->queue = BufferListItem->next;
548 if(BufferListItem->buffer)
549 BufferListItem->buffer->refcount--;
550 free(BufferListItem);
552 Source->BuffersInQueue = 0;
554 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
555 if(buffer != NULL)
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;
564 BufferListItem->prev = NULL;
566 Source->queue = BufferListItem;
567 Source->BuffersInQueue = 1;
569 if(buffer->FmtChannels == FmtMono)
570 Source->Update = CalcSourceParams;
571 else
572 Source->Update = CalcNonAttnSourceParams;
574 // Increment reference counter for buffer
575 buffer->refcount++;
577 else
579 // Source is now in UNDETERMINED mode
580 Source->lSourceType = AL_UNDETERMINED;
582 Source->BuffersPlayed = 0;
584 // Update AL_BUFFER parameter
585 Source->Buffer = buffer;
586 Source->NeedsUpdate = AL_TRUE;
588 else
589 alSetError(pContext, AL_INVALID_VALUE);
591 else
592 alSetError(pContext, AL_INVALID_OPERATION);
593 break;
595 case AL_SOURCE_STATE:
596 // Query only
597 alSetError(pContext, AL_INVALID_OPERATION);
598 break;
600 case AL_SEC_OFFSET:
601 case AL_SAMPLE_OFFSET:
602 case AL_BYTE_OFFSET:
603 if(lValue >= 0)
605 Source->lOffsetType = eParam;
607 // Store Offset (convert Seconds into Milliseconds)
608 if(eParam == AL_SEC_OFFSET)
609 Source->lOffset = lValue * 1000;
610 else
611 Source->lOffset = lValue;
613 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
615 if(ApplyOffset(Source) == AL_FALSE)
616 alSetError(pContext, AL_INVALID_VALUE);
619 else
620 alSetError(pContext, AL_INVALID_VALUE);
621 break;
623 case AL_DIRECT_FILTER: {
624 ALfilter *filter = NULL;
626 if(lValue == 0 ||
627 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
629 if(!filter)
631 Source->DirectFilter.type = AL_FILTER_NULL;
632 Source->DirectFilter.filter = 0;
634 else
635 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
636 Source->NeedsUpdate = AL_TRUE;
638 else
639 alSetError(pContext, AL_INVALID_VALUE);
640 } break;
642 case AL_DIRECT_FILTER_GAINHF_AUTO:
643 if(lValue == AL_TRUE || lValue == AL_FALSE)
645 Source->DryGainHFAuto = lValue;
646 Source->NeedsUpdate = AL_TRUE;
648 else
649 alSetError(pContext, AL_INVALID_VALUE);
650 break;
652 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
653 if(lValue == AL_TRUE || lValue == AL_FALSE)
655 Source->WetGainAuto = lValue;
656 Source->NeedsUpdate = AL_TRUE;
658 else
659 alSetError(pContext, AL_INVALID_VALUE);
660 break;
662 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
663 if(lValue == AL_TRUE || lValue == AL_FALSE)
665 Source->WetGainHFAuto = lValue;
666 Source->NeedsUpdate = AL_TRUE;
668 else
669 alSetError(pContext, AL_INVALID_VALUE);
670 break;
672 case AL_DISTANCE_MODEL:
673 if(lValue == AL_NONE ||
674 lValue == AL_INVERSE_DISTANCE ||
675 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
676 lValue == AL_LINEAR_DISTANCE ||
677 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
678 lValue == AL_EXPONENT_DISTANCE ||
679 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
681 Source->DistanceModel = lValue;
682 if(pContext->SourceDistanceModel)
683 Source->NeedsUpdate = AL_TRUE;
685 else
686 alSetError(pContext, AL_INVALID_VALUE);
687 break;
689 default:
690 alSetError(pContext, AL_INVALID_ENUM);
691 break;
694 else
695 alSetError(pContext, AL_INVALID_NAME);
697 ProcessContext(pContext);
701 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
703 ALCcontext *pContext;
704 ALsource *Source;
706 pContext = GetContextSuspended();
707 if(!pContext) return;
709 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
711 ALCdevice *device = pContext->Device;
713 switch (eParam)
715 case AL_POSITION:
716 case AL_VELOCITY:
717 case AL_DIRECTION:
718 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
719 break;
721 case AL_AUXILIARY_SEND_FILTER: {
722 ALeffectslot *ALEffectSlot = NULL;
723 ALfilter *ALFilter = NULL;
725 if((ALuint)lValue2 < device->NumAuxSends &&
726 (lValue1 == 0 ||
727 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
728 (lValue3 == 0 ||
729 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
731 /* Release refcount on the previous slot, and add one for
732 * the new slot */
733 if(Source->Send[lValue2].Slot)
734 Source->Send[lValue2].Slot->refcount--;
735 Source->Send[lValue2].Slot = ALEffectSlot;
736 if(Source->Send[lValue2].Slot)
737 Source->Send[lValue2].Slot->refcount++;
739 if(!ALFilter)
741 /* Disable filter */
742 Source->Send[lValue2].WetFilter.type = 0;
743 Source->Send[lValue2].WetFilter.filter = 0;
745 else
746 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
747 Source->NeedsUpdate = AL_TRUE;
749 else
750 alSetError(pContext, AL_INVALID_VALUE);
751 } break;
753 default:
754 alSetError(pContext, AL_INVALID_ENUM);
755 break;
758 else
759 alSetError(pContext, AL_INVALID_NAME);
761 ProcessContext(pContext);
765 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
767 ALCcontext *pContext;
769 pContext = GetContextSuspended();
770 if(!pContext) return;
772 if(plValues)
774 if(LookupSource(pContext->SourceMap, source) != NULL)
776 switch(eParam)
778 case AL_SOURCE_RELATIVE:
779 case AL_CONE_INNER_ANGLE:
780 case AL_CONE_OUTER_ANGLE:
781 case AL_LOOPING:
782 case AL_BUFFER:
783 case AL_SOURCE_STATE:
784 case AL_SEC_OFFSET:
785 case AL_SAMPLE_OFFSET:
786 case AL_BYTE_OFFSET:
787 case AL_MAX_DISTANCE:
788 case AL_ROLLOFF_FACTOR:
789 case AL_REFERENCE_DISTANCE:
790 case AL_DIRECT_FILTER:
791 case AL_DIRECT_FILTER_GAINHF_AUTO:
792 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
793 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
794 case AL_DISTANCE_MODEL:
795 alSourcei(source, eParam, plValues[0]);
796 break;
798 case AL_POSITION:
799 case AL_VELOCITY:
800 case AL_DIRECTION:
801 case AL_AUXILIARY_SEND_FILTER:
802 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
803 break;
805 default:
806 alSetError(pContext, AL_INVALID_ENUM);
807 break;
810 else
811 alSetError(pContext, AL_INVALID_NAME);
813 else
814 alSetError(pContext, AL_INVALID_VALUE);
816 ProcessContext(pContext);
820 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
822 ALCcontext *pContext;
823 ALsource *Source;
824 ALdouble Offsets[2];
825 ALdouble updateLen;
827 pContext = GetContextSuspended();
828 if(!pContext) return;
830 if(pflValue)
832 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
834 switch(eParam)
836 case AL_PITCH:
837 *pflValue = Source->flPitch;
838 break;
840 case AL_GAIN:
841 *pflValue = Source->flGain;
842 break;
844 case AL_MIN_GAIN:
845 *pflValue = Source->flMinGain;
846 break;
848 case AL_MAX_GAIN:
849 *pflValue = Source->flMaxGain;
850 break;
852 case AL_MAX_DISTANCE:
853 *pflValue = Source->flMaxDistance;
854 break;
856 case AL_ROLLOFF_FACTOR:
857 *pflValue = Source->flRollOffFactor;
858 break;
860 case AL_CONE_OUTER_GAIN:
861 *pflValue = Source->flOuterGain;
862 break;
864 case AL_CONE_OUTER_GAINHF:
865 *pflValue = Source->OuterGainHF;
866 break;
868 case AL_SEC_OFFSET:
869 case AL_SAMPLE_OFFSET:
870 case AL_BYTE_OFFSET:
871 updateLen = (ALdouble)pContext->Device->UpdateSize /
872 pContext->Device->Frequency;
873 GetSourceOffset(Source, eParam, Offsets, updateLen);
874 *pflValue = Offsets[0];
875 break;
877 case AL_CONE_INNER_ANGLE:
878 *pflValue = Source->flInnerAngle;
879 break;
881 case AL_CONE_OUTER_ANGLE:
882 *pflValue = Source->flOuterAngle;
883 break;
885 case AL_REFERENCE_DISTANCE:
886 *pflValue = Source->flRefDistance;
887 break;
889 case AL_AIR_ABSORPTION_FACTOR:
890 *pflValue = Source->AirAbsorptionFactor;
891 break;
893 case AL_ROOM_ROLLOFF_FACTOR:
894 *pflValue = Source->RoomRolloffFactor;
895 break;
897 case AL_DOPPLER_FACTOR:
898 *pflValue = Source->DopplerFactor;
899 break;
901 default:
902 alSetError(pContext, AL_INVALID_ENUM);
903 break;
906 else
907 alSetError(pContext, AL_INVALID_NAME);
909 else
910 alSetError(pContext, AL_INVALID_VALUE);
912 ProcessContext(pContext);
916 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
918 ALCcontext *pContext;
919 ALsource *Source;
921 pContext = GetContextSuspended();
922 if(!pContext) return;
924 if(pflValue1 && pflValue2 && pflValue3)
926 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
928 switch(eParam)
930 case AL_POSITION:
931 *pflValue1 = Source->vPosition[0];
932 *pflValue2 = Source->vPosition[1];
933 *pflValue3 = Source->vPosition[2];
934 break;
936 case AL_VELOCITY:
937 *pflValue1 = Source->vVelocity[0];
938 *pflValue2 = Source->vVelocity[1];
939 *pflValue3 = Source->vVelocity[2];
940 break;
942 case AL_DIRECTION:
943 *pflValue1 = Source->vOrientation[0];
944 *pflValue2 = Source->vOrientation[1];
945 *pflValue3 = Source->vOrientation[2];
946 break;
948 default:
949 alSetError(pContext, AL_INVALID_ENUM);
950 break;
953 else
954 alSetError(pContext, AL_INVALID_NAME);
956 else
957 alSetError(pContext, AL_INVALID_VALUE);
959 ProcessContext(pContext);
963 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
965 ALCcontext *pContext;
966 ALsource *Source;
967 ALdouble Offsets[2];
968 ALdouble updateLen;
970 pContext = GetContextSuspended();
971 if(!pContext) return;
973 if(pflValues)
975 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
977 switch(eParam)
979 case AL_PITCH:
980 case AL_GAIN:
981 case AL_MIN_GAIN:
982 case AL_MAX_GAIN:
983 case AL_MAX_DISTANCE:
984 case AL_ROLLOFF_FACTOR:
985 case AL_DOPPLER_FACTOR:
986 case AL_CONE_OUTER_GAIN:
987 case AL_SEC_OFFSET:
988 case AL_SAMPLE_OFFSET:
989 case AL_BYTE_OFFSET:
990 case AL_CONE_INNER_ANGLE:
991 case AL_CONE_OUTER_ANGLE:
992 case AL_REFERENCE_DISTANCE:
993 case AL_CONE_OUTER_GAINHF:
994 case AL_AIR_ABSORPTION_FACTOR:
995 case AL_ROOM_ROLLOFF_FACTOR:
996 alGetSourcef(source, eParam, pflValues);
997 break;
999 case AL_POSITION:
1000 case AL_VELOCITY:
1001 case AL_DIRECTION:
1002 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1003 break;
1005 case AL_SAMPLE_RW_OFFSETS_SOFT:
1006 case AL_BYTE_RW_OFFSETS_SOFT:
1007 updateLen = (ALdouble)pContext->Device->UpdateSize /
1008 pContext->Device->Frequency;
1009 GetSourceOffset(Source, eParam, Offsets, updateLen);
1010 pflValues[0] = Offsets[0];
1011 pflValues[1] = Offsets[1];
1012 break;
1014 default:
1015 alSetError(pContext, AL_INVALID_ENUM);
1016 break;
1019 else
1020 alSetError(pContext, AL_INVALID_NAME);
1022 else
1023 alSetError(pContext, AL_INVALID_VALUE);
1025 ProcessContext(pContext);
1029 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1031 ALCcontext *pContext;
1032 ALsource *Source;
1033 ALdouble Offsets[2];
1034 ALdouble updateLen;
1036 pContext = GetContextSuspended();
1037 if(!pContext) return;
1039 if(plValue)
1041 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1043 switch(eParam)
1045 case AL_MAX_DISTANCE:
1046 *plValue = (ALint)Source->flMaxDistance;
1047 break;
1049 case AL_ROLLOFF_FACTOR:
1050 *plValue = (ALint)Source->flRollOffFactor;
1051 break;
1053 case AL_REFERENCE_DISTANCE:
1054 *plValue = (ALint)Source->flRefDistance;
1055 break;
1057 case AL_SOURCE_RELATIVE:
1058 *plValue = Source->bHeadRelative;
1059 break;
1061 case AL_CONE_INNER_ANGLE:
1062 *plValue = (ALint)Source->flInnerAngle;
1063 break;
1065 case AL_CONE_OUTER_ANGLE:
1066 *plValue = (ALint)Source->flOuterAngle;
1067 break;
1069 case AL_LOOPING:
1070 *plValue = Source->bLooping;
1071 break;
1073 case AL_BUFFER:
1074 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1075 break;
1077 case AL_SOURCE_STATE:
1078 *plValue = Source->state;
1079 break;
1081 case AL_BUFFERS_QUEUED:
1082 *plValue = Source->BuffersInQueue;
1083 break;
1085 case AL_BUFFERS_PROCESSED:
1086 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1088 /* Buffers on a looping source are in a perpetual state
1089 * of PENDING, so don't report any as PROCESSED */
1090 *plValue = 0;
1092 else
1093 *plValue = Source->BuffersPlayed;
1094 break;
1096 case AL_SOURCE_TYPE:
1097 *plValue = Source->lSourceType;
1098 break;
1100 case AL_SEC_OFFSET:
1101 case AL_SAMPLE_OFFSET:
1102 case AL_BYTE_OFFSET:
1103 updateLen = (ALdouble)pContext->Device->UpdateSize /
1104 pContext->Device->Frequency;
1105 GetSourceOffset(Source, eParam, Offsets, updateLen);
1106 *plValue = (ALint)Offsets[0];
1107 break;
1109 case AL_DIRECT_FILTER:
1110 *plValue = Source->DirectFilter.filter;
1111 break;
1113 case AL_DIRECT_FILTER_GAINHF_AUTO:
1114 *plValue = Source->DryGainHFAuto;
1115 break;
1117 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1118 *plValue = Source->WetGainAuto;
1119 break;
1121 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1122 *plValue = Source->WetGainHFAuto;
1123 break;
1125 case AL_DOPPLER_FACTOR:
1126 *plValue = (ALint)Source->DopplerFactor;
1127 break;
1129 case AL_DISTANCE_MODEL:
1130 *plValue = Source->DistanceModel;
1131 break;
1133 default:
1134 alSetError(pContext, AL_INVALID_ENUM);
1135 break;
1138 else
1139 alSetError(pContext, AL_INVALID_NAME);
1141 else
1142 alSetError(pContext, AL_INVALID_VALUE);
1144 ProcessContext(pContext);
1148 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1150 ALCcontext *pContext;
1151 ALsource *Source;
1153 pContext = GetContextSuspended();
1154 if(!pContext) return;
1156 if(plValue1 && plValue2 && plValue3)
1158 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1160 switch(eParam)
1162 case AL_POSITION:
1163 *plValue1 = (ALint)Source->vPosition[0];
1164 *plValue2 = (ALint)Source->vPosition[1];
1165 *plValue3 = (ALint)Source->vPosition[2];
1166 break;
1168 case AL_VELOCITY:
1169 *plValue1 = (ALint)Source->vVelocity[0];
1170 *plValue2 = (ALint)Source->vVelocity[1];
1171 *plValue3 = (ALint)Source->vVelocity[2];
1172 break;
1174 case AL_DIRECTION:
1175 *plValue1 = (ALint)Source->vOrientation[0];
1176 *plValue2 = (ALint)Source->vOrientation[1];
1177 *plValue3 = (ALint)Source->vOrientation[2];
1178 break;
1180 default:
1181 alSetError(pContext, AL_INVALID_ENUM);
1182 break;
1185 else
1186 alSetError(pContext, AL_INVALID_NAME);
1188 else
1189 alSetError(pContext, AL_INVALID_VALUE);
1191 ProcessContext(pContext);
1195 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1197 ALCcontext *pContext;
1198 ALsource *Source;
1199 ALdouble Offsets[2];
1200 ALdouble updateLen;
1202 pContext = GetContextSuspended();
1203 if(!pContext) return;
1205 if(plValues)
1207 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1209 switch(eParam)
1211 case AL_SOURCE_RELATIVE:
1212 case AL_CONE_INNER_ANGLE:
1213 case AL_CONE_OUTER_ANGLE:
1214 case AL_LOOPING:
1215 case AL_BUFFER:
1216 case AL_SOURCE_STATE:
1217 case AL_BUFFERS_QUEUED:
1218 case AL_BUFFERS_PROCESSED:
1219 case AL_SEC_OFFSET:
1220 case AL_SAMPLE_OFFSET:
1221 case AL_BYTE_OFFSET:
1222 case AL_MAX_DISTANCE:
1223 case AL_ROLLOFF_FACTOR:
1224 case AL_DOPPLER_FACTOR:
1225 case AL_REFERENCE_DISTANCE:
1226 case AL_SOURCE_TYPE:
1227 case AL_DIRECT_FILTER:
1228 case AL_DIRECT_FILTER_GAINHF_AUTO:
1229 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1230 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1231 case AL_DISTANCE_MODEL:
1232 alGetSourcei(source, eParam, plValues);
1233 break;
1235 case AL_POSITION:
1236 case AL_VELOCITY:
1237 case AL_DIRECTION:
1238 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1239 break;
1241 case AL_SAMPLE_RW_OFFSETS_SOFT:
1242 case AL_BYTE_RW_OFFSETS_SOFT:
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 default:
1251 alSetError(pContext, AL_INVALID_ENUM);
1252 break;
1255 else
1256 alSetError(pContext, AL_INVALID_NAME);
1258 else
1259 alSetError(pContext, AL_INVALID_VALUE);
1261 ProcessContext(pContext);
1265 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1267 alSourcePlayv(1, &source);
1270 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1272 ALCcontext *Context;
1273 ALsource *Source;
1274 ALbufferlistitem *BufferList;
1275 ALsizei i, j;
1277 Context = GetContextSuspended();
1278 if(!Context) return;
1280 if(n < 0)
1282 alSetError(Context, AL_INVALID_VALUE);
1283 goto done;
1285 if(n > 0 && !sources)
1287 alSetError(Context, AL_INVALID_VALUE);
1288 goto done;
1291 // Check that all the Sources are valid
1292 for(i = 0;i < n;i++)
1294 if(!LookupSource(Context->SourceMap, sources[i]))
1296 alSetError(Context, AL_INVALID_NAME);
1297 goto done;
1301 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1303 void *temp = NULL;
1304 ALsizei newcount;
1306 newcount = Context->MaxActiveSources << 1;
1307 if(newcount > 0)
1308 temp = realloc(Context->ActiveSources,
1309 sizeof(*Context->ActiveSources) * newcount);
1310 if(!temp)
1312 alSetError(Context, AL_OUT_OF_MEMORY);
1313 goto done;
1316 Context->ActiveSources = temp;
1317 Context->MaxActiveSources = newcount;
1320 for(i = 0;i < n;i++)
1322 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1324 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1325 BufferList = Source->queue;
1326 while(BufferList)
1328 if(BufferList->buffer != NULL && BufferList->buffer->size)
1329 break;
1330 BufferList = BufferList->next;
1333 if(!BufferList)
1335 Source->state = AL_STOPPED;
1336 Source->BuffersPlayed = Source->BuffersInQueue;
1337 Source->position = 0;
1338 Source->position_fraction = 0;
1339 Source->lOffset = 0;
1340 continue;
1343 if(Source->state != AL_PAUSED)
1345 Source->state = AL_PLAYING;
1346 Source->position = 0;
1347 Source->position_fraction = 0;
1348 Source->BuffersPlayed = 0;
1350 Source->Buffer = Source->queue->buffer;
1352 else
1353 Source->state = AL_PLAYING;
1355 // Check if an Offset has been set
1356 if(Source->lOffset)
1357 ApplyOffset(Source);
1359 // If device is disconnected, go right to stopped
1360 if(!Context->Device->Connected)
1362 Source->state = AL_STOPPED;
1363 Source->BuffersPlayed = Source->BuffersInQueue;
1364 Source->position = 0;
1365 Source->position_fraction = 0;
1367 else
1369 for(j = 0;j < Context->ActiveSourceCount;j++)
1371 if(Context->ActiveSources[j] == Source)
1372 break;
1374 if(j == Context->ActiveSourceCount)
1375 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1379 done:
1380 ProcessContext(Context);
1383 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1385 alSourcePausev(1, &source);
1388 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1390 ALCcontext *Context;
1391 ALsource *Source;
1392 ALsizei i;
1394 Context = GetContextSuspended();
1395 if(!Context) return;
1397 if(n < 0)
1399 alSetError(Context, AL_INVALID_VALUE);
1400 goto done;
1402 if(n > 0 && !sources)
1404 alSetError(Context, AL_INVALID_VALUE);
1405 goto done;
1408 // Check all the Sources are valid
1409 for(i = 0;i < n;i++)
1411 if(!LookupSource(Context->SourceMap, sources[i]))
1413 alSetError(Context, AL_INVALID_NAME);
1414 goto done;
1418 for(i = 0;i < n;i++)
1420 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1421 if(Source->state == AL_PLAYING)
1422 Source->state = AL_PAUSED;
1425 done:
1426 ProcessContext(Context);
1429 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1431 alSourceStopv(1, &source);
1434 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1436 ALCcontext *Context;
1437 ALsource *Source;
1438 ALsizei i;
1440 Context = GetContextSuspended();
1441 if(!Context) return;
1443 if(n < 0)
1445 alSetError(Context, AL_INVALID_VALUE);
1446 goto done;
1448 if(n > 0 && !sources)
1450 alSetError(Context, AL_INVALID_VALUE);
1451 goto done;
1454 // Check all the Sources are valid
1455 for(i = 0;i < n;i++)
1457 if(!LookupSource(Context->SourceMap, sources[i]))
1459 alSetError(Context, AL_INVALID_NAME);
1460 goto done;
1464 for(i = 0;i < n;i++)
1466 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1467 if(Source->state != AL_INITIAL)
1469 Source->state = AL_STOPPED;
1470 Source->BuffersPlayed = Source->BuffersInQueue;
1472 Source->lOffset = 0;
1475 done:
1476 ProcessContext(Context);
1479 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1481 alSourceRewindv(1, &source);
1484 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1486 ALCcontext *Context;
1487 ALsource *Source;
1488 ALsizei i;
1490 Context = GetContextSuspended();
1491 if(!Context) return;
1493 if(n < 0)
1495 alSetError(Context, AL_INVALID_VALUE);
1496 goto done;
1498 if(n > 0 && !sources)
1500 alSetError(Context, AL_INVALID_VALUE);
1501 goto done;
1504 // Check all the Sources are valid
1505 for(i = 0;i < n;i++)
1507 if(!LookupSource(Context->SourceMap, sources[i]))
1509 alSetError(Context, AL_INVALID_NAME);
1510 goto done;
1514 for(i = 0;i < n;i++)
1516 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1517 if(Source->state != AL_INITIAL)
1519 Source->state = AL_INITIAL;
1520 Source->position = 0;
1521 Source->position_fraction = 0;
1522 Source->BuffersPlayed = 0;
1523 if(Source->queue)
1524 Source->Buffer = Source->queue->buffer;
1526 Source->lOffset = 0;
1529 done:
1530 ProcessContext(Context);
1534 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1536 ALCcontext *Context;
1537 ALCdevice *device;
1538 ALsource *Source;
1539 ALbuffer *buffer;
1540 ALsizei i;
1541 ALbufferlistitem *BufferListStart;
1542 ALbufferlistitem *BufferList;
1543 ALbuffer *BufferFmt;
1545 if(n == 0)
1546 return;
1548 Context = GetContextSuspended();
1549 if(!Context) return;
1551 if(n < 0)
1553 alSetError(Context, AL_INVALID_VALUE);
1554 goto done;
1557 // Check that all buffers are valid or zero and that the source is valid
1559 // Check that this is a valid source
1560 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1562 alSetError(Context, AL_INVALID_NAME);
1563 goto done;
1566 // Check that this is not a STATIC Source
1567 if(Source->lSourceType == AL_STATIC)
1569 // Invalid Source Type (can't queue on a Static Source)
1570 alSetError(Context, AL_INVALID_OPERATION);
1571 goto done;
1574 device = Context->Device;
1576 BufferFmt = NULL;
1578 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1579 BufferList = Source->queue;
1580 while(BufferList)
1582 if(BufferList->buffer)
1584 BufferFmt = BufferList->buffer;
1585 break;
1587 BufferList = BufferList->next;
1590 for(i = 0;i < n;i++)
1592 if(!buffers[i])
1593 continue;
1595 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1597 alSetError(Context, AL_INVALID_NAME);
1598 goto done;
1601 if(BufferFmt == NULL)
1603 BufferFmt = buffer;
1605 if(buffer->FmtChannels == FmtMono)
1606 Source->Update = CalcSourceParams;
1607 else
1608 Source->Update = CalcNonAttnSourceParams;
1610 Source->NeedsUpdate = AL_TRUE;
1612 else if(BufferFmt->Frequency != buffer->Frequency ||
1613 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1614 BufferFmt->OriginalType != buffer->OriginalType)
1616 alSetError(Context, AL_INVALID_OPERATION);
1617 goto done;
1621 // Change Source Type
1622 Source->lSourceType = AL_STREAMING;
1624 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1626 // All buffers are valid - so add them to the list
1627 BufferListStart = malloc(sizeof(ALbufferlistitem));
1628 BufferListStart->buffer = buffer;
1629 BufferListStart->next = NULL;
1630 BufferListStart->prev = NULL;
1632 // Increment reference counter for buffer
1633 if(buffer) buffer->refcount++;
1635 BufferList = BufferListStart;
1637 for(i = 1;i < n;i++)
1639 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1641 BufferList->next = malloc(sizeof(ALbufferlistitem));
1642 BufferList->next->buffer = buffer;
1643 BufferList->next->next = NULL;
1644 BufferList->next->prev = BufferList;
1646 // Increment reference counter for buffer
1647 if(buffer) buffer->refcount++;
1649 BufferList = BufferList->next;
1652 if(Source->queue == NULL)
1654 Source->queue = BufferListStart;
1655 // Update Current Buffer
1656 Source->Buffer = BufferListStart->buffer;
1658 else
1660 // Find end of queue
1661 BufferList = Source->queue;
1662 while(BufferList->next != NULL)
1663 BufferList = BufferList->next;
1665 BufferList->next = BufferListStart;
1666 BufferList->next->prev = BufferList;
1669 // Update number of buffers in queue
1670 Source->BuffersInQueue += n;
1672 done:
1673 ProcessContext(Context);
1677 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1678 // an array of buffer IDs that are to be filled with the names of the buffers removed
1679 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1681 ALCcontext *Context;
1682 ALsource *Source;
1683 ALsizei i;
1684 ALbufferlistitem *BufferList;
1686 if(n == 0)
1687 return;
1689 Context = GetContextSuspended();
1690 if(!Context) return;
1692 if(n < 0)
1694 alSetError(Context, AL_INVALID_VALUE);
1695 goto done;
1698 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1700 alSetError(Context, AL_INVALID_NAME);
1701 goto done;
1704 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1705 (ALuint)n > Source->BuffersPlayed)
1707 // Some buffers can't be unqueue because they have not been processed
1708 alSetError(Context, AL_INVALID_VALUE);
1709 goto done;
1712 for(i = 0;i < n;i++)
1714 BufferList = Source->queue;
1715 Source->queue = BufferList->next;
1717 if(BufferList->buffer)
1719 // Record name of buffer
1720 buffers[i] = BufferList->buffer->buffer;
1721 // Decrement buffer reference counter
1722 BufferList->buffer->refcount--;
1724 else
1725 buffers[i] = 0;
1727 // Release memory for buffer list item
1728 free(BufferList);
1729 Source->BuffersInQueue--;
1731 if(Source->queue)
1732 Source->queue->prev = NULL;
1734 if(Source->state != AL_PLAYING)
1736 if(Source->queue)
1737 Source->Buffer = Source->queue->buffer;
1738 else
1739 Source->Buffer = NULL;
1741 Source->BuffersPlayed -= n;
1743 done:
1744 ProcessContext(Context);
1748 static ALvoid InitSourceParams(ALsource *Source)
1750 Source->flInnerAngle = 360.0f;
1751 Source->flOuterAngle = 360.0f;
1752 Source->flPitch = 1.0f;
1753 Source->vPosition[0] = 0.0f;
1754 Source->vPosition[1] = 0.0f;
1755 Source->vPosition[2] = 0.0f;
1756 Source->vOrientation[0] = 0.0f;
1757 Source->vOrientation[1] = 0.0f;
1758 Source->vOrientation[2] = 0.0f;
1759 Source->vVelocity[0] = 0.0f;
1760 Source->vVelocity[1] = 0.0f;
1761 Source->vVelocity[2] = 0.0f;
1762 Source->flRefDistance = 1.0f;
1763 Source->flMaxDistance = FLT_MAX;
1764 Source->flRollOffFactor = 1.0f;
1765 Source->bLooping = AL_FALSE;
1766 Source->flGain = 1.0f;
1767 Source->flMinGain = 0.0f;
1768 Source->flMaxGain = 1.0f;
1769 Source->flOuterGain = 0.0f;
1770 Source->OuterGainHF = 1.0f;
1772 Source->DryGainHFAuto = AL_TRUE;
1773 Source->WetGainAuto = AL_TRUE;
1774 Source->WetGainHFAuto = AL_TRUE;
1775 Source->AirAbsorptionFactor = 0.0f;
1776 Source->RoomRolloffFactor = 0.0f;
1777 Source->DopplerFactor = 1.0f;
1779 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1781 Source->Resampler = DefaultResampler;
1783 Source->state = AL_INITIAL;
1784 Source->lSourceType = AL_UNDETERMINED;
1786 Source->NeedsUpdate = AL_TRUE;
1788 Source->Buffer = NULL;
1793 GetSourceOffset
1795 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1796 The offset is relative to the start of the queue (not the start of the current buffer)
1798 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1800 const ALbufferlistitem *BufferList;
1801 const ALbuffer *Buffer = NULL;
1802 enum UserFmtType OriginalType;
1803 ALfloat BufferFreq;
1804 ALint Channels, Bytes;
1805 ALuint readPos, writePos;
1806 ALuint TotalBufferDataSize;
1807 ALuint i;
1809 // Find the first non-NULL Buffer in the Queue
1810 BufferList = Source->queue;
1811 while(BufferList)
1813 if(BufferList->buffer)
1815 Buffer = BufferList->buffer;
1816 break;
1818 BufferList = BufferList->next;
1821 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1823 offset[0] = 0.0;
1824 offset[1] = 0.0;
1825 return;
1828 // Get Current Buffer Size and frequency (in milliseconds)
1829 BufferFreq = (ALfloat)Buffer->Frequency;
1830 OriginalType = Buffer->OriginalType;
1831 Channels = ChannelsFromFmt(Buffer->FmtChannels);
1832 Bytes = BytesFromFmt(Buffer->FmtType);
1834 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1835 readPos = Source->position * Channels * Bytes;
1836 // Add byte length of any processed buffers in the queue
1837 TotalBufferDataSize = 0;
1838 BufferList = Source->queue;
1839 for(i = 0;BufferList;i++)
1841 if(BufferList->buffer)
1843 if(i < Source->BuffersPlayed)
1844 readPos += BufferList->buffer->size;
1845 TotalBufferDataSize += BufferList->buffer->size;
1847 BufferList = BufferList->next;
1849 if(Source->state == AL_PLAYING)
1850 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1851 else
1852 writePos = readPos;
1854 if(Source->bLooping)
1856 readPos %= TotalBufferDataSize;
1857 writePos %= TotalBufferDataSize;
1859 else
1861 // Wrap positions back to 0
1862 if(readPos >= TotalBufferDataSize)
1863 readPos = 0;
1864 if(writePos >= TotalBufferDataSize)
1865 writePos = 0;
1868 switch(name)
1870 case AL_SEC_OFFSET:
1871 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1872 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1873 break;
1874 case AL_SAMPLE_OFFSET:
1875 case AL_SAMPLE_RW_OFFSETS_SOFT:
1876 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1877 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1878 break;
1879 case AL_BYTE_OFFSET:
1880 case AL_BYTE_RW_OFFSETS_SOFT:
1881 // Take into account the original format of the Buffer
1882 if(OriginalType == UserFmtIMA4)
1884 ALuint FrameBlockSize = 65 * Bytes * Channels;
1885 ALuint BlockSize = 36 * Channels;
1887 // Round down to nearest ADPCM block
1888 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1889 if(Source->state != AL_PLAYING)
1890 offset[1] = offset[0];
1891 else
1893 // Round up to nearest ADPCM block
1894 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1895 FrameBlockSize * BlockSize);
1898 else
1900 ALuint OrigBytes = BytesFromUserFmt(OriginalType);
1901 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1902 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1904 break;
1910 ApplyOffset
1912 Apply a playback offset to the Source. This function will update the queue (to correctly
1913 mark buffers as 'pending' or 'processed' depending upon the new offset.
1915 static ALboolean ApplyOffset(ALsource *Source)
1917 const ALbufferlistitem *BufferList;
1918 const ALbuffer *Buffer;
1919 ALint lBufferSize, lTotalBufferSize;
1920 ALint BuffersPlayed;
1921 ALint lByteOffset;
1923 // Get true byte offset
1924 lByteOffset = GetByteOffset(Source);
1926 // If the offset is invalid, don't apply it
1927 if(lByteOffset == -1)
1928 return AL_FALSE;
1930 // Sort out the queue (pending and processed states)
1931 BufferList = Source->queue;
1932 lTotalBufferSize = 0;
1933 BuffersPlayed = 0;
1935 while(BufferList)
1937 Buffer = BufferList->buffer;
1938 lBufferSize = Buffer ? Buffer->size : 0;
1940 if(lBufferSize <= lByteOffset-lTotalBufferSize)
1942 // Offset is past this buffer so increment BuffersPlayed
1943 BuffersPlayed++;
1945 else if(lTotalBufferSize <= lByteOffset)
1947 // Offset is within this buffer
1948 // Set Current Buffer
1949 Source->Buffer = BufferList->buffer;
1950 Source->BuffersPlayed = BuffersPlayed;
1952 // SW Mixer Positions are in Samples
1953 Source->position = (lByteOffset - lTotalBufferSize) /
1954 FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
1955 return AL_TRUE;
1958 // Increment the TotalBufferSize
1959 lTotalBufferSize += lBufferSize;
1961 // Move on to next buffer in the Queue
1962 BufferList = BufferList->next;
1964 // Offset is out of range of the buffer queue
1965 return AL_FALSE;
1970 GetByteOffset
1972 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1973 offset supplied by the application). This takes into account the fact that the buffer format
1974 may have been modifed by AL (e.g 8bit samples are converted to float)
1976 static ALint GetByteOffset(ALsource *Source)
1978 const ALbuffer *Buffer = NULL;
1979 const ALbufferlistitem *BufferList;
1980 ALint ByteOffset = -1;
1982 // Find the first non-NULL Buffer in the Queue
1983 BufferList = Source->queue;
1984 while(BufferList)
1986 if(BufferList->buffer)
1988 Buffer = BufferList->buffer;
1989 break;
1991 BufferList = BufferList->next;
1994 if(!Buffer)
1996 Source->lOffset = 0;
1997 return -1;
2000 // Determine the ByteOffset (and ensure it is block aligned)
2001 switch(Source->lOffsetType)
2003 case AL_BYTE_OFFSET:
2004 // Take into consideration the original format
2005 ByteOffset = Source->lOffset;
2006 if(Buffer->OriginalType == UserFmtIMA4)
2008 // Round down to nearest ADPCM block
2009 ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2010 // Multiply by compression rate (65 sample frames per block)
2011 ByteOffset *= 65;
2013 else
2014 ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2015 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2016 break;
2018 case AL_SAMPLE_OFFSET:
2019 ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2020 break;
2022 case AL_SEC_OFFSET:
2023 // Note - lOffset is internally stored as Milliseconds
2024 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2025 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2026 break;
2028 // Clear Offset
2029 Source->lOffset = 0;
2031 return ByteOffset;
2035 ALvoid ReleaseALSources(ALCcontext *Context)
2037 ALsizei pos;
2038 ALuint j;
2039 for(pos = 0;pos < Context->SourceMap.size;pos++)
2041 ALsource *temp = Context->SourceMap.array[pos].value;
2042 Context->SourceMap.array[pos].value = NULL;
2044 // For each buffer in the source's queue, decrement its reference counter and remove it
2045 while(temp->queue != NULL)
2047 ALbufferlistitem *BufferList = temp->queue;
2048 temp->queue = BufferList->next;
2050 if(BufferList->buffer != NULL)
2051 BufferList->buffer->refcount--;
2052 free(BufferList);
2055 for(j = 0;j < MAX_SENDS;++j)
2057 if(temp->Send[j].Slot)
2058 temp->Send[j].Slot->refcount--;
2059 temp->Send[j].Slot = NULL;
2062 // Release source structure
2063 ALTHUNK_REMOVEENTRY(temp->source);
2064 memset(temp, 0, sizeof(ALsource));
2065 free(temp);