Implement AL_AUXILIARY_SEND_FILTER_GAIN_AUTO property
[openal-soft.git] / OpenAL32 / alSource.c
blob2c605d42b99e6ad3d09dc549891481adaa6b4c08
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 <stdlib.h>
22 #include <math.h>
23 #include <float.h>
24 #include "alMain.h"
25 #include "AL/al.h"
26 #include "AL/alc.h"
27 #include "alError.h"
28 #include "alSource.h"
30 static ALvoid InitSourceParams(ALsource *pSource);
31 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
32 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
33 static ALint GetByteOffset(ALsource *pSource);
35 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
37 ALCcontext *Context;
38 ALCdevice *Device;
39 ALsizei i=0;
41 Context = alcGetCurrentContext();
42 if (Context)
44 SuspendContext(Context);
46 if (n > 0)
48 Device = alcGetContextsDevice(Context);
50 if (Device)
52 // Check that enough memory has been allocted in the 'sources' array for n Sources
53 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
55 // Check that the requested number of sources can be generated
56 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
58 ALsource **list = &Context->Source;
59 while(*list)
60 list = &(*list)->next;
62 // Add additional sources to the list (Source->next points to the location for the next Source structure)
63 while(i < n)
65 *list = calloc(1, sizeof(ALsource));
66 if(*list)
68 sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list);
69 (*list)->source = sources[i];
71 InitSourceParams(*list);
72 Context->SourceCount++;
73 i++;
75 list = &(*list)->next;
79 // If we didn't create all the Sources, we must have run out or memory
80 if(i != n)
81 alSetError(AL_OUT_OF_MEMORY);
83 else
85 // Not enough resources to create the Sources
86 alSetError(AL_INVALID_VALUE);
89 else
91 // Bad pointer
92 alSetError(AL_INVALID_VALUE);
95 else
97 // No Device created, or attached to Context
98 alSetError(AL_INVALID_OPERATION);
102 ProcessContext(Context);
104 else
106 // Invalid Context
107 alSetError(AL_INVALID_OPERATION);
110 return;
114 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
116 ALCcontext *Context;
117 ALCdevice *Device;
118 ALsource *ALSource;
119 ALsource **list;
120 ALsizei i;
121 ALbufferlistitem *ALBufferList;
122 ALboolean bSourcesValid = AL_TRUE;
124 Context = alcGetCurrentContext();
125 if (Context)
127 SuspendContext(Context);
129 if (n >= 0)
131 Device = alcGetContextsDevice(Context);
133 if (Device)
135 if ((ALuint)n <= Context->SourceCount)
137 // Check that all Sources are valid (and can therefore be deleted)
138 for (i = 0; i < n; i++)
140 if (!alIsSource(sources[i]))
142 alSetError(AL_INVALID_NAME);
143 bSourcesValid = AL_FALSE;
144 break;
148 if (bSourcesValid)
150 // All Sources are valid, and can be deleted
151 for (i = 0; i < n; i++)
153 // Recheck that the Source is valid, because there could be duplicated Source names
154 if (alIsSource(sources[i]))
156 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
157 alSourceStop((ALuint)ALSource->source);
159 // For each buffer in the source's queue, decrement its reference counter and remove it
160 while (ALSource->queue != NULL)
162 ALBufferList = ALSource->queue;
163 // Decrement buffer's reference counter
164 if (ALBufferList->buffer != 0)
165 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
166 // Update queue to point to next element in list
167 ALSource->queue = ALBufferList->next;
168 // Release memory allocated for buffer list item
169 free(ALBufferList);
172 // Decrement Source count
173 Context->SourceCount--;
175 // Remove Source from list of Sources
176 list = &Context->Source;
177 while(*list && *list != ALSource)
178 list = &(*list)->next;
180 if(*list)
181 *list = (*list)->next;
182 ALTHUNK_REMOVEENTRY(ALSource->source);
184 memset(ALSource,0,sizeof(ALsource));
185 free(ALSource);
191 else
193 // Trying to delete more Sources than have been generated
194 alSetError(AL_INVALID_NAME);
197 else
199 // No Device created, or attached to Context
200 alSetError(AL_INVALID_OPERATION);
203 else
204 alSetError(AL_INVALID_VALUE);
206 ProcessContext(Context);
208 else
210 // Invalid Context
211 alSetError(AL_INVALID_OPERATION);
214 return;
218 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
220 ALboolean result=AL_FALSE;
221 ALCcontext *Context;
222 ALsource *Source;
224 Context=alcGetCurrentContext();
225 if (Context)
227 SuspendContext(Context);
229 // To determine if this is a valid Source name, look through the list of generated Sources
230 Source = Context->Source;
231 while(Source)
233 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
235 result = AL_TRUE;
236 break;
239 Source = Source->next;
242 ProcessContext(Context);
244 else
246 // Invalid Context
247 alSetError(AL_INVALID_OPERATION);
250 return result;
254 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
256 ALCcontext *pContext;
257 ALsource *pSource;
259 pContext = alcGetCurrentContext();
260 if (pContext)
262 SuspendContext(pContext);
264 if (alIsSource(source))
266 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
268 switch (eParam)
270 case AL_PITCH:
271 if (flValue >= 0.0f)
273 pSource->flPitch = flValue;
274 if(pSource->flPitch < 0.001f)
275 pSource->flPitch = 0.001f;
277 else
278 alSetError(AL_INVALID_VALUE);
279 break;
281 case AL_CONE_INNER_ANGLE:
282 if ((flValue >= 0.0f) && (flValue <= 360.0f))
283 pSource->flInnerAngle = flValue;
284 else
285 alSetError(AL_INVALID_VALUE);
286 break;
288 case AL_CONE_OUTER_ANGLE:
289 if ((flValue >= 0.0f) && (flValue <= 360.0f))
290 pSource->flOuterAngle = flValue;
291 else
292 alSetError(AL_INVALID_VALUE);
293 break;
295 case AL_GAIN:
296 if (flValue >= 0.0f)
297 pSource->flGain = flValue;
298 else
299 alSetError(AL_INVALID_VALUE);
300 break;
302 case AL_MAX_DISTANCE:
303 if (flValue >= 0.0f)
304 pSource->flMaxDistance = flValue;
305 else
306 alSetError(AL_INVALID_VALUE);
307 break;
309 case AL_ROLLOFF_FACTOR:
310 if (flValue >= 0.0f)
311 pSource->flRollOffFactor = flValue;
312 else
313 alSetError(AL_INVALID_VALUE);
314 break;
316 case AL_REFERENCE_DISTANCE:
317 if (flValue >= 0.0f)
318 pSource->flRefDistance = flValue;
319 else
320 alSetError(AL_INVALID_VALUE);
321 break;
323 case AL_MIN_GAIN:
324 if ((flValue >= 0.0f) && (flValue <= 1.0f))
325 pSource->flMinGain = flValue;
326 else
327 alSetError(AL_INVALID_VALUE);
328 break;
330 case AL_MAX_GAIN:
331 if ((flValue >= 0.0f) && (flValue <= 1.0f))
332 pSource->flMaxGain = flValue;
333 else
334 alSetError(AL_INVALID_VALUE);
335 break;
337 case AL_CONE_OUTER_GAIN:
338 if ((flValue >= 0.0f) && (flValue <= 1.0f))
339 pSource->flOuterGain = flValue;
340 else
341 alSetError(AL_INVALID_VALUE);
342 break;
344 case AL_CONE_OUTER_GAINHF:
345 if ((flValue >= 0.0f) && (flValue <= 1.0f))
346 pSource->OuterGainHF = flValue;
347 else
348 alSetError(AL_INVALID_VALUE);
349 break;
351 case AL_AIR_ABSORPTION_FACTOR:
352 if (flValue >= 0.0f && flValue <= 10.0f)
353 pSource->AirAbsorptionFactor = flValue;
354 else
355 alSetError(AL_INVALID_VALUE);
356 break;
358 case AL_ROOM_ROLLOFF_FACTOR:
359 if (flValue >= 0.0f && flValue <= 1.0f)
360 pSource->RoomRolloffFactor = flValue;
361 else
362 alSetError(AL_INVALID_VALUE);
363 break;
365 case AL_SEC_OFFSET:
366 case AL_SAMPLE_OFFSET:
367 case AL_BYTE_OFFSET:
368 if (flValue >= 0.0f)
370 pSource->lOffsetType = eParam;
372 // Store Offset (convert Seconds into Milliseconds)
373 if (eParam == AL_SEC_OFFSET)
374 pSource->lOffset = (ALint)(flValue * 1000.0f);
375 else
376 pSource->lOffset = (ALint)flValue;
378 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
379 ApplyOffset(pSource, AL_TRUE);
381 else
382 alSetError(AL_INVALID_VALUE);
383 break;
385 default:
386 alSetError(AL_INVALID_ENUM);
387 break;
390 else
392 // Invalid Source Name
393 alSetError(AL_INVALID_NAME);
396 ProcessContext(pContext);
398 else
400 // Invalid context
401 alSetError(AL_INVALID_OPERATION);
404 return;
408 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
410 ALCcontext *pContext;
411 ALsource *pSource;
413 pContext = alcGetCurrentContext();
414 if (pContext)
416 SuspendContext(pContext);
418 if (alIsSource(source))
420 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
421 switch(eParam)
423 case AL_POSITION:
424 pSource->vPosition[0] = flValue1;
425 pSource->vPosition[1] = flValue2;
426 pSource->vPosition[2] = flValue3;
427 break;
429 case AL_VELOCITY:
430 pSource->vVelocity[0] = flValue1;
431 pSource->vVelocity[1] = flValue2;
432 pSource->vVelocity[2] = flValue3;
433 break;
435 case AL_DIRECTION:
436 pSource->vOrientation[0] = flValue1;
437 pSource->vOrientation[1] = flValue2;
438 pSource->vOrientation[2] = flValue3;
439 break;
441 default:
442 alSetError(AL_INVALID_ENUM);
443 break;
446 else
447 alSetError(AL_INVALID_NAME);
449 ProcessContext(pContext);
451 else
453 alSetError(AL_INVALID_OPERATION);
456 return;
460 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
462 ALCcontext *pContext;
464 pContext = alcGetCurrentContext();
465 if (pContext)
467 SuspendContext(pContext);
469 if (pflValues)
471 if (alIsSource(source))
473 switch (eParam)
475 case AL_PITCH:
476 case AL_CONE_INNER_ANGLE:
477 case AL_CONE_OUTER_ANGLE:
478 case AL_GAIN:
479 case AL_MAX_DISTANCE:
480 case AL_ROLLOFF_FACTOR:
481 case AL_REFERENCE_DISTANCE:
482 case AL_MIN_GAIN:
483 case AL_MAX_GAIN:
484 case AL_CONE_OUTER_GAIN:
485 case AL_CONE_OUTER_GAINHF:
486 case AL_SEC_OFFSET:
487 case AL_SAMPLE_OFFSET:
488 case AL_BYTE_OFFSET:
489 case AL_AIR_ABSORPTION_FACTOR:
490 case AL_ROOM_ROLLOFF_FACTOR:
491 alSourcef(source, eParam, pflValues[0]);
492 break;
494 case AL_POSITION:
495 case AL_VELOCITY:
496 case AL_DIRECTION:
497 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
498 break;
500 default:
501 alSetError(AL_INVALID_ENUM);
502 break;
505 else
506 alSetError(AL_INVALID_NAME);
508 else
509 alSetError(AL_INVALID_VALUE);
511 ProcessContext(pContext);
513 else
514 alSetError(AL_INVALID_OPERATION);
516 return;
520 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
522 ALCcontext *pContext;
523 ALsource *pSource;
524 ALbufferlistitem *pALBufferListItem;
525 ALint Counter = 0;
526 ALint DataSize = 0;
527 ALint BufferSize;
529 pContext = alcGetCurrentContext();
530 if (pContext)
532 SuspendContext(pContext);
534 if (alIsSource(source))
536 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
538 switch(eParam)
540 case AL_MAX_DISTANCE:
541 case AL_ROLLOFF_FACTOR:
542 case AL_REFERENCE_DISTANCE:
543 alSourcef(source, eParam, (ALfloat)lValue);
544 break;
546 case AL_SOURCE_RELATIVE:
547 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
548 pSource->bHeadRelative = (ALboolean)lValue;
549 else
550 alSetError(AL_INVALID_VALUE);
551 break;
553 case AL_CONE_INNER_ANGLE:
554 if ((lValue >= 0) && (lValue <= 360))
555 pSource->flInnerAngle = (float)lValue;
556 else
557 alSetError(AL_INVALID_VALUE);
558 break;
560 case AL_CONE_OUTER_ANGLE:
561 if ((lValue >= 0) && (lValue <= 360))
562 pSource->flOuterAngle = (float)lValue;
563 else
564 alSetError(AL_INVALID_VALUE);
565 break;
567 case AL_LOOPING:
568 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
569 pSource->bLooping = (ALboolean)lValue;
570 else
571 alSetError(AL_INVALID_VALUE);
572 break;
574 case AL_BUFFER:
575 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
577 if (alIsBuffer(lValue))
579 // Remove all elements in the queue
580 while (pSource->queue != NULL)
582 pALBufferListItem = pSource->queue;
583 pSource->queue = pALBufferListItem->next;
584 // Decrement reference counter for buffer
585 if (pALBufferListItem->buffer)
586 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
587 // Record size of buffer
588 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
589 DataSize += BufferSize;
590 // Increment the number of buffers removed from queue
591 Counter++;
592 // Release memory for buffer list item
593 free(pALBufferListItem);
594 // Decrement the number of buffers in the queue
595 pSource->BuffersInQueue--;
598 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
599 if (lValue != 0)
601 // Source is now in STATIC mode
602 pSource->lSourceType = AL_STATIC;
604 // Add the selected buffer to the queue
605 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
606 pALBufferListItem->buffer = lValue;
607 pALBufferListItem->bufferstate = PENDING;
608 pALBufferListItem->flag = 0;
609 pALBufferListItem->next = NULL;
611 pSource->queue = pALBufferListItem;
612 pSource->BuffersInQueue = 1;
614 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
616 // Increment reference counter for buffer
617 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
619 else
621 // Source is now in UNDETERMINED mode
622 pSource->lSourceType = AL_UNDETERMINED;
625 // Set Buffers Processed
626 pSource->BuffersProcessed = 0;
628 // Update AL_BUFFER parameter
629 pSource->ulBufferID = lValue;
631 else
632 alSetError(AL_INVALID_VALUE);
634 else
635 alSetError(AL_INVALID_OPERATION);
636 break;
638 case AL_SOURCE_STATE:
639 // Query only
640 alSetError(AL_INVALID_OPERATION);
641 break;
643 case AL_SEC_OFFSET:
644 case AL_SAMPLE_OFFSET:
645 case AL_BYTE_OFFSET:
646 if (lValue >= 0)
648 pSource->lOffsetType = eParam;
650 // Store Offset (convert Seconds into Milliseconds)
651 if (eParam == AL_SEC_OFFSET)
652 pSource->lOffset = lValue * 1000;
653 else
654 pSource->lOffset = lValue;
656 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
657 ApplyOffset(pSource, AL_TRUE);
659 else
660 alSetError(AL_INVALID_VALUE);
661 break;
663 case AL_DIRECT_FILTER:
664 if(alIsFilter(lValue))
666 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
667 if(!filter)
669 pSource->DirectFilter.type = AL_FILTER_NULL;
670 pSource->DirectFilter.filter = 0;
672 else
673 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
675 else
676 alSetError(AL_INVALID_VALUE);
677 break;
679 case AL_DIRECT_FILTER_GAINHF_AUTO:
680 if(lValue == AL_TRUE || lValue == AL_FALSE)
681 pSource->DryGainHFAuto = lValue;
682 else
683 alSetError(AL_INVALID_VALUE);
684 break;
686 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
687 if(lValue == AL_TRUE || lValue == AL_FALSE)
688 pSource->WetGainAuto = lValue;
689 else
690 alSetError(AL_INVALID_VALUE);
691 break;
693 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
694 if(lValue == AL_TRUE || lValue == AL_FALSE)
695 pSource->WetGainHFAuto = lValue;
696 else
697 alSetError(AL_INVALID_VALUE);
698 break;
700 default:
701 alSetError(AL_INVALID_ENUM);
702 break;
705 else
706 alSetError(AL_INVALID_NAME);
708 ProcessContext(pContext);
710 else
711 alSetError(AL_INVALID_OPERATION);
713 return;
717 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
719 ALCcontext *pContext;
721 pContext = alcGetCurrentContext();
722 if (pContext)
724 SuspendContext(pContext);
726 if (alIsSource(source))
728 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
730 switch (eParam)
732 case AL_POSITION:
733 case AL_VELOCITY:
734 case AL_DIRECTION:
735 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
736 break;
738 case AL_AUXILIARY_SEND_FILTER:
739 if(lValue2 >= 0 && lValue2 <= 0 &&
740 alIsAuxiliaryEffectSlot(lValue1) && alIsFilter(lValue3))
742 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
743 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
745 if(!ALEffectSlot)
747 /* Disable slot */
748 pSource->Send[lValue2].Slot.effectslot = 0;
750 else
751 memcpy(&pSource->Send[lValue2].Slot, ALEffectSlot, sizeof(*ALEffectSlot));
753 if(!ALFilter)
755 /* Disable filter */
756 pSource->Send[lValue2].WetFilter.type = 0;
757 pSource->Send[lValue2].WetFilter.filter = 0;
759 else
760 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
762 else
763 alSetError(AL_INVALID_VALUE);
764 break;
766 default:
767 alSetError(AL_INVALID_ENUM);
768 break;
771 else
772 alSetError(AL_INVALID_NAME);
774 ProcessContext(pContext);
776 else
777 alSetError(AL_INVALID_OPERATION);
779 return;
783 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
785 ALCcontext *pContext;
787 pContext = alcGetCurrentContext();
788 if (pContext)
790 SuspendContext(pContext);
792 if (plValues)
794 if (alIsSource(source))
796 switch (eParam)
798 case AL_SOURCE_RELATIVE:
799 case AL_CONE_INNER_ANGLE:
800 case AL_CONE_OUTER_ANGLE:
801 case AL_LOOPING:
802 case AL_BUFFER:
803 case AL_SOURCE_STATE:
804 case AL_SEC_OFFSET:
805 case AL_SAMPLE_OFFSET:
806 case AL_BYTE_OFFSET:
807 case AL_MAX_DISTANCE:
808 case AL_ROLLOFF_FACTOR:
809 case AL_REFERENCE_DISTANCE:
810 case AL_DIRECT_FILTER:
811 case AL_DIRECT_FILTER_GAINHF_AUTO:
812 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
813 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
814 alSourcei(source, eParam, plValues[0]);
815 break;
817 case AL_POSITION:
818 case AL_VELOCITY:
819 case AL_DIRECTION:
820 case AL_AUXILIARY_SEND_FILTER:
821 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
822 break;
824 default:
825 alSetError(AL_INVALID_ENUM);
826 break;
829 else
830 alSetError(AL_INVALID_NAME);
832 else
833 alSetError(AL_INVALID_VALUE);
835 ProcessContext(pContext);
837 else
838 alSetError(AL_INVALID_OPERATION);
840 return;
844 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
846 ALCcontext *pContext;
847 ALsource *pSource;
848 ALfloat flOffset;
850 pContext = alcGetCurrentContext();
851 if (pContext)
853 SuspendContext(pContext);
855 if (pflValue)
857 if (alIsSource(source))
859 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
861 switch(eParam)
863 case AL_PITCH:
864 *pflValue = pSource->flPitch;
865 break;
867 case AL_GAIN:
868 *pflValue = pSource->flGain;
869 break;
871 case AL_MIN_GAIN:
872 *pflValue = pSource->flMinGain;
873 break;
875 case AL_MAX_GAIN:
876 *pflValue = pSource->flMaxGain;
877 break;
879 case AL_MAX_DISTANCE:
880 *pflValue = pSource->flMaxDistance;
881 break;
883 case AL_ROLLOFF_FACTOR:
884 *pflValue = pSource->flRollOffFactor;
885 break;
887 case AL_CONE_OUTER_GAIN:
888 *pflValue = pSource->flOuterGain;
889 break;
891 case AL_CONE_OUTER_GAINHF:
892 *pflValue = pSource->OuterGainHF;
893 break;
895 case AL_SEC_OFFSET:
896 case AL_SAMPLE_OFFSET:
897 case AL_BYTE_OFFSET:
898 if (GetSourceOffset(pSource, eParam, &flOffset))
899 *pflValue = flOffset;
900 else
901 alSetError(AL_INVALID_OPERATION);
902 break;
904 case AL_CONE_INNER_ANGLE:
905 *pflValue = pSource->flInnerAngle;
906 break;
908 case AL_CONE_OUTER_ANGLE:
909 *pflValue = pSource->flOuterAngle;
910 break;
912 case AL_REFERENCE_DISTANCE:
913 *pflValue = pSource->flRefDistance;
914 break;
916 case AL_AIR_ABSORPTION_FACTOR:
917 *pflValue = pSource->AirAbsorptionFactor;
918 break;
920 case AL_ROOM_ROLLOFF_FACTOR:
921 *pflValue = pSource->RoomRolloffFactor;
922 break;
924 default:
925 alSetError(AL_INVALID_ENUM);
926 break;
929 else
930 alSetError(AL_INVALID_NAME);
932 else
933 alSetError(AL_INVALID_VALUE);
935 ProcessContext(pContext);
937 else
938 alSetError(AL_INVALID_OPERATION);
940 return;
944 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
946 ALCcontext *pContext;
947 ALsource *pSource;
949 pContext = alcGetCurrentContext();
950 if (pContext)
952 SuspendContext(pContext);
954 if ((pflValue1) && (pflValue2) && (pflValue3))
956 if (alIsSource(source))
958 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
960 switch(eParam)
962 case AL_POSITION:
963 *pflValue1 = pSource->vPosition[0];
964 *pflValue2 = pSource->vPosition[1];
965 *pflValue3 = pSource->vPosition[2];
966 break;
968 case AL_VELOCITY:
969 *pflValue1 = pSource->vVelocity[0];
970 *pflValue2 = pSource->vVelocity[1];
971 *pflValue3 = pSource->vVelocity[2];
972 break;
974 case AL_DIRECTION:
975 *pflValue1 = pSource->vOrientation[0];
976 *pflValue2 = pSource->vOrientation[1];
977 *pflValue3 = pSource->vOrientation[2];
978 break;
980 default:
981 alSetError(AL_INVALID_ENUM);
982 break;
985 else
986 alSetError(AL_INVALID_NAME);
988 else
989 alSetError(AL_INVALID_VALUE);
991 ProcessContext(pContext);
993 else
994 alSetError(AL_INVALID_OPERATION);
996 return;
1000 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1002 ALCcontext *pContext;
1003 ALsource *pSource;
1005 pContext = alcGetCurrentContext();
1006 if (pContext)
1008 SuspendContext(pContext);
1010 if (pflValues)
1012 if (alIsSource(source))
1014 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1016 switch(eParam)
1018 case AL_PITCH:
1019 case AL_GAIN:
1020 case AL_MIN_GAIN:
1021 case AL_MAX_GAIN:
1022 case AL_MAX_DISTANCE:
1023 case AL_ROLLOFF_FACTOR:
1024 case AL_CONE_OUTER_GAIN:
1025 case AL_SEC_OFFSET:
1026 case AL_SAMPLE_OFFSET:
1027 case AL_BYTE_OFFSET:
1028 case AL_CONE_INNER_ANGLE:
1029 case AL_CONE_OUTER_ANGLE:
1030 case AL_REFERENCE_DISTANCE:
1031 case AL_CONE_OUTER_GAINHF:
1032 case AL_AIR_ABSORPTION_FACTOR:
1033 case AL_ROOM_ROLLOFF_FACTOR:
1034 alGetSourcef(source, eParam, pflValues);
1035 break;
1037 case AL_POSITION:
1038 pflValues[0] = pSource->vPosition[0];
1039 pflValues[1] = pSource->vPosition[1];
1040 pflValues[2] = pSource->vPosition[2];
1041 break;
1043 case AL_VELOCITY:
1044 pflValues[0] = pSource->vVelocity[0];
1045 pflValues[1] = pSource->vVelocity[1];
1046 pflValues[2] = pSource->vVelocity[2];
1047 break;
1049 case AL_DIRECTION:
1050 pflValues[0] = pSource->vOrientation[0];
1051 pflValues[1] = pSource->vOrientation[1];
1052 pflValues[2] = pSource->vOrientation[2];
1053 break;
1055 default:
1056 alSetError(AL_INVALID_ENUM);
1057 break;
1060 else
1061 alSetError(AL_INVALID_NAME);
1063 else
1064 alSetError(AL_INVALID_VALUE);
1066 ProcessContext(pContext);
1068 else
1069 alSetError(AL_INVALID_OPERATION);
1071 return;
1075 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1077 ALCcontext *pContext;
1078 ALsource *pSource;
1079 ALfloat flOffset;
1081 pContext = alcGetCurrentContext();
1082 if (pContext)
1084 SuspendContext(pContext);
1086 if (plValue)
1088 if (alIsSource(source))
1090 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1092 switch(eParam)
1094 case AL_MAX_DISTANCE:
1095 *plValue = (ALint)pSource->flMaxDistance;
1096 break;
1098 case AL_ROLLOFF_FACTOR:
1099 *plValue = (ALint)pSource->flRollOffFactor;
1100 break;
1102 case AL_REFERENCE_DISTANCE:
1103 *plValue = (ALint)pSource->flRefDistance;
1104 break;
1106 case AL_SOURCE_RELATIVE:
1107 *plValue = pSource->bHeadRelative;
1108 break;
1110 case AL_CONE_INNER_ANGLE:
1111 *plValue = (ALint)pSource->flInnerAngle;
1112 break;
1114 case AL_CONE_OUTER_ANGLE:
1115 *plValue = (ALint)pSource->flOuterAngle;
1116 break;
1118 case AL_LOOPING:
1119 *plValue = pSource->bLooping;
1120 break;
1122 case AL_BUFFER:
1123 *plValue = pSource->ulBufferID;
1124 break;
1126 case AL_SOURCE_STATE:
1127 *plValue = pSource->state;
1128 break;
1130 case AL_BUFFERS_QUEUED:
1131 *plValue = pSource->BuffersInQueue;
1132 break;
1134 case AL_BUFFERS_PROCESSED:
1135 if(pSource->bLooping)
1137 /* Buffers on a looping source are in a perpetual state
1138 * of PENDING, so don't report any as PROCESSED */
1139 *plValue = 0;
1141 else
1142 *plValue = pSource->BuffersProcessed;
1143 break;
1145 case AL_SOURCE_TYPE:
1146 *plValue = pSource->lSourceType;
1147 break;
1149 case AL_SEC_OFFSET:
1150 case AL_SAMPLE_OFFSET:
1151 case AL_BYTE_OFFSET:
1152 if (GetSourceOffset(pSource, eParam, &flOffset))
1153 *plValue = (ALint)flOffset;
1154 else
1155 alSetError(AL_INVALID_OPERATION);
1156 break;
1158 case AL_DIRECT_FILTER:
1159 *plValue = pSource->DirectFilter.filter;
1160 break;
1162 case AL_DIRECT_FILTER_GAINHF_AUTO:
1163 *plValue = pSource->DryGainHFAuto;
1164 break;
1166 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1167 *plValue = pSource->WetGainAuto;
1168 break;
1170 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1171 *plValue = pSource->WetGainHFAuto;
1172 break;
1174 default:
1175 alSetError(AL_INVALID_ENUM);
1176 break;
1179 else
1180 alSetError(AL_INVALID_NAME);
1182 else
1183 alSetError(AL_INVALID_VALUE);
1185 ProcessContext(pContext);
1187 else
1188 alSetError(AL_INVALID_OPERATION);
1190 return;
1194 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1196 ALCcontext *pContext;
1197 ALsource *pSource;
1199 pContext = alcGetCurrentContext();
1200 if (pContext)
1202 SuspendContext(pContext);
1204 if ((plValue1) && (plValue2) && (plValue3))
1206 if (alIsSource(source))
1208 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1210 switch(eParam)
1212 case AL_POSITION:
1213 *plValue1 = (ALint)pSource->vPosition[0];
1214 *plValue2 = (ALint)pSource->vPosition[1];
1215 *plValue3 = (ALint)pSource->vPosition[2];
1216 break;
1218 case AL_VELOCITY:
1219 *plValue1 = (ALint)pSource->vVelocity[0];
1220 *plValue2 = (ALint)pSource->vVelocity[1];
1221 *plValue3 = (ALint)pSource->vVelocity[2];
1222 break;
1224 case AL_DIRECTION:
1225 *plValue1 = (ALint)pSource->vOrientation[0];
1226 *plValue2 = (ALint)pSource->vOrientation[1];
1227 *plValue3 = (ALint)pSource->vOrientation[2];
1228 break;
1230 default:
1231 alSetError(AL_INVALID_ENUM);
1232 break;
1235 else
1236 alSetError(AL_INVALID_NAME);
1238 else
1239 alSetError(AL_INVALID_VALUE);
1241 ProcessContext(pContext);
1243 else
1244 alSetError(AL_INVALID_OPERATION);
1246 return;
1250 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1252 ALCcontext *pContext;
1253 ALsource *pSource;
1255 pContext = alcGetCurrentContext();
1256 if (pContext)
1258 SuspendContext(pContext);
1260 if (plValues)
1262 if (alIsSource(source))
1264 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1266 switch (eParam)
1268 case AL_SOURCE_RELATIVE:
1269 case AL_CONE_INNER_ANGLE:
1270 case AL_CONE_OUTER_ANGLE:
1271 case AL_LOOPING:
1272 case AL_BUFFER:
1273 case AL_SOURCE_STATE:
1274 case AL_BUFFERS_QUEUED:
1275 case AL_BUFFERS_PROCESSED:
1276 case AL_SEC_OFFSET:
1277 case AL_SAMPLE_OFFSET:
1278 case AL_BYTE_OFFSET:
1279 case AL_MAX_DISTANCE:
1280 case AL_ROLLOFF_FACTOR:
1281 case AL_REFERENCE_DISTANCE:
1282 case AL_SOURCE_TYPE:
1283 case AL_DIRECT_FILTER:
1284 case AL_DIRECT_FILTER_GAINHF_AUTO:
1285 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1286 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1287 alGetSourcei(source, eParam, plValues);
1288 break;
1290 case AL_POSITION:
1291 plValues[0] = (ALint)pSource->vPosition[0];
1292 plValues[1] = (ALint)pSource->vPosition[1];
1293 plValues[2] = (ALint)pSource->vPosition[2];
1294 break;
1296 case AL_VELOCITY:
1297 plValues[0] = (ALint)pSource->vVelocity[0];
1298 plValues[1] = (ALint)pSource->vVelocity[1];
1299 plValues[2] = (ALint)pSource->vVelocity[2];
1300 break;
1302 case AL_DIRECTION:
1303 plValues[0] = (ALint)pSource->vOrientation[0];
1304 plValues[1] = (ALint)pSource->vOrientation[1];
1305 plValues[2] = (ALint)pSource->vOrientation[2];
1306 break;
1308 default:
1309 alSetError(AL_INVALID_ENUM);
1310 break;
1313 else
1314 alSetError(AL_INVALID_NAME);
1316 else
1317 alSetError(AL_INVALID_VALUE);
1319 ProcessContext(pContext);
1321 else
1322 alSetError(AL_INVALID_OPERATION);
1324 return;
1328 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1330 alSourcePlayv(1, &source);
1331 return;
1334 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1336 ALCcontext *pContext;
1337 ALsource *pSource;
1338 ALbufferlistitem *ALBufferList;
1339 ALboolean bSourcesValid = AL_TRUE;
1340 ALboolean bPlay;
1341 ALsizei i;
1343 pContext = alcGetCurrentContext();
1344 if (pContext)
1346 SuspendContext(pContext);
1348 if (pSourceList)
1350 // Check that all the Sources are valid
1351 for (i = 0; i < n; i++)
1353 if (!alIsSource(pSourceList[i]))
1355 alSetError(AL_INVALID_NAME);
1356 bSourcesValid = AL_FALSE;
1357 break;
1361 if (bSourcesValid)
1363 for (i = 0; i < n; i++)
1365 // Assume Source won't need to play
1366 bPlay = AL_FALSE;
1368 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1370 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1371 ALBufferList = pSource->queue;
1372 while (ALBufferList)
1374 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1376 bPlay = AL_TRUE;
1377 break;
1379 ALBufferList = ALBufferList->next;
1382 if (bPlay)
1384 if (pSource->state != AL_PAUSED)
1386 pSource->state = AL_PLAYING;
1387 pSource->inuse = AL_TRUE;
1388 pSource->play = AL_TRUE;
1389 pSource->position = 0;
1390 pSource->position_fraction = 0;
1391 pSource->BuffersProcessed = 0;
1392 pSource->BuffersPlayed = 0;
1393 pSource->BufferPosition = 0;
1394 pSource->lBytesPlayed = 0;
1396 pSource->ulBufferID = pSource->queue->buffer;
1398 // Make sure all the Buffers in the queue are marked as PENDING
1399 ALBufferList = pSource->queue;
1400 while (ALBufferList)
1402 ALBufferList->bufferstate = PENDING;
1403 ALBufferList = ALBufferList->next;
1406 else
1408 pSource->state = AL_PLAYING;
1409 pSource->inuse = AL_TRUE;
1410 pSource->play = AL_TRUE;
1413 // Check if an Offset has been set
1414 if (pSource->lOffset)
1415 ApplyOffset(pSource, AL_FALSE);
1417 else
1419 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1420 ALBufferList = pSource->queue;
1421 while (ALBufferList)
1423 ALBufferList->bufferstate = PROCESSED;
1424 ALBufferList = ALBufferList->next;
1427 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1432 else
1434 // sources is a NULL pointer
1435 alSetError(AL_INVALID_VALUE);
1438 ProcessContext(pContext);
1440 else
1442 // Invalid Context
1443 alSetError(AL_INVALID_OPERATION);
1446 return;
1449 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1451 alSourcePausev(1, &source);
1452 return;
1455 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1457 ALCcontext *Context;
1458 ALsource *Source;
1459 ALsizei i;
1460 ALboolean bSourcesValid = AL_TRUE;
1462 Context=alcGetCurrentContext();
1463 if (Context)
1465 SuspendContext(Context);
1467 if (sources)
1469 // Check all the Sources are valid
1470 for (i=0;i<n;i++)
1472 if (!alIsSource(sources[i]))
1474 alSetError(AL_INVALID_NAME);
1475 bSourcesValid = AL_FALSE;
1476 break;
1480 if (bSourcesValid)
1482 for (i=0;i<n;i++)
1484 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1485 if (Source->state==AL_PLAYING)
1487 Source->state=AL_PAUSED;
1488 Source->inuse=AL_FALSE;
1493 else
1495 // sources is a NULL pointer
1496 alSetError(AL_INVALID_VALUE);
1499 ProcessContext(Context);
1501 else
1503 // Invalid Context
1504 alSetError(AL_INVALID_OPERATION);
1507 return;
1510 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1512 alSourceStopv(1, &source);
1513 return;
1516 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1518 ALCcontext *Context;
1519 ALsource *Source;
1520 ALsizei i;
1521 ALbufferlistitem *ALBufferListItem;
1522 ALboolean bSourcesValid = AL_TRUE;
1524 Context=alcGetCurrentContext();
1525 if (Context)
1527 SuspendContext(Context);
1529 if (sources)
1531 // Check all the Sources are valid
1532 for (i=0;i<n;i++)
1534 if (!alIsSource(sources[i]))
1536 alSetError(AL_INVALID_NAME);
1537 bSourcesValid = AL_FALSE;
1538 break;
1542 if (bSourcesValid)
1544 for (i=0;i<n;i++)
1546 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1547 if (Source->state!=AL_INITIAL)
1549 Source->state=AL_STOPPED;
1550 Source->inuse=AL_FALSE;
1551 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1552 ALBufferListItem= Source->queue;
1553 while (ALBufferListItem != NULL)
1555 ALBufferListItem->bufferstate = PROCESSED;
1556 ALBufferListItem = ALBufferListItem->next;
1559 Source->lOffset = 0;
1563 else
1565 // sources is a NULL pointer
1566 alSetError(AL_INVALID_VALUE);
1569 ProcessContext(Context);
1571 else
1573 // Invalid Context
1574 alSetError(AL_INVALID_OPERATION);
1577 return;
1580 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1582 alSourceRewindv(1, &source);
1583 return;
1586 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1588 ALCcontext *Context;
1589 ALsource *Source;
1590 ALsizei i;
1591 ALbufferlistitem *ALBufferListItem;
1592 ALboolean bSourcesValid = AL_TRUE;
1594 Context=alcGetCurrentContext();
1595 if (Context)
1597 SuspendContext(Context);
1599 if (sources)
1601 // Check all the Sources are valid
1602 for (i=0;i<n;i++)
1604 if (!alIsSource(sources[i]))
1606 alSetError(AL_INVALID_NAME);
1607 bSourcesValid = AL_FALSE;
1608 break;
1612 if (bSourcesValid)
1614 for (i=0;i<n;i++)
1616 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1617 if (Source->state!=AL_INITIAL)
1619 Source->state=AL_INITIAL;
1620 Source->inuse=AL_FALSE;
1621 Source->position=0;
1622 Source->position_fraction=0;
1623 Source->BuffersProcessed = 0;
1624 ALBufferListItem= Source->queue;
1625 while (ALBufferListItem != NULL)
1627 ALBufferListItem->bufferstate = PENDING;
1628 ALBufferListItem = ALBufferListItem->next;
1630 if (Source->queue)
1631 Source->ulBufferID = Source->queue->buffer;
1633 Source->lOffset = 0;
1637 else
1639 // sources is a NULL pointer
1640 alSetError(AL_INVALID_VALUE);
1643 ProcessContext(Context);
1645 else
1647 // Invalid Context
1648 alSetError(AL_INVALID_OPERATION);
1651 return;
1655 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1657 ALCcontext *Context;
1658 ALsource *ALSource;
1659 ALsizei i;
1660 ALbufferlistitem *ALBufferList;
1661 ALbufferlistitem *ALBufferListStart;
1662 ALuint DataSize;
1663 ALuint BufferSize;
1664 ALint iFrequency;
1665 ALint iFormat;
1666 ALboolean bBuffersValid = AL_TRUE;
1668 if (n == 0)
1669 return;
1671 Context=alcGetCurrentContext();
1672 if (Context)
1674 SuspendContext(Context);
1676 DataSize = 0;
1677 BufferSize = 0;
1679 // Check that all buffers are valid or zero and that the source is valid
1681 // Check that this is a valid source
1682 if (alIsSource(source))
1684 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1686 // Check that this is not a STATIC Source
1687 if (ALSource->lSourceType != AL_STATIC)
1689 iFrequency = -1;
1690 iFormat = -1;
1692 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1693 ALBufferList = ALSource->queue;
1694 while (ALBufferList)
1696 if (ALBufferList->buffer)
1698 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1699 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1700 break;
1702 ALBufferList = ALBufferList->next;
1705 for (i = 0; i < n; i++)
1707 if (alIsBuffer(buffers[i]))
1709 if (buffers[i])
1711 if ((iFrequency == -1) && (iFormat == -1))
1713 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1714 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1716 else
1718 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1719 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1721 alSetError(AL_INVALID_OPERATION);
1722 bBuffersValid = AL_FALSE;
1723 break;
1728 else
1730 alSetError(AL_INVALID_NAME);
1731 bBuffersValid = AL_FALSE;
1732 break;
1736 if (bBuffersValid)
1738 // Change Source Type
1739 ALSource->lSourceType = AL_STREAMING;
1741 // All buffers are valid - so add them to the list
1742 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1743 ALBufferListStart->buffer = buffers[0];
1744 ALBufferListStart->bufferstate = PENDING;
1745 ALBufferListStart->flag = 0;
1746 ALBufferListStart->next = NULL;
1748 if (buffers[0])
1749 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1750 else
1751 BufferSize = 0;
1753 DataSize += BufferSize;
1755 // Increment reference counter for buffer
1756 if (buffers[0])
1757 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1759 ALBufferList = ALBufferListStart;
1761 for (i = 1; i < n; i++)
1763 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1764 ALBufferList->next->buffer = buffers[i];
1765 ALBufferList->next->bufferstate = PENDING;
1766 ALBufferList->next->flag = 0;
1767 ALBufferList->next->next = NULL;
1769 if (buffers[i])
1770 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1771 else
1772 BufferSize = 0;
1774 DataSize += BufferSize;
1776 // Increment reference counter for buffer
1777 if (buffers[i])
1778 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1780 ALBufferList = ALBufferList->next;
1783 if (ALSource->queue == NULL)
1785 ALSource->queue = ALBufferListStart;
1786 // Update Current Buffer
1787 ALSource->ulBufferID = ALBufferListStart->buffer;
1789 else
1791 // Find end of queue
1792 ALBufferList = ALSource->queue;
1793 while (ALBufferList->next != NULL)
1795 ALBufferList = ALBufferList->next;
1798 ALBufferList->next = ALBufferListStart;
1801 // Update number of buffers in queue
1802 ALSource->BuffersInQueue += n;
1805 else
1807 // Invalid Source Type (can't queue on a Static Source)
1808 alSetError(AL_INVALID_OPERATION);
1811 else
1813 // Invalid Source Name
1814 alSetError(AL_INVALID_NAME);
1817 ProcessContext(Context);
1819 else
1821 // Invalid Context
1822 alSetError(AL_INVALID_OPERATION);
1825 return;
1829 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1830 // an array of buffer IDs that are to be filled with the names of the buffers removed
1831 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1833 ALCcontext *Context;
1834 ALsource *ALSource;
1835 ALsizei i;
1836 ALbufferlistitem *ALBufferList;
1837 ALuint DataSize;
1838 ALuint BufferSize;
1839 ALuint BufferID;
1840 ALboolean bBuffersProcessed;
1842 if (n == 0)
1843 return;
1845 DataSize = 0;
1846 BufferSize = 0;
1847 bBuffersProcessed = AL_TRUE;
1849 Context=alcGetCurrentContext();
1850 if (Context)
1852 SuspendContext(Context);
1854 if (alIsSource(source))
1856 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1858 // Check that all 'n' buffers have been processed
1859 ALBufferList = ALSource->queue;
1860 for (i = 0; i < n; i++)
1862 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1864 ALBufferList = ALBufferList->next;
1866 else
1868 bBuffersProcessed = AL_FALSE;
1869 break;
1873 // If all 'n' buffers have been processed, remove them from the queue
1874 if (bBuffersProcessed)
1876 for (i = 0; i < n; i++)
1878 ALBufferList = ALSource->queue;
1880 ALSource->queue = ALBufferList->next;
1881 // Record name of buffer
1882 buffers[i] = ALBufferList->buffer;
1883 // Decrement buffer reference counter
1884 if (ALBufferList->buffer)
1885 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1886 // Record size of buffer
1887 if (ALBufferList->buffer)
1888 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1889 else
1890 BufferSize = 0;
1892 DataSize += BufferSize;
1893 // Release memory for buffer list item
1894 free(ALBufferList);
1895 ALSource->BuffersInQueue--;
1896 ALSource->BuffersProcessed--;
1899 if (ALSource->state != AL_PLAYING)
1901 if (ALSource->queue)
1902 BufferID = ALSource->queue->buffer;
1903 else
1904 BufferID = 0;
1906 ALSource->ulBufferID = BufferID;
1909 if((ALuint)n > ALSource->BuffersPlayed)
1911 ALSource->BuffersPlayed = 0;
1912 ALSource->BufferPosition = 0;
1914 else
1915 ALSource->BuffersPlayed -= n;
1917 else
1919 // Some buffers can't be unqueue because they have not been processed
1920 alSetError(AL_INVALID_VALUE);
1923 else
1925 // Invalid Source Name
1926 alSetError(AL_INVALID_NAME);
1929 ProcessContext(Context);
1931 else
1933 // Invalid Context
1934 alSetError(AL_INVALID_OPERATION);
1937 return;
1941 static ALvoid InitSourceParams(ALsource *pSource)
1943 pSource->flInnerAngle = 360.0f;
1944 pSource->flOuterAngle = 360.0f;
1945 pSource->flPitch = 1.0f;
1946 pSource->vPosition[0] = 0.0f;
1947 pSource->vPosition[1] = 0.0f;
1948 pSource->vPosition[2] = 0.0f;
1949 pSource->vOrientation[0] = 0.0f;
1950 pSource->vOrientation[1] = 0.0f;
1951 pSource->vOrientation[2] = 0.0f;
1952 pSource->vVelocity[0] = 0.0f;
1953 pSource->vVelocity[1] = 0.0f;
1954 pSource->vVelocity[2] = 0.0f;
1955 pSource->flRefDistance = 1.0f;
1956 pSource->flMaxDistance = FLT_MAX;
1957 pSource->flRollOffFactor = 1.0f;
1958 pSource->bLooping = AL_FALSE;
1959 pSource->flGain = 1.0f;
1960 pSource->flMinGain = 0.0f;
1961 pSource->flMaxGain = 1.0f;
1962 pSource->flOuterGain = 0.0f;
1964 pSource->DryGainHFAuto = AL_TRUE;
1965 pSource->WetGainAuto = AL_TRUE;
1966 pSource->WetGainHFAuto = AL_TRUE;
1967 pSource->AirAbsorptionFactor = 0.0f;
1969 pSource->state = AL_INITIAL;
1970 pSource->lSourceType = AL_UNDETERMINED;
1972 pSource->ulBufferID= 0;
1977 GetSourceOffset
1979 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1980 The offset is relative to the start of the queue (not the start of the current buffer)
1982 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1984 ALbufferlistitem *pBufferList;
1985 ALfloat flBufferFreq;
1986 ALint lBytesPlayed, lChannels;
1987 ALenum eOriginalFormat;
1988 ALboolean bReturn = AL_TRUE;
1989 ALint lTotalBufferDataSize;
1991 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1993 // Get Current Buffer Size and frequency (in milliseconds)
1994 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1995 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1996 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1998 // Get Current BytesPlayed
1999 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2000 // Add byte length of any processed buffers in the queue
2001 pBufferList = pSource->queue;
2002 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2004 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2005 pBufferList = pBufferList->next;
2008 lTotalBufferDataSize = 0;
2009 pBufferList = pSource->queue;
2010 while (pBufferList)
2012 if (pBufferList->buffer)
2013 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2014 pBufferList = pBufferList->next;
2017 if (pSource->bLooping)
2019 if (lBytesPlayed < 0)
2020 lBytesPlayed = 0;
2021 else
2022 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2024 else
2026 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2027 if(lBytesPlayed < 0)
2028 lBytesPlayed = 0;
2029 if(lBytesPlayed > lTotalBufferDataSize)
2030 lBytesPlayed = lTotalBufferDataSize;
2033 switch (eName)
2035 case AL_SEC_OFFSET:
2036 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2037 break;
2038 case AL_SAMPLE_OFFSET:
2039 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2040 break;
2041 case AL_BYTE_OFFSET:
2042 // Take into account the original format of the Buffer
2043 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
2045 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2047 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2049 // Compression rate of the ADPCM supported is 3.6111 to 1
2050 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2051 // Round down to nearest ADPCM block
2052 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2054 else
2056 *pflOffset = (ALfloat)lBytesPlayed;
2058 break;
2061 else
2063 *pflOffset = 0.0f;
2066 return bReturn;
2071 ApplyOffset
2073 Apply a playback offset to the Source. This function will update the queue (to correctly
2074 mark buffers as 'pending' or 'processed' depending upon the new offset.
2076 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2078 ALbufferlistitem *pBufferList;
2079 ALint lBufferSize, lTotalBufferSize;
2080 ALint lByteOffset;
2082 // Get true byte offset
2083 lByteOffset = GetByteOffset(pSource);
2085 // If this is a valid offset apply it
2086 if (lByteOffset != -1)
2088 // Sort out the queue (pending and processed states)
2089 pBufferList = pSource->queue;
2090 lTotalBufferSize = 0;
2091 pSource->BuffersPlayed = 0;
2092 pSource->BuffersProcessed = 0;
2093 while (pBufferList)
2095 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
2097 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2099 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2100 // update the state to PROCESSED
2101 pSource->BuffersPlayed++;
2103 if (!pSource->bLooping)
2105 pBufferList->bufferstate = PROCESSED;
2106 pSource->BuffersProcessed++;
2109 else if (lTotalBufferSize <= lByteOffset)
2111 // Offset is within this buffer
2112 pBufferList->bufferstate = PENDING;
2114 // Set Current Buffer ID
2115 pSource->ulBufferID = pBufferList->buffer;
2117 // Set current position in this buffer
2118 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2120 // Set Total Bytes Played to Offset
2121 pSource->lBytesPlayed = lByteOffset;
2123 // SW Mixer Positions are in Samples
2124 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2126 else
2128 // Offset is before this buffer, so mark as pending
2129 pBufferList->bufferstate = PENDING;
2132 // Increment the TotalBufferSize
2133 lTotalBufferSize += lBufferSize;
2135 // Move on to next buffer in the Queue
2136 pBufferList = pBufferList->next;
2139 else
2141 if (bUpdateContext)
2142 alSetError(AL_INVALID_VALUE);
2145 // Clear Offset
2146 pSource->lOffset = 0;
2151 GetByteOffset
2153 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2154 offset supplied by the application). This takes into account the fact that the buffer format
2155 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2157 static ALint GetByteOffset(ALsource *pSource)
2159 ALbuffer *pBuffer = NULL;
2160 ALbufferlistitem *pBufferList;
2161 ALfloat flBufferFreq;
2162 ALint lChannels;
2163 ALint lByteOffset = -1;
2164 ALint lTotalBufferDataSize;
2166 // Find the first non-NULL Buffer in the Queue
2167 pBufferList = pSource->queue;
2168 while (pBufferList)
2170 if (pBufferList->buffer)
2172 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2173 break;
2175 pBufferList = pBufferList->next;
2178 if (pBuffer)
2180 flBufferFreq = ((ALfloat)pBuffer->frequency);
2181 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2183 // Determine the ByteOffset (and ensure it is block aligned)
2184 switch (pSource->lOffsetType)
2186 case AL_BYTE_OFFSET:
2187 // Take into consideration the original format
2188 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2190 lByteOffset = pSource->lOffset * 2;
2191 lByteOffset -= (lByteOffset % (lChannels * 2));
2193 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2195 // Round down to nearest ADPCM block
2196 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2197 // Multiply by compression rate
2198 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2199 lByteOffset -= (lByteOffset % (lChannels * 2));
2201 else
2203 lByteOffset = pSource->lOffset;
2204 lByteOffset -= (lByteOffset % (lChannels * 2));
2206 break;
2208 case AL_SAMPLE_OFFSET:
2209 lByteOffset = pSource->lOffset * lChannels * 2;
2210 break;
2212 case AL_SEC_OFFSET:
2213 // Note - lOffset is internally stored as Milliseconds
2214 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2215 lByteOffset -= (lByteOffset % (lChannels * 2));
2216 break;
2219 lTotalBufferDataSize = 0;
2220 pBufferList = pSource->queue;
2221 while (pBufferList)
2223 if (pBufferList->buffer)
2224 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2225 pBufferList = pBufferList->next;
2228 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2229 if (lByteOffset >= lTotalBufferDataSize)
2230 lByteOffset = -1;
2233 return lByteOffset;