Rename some stuff for consistency
[openal-soft.git] / OpenAL32 / alSource.c
blobfd258872bc9a6f2fcd916cf7f74e886c394353af
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);
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;
51 Context = GetContextSuspended();
52 if(!Context) return;
54 Device = Context->Device;
55 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
56 alSetError(Context, AL_INVALID_VALUE);
57 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
58 alSetError(Context, AL_INVALID_VALUE);
59 else
61 ALenum err;
62 ALsizei i;
64 // Add additional sources to the list
65 i = 0;
66 while(i < n)
68 ALsource *source = calloc(1, sizeof(ALsource));
69 if(!source)
71 alSetError(Context, AL_OUT_OF_MEMORY);
72 alDeleteSources(i, sources);
73 break;
76 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
77 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
78 source);
79 if(err != AL_NO_ERROR)
81 ALTHUNK_REMOVEENTRY(source->source);
82 memset(source, 0, sizeof(ALsource));
83 free(source);
85 alSetError(Context, err);
86 alDeleteSources(i, sources);
87 break;
90 sources[i++] = source->source;
91 InitSourceParams(source);
95 ProcessContext(Context);
99 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
101 ALCcontext *Context;
102 ALsource *Source;
103 ALsizei i, j;
104 ALbufferlistitem *BufferList;
105 ALboolean SourcesValid = AL_FALSE;
107 Context = GetContextSuspended();
108 if(!Context) return;
110 if(n < 0)
111 alSetError(Context, AL_INVALID_VALUE);
112 else
114 SourcesValid = AL_TRUE;
115 // Check that all Sources are valid (and can therefore be deleted)
116 for(i = 0;i < n;i++)
118 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
120 alSetError(Context, AL_INVALID_NAME);
121 SourcesValid = AL_FALSE;
122 break;
127 if(SourcesValid)
129 // All Sources are valid, and can be deleted
130 for(i = 0;i < n;i++)
132 // Recheck that the Source is valid, because there could be duplicated Source names
133 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
134 continue;
136 for(j = 0;j < Context->ActiveSourceCount;j++)
138 if(Context->ActiveSources[j] == Source)
140 ALsizei end = --(Context->ActiveSourceCount);
141 Context->ActiveSources[j] = Context->ActiveSources[end];
142 break;
146 // For each buffer in the source's queue...
147 while(Source->queue != NULL)
149 BufferList = Source->queue;
150 Source->queue = BufferList->next;
152 if(BufferList->buffer != NULL)
153 BufferList->buffer->refcount--;
154 free(BufferList);
157 for(j = 0;j < MAX_SENDS;++j)
159 if(Source->Send[j].Slot)
160 Source->Send[j].Slot->refcount--;
161 Source->Send[j].Slot = NULL;
164 // Remove Source from list of Sources
165 RemoveUIntMapKey(&Context->SourceMap, Source->source);
166 ALTHUNK_REMOVEENTRY(Source->source);
168 memset(Source,0,sizeof(ALsource));
169 free(Source);
173 ProcessContext(Context);
177 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
179 ALCcontext *Context;
180 ALboolean result;
182 Context = GetContextSuspended();
183 if(!Context) return AL_FALSE;
185 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
187 ProcessContext(Context);
189 return result;
193 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
195 ALCcontext *pContext;
196 ALsource *Source;
198 pContext = GetContextSuspended();
199 if(!pContext) return;
201 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
203 switch(eParam)
205 case AL_PITCH:
206 if(flValue >= 0.0f)
208 Source->flPitch = flValue;
209 if(Source->flPitch < 0.001f)
210 Source->flPitch = 0.001f;
211 Source->NeedsUpdate = AL_TRUE;
213 else
214 alSetError(pContext, AL_INVALID_VALUE);
215 break;
217 case AL_CONE_INNER_ANGLE:
218 if(flValue >= 0.0f && flValue <= 360.0f)
220 Source->flInnerAngle = flValue;
221 Source->NeedsUpdate = AL_TRUE;
223 else
224 alSetError(pContext, AL_INVALID_VALUE);
225 break;
227 case AL_CONE_OUTER_ANGLE:
228 if(flValue >= 0.0f && flValue <= 360.0f)
230 Source->flOuterAngle = flValue;
231 Source->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_GAIN:
238 if(flValue >= 0.0f)
240 Source->flGain = flValue;
241 Source->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_MAX_DISTANCE:
248 if(flValue >= 0.0f)
250 Source->flMaxDistance = flValue;
251 Source->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_ROLLOFF_FACTOR:
258 if(flValue >= 0.0f)
260 Source->flRollOffFactor = flValue;
261 Source->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_REFERENCE_DISTANCE:
268 if(flValue >= 0.0f)
270 Source->flRefDistance = flValue;
271 Source->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_MIN_GAIN:
278 if(flValue >= 0.0f && flValue <= 1.0f)
280 Source->flMinGain = flValue;
281 Source->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_MAX_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
290 Source->flMaxGain = flValue;
291 Source->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_CONE_OUTER_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 Source->flOuterGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_CONE_OUTER_GAINHF:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 Source->OuterGainHF = flValue;
311 Source->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_AIR_ABSORPTION_FACTOR:
318 if(flValue >= 0.0f && flValue <= 10.0f)
320 Source->AirAbsorptionFactor = flValue;
321 Source->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_ROOM_ROLLOFF_FACTOR:
328 if(flValue >= 0.0f && flValue <= 10.0f)
330 Source->RoomRolloffFactor = flValue;
331 Source->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_DOPPLER_FACTOR:
338 if(flValue >= 0.0f && flValue <= 1.0f)
340 Source->DopplerFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_SEC_OFFSET:
348 case AL_SAMPLE_OFFSET:
349 case AL_BYTE_OFFSET:
350 if(flValue >= 0.0f)
352 Source->lOffsetType = eParam;
354 // Store Offset (convert Seconds into Milliseconds)
355 if(eParam == AL_SEC_OFFSET)
356 Source->lOffset = (ALint)(flValue * 1000.0f);
357 else
358 Source->lOffset = (ALint)flValue;
360 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
362 if(ApplyOffset(Source) == AL_FALSE)
363 alSetError(pContext, AL_INVALID_VALUE);
366 else
367 alSetError(pContext, AL_INVALID_VALUE);
368 break;
370 default:
371 alSetError(pContext, AL_INVALID_ENUM);
372 break;
375 else
377 // Invalid Source Name
378 alSetError(pContext, AL_INVALID_NAME);
381 ProcessContext(pContext);
385 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
387 ALCcontext *pContext;
388 ALsource *Source;
390 pContext = GetContextSuspended();
391 if(!pContext) return;
393 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
395 switch(eParam)
397 case AL_POSITION:
398 Source->vPosition[0] = flValue1;
399 Source->vPosition[1] = flValue2;
400 Source->vPosition[2] = flValue3;
401 Source->NeedsUpdate = AL_TRUE;
402 break;
404 case AL_VELOCITY:
405 Source->vVelocity[0] = flValue1;
406 Source->vVelocity[1] = flValue2;
407 Source->vVelocity[2] = flValue3;
408 Source->NeedsUpdate = AL_TRUE;
409 break;
411 case AL_DIRECTION:
412 Source->vOrientation[0] = flValue1;
413 Source->vOrientation[1] = flValue2;
414 Source->vOrientation[2] = flValue3;
415 Source->NeedsUpdate = AL_TRUE;
416 break;
418 default:
419 alSetError(pContext, AL_INVALID_ENUM);
420 break;
423 else
424 alSetError(pContext, AL_INVALID_NAME);
426 ProcessContext(pContext);
430 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
432 ALCcontext *pContext;
434 pContext = GetContextSuspended();
435 if(!pContext) return;
437 if(pflValues)
439 if(LookupSource(pContext->SourceMap, source) != NULL)
441 switch(eParam)
443 case AL_PITCH:
444 case AL_CONE_INNER_ANGLE:
445 case AL_CONE_OUTER_ANGLE:
446 case AL_GAIN:
447 case AL_MAX_DISTANCE:
448 case AL_ROLLOFF_FACTOR:
449 case AL_REFERENCE_DISTANCE:
450 case AL_MIN_GAIN:
451 case AL_MAX_GAIN:
452 case AL_CONE_OUTER_GAIN:
453 case AL_CONE_OUTER_GAINHF:
454 case AL_SEC_OFFSET:
455 case AL_SAMPLE_OFFSET:
456 case AL_BYTE_OFFSET:
457 case AL_AIR_ABSORPTION_FACTOR:
458 case AL_ROOM_ROLLOFF_FACTOR:
459 alSourcef(source, eParam, pflValues[0]);
460 break;
462 case AL_POSITION:
463 case AL_VELOCITY:
464 case AL_DIRECTION:
465 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
466 break;
468 default:
469 alSetError(pContext, AL_INVALID_ENUM);
470 break;
473 else
474 alSetError(pContext, AL_INVALID_NAME);
476 else
477 alSetError(pContext, AL_INVALID_VALUE);
479 ProcessContext(pContext);
483 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
485 ALCcontext *pContext;
486 ALsource *Source;
487 ALbufferlistitem *BufferListItem;
489 pContext = GetContextSuspended();
490 if(!pContext) return;
492 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
494 ALCdevice *device = pContext->Device;
496 switch(eParam)
498 case AL_MAX_DISTANCE:
499 case AL_ROLLOFF_FACTOR:
500 case AL_CONE_INNER_ANGLE:
501 case AL_CONE_OUTER_ANGLE:
502 case AL_REFERENCE_DISTANCE:
503 alSourcef(source, eParam, (ALfloat)lValue);
504 break;
506 case AL_SOURCE_RELATIVE:
507 if(lValue == AL_FALSE || lValue == AL_TRUE)
509 Source->bHeadRelative = (ALboolean)lValue;
510 Source->NeedsUpdate = AL_TRUE;
512 else
513 alSetError(pContext, AL_INVALID_VALUE);
514 break;
516 case AL_LOOPING:
517 if(lValue == AL_FALSE || lValue == AL_TRUE)
518 Source->bLooping = (ALboolean)lValue;
519 else
520 alSetError(pContext, AL_INVALID_VALUE);
521 break;
523 case AL_BUFFER:
524 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
526 ALbuffer *buffer = NULL;
528 if(lValue == 0 ||
529 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
531 // Remove all elements in the queue
532 while(Source->queue != NULL)
534 BufferListItem = Source->queue;
535 Source->queue = BufferListItem->next;
537 if(BufferListItem->buffer)
538 BufferListItem->buffer->refcount--;
539 free(BufferListItem);
541 Source->BuffersInQueue = 0;
543 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
544 if(buffer != NULL)
546 // Source is now in STATIC mode
547 Source->lSourceType = AL_STATIC;
549 // Add the selected buffer to the queue
550 BufferListItem = malloc(sizeof(ALbufferlistitem));
551 BufferListItem->buffer = buffer;
552 BufferListItem->next = NULL;
553 BufferListItem->prev = NULL;
555 Source->queue = BufferListItem;
556 Source->BuffersInQueue = 1;
558 if(buffer->FmtChannels == FmtMono)
559 Source->Update = CalcSourceParams;
560 else
561 Source->Update = CalcNonAttnSourceParams;
563 // Increment reference counter for buffer
564 buffer->refcount++;
566 else
568 // Source is now in UNDETERMINED mode
569 Source->lSourceType = AL_UNDETERMINED;
571 Source->BuffersPlayed = 0;
573 // Update AL_BUFFER parameter
574 Source->Buffer = buffer;
575 Source->NeedsUpdate = AL_TRUE;
577 else
578 alSetError(pContext, AL_INVALID_VALUE);
580 else
581 alSetError(pContext, AL_INVALID_OPERATION);
582 break;
584 case AL_SOURCE_STATE:
585 // Query only
586 alSetError(pContext, AL_INVALID_OPERATION);
587 break;
589 case AL_SEC_OFFSET:
590 case AL_SAMPLE_OFFSET:
591 case AL_BYTE_OFFSET:
592 if(lValue >= 0)
594 Source->lOffsetType = eParam;
596 // Store Offset (convert Seconds into Milliseconds)
597 if(eParam == AL_SEC_OFFSET)
598 Source->lOffset = lValue * 1000;
599 else
600 Source->lOffset = lValue;
602 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
604 if(ApplyOffset(Source) == AL_FALSE)
605 alSetError(pContext, AL_INVALID_VALUE);
608 else
609 alSetError(pContext, AL_INVALID_VALUE);
610 break;
612 case AL_DIRECT_FILTER: {
613 ALfilter *filter = NULL;
615 if(lValue == 0 ||
616 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
618 if(!filter)
620 Source->DirectFilter.type = AL_FILTER_NULL;
621 Source->DirectFilter.filter = 0;
623 else
624 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
625 Source->NeedsUpdate = AL_TRUE;
627 else
628 alSetError(pContext, AL_INVALID_VALUE);
629 } break;
631 case AL_DIRECT_FILTER_GAINHF_AUTO:
632 if(lValue == AL_TRUE || lValue == AL_FALSE)
634 Source->DryGainHFAuto = lValue;
635 Source->NeedsUpdate = AL_TRUE;
637 else
638 alSetError(pContext, AL_INVALID_VALUE);
639 break;
641 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
642 if(lValue == AL_TRUE || lValue == AL_FALSE)
644 Source->WetGainAuto = lValue;
645 Source->NeedsUpdate = AL_TRUE;
647 else
648 alSetError(pContext, AL_INVALID_VALUE);
649 break;
651 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
652 if(lValue == AL_TRUE || lValue == AL_FALSE)
654 Source->WetGainHFAuto = lValue;
655 Source->NeedsUpdate = AL_TRUE;
657 else
658 alSetError(pContext, AL_INVALID_VALUE);
659 break;
661 case AL_DISTANCE_MODEL:
662 if(lValue == AL_NONE ||
663 lValue == AL_INVERSE_DISTANCE ||
664 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
665 lValue == AL_LINEAR_DISTANCE ||
666 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
667 lValue == AL_EXPONENT_DISTANCE ||
668 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
670 Source->DistanceModel = lValue;
671 if(pContext->SourceDistanceModel)
672 Source->NeedsUpdate = AL_TRUE;
674 else
675 alSetError(pContext, AL_INVALID_VALUE);
676 break;
678 default:
679 alSetError(pContext, AL_INVALID_ENUM);
680 break;
683 else
684 alSetError(pContext, AL_INVALID_NAME);
686 ProcessContext(pContext);
690 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
692 ALCcontext *pContext;
693 ALsource *Source;
695 pContext = GetContextSuspended();
696 if(!pContext) return;
698 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
700 ALCdevice *device = pContext->Device;
702 switch (eParam)
704 case AL_POSITION:
705 case AL_VELOCITY:
706 case AL_DIRECTION:
707 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
708 break;
710 case AL_AUXILIARY_SEND_FILTER: {
711 ALeffectslot *ALEffectSlot = NULL;
712 ALfilter *ALFilter = NULL;
714 if((ALuint)lValue2 < device->NumAuxSends &&
715 (lValue1 == 0 ||
716 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
717 (lValue3 == 0 ||
718 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
720 /* Release refcount on the previous slot, and add one for
721 * the new slot */
722 if(Source->Send[lValue2].Slot)
723 Source->Send[lValue2].Slot->refcount--;
724 Source->Send[lValue2].Slot = ALEffectSlot;
725 if(Source->Send[lValue2].Slot)
726 Source->Send[lValue2].Slot->refcount++;
728 if(!ALFilter)
730 /* Disable filter */
731 Source->Send[lValue2].WetFilter.type = 0;
732 Source->Send[lValue2].WetFilter.filter = 0;
734 else
735 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
736 Source->NeedsUpdate = AL_TRUE;
738 else
739 alSetError(pContext, AL_INVALID_VALUE);
740 } break;
742 default:
743 alSetError(pContext, AL_INVALID_ENUM);
744 break;
747 else
748 alSetError(pContext, AL_INVALID_NAME);
750 ProcessContext(pContext);
754 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
756 ALCcontext *pContext;
758 pContext = GetContextSuspended();
759 if(!pContext) return;
761 if(plValues)
763 if(LookupSource(pContext->SourceMap, source) != NULL)
765 switch(eParam)
767 case AL_SOURCE_RELATIVE:
768 case AL_CONE_INNER_ANGLE:
769 case AL_CONE_OUTER_ANGLE:
770 case AL_LOOPING:
771 case AL_BUFFER:
772 case AL_SOURCE_STATE:
773 case AL_SEC_OFFSET:
774 case AL_SAMPLE_OFFSET:
775 case AL_BYTE_OFFSET:
776 case AL_MAX_DISTANCE:
777 case AL_ROLLOFF_FACTOR:
778 case AL_REFERENCE_DISTANCE:
779 case AL_DIRECT_FILTER:
780 case AL_DIRECT_FILTER_GAINHF_AUTO:
781 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
782 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
783 case AL_DISTANCE_MODEL:
784 alSourcei(source, eParam, plValues[0]);
785 break;
787 case AL_POSITION:
788 case AL_VELOCITY:
789 case AL_DIRECTION:
790 case AL_AUXILIARY_SEND_FILTER:
791 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
792 break;
794 default:
795 alSetError(pContext, AL_INVALID_ENUM);
796 break;
799 else
800 alSetError(pContext, AL_INVALID_NAME);
802 else
803 alSetError(pContext, AL_INVALID_VALUE);
805 ProcessContext(pContext);
809 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
811 ALCcontext *pContext;
812 ALsource *Source;
813 ALdouble Offsets[2];
814 ALdouble updateLen;
816 pContext = GetContextSuspended();
817 if(!pContext) return;
819 if(pflValue)
821 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
823 switch(eParam)
825 case AL_PITCH:
826 *pflValue = Source->flPitch;
827 break;
829 case AL_GAIN:
830 *pflValue = Source->flGain;
831 break;
833 case AL_MIN_GAIN:
834 *pflValue = Source->flMinGain;
835 break;
837 case AL_MAX_GAIN:
838 *pflValue = Source->flMaxGain;
839 break;
841 case AL_MAX_DISTANCE:
842 *pflValue = Source->flMaxDistance;
843 break;
845 case AL_ROLLOFF_FACTOR:
846 *pflValue = Source->flRollOffFactor;
847 break;
849 case AL_CONE_OUTER_GAIN:
850 *pflValue = Source->flOuterGain;
851 break;
853 case AL_CONE_OUTER_GAINHF:
854 *pflValue = Source->OuterGainHF;
855 break;
857 case AL_SEC_OFFSET:
858 case AL_SAMPLE_OFFSET:
859 case AL_BYTE_OFFSET:
860 updateLen = (ALdouble)pContext->Device->UpdateSize /
861 pContext->Device->Frequency;
862 GetSourceOffset(Source, eParam, Offsets, updateLen);
863 *pflValue = Offsets[0];
864 break;
866 case AL_CONE_INNER_ANGLE:
867 *pflValue = Source->flInnerAngle;
868 break;
870 case AL_CONE_OUTER_ANGLE:
871 *pflValue = Source->flOuterAngle;
872 break;
874 case AL_REFERENCE_DISTANCE:
875 *pflValue = Source->flRefDistance;
876 break;
878 case AL_AIR_ABSORPTION_FACTOR:
879 *pflValue = Source->AirAbsorptionFactor;
880 break;
882 case AL_ROOM_ROLLOFF_FACTOR:
883 *pflValue = Source->RoomRolloffFactor;
884 break;
886 case AL_DOPPLER_FACTOR:
887 *pflValue = Source->DopplerFactor;
888 break;
890 default:
891 alSetError(pContext, AL_INVALID_ENUM);
892 break;
895 else
896 alSetError(pContext, AL_INVALID_NAME);
898 else
899 alSetError(pContext, AL_INVALID_VALUE);
901 ProcessContext(pContext);
905 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
907 ALCcontext *pContext;
908 ALsource *Source;
910 pContext = GetContextSuspended();
911 if(!pContext) return;
913 if(pflValue1 && pflValue2 && pflValue3)
915 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
917 switch(eParam)
919 case AL_POSITION:
920 *pflValue1 = Source->vPosition[0];
921 *pflValue2 = Source->vPosition[1];
922 *pflValue3 = Source->vPosition[2];
923 break;
925 case AL_VELOCITY:
926 *pflValue1 = Source->vVelocity[0];
927 *pflValue2 = Source->vVelocity[1];
928 *pflValue3 = Source->vVelocity[2];
929 break;
931 case AL_DIRECTION:
932 *pflValue1 = Source->vOrientation[0];
933 *pflValue2 = Source->vOrientation[1];
934 *pflValue3 = Source->vOrientation[2];
935 break;
937 default:
938 alSetError(pContext, AL_INVALID_ENUM);
939 break;
942 else
943 alSetError(pContext, AL_INVALID_NAME);
945 else
946 alSetError(pContext, AL_INVALID_VALUE);
948 ProcessContext(pContext);
952 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
954 ALCcontext *pContext;
955 ALsource *Source;
956 ALdouble Offsets[2];
957 ALdouble updateLen;
959 pContext = GetContextSuspended();
960 if(!pContext) return;
962 if(pflValues)
964 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
966 switch(eParam)
968 case AL_PITCH:
969 case AL_GAIN:
970 case AL_MIN_GAIN:
971 case AL_MAX_GAIN:
972 case AL_MAX_DISTANCE:
973 case AL_ROLLOFF_FACTOR:
974 case AL_DOPPLER_FACTOR:
975 case AL_CONE_OUTER_GAIN:
976 case AL_SEC_OFFSET:
977 case AL_SAMPLE_OFFSET:
978 case AL_BYTE_OFFSET:
979 case AL_CONE_INNER_ANGLE:
980 case AL_CONE_OUTER_ANGLE:
981 case AL_REFERENCE_DISTANCE:
982 case AL_CONE_OUTER_GAINHF:
983 case AL_AIR_ABSORPTION_FACTOR:
984 case AL_ROOM_ROLLOFF_FACTOR:
985 alGetSourcef(source, eParam, pflValues);
986 break;
988 case AL_POSITION:
989 case AL_VELOCITY:
990 case AL_DIRECTION:
991 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
992 break;
994 case AL_SAMPLE_RW_OFFSETS_SOFT:
995 case AL_BYTE_RW_OFFSETS_SOFT:
996 updateLen = (ALdouble)pContext->Device->UpdateSize /
997 pContext->Device->Frequency;
998 GetSourceOffset(Source, eParam, Offsets, updateLen);
999 pflValues[0] = Offsets[0];
1000 pflValues[1] = Offsets[1];
1001 break;
1003 default:
1004 alSetError(pContext, AL_INVALID_ENUM);
1005 break;
1008 else
1009 alSetError(pContext, AL_INVALID_NAME);
1011 else
1012 alSetError(pContext, AL_INVALID_VALUE);
1014 ProcessContext(pContext);
1018 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1020 ALCcontext *pContext;
1021 ALsource *Source;
1022 ALdouble Offsets[2];
1023 ALdouble updateLen;
1025 pContext = GetContextSuspended();
1026 if(!pContext) return;
1028 if(plValue)
1030 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1032 switch(eParam)
1034 case AL_MAX_DISTANCE:
1035 *plValue = (ALint)Source->flMaxDistance;
1036 break;
1038 case AL_ROLLOFF_FACTOR:
1039 *plValue = (ALint)Source->flRollOffFactor;
1040 break;
1042 case AL_REFERENCE_DISTANCE:
1043 *plValue = (ALint)Source->flRefDistance;
1044 break;
1046 case AL_SOURCE_RELATIVE:
1047 *plValue = Source->bHeadRelative;
1048 break;
1050 case AL_CONE_INNER_ANGLE:
1051 *plValue = (ALint)Source->flInnerAngle;
1052 break;
1054 case AL_CONE_OUTER_ANGLE:
1055 *plValue = (ALint)Source->flOuterAngle;
1056 break;
1058 case AL_LOOPING:
1059 *plValue = Source->bLooping;
1060 break;
1062 case AL_BUFFER:
1063 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1064 break;
1066 case AL_SOURCE_STATE:
1067 *plValue = Source->state;
1068 break;
1070 case AL_BUFFERS_QUEUED:
1071 *plValue = Source->BuffersInQueue;
1072 break;
1074 case AL_BUFFERS_PROCESSED:
1075 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1077 /* Buffers on a looping source are in a perpetual state
1078 * of PENDING, so don't report any as PROCESSED */
1079 *plValue = 0;
1081 else
1082 *plValue = Source->BuffersPlayed;
1083 break;
1085 case AL_SOURCE_TYPE:
1086 *plValue = Source->lSourceType;
1087 break;
1089 case AL_SEC_OFFSET:
1090 case AL_SAMPLE_OFFSET:
1091 case AL_BYTE_OFFSET:
1092 updateLen = (ALdouble)pContext->Device->UpdateSize /
1093 pContext->Device->Frequency;
1094 GetSourceOffset(Source, eParam, Offsets, updateLen);
1095 *plValue = (ALint)Offsets[0];
1096 break;
1098 case AL_DIRECT_FILTER:
1099 *plValue = Source->DirectFilter.filter;
1100 break;
1102 case AL_DIRECT_FILTER_GAINHF_AUTO:
1103 *plValue = Source->DryGainHFAuto;
1104 break;
1106 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1107 *plValue = Source->WetGainAuto;
1108 break;
1110 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1111 *plValue = Source->WetGainHFAuto;
1112 break;
1114 case AL_DOPPLER_FACTOR:
1115 *plValue = (ALint)Source->DopplerFactor;
1116 break;
1118 case AL_DISTANCE_MODEL:
1119 *plValue = Source->DistanceModel;
1120 break;
1122 default:
1123 alSetError(pContext, AL_INVALID_ENUM);
1124 break;
1127 else
1128 alSetError(pContext, AL_INVALID_NAME);
1130 else
1131 alSetError(pContext, AL_INVALID_VALUE);
1133 ProcessContext(pContext);
1137 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1139 ALCcontext *pContext;
1140 ALsource *Source;
1142 pContext = GetContextSuspended();
1143 if(!pContext) return;
1145 if(plValue1 && plValue2 && plValue3)
1147 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1149 switch(eParam)
1151 case AL_POSITION:
1152 *plValue1 = (ALint)Source->vPosition[0];
1153 *plValue2 = (ALint)Source->vPosition[1];
1154 *plValue3 = (ALint)Source->vPosition[2];
1155 break;
1157 case AL_VELOCITY:
1158 *plValue1 = (ALint)Source->vVelocity[0];
1159 *plValue2 = (ALint)Source->vVelocity[1];
1160 *plValue3 = (ALint)Source->vVelocity[2];
1161 break;
1163 case AL_DIRECTION:
1164 *plValue1 = (ALint)Source->vOrientation[0];
1165 *plValue2 = (ALint)Source->vOrientation[1];
1166 *plValue3 = (ALint)Source->vOrientation[2];
1167 break;
1169 default:
1170 alSetError(pContext, AL_INVALID_ENUM);
1171 break;
1174 else
1175 alSetError(pContext, AL_INVALID_NAME);
1177 else
1178 alSetError(pContext, AL_INVALID_VALUE);
1180 ProcessContext(pContext);
1184 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1186 ALCcontext *pContext;
1187 ALsource *Source;
1188 ALdouble Offsets[2];
1189 ALdouble updateLen;
1191 pContext = GetContextSuspended();
1192 if(!pContext) return;
1194 if(plValues)
1196 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1198 switch(eParam)
1200 case AL_SOURCE_RELATIVE:
1201 case AL_CONE_INNER_ANGLE:
1202 case AL_CONE_OUTER_ANGLE:
1203 case AL_LOOPING:
1204 case AL_BUFFER:
1205 case AL_SOURCE_STATE:
1206 case AL_BUFFERS_QUEUED:
1207 case AL_BUFFERS_PROCESSED:
1208 case AL_SEC_OFFSET:
1209 case AL_SAMPLE_OFFSET:
1210 case AL_BYTE_OFFSET:
1211 case AL_MAX_DISTANCE:
1212 case AL_ROLLOFF_FACTOR:
1213 case AL_DOPPLER_FACTOR:
1214 case AL_REFERENCE_DISTANCE:
1215 case AL_SOURCE_TYPE:
1216 case AL_DIRECT_FILTER:
1217 case AL_DIRECT_FILTER_GAINHF_AUTO:
1218 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1219 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1220 case AL_DISTANCE_MODEL:
1221 alGetSourcei(source, eParam, plValues);
1222 break;
1224 case AL_POSITION:
1225 case AL_VELOCITY:
1226 case AL_DIRECTION:
1227 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1228 break;
1230 case AL_SAMPLE_RW_OFFSETS_SOFT:
1231 case AL_BYTE_RW_OFFSETS_SOFT:
1232 updateLen = (ALdouble)pContext->Device->UpdateSize /
1233 pContext->Device->Frequency;
1234 GetSourceOffset(Source, eParam, Offsets, updateLen);
1235 plValues[0] = (ALint)Offsets[0];
1236 plValues[1] = (ALint)Offsets[1];
1237 break;
1239 default:
1240 alSetError(pContext, AL_INVALID_ENUM);
1241 break;
1244 else
1245 alSetError(pContext, AL_INVALID_NAME);
1247 else
1248 alSetError(pContext, AL_INVALID_VALUE);
1250 ProcessContext(pContext);
1254 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1256 alSourcePlayv(1, &source);
1259 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1261 ALCcontext *Context;
1262 ALsource *Source;
1263 ALbufferlistitem *BufferList;
1264 ALsizei i, j;
1266 Context = GetContextSuspended();
1267 if(!Context) return;
1269 if(n < 0)
1271 alSetError(Context, AL_INVALID_VALUE);
1272 goto done;
1274 if(n > 0 && !sources)
1276 alSetError(Context, AL_INVALID_VALUE);
1277 goto done;
1280 // Check that all the Sources are valid
1281 for(i = 0;i < n;i++)
1283 if(!LookupSource(Context->SourceMap, sources[i]))
1285 alSetError(Context, AL_INVALID_NAME);
1286 goto done;
1290 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1292 void *temp = NULL;
1293 ALsizei newcount;
1295 newcount = Context->MaxActiveSources << 1;
1296 if(newcount > 0)
1297 temp = realloc(Context->ActiveSources,
1298 sizeof(*Context->ActiveSources) * newcount);
1299 if(!temp)
1301 alSetError(Context, AL_OUT_OF_MEMORY);
1302 goto done;
1305 Context->ActiveSources = temp;
1306 Context->MaxActiveSources = newcount;
1309 for(i = 0;i < n;i++)
1311 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1313 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1314 BufferList = Source->queue;
1315 while(BufferList)
1317 if(BufferList->buffer != NULL && BufferList->buffer->size)
1318 break;
1319 BufferList = BufferList->next;
1322 if(!BufferList)
1324 Source->state = AL_STOPPED;
1325 Source->BuffersPlayed = Source->BuffersInQueue;
1326 Source->position = 0;
1327 Source->position_fraction = 0;
1328 Source->lOffset = 0;
1329 continue;
1332 if(Source->state != AL_PAUSED)
1334 Source->state = AL_PLAYING;
1335 Source->position = 0;
1336 Source->position_fraction = 0;
1337 Source->BuffersPlayed = 0;
1339 Source->Buffer = Source->queue->buffer;
1341 else
1342 Source->state = AL_PLAYING;
1344 // Check if an Offset has been set
1345 if(Source->lOffset)
1346 ApplyOffset(Source);
1348 // If device is disconnected, go right to stopped
1349 if(!Context->Device->Connected)
1351 Source->state = AL_STOPPED;
1352 Source->BuffersPlayed = Source->BuffersInQueue;
1353 Source->position = 0;
1354 Source->position_fraction = 0;
1356 else
1358 for(j = 0;j < Context->ActiveSourceCount;j++)
1360 if(Context->ActiveSources[j] == Source)
1361 break;
1363 if(j == Context->ActiveSourceCount)
1364 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1368 done:
1369 ProcessContext(Context);
1372 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1374 alSourcePausev(1, &source);
1377 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1379 ALCcontext *Context;
1380 ALsource *Source;
1381 ALsizei i;
1383 Context = GetContextSuspended();
1384 if(!Context) return;
1386 if(n < 0)
1388 alSetError(Context, AL_INVALID_VALUE);
1389 goto done;
1391 if(n > 0 && !sources)
1393 alSetError(Context, AL_INVALID_VALUE);
1394 goto done;
1397 // Check all the Sources are valid
1398 for(i = 0;i < n;i++)
1400 if(!LookupSource(Context->SourceMap, sources[i]))
1402 alSetError(Context, AL_INVALID_NAME);
1403 goto done;
1407 for(i = 0;i < n;i++)
1409 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1410 if(Source->state == AL_PLAYING)
1411 Source->state = AL_PAUSED;
1414 done:
1415 ProcessContext(Context);
1418 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1420 alSourceStopv(1, &source);
1423 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1425 ALCcontext *Context;
1426 ALsource *Source;
1427 ALsizei i;
1429 Context = GetContextSuspended();
1430 if(!Context) return;
1432 if(n < 0)
1434 alSetError(Context, AL_INVALID_VALUE);
1435 goto done;
1437 if(n > 0 && !sources)
1439 alSetError(Context, AL_INVALID_VALUE);
1440 goto done;
1443 // Check all the Sources are valid
1444 for(i = 0;i < n;i++)
1446 if(!LookupSource(Context->SourceMap, sources[i]))
1448 alSetError(Context, AL_INVALID_NAME);
1449 goto done;
1453 for(i = 0;i < n;i++)
1455 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1456 if(Source->state != AL_INITIAL)
1458 Source->state = AL_STOPPED;
1459 Source->BuffersPlayed = Source->BuffersInQueue;
1461 Source->lOffset = 0;
1464 done:
1465 ProcessContext(Context);
1468 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1470 alSourceRewindv(1, &source);
1473 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1475 ALCcontext *Context;
1476 ALsource *Source;
1477 ALsizei i;
1479 Context = GetContextSuspended();
1480 if(!Context) return;
1482 if(n < 0)
1484 alSetError(Context, AL_INVALID_VALUE);
1485 goto done;
1487 if(n > 0 && !sources)
1489 alSetError(Context, AL_INVALID_VALUE);
1490 goto done;
1493 // Check all the Sources are valid
1494 for(i = 0;i < n;i++)
1496 if(!LookupSource(Context->SourceMap, sources[i]))
1498 alSetError(Context, AL_INVALID_NAME);
1499 goto done;
1503 for(i = 0;i < n;i++)
1505 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1506 if(Source->state != AL_INITIAL)
1508 Source->state = AL_INITIAL;
1509 Source->position = 0;
1510 Source->position_fraction = 0;
1511 Source->BuffersPlayed = 0;
1512 if(Source->queue)
1513 Source->Buffer = Source->queue->buffer;
1515 Source->lOffset = 0;
1518 done:
1519 ProcessContext(Context);
1523 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1525 ALCcontext *Context;
1526 ALCdevice *device;
1527 ALsource *Source;
1528 ALbuffer *buffer;
1529 ALsizei i;
1530 ALbufferlistitem *BufferListStart;
1531 ALbufferlistitem *BufferList;
1532 ALint Frequency;
1533 ALint Format;
1535 if(n == 0)
1536 return;
1538 Context = GetContextSuspended();
1539 if(!Context) return;
1541 if(n < 0)
1543 alSetError(Context, AL_INVALID_VALUE);
1544 goto done;
1547 // Check that all buffers are valid or zero and that the source is valid
1549 // Check that this is a valid source
1550 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1552 alSetError(Context, AL_INVALID_NAME);
1553 goto done;
1556 // Check that this is not a STATIC Source
1557 if(Source->lSourceType == AL_STATIC)
1559 // Invalid Source Type (can't queue on a Static Source)
1560 alSetError(Context, AL_INVALID_OPERATION);
1561 goto done;
1564 device = Context->Device;
1566 Frequency = -1;
1567 Format = -1;
1569 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1570 BufferList = Source->queue;
1571 while(BufferList)
1573 if(BufferList->buffer)
1575 Frequency = BufferList->buffer->Frequency;
1576 Format = BufferList->buffer->OriginalFormat;
1577 break;
1579 BufferList = BufferList->next;
1582 for(i = 0;i < n;i++)
1584 if(!buffers[i])
1585 continue;
1587 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1589 alSetError(Context, AL_INVALID_NAME);
1590 goto done;
1593 if(Frequency == -1 && Format == -1)
1595 Frequency = buffer->Frequency;
1596 Format = buffer->OriginalFormat;
1598 if(buffer->FmtChannels == FmtMono)
1599 Source->Update = CalcSourceParams;
1600 else
1601 Source->Update = CalcNonAttnSourceParams;
1603 Source->NeedsUpdate = AL_TRUE;
1605 else if(Frequency != buffer->Frequency || Format != buffer->OriginalFormat)
1607 alSetError(Context, AL_INVALID_OPERATION);
1608 goto done;
1612 // Change Source Type
1613 Source->lSourceType = AL_STREAMING;
1615 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1617 // All buffers are valid - so add them to the list
1618 BufferListStart = malloc(sizeof(ALbufferlistitem));
1619 BufferListStart->buffer = buffer;
1620 BufferListStart->next = NULL;
1621 BufferListStart->prev = NULL;
1623 // Increment reference counter for buffer
1624 if(buffer) buffer->refcount++;
1626 BufferList = BufferListStart;
1628 for(i = 1;i < n;i++)
1630 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1632 BufferList->next = malloc(sizeof(ALbufferlistitem));
1633 BufferList->next->buffer = buffer;
1634 BufferList->next->next = NULL;
1635 BufferList->next->prev = BufferList;
1637 // Increment reference counter for buffer
1638 if(buffer) buffer->refcount++;
1640 BufferList = BufferList->next;
1643 if(Source->queue == NULL)
1645 Source->queue = BufferListStart;
1646 // Update Current Buffer
1647 Source->Buffer = BufferListStart->buffer;
1649 else
1651 // Find end of queue
1652 BufferList = Source->queue;
1653 while(BufferList->next != NULL)
1654 BufferList = BufferList->next;
1656 BufferList->next = BufferListStart;
1657 BufferList->next->prev = BufferList;
1660 // Update number of buffers in queue
1661 Source->BuffersInQueue += n;
1663 done:
1664 ProcessContext(Context);
1668 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1669 // an array of buffer IDs that are to be filled with the names of the buffers removed
1670 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1672 ALCcontext *Context;
1673 ALsource *Source;
1674 ALsizei i;
1675 ALbufferlistitem *BufferList;
1677 if(n == 0)
1678 return;
1680 Context = GetContextSuspended();
1681 if(!Context) return;
1683 if(n < 0)
1685 alSetError(Context, AL_INVALID_VALUE);
1686 goto done;
1689 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 goto done;
1695 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1696 (ALuint)n > Source->BuffersPlayed)
1698 // Some buffers can't be unqueue because they have not been processed
1699 alSetError(Context, AL_INVALID_VALUE);
1700 goto done;
1703 for(i = 0;i < n;i++)
1705 BufferList = Source->queue;
1706 Source->queue = BufferList->next;
1708 if(BufferList->buffer)
1710 // Record name of buffer
1711 buffers[i] = BufferList->buffer->buffer;
1712 // Decrement buffer reference counter
1713 BufferList->buffer->refcount--;
1715 else
1716 buffers[i] = 0;
1718 // Release memory for buffer list item
1719 free(BufferList);
1720 Source->BuffersInQueue--;
1722 if(Source->queue)
1723 Source->queue->prev = NULL;
1725 if(Source->state != AL_PLAYING)
1727 if(Source->queue)
1728 Source->Buffer = Source->queue->buffer;
1729 else
1730 Source->Buffer = NULL;
1732 Source->BuffersPlayed -= n;
1734 done:
1735 ProcessContext(Context);
1739 static ALvoid InitSourceParams(ALsource *Source)
1741 Source->flInnerAngle = 360.0f;
1742 Source->flOuterAngle = 360.0f;
1743 Source->flPitch = 1.0f;
1744 Source->vPosition[0] = 0.0f;
1745 Source->vPosition[1] = 0.0f;
1746 Source->vPosition[2] = 0.0f;
1747 Source->vOrientation[0] = 0.0f;
1748 Source->vOrientation[1] = 0.0f;
1749 Source->vOrientation[2] = 0.0f;
1750 Source->vVelocity[0] = 0.0f;
1751 Source->vVelocity[1] = 0.0f;
1752 Source->vVelocity[2] = 0.0f;
1753 Source->flRefDistance = 1.0f;
1754 Source->flMaxDistance = FLT_MAX;
1755 Source->flRollOffFactor = 1.0f;
1756 Source->bLooping = AL_FALSE;
1757 Source->flGain = 1.0f;
1758 Source->flMinGain = 0.0f;
1759 Source->flMaxGain = 1.0f;
1760 Source->flOuterGain = 0.0f;
1761 Source->OuterGainHF = 1.0f;
1763 Source->DryGainHFAuto = AL_TRUE;
1764 Source->WetGainAuto = AL_TRUE;
1765 Source->WetGainHFAuto = AL_TRUE;
1766 Source->AirAbsorptionFactor = 0.0f;
1767 Source->RoomRolloffFactor = 0.0f;
1768 Source->DopplerFactor = 1.0f;
1770 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1772 Source->Resampler = DefaultResampler;
1774 Source->state = AL_INITIAL;
1775 Source->lSourceType = AL_UNDETERMINED;
1777 Source->NeedsUpdate = AL_TRUE;
1779 Source->Buffer = NULL;
1784 GetSourceOffset
1786 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1787 The offset is relative to the start of the queue (not the start of the current buffer)
1789 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1791 ALbufferlistitem *BufferList;
1792 ALbuffer *Buffer = NULL;
1793 ALfloat BufferFreq;
1794 ALint Channels, Bytes;
1795 ALuint readPos, writePos;
1796 ALenum OriginalFormat;
1797 ALuint TotalBufferDataSize;
1798 ALuint i;
1800 // Find the first non-NULL Buffer in the Queue
1801 BufferList = Source->queue;
1802 while(BufferList)
1804 if(BufferList->buffer)
1806 Buffer = BufferList->buffer;
1807 break;
1809 BufferList = BufferList->next;
1812 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1814 offset[0] = 0.0;
1815 offset[1] = 0.0;
1816 return;
1819 // Get Current Buffer Size and frequency (in milliseconds)
1820 BufferFreq = (ALfloat)Buffer->Frequency;
1821 OriginalFormat = Buffer->OriginalFormat;
1822 Channels = ChannelsFromFmt(Buffer->FmtChannels);
1823 Bytes = BytesFromFmt(Buffer->FmtType);
1825 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1826 readPos = Source->position * Channels * Bytes;
1827 // Add byte length of any processed buffers in the queue
1828 TotalBufferDataSize = 0;
1829 BufferList = Source->queue;
1830 for(i = 0;BufferList;i++)
1832 if(BufferList->buffer)
1834 if(i < Source->BuffersPlayed)
1835 readPos += BufferList->buffer->size;
1836 TotalBufferDataSize += BufferList->buffer->size;
1838 BufferList = BufferList->next;
1840 if(Source->state == AL_PLAYING)
1841 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1842 else
1843 writePos = readPos;
1845 if(Source->bLooping)
1847 readPos %= TotalBufferDataSize;
1848 writePos %= TotalBufferDataSize;
1850 else
1852 // Wrap positions back to 0
1853 if(readPos >= TotalBufferDataSize)
1854 readPos = 0;
1855 if(writePos >= TotalBufferDataSize)
1856 writePos = 0;
1859 switch(name)
1861 case AL_SEC_OFFSET:
1862 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1863 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1864 break;
1865 case AL_SAMPLE_OFFSET:
1866 case AL_SAMPLE_RW_OFFSETS_SOFT:
1867 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1868 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1869 break;
1870 case AL_BYTE_OFFSET:
1871 case AL_BYTE_RW_OFFSETS_SOFT:
1872 // Take into account the original format of the Buffer
1873 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1874 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1876 ALuint FrameBlockSize = 65 * Bytes * Channels;
1877 ALuint BlockSize = 36 * Channels;
1879 // Round down to nearest ADPCM block
1880 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1881 if(Source->state != AL_PLAYING)
1882 offset[1] = offset[0];
1883 else
1885 // Round up to nearest ADPCM block
1886 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1887 FrameBlockSize * BlockSize);
1890 else
1892 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1893 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1894 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1896 break;
1902 ApplyOffset
1904 Apply a playback offset to the Source. This function will update the queue (to correctly
1905 mark buffers as 'pending' or 'processed' depending upon the new offset.
1907 static ALboolean ApplyOffset(ALsource *Source)
1909 ALbufferlistitem *BufferList;
1910 ALbuffer *Buffer;
1911 ALint lBufferSize, lTotalBufferSize;
1912 ALint BuffersPlayed;
1913 ALint lByteOffset;
1915 // Get true byte offset
1916 lByteOffset = GetByteOffset(Source);
1918 // If the offset is invalid, don't apply it
1919 if(lByteOffset == -1)
1920 return AL_FALSE;
1922 // Sort out the queue (pending and processed states)
1923 BufferList = Source->queue;
1924 lTotalBufferSize = 0;
1925 BuffersPlayed = 0;
1927 while(BufferList)
1929 Buffer = BufferList->buffer;
1930 lBufferSize = Buffer ? Buffer->size : 0;
1932 if(lBufferSize <= lByteOffset-lTotalBufferSize)
1934 // Offset is past this buffer so increment BuffersPlayed
1935 BuffersPlayed++;
1937 else if(lTotalBufferSize <= lByteOffset)
1939 // Offset is within this buffer
1940 // Set Current Buffer
1941 Source->Buffer = BufferList->buffer;
1942 Source->BuffersPlayed = BuffersPlayed;
1944 // SW Mixer Positions are in Samples
1945 Source->position = (lByteOffset - lTotalBufferSize) /
1946 FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
1947 return AL_TRUE;
1950 // Increment the TotalBufferSize
1951 lTotalBufferSize += lBufferSize;
1953 // Move on to next buffer in the Queue
1954 BufferList = BufferList->next;
1956 // Offset is out of range of the buffer queue
1957 return AL_FALSE;
1962 GetByteOffset
1964 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1965 offset supplied by the application). This takes into account the fact that the buffer format
1966 may have been modifed by AL (e.g 8bit samples are converted to float)
1968 static ALint GetByteOffset(ALsource *Source)
1970 ALbuffer *Buffer = NULL;
1971 ALbufferlistitem *BufferList;
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 // Determine the ByteOffset (and ensure it is block aligned)
1993 switch(Source->lOffsetType)
1995 case AL_BYTE_OFFSET:
1996 // Take into consideration the original format
1997 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->OriginalFormat);
1998 ByteOffset *= FrameSizeFromFmt(Buffer->FmtType, Buffer->FmtChannels);
1999 break;
2001 case AL_SAMPLE_OFFSET:
2002 ByteOffset = Source->lOffset * BytesFromFmt(Buffer->FmtType);
2003 break;
2005 case AL_SEC_OFFSET:
2006 // Note - lOffset is internally stored as Milliseconds
2007 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2008 ByteOffset *= BytesFromFmt(Buffer->FmtType);
2009 break;
2011 // Clear Offset
2012 Source->lOffset = 0;
2014 return ByteOffset;
2017 static ALint FramesFromBytes(ALint offset, ALenum format)
2019 if(format==AL_FORMAT_MONO_IMA4)
2021 // Round down to nearest ADPCM block
2022 offset /= 36;
2023 // Multiply by compression rate (65 sample frames per block)
2024 offset *= 65;
2026 else if(format==AL_FORMAT_STEREO_IMA4)
2028 offset /= 36 * 2;
2029 offset *= 65;
2031 else
2032 offset /= aluFrameSizeFromFormat(format);
2033 return offset;
2037 ALvoid ReleaseALSources(ALCcontext *Context)
2039 ALsizei pos;
2040 ALuint j;
2041 for(pos = 0;pos < Context->SourceMap.size;pos++)
2043 ALsource *temp = Context->SourceMap.array[pos].value;
2044 Context->SourceMap.array[pos].value = NULL;
2046 // For each buffer in the source's queue, decrement its reference counter and remove it
2047 while(temp->queue != NULL)
2049 ALbufferlistitem *BufferList = temp->queue;
2050 temp->queue = BufferList->next;
2052 if(BufferList->buffer != NULL)
2053 BufferList->buffer->refcount--;
2054 free(BufferList);
2057 for(j = 0;j < MAX_SENDS;++j)
2059 if(temp->Send[j].Slot)
2060 temp->Send[j].Slot->refcount--;
2061 temp->Send[j].Slot = NULL;
2064 // Release source structure
2065 ALTHUNK_REMOVEENTRY(temp->source);
2066 memset(temp, 0, sizeof(ALsource));
2067 free(temp);