Implement an alternative low-pass filter
[openal-soft.git] / OpenAL32 / alSource.c
blob892129335231e288ff38f7f0f568bcb9e5656b60
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = alcGetCurrentContext();
47 if (Context)
49 SuspendContext(Context);
51 if (n > 0)
53 Device = alcGetContextsDevice(Context);
55 if (Device)
57 // Check that enough memory has been allocted in the 'sources' array for n Sources
58 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
60 // Check that the requested number of sources can be generated
61 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
63 ALsource **list = &Context->Source;
64 while(*list)
65 list = &(*list)->next;
67 // Add additional sources to the list (Source->next points to the location for the next Source structure)
68 while(i < n)
70 *list = calloc(1, sizeof(ALsource));
71 if(!(*list))
73 alDeleteSources(i, sources);
74 alSetError(AL_OUT_OF_MEMORY);
75 break;
78 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->source = sources[i];
81 InitSourceParams(*list);
82 Context->SourceCount++;
83 i++;
85 list = &(*list)->next;
88 else
90 // Not enough resources to create the Sources
91 alSetError(AL_INVALID_VALUE);
94 else
96 // Bad pointer
97 alSetError(AL_INVALID_VALUE);
100 else
102 // No Device created, or attached to Context
103 alSetError(AL_INVALID_OPERATION);
107 ProcessContext(Context);
109 else
111 // Invalid Context
112 alSetError(AL_INVALID_OPERATION);
115 return;
119 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
121 ALCcontext *Context;
122 ALCdevice *Device;
123 ALsource *ALSource;
124 ALsource **list;
125 ALsizei i, j;
126 ALbufferlistitem *ALBufferList;
127 ALboolean bSourcesValid = AL_TRUE;
129 Context = alcGetCurrentContext();
130 if (Context)
132 SuspendContext(Context);
134 if (n >= 0)
136 Device = alcGetContextsDevice(Context);
138 if (Device)
140 // Check that all Sources are valid (and can therefore be deleted)
141 for (i = 0; i < n; i++)
143 if (!alIsSource(sources[i]))
145 alSetError(AL_INVALID_NAME);
146 bSourcesValid = AL_FALSE;
147 break;
151 if (bSourcesValid)
153 // All Sources are valid, and can be deleted
154 for (i = 0; i < n; i++)
156 // Recheck that the Source is valid, because there could be duplicated Source names
157 if (alIsSource(sources[i]))
159 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
160 alSourceStop((ALuint)ALSource->source);
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while (ALSource->queue != NULL)
165 ALBufferList = ALSource->queue;
166 // Decrement buffer's reference counter
167 if (ALBufferList->buffer != 0)
168 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
169 // Update queue to point to next element in list
170 ALSource->queue = ALBufferList->next;
171 // Release memory allocated for buffer list item
172 free(ALBufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(ALSource->Send[j].Slot)
178 ALSource->Send[j].Slot->refcount--;
179 ALSource->Send[j].Slot = NULL;
182 // Decrement Source count
183 Context->SourceCount--;
185 // Remove Source from list of Sources
186 list = &Context->Source;
187 while(*list && *list != ALSource)
188 list = &(*list)->next;
190 if(*list)
191 *list = (*list)->next;
192 ALTHUNK_REMOVEENTRY(ALSource->source);
194 memset(ALSource,0,sizeof(ALsource));
195 free(ALSource);
200 else
202 // No Device created, or attached to Context
203 alSetError(AL_INVALID_OPERATION);
206 else
207 alSetError(AL_INVALID_VALUE);
209 ProcessContext(Context);
211 else
213 // Invalid Context
214 alSetError(AL_INVALID_OPERATION);
217 return;
221 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
223 ALboolean result=AL_FALSE;
224 ALCcontext *Context;
225 ALsource *Source;
227 Context=alcGetCurrentContext();
228 if (Context)
230 SuspendContext(Context);
232 // To determine if this is a valid Source name, look through the list of generated Sources
233 Source = Context->Source;
234 while(Source)
236 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
238 result = AL_TRUE;
239 break;
242 Source = Source->next;
245 ProcessContext(Context);
247 else
249 // Invalid Context
250 alSetError(AL_INVALID_OPERATION);
253 return result;
257 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
259 ALCcontext *pContext;
260 ALsource *pSource;
262 pContext = alcGetCurrentContext();
263 if (pContext)
265 SuspendContext(pContext);
267 if (alIsSource(source))
269 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
271 switch (eParam)
273 case AL_PITCH:
274 if (flValue >= 0.0f)
276 pSource->flPitch = flValue;
277 if(pSource->flPitch < 0.001f)
278 pSource->flPitch = 0.001f;
280 else
281 alSetError(AL_INVALID_VALUE);
282 break;
284 case AL_CONE_INNER_ANGLE:
285 if ((flValue >= 0.0f) && (flValue <= 360.0f))
286 pSource->flInnerAngle = flValue;
287 else
288 alSetError(AL_INVALID_VALUE);
289 break;
291 case AL_CONE_OUTER_ANGLE:
292 if ((flValue >= 0.0f) && (flValue <= 360.0f))
293 pSource->flOuterAngle = flValue;
294 else
295 alSetError(AL_INVALID_VALUE);
296 break;
298 case AL_GAIN:
299 if (flValue >= 0.0f)
300 pSource->flGain = flValue;
301 else
302 alSetError(AL_INVALID_VALUE);
303 break;
305 case AL_MAX_DISTANCE:
306 if (flValue >= 0.0f)
307 pSource->flMaxDistance = flValue;
308 else
309 alSetError(AL_INVALID_VALUE);
310 break;
312 case AL_ROLLOFF_FACTOR:
313 if (flValue >= 0.0f)
314 pSource->flRollOffFactor = flValue;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_REFERENCE_DISTANCE:
320 if (flValue >= 0.0f)
321 pSource->flRefDistance = flValue;
322 else
323 alSetError(AL_INVALID_VALUE);
324 break;
326 case AL_MIN_GAIN:
327 if ((flValue >= 0.0f) && (flValue <= 1.0f))
328 pSource->flMinGain = flValue;
329 else
330 alSetError(AL_INVALID_VALUE);
331 break;
333 case AL_MAX_GAIN:
334 if ((flValue >= 0.0f) && (flValue <= 1.0f))
335 pSource->flMaxGain = flValue;
336 else
337 alSetError(AL_INVALID_VALUE);
338 break;
340 case AL_CONE_OUTER_GAIN:
341 if ((flValue >= 0.0f) && (flValue <= 1.0f))
342 pSource->flOuterGain = flValue;
343 else
344 alSetError(AL_INVALID_VALUE);
345 break;
347 case AL_CONE_OUTER_GAINHF:
348 if ((flValue >= 0.0f) && (flValue <= 1.0f))
349 pSource->OuterGainHF = flValue;
350 else
351 alSetError(AL_INVALID_VALUE);
352 break;
354 case AL_AIR_ABSORPTION_FACTOR:
355 if (flValue >= 0.0f && flValue <= 10.0f)
356 pSource->AirAbsorptionFactor = flValue;
357 else
358 alSetError(AL_INVALID_VALUE);
359 break;
361 case AL_ROOM_ROLLOFF_FACTOR:
362 if (flValue >= 0.0f && flValue <= 1.0f)
363 pSource->RoomRolloffFactor = flValue;
364 else
365 alSetError(AL_INVALID_VALUE);
366 break;
368 case AL_SEC_OFFSET:
369 case AL_SAMPLE_OFFSET:
370 case AL_BYTE_OFFSET:
371 if (flValue >= 0.0f)
373 pSource->lOffsetType = eParam;
375 // Store Offset (convert Seconds into Milliseconds)
376 if (eParam == AL_SEC_OFFSET)
377 pSource->lOffset = (ALint)(flValue * 1000.0f);
378 else
379 pSource->lOffset = (ALint)flValue;
381 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
382 ApplyOffset(pSource, AL_TRUE);
384 else
385 alSetError(AL_INVALID_VALUE);
386 break;
388 default:
389 alSetError(AL_INVALID_ENUM);
390 break;
393 else
395 // Invalid Source Name
396 alSetError(AL_INVALID_NAME);
399 ProcessContext(pContext);
401 else
403 // Invalid context
404 alSetError(AL_INVALID_OPERATION);
407 return;
411 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
413 ALCcontext *pContext;
414 ALsource *pSource;
416 pContext = alcGetCurrentContext();
417 if (pContext)
419 SuspendContext(pContext);
421 if (alIsSource(source))
423 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
424 switch(eParam)
426 case AL_POSITION:
427 pSource->vPosition[0] = flValue1;
428 pSource->vPosition[1] = flValue2;
429 pSource->vPosition[2] = flValue3;
430 break;
432 case AL_VELOCITY:
433 pSource->vVelocity[0] = flValue1;
434 pSource->vVelocity[1] = flValue2;
435 pSource->vVelocity[2] = flValue3;
436 break;
438 case AL_DIRECTION:
439 pSource->vOrientation[0] = flValue1;
440 pSource->vOrientation[1] = flValue2;
441 pSource->vOrientation[2] = flValue3;
442 break;
444 default:
445 alSetError(AL_INVALID_ENUM);
446 break;
449 else
450 alSetError(AL_INVALID_NAME);
452 ProcessContext(pContext);
454 else
456 alSetError(AL_INVALID_OPERATION);
459 return;
463 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
465 ALCcontext *pContext;
467 pContext = alcGetCurrentContext();
468 if (pContext)
470 SuspendContext(pContext);
472 if (pflValues)
474 if (alIsSource(source))
476 switch (eParam)
478 case AL_PITCH:
479 case AL_CONE_INNER_ANGLE:
480 case AL_CONE_OUTER_ANGLE:
481 case AL_GAIN:
482 case AL_MAX_DISTANCE:
483 case AL_ROLLOFF_FACTOR:
484 case AL_REFERENCE_DISTANCE:
485 case AL_MIN_GAIN:
486 case AL_MAX_GAIN:
487 case AL_CONE_OUTER_GAIN:
488 case AL_CONE_OUTER_GAINHF:
489 case AL_SEC_OFFSET:
490 case AL_SAMPLE_OFFSET:
491 case AL_BYTE_OFFSET:
492 case AL_AIR_ABSORPTION_FACTOR:
493 case AL_ROOM_ROLLOFF_FACTOR:
494 alSourcef(source, eParam, pflValues[0]);
495 break;
497 case AL_POSITION:
498 case AL_VELOCITY:
499 case AL_DIRECTION:
500 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
501 break;
503 default:
504 alSetError(AL_INVALID_ENUM);
505 break;
508 else
509 alSetError(AL_INVALID_NAME);
511 else
512 alSetError(AL_INVALID_VALUE);
514 ProcessContext(pContext);
516 else
517 alSetError(AL_INVALID_OPERATION);
519 return;
523 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
525 ALCcontext *pContext;
526 ALsource *pSource;
527 ALbufferlistitem *pALBufferListItem;
528 ALint Counter = 0;
529 ALint DataSize = 0;
530 ALint BufferSize;
532 pContext = alcGetCurrentContext();
533 if (pContext)
535 SuspendContext(pContext);
537 if (alIsSource(source))
539 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
541 switch(eParam)
543 case AL_MAX_DISTANCE:
544 case AL_ROLLOFF_FACTOR:
545 case AL_REFERENCE_DISTANCE:
546 alSourcef(source, eParam, (ALfloat)lValue);
547 break;
549 case AL_SOURCE_RELATIVE:
550 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
551 pSource->bHeadRelative = (ALboolean)lValue;
552 else
553 alSetError(AL_INVALID_VALUE);
554 break;
556 case AL_CONE_INNER_ANGLE:
557 if ((lValue >= 0) && (lValue <= 360))
558 pSource->flInnerAngle = (float)lValue;
559 else
560 alSetError(AL_INVALID_VALUE);
561 break;
563 case AL_CONE_OUTER_ANGLE:
564 if ((lValue >= 0) && (lValue <= 360))
565 pSource->flOuterAngle = (float)lValue;
566 else
567 alSetError(AL_INVALID_VALUE);
568 break;
570 case AL_LOOPING:
571 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
572 pSource->bLooping = (ALboolean)lValue;
573 else
574 alSetError(AL_INVALID_VALUE);
575 break;
577 case AL_BUFFER:
578 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
580 if (alIsBuffer(lValue))
582 // Remove all elements in the queue
583 while (pSource->queue != NULL)
585 pALBufferListItem = pSource->queue;
586 pSource->queue = pALBufferListItem->next;
587 // Decrement reference counter for buffer
588 if (pALBufferListItem->buffer)
589 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
590 // Record size of buffer
591 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
592 DataSize += BufferSize;
593 // Increment the number of buffers removed from queue
594 Counter++;
595 // Release memory for buffer list item
596 free(pALBufferListItem);
597 // Decrement the number of buffers in the queue
598 pSource->BuffersInQueue--;
601 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
602 if (lValue != 0)
604 // Source is now in STATIC mode
605 pSource->lSourceType = AL_STATIC;
607 // Add the selected buffer to the queue
608 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
609 pALBufferListItem->buffer = lValue;
610 pALBufferListItem->bufferstate = PENDING;
611 pALBufferListItem->flag = 0;
612 pALBufferListItem->next = NULL;
614 pSource->queue = pALBufferListItem;
615 pSource->BuffersInQueue = 1;
617 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
619 // Increment reference counter for buffer
620 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
622 else
624 // Source is now in UNDETERMINED mode
625 pSource->lSourceType = AL_UNDETERMINED;
628 // Set Buffers Processed
629 pSource->BuffersProcessed = 0;
631 // Update AL_BUFFER parameter
632 pSource->ulBufferID = lValue;
634 else
635 alSetError(AL_INVALID_VALUE);
637 else
638 alSetError(AL_INVALID_OPERATION);
639 break;
641 case AL_SOURCE_STATE:
642 // Query only
643 alSetError(AL_INVALID_OPERATION);
644 break;
646 case AL_SEC_OFFSET:
647 case AL_SAMPLE_OFFSET:
648 case AL_BYTE_OFFSET:
649 if (lValue >= 0)
651 pSource->lOffsetType = eParam;
653 // Store Offset (convert Seconds into Milliseconds)
654 if (eParam == AL_SEC_OFFSET)
655 pSource->lOffset = lValue * 1000;
656 else
657 pSource->lOffset = lValue;
659 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
660 ApplyOffset(pSource, AL_TRUE);
662 else
663 alSetError(AL_INVALID_VALUE);
664 break;
666 case AL_DIRECT_FILTER:
667 if(alIsFilter(lValue))
669 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
670 if(!filter)
672 pSource->DirectFilter.type = AL_FILTER_NULL;
673 pSource->DirectFilter.filter = 0;
675 else
676 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
678 else
679 alSetError(AL_INVALID_VALUE);
680 break;
682 case AL_DIRECT_FILTER_GAINHF_AUTO:
683 if(lValue == AL_TRUE || lValue == AL_FALSE)
684 pSource->DryGainHFAuto = lValue;
685 else
686 alSetError(AL_INVALID_VALUE);
687 break;
689 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
690 if(lValue == AL_TRUE || lValue == AL_FALSE)
691 pSource->WetGainAuto = lValue;
692 else
693 alSetError(AL_INVALID_VALUE);
694 break;
696 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
697 if(lValue == AL_TRUE || lValue == AL_FALSE)
698 pSource->WetGainHFAuto = lValue;
699 else
700 alSetError(AL_INVALID_VALUE);
701 break;
703 default:
704 alSetError(AL_INVALID_ENUM);
705 break;
708 else
709 alSetError(AL_INVALID_NAME);
711 ProcessContext(pContext);
713 else
714 alSetError(AL_INVALID_OPERATION);
716 return;
720 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
722 ALCcontext *pContext;
724 pContext = alcGetCurrentContext();
725 if (pContext)
727 SuspendContext(pContext);
729 if (alIsSource(source))
731 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
733 switch (eParam)
735 case AL_POSITION:
736 case AL_VELOCITY:
737 case AL_DIRECTION:
738 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
739 break;
741 case AL_AUXILIARY_SEND_FILTER:
742 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
743 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
744 alIsFilter(lValue3))
746 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
747 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
749 /* Release refcount on the previous slot, and add one for
750 * the new slot */
751 if(pSource->Send[lValue2].Slot)
752 pSource->Send[lValue2].Slot->refcount--;
753 pSource->Send[lValue2].Slot = ALEffectSlot;
754 if(pSource->Send[lValue2].Slot)
755 pSource->Send[lValue2].Slot->refcount++;
757 if(!ALFilter)
759 /* Disable filter */
760 pSource->Send[lValue2].WetFilter.type = 0;
761 pSource->Send[lValue2].WetFilter.filter = 0;
763 else
764 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
766 else
767 alSetError(AL_INVALID_VALUE);
768 break;
770 default:
771 alSetError(AL_INVALID_ENUM);
772 break;
775 else
776 alSetError(AL_INVALID_NAME);
778 ProcessContext(pContext);
780 else
781 alSetError(AL_INVALID_OPERATION);
783 return;
787 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
789 ALCcontext *pContext;
791 pContext = alcGetCurrentContext();
792 if (pContext)
794 SuspendContext(pContext);
796 if (plValues)
798 if (alIsSource(source))
800 switch (eParam)
802 case AL_SOURCE_RELATIVE:
803 case AL_CONE_INNER_ANGLE:
804 case AL_CONE_OUTER_ANGLE:
805 case AL_LOOPING:
806 case AL_BUFFER:
807 case AL_SOURCE_STATE:
808 case AL_SEC_OFFSET:
809 case AL_SAMPLE_OFFSET:
810 case AL_BYTE_OFFSET:
811 case AL_MAX_DISTANCE:
812 case AL_ROLLOFF_FACTOR:
813 case AL_REFERENCE_DISTANCE:
814 case AL_DIRECT_FILTER:
815 case AL_DIRECT_FILTER_GAINHF_AUTO:
816 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
817 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
818 alSourcei(source, eParam, plValues[0]);
819 break;
821 case AL_POSITION:
822 case AL_VELOCITY:
823 case AL_DIRECTION:
824 case AL_AUXILIARY_SEND_FILTER:
825 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
826 break;
828 default:
829 alSetError(AL_INVALID_ENUM);
830 break;
833 else
834 alSetError(AL_INVALID_NAME);
836 else
837 alSetError(AL_INVALID_VALUE);
839 ProcessContext(pContext);
841 else
842 alSetError(AL_INVALID_OPERATION);
844 return;
848 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
850 ALCcontext *pContext;
851 ALsource *pSource;
852 ALfloat flOffset;
854 pContext = alcGetCurrentContext();
855 if (pContext)
857 SuspendContext(pContext);
859 if (pflValue)
861 if (alIsSource(source))
863 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
865 switch(eParam)
867 case AL_PITCH:
868 *pflValue = pSource->flPitch;
869 break;
871 case AL_GAIN:
872 *pflValue = pSource->flGain;
873 break;
875 case AL_MIN_GAIN:
876 *pflValue = pSource->flMinGain;
877 break;
879 case AL_MAX_GAIN:
880 *pflValue = pSource->flMaxGain;
881 break;
883 case AL_MAX_DISTANCE:
884 *pflValue = pSource->flMaxDistance;
885 break;
887 case AL_ROLLOFF_FACTOR:
888 *pflValue = pSource->flRollOffFactor;
889 break;
891 case AL_CONE_OUTER_GAIN:
892 *pflValue = pSource->flOuterGain;
893 break;
895 case AL_CONE_OUTER_GAINHF:
896 *pflValue = pSource->OuterGainHF;
897 break;
899 case AL_SEC_OFFSET:
900 case AL_SAMPLE_OFFSET:
901 case AL_BYTE_OFFSET:
902 if (GetSourceOffset(pSource, eParam, &flOffset))
903 *pflValue = flOffset;
904 else
905 alSetError(AL_INVALID_OPERATION);
906 break;
908 case AL_CONE_INNER_ANGLE:
909 *pflValue = pSource->flInnerAngle;
910 break;
912 case AL_CONE_OUTER_ANGLE:
913 *pflValue = pSource->flOuterAngle;
914 break;
916 case AL_REFERENCE_DISTANCE:
917 *pflValue = pSource->flRefDistance;
918 break;
920 case AL_AIR_ABSORPTION_FACTOR:
921 *pflValue = pSource->AirAbsorptionFactor;
922 break;
924 case AL_ROOM_ROLLOFF_FACTOR:
925 *pflValue = pSource->RoomRolloffFactor;
926 break;
928 case AL_DOPPLER_FACTOR:
929 *pflValue = pSource->DopplerFactor;
930 break;
932 default:
933 alSetError(AL_INVALID_ENUM);
934 break;
937 else
938 alSetError(AL_INVALID_NAME);
940 else
941 alSetError(AL_INVALID_VALUE);
943 ProcessContext(pContext);
945 else
946 alSetError(AL_INVALID_OPERATION);
948 return;
952 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
954 ALCcontext *pContext;
955 ALsource *pSource;
957 pContext = alcGetCurrentContext();
958 if (pContext)
960 SuspendContext(pContext);
962 if ((pflValue1) && (pflValue2) && (pflValue3))
964 if (alIsSource(source))
966 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
968 switch(eParam)
970 case AL_POSITION:
971 *pflValue1 = pSource->vPosition[0];
972 *pflValue2 = pSource->vPosition[1];
973 *pflValue3 = pSource->vPosition[2];
974 break;
976 case AL_VELOCITY:
977 *pflValue1 = pSource->vVelocity[0];
978 *pflValue2 = pSource->vVelocity[1];
979 *pflValue3 = pSource->vVelocity[2];
980 break;
982 case AL_DIRECTION:
983 *pflValue1 = pSource->vOrientation[0];
984 *pflValue2 = pSource->vOrientation[1];
985 *pflValue3 = pSource->vOrientation[2];
986 break;
988 default:
989 alSetError(AL_INVALID_ENUM);
990 break;
993 else
994 alSetError(AL_INVALID_NAME);
996 else
997 alSetError(AL_INVALID_VALUE);
999 ProcessContext(pContext);
1001 else
1002 alSetError(AL_INVALID_OPERATION);
1004 return;
1008 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1010 ALCcontext *pContext;
1011 ALsource *pSource;
1013 pContext = alcGetCurrentContext();
1014 if (pContext)
1016 SuspendContext(pContext);
1018 if (pflValues)
1020 if (alIsSource(source))
1022 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1024 switch(eParam)
1026 case AL_PITCH:
1027 case AL_GAIN:
1028 case AL_MIN_GAIN:
1029 case AL_MAX_GAIN:
1030 case AL_MAX_DISTANCE:
1031 case AL_ROLLOFF_FACTOR:
1032 case AL_DOPPLER_FACTOR:
1033 case AL_CONE_OUTER_GAIN:
1034 case AL_SEC_OFFSET:
1035 case AL_SAMPLE_OFFSET:
1036 case AL_BYTE_OFFSET:
1037 case AL_CONE_INNER_ANGLE:
1038 case AL_CONE_OUTER_ANGLE:
1039 case AL_REFERENCE_DISTANCE:
1040 case AL_CONE_OUTER_GAINHF:
1041 case AL_AIR_ABSORPTION_FACTOR:
1042 case AL_ROOM_ROLLOFF_FACTOR:
1043 alGetSourcef(source, eParam, pflValues);
1044 break;
1046 case AL_POSITION:
1047 pflValues[0] = pSource->vPosition[0];
1048 pflValues[1] = pSource->vPosition[1];
1049 pflValues[2] = pSource->vPosition[2];
1050 break;
1052 case AL_VELOCITY:
1053 pflValues[0] = pSource->vVelocity[0];
1054 pflValues[1] = pSource->vVelocity[1];
1055 pflValues[2] = pSource->vVelocity[2];
1056 break;
1058 case AL_DIRECTION:
1059 pflValues[0] = pSource->vOrientation[0];
1060 pflValues[1] = pSource->vOrientation[1];
1061 pflValues[2] = pSource->vOrientation[2];
1062 break;
1064 default:
1065 alSetError(AL_INVALID_ENUM);
1066 break;
1069 else
1070 alSetError(AL_INVALID_NAME);
1072 else
1073 alSetError(AL_INVALID_VALUE);
1075 ProcessContext(pContext);
1077 else
1078 alSetError(AL_INVALID_OPERATION);
1080 return;
1084 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1086 ALCcontext *pContext;
1087 ALsource *pSource;
1088 ALfloat flOffset;
1090 pContext = alcGetCurrentContext();
1091 if (pContext)
1093 SuspendContext(pContext);
1095 if (plValue)
1097 if (alIsSource(source))
1099 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1101 switch(eParam)
1103 case AL_MAX_DISTANCE:
1104 *plValue = (ALint)pSource->flMaxDistance;
1105 break;
1107 case AL_ROLLOFF_FACTOR:
1108 *plValue = (ALint)pSource->flRollOffFactor;
1109 break;
1111 case AL_REFERENCE_DISTANCE:
1112 *plValue = (ALint)pSource->flRefDistance;
1113 break;
1115 case AL_SOURCE_RELATIVE:
1116 *plValue = pSource->bHeadRelative;
1117 break;
1119 case AL_CONE_INNER_ANGLE:
1120 *plValue = (ALint)pSource->flInnerAngle;
1121 break;
1123 case AL_CONE_OUTER_ANGLE:
1124 *plValue = (ALint)pSource->flOuterAngle;
1125 break;
1127 case AL_LOOPING:
1128 *plValue = pSource->bLooping;
1129 break;
1131 case AL_BUFFER:
1132 *plValue = pSource->ulBufferID;
1133 break;
1135 case AL_SOURCE_STATE:
1136 *plValue = pSource->state;
1137 break;
1139 case AL_BUFFERS_QUEUED:
1140 *plValue = pSource->BuffersInQueue;
1141 break;
1143 case AL_BUFFERS_PROCESSED:
1144 if(pSource->bLooping)
1146 /* Buffers on a looping source are in a perpetual state
1147 * of PENDING, so don't report any as PROCESSED */
1148 *plValue = 0;
1150 else
1151 *plValue = pSource->BuffersProcessed;
1152 break;
1154 case AL_SOURCE_TYPE:
1155 *plValue = pSource->lSourceType;
1156 break;
1158 case AL_SEC_OFFSET:
1159 case AL_SAMPLE_OFFSET:
1160 case AL_BYTE_OFFSET:
1161 if (GetSourceOffset(pSource, eParam, &flOffset))
1162 *plValue = (ALint)flOffset;
1163 else
1164 alSetError(AL_INVALID_OPERATION);
1165 break;
1167 case AL_DIRECT_FILTER:
1168 *plValue = pSource->DirectFilter.filter;
1169 break;
1171 case AL_DIRECT_FILTER_GAINHF_AUTO:
1172 *plValue = pSource->DryGainHFAuto;
1173 break;
1175 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1176 *plValue = pSource->WetGainAuto;
1177 break;
1179 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1180 *plValue = pSource->WetGainHFAuto;
1181 break;
1183 case AL_DOPPLER_FACTOR:
1184 *plValue = (ALint)pSource->DopplerFactor;
1185 break;
1187 default:
1188 alSetError(AL_INVALID_ENUM);
1189 break;
1192 else
1193 alSetError(AL_INVALID_NAME);
1195 else
1196 alSetError(AL_INVALID_VALUE);
1198 ProcessContext(pContext);
1200 else
1201 alSetError(AL_INVALID_OPERATION);
1203 return;
1207 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1209 ALCcontext *pContext;
1210 ALsource *pSource;
1212 pContext = alcGetCurrentContext();
1213 if (pContext)
1215 SuspendContext(pContext);
1217 if ((plValue1) && (plValue2) && (plValue3))
1219 if (alIsSource(source))
1221 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1223 switch(eParam)
1225 case AL_POSITION:
1226 *plValue1 = (ALint)pSource->vPosition[0];
1227 *plValue2 = (ALint)pSource->vPosition[1];
1228 *plValue3 = (ALint)pSource->vPosition[2];
1229 break;
1231 case AL_VELOCITY:
1232 *plValue1 = (ALint)pSource->vVelocity[0];
1233 *plValue2 = (ALint)pSource->vVelocity[1];
1234 *plValue3 = (ALint)pSource->vVelocity[2];
1235 break;
1237 case AL_DIRECTION:
1238 *plValue1 = (ALint)pSource->vOrientation[0];
1239 *plValue2 = (ALint)pSource->vOrientation[1];
1240 *plValue3 = (ALint)pSource->vOrientation[2];
1241 break;
1243 default:
1244 alSetError(AL_INVALID_ENUM);
1245 break;
1248 else
1249 alSetError(AL_INVALID_NAME);
1251 else
1252 alSetError(AL_INVALID_VALUE);
1254 ProcessContext(pContext);
1256 else
1257 alSetError(AL_INVALID_OPERATION);
1259 return;
1263 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1265 ALCcontext *pContext;
1266 ALsource *pSource;
1268 pContext = alcGetCurrentContext();
1269 if (pContext)
1271 SuspendContext(pContext);
1273 if (plValues)
1275 if (alIsSource(source))
1277 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1279 switch (eParam)
1281 case AL_SOURCE_RELATIVE:
1282 case AL_CONE_INNER_ANGLE:
1283 case AL_CONE_OUTER_ANGLE:
1284 case AL_LOOPING:
1285 case AL_BUFFER:
1286 case AL_SOURCE_STATE:
1287 case AL_BUFFERS_QUEUED:
1288 case AL_BUFFERS_PROCESSED:
1289 case AL_SEC_OFFSET:
1290 case AL_SAMPLE_OFFSET:
1291 case AL_BYTE_OFFSET:
1292 case AL_MAX_DISTANCE:
1293 case AL_ROLLOFF_FACTOR:
1294 case AL_DOPPLER_FACTOR:
1295 case AL_REFERENCE_DISTANCE:
1296 case AL_SOURCE_TYPE:
1297 case AL_DIRECT_FILTER:
1298 case AL_DIRECT_FILTER_GAINHF_AUTO:
1299 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1300 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1301 alGetSourcei(source, eParam, plValues);
1302 break;
1304 case AL_POSITION:
1305 plValues[0] = (ALint)pSource->vPosition[0];
1306 plValues[1] = (ALint)pSource->vPosition[1];
1307 plValues[2] = (ALint)pSource->vPosition[2];
1308 break;
1310 case AL_VELOCITY:
1311 plValues[0] = (ALint)pSource->vVelocity[0];
1312 plValues[1] = (ALint)pSource->vVelocity[1];
1313 plValues[2] = (ALint)pSource->vVelocity[2];
1314 break;
1316 case AL_DIRECTION:
1317 plValues[0] = (ALint)pSource->vOrientation[0];
1318 plValues[1] = (ALint)pSource->vOrientation[1];
1319 plValues[2] = (ALint)pSource->vOrientation[2];
1320 break;
1322 default:
1323 alSetError(AL_INVALID_ENUM);
1324 break;
1327 else
1328 alSetError(AL_INVALID_NAME);
1330 else
1331 alSetError(AL_INVALID_VALUE);
1333 ProcessContext(pContext);
1335 else
1336 alSetError(AL_INVALID_OPERATION);
1338 return;
1342 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1344 alSourcePlayv(1, &source);
1345 return;
1348 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1350 ALCcontext *pContext;
1351 ALsource *pSource;
1352 ALbufferlistitem *ALBufferList;
1353 ALboolean bSourcesValid = AL_TRUE;
1354 ALboolean bPlay;
1355 ALsizei i;
1357 pContext = alcGetCurrentContext();
1358 if (pContext)
1360 SuspendContext(pContext);
1362 if (pSourceList)
1364 // Check that all the Sources are valid
1365 for (i = 0; i < n; i++)
1367 if (!alIsSource(pSourceList[i]))
1369 alSetError(AL_INVALID_NAME);
1370 bSourcesValid = AL_FALSE;
1371 break;
1375 if (bSourcesValid)
1377 for (i = 0; i < n; i++)
1379 // Assume Source won't need to play
1380 bPlay = AL_FALSE;
1382 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1384 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1385 ALBufferList = pSource->queue;
1386 while (ALBufferList)
1388 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1390 bPlay = AL_TRUE;
1391 break;
1393 ALBufferList = ALBufferList->next;
1396 if (bPlay)
1398 if (pSource->state != AL_PAUSED)
1400 pSource->state = AL_PLAYING;
1401 pSource->inuse = AL_TRUE;
1402 pSource->play = AL_TRUE;
1403 pSource->position = 0;
1404 pSource->position_fraction = 0;
1405 pSource->BuffersProcessed = 0;
1406 pSource->BuffersPlayed = 0;
1407 pSource->BufferPosition = 0;
1408 pSource->lBytesPlayed = 0;
1410 pSource->ulBufferID = pSource->queue->buffer;
1412 // Make sure all the Buffers in the queue are marked as PENDING
1413 ALBufferList = pSource->queue;
1414 while (ALBufferList)
1416 ALBufferList->bufferstate = PENDING;
1417 ALBufferList = ALBufferList->next;
1420 else
1422 pSource->state = AL_PLAYING;
1423 pSource->inuse = AL_TRUE;
1424 pSource->play = AL_TRUE;
1427 // Check if an Offset has been set
1428 if (pSource->lOffset)
1429 ApplyOffset(pSource, AL_FALSE);
1431 else
1433 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1434 ALBufferList = pSource->queue;
1435 while (ALBufferList)
1437 ALBufferList->bufferstate = PROCESSED;
1438 ALBufferList = ALBufferList->next;
1441 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1446 else
1448 // sources is a NULL pointer
1449 alSetError(AL_INVALID_VALUE);
1452 ProcessContext(pContext);
1454 else
1456 // Invalid Context
1457 alSetError(AL_INVALID_OPERATION);
1460 return;
1463 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1465 alSourcePausev(1, &source);
1466 return;
1469 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1471 ALCcontext *Context;
1472 ALsource *Source;
1473 ALsizei i;
1474 ALboolean bSourcesValid = AL_TRUE;
1476 Context=alcGetCurrentContext();
1477 if (Context)
1479 SuspendContext(Context);
1481 if (sources)
1483 // Check all the Sources are valid
1484 for (i=0;i<n;i++)
1486 if (!alIsSource(sources[i]))
1488 alSetError(AL_INVALID_NAME);
1489 bSourcesValid = AL_FALSE;
1490 break;
1494 if (bSourcesValid)
1496 for (i=0;i<n;i++)
1498 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1499 if (Source->state==AL_PLAYING)
1501 Source->state=AL_PAUSED;
1502 Source->inuse=AL_FALSE;
1507 else
1509 // sources is a NULL pointer
1510 alSetError(AL_INVALID_VALUE);
1513 ProcessContext(Context);
1515 else
1517 // Invalid Context
1518 alSetError(AL_INVALID_OPERATION);
1521 return;
1524 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1526 alSourceStopv(1, &source);
1527 return;
1530 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1532 ALCcontext *Context;
1533 ALsource *Source;
1534 ALsizei i;
1535 ALbufferlistitem *ALBufferListItem;
1536 ALboolean bSourcesValid = AL_TRUE;
1538 Context=alcGetCurrentContext();
1539 if (Context)
1541 SuspendContext(Context);
1543 if (sources)
1545 // Check all the Sources are valid
1546 for (i=0;i<n;i++)
1548 if (!alIsSource(sources[i]))
1550 alSetError(AL_INVALID_NAME);
1551 bSourcesValid = AL_FALSE;
1552 break;
1556 if (bSourcesValid)
1558 for (i=0;i<n;i++)
1560 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1561 if (Source->state!=AL_INITIAL)
1563 Source->state=AL_STOPPED;
1564 Source->inuse=AL_FALSE;
1565 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1566 ALBufferListItem= Source->queue;
1567 while (ALBufferListItem != NULL)
1569 ALBufferListItem->bufferstate = PROCESSED;
1570 ALBufferListItem = ALBufferListItem->next;
1573 Source->lOffset = 0;
1577 else
1579 // sources is a NULL pointer
1580 alSetError(AL_INVALID_VALUE);
1583 ProcessContext(Context);
1585 else
1587 // Invalid Context
1588 alSetError(AL_INVALID_OPERATION);
1591 return;
1594 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1596 alSourceRewindv(1, &source);
1597 return;
1600 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1602 ALCcontext *Context;
1603 ALsource *Source;
1604 ALsizei i;
1605 ALbufferlistitem *ALBufferListItem;
1606 ALboolean bSourcesValid = AL_TRUE;
1608 Context=alcGetCurrentContext();
1609 if (Context)
1611 SuspendContext(Context);
1613 if (sources)
1615 // Check all the Sources are valid
1616 for (i=0;i<n;i++)
1618 if (!alIsSource(sources[i]))
1620 alSetError(AL_INVALID_NAME);
1621 bSourcesValid = AL_FALSE;
1622 break;
1626 if (bSourcesValid)
1628 for (i=0;i<n;i++)
1630 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1631 if (Source->state!=AL_INITIAL)
1633 Source->state=AL_INITIAL;
1634 Source->inuse=AL_FALSE;
1635 Source->position=0;
1636 Source->position_fraction=0;
1637 Source->BuffersProcessed = 0;
1638 ALBufferListItem= Source->queue;
1639 while (ALBufferListItem != NULL)
1641 ALBufferListItem->bufferstate = PENDING;
1642 ALBufferListItem = ALBufferListItem->next;
1644 if (Source->queue)
1645 Source->ulBufferID = Source->queue->buffer;
1647 Source->lOffset = 0;
1651 else
1653 // sources is a NULL pointer
1654 alSetError(AL_INVALID_VALUE);
1657 ProcessContext(Context);
1659 else
1661 // Invalid Context
1662 alSetError(AL_INVALID_OPERATION);
1665 return;
1669 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1671 ALCcontext *Context;
1672 ALsource *ALSource;
1673 ALsizei i;
1674 ALbufferlistitem *ALBufferList;
1675 ALbufferlistitem *ALBufferListStart;
1676 ALuint DataSize;
1677 ALuint BufferSize;
1678 ALint iFrequency;
1679 ALint iFormat;
1680 ALboolean bBuffersValid = AL_TRUE;
1682 if (n == 0)
1683 return;
1685 Context=alcGetCurrentContext();
1686 if (Context)
1688 SuspendContext(Context);
1690 DataSize = 0;
1691 BufferSize = 0;
1693 // Check that all buffers are valid or zero and that the source is valid
1695 // Check that this is a valid source
1696 if (alIsSource(source))
1698 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1700 // Check that this is not a STATIC Source
1701 if (ALSource->lSourceType != AL_STATIC)
1703 iFrequency = -1;
1704 iFormat = -1;
1706 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1707 ALBufferList = ALSource->queue;
1708 while (ALBufferList)
1710 if (ALBufferList->buffer)
1712 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1713 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1714 break;
1716 ALBufferList = ALBufferList->next;
1719 for (i = 0; i < n; i++)
1721 if (alIsBuffer(buffers[i]))
1723 if (buffers[i])
1725 if ((iFrequency == -1) && (iFormat == -1))
1727 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1728 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1730 else
1732 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1733 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1735 alSetError(AL_INVALID_OPERATION);
1736 bBuffersValid = AL_FALSE;
1737 break;
1742 else
1744 alSetError(AL_INVALID_NAME);
1745 bBuffersValid = AL_FALSE;
1746 break;
1750 if (bBuffersValid)
1752 // Change Source Type
1753 ALSource->lSourceType = AL_STREAMING;
1755 // All buffers are valid - so add them to the list
1756 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1757 ALBufferListStart->buffer = buffers[0];
1758 ALBufferListStart->bufferstate = PENDING;
1759 ALBufferListStart->flag = 0;
1760 ALBufferListStart->next = NULL;
1762 if (buffers[0])
1763 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1764 else
1765 BufferSize = 0;
1767 DataSize += BufferSize;
1769 // Increment reference counter for buffer
1770 if (buffers[0])
1771 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1773 ALBufferList = ALBufferListStart;
1775 for (i = 1; i < n; i++)
1777 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1778 ALBufferList->next->buffer = buffers[i];
1779 ALBufferList->next->bufferstate = PENDING;
1780 ALBufferList->next->flag = 0;
1781 ALBufferList->next->next = NULL;
1783 if (buffers[i])
1784 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1785 else
1786 BufferSize = 0;
1788 DataSize += BufferSize;
1790 // Increment reference counter for buffer
1791 if (buffers[i])
1792 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1794 ALBufferList = ALBufferList->next;
1797 if (ALSource->queue == NULL)
1799 ALSource->queue = ALBufferListStart;
1800 // Update Current Buffer
1801 ALSource->ulBufferID = ALBufferListStart->buffer;
1803 else
1805 // Find end of queue
1806 ALBufferList = ALSource->queue;
1807 while (ALBufferList->next != NULL)
1809 ALBufferList = ALBufferList->next;
1812 ALBufferList->next = ALBufferListStart;
1815 // Update number of buffers in queue
1816 ALSource->BuffersInQueue += n;
1819 else
1821 // Invalid Source Type (can't queue on a Static Source)
1822 alSetError(AL_INVALID_OPERATION);
1825 else
1827 // Invalid Source Name
1828 alSetError(AL_INVALID_NAME);
1831 ProcessContext(Context);
1833 else
1835 // Invalid Context
1836 alSetError(AL_INVALID_OPERATION);
1839 return;
1843 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1844 // an array of buffer IDs that are to be filled with the names of the buffers removed
1845 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1847 ALCcontext *Context;
1848 ALsource *ALSource;
1849 ALsizei i;
1850 ALbufferlistitem *ALBufferList;
1851 ALuint DataSize;
1852 ALuint BufferSize;
1853 ALuint BufferID;
1854 ALboolean bBuffersProcessed;
1856 if (n == 0)
1857 return;
1859 DataSize = 0;
1860 BufferSize = 0;
1861 bBuffersProcessed = AL_TRUE;
1863 Context=alcGetCurrentContext();
1864 if (Context)
1866 SuspendContext(Context);
1868 if (alIsSource(source))
1870 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1872 // Check that all 'n' buffers have been processed
1873 ALBufferList = ALSource->queue;
1874 for (i = 0; i < n; i++)
1876 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1878 ALBufferList = ALBufferList->next;
1880 else
1882 bBuffersProcessed = AL_FALSE;
1883 break;
1887 // If all 'n' buffers have been processed, remove them from the queue
1888 if (bBuffersProcessed)
1890 for (i = 0; i < n; i++)
1892 ALBufferList = ALSource->queue;
1894 ALSource->queue = ALBufferList->next;
1895 // Record name of buffer
1896 buffers[i] = ALBufferList->buffer;
1897 // Decrement buffer reference counter
1898 if (ALBufferList->buffer)
1899 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1900 // Record size of buffer
1901 if (ALBufferList->buffer)
1902 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1903 else
1904 BufferSize = 0;
1906 DataSize += BufferSize;
1907 // Release memory for buffer list item
1908 free(ALBufferList);
1909 ALSource->BuffersInQueue--;
1910 ALSource->BuffersProcessed--;
1913 if (ALSource->state != AL_PLAYING)
1915 if (ALSource->queue)
1916 BufferID = ALSource->queue->buffer;
1917 else
1918 BufferID = 0;
1920 ALSource->ulBufferID = BufferID;
1923 if((ALuint)n > ALSource->BuffersPlayed)
1925 ALSource->BuffersPlayed = 0;
1926 ALSource->BufferPosition = 0;
1928 else
1929 ALSource->BuffersPlayed -= n;
1931 else
1933 // Some buffers can't be unqueue because they have not been processed
1934 alSetError(AL_INVALID_VALUE);
1937 else
1939 // Invalid Source Name
1940 alSetError(AL_INVALID_NAME);
1943 ProcessContext(Context);
1945 else
1947 // Invalid Context
1948 alSetError(AL_INVALID_OPERATION);
1951 return;
1955 static ALvoid InitSourceParams(ALsource *pSource)
1957 pSource->flInnerAngle = 360.0f;
1958 pSource->flOuterAngle = 360.0f;
1959 pSource->flPitch = 1.0f;
1960 pSource->vPosition[0] = 0.0f;
1961 pSource->vPosition[1] = 0.0f;
1962 pSource->vPosition[2] = 0.0f;
1963 pSource->vOrientation[0] = 0.0f;
1964 pSource->vOrientation[1] = 0.0f;
1965 pSource->vOrientation[2] = 0.0f;
1966 pSource->vVelocity[0] = 0.0f;
1967 pSource->vVelocity[1] = 0.0f;
1968 pSource->vVelocity[2] = 0.0f;
1969 pSource->flRefDistance = 1.0f;
1970 pSource->flMaxDistance = FLT_MAX;
1971 pSource->flRollOffFactor = 1.0f;
1972 pSource->bLooping = AL_FALSE;
1973 pSource->flGain = 1.0f;
1974 pSource->flMinGain = 0.0f;
1975 pSource->flMaxGain = 1.0f;
1976 pSource->flOuterGain = 0.0f;
1977 pSource->OuterGainHF = 1.0f;
1979 pSource->DryGainHFAuto = AL_TRUE;
1980 pSource->WetGainAuto = AL_TRUE;
1981 pSource->WetGainHFAuto = AL_TRUE;
1982 pSource->AirAbsorptionFactor = 0.0f;
1983 pSource->RoomRolloffFactor = 0.0f;
1984 pSource->DopplerFactor = 1.0f;
1986 pSource->state = AL_INITIAL;
1987 pSource->lSourceType = AL_UNDETERMINED;
1989 pSource->ulBufferID= 0;
1994 GetSourceOffset
1996 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1997 The offset is relative to the start of the queue (not the start of the current buffer)
1999 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2001 ALbufferlistitem *pBufferList;
2002 ALbuffer *pBuffer;
2003 ALfloat flBufferFreq;
2004 ALint lBytesPlayed, lChannels;
2005 ALenum eOriginalFormat;
2006 ALboolean bReturn = AL_TRUE;
2007 ALint lTotalBufferDataSize;
2009 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2011 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2012 // Get Current Buffer Size and frequency (in milliseconds)
2013 flBufferFreq = (ALfloat)pBuffer->frequency;
2014 eOriginalFormat = pBuffer->eOriginalFormat;
2015 lChannels = aluChannelsFromFormat(pBuffer->format);
2017 // Get Current BytesPlayed
2018 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2019 // Add byte length of any processed buffers in the queue
2020 pBufferList = pSource->queue;
2021 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2023 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2024 pBufferList = pBufferList->next;
2027 lTotalBufferDataSize = 0;
2028 pBufferList = pSource->queue;
2029 while (pBufferList)
2031 if (pBufferList->buffer)
2032 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2033 pBufferList = pBufferList->next;
2036 if (pSource->bLooping)
2038 if (lBytesPlayed < 0)
2039 lBytesPlayed = 0;
2040 else
2041 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2043 else
2045 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2046 if(lBytesPlayed < 0)
2047 lBytesPlayed = 0;
2048 if(lBytesPlayed > lTotalBufferDataSize)
2049 lBytesPlayed = lTotalBufferDataSize;
2052 switch (eName)
2054 case AL_SEC_OFFSET:
2055 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2056 break;
2057 case AL_SAMPLE_OFFSET:
2058 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2059 break;
2060 case AL_BYTE_OFFSET:
2061 // Take into account the original format of the Buffer
2062 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2063 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2065 // Compression rate of the ADPCM supported is 3.6111 to 1
2066 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2067 // Round down to nearest ADPCM block
2068 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2070 else if (eOriginalFormat == AL_FORMAT_REAR8)
2072 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2074 else if (eOriginalFormat == AL_FORMAT_REAR16)
2076 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2078 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2080 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2082 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2084 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2086 else
2088 *pflOffset = (ALfloat)lBytesPlayed;
2090 break;
2093 else
2095 *pflOffset = 0.0f;
2098 return bReturn;
2103 ApplyOffset
2105 Apply a playback offset to the Source. This function will update the queue (to correctly
2106 mark buffers as 'pending' or 'processed' depending upon the new offset.
2108 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2110 ALbufferlistitem *pBufferList;
2111 ALbuffer *pBuffer;
2112 ALint lBufferSize, lTotalBufferSize;
2113 ALint lByteOffset;
2115 // Get true byte offset
2116 lByteOffset = GetByteOffset(pSource);
2118 // If this is a valid offset apply it
2119 if (lByteOffset != -1)
2121 // Sort out the queue (pending and processed states)
2122 pBufferList = pSource->queue;
2123 lTotalBufferSize = 0;
2124 pSource->BuffersPlayed = 0;
2125 pSource->BuffersProcessed = 0;
2126 while (pBufferList)
2128 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2129 lBufferSize = pBuffer ? pBuffer->size : 0;
2131 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2133 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2134 // update the state to PROCESSED
2135 pSource->BuffersPlayed++;
2137 if (!pSource->bLooping)
2139 pBufferList->bufferstate = PROCESSED;
2140 pSource->BuffersProcessed++;
2143 else if (lTotalBufferSize <= lByteOffset)
2145 // Offset is within this buffer
2146 pBufferList->bufferstate = PENDING;
2148 // Set Current Buffer ID
2149 pSource->ulBufferID = pBufferList->buffer;
2151 // Set current position in this buffer
2152 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2154 // Set Total Bytes Played to Offset
2155 pSource->lBytesPlayed = lByteOffset;
2157 // SW Mixer Positions are in Samples
2158 pSource->position = pSource->BufferPosition /
2159 aluBytesFromFormat(pBuffer->format) /
2160 aluChannelsFromFormat(pBuffer->format);
2162 else
2164 // Offset is before this buffer, so mark as pending
2165 pBufferList->bufferstate = PENDING;
2168 // Increment the TotalBufferSize
2169 lTotalBufferSize += lBufferSize;
2171 // Move on to next buffer in the Queue
2172 pBufferList = pBufferList->next;
2175 else
2177 if (bUpdateContext)
2178 alSetError(AL_INVALID_VALUE);
2181 // Clear Offset
2182 pSource->lOffset = 0;
2187 GetByteOffset
2189 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2190 offset supplied by the application). This takes into account the fact that the buffer format
2191 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2193 static ALint GetByteOffset(ALsource *pSource)
2195 ALbuffer *pBuffer = NULL;
2196 ALbufferlistitem *pBufferList;
2197 ALfloat flBufferFreq;
2198 ALint lChannels;
2199 ALint lByteOffset = -1;
2200 ALint lTotalBufferDataSize;
2202 // Find the first non-NULL Buffer in the Queue
2203 pBufferList = pSource->queue;
2204 while (pBufferList)
2206 if (pBufferList->buffer)
2208 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2209 break;
2211 pBufferList = pBufferList->next;
2214 if (pBuffer)
2216 flBufferFreq = ((ALfloat)pBuffer->frequency);
2217 lChannels = aluChannelsFromFormat(pBuffer->format);
2219 // Determine the ByteOffset (and ensure it is block aligned)
2220 switch (pSource->lOffsetType)
2222 case AL_BYTE_OFFSET:
2223 // Take into consideration the original format
2224 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2225 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2227 // Round down to nearest ADPCM block
2228 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2229 // Multiply by compression rate
2230 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2231 lByteOffset -= (lByteOffset % (lChannels * 2));
2233 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2235 lByteOffset = pSource->lOffset * 4;
2236 lByteOffset -= (lByteOffset % (lChannels * 2));
2238 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2240 lByteOffset = pSource->lOffset * 2;
2241 lByteOffset -= (lByteOffset % (lChannels * 2));
2243 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2245 lByteOffset = pSource->lOffset * 2;
2246 lByteOffset -= (lByteOffset % (lChannels * 2));
2248 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2250 lByteOffset = pSource->lOffset / 2;
2251 lByteOffset -= (lByteOffset % (lChannels * 2));
2253 else
2255 lByteOffset = pSource->lOffset;
2256 lByteOffset -= (lByteOffset % (lChannels * 2));
2258 break;
2260 case AL_SAMPLE_OFFSET:
2261 lByteOffset = pSource->lOffset * lChannels * 2;
2262 break;
2264 case AL_SEC_OFFSET:
2265 // Note - lOffset is internally stored as Milliseconds
2266 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2267 lByteOffset -= (lByteOffset % (lChannels * 2));
2268 break;
2271 lTotalBufferDataSize = 0;
2272 pBufferList = pSource->queue;
2273 while (pBufferList)
2275 if (pBufferList->buffer)
2276 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2277 pBufferList = pBufferList->next;
2280 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2281 if (lByteOffset >= lTotalBufferDataSize)
2282 lByteOffset = -1;
2285 return lByteOffset;
2289 ALvoid ReleaseALSources(ALCcontext *Context)
2291 #ifdef _DEBUG
2292 if(Context->SourceCount > 0)
2293 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2294 #endif
2296 while(Context->Source)
2298 ALsource *temp = Context->Source;
2299 Context->Source = Context->Source->next;
2301 // Release source structure
2302 ALTHUNK_REMOVEENTRY(temp->source);
2303 memset(temp, 0, sizeof(ALsource));
2304 free(temp);
2306 Context->SourceCount = 0;