Allow auxiliary effect slot 0 when (un)setting the source auxiliary send
[openal-soft.git] / OpenAL32 / alSource.c
blob5b40f7eb6fd8141f18d8c26d721f3acec261f6d5
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 < MAX_SENDS &&
740 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
741 alIsFilter(lValue3))
743 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
744 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
746 if(!ALEffectSlot)
748 /* Disable slot */
749 pSource->Send[lValue2].Slot.effectslot = 0;
751 else
752 memcpy(&pSource->Send[lValue2].Slot, ALEffectSlot, sizeof(*ALEffectSlot));
754 if(!ALFilter)
756 /* Disable filter */
757 pSource->Send[lValue2].WetFilter.type = 0;
758 pSource->Send[lValue2].WetFilter.filter = 0;
760 else
761 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
763 else
764 alSetError(AL_INVALID_VALUE);
765 break;
767 default:
768 alSetError(AL_INVALID_ENUM);
769 break;
772 else
773 alSetError(AL_INVALID_NAME);
775 ProcessContext(pContext);
777 else
778 alSetError(AL_INVALID_OPERATION);
780 return;
784 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
786 ALCcontext *pContext;
788 pContext = alcGetCurrentContext();
789 if (pContext)
791 SuspendContext(pContext);
793 if (plValues)
795 if (alIsSource(source))
797 switch (eParam)
799 case AL_SOURCE_RELATIVE:
800 case AL_CONE_INNER_ANGLE:
801 case AL_CONE_OUTER_ANGLE:
802 case AL_LOOPING:
803 case AL_BUFFER:
804 case AL_SOURCE_STATE:
805 case AL_SEC_OFFSET:
806 case AL_SAMPLE_OFFSET:
807 case AL_BYTE_OFFSET:
808 case AL_MAX_DISTANCE:
809 case AL_ROLLOFF_FACTOR:
810 case AL_REFERENCE_DISTANCE:
811 case AL_DIRECT_FILTER:
812 case AL_DIRECT_FILTER_GAINHF_AUTO:
813 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
814 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
815 alSourcei(source, eParam, plValues[0]);
816 break;
818 case AL_POSITION:
819 case AL_VELOCITY:
820 case AL_DIRECTION:
821 case AL_AUXILIARY_SEND_FILTER:
822 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
823 break;
825 default:
826 alSetError(AL_INVALID_ENUM);
827 break;
830 else
831 alSetError(AL_INVALID_NAME);
833 else
834 alSetError(AL_INVALID_VALUE);
836 ProcessContext(pContext);
838 else
839 alSetError(AL_INVALID_OPERATION);
841 return;
845 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
847 ALCcontext *pContext;
848 ALsource *pSource;
849 ALfloat flOffset;
851 pContext = alcGetCurrentContext();
852 if (pContext)
854 SuspendContext(pContext);
856 if (pflValue)
858 if (alIsSource(source))
860 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
862 switch(eParam)
864 case AL_PITCH:
865 *pflValue = pSource->flPitch;
866 break;
868 case AL_GAIN:
869 *pflValue = pSource->flGain;
870 break;
872 case AL_MIN_GAIN:
873 *pflValue = pSource->flMinGain;
874 break;
876 case AL_MAX_GAIN:
877 *pflValue = pSource->flMaxGain;
878 break;
880 case AL_MAX_DISTANCE:
881 *pflValue = pSource->flMaxDistance;
882 break;
884 case AL_ROLLOFF_FACTOR:
885 *pflValue = pSource->flRollOffFactor;
886 break;
888 case AL_CONE_OUTER_GAIN:
889 *pflValue = pSource->flOuterGain;
890 break;
892 case AL_CONE_OUTER_GAINHF:
893 *pflValue = pSource->OuterGainHF;
894 break;
896 case AL_SEC_OFFSET:
897 case AL_SAMPLE_OFFSET:
898 case AL_BYTE_OFFSET:
899 if (GetSourceOffset(pSource, eParam, &flOffset))
900 *pflValue = flOffset;
901 else
902 alSetError(AL_INVALID_OPERATION);
903 break;
905 case AL_CONE_INNER_ANGLE:
906 *pflValue = pSource->flInnerAngle;
907 break;
909 case AL_CONE_OUTER_ANGLE:
910 *pflValue = pSource->flOuterAngle;
911 break;
913 case AL_REFERENCE_DISTANCE:
914 *pflValue = pSource->flRefDistance;
915 break;
917 case AL_AIR_ABSORPTION_FACTOR:
918 *pflValue = pSource->AirAbsorptionFactor;
919 break;
921 case AL_ROOM_ROLLOFF_FACTOR:
922 *pflValue = pSource->RoomRolloffFactor;
923 break;
925 default:
926 alSetError(AL_INVALID_ENUM);
927 break;
930 else
931 alSetError(AL_INVALID_NAME);
933 else
934 alSetError(AL_INVALID_VALUE);
936 ProcessContext(pContext);
938 else
939 alSetError(AL_INVALID_OPERATION);
941 return;
945 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
947 ALCcontext *pContext;
948 ALsource *pSource;
950 pContext = alcGetCurrentContext();
951 if (pContext)
953 SuspendContext(pContext);
955 if ((pflValue1) && (pflValue2) && (pflValue3))
957 if (alIsSource(source))
959 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
961 switch(eParam)
963 case AL_POSITION:
964 *pflValue1 = pSource->vPosition[0];
965 *pflValue2 = pSource->vPosition[1];
966 *pflValue3 = pSource->vPosition[2];
967 break;
969 case AL_VELOCITY:
970 *pflValue1 = pSource->vVelocity[0];
971 *pflValue2 = pSource->vVelocity[1];
972 *pflValue3 = pSource->vVelocity[2];
973 break;
975 case AL_DIRECTION:
976 *pflValue1 = pSource->vOrientation[0];
977 *pflValue2 = pSource->vOrientation[1];
978 *pflValue3 = pSource->vOrientation[2];
979 break;
981 default:
982 alSetError(AL_INVALID_ENUM);
983 break;
986 else
987 alSetError(AL_INVALID_NAME);
989 else
990 alSetError(AL_INVALID_VALUE);
992 ProcessContext(pContext);
994 else
995 alSetError(AL_INVALID_OPERATION);
997 return;
1001 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1003 ALCcontext *pContext;
1004 ALsource *pSource;
1006 pContext = alcGetCurrentContext();
1007 if (pContext)
1009 SuspendContext(pContext);
1011 if (pflValues)
1013 if (alIsSource(source))
1015 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1017 switch(eParam)
1019 case AL_PITCH:
1020 case AL_GAIN:
1021 case AL_MIN_GAIN:
1022 case AL_MAX_GAIN:
1023 case AL_MAX_DISTANCE:
1024 case AL_ROLLOFF_FACTOR:
1025 case AL_CONE_OUTER_GAIN:
1026 case AL_SEC_OFFSET:
1027 case AL_SAMPLE_OFFSET:
1028 case AL_BYTE_OFFSET:
1029 case AL_CONE_INNER_ANGLE:
1030 case AL_CONE_OUTER_ANGLE:
1031 case AL_REFERENCE_DISTANCE:
1032 case AL_CONE_OUTER_GAINHF:
1033 case AL_AIR_ABSORPTION_FACTOR:
1034 case AL_ROOM_ROLLOFF_FACTOR:
1035 alGetSourcef(source, eParam, pflValues);
1036 break;
1038 case AL_POSITION:
1039 pflValues[0] = pSource->vPosition[0];
1040 pflValues[1] = pSource->vPosition[1];
1041 pflValues[2] = pSource->vPosition[2];
1042 break;
1044 case AL_VELOCITY:
1045 pflValues[0] = pSource->vVelocity[0];
1046 pflValues[1] = pSource->vVelocity[1];
1047 pflValues[2] = pSource->vVelocity[2];
1048 break;
1050 case AL_DIRECTION:
1051 pflValues[0] = pSource->vOrientation[0];
1052 pflValues[1] = pSource->vOrientation[1];
1053 pflValues[2] = pSource->vOrientation[2];
1054 break;
1056 default:
1057 alSetError(AL_INVALID_ENUM);
1058 break;
1061 else
1062 alSetError(AL_INVALID_NAME);
1064 else
1065 alSetError(AL_INVALID_VALUE);
1067 ProcessContext(pContext);
1069 else
1070 alSetError(AL_INVALID_OPERATION);
1072 return;
1076 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1078 ALCcontext *pContext;
1079 ALsource *pSource;
1080 ALfloat flOffset;
1082 pContext = alcGetCurrentContext();
1083 if (pContext)
1085 SuspendContext(pContext);
1087 if (plValue)
1089 if (alIsSource(source))
1091 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1093 switch(eParam)
1095 case AL_MAX_DISTANCE:
1096 *plValue = (ALint)pSource->flMaxDistance;
1097 break;
1099 case AL_ROLLOFF_FACTOR:
1100 *plValue = (ALint)pSource->flRollOffFactor;
1101 break;
1103 case AL_REFERENCE_DISTANCE:
1104 *plValue = (ALint)pSource->flRefDistance;
1105 break;
1107 case AL_SOURCE_RELATIVE:
1108 *plValue = pSource->bHeadRelative;
1109 break;
1111 case AL_CONE_INNER_ANGLE:
1112 *plValue = (ALint)pSource->flInnerAngle;
1113 break;
1115 case AL_CONE_OUTER_ANGLE:
1116 *plValue = (ALint)pSource->flOuterAngle;
1117 break;
1119 case AL_LOOPING:
1120 *plValue = pSource->bLooping;
1121 break;
1123 case AL_BUFFER:
1124 *plValue = pSource->ulBufferID;
1125 break;
1127 case AL_SOURCE_STATE:
1128 *plValue = pSource->state;
1129 break;
1131 case AL_BUFFERS_QUEUED:
1132 *plValue = pSource->BuffersInQueue;
1133 break;
1135 case AL_BUFFERS_PROCESSED:
1136 if(pSource->bLooping)
1138 /* Buffers on a looping source are in a perpetual state
1139 * of PENDING, so don't report any as PROCESSED */
1140 *plValue = 0;
1142 else
1143 *plValue = pSource->BuffersProcessed;
1144 break;
1146 case AL_SOURCE_TYPE:
1147 *plValue = pSource->lSourceType;
1148 break;
1150 case AL_SEC_OFFSET:
1151 case AL_SAMPLE_OFFSET:
1152 case AL_BYTE_OFFSET:
1153 if (GetSourceOffset(pSource, eParam, &flOffset))
1154 *plValue = (ALint)flOffset;
1155 else
1156 alSetError(AL_INVALID_OPERATION);
1157 break;
1159 case AL_DIRECT_FILTER:
1160 *plValue = pSource->DirectFilter.filter;
1161 break;
1163 case AL_DIRECT_FILTER_GAINHF_AUTO:
1164 *plValue = pSource->DryGainHFAuto;
1165 break;
1167 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1168 *plValue = pSource->WetGainAuto;
1169 break;
1171 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1172 *plValue = pSource->WetGainHFAuto;
1173 break;
1175 default:
1176 alSetError(AL_INVALID_ENUM);
1177 break;
1180 else
1181 alSetError(AL_INVALID_NAME);
1183 else
1184 alSetError(AL_INVALID_VALUE);
1186 ProcessContext(pContext);
1188 else
1189 alSetError(AL_INVALID_OPERATION);
1191 return;
1195 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1197 ALCcontext *pContext;
1198 ALsource *pSource;
1200 pContext = alcGetCurrentContext();
1201 if (pContext)
1203 SuspendContext(pContext);
1205 if ((plValue1) && (plValue2) && (plValue3))
1207 if (alIsSource(source))
1209 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1211 switch(eParam)
1213 case AL_POSITION:
1214 *plValue1 = (ALint)pSource->vPosition[0];
1215 *plValue2 = (ALint)pSource->vPosition[1];
1216 *plValue3 = (ALint)pSource->vPosition[2];
1217 break;
1219 case AL_VELOCITY:
1220 *plValue1 = (ALint)pSource->vVelocity[0];
1221 *plValue2 = (ALint)pSource->vVelocity[1];
1222 *plValue3 = (ALint)pSource->vVelocity[2];
1223 break;
1225 case AL_DIRECTION:
1226 *plValue1 = (ALint)pSource->vOrientation[0];
1227 *plValue2 = (ALint)pSource->vOrientation[1];
1228 *plValue3 = (ALint)pSource->vOrientation[2];
1229 break;
1231 default:
1232 alSetError(AL_INVALID_ENUM);
1233 break;
1236 else
1237 alSetError(AL_INVALID_NAME);
1239 else
1240 alSetError(AL_INVALID_VALUE);
1242 ProcessContext(pContext);
1244 else
1245 alSetError(AL_INVALID_OPERATION);
1247 return;
1251 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1253 ALCcontext *pContext;
1254 ALsource *pSource;
1256 pContext = alcGetCurrentContext();
1257 if (pContext)
1259 SuspendContext(pContext);
1261 if (plValues)
1263 if (alIsSource(source))
1265 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1267 switch (eParam)
1269 case AL_SOURCE_RELATIVE:
1270 case AL_CONE_INNER_ANGLE:
1271 case AL_CONE_OUTER_ANGLE:
1272 case AL_LOOPING:
1273 case AL_BUFFER:
1274 case AL_SOURCE_STATE:
1275 case AL_BUFFERS_QUEUED:
1276 case AL_BUFFERS_PROCESSED:
1277 case AL_SEC_OFFSET:
1278 case AL_SAMPLE_OFFSET:
1279 case AL_BYTE_OFFSET:
1280 case AL_MAX_DISTANCE:
1281 case AL_ROLLOFF_FACTOR:
1282 case AL_REFERENCE_DISTANCE:
1283 case AL_SOURCE_TYPE:
1284 case AL_DIRECT_FILTER:
1285 case AL_DIRECT_FILTER_GAINHF_AUTO:
1286 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1287 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1288 alGetSourcei(source, eParam, plValues);
1289 break;
1291 case AL_POSITION:
1292 plValues[0] = (ALint)pSource->vPosition[0];
1293 plValues[1] = (ALint)pSource->vPosition[1];
1294 plValues[2] = (ALint)pSource->vPosition[2];
1295 break;
1297 case AL_VELOCITY:
1298 plValues[0] = (ALint)pSource->vVelocity[0];
1299 plValues[1] = (ALint)pSource->vVelocity[1];
1300 plValues[2] = (ALint)pSource->vVelocity[2];
1301 break;
1303 case AL_DIRECTION:
1304 plValues[0] = (ALint)pSource->vOrientation[0];
1305 plValues[1] = (ALint)pSource->vOrientation[1];
1306 plValues[2] = (ALint)pSource->vOrientation[2];
1307 break;
1309 default:
1310 alSetError(AL_INVALID_ENUM);
1311 break;
1314 else
1315 alSetError(AL_INVALID_NAME);
1317 else
1318 alSetError(AL_INVALID_VALUE);
1320 ProcessContext(pContext);
1322 else
1323 alSetError(AL_INVALID_OPERATION);
1325 return;
1329 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1331 alSourcePlayv(1, &source);
1332 return;
1335 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1337 ALCcontext *pContext;
1338 ALsource *pSource;
1339 ALbufferlistitem *ALBufferList;
1340 ALboolean bSourcesValid = AL_TRUE;
1341 ALboolean bPlay;
1342 ALsizei i;
1344 pContext = alcGetCurrentContext();
1345 if (pContext)
1347 SuspendContext(pContext);
1349 if (pSourceList)
1351 // Check that all the Sources are valid
1352 for (i = 0; i < n; i++)
1354 if (!alIsSource(pSourceList[i]))
1356 alSetError(AL_INVALID_NAME);
1357 bSourcesValid = AL_FALSE;
1358 break;
1362 if (bSourcesValid)
1364 for (i = 0; i < n; i++)
1366 // Assume Source won't need to play
1367 bPlay = AL_FALSE;
1369 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1371 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1372 ALBufferList = pSource->queue;
1373 while (ALBufferList)
1375 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1377 bPlay = AL_TRUE;
1378 break;
1380 ALBufferList = ALBufferList->next;
1383 if (bPlay)
1385 if (pSource->state != AL_PAUSED)
1387 pSource->state = AL_PLAYING;
1388 pSource->inuse = AL_TRUE;
1389 pSource->play = AL_TRUE;
1390 pSource->position = 0;
1391 pSource->position_fraction = 0;
1392 pSource->BuffersProcessed = 0;
1393 pSource->BuffersPlayed = 0;
1394 pSource->BufferPosition = 0;
1395 pSource->lBytesPlayed = 0;
1397 pSource->ulBufferID = pSource->queue->buffer;
1399 // Make sure all the Buffers in the queue are marked as PENDING
1400 ALBufferList = pSource->queue;
1401 while (ALBufferList)
1403 ALBufferList->bufferstate = PENDING;
1404 ALBufferList = ALBufferList->next;
1407 else
1409 pSource->state = AL_PLAYING;
1410 pSource->inuse = AL_TRUE;
1411 pSource->play = AL_TRUE;
1414 // Check if an Offset has been set
1415 if (pSource->lOffset)
1416 ApplyOffset(pSource, AL_FALSE);
1418 else
1420 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1421 ALBufferList = pSource->queue;
1422 while (ALBufferList)
1424 ALBufferList->bufferstate = PROCESSED;
1425 ALBufferList = ALBufferList->next;
1428 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1433 else
1435 // sources is a NULL pointer
1436 alSetError(AL_INVALID_VALUE);
1439 ProcessContext(pContext);
1441 else
1443 // Invalid Context
1444 alSetError(AL_INVALID_OPERATION);
1447 return;
1450 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1452 alSourcePausev(1, &source);
1453 return;
1456 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1458 ALCcontext *Context;
1459 ALsource *Source;
1460 ALsizei i;
1461 ALboolean bSourcesValid = AL_TRUE;
1463 Context=alcGetCurrentContext();
1464 if (Context)
1466 SuspendContext(Context);
1468 if (sources)
1470 // Check all the Sources are valid
1471 for (i=0;i<n;i++)
1473 if (!alIsSource(sources[i]))
1475 alSetError(AL_INVALID_NAME);
1476 bSourcesValid = AL_FALSE;
1477 break;
1481 if (bSourcesValid)
1483 for (i=0;i<n;i++)
1485 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1486 if (Source->state==AL_PLAYING)
1488 Source->state=AL_PAUSED;
1489 Source->inuse=AL_FALSE;
1494 else
1496 // sources is a NULL pointer
1497 alSetError(AL_INVALID_VALUE);
1500 ProcessContext(Context);
1502 else
1504 // Invalid Context
1505 alSetError(AL_INVALID_OPERATION);
1508 return;
1511 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1513 alSourceStopv(1, &source);
1514 return;
1517 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1519 ALCcontext *Context;
1520 ALsource *Source;
1521 ALsizei i;
1522 ALbufferlistitem *ALBufferListItem;
1523 ALboolean bSourcesValid = AL_TRUE;
1525 Context=alcGetCurrentContext();
1526 if (Context)
1528 SuspendContext(Context);
1530 if (sources)
1532 // Check all the Sources are valid
1533 for (i=0;i<n;i++)
1535 if (!alIsSource(sources[i]))
1537 alSetError(AL_INVALID_NAME);
1538 bSourcesValid = AL_FALSE;
1539 break;
1543 if (bSourcesValid)
1545 for (i=0;i<n;i++)
1547 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1548 if (Source->state!=AL_INITIAL)
1550 Source->state=AL_STOPPED;
1551 Source->inuse=AL_FALSE;
1552 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1553 ALBufferListItem= Source->queue;
1554 while (ALBufferListItem != NULL)
1556 ALBufferListItem->bufferstate = PROCESSED;
1557 ALBufferListItem = ALBufferListItem->next;
1560 Source->lOffset = 0;
1564 else
1566 // sources is a NULL pointer
1567 alSetError(AL_INVALID_VALUE);
1570 ProcessContext(Context);
1572 else
1574 // Invalid Context
1575 alSetError(AL_INVALID_OPERATION);
1578 return;
1581 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1583 alSourceRewindv(1, &source);
1584 return;
1587 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1589 ALCcontext *Context;
1590 ALsource *Source;
1591 ALsizei i;
1592 ALbufferlistitem *ALBufferListItem;
1593 ALboolean bSourcesValid = AL_TRUE;
1595 Context=alcGetCurrentContext();
1596 if (Context)
1598 SuspendContext(Context);
1600 if (sources)
1602 // Check all the Sources are valid
1603 for (i=0;i<n;i++)
1605 if (!alIsSource(sources[i]))
1607 alSetError(AL_INVALID_NAME);
1608 bSourcesValid = AL_FALSE;
1609 break;
1613 if (bSourcesValid)
1615 for (i=0;i<n;i++)
1617 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1618 if (Source->state!=AL_INITIAL)
1620 Source->state=AL_INITIAL;
1621 Source->inuse=AL_FALSE;
1622 Source->position=0;
1623 Source->position_fraction=0;
1624 Source->BuffersProcessed = 0;
1625 ALBufferListItem= Source->queue;
1626 while (ALBufferListItem != NULL)
1628 ALBufferListItem->bufferstate = PENDING;
1629 ALBufferListItem = ALBufferListItem->next;
1631 if (Source->queue)
1632 Source->ulBufferID = Source->queue->buffer;
1634 Source->lOffset = 0;
1638 else
1640 // sources is a NULL pointer
1641 alSetError(AL_INVALID_VALUE);
1644 ProcessContext(Context);
1646 else
1648 // Invalid Context
1649 alSetError(AL_INVALID_OPERATION);
1652 return;
1656 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1658 ALCcontext *Context;
1659 ALsource *ALSource;
1660 ALsizei i;
1661 ALbufferlistitem *ALBufferList;
1662 ALbufferlistitem *ALBufferListStart;
1663 ALuint DataSize;
1664 ALuint BufferSize;
1665 ALint iFrequency;
1666 ALint iFormat;
1667 ALboolean bBuffersValid = AL_TRUE;
1669 if (n == 0)
1670 return;
1672 Context=alcGetCurrentContext();
1673 if (Context)
1675 SuspendContext(Context);
1677 DataSize = 0;
1678 BufferSize = 0;
1680 // Check that all buffers are valid or zero and that the source is valid
1682 // Check that this is a valid source
1683 if (alIsSource(source))
1685 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1687 // Check that this is not a STATIC Source
1688 if (ALSource->lSourceType != AL_STATIC)
1690 iFrequency = -1;
1691 iFormat = -1;
1693 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1694 ALBufferList = ALSource->queue;
1695 while (ALBufferList)
1697 if (ALBufferList->buffer)
1699 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1700 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1701 break;
1703 ALBufferList = ALBufferList->next;
1706 for (i = 0; i < n; i++)
1708 if (alIsBuffer(buffers[i]))
1710 if (buffers[i])
1712 if ((iFrequency == -1) && (iFormat == -1))
1714 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1715 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1717 else
1719 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1720 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1722 alSetError(AL_INVALID_OPERATION);
1723 bBuffersValid = AL_FALSE;
1724 break;
1729 else
1731 alSetError(AL_INVALID_NAME);
1732 bBuffersValid = AL_FALSE;
1733 break;
1737 if (bBuffersValid)
1739 // Change Source Type
1740 ALSource->lSourceType = AL_STREAMING;
1742 // All buffers are valid - so add them to the list
1743 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1744 ALBufferListStart->buffer = buffers[0];
1745 ALBufferListStart->bufferstate = PENDING;
1746 ALBufferListStart->flag = 0;
1747 ALBufferListStart->next = NULL;
1749 if (buffers[0])
1750 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1751 else
1752 BufferSize = 0;
1754 DataSize += BufferSize;
1756 // Increment reference counter for buffer
1757 if (buffers[0])
1758 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1760 ALBufferList = ALBufferListStart;
1762 for (i = 1; i < n; i++)
1764 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1765 ALBufferList->next->buffer = buffers[i];
1766 ALBufferList->next->bufferstate = PENDING;
1767 ALBufferList->next->flag = 0;
1768 ALBufferList->next->next = NULL;
1770 if (buffers[i])
1771 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1772 else
1773 BufferSize = 0;
1775 DataSize += BufferSize;
1777 // Increment reference counter for buffer
1778 if (buffers[i])
1779 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1781 ALBufferList = ALBufferList->next;
1784 if (ALSource->queue == NULL)
1786 ALSource->queue = ALBufferListStart;
1787 // Update Current Buffer
1788 ALSource->ulBufferID = ALBufferListStart->buffer;
1790 else
1792 // Find end of queue
1793 ALBufferList = ALSource->queue;
1794 while (ALBufferList->next != NULL)
1796 ALBufferList = ALBufferList->next;
1799 ALBufferList->next = ALBufferListStart;
1802 // Update number of buffers in queue
1803 ALSource->BuffersInQueue += n;
1806 else
1808 // Invalid Source Type (can't queue on a Static Source)
1809 alSetError(AL_INVALID_OPERATION);
1812 else
1814 // Invalid Source Name
1815 alSetError(AL_INVALID_NAME);
1818 ProcessContext(Context);
1820 else
1822 // Invalid Context
1823 alSetError(AL_INVALID_OPERATION);
1826 return;
1830 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1831 // an array of buffer IDs that are to be filled with the names of the buffers removed
1832 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1834 ALCcontext *Context;
1835 ALsource *ALSource;
1836 ALsizei i;
1837 ALbufferlistitem *ALBufferList;
1838 ALuint DataSize;
1839 ALuint BufferSize;
1840 ALuint BufferID;
1841 ALboolean bBuffersProcessed;
1843 if (n == 0)
1844 return;
1846 DataSize = 0;
1847 BufferSize = 0;
1848 bBuffersProcessed = AL_TRUE;
1850 Context=alcGetCurrentContext();
1851 if (Context)
1853 SuspendContext(Context);
1855 if (alIsSource(source))
1857 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1859 // Check that all 'n' buffers have been processed
1860 ALBufferList = ALSource->queue;
1861 for (i = 0; i < n; i++)
1863 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1865 ALBufferList = ALBufferList->next;
1867 else
1869 bBuffersProcessed = AL_FALSE;
1870 break;
1874 // If all 'n' buffers have been processed, remove them from the queue
1875 if (bBuffersProcessed)
1877 for (i = 0; i < n; i++)
1879 ALBufferList = ALSource->queue;
1881 ALSource->queue = ALBufferList->next;
1882 // Record name of buffer
1883 buffers[i] = ALBufferList->buffer;
1884 // Decrement buffer reference counter
1885 if (ALBufferList->buffer)
1886 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1887 // Record size of buffer
1888 if (ALBufferList->buffer)
1889 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1890 else
1891 BufferSize = 0;
1893 DataSize += BufferSize;
1894 // Release memory for buffer list item
1895 free(ALBufferList);
1896 ALSource->BuffersInQueue--;
1897 ALSource->BuffersProcessed--;
1900 if (ALSource->state != AL_PLAYING)
1902 if (ALSource->queue)
1903 BufferID = ALSource->queue->buffer;
1904 else
1905 BufferID = 0;
1907 ALSource->ulBufferID = BufferID;
1910 if((ALuint)n > ALSource->BuffersPlayed)
1912 ALSource->BuffersPlayed = 0;
1913 ALSource->BufferPosition = 0;
1915 else
1916 ALSource->BuffersPlayed -= n;
1918 else
1920 // Some buffers can't be unqueue because they have not been processed
1921 alSetError(AL_INVALID_VALUE);
1924 else
1926 // Invalid Source Name
1927 alSetError(AL_INVALID_NAME);
1930 ProcessContext(Context);
1932 else
1934 // Invalid Context
1935 alSetError(AL_INVALID_OPERATION);
1938 return;
1942 static ALvoid InitSourceParams(ALsource *pSource)
1944 pSource->flInnerAngle = 360.0f;
1945 pSource->flOuterAngle = 360.0f;
1946 pSource->flPitch = 1.0f;
1947 pSource->vPosition[0] = 0.0f;
1948 pSource->vPosition[1] = 0.0f;
1949 pSource->vPosition[2] = 0.0f;
1950 pSource->vOrientation[0] = 0.0f;
1951 pSource->vOrientation[1] = 0.0f;
1952 pSource->vOrientation[2] = 0.0f;
1953 pSource->vVelocity[0] = 0.0f;
1954 pSource->vVelocity[1] = 0.0f;
1955 pSource->vVelocity[2] = 0.0f;
1956 pSource->flRefDistance = 1.0f;
1957 pSource->flMaxDistance = FLT_MAX;
1958 pSource->flRollOffFactor = 1.0f;
1959 pSource->bLooping = AL_FALSE;
1960 pSource->flGain = 1.0f;
1961 pSource->flMinGain = 0.0f;
1962 pSource->flMaxGain = 1.0f;
1963 pSource->flOuterGain = 0.0f;
1965 pSource->DryGainHFAuto = AL_TRUE;
1966 pSource->WetGainAuto = AL_TRUE;
1967 pSource->WetGainHFAuto = AL_TRUE;
1968 pSource->AirAbsorptionFactor = 0.0f;
1970 pSource->state = AL_INITIAL;
1971 pSource->lSourceType = AL_UNDETERMINED;
1973 pSource->ulBufferID= 0;
1978 GetSourceOffset
1980 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1981 The offset is relative to the start of the queue (not the start of the current buffer)
1983 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1985 ALbufferlistitem *pBufferList;
1986 ALfloat flBufferFreq;
1987 ALint lBytesPlayed, lChannels;
1988 ALenum eOriginalFormat;
1989 ALboolean bReturn = AL_TRUE;
1990 ALint lTotalBufferDataSize;
1992 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1994 // Get Current Buffer Size and frequency (in milliseconds)
1995 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1996 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1997 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1999 // Get Current BytesPlayed
2000 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2001 // Add byte length of any processed buffers in the queue
2002 pBufferList = pSource->queue;
2003 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2005 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2006 pBufferList = pBufferList->next;
2009 lTotalBufferDataSize = 0;
2010 pBufferList = pSource->queue;
2011 while (pBufferList)
2013 if (pBufferList->buffer)
2014 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2015 pBufferList = pBufferList->next;
2018 if (pSource->bLooping)
2020 if (lBytesPlayed < 0)
2021 lBytesPlayed = 0;
2022 else
2023 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2025 else
2027 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2028 if(lBytesPlayed < 0)
2029 lBytesPlayed = 0;
2030 if(lBytesPlayed > lTotalBufferDataSize)
2031 lBytesPlayed = lTotalBufferDataSize;
2034 switch (eName)
2036 case AL_SEC_OFFSET:
2037 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2038 break;
2039 case AL_SAMPLE_OFFSET:
2040 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2041 break;
2042 case AL_BYTE_OFFSET:
2043 // Take into account the original format of the Buffer
2044 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
2046 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2048 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2050 // Compression rate of the ADPCM supported is 3.6111 to 1
2051 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2052 // Round down to nearest ADPCM block
2053 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2055 else
2057 *pflOffset = (ALfloat)lBytesPlayed;
2059 break;
2062 else
2064 *pflOffset = 0.0f;
2067 return bReturn;
2072 ApplyOffset
2074 Apply a playback offset to the Source. This function will update the queue (to correctly
2075 mark buffers as 'pending' or 'processed' depending upon the new offset.
2077 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2079 ALbufferlistitem *pBufferList;
2080 ALint lBufferSize, lTotalBufferSize;
2081 ALint lByteOffset;
2083 // Get true byte offset
2084 lByteOffset = GetByteOffset(pSource);
2086 // If this is a valid offset apply it
2087 if (lByteOffset != -1)
2089 // Sort out the queue (pending and processed states)
2090 pBufferList = pSource->queue;
2091 lTotalBufferSize = 0;
2092 pSource->BuffersPlayed = 0;
2093 pSource->BuffersProcessed = 0;
2094 while (pBufferList)
2096 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
2098 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2100 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2101 // update the state to PROCESSED
2102 pSource->BuffersPlayed++;
2104 if (!pSource->bLooping)
2106 pBufferList->bufferstate = PROCESSED;
2107 pSource->BuffersProcessed++;
2110 else if (lTotalBufferSize <= lByteOffset)
2112 // Offset is within this buffer
2113 pBufferList->bufferstate = PENDING;
2115 // Set Current Buffer ID
2116 pSource->ulBufferID = pBufferList->buffer;
2118 // Set current position in this buffer
2119 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2121 // Set Total Bytes Played to Offset
2122 pSource->lBytesPlayed = lByteOffset;
2124 // SW Mixer Positions are in Samples
2125 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2127 else
2129 // Offset is before this buffer, so mark as pending
2130 pBufferList->bufferstate = PENDING;
2133 // Increment the TotalBufferSize
2134 lTotalBufferSize += lBufferSize;
2136 // Move on to next buffer in the Queue
2137 pBufferList = pBufferList->next;
2140 else
2142 if (bUpdateContext)
2143 alSetError(AL_INVALID_VALUE);
2146 // Clear Offset
2147 pSource->lOffset = 0;
2152 GetByteOffset
2154 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2155 offset supplied by the application). This takes into account the fact that the buffer format
2156 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2158 static ALint GetByteOffset(ALsource *pSource)
2160 ALbuffer *pBuffer = NULL;
2161 ALbufferlistitem *pBufferList;
2162 ALfloat flBufferFreq;
2163 ALint lChannels;
2164 ALint lByteOffset = -1;
2165 ALint lTotalBufferDataSize;
2167 // Find the first non-NULL Buffer in the Queue
2168 pBufferList = pSource->queue;
2169 while (pBufferList)
2171 if (pBufferList->buffer)
2173 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2174 break;
2176 pBufferList = pBufferList->next;
2179 if (pBuffer)
2181 flBufferFreq = ((ALfloat)pBuffer->frequency);
2182 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2184 // Determine the ByteOffset (and ensure it is block aligned)
2185 switch (pSource->lOffsetType)
2187 case AL_BYTE_OFFSET:
2188 // Take into consideration the original format
2189 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2191 lByteOffset = pSource->lOffset * 2;
2192 lByteOffset -= (lByteOffset % (lChannels * 2));
2194 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2196 // Round down to nearest ADPCM block
2197 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2198 // Multiply by compression rate
2199 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2200 lByteOffset -= (lByteOffset % (lChannels * 2));
2202 else
2204 lByteOffset = pSource->lOffset;
2205 lByteOffset -= (lByteOffset % (lChannels * 2));
2207 break;
2209 case AL_SAMPLE_OFFSET:
2210 lByteOffset = pSource->lOffset * lChannels * 2;
2211 break;
2213 case AL_SEC_OFFSET:
2214 // Note - lOffset is internally stored as Milliseconds
2215 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2216 lByteOffset -= (lByteOffset % (lChannels * 2));
2217 break;
2220 lTotalBufferDataSize = 0;
2221 pBufferList = pSource->queue;
2222 while (pBufferList)
2224 if (pBufferList->buffer)
2225 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2226 pBufferList = pBufferList->next;
2229 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2230 if (lByteOffset >= lTotalBufferDataSize)
2231 lByteOffset = -1;
2234 return lByteOffset;