Check for invalid negative sizes
[openal-soft.git] / OpenAL32 / alSource.c
blob8df2935c9d2f80220afb9cbc39e98b94c7de88e2
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *Source);
36 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
37 static ALboolean ApplyOffset(ALsource *Source);
38 static ALint GetByteOffset(ALsource *Source);
39 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels);
41 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
42 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
43 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
44 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
46 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
48 ALCcontext *Context;
49 ALCdevice *Device;
50 ALsizei i=0;
52 Context = GetContextSuspended();
53 if(!Context) return;
55 if(n < 0)
56 alSetError(Context, AL_INVALID_VALUE);
57 else
59 Device = Context->Device;
61 // Check that enough memory has been allocted in the 'sources' array for n Sources
62 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
64 // Check that the requested number of sources can be generated
65 if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources)
67 ALenum err;
69 // Add additional sources to the list
70 while(i < n)
72 ALsource *source = calloc(1, sizeof(ALsource));
73 if(!source)
75 alSetError(Context, AL_OUT_OF_MEMORY);
76 alDeleteSources(i, sources);
77 break;
80 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
81 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
82 source);
83 if(err != AL_NO_ERROR)
85 ALTHUNK_REMOVEENTRY(source->source);
86 memset(source, 0, sizeof(ALsource));
87 free(source);
89 alSetError(Context, err);
90 alDeleteSources(i, sources);
91 break;
94 sources[i++] = source->source;
95 InitSourceParams(source);
98 else
100 // Not enough resources to create the Sources
101 alSetError(Context, AL_INVALID_VALUE);
104 else
106 // Bad pointer
107 alSetError(Context, AL_INVALID_VALUE);
111 ProcessContext(Context);
115 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
117 ALCcontext *Context;
118 ALCdevice *Device;
119 ALsource *Source;
120 ALsizei i, j;
121 ALbufferlistitem *BufferList;
122 ALboolean bSourcesValid = AL_TRUE;
124 Context = GetContextSuspended();
125 if(!Context) return;
127 if(n < 0)
128 alSetError(Context, AL_INVALID_VALUE);
129 else
131 Device = Context->Device;
133 // Check that all Sources are valid (and can therefore be deleted)
134 for(i = 0;i < n;i++)
136 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
138 alSetError(Context, AL_INVALID_NAME);
139 bSourcesValid = AL_FALSE;
140 break;
144 if(bSourcesValid)
146 // All Sources are valid, and can be deleted
147 for(i = 0;i < n;i++)
149 // Recheck that the Source is valid, because there could be duplicated Source names
150 if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL)
152 for(j = 0;j < Context->ActiveSourceCount;j++)
154 if(Context->ActiveSources[j] == Source)
156 ALsizei end = --(Context->ActiveSourceCount);
157 Context->ActiveSources[j] = Context->ActiveSources[end];
158 break;
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while(Source->queue != NULL)
165 BufferList = Source->queue;
166 // Decrement buffer's reference counter
167 if(BufferList->buffer != NULL)
168 BufferList->buffer->refcount--;
169 // Update queue to point to next element in list
170 Source->queue = BufferList->next;
171 // Release memory allocated for buffer list item
172 free(BufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(Source->Send[j].Slot)
178 Source->Send[j].Slot->refcount--;
179 Source->Send[j].Slot = NULL;
182 // Remove Source from list of Sources
183 RemoveUIntMapKey(&Context->SourceMap, Source->source);
184 ALTHUNK_REMOVEENTRY(Source->source);
186 memset(Source,0,sizeof(ALsource));
187 free(Source);
193 ProcessContext(Context);
197 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
199 ALCcontext *Context;
200 ALboolean result;
202 Context = GetContextSuspended();
203 if(!Context) return AL_FALSE;
205 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
207 ProcessContext(Context);
209 return result;
213 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *Source;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
223 switch(eParam)
225 case AL_PITCH:
226 if(flValue >= 0.0f)
228 Source->flPitch = flValue;
229 if(Source->flPitch < 0.001f)
230 Source->flPitch = 0.001f;
231 Source->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_CONE_INNER_ANGLE:
238 if(flValue >= 0.0f && flValue <= 360.0f)
240 Source->flInnerAngle = flValue;
241 Source->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_CONE_OUTER_ANGLE:
248 if(flValue >= 0.0f && flValue <= 360.0f)
250 Source->flOuterAngle = flValue;
251 Source->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_GAIN:
258 if(flValue >= 0.0f)
260 Source->flGain = flValue;
261 Source->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_MAX_DISTANCE:
268 if(flValue >= 0.0f)
270 Source->flMaxDistance = flValue;
271 Source->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_ROLLOFF_FACTOR:
278 if(flValue >= 0.0f)
280 Source->flRollOffFactor = flValue;
281 Source->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_REFERENCE_DISTANCE:
288 if(flValue >= 0.0f)
290 Source->flRefDistance = flValue;
291 Source->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_MIN_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 Source->flMinGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_MAX_GAIN:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 Source->flMaxGain = flValue;
311 Source->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_CONE_OUTER_GAIN:
318 if(flValue >= 0.0f && flValue <= 1.0f)
320 Source->flOuterGain = flValue;
321 Source->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_CONE_OUTER_GAINHF:
328 if(flValue >= 0.0f && flValue <= 1.0f)
330 Source->OuterGainHF = flValue;
331 Source->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_AIR_ABSORPTION_FACTOR:
338 if(flValue >= 0.0f && flValue <= 10.0f)
340 Source->AirAbsorptionFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_ROOM_ROLLOFF_FACTOR:
348 if(flValue >= 0.0f && flValue <= 10.0f)
350 Source->RoomRolloffFactor = flValue;
351 Source->NeedsUpdate = AL_TRUE;
353 else
354 alSetError(pContext, AL_INVALID_VALUE);
355 break;
357 case AL_DOPPLER_FACTOR:
358 if(flValue >= 0.0f && flValue <= 1.0f)
360 Source->DopplerFactor = flValue;
361 Source->NeedsUpdate = AL_TRUE;
363 else
364 alSetError(pContext, AL_INVALID_VALUE);
365 break;
367 case AL_SEC_OFFSET:
368 case AL_SAMPLE_OFFSET:
369 case AL_BYTE_OFFSET:
370 if(flValue >= 0.0f)
372 Source->lOffsetType = eParam;
374 // Store Offset (convert Seconds into Milliseconds)
375 if(eParam == AL_SEC_OFFSET)
376 Source->lOffset = (ALint)(flValue * 1000.0f);
377 else
378 Source->lOffset = (ALint)flValue;
380 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
382 if(ApplyOffset(Source) == AL_FALSE)
383 alSetError(pContext, AL_INVALID_VALUE);
386 else
387 alSetError(pContext, AL_INVALID_VALUE);
388 break;
390 default:
391 alSetError(pContext, AL_INVALID_ENUM);
392 break;
395 else
397 // Invalid Source Name
398 alSetError(pContext, AL_INVALID_NAME);
401 ProcessContext(pContext);
405 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
407 ALCcontext *pContext;
408 ALsource *Source;
410 pContext = GetContextSuspended();
411 if(!pContext) return;
413 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
415 switch(eParam)
417 case AL_POSITION:
418 Source->vPosition[0] = flValue1;
419 Source->vPosition[1] = flValue2;
420 Source->vPosition[2] = flValue3;
421 Source->NeedsUpdate = AL_TRUE;
422 break;
424 case AL_VELOCITY:
425 Source->vVelocity[0] = flValue1;
426 Source->vVelocity[1] = flValue2;
427 Source->vVelocity[2] = flValue3;
428 Source->NeedsUpdate = AL_TRUE;
429 break;
431 case AL_DIRECTION:
432 Source->vOrientation[0] = flValue1;
433 Source->vOrientation[1] = flValue2;
434 Source->vOrientation[2] = flValue3;
435 Source->NeedsUpdate = AL_TRUE;
436 break;
438 default:
439 alSetError(pContext, AL_INVALID_ENUM);
440 break;
443 else
444 alSetError(pContext, AL_INVALID_NAME);
446 ProcessContext(pContext);
450 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
452 ALCcontext *pContext;
454 pContext = GetContextSuspended();
455 if(!pContext) return;
457 if(pflValues)
459 if(LookupSource(pContext->SourceMap, source) != NULL)
461 switch(eParam)
463 case AL_PITCH:
464 case AL_CONE_INNER_ANGLE:
465 case AL_CONE_OUTER_ANGLE:
466 case AL_GAIN:
467 case AL_MAX_DISTANCE:
468 case AL_ROLLOFF_FACTOR:
469 case AL_REFERENCE_DISTANCE:
470 case AL_MIN_GAIN:
471 case AL_MAX_GAIN:
472 case AL_CONE_OUTER_GAIN:
473 case AL_CONE_OUTER_GAINHF:
474 case AL_SEC_OFFSET:
475 case AL_SAMPLE_OFFSET:
476 case AL_BYTE_OFFSET:
477 case AL_AIR_ABSORPTION_FACTOR:
478 case AL_ROOM_ROLLOFF_FACTOR:
479 alSourcef(source, eParam, pflValues[0]);
480 break;
482 case AL_POSITION:
483 case AL_VELOCITY:
484 case AL_DIRECTION:
485 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
486 break;
488 default:
489 alSetError(pContext, AL_INVALID_ENUM);
490 break;
493 else
494 alSetError(pContext, AL_INVALID_NAME);
496 else
497 alSetError(pContext, AL_INVALID_VALUE);
499 ProcessContext(pContext);
503 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
505 ALCcontext *pContext;
506 ALsource *Source;
507 ALbufferlistitem *BufferListItem;
509 pContext = GetContextSuspended();
510 if(!pContext) return;
512 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
514 ALCdevice *device = pContext->Device;
516 switch(eParam)
518 case AL_MAX_DISTANCE:
519 case AL_ROLLOFF_FACTOR:
520 case AL_CONE_INNER_ANGLE:
521 case AL_CONE_OUTER_ANGLE:
522 case AL_REFERENCE_DISTANCE:
523 alSourcef(source, eParam, (ALfloat)lValue);
524 break;
526 case AL_SOURCE_RELATIVE:
527 if(lValue == AL_FALSE || lValue == AL_TRUE)
529 Source->bHeadRelative = (ALboolean)lValue;
530 Source->NeedsUpdate = AL_TRUE;
532 else
533 alSetError(pContext, AL_INVALID_VALUE);
534 break;
536 case AL_LOOPING:
537 if(lValue == AL_FALSE || lValue == AL_TRUE)
538 Source->bLooping = (ALboolean)lValue;
539 else
540 alSetError(pContext, AL_INVALID_VALUE);
541 break;
543 case AL_BUFFER:
544 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
546 ALbuffer *buffer = NULL;
548 if(lValue == 0 ||
549 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
551 // Remove all elements in the queue
552 while(Source->queue != NULL)
554 BufferListItem = Source->queue;
555 Source->queue = BufferListItem->next;
556 // Decrement reference counter for buffer
557 if(BufferListItem->buffer)
558 BufferListItem->buffer->refcount--;
559 // Release memory for buffer list item
560 free(BufferListItem);
561 // Decrement the number of buffers in the queue
562 Source->BuffersInQueue--;
565 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
566 if(lValue != 0)
568 // Source is now in STATIC mode
569 Source->lSourceType = AL_STATIC;
571 // Add the selected buffer to the queue
572 BufferListItem = malloc(sizeof(ALbufferlistitem));
573 BufferListItem->buffer = buffer;
574 BufferListItem->next = NULL;
576 Source->queue = BufferListItem;
577 Source->BuffersInQueue = 1;
579 if(aluChannelsFromFormat(buffer->format) == 1)
580 Source->Update = CalcSourceParams;
581 else
582 Source->Update = CalcNonAttnSourceParams;
584 // Increment reference counter for buffer
585 buffer->refcount++;
587 else
589 // Source is now in UNDETERMINED mode
590 Source->lSourceType = AL_UNDETERMINED;
592 Source->BuffersPlayed = 0;
594 // Update AL_BUFFER parameter
595 Source->Buffer = buffer;
596 Source->NeedsUpdate = AL_TRUE;
598 else
599 alSetError(pContext, AL_INVALID_VALUE);
601 else
602 alSetError(pContext, AL_INVALID_OPERATION);
603 break;
605 case AL_SOURCE_STATE:
606 // Query only
607 alSetError(pContext, AL_INVALID_OPERATION);
608 break;
610 case AL_SEC_OFFSET:
611 case AL_SAMPLE_OFFSET:
612 case AL_BYTE_OFFSET:
613 if(lValue >= 0)
615 Source->lOffsetType = eParam;
617 // Store Offset (convert Seconds into Milliseconds)
618 if(eParam == AL_SEC_OFFSET)
619 Source->lOffset = lValue * 1000;
620 else
621 Source->lOffset = lValue;
623 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
625 if(ApplyOffset(Source) == AL_FALSE)
626 alSetError(pContext, AL_INVALID_VALUE);
629 else
630 alSetError(pContext, AL_INVALID_VALUE);
631 break;
633 case AL_DIRECT_FILTER: {
634 ALfilter *filter = NULL;
636 if(lValue == 0 ||
637 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
639 if(!filter)
641 Source->DirectFilter.type = AL_FILTER_NULL;
642 Source->DirectFilter.filter = 0;
644 else
645 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
646 Source->NeedsUpdate = AL_TRUE;
648 else
649 alSetError(pContext, AL_INVALID_VALUE);
650 } break;
652 case AL_DIRECT_FILTER_GAINHF_AUTO:
653 if(lValue == AL_TRUE || lValue == AL_FALSE)
655 Source->DryGainHFAuto = lValue;
656 Source->NeedsUpdate = AL_TRUE;
658 else
659 alSetError(pContext, AL_INVALID_VALUE);
660 break;
662 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
663 if(lValue == AL_TRUE || lValue == AL_FALSE)
665 Source->WetGainAuto = lValue;
666 Source->NeedsUpdate = AL_TRUE;
668 else
669 alSetError(pContext, AL_INVALID_VALUE);
670 break;
672 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
673 if(lValue == AL_TRUE || lValue == AL_FALSE)
675 Source->WetGainHFAuto = lValue;
676 Source->NeedsUpdate = AL_TRUE;
678 else
679 alSetError(pContext, AL_INVALID_VALUE);
680 break;
682 case AL_DISTANCE_MODEL:
683 if(lValue == AL_NONE ||
684 lValue == AL_INVERSE_DISTANCE ||
685 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
686 lValue == AL_LINEAR_DISTANCE ||
687 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
688 lValue == AL_EXPONENT_DISTANCE ||
689 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
691 Source->DistanceModel = lValue;
692 if(pContext->SourceDistanceModel)
693 Source->NeedsUpdate = AL_TRUE;
695 else
696 alSetError(pContext, AL_INVALID_VALUE);
697 break;
699 default:
700 alSetError(pContext, AL_INVALID_ENUM);
701 break;
704 else
705 alSetError(pContext, AL_INVALID_NAME);
707 ProcessContext(pContext);
711 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
713 ALCcontext *pContext;
714 ALsource *Source;
716 pContext = GetContextSuspended();
717 if(!pContext) return;
719 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
721 ALCdevice *device = pContext->Device;
723 switch (eParam)
725 case AL_POSITION:
726 case AL_VELOCITY:
727 case AL_DIRECTION:
728 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
729 break;
731 case AL_AUXILIARY_SEND_FILTER: {
732 ALeffectslot *ALEffectSlot = NULL;
733 ALfilter *ALFilter = NULL;
735 if((ALuint)lValue2 < device->NumAuxSends &&
736 (lValue1 == 0 ||
737 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
738 (lValue3 == 0 ||
739 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
741 /* Release refcount on the previous slot, and add one for
742 * the new slot */
743 if(Source->Send[lValue2].Slot)
744 Source->Send[lValue2].Slot->refcount--;
745 Source->Send[lValue2].Slot = ALEffectSlot;
746 if(Source->Send[lValue2].Slot)
747 Source->Send[lValue2].Slot->refcount++;
749 if(!ALFilter)
751 /* Disable filter */
752 Source->Send[lValue2].WetFilter.type = 0;
753 Source->Send[lValue2].WetFilter.filter = 0;
755 else
756 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
757 Source->NeedsUpdate = AL_TRUE;
759 else
760 alSetError(pContext, AL_INVALID_VALUE);
761 } break;
763 default:
764 alSetError(pContext, AL_INVALID_ENUM);
765 break;
768 else
769 alSetError(pContext, AL_INVALID_NAME);
771 ProcessContext(pContext);
775 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
777 ALCcontext *pContext;
779 pContext = GetContextSuspended();
780 if(!pContext) return;
782 if(plValues)
784 if(LookupSource(pContext->SourceMap, source) != NULL)
786 switch(eParam)
788 case AL_SOURCE_RELATIVE:
789 case AL_CONE_INNER_ANGLE:
790 case AL_CONE_OUTER_ANGLE:
791 case AL_LOOPING:
792 case AL_BUFFER:
793 case AL_SOURCE_STATE:
794 case AL_SEC_OFFSET:
795 case AL_SAMPLE_OFFSET:
796 case AL_BYTE_OFFSET:
797 case AL_MAX_DISTANCE:
798 case AL_ROLLOFF_FACTOR:
799 case AL_REFERENCE_DISTANCE:
800 case AL_DIRECT_FILTER:
801 case AL_DIRECT_FILTER_GAINHF_AUTO:
802 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
803 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
804 case AL_DISTANCE_MODEL:
805 alSourcei(source, eParam, plValues[0]);
806 break;
808 case AL_POSITION:
809 case AL_VELOCITY:
810 case AL_DIRECTION:
811 case AL_AUXILIARY_SEND_FILTER:
812 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
813 break;
815 default:
816 alSetError(pContext, AL_INVALID_ENUM);
817 break;
820 else
821 alSetError(pContext, AL_INVALID_NAME);
823 else
824 alSetError(pContext, AL_INVALID_VALUE);
826 ProcessContext(pContext);
830 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
832 ALCcontext *pContext;
833 ALsource *Source;
834 ALdouble Offsets[2];
835 ALdouble updateLen;
837 pContext = GetContextSuspended();
838 if(!pContext) return;
840 if(pflValue)
842 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
844 switch(eParam)
846 case AL_PITCH:
847 *pflValue = Source->flPitch;
848 break;
850 case AL_GAIN:
851 *pflValue = Source->flGain;
852 break;
854 case AL_MIN_GAIN:
855 *pflValue = Source->flMinGain;
856 break;
858 case AL_MAX_GAIN:
859 *pflValue = Source->flMaxGain;
860 break;
862 case AL_MAX_DISTANCE:
863 *pflValue = Source->flMaxDistance;
864 break;
866 case AL_ROLLOFF_FACTOR:
867 *pflValue = Source->flRollOffFactor;
868 break;
870 case AL_CONE_OUTER_GAIN:
871 *pflValue = Source->flOuterGain;
872 break;
874 case AL_CONE_OUTER_GAINHF:
875 *pflValue = Source->OuterGainHF;
876 break;
878 case AL_SEC_OFFSET:
879 case AL_SAMPLE_OFFSET:
880 case AL_BYTE_OFFSET:
881 updateLen = (ALdouble)pContext->Device->UpdateSize /
882 pContext->Device->Frequency;
883 GetSourceOffset(Source, eParam, Offsets, updateLen);
884 *pflValue = Offsets[0];
885 break;
887 case AL_CONE_INNER_ANGLE:
888 *pflValue = Source->flInnerAngle;
889 break;
891 case AL_CONE_OUTER_ANGLE:
892 *pflValue = Source->flOuterAngle;
893 break;
895 case AL_REFERENCE_DISTANCE:
896 *pflValue = Source->flRefDistance;
897 break;
899 case AL_AIR_ABSORPTION_FACTOR:
900 *pflValue = Source->AirAbsorptionFactor;
901 break;
903 case AL_ROOM_ROLLOFF_FACTOR:
904 *pflValue = Source->RoomRolloffFactor;
905 break;
907 case AL_DOPPLER_FACTOR:
908 *pflValue = Source->DopplerFactor;
909 break;
911 default:
912 alSetError(pContext, AL_INVALID_ENUM);
913 break;
916 else
917 alSetError(pContext, AL_INVALID_NAME);
919 else
920 alSetError(pContext, AL_INVALID_VALUE);
922 ProcessContext(pContext);
926 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
928 ALCcontext *pContext;
929 ALsource *Source;
931 pContext = GetContextSuspended();
932 if(!pContext) return;
934 if(pflValue1 && pflValue2 && pflValue3)
936 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
938 switch(eParam)
940 case AL_POSITION:
941 *pflValue1 = Source->vPosition[0];
942 *pflValue2 = Source->vPosition[1];
943 *pflValue3 = Source->vPosition[2];
944 break;
946 case AL_VELOCITY:
947 *pflValue1 = Source->vVelocity[0];
948 *pflValue2 = Source->vVelocity[1];
949 *pflValue3 = Source->vVelocity[2];
950 break;
952 case AL_DIRECTION:
953 *pflValue1 = Source->vOrientation[0];
954 *pflValue2 = Source->vOrientation[1];
955 *pflValue3 = Source->vOrientation[2];
956 break;
958 default:
959 alSetError(pContext, AL_INVALID_ENUM);
960 break;
963 else
964 alSetError(pContext, AL_INVALID_NAME);
966 else
967 alSetError(pContext, AL_INVALID_VALUE);
969 ProcessContext(pContext);
973 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
975 ALCcontext *pContext;
976 ALsource *Source;
977 ALdouble Offsets[2];
978 ALdouble updateLen;
980 pContext = GetContextSuspended();
981 if(!pContext) return;
983 if(pflValues)
985 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
987 switch(eParam)
989 case AL_PITCH:
990 case AL_GAIN:
991 case AL_MIN_GAIN:
992 case AL_MAX_GAIN:
993 case AL_MAX_DISTANCE:
994 case AL_ROLLOFF_FACTOR:
995 case AL_DOPPLER_FACTOR:
996 case AL_CONE_OUTER_GAIN:
997 case AL_SEC_OFFSET:
998 case AL_SAMPLE_OFFSET:
999 case AL_BYTE_OFFSET:
1000 case AL_CONE_INNER_ANGLE:
1001 case AL_CONE_OUTER_ANGLE:
1002 case AL_REFERENCE_DISTANCE:
1003 case AL_CONE_OUTER_GAINHF:
1004 case AL_AIR_ABSORPTION_FACTOR:
1005 case AL_ROOM_ROLLOFF_FACTOR:
1006 alGetSourcef(source, eParam, pflValues);
1007 break;
1009 case AL_POSITION:
1010 case AL_VELOCITY:
1011 case AL_DIRECTION:
1012 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1013 break;
1015 case AL_SAMPLE_RW_OFFSETS_EXT:
1016 case AL_BYTE_RW_OFFSETS_EXT:
1017 updateLen = (ALdouble)pContext->Device->UpdateSize /
1018 pContext->Device->Frequency;
1019 GetSourceOffset(Source, eParam, Offsets, updateLen);
1020 pflValues[0] = Offsets[0];
1021 pflValues[1] = Offsets[1];
1022 break;
1024 default:
1025 alSetError(pContext, AL_INVALID_ENUM);
1026 break;
1029 else
1030 alSetError(pContext, AL_INVALID_NAME);
1032 else
1033 alSetError(pContext, AL_INVALID_VALUE);
1035 ProcessContext(pContext);
1039 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1041 ALCcontext *pContext;
1042 ALsource *Source;
1043 ALdouble Offsets[2];
1044 ALdouble updateLen;
1046 pContext = GetContextSuspended();
1047 if(!pContext) return;
1049 if(plValue)
1051 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1053 switch(eParam)
1055 case AL_MAX_DISTANCE:
1056 *plValue = (ALint)Source->flMaxDistance;
1057 break;
1059 case AL_ROLLOFF_FACTOR:
1060 *plValue = (ALint)Source->flRollOffFactor;
1061 break;
1063 case AL_REFERENCE_DISTANCE:
1064 *plValue = (ALint)Source->flRefDistance;
1065 break;
1067 case AL_SOURCE_RELATIVE:
1068 *plValue = Source->bHeadRelative;
1069 break;
1071 case AL_CONE_INNER_ANGLE:
1072 *plValue = (ALint)Source->flInnerAngle;
1073 break;
1075 case AL_CONE_OUTER_ANGLE:
1076 *plValue = (ALint)Source->flOuterAngle;
1077 break;
1079 case AL_LOOPING:
1080 *plValue = Source->bLooping;
1081 break;
1083 case AL_BUFFER:
1084 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1085 break;
1087 case AL_SOURCE_STATE:
1088 *plValue = Source->state;
1089 break;
1091 case AL_BUFFERS_QUEUED:
1092 *plValue = Source->BuffersInQueue;
1093 break;
1095 case AL_BUFFERS_PROCESSED:
1096 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1098 /* Buffers on a looping source are in a perpetual state
1099 * of PENDING, so don't report any as PROCESSED */
1100 *plValue = 0;
1102 else
1103 *plValue = Source->BuffersPlayed;
1104 break;
1106 case AL_SOURCE_TYPE:
1107 *plValue = Source->lSourceType;
1108 break;
1110 case AL_SEC_OFFSET:
1111 case AL_SAMPLE_OFFSET:
1112 case AL_BYTE_OFFSET:
1113 updateLen = (ALdouble)pContext->Device->UpdateSize /
1114 pContext->Device->Frequency;
1115 GetSourceOffset(Source, eParam, Offsets, updateLen);
1116 *plValue = (ALint)Offsets[0];
1117 break;
1119 case AL_DIRECT_FILTER:
1120 *plValue = Source->DirectFilter.filter;
1121 break;
1123 case AL_DIRECT_FILTER_GAINHF_AUTO:
1124 *plValue = Source->DryGainHFAuto;
1125 break;
1127 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1128 *plValue = Source->WetGainAuto;
1129 break;
1131 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1132 *plValue = Source->WetGainHFAuto;
1133 break;
1135 case AL_DOPPLER_FACTOR:
1136 *plValue = (ALint)Source->DopplerFactor;
1137 break;
1139 case AL_DISTANCE_MODEL:
1140 *plValue = Source->DistanceModel;
1141 break;
1143 default:
1144 alSetError(pContext, AL_INVALID_ENUM);
1145 break;
1148 else
1149 alSetError(pContext, AL_INVALID_NAME);
1151 else
1152 alSetError(pContext, AL_INVALID_VALUE);
1154 ProcessContext(pContext);
1158 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1160 ALCcontext *pContext;
1161 ALsource *Source;
1163 pContext = GetContextSuspended();
1164 if(!pContext) return;
1166 if(plValue1 && plValue2 && plValue3)
1168 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1170 switch(eParam)
1172 case AL_POSITION:
1173 *plValue1 = (ALint)Source->vPosition[0];
1174 *plValue2 = (ALint)Source->vPosition[1];
1175 *plValue3 = (ALint)Source->vPosition[2];
1176 break;
1178 case AL_VELOCITY:
1179 *plValue1 = (ALint)Source->vVelocity[0];
1180 *plValue2 = (ALint)Source->vVelocity[1];
1181 *plValue3 = (ALint)Source->vVelocity[2];
1182 break;
1184 case AL_DIRECTION:
1185 *plValue1 = (ALint)Source->vOrientation[0];
1186 *plValue2 = (ALint)Source->vOrientation[1];
1187 *plValue3 = (ALint)Source->vOrientation[2];
1188 break;
1190 default:
1191 alSetError(pContext, AL_INVALID_ENUM);
1192 break;
1195 else
1196 alSetError(pContext, AL_INVALID_NAME);
1198 else
1199 alSetError(pContext, AL_INVALID_VALUE);
1201 ProcessContext(pContext);
1205 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1207 ALCcontext *pContext;
1208 ALsource *Source;
1209 ALdouble Offsets[2];
1210 ALdouble updateLen;
1212 pContext = GetContextSuspended();
1213 if(!pContext) return;
1215 if(plValues)
1217 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1219 switch(eParam)
1221 case AL_SOURCE_RELATIVE:
1222 case AL_CONE_INNER_ANGLE:
1223 case AL_CONE_OUTER_ANGLE:
1224 case AL_LOOPING:
1225 case AL_BUFFER:
1226 case AL_SOURCE_STATE:
1227 case AL_BUFFERS_QUEUED:
1228 case AL_BUFFERS_PROCESSED:
1229 case AL_SEC_OFFSET:
1230 case AL_SAMPLE_OFFSET:
1231 case AL_BYTE_OFFSET:
1232 case AL_MAX_DISTANCE:
1233 case AL_ROLLOFF_FACTOR:
1234 case AL_DOPPLER_FACTOR:
1235 case AL_REFERENCE_DISTANCE:
1236 case AL_SOURCE_TYPE:
1237 case AL_DIRECT_FILTER:
1238 case AL_DIRECT_FILTER_GAINHF_AUTO:
1239 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1240 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1241 case AL_DISTANCE_MODEL:
1242 alGetSourcei(source, eParam, plValues);
1243 break;
1245 case AL_POSITION:
1246 case AL_VELOCITY:
1247 case AL_DIRECTION:
1248 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1249 break;
1251 case AL_SAMPLE_RW_OFFSETS_EXT:
1252 case AL_BYTE_RW_OFFSETS_EXT:
1253 updateLen = (ALdouble)pContext->Device->UpdateSize /
1254 pContext->Device->Frequency;
1255 GetSourceOffset(Source, eParam, Offsets, updateLen);
1256 plValues[0] = (ALint)Offsets[0];
1257 plValues[1] = (ALint)Offsets[1];
1258 break;
1260 default:
1261 alSetError(pContext, AL_INVALID_ENUM);
1262 break;
1265 else
1266 alSetError(pContext, AL_INVALID_NAME);
1268 else
1269 alSetError(pContext, AL_INVALID_VALUE);
1271 ProcessContext(pContext);
1275 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1277 alSourcePlayv(1, &source);
1280 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1282 ALCcontext *Context;
1283 ALsource *Source;
1284 ALbufferlistitem *BufferList;
1285 ALsizei i, j;
1287 Context = GetContextSuspended();
1288 if(!Context) return;
1290 if(n < 0)
1292 alSetError(Context, AL_INVALID_VALUE);
1293 goto done;
1295 if(n > 0 && !sources)
1297 alSetError(Context, AL_INVALID_VALUE);
1298 goto done;
1301 // Check that all the Sources are valid
1302 for(i = 0;i < n;i++)
1304 if(!LookupSource(Context->SourceMap, sources[i]))
1306 alSetError(Context, AL_INVALID_NAME);
1307 goto done;
1311 if(Context->ActiveSourceCount+n < n)
1313 alSetError(Context, AL_OUT_OF_MEMORY);
1314 goto done;
1317 while(Context->MaxActiveSources-Context->ActiveSourceCount > n)
1319 void *temp = NULL;
1320 ALsizei newcount;
1322 newcount = Context->MaxActiveSources << 1;
1323 if(newcount > 0)
1324 temp = realloc(Context->ActiveSources,
1325 sizeof(*Context->ActiveSources) * newcount);
1326 if(!temp)
1328 alSetError(Context, AL_OUT_OF_MEMORY);
1329 goto done;
1332 Context->ActiveSources = temp;
1333 Context->MaxActiveSources = newcount;
1336 for(i = 0;i < n;i++)
1338 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1340 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1341 BufferList = Source->queue;
1342 while(BufferList)
1344 if(BufferList->buffer != NULL && BufferList->buffer->size)
1345 break;
1346 BufferList = BufferList->next;
1349 if(!BufferList)
1351 Source->BuffersPlayed = Source->BuffersInQueue;
1352 continue;
1355 if(Source->state != AL_PAUSED)
1357 Source->state = AL_PLAYING;
1358 Source->position = 0;
1359 Source->position_fraction = 0;
1360 Source->BuffersPlayed = 0;
1362 Source->Buffer = Source->queue->buffer;
1364 else
1365 Source->state = AL_PLAYING;
1367 // Check if an Offset has been set
1368 if(Source->lOffset)
1369 ApplyOffset(Source);
1371 // If device is disconnected, go right to stopped
1372 if(!Context->Device->Connected)
1374 Source->state = AL_STOPPED;
1375 Source->BuffersPlayed = Source->BuffersInQueue;
1376 Source->position = 0;
1377 Source->position_fraction = 0;
1379 else
1381 for(j = 0;j < Context->ActiveSourceCount;j++)
1383 if(Context->ActiveSources[j] == Source)
1384 break;
1386 if(j == Context->ActiveSourceCount)
1387 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1391 done:
1392 ProcessContext(Context);
1395 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1397 alSourcePausev(1, &source);
1400 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1402 ALCcontext *Context;
1403 ALsource *Source;
1404 ALsizei i;
1406 Context = GetContextSuspended();
1407 if(!Context) return;
1409 if(n < 0)
1411 alSetError(Context, AL_INVALID_VALUE);
1412 goto done;
1414 if(n > 0 && !sources)
1416 alSetError(Context, AL_INVALID_VALUE);
1417 goto done;
1420 // Check all the Sources are valid
1421 for(i = 0;i < n;i++)
1423 if(!LookupSource(Context->SourceMap, sources[i]))
1425 alSetError(Context, AL_INVALID_NAME);
1426 goto done;
1430 for(i = 0;i < n;i++)
1432 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1433 if(Source->state == AL_PLAYING)
1434 Source->state = AL_PAUSED;
1437 done:
1438 ProcessContext(Context);
1441 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1443 alSourceStopv(1, &source);
1446 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1448 ALCcontext *Context;
1449 ALsource *Source;
1450 ALsizei i;
1452 Context = GetContextSuspended();
1453 if(!Context) return;
1455 if(n < 0)
1457 alSetError(Context, AL_INVALID_VALUE);
1458 goto done;
1460 if(n > 0 && !sources)
1462 alSetError(Context, AL_INVALID_VALUE);
1463 goto done;
1466 // Check all the Sources are valid
1467 for(i = 0;i < n;i++)
1469 if(!LookupSource(Context->SourceMap, sources[i]))
1471 alSetError(Context, AL_INVALID_NAME);
1472 goto done;
1476 for(i = 0;i < n;i++)
1478 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1479 if(Source->state != AL_INITIAL)
1481 Source->state = AL_STOPPED;
1482 Source->BuffersPlayed = Source->BuffersInQueue;
1484 Source->lOffset = 0;
1487 done:
1488 ProcessContext(Context);
1491 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1493 alSourceRewindv(1, &source);
1496 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1498 ALCcontext *Context;
1499 ALsource *Source;
1500 ALsizei i;
1502 Context = GetContextSuspended();
1503 if(!Context) return;
1505 if(n < 0)
1507 alSetError(Context, AL_INVALID_VALUE);
1508 goto done;
1510 if(n > 0 && !sources)
1512 alSetError(Context, AL_INVALID_VALUE);
1513 goto done;
1516 // Check all the Sources are valid
1517 for(i = 0;i < n;i++)
1519 if(!LookupSource(Context->SourceMap, sources[i]))
1521 alSetError(Context, AL_INVALID_NAME);
1522 goto done;
1526 for(i = 0;i < n;i++)
1528 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1529 if(Source->state != AL_INITIAL)
1531 Source->state = AL_INITIAL;
1532 Source->position = 0;
1533 Source->position_fraction = 0;
1534 Source->BuffersPlayed = 0;
1535 if(Source->queue)
1536 Source->Buffer = Source->queue->buffer;
1538 Source->lOffset = 0;
1541 done:
1542 ProcessContext(Context);
1546 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1548 ALCcontext *Context;
1549 ALCdevice *device;
1550 ALsource *Source;
1551 ALbuffer *buffer;
1552 ALsizei i;
1553 ALbufferlistitem *BufferListStart;
1554 ALbufferlistitem *BufferList;
1555 ALint Frequency;
1556 ALint Format;
1558 if(n == 0)
1559 return;
1561 Context = GetContextSuspended();
1562 if(!Context) return;
1564 if(n < 0)
1566 alSetError(Context, AL_INVALID_VALUE);
1567 goto done;
1570 // Check that all buffers are valid or zero and that the source is valid
1572 // Check that this is a valid source
1573 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1575 alSetError(Context, AL_INVALID_NAME);
1576 goto done;
1579 // Check that this is not a STATIC Source
1580 if(Source->lSourceType == AL_STATIC)
1582 // Invalid Source Type (can't queue on a Static Source)
1583 alSetError(Context, AL_INVALID_OPERATION);
1584 goto done;
1587 device = Context->Device;
1589 Frequency = -1;
1590 Format = -1;
1592 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1593 BufferList = Source->queue;
1594 while(BufferList)
1596 if(BufferList->buffer)
1598 Frequency = BufferList->buffer->frequency;
1599 Format = BufferList->buffer->eOriginalFormat;
1600 break;
1602 BufferList = BufferList->next;
1605 for(i = 0;i < n;i++)
1607 if(!buffers[i])
1608 continue;
1610 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1612 alSetError(Context, AL_INVALID_NAME);
1613 goto done;
1616 if(Frequency == -1 && Format == -1)
1618 Frequency = buffer->frequency;
1619 Format = buffer->eOriginalFormat;
1620 if(aluChannelsFromFormat(buffer->format) == 1)
1621 Source->Update = CalcSourceParams;
1622 else
1623 Source->Update = CalcNonAttnSourceParams;
1624 Source->NeedsUpdate = AL_TRUE;
1626 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1628 alSetError(Context, AL_INVALID_OPERATION);
1629 goto done;
1633 // Change Source Type
1634 Source->lSourceType = AL_STREAMING;
1636 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1638 // All buffers are valid - so add them to the list
1639 BufferListStart = malloc(sizeof(ALbufferlistitem));
1640 BufferListStart->buffer = buffer;
1641 BufferListStart->next = NULL;
1643 // Increment reference counter for buffer
1644 if(buffer) buffer->refcount++;
1646 BufferList = BufferListStart;
1648 for(i = 1;i < n;i++)
1650 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1652 BufferList->next = malloc(sizeof(ALbufferlistitem));
1653 BufferList->next->buffer = buffer;
1654 BufferList->next->next = NULL;
1656 // Increment reference counter for buffer
1657 if(buffer) buffer->refcount++;
1659 BufferList = BufferList->next;
1662 if(Source->queue == NULL)
1664 Source->queue = BufferListStart;
1665 // Update Current Buffer
1666 Source->Buffer = BufferListStart->buffer;
1668 else
1670 // Find end of queue
1671 BufferList = Source->queue;
1672 while(BufferList->next != NULL)
1673 BufferList = BufferList->next;
1675 BufferList->next = BufferListStart;
1678 // Update number of buffers in queue
1679 Source->BuffersInQueue += n;
1681 done:
1682 ProcessContext(Context);
1686 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1687 // an array of buffer IDs that are to be filled with the names of the buffers removed
1688 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1690 ALCcontext *Context;
1691 ALsource *Source;
1692 ALsizei i;
1693 ALbufferlistitem *BufferList;
1695 if(n == 0)
1696 return;
1698 Context = GetContextSuspended();
1699 if(!Context) return;
1701 if(n < 0)
1703 alSetError(Context, AL_INVALID_VALUE);
1704 goto done;
1707 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1709 alSetError(Context, AL_INVALID_NAME);
1710 goto done;
1713 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1714 (ALuint)n > Source->BuffersPlayed)
1716 // Some buffers can't be unqueue because they have not been processed
1717 alSetError(Context, AL_INVALID_VALUE);
1718 goto done;
1721 for(i = 0;i < n;i++)
1723 BufferList = Source->queue;
1724 Source->queue = BufferList->next;
1726 if(BufferList->buffer)
1728 // Record name of buffer
1729 buffers[i] = BufferList->buffer->buffer;
1730 // Decrement buffer reference counter
1731 BufferList->buffer->refcount--;
1733 else
1734 buffers[i] = 0;
1736 // Release memory for buffer list item
1737 free(BufferList);
1738 Source->BuffersInQueue--;
1741 if(Source->state != AL_PLAYING)
1743 if(Source->queue)
1744 Source->Buffer = Source->queue->buffer;
1745 else
1746 Source->Buffer = NULL;
1748 Source->BuffersPlayed -= n;
1750 done:
1751 ProcessContext(Context);
1755 static ALvoid InitSourceParams(ALsource *Source)
1757 Source->flInnerAngle = 360.0f;
1758 Source->flOuterAngle = 360.0f;
1759 Source->flPitch = 1.0f;
1760 Source->vPosition[0] = 0.0f;
1761 Source->vPosition[1] = 0.0f;
1762 Source->vPosition[2] = 0.0f;
1763 Source->vOrientation[0] = 0.0f;
1764 Source->vOrientation[1] = 0.0f;
1765 Source->vOrientation[2] = 0.0f;
1766 Source->vVelocity[0] = 0.0f;
1767 Source->vVelocity[1] = 0.0f;
1768 Source->vVelocity[2] = 0.0f;
1769 Source->flRefDistance = 1.0f;
1770 Source->flMaxDistance = FLT_MAX;
1771 Source->flRollOffFactor = 1.0f;
1772 Source->bLooping = AL_FALSE;
1773 Source->flGain = 1.0f;
1774 Source->flMinGain = 0.0f;
1775 Source->flMaxGain = 1.0f;
1776 Source->flOuterGain = 0.0f;
1777 Source->OuterGainHF = 1.0f;
1779 Source->DryGainHFAuto = AL_TRUE;
1780 Source->WetGainAuto = AL_TRUE;
1781 Source->WetGainHFAuto = AL_TRUE;
1782 Source->AirAbsorptionFactor = 0.0f;
1783 Source->RoomRolloffFactor = 0.0f;
1784 Source->DopplerFactor = 1.0f;
1786 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1788 Source->Resampler = DefaultResampler;
1790 Source->state = AL_INITIAL;
1791 Source->lSourceType = AL_UNDETERMINED;
1793 Source->NeedsUpdate = AL_TRUE;
1795 Source->Buffer = NULL;
1800 GetSourceOffset
1802 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1803 The offset is relative to the start of the queue (not the start of the current buffer)
1805 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1807 ALbufferlistitem *BufferList;
1808 ALbuffer *Buffer = NULL;
1809 ALfloat BufferFreq;
1810 ALint Channels, Bytes;
1811 ALuint readPos, writePos;
1812 ALenum OriginalFormat;
1813 ALuint TotalBufferDataSize;
1814 ALuint i;
1816 // Find the first non-NULL Buffer in the Queue
1817 BufferList = Source->queue;
1818 while(BufferList)
1820 if(BufferList->buffer)
1822 Buffer = BufferList->buffer;
1823 break;
1825 BufferList = BufferList->next;
1828 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1830 offset[0] = 0.0;
1831 offset[1] = 0.0;
1832 return;
1835 // Get Current Buffer Size and frequency (in milliseconds)
1836 BufferFreq = (ALfloat)Buffer->frequency;
1837 OriginalFormat = Buffer->eOriginalFormat;
1838 Channels = aluChannelsFromFormat(Buffer->format);
1839 Bytes = aluBytesFromFormat(Buffer->format);
1841 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1842 readPos = Source->position * Channels * Bytes;
1843 // Add byte length of any processed buffers in the queue
1844 TotalBufferDataSize = 0;
1845 BufferList = Source->queue;
1846 for(i = 0;BufferList;i++)
1848 if(BufferList->buffer)
1850 if(i < Source->BuffersPlayed)
1851 readPos += BufferList->buffer->size;
1852 TotalBufferDataSize += BufferList->buffer->size;
1854 BufferList = BufferList->next;
1856 if(Source->state == AL_PLAYING)
1857 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1858 else
1859 writePos = readPos;
1861 if(Source->bLooping)
1863 readPos %= TotalBufferDataSize;
1864 writePos %= TotalBufferDataSize;
1866 else
1868 // Clamp positions to TotalBufferDataSize
1869 if(readPos > TotalBufferDataSize)
1870 readPos = TotalBufferDataSize;
1871 if(writePos > TotalBufferDataSize)
1872 writePos = TotalBufferDataSize;
1875 switch(name)
1877 case AL_SEC_OFFSET:
1878 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1879 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1880 break;
1881 case AL_SAMPLE_OFFSET:
1882 case AL_SAMPLE_RW_OFFSETS_EXT:
1883 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1884 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1885 break;
1886 case AL_BYTE_OFFSET:
1887 case AL_BYTE_RW_OFFSETS_EXT:
1888 // Take into account the original format of the Buffer
1889 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1890 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1892 // Round down to nearest ADPCM block
1893 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1894 if(Source->state == AL_PLAYING)
1896 // Round up to nearest ADPCM block
1897 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1899 else
1900 offset[1] = offset[0];
1902 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1903 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1904 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1905 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1906 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1907 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1909 offset[0] = (ALdouble)(readPos / Bytes * 1);
1910 offset[1] = (ALdouble)(writePos / Bytes * 1);
1912 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1914 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1915 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1917 else if(OriginalFormat == AL_FORMAT_REAR8)
1919 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1920 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1922 else if(OriginalFormat == AL_FORMAT_REAR16)
1924 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1925 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1927 else if(OriginalFormat == AL_FORMAT_REAR32)
1929 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1930 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1932 else
1934 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1935 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1936 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1938 break;
1944 ApplyOffset
1946 Apply a playback offset to the Source. This function will update the queue (to correctly
1947 mark buffers as 'pending' or 'processed' depending upon the new offset.
1949 static ALboolean ApplyOffset(ALsource *Source)
1951 ALbufferlistitem *BufferList;
1952 ALbuffer *Buffer;
1953 ALint lBufferSize, lTotalBufferSize;
1954 ALint BuffersPlayed;
1955 ALint lByteOffset;
1957 // Get true byte offset
1958 lByteOffset = GetByteOffset(Source);
1960 // If the offset is invalid, don't apply it
1961 if(lByteOffset == -1)
1962 return AL_FALSE;
1964 // Sort out the queue (pending and processed states)
1965 BufferList = Source->queue;
1966 lTotalBufferSize = 0;
1967 BuffersPlayed = 0;
1969 while(BufferList)
1971 Buffer = BufferList->buffer;
1972 lBufferSize = Buffer ? Buffer->size : 0;
1974 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1976 // Offset is past this buffer so increment BuffersPlayed
1977 BuffersPlayed++;
1979 else if(lTotalBufferSize <= lByteOffset)
1981 // Offset is within this buffer
1982 // Set Current Buffer
1983 Source->Buffer = BufferList->buffer;
1984 Source->BuffersPlayed = BuffersPlayed;
1986 // SW Mixer Positions are in Samples
1987 Source->position = (lByteOffset - lTotalBufferSize) /
1988 aluFrameSizeFromFormat(Buffer->format);
1989 return AL_TRUE;
1992 // Increment the TotalBufferSize
1993 lTotalBufferSize += lBufferSize;
1995 // Move on to next buffer in the Queue
1996 BufferList = BufferList->next;
1998 // Offset is out of range of the buffer queue
1999 return AL_FALSE;
2004 GetByteOffset
2006 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2007 offset supplied by the application). This takes into account the fact that the buffer format
2008 may have been modifed by AL (e.g 8bit samples are converted to float)
2010 static ALint GetByteOffset(ALsource *Source)
2012 ALbuffer *Buffer = NULL;
2013 ALbufferlistitem *BufferList;
2014 ALfloat BufferFreq;
2015 ALint Channels, Bytes;
2016 ALint ByteOffset = -1;
2018 // Find the first non-NULL Buffer in the Queue
2019 BufferList = Source->queue;
2020 while(BufferList)
2022 if(BufferList->buffer)
2024 Buffer = BufferList->buffer;
2025 break;
2027 BufferList = BufferList->next;
2030 if(!Buffer)
2032 Source->lOffset = 0;
2033 return -1;
2036 BufferFreq = ((ALfloat)Buffer->frequency);
2037 Channels = aluChannelsFromFormat(Buffer->format);
2038 Bytes = aluBytesFromFormat(Buffer->format);
2040 // Determine the ByteOffset (and ensure it is block aligned)
2041 switch(Source->lOffsetType)
2043 case AL_BYTE_OFFSET:
2044 // Take into consideration the original format
2045 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2046 Channels);
2047 ByteOffset *= Channels * Bytes;
2048 break;
2050 case AL_SAMPLE_OFFSET:
2051 ByteOffset = Source->lOffset * Channels * Bytes;
2052 break;
2054 case AL_SEC_OFFSET:
2055 // Note - lOffset is internally stored as Milliseconds
2056 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2057 ByteOffset *= Channels * Bytes;
2058 break;
2060 // Clear Offset
2061 Source->lOffset = 0;
2063 return ByteOffset;
2066 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2068 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2070 // Round down to nearest ADPCM block
2071 offset /= 36 * channels;
2072 // Multiply by compression rate (65 sample frames per block)
2073 offset *= 65;
2075 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2076 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2077 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2079 /* muLaw has 1 byte per sample */
2080 offset /= 1 * channels;
2082 else if(format == AL_FORMAT_REAR_MULAW)
2084 /* Rear is 2 channels */
2085 offset /= 1 * 2;
2087 else if(format == AL_FORMAT_REAR8)
2088 offset /= 1 * 2;
2089 else if(format == AL_FORMAT_REAR16)
2090 offset /= 2 * 2;
2091 else if(format == AL_FORMAT_REAR32)
2092 offset /= 4 * 2;
2093 else
2095 ALuint bytes = aluBytesFromFormat(format);
2096 offset /= bytes * channels;
2098 return offset;
2102 ALvoid ReleaseALSources(ALCcontext *Context)
2104 ALsizei pos;
2105 ALuint j;
2106 for(pos = 0;pos < Context->SourceMap.size;pos++)
2108 ALsource *temp = Context->SourceMap.array[pos].value;
2109 Context->SourceMap.array[pos].value = NULL;
2111 // For each buffer in the source's queue, decrement its reference counter and remove it
2112 while(temp->queue != NULL)
2114 ALbufferlistitem *BufferList = temp->queue;
2115 // Decrement buffer's reference counter
2116 if(BufferList->buffer != NULL)
2117 BufferList->buffer->refcount--;
2118 // Update queue to point to next element in list
2119 temp->queue = BufferList->next;
2120 // Release memory allocated for buffer list item
2121 free(BufferList);
2124 for(j = 0;j < MAX_SENDS;++j)
2126 if(temp->Send[j].Slot)
2127 temp->Send[j].Slot->refcount--;
2130 // Release source structure
2131 ALTHUNK_REMOVEENTRY(temp->source);
2132 memset(temp, 0, sizeof(ALsource));
2133 free(temp);