Use a 12dB/oct rolloff instead of 24 for the lowpass filter
[openal-soft.git] / OpenAL32 / alSource.c
blobfa07751f29918dc73a6c22b9a373eff9cc5e8c3b
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 InitLowPassFilter(Context, &(*list)->iirFilter);
80 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
81 (*list)->source = sources[i];
83 InitSourceParams(*list);
84 Context->SourceCount++;
85 i++;
87 list = &(*list)->next;
90 else
92 // Not enough resources to create the Sources
93 alSetError(AL_INVALID_VALUE);
96 else
98 // Bad pointer
99 alSetError(AL_INVALID_VALUE);
102 else
104 // No Device created, or attached to Context
105 alSetError(AL_INVALID_OPERATION);
109 ProcessContext(Context);
111 else
113 // Invalid Context
114 alSetError(AL_INVALID_OPERATION);
117 return;
121 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
123 ALCcontext *Context;
124 ALCdevice *Device;
125 ALsource *ALSource;
126 ALsource **list;
127 ALsizei i, j;
128 ALbufferlistitem *ALBufferList;
129 ALboolean bSourcesValid = AL_TRUE;
131 Context = alcGetCurrentContext();
132 if (Context)
134 SuspendContext(Context);
136 if (n >= 0)
138 Device = alcGetContextsDevice(Context);
140 if (Device)
142 // Check that all Sources are valid (and can therefore be deleted)
143 for (i = 0; i < n; i++)
145 if (!alIsSource(sources[i]))
147 alSetError(AL_INVALID_NAME);
148 bSourcesValid = AL_FALSE;
149 break;
153 if (bSourcesValid)
155 // All Sources are valid, and can be deleted
156 for (i = 0; i < n; i++)
158 // Recheck that the Source is valid, because there could be duplicated Source names
159 if (alIsSource(sources[i]))
161 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
162 alSourceStop((ALuint)ALSource->source);
164 // For each buffer in the source's queue, decrement its reference counter and remove it
165 while (ALSource->queue != NULL)
167 ALBufferList = ALSource->queue;
168 // Decrement buffer's reference counter
169 if (ALBufferList->buffer != 0)
170 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
171 // Update queue to point to next element in list
172 ALSource->queue = ALBufferList->next;
173 // Release memory allocated for buffer list item
174 free(ALBufferList);
177 for(j = 0;j < MAX_SENDS;++j)
179 if(ALSource->Send[j].Slot)
180 ALSource->Send[j].Slot->refcount--;
181 ALSource->Send[j].Slot = NULL;
184 // Decrement Source count
185 Context->SourceCount--;
187 // Remove Source from list of Sources
188 list = &Context->Source;
189 while(*list && *list != ALSource)
190 list = &(*list)->next;
192 if(*list)
193 *list = (*list)->next;
194 ALTHUNK_REMOVEENTRY(ALSource->source);
196 memset(ALSource,0,sizeof(ALsource));
197 free(ALSource);
202 else
204 // No Device created, or attached to Context
205 alSetError(AL_INVALID_OPERATION);
208 else
209 alSetError(AL_INVALID_VALUE);
211 ProcessContext(Context);
213 else
215 // Invalid Context
216 alSetError(AL_INVALID_OPERATION);
219 return;
223 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
225 ALboolean result=AL_FALSE;
226 ALCcontext *Context;
227 ALsource *Source;
229 Context=alcGetCurrentContext();
230 if (Context)
232 SuspendContext(Context);
234 // To determine if this is a valid Source name, look through the list of generated Sources
235 Source = Context->Source;
236 while(Source)
238 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
240 result = AL_TRUE;
241 break;
244 Source = Source->next;
247 ProcessContext(Context);
249 else
251 // Invalid Context
252 alSetError(AL_INVALID_OPERATION);
255 return result;
259 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
261 ALCcontext *pContext;
262 ALsource *pSource;
264 pContext = alcGetCurrentContext();
265 if (pContext)
267 SuspendContext(pContext);
269 if (alIsSource(source))
271 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
273 switch (eParam)
275 case AL_PITCH:
276 if (flValue >= 0.0f)
278 pSource->flPitch = flValue;
279 if(pSource->flPitch < 0.001f)
280 pSource->flPitch = 0.001f;
282 else
283 alSetError(AL_INVALID_VALUE);
284 break;
286 case AL_CONE_INNER_ANGLE:
287 if ((flValue >= 0.0f) && (flValue <= 360.0f))
288 pSource->flInnerAngle = flValue;
289 else
290 alSetError(AL_INVALID_VALUE);
291 break;
293 case AL_CONE_OUTER_ANGLE:
294 if ((flValue >= 0.0f) && (flValue <= 360.0f))
295 pSource->flOuterAngle = flValue;
296 else
297 alSetError(AL_INVALID_VALUE);
298 break;
300 case AL_GAIN:
301 if (flValue >= 0.0f)
302 pSource->flGain = flValue;
303 else
304 alSetError(AL_INVALID_VALUE);
305 break;
307 case AL_MAX_DISTANCE:
308 if (flValue >= 0.0f)
309 pSource->flMaxDistance = flValue;
310 else
311 alSetError(AL_INVALID_VALUE);
312 break;
314 case AL_ROLLOFF_FACTOR:
315 if (flValue >= 0.0f)
316 pSource->flRollOffFactor = flValue;
317 else
318 alSetError(AL_INVALID_VALUE);
319 break;
321 case AL_REFERENCE_DISTANCE:
322 if (flValue >= 0.0f)
323 pSource->flRefDistance = flValue;
324 else
325 alSetError(AL_INVALID_VALUE);
326 break;
328 case AL_MIN_GAIN:
329 if ((flValue >= 0.0f) && (flValue <= 1.0f))
330 pSource->flMinGain = flValue;
331 else
332 alSetError(AL_INVALID_VALUE);
333 break;
335 case AL_MAX_GAIN:
336 if ((flValue >= 0.0f) && (flValue <= 1.0f))
337 pSource->flMaxGain = flValue;
338 else
339 alSetError(AL_INVALID_VALUE);
340 break;
342 case AL_CONE_OUTER_GAIN:
343 if ((flValue >= 0.0f) && (flValue <= 1.0f))
344 pSource->flOuterGain = flValue;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 case AL_CONE_OUTER_GAINHF:
350 if ((flValue >= 0.0f) && (flValue <= 1.0f))
351 pSource->OuterGainHF = flValue;
352 else
353 alSetError(AL_INVALID_VALUE);
354 break;
356 case AL_AIR_ABSORPTION_FACTOR:
357 if (flValue >= 0.0f && flValue <= 10.0f)
358 pSource->AirAbsorptionFactor = flValue;
359 else
360 alSetError(AL_INVALID_VALUE);
361 break;
363 case AL_ROOM_ROLLOFF_FACTOR:
364 if (flValue >= 0.0f && flValue <= 1.0f)
365 pSource->RoomRolloffFactor = flValue;
366 else
367 alSetError(AL_INVALID_VALUE);
368 break;
370 case AL_DOPPLER_FACTOR:
371 if (flValue >= 0.0f && flValue <= 1.0f)
372 pSource->DopplerFactor = flValue;
373 else
374 alSetError(AL_INVALID_VALUE);
375 break;
377 case AL_SEC_OFFSET:
378 case AL_SAMPLE_OFFSET:
379 case AL_BYTE_OFFSET:
380 if (flValue >= 0.0f)
382 pSource->lOffsetType = eParam;
384 // Store Offset (convert Seconds into Milliseconds)
385 if (eParam == AL_SEC_OFFSET)
386 pSource->lOffset = (ALint)(flValue * 1000.0f);
387 else
388 pSource->lOffset = (ALint)flValue;
390 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
391 ApplyOffset(pSource, AL_TRUE);
393 else
394 alSetError(AL_INVALID_VALUE);
395 break;
397 default:
398 alSetError(AL_INVALID_ENUM);
399 break;
402 else
404 // Invalid Source Name
405 alSetError(AL_INVALID_NAME);
408 ProcessContext(pContext);
410 else
412 // Invalid context
413 alSetError(AL_INVALID_OPERATION);
416 return;
420 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
422 ALCcontext *pContext;
423 ALsource *pSource;
425 pContext = alcGetCurrentContext();
426 if (pContext)
428 SuspendContext(pContext);
430 if (alIsSource(source))
432 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
433 switch(eParam)
435 case AL_POSITION:
436 pSource->vPosition[0] = flValue1;
437 pSource->vPosition[1] = flValue2;
438 pSource->vPosition[2] = flValue3;
439 break;
441 case AL_VELOCITY:
442 pSource->vVelocity[0] = flValue1;
443 pSource->vVelocity[1] = flValue2;
444 pSource->vVelocity[2] = flValue3;
445 break;
447 case AL_DIRECTION:
448 pSource->vOrientation[0] = flValue1;
449 pSource->vOrientation[1] = flValue2;
450 pSource->vOrientation[2] = flValue3;
451 break;
453 default:
454 alSetError(AL_INVALID_ENUM);
455 break;
458 else
459 alSetError(AL_INVALID_NAME);
461 ProcessContext(pContext);
463 else
465 alSetError(AL_INVALID_OPERATION);
468 return;
472 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
474 ALCcontext *pContext;
476 pContext = alcGetCurrentContext();
477 if (pContext)
479 SuspendContext(pContext);
481 if (pflValues)
483 if (alIsSource(source))
485 switch (eParam)
487 case AL_PITCH:
488 case AL_CONE_INNER_ANGLE:
489 case AL_CONE_OUTER_ANGLE:
490 case AL_GAIN:
491 case AL_MAX_DISTANCE:
492 case AL_ROLLOFF_FACTOR:
493 case AL_REFERENCE_DISTANCE:
494 case AL_MIN_GAIN:
495 case AL_MAX_GAIN:
496 case AL_CONE_OUTER_GAIN:
497 case AL_CONE_OUTER_GAINHF:
498 case AL_SEC_OFFSET:
499 case AL_SAMPLE_OFFSET:
500 case AL_BYTE_OFFSET:
501 case AL_AIR_ABSORPTION_FACTOR:
502 case AL_ROOM_ROLLOFF_FACTOR:
503 alSourcef(source, eParam, pflValues[0]);
504 break;
506 case AL_POSITION:
507 case AL_VELOCITY:
508 case AL_DIRECTION:
509 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
510 break;
512 default:
513 alSetError(AL_INVALID_ENUM);
514 break;
517 else
518 alSetError(AL_INVALID_NAME);
520 else
521 alSetError(AL_INVALID_VALUE);
523 ProcessContext(pContext);
525 else
526 alSetError(AL_INVALID_OPERATION);
528 return;
532 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
534 ALCcontext *pContext;
535 ALsource *pSource;
536 ALbufferlistitem *pALBufferListItem;
537 ALint Counter = 0;
538 ALint DataSize = 0;
539 ALint BufferSize;
541 pContext = alcGetCurrentContext();
542 if (pContext)
544 SuspendContext(pContext);
546 if (alIsSource(source))
548 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
550 switch(eParam)
552 case AL_MAX_DISTANCE:
553 case AL_ROLLOFF_FACTOR:
554 case AL_REFERENCE_DISTANCE:
555 alSourcef(source, eParam, (ALfloat)lValue);
556 break;
558 case AL_SOURCE_RELATIVE:
559 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
560 pSource->bHeadRelative = (ALboolean)lValue;
561 else
562 alSetError(AL_INVALID_VALUE);
563 break;
565 case AL_CONE_INNER_ANGLE:
566 if ((lValue >= 0) && (lValue <= 360))
567 pSource->flInnerAngle = (float)lValue;
568 else
569 alSetError(AL_INVALID_VALUE);
570 break;
572 case AL_CONE_OUTER_ANGLE:
573 if ((lValue >= 0) && (lValue <= 360))
574 pSource->flOuterAngle = (float)lValue;
575 else
576 alSetError(AL_INVALID_VALUE);
577 break;
579 case AL_LOOPING:
580 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
581 pSource->bLooping = (ALboolean)lValue;
582 else
583 alSetError(AL_INVALID_VALUE);
584 break;
586 case AL_BUFFER:
587 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
589 if (alIsBuffer(lValue))
591 // Remove all elements in the queue
592 while (pSource->queue != NULL)
594 pALBufferListItem = pSource->queue;
595 pSource->queue = pALBufferListItem->next;
596 // Decrement reference counter for buffer
597 if (pALBufferListItem->buffer)
598 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
599 // Record size of buffer
600 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
601 DataSize += BufferSize;
602 // Increment the number of buffers removed from queue
603 Counter++;
604 // Release memory for buffer list item
605 free(pALBufferListItem);
606 // Decrement the number of buffers in the queue
607 pSource->BuffersInQueue--;
610 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
611 if (lValue != 0)
613 // Source is now in STATIC mode
614 pSource->lSourceType = AL_STATIC;
616 // Add the selected buffer to the queue
617 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
618 pALBufferListItem->buffer = lValue;
619 pALBufferListItem->bufferstate = PENDING;
620 pALBufferListItem->flag = 0;
621 pALBufferListItem->next = NULL;
623 pSource->queue = pALBufferListItem;
624 pSource->BuffersInQueue = 1;
626 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
628 // Increment reference counter for buffer
629 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
631 else
633 // Source is now in UNDETERMINED mode
634 pSource->lSourceType = AL_UNDETERMINED;
637 // Update AL_BUFFER parameter
638 pSource->ulBufferID = lValue;
640 else
641 alSetError(AL_INVALID_VALUE);
643 else
644 alSetError(AL_INVALID_OPERATION);
645 break;
647 case AL_SOURCE_STATE:
648 // Query only
649 alSetError(AL_INVALID_OPERATION);
650 break;
652 case AL_SEC_OFFSET:
653 case AL_SAMPLE_OFFSET:
654 case AL_BYTE_OFFSET:
655 if (lValue >= 0)
657 pSource->lOffsetType = eParam;
659 // Store Offset (convert Seconds into Milliseconds)
660 if (eParam == AL_SEC_OFFSET)
661 pSource->lOffset = lValue * 1000;
662 else
663 pSource->lOffset = lValue;
665 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
666 ApplyOffset(pSource, AL_TRUE);
668 else
669 alSetError(AL_INVALID_VALUE);
670 break;
672 case AL_DIRECT_FILTER:
673 if(alIsFilter(lValue))
675 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
676 if(!filter)
678 pSource->DirectFilter.type = AL_FILTER_NULL;
679 pSource->DirectFilter.filter = 0;
681 else
682 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
684 else
685 alSetError(AL_INVALID_VALUE);
686 break;
688 case AL_DIRECT_FILTER_GAINHF_AUTO:
689 if(lValue == AL_TRUE || lValue == AL_FALSE)
690 pSource->DryGainHFAuto = lValue;
691 else
692 alSetError(AL_INVALID_VALUE);
693 break;
695 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
696 if(lValue == AL_TRUE || lValue == AL_FALSE)
697 pSource->WetGainAuto = lValue;
698 else
699 alSetError(AL_INVALID_VALUE);
700 break;
702 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
703 if(lValue == AL_TRUE || lValue == AL_FALSE)
704 pSource->WetGainHFAuto = lValue;
705 else
706 alSetError(AL_INVALID_VALUE);
707 break;
709 default:
710 alSetError(AL_INVALID_ENUM);
711 break;
714 else
715 alSetError(AL_INVALID_NAME);
717 ProcessContext(pContext);
719 else
720 alSetError(AL_INVALID_OPERATION);
722 return;
726 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
728 ALCcontext *pContext;
730 pContext = alcGetCurrentContext();
731 if (pContext)
733 SuspendContext(pContext);
735 if (alIsSource(source))
737 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
739 switch (eParam)
741 case AL_POSITION:
742 case AL_VELOCITY:
743 case AL_DIRECTION:
744 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
745 break;
747 case AL_AUXILIARY_SEND_FILTER:
748 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
749 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
750 alIsFilter(lValue3))
752 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
753 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
755 /* Release refcount on the previous slot, and add one for
756 * the new slot */
757 if(pSource->Send[lValue2].Slot)
758 pSource->Send[lValue2].Slot->refcount--;
759 pSource->Send[lValue2].Slot = ALEffectSlot;
760 if(pSource->Send[lValue2].Slot)
761 pSource->Send[lValue2].Slot->refcount++;
763 if(!ALFilter)
765 /* Disable filter */
766 pSource->Send[lValue2].WetFilter.type = 0;
767 pSource->Send[lValue2].WetFilter.filter = 0;
769 else
770 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
772 else
773 alSetError(AL_INVALID_VALUE);
774 break;
776 default:
777 alSetError(AL_INVALID_ENUM);
778 break;
781 else
782 alSetError(AL_INVALID_NAME);
784 ProcessContext(pContext);
786 else
787 alSetError(AL_INVALID_OPERATION);
789 return;
793 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
795 ALCcontext *pContext;
797 pContext = alcGetCurrentContext();
798 if (pContext)
800 SuspendContext(pContext);
802 if (plValues)
804 if (alIsSource(source))
806 switch (eParam)
808 case AL_SOURCE_RELATIVE:
809 case AL_CONE_INNER_ANGLE:
810 case AL_CONE_OUTER_ANGLE:
811 case AL_LOOPING:
812 case AL_BUFFER:
813 case AL_SOURCE_STATE:
814 case AL_SEC_OFFSET:
815 case AL_SAMPLE_OFFSET:
816 case AL_BYTE_OFFSET:
817 case AL_MAX_DISTANCE:
818 case AL_ROLLOFF_FACTOR:
819 case AL_REFERENCE_DISTANCE:
820 case AL_DIRECT_FILTER:
821 case AL_DIRECT_FILTER_GAINHF_AUTO:
822 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
823 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
824 alSourcei(source, eParam, plValues[0]);
825 break;
827 case AL_POSITION:
828 case AL_VELOCITY:
829 case AL_DIRECTION:
830 case AL_AUXILIARY_SEND_FILTER:
831 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
832 break;
834 default:
835 alSetError(AL_INVALID_ENUM);
836 break;
839 else
840 alSetError(AL_INVALID_NAME);
842 else
843 alSetError(AL_INVALID_VALUE);
845 ProcessContext(pContext);
847 else
848 alSetError(AL_INVALID_OPERATION);
850 return;
854 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
856 ALCcontext *pContext;
857 ALsource *pSource;
858 ALfloat flOffset;
860 pContext = alcGetCurrentContext();
861 if (pContext)
863 SuspendContext(pContext);
865 if (pflValue)
867 if (alIsSource(source))
869 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
871 switch(eParam)
873 case AL_PITCH:
874 *pflValue = pSource->flPitch;
875 break;
877 case AL_GAIN:
878 *pflValue = pSource->flGain;
879 break;
881 case AL_MIN_GAIN:
882 *pflValue = pSource->flMinGain;
883 break;
885 case AL_MAX_GAIN:
886 *pflValue = pSource->flMaxGain;
887 break;
889 case AL_MAX_DISTANCE:
890 *pflValue = pSource->flMaxDistance;
891 break;
893 case AL_ROLLOFF_FACTOR:
894 *pflValue = pSource->flRollOffFactor;
895 break;
897 case AL_CONE_OUTER_GAIN:
898 *pflValue = pSource->flOuterGain;
899 break;
901 case AL_CONE_OUTER_GAINHF:
902 *pflValue = pSource->OuterGainHF;
903 break;
905 case AL_SEC_OFFSET:
906 case AL_SAMPLE_OFFSET:
907 case AL_BYTE_OFFSET:
908 if (GetSourceOffset(pSource, eParam, &flOffset))
909 *pflValue = flOffset;
910 else
911 alSetError(AL_INVALID_OPERATION);
912 break;
914 case AL_CONE_INNER_ANGLE:
915 *pflValue = pSource->flInnerAngle;
916 break;
918 case AL_CONE_OUTER_ANGLE:
919 *pflValue = pSource->flOuterAngle;
920 break;
922 case AL_REFERENCE_DISTANCE:
923 *pflValue = pSource->flRefDistance;
924 break;
926 case AL_AIR_ABSORPTION_FACTOR:
927 *pflValue = pSource->AirAbsorptionFactor;
928 break;
930 case AL_ROOM_ROLLOFF_FACTOR:
931 *pflValue = pSource->RoomRolloffFactor;
932 break;
934 case AL_DOPPLER_FACTOR:
935 *pflValue = pSource->DopplerFactor;
936 break;
938 default:
939 alSetError(AL_INVALID_ENUM);
940 break;
943 else
944 alSetError(AL_INVALID_NAME);
946 else
947 alSetError(AL_INVALID_VALUE);
949 ProcessContext(pContext);
951 else
952 alSetError(AL_INVALID_OPERATION);
954 return;
958 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
960 ALCcontext *pContext;
961 ALsource *pSource;
963 pContext = alcGetCurrentContext();
964 if (pContext)
966 SuspendContext(pContext);
968 if ((pflValue1) && (pflValue2) && (pflValue3))
970 if (alIsSource(source))
972 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
974 switch(eParam)
976 case AL_POSITION:
977 *pflValue1 = pSource->vPosition[0];
978 *pflValue2 = pSource->vPosition[1];
979 *pflValue3 = pSource->vPosition[2];
980 break;
982 case AL_VELOCITY:
983 *pflValue1 = pSource->vVelocity[0];
984 *pflValue2 = pSource->vVelocity[1];
985 *pflValue3 = pSource->vVelocity[2];
986 break;
988 case AL_DIRECTION:
989 *pflValue1 = pSource->vOrientation[0];
990 *pflValue2 = pSource->vOrientation[1];
991 *pflValue3 = pSource->vOrientation[2];
992 break;
994 default:
995 alSetError(AL_INVALID_ENUM);
996 break;
999 else
1000 alSetError(AL_INVALID_NAME);
1002 else
1003 alSetError(AL_INVALID_VALUE);
1005 ProcessContext(pContext);
1007 else
1008 alSetError(AL_INVALID_OPERATION);
1010 return;
1014 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1016 ALCcontext *pContext;
1017 ALsource *pSource;
1019 pContext = alcGetCurrentContext();
1020 if (pContext)
1022 SuspendContext(pContext);
1024 if (pflValues)
1026 if (alIsSource(source))
1028 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1030 switch(eParam)
1032 case AL_PITCH:
1033 case AL_GAIN:
1034 case AL_MIN_GAIN:
1035 case AL_MAX_GAIN:
1036 case AL_MAX_DISTANCE:
1037 case AL_ROLLOFF_FACTOR:
1038 case AL_DOPPLER_FACTOR:
1039 case AL_CONE_OUTER_GAIN:
1040 case AL_SEC_OFFSET:
1041 case AL_SAMPLE_OFFSET:
1042 case AL_BYTE_OFFSET:
1043 case AL_CONE_INNER_ANGLE:
1044 case AL_CONE_OUTER_ANGLE:
1045 case AL_REFERENCE_DISTANCE:
1046 case AL_CONE_OUTER_GAINHF:
1047 case AL_AIR_ABSORPTION_FACTOR:
1048 case AL_ROOM_ROLLOFF_FACTOR:
1049 alGetSourcef(source, eParam, pflValues);
1050 break;
1052 case AL_POSITION:
1053 pflValues[0] = pSource->vPosition[0];
1054 pflValues[1] = pSource->vPosition[1];
1055 pflValues[2] = pSource->vPosition[2];
1056 break;
1058 case AL_VELOCITY:
1059 pflValues[0] = pSource->vVelocity[0];
1060 pflValues[1] = pSource->vVelocity[1];
1061 pflValues[2] = pSource->vVelocity[2];
1062 break;
1064 case AL_DIRECTION:
1065 pflValues[0] = pSource->vOrientation[0];
1066 pflValues[1] = pSource->vOrientation[1];
1067 pflValues[2] = pSource->vOrientation[2];
1068 break;
1070 default:
1071 alSetError(AL_INVALID_ENUM);
1072 break;
1075 else
1076 alSetError(AL_INVALID_NAME);
1078 else
1079 alSetError(AL_INVALID_VALUE);
1081 ProcessContext(pContext);
1083 else
1084 alSetError(AL_INVALID_OPERATION);
1086 return;
1090 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1092 ALCcontext *pContext;
1093 ALsource *pSource;
1094 ALfloat flOffset;
1096 pContext = alcGetCurrentContext();
1097 if (pContext)
1099 SuspendContext(pContext);
1101 if (plValue)
1103 if (alIsSource(source))
1105 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1107 switch(eParam)
1109 case AL_MAX_DISTANCE:
1110 *plValue = (ALint)pSource->flMaxDistance;
1111 break;
1113 case AL_ROLLOFF_FACTOR:
1114 *plValue = (ALint)pSource->flRollOffFactor;
1115 break;
1117 case AL_REFERENCE_DISTANCE:
1118 *plValue = (ALint)pSource->flRefDistance;
1119 break;
1121 case AL_SOURCE_RELATIVE:
1122 *plValue = pSource->bHeadRelative;
1123 break;
1125 case AL_CONE_INNER_ANGLE:
1126 *plValue = (ALint)pSource->flInnerAngle;
1127 break;
1129 case AL_CONE_OUTER_ANGLE:
1130 *plValue = (ALint)pSource->flOuterAngle;
1131 break;
1133 case AL_LOOPING:
1134 *plValue = pSource->bLooping;
1135 break;
1137 case AL_BUFFER:
1138 *plValue = pSource->ulBufferID;
1139 break;
1141 case AL_SOURCE_STATE:
1142 *plValue = pSource->state;
1143 break;
1145 case AL_BUFFERS_QUEUED:
1146 *plValue = pSource->BuffersInQueue;
1147 break;
1149 case AL_BUFFERS_PROCESSED:
1150 if(pSource->bLooping)
1152 /* Buffers on a looping source are in a perpetual state
1153 * of PENDING, so don't report any as PROCESSED */
1154 *plValue = 0;
1156 else
1157 *plValue = pSource->BuffersPlayed;
1158 break;
1160 case AL_SOURCE_TYPE:
1161 *plValue = pSource->lSourceType;
1162 break;
1164 case AL_SEC_OFFSET:
1165 case AL_SAMPLE_OFFSET:
1166 case AL_BYTE_OFFSET:
1167 if (GetSourceOffset(pSource, eParam, &flOffset))
1168 *plValue = (ALint)flOffset;
1169 else
1170 alSetError(AL_INVALID_OPERATION);
1171 break;
1173 case AL_DIRECT_FILTER:
1174 *plValue = pSource->DirectFilter.filter;
1175 break;
1177 case AL_DIRECT_FILTER_GAINHF_AUTO:
1178 *plValue = pSource->DryGainHFAuto;
1179 break;
1181 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1182 *plValue = pSource->WetGainAuto;
1183 break;
1185 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1186 *plValue = pSource->WetGainHFAuto;
1187 break;
1189 case AL_DOPPLER_FACTOR:
1190 *plValue = (ALint)pSource->DopplerFactor;
1191 break;
1193 default:
1194 alSetError(AL_INVALID_ENUM);
1195 break;
1198 else
1199 alSetError(AL_INVALID_NAME);
1201 else
1202 alSetError(AL_INVALID_VALUE);
1204 ProcessContext(pContext);
1206 else
1207 alSetError(AL_INVALID_OPERATION);
1209 return;
1213 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1215 ALCcontext *pContext;
1216 ALsource *pSource;
1218 pContext = alcGetCurrentContext();
1219 if (pContext)
1221 SuspendContext(pContext);
1223 if ((plValue1) && (plValue2) && (plValue3))
1225 if (alIsSource(source))
1227 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1229 switch(eParam)
1231 case AL_POSITION:
1232 *plValue1 = (ALint)pSource->vPosition[0];
1233 *plValue2 = (ALint)pSource->vPosition[1];
1234 *plValue3 = (ALint)pSource->vPosition[2];
1235 break;
1237 case AL_VELOCITY:
1238 *plValue1 = (ALint)pSource->vVelocity[0];
1239 *plValue2 = (ALint)pSource->vVelocity[1];
1240 *plValue3 = (ALint)pSource->vVelocity[2];
1241 break;
1243 case AL_DIRECTION:
1244 *plValue1 = (ALint)pSource->vOrientation[0];
1245 *plValue2 = (ALint)pSource->vOrientation[1];
1246 *plValue3 = (ALint)pSource->vOrientation[2];
1247 break;
1249 default:
1250 alSetError(AL_INVALID_ENUM);
1251 break;
1254 else
1255 alSetError(AL_INVALID_NAME);
1257 else
1258 alSetError(AL_INVALID_VALUE);
1260 ProcessContext(pContext);
1262 else
1263 alSetError(AL_INVALID_OPERATION);
1265 return;
1269 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1271 ALCcontext *pContext;
1272 ALsource *pSource;
1274 pContext = alcGetCurrentContext();
1275 if (pContext)
1277 SuspendContext(pContext);
1279 if (plValues)
1281 if (alIsSource(source))
1283 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1285 switch (eParam)
1287 case AL_SOURCE_RELATIVE:
1288 case AL_CONE_INNER_ANGLE:
1289 case AL_CONE_OUTER_ANGLE:
1290 case AL_LOOPING:
1291 case AL_BUFFER:
1292 case AL_SOURCE_STATE:
1293 case AL_BUFFERS_QUEUED:
1294 case AL_BUFFERS_PROCESSED:
1295 case AL_SEC_OFFSET:
1296 case AL_SAMPLE_OFFSET:
1297 case AL_BYTE_OFFSET:
1298 case AL_MAX_DISTANCE:
1299 case AL_ROLLOFF_FACTOR:
1300 case AL_DOPPLER_FACTOR:
1301 case AL_REFERENCE_DISTANCE:
1302 case AL_SOURCE_TYPE:
1303 case AL_DIRECT_FILTER:
1304 case AL_DIRECT_FILTER_GAINHF_AUTO:
1305 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1306 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1307 alGetSourcei(source, eParam, plValues);
1308 break;
1310 case AL_POSITION:
1311 plValues[0] = (ALint)pSource->vPosition[0];
1312 plValues[1] = (ALint)pSource->vPosition[1];
1313 plValues[2] = (ALint)pSource->vPosition[2];
1314 break;
1316 case AL_VELOCITY:
1317 plValues[0] = (ALint)pSource->vVelocity[0];
1318 plValues[1] = (ALint)pSource->vVelocity[1];
1319 plValues[2] = (ALint)pSource->vVelocity[2];
1320 break;
1322 case AL_DIRECTION:
1323 plValues[0] = (ALint)pSource->vOrientation[0];
1324 plValues[1] = (ALint)pSource->vOrientation[1];
1325 plValues[2] = (ALint)pSource->vOrientation[2];
1326 break;
1328 default:
1329 alSetError(AL_INVALID_ENUM);
1330 break;
1333 else
1334 alSetError(AL_INVALID_NAME);
1336 else
1337 alSetError(AL_INVALID_VALUE);
1339 ProcessContext(pContext);
1341 else
1342 alSetError(AL_INVALID_OPERATION);
1344 return;
1348 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1350 alSourcePlayv(1, &source);
1351 return;
1354 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1356 ALCcontext *pContext;
1357 ALsource *pSource;
1358 ALbufferlistitem *ALBufferList;
1359 ALboolean bSourcesValid = AL_TRUE;
1360 ALboolean bPlay;
1361 ALsizei i, j;
1363 pContext = alcGetCurrentContext();
1364 if (pContext)
1366 SuspendContext(pContext);
1368 if (pSourceList)
1370 // Check that all the Sources are valid
1371 for (i = 0; i < n; i++)
1373 if (!alIsSource(pSourceList[i]))
1375 alSetError(AL_INVALID_NAME);
1376 bSourcesValid = AL_FALSE;
1377 break;
1381 if (bSourcesValid)
1383 for (i = 0; i < n; i++)
1385 // Assume Source won't need to play
1386 bPlay = AL_FALSE;
1388 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1390 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1391 ALBufferList = pSource->queue;
1392 while (ALBufferList)
1394 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1396 bPlay = AL_TRUE;
1397 break;
1399 ALBufferList = ALBufferList->next;
1402 if (bPlay)
1404 for(j = 0;j < OUTPUTCHANNELS;j++)
1406 pSource->DryGains[j] = 0.0f;
1407 pSource->WetGains[j] = 0.0f;
1409 pSource->DryGainHF = 0.0f;
1410 pSource->WetGainHF = 0.0f;
1412 if (pSource->state != AL_PAUSED)
1414 pSource->state = AL_PLAYING;
1415 pSource->inuse = AL_TRUE;
1416 pSource->play = AL_TRUE;
1417 pSource->position = 0;
1418 pSource->position_fraction = 0;
1419 pSource->BuffersPlayed = 0;
1420 pSource->BufferPosition = 0;
1421 pSource->lBytesPlayed = 0;
1423 pSource->ulBufferID = pSource->queue->buffer;
1425 // Make sure all the Buffers in the queue are marked as PENDING
1426 ALBufferList = pSource->queue;
1427 while (ALBufferList)
1429 ALBufferList->bufferstate = PENDING;
1430 ALBufferList = ALBufferList->next;
1433 else
1435 pSource->state = AL_PLAYING;
1436 pSource->inuse = AL_TRUE;
1437 pSource->play = AL_TRUE;
1440 // Check if an Offset has been set
1441 if (pSource->lOffset)
1442 ApplyOffset(pSource, AL_FALSE);
1444 else
1446 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1447 ALBufferList = pSource->queue;
1448 while (ALBufferList)
1450 ALBufferList->bufferstate = PROCESSED;
1451 ALBufferList = ALBufferList->next;
1454 pSource->BuffersPlayed = pSource->BuffersInQueue;
1459 else
1461 // sources is a NULL pointer
1462 alSetError(AL_INVALID_VALUE);
1465 ProcessContext(pContext);
1467 else
1469 // Invalid Context
1470 alSetError(AL_INVALID_OPERATION);
1473 return;
1476 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1478 alSourcePausev(1, &source);
1479 return;
1482 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1484 ALCcontext *Context;
1485 ALsource *Source;
1486 ALsizei i;
1487 ALboolean bSourcesValid = AL_TRUE;
1489 Context=alcGetCurrentContext();
1490 if (Context)
1492 SuspendContext(Context);
1494 if (sources)
1496 // Check all the Sources are valid
1497 for (i=0;i<n;i++)
1499 if (!alIsSource(sources[i]))
1501 alSetError(AL_INVALID_NAME);
1502 bSourcesValid = AL_FALSE;
1503 break;
1507 if (bSourcesValid)
1509 for (i=0;i<n;i++)
1511 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1512 if (Source->state==AL_PLAYING)
1514 Source->state=AL_PAUSED;
1515 Source->inuse=AL_FALSE;
1520 else
1522 // sources is a NULL pointer
1523 alSetError(AL_INVALID_VALUE);
1526 ProcessContext(Context);
1528 else
1530 // Invalid Context
1531 alSetError(AL_INVALID_OPERATION);
1534 return;
1537 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1539 alSourceStopv(1, &source);
1540 return;
1543 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1545 ALCcontext *Context;
1546 ALsource *Source;
1547 ALsizei i;
1548 ALbufferlistitem *ALBufferListItem;
1549 ALboolean bSourcesValid = AL_TRUE;
1551 Context=alcGetCurrentContext();
1552 if (Context)
1554 SuspendContext(Context);
1556 if (sources)
1558 // Check all the Sources are valid
1559 for (i=0;i<n;i++)
1561 if (!alIsSource(sources[i]))
1563 alSetError(AL_INVALID_NAME);
1564 bSourcesValid = AL_FALSE;
1565 break;
1569 if (bSourcesValid)
1571 for (i=0;i<n;i++)
1573 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1574 if (Source->state!=AL_INITIAL)
1576 Source->state=AL_STOPPED;
1577 Source->inuse=AL_FALSE;
1578 Source->BuffersPlayed = Source->BuffersInQueue;
1579 ALBufferListItem= Source->queue;
1580 while (ALBufferListItem != NULL)
1582 ALBufferListItem->bufferstate = PROCESSED;
1583 ALBufferListItem = ALBufferListItem->next;
1586 Source->lOffset = 0;
1590 else
1592 // sources is a NULL pointer
1593 alSetError(AL_INVALID_VALUE);
1596 ProcessContext(Context);
1598 else
1600 // Invalid Context
1601 alSetError(AL_INVALID_OPERATION);
1604 return;
1607 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1609 alSourceRewindv(1, &source);
1610 return;
1613 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1615 ALCcontext *Context;
1616 ALsource *Source;
1617 ALsizei i;
1618 ALbufferlistitem *ALBufferListItem;
1619 ALboolean bSourcesValid = AL_TRUE;
1621 Context=alcGetCurrentContext();
1622 if (Context)
1624 SuspendContext(Context);
1626 if (sources)
1628 // Check all the Sources are valid
1629 for (i=0;i<n;i++)
1631 if (!alIsSource(sources[i]))
1633 alSetError(AL_INVALID_NAME);
1634 bSourcesValid = AL_FALSE;
1635 break;
1639 if (bSourcesValid)
1641 for (i=0;i<n;i++)
1643 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1644 if (Source->state!=AL_INITIAL)
1646 Source->state=AL_INITIAL;
1647 Source->inuse=AL_FALSE;
1648 Source->position=0;
1649 Source->position_fraction=0;
1650 Source->BuffersPlayed = 0;
1651 ALBufferListItem= Source->queue;
1652 while (ALBufferListItem != NULL)
1654 ALBufferListItem->bufferstate = PENDING;
1655 ALBufferListItem = ALBufferListItem->next;
1657 if (Source->queue)
1658 Source->ulBufferID = Source->queue->buffer;
1660 Source->lOffset = 0;
1664 else
1666 // sources is a NULL pointer
1667 alSetError(AL_INVALID_VALUE);
1670 ProcessContext(Context);
1672 else
1674 // Invalid Context
1675 alSetError(AL_INVALID_OPERATION);
1678 return;
1682 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1684 ALCcontext *Context;
1685 ALsource *ALSource;
1686 ALsizei i;
1687 ALbufferlistitem *ALBufferList;
1688 ALbufferlistitem *ALBufferListStart;
1689 ALuint DataSize;
1690 ALuint BufferSize;
1691 ALint iFrequency;
1692 ALint iFormat;
1693 ALboolean bBuffersValid = AL_TRUE;
1695 if (n == 0)
1696 return;
1698 Context=alcGetCurrentContext();
1699 if (Context)
1701 SuspendContext(Context);
1703 DataSize = 0;
1704 BufferSize = 0;
1706 // Check that all buffers are valid or zero and that the source is valid
1708 // Check that this is a valid source
1709 if (alIsSource(source))
1711 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1713 // Check that this is not a STATIC Source
1714 if (ALSource->lSourceType != AL_STATIC)
1716 iFrequency = -1;
1717 iFormat = -1;
1719 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1720 ALBufferList = ALSource->queue;
1721 while (ALBufferList)
1723 if (ALBufferList->buffer)
1725 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1726 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1727 break;
1729 ALBufferList = ALBufferList->next;
1732 for (i = 0; i < n; i++)
1734 if (alIsBuffer(buffers[i]))
1736 if (buffers[i])
1738 if ((iFrequency == -1) && (iFormat == -1))
1740 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1741 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1743 else
1745 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1746 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1748 alSetError(AL_INVALID_OPERATION);
1749 bBuffersValid = AL_FALSE;
1750 break;
1755 else
1757 alSetError(AL_INVALID_NAME);
1758 bBuffersValid = AL_FALSE;
1759 break;
1763 if (bBuffersValid)
1765 // Change Source Type
1766 ALSource->lSourceType = AL_STREAMING;
1768 // All buffers are valid - so add them to the list
1769 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1770 ALBufferListStart->buffer = buffers[0];
1771 ALBufferListStart->bufferstate = PENDING;
1772 ALBufferListStart->flag = 0;
1773 ALBufferListStart->next = NULL;
1775 if (buffers[0])
1776 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1777 else
1778 BufferSize = 0;
1780 DataSize += BufferSize;
1782 // Increment reference counter for buffer
1783 if (buffers[0])
1784 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1786 ALBufferList = ALBufferListStart;
1788 for (i = 1; i < n; i++)
1790 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1791 ALBufferList->next->buffer = buffers[i];
1792 ALBufferList->next->bufferstate = PENDING;
1793 ALBufferList->next->flag = 0;
1794 ALBufferList->next->next = NULL;
1796 if (buffers[i])
1797 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1798 else
1799 BufferSize = 0;
1801 DataSize += BufferSize;
1803 // Increment reference counter for buffer
1804 if (buffers[i])
1805 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1807 ALBufferList = ALBufferList->next;
1810 if (ALSource->queue == NULL)
1812 ALSource->queue = ALBufferListStart;
1813 // Update Current Buffer
1814 ALSource->ulBufferID = ALBufferListStart->buffer;
1816 else
1818 // Find end of queue
1819 ALBufferList = ALSource->queue;
1820 while (ALBufferList->next != NULL)
1822 ALBufferList = ALBufferList->next;
1825 ALBufferList->next = ALBufferListStart;
1828 // Update number of buffers in queue
1829 ALSource->BuffersInQueue += n;
1832 else
1834 // Invalid Source Type (can't queue on a Static Source)
1835 alSetError(AL_INVALID_OPERATION);
1838 else
1840 // Invalid Source Name
1841 alSetError(AL_INVALID_NAME);
1844 ProcessContext(Context);
1846 else
1848 // Invalid Context
1849 alSetError(AL_INVALID_OPERATION);
1852 return;
1856 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1857 // an array of buffer IDs that are to be filled with the names of the buffers removed
1858 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1860 ALCcontext *Context;
1861 ALsource *ALSource;
1862 ALsizei i;
1863 ALbufferlistitem *ALBufferList;
1864 ALuint DataSize;
1865 ALuint BufferSize;
1866 ALuint BufferID;
1867 ALboolean bBuffersProcessed;
1869 if (n == 0)
1870 return;
1872 DataSize = 0;
1873 BufferSize = 0;
1874 bBuffersProcessed = AL_TRUE;
1876 Context=alcGetCurrentContext();
1877 if (Context)
1879 SuspendContext(Context);
1881 if (alIsSource(source))
1883 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1885 // Check that all 'n' buffers have been processed
1886 ALBufferList = ALSource->queue;
1887 for (i = 0; i < n; i++)
1889 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1891 ALBufferList = ALBufferList->next;
1893 else
1895 bBuffersProcessed = AL_FALSE;
1896 break;
1900 // If all 'n' buffers have been processed, remove them from the queue
1901 if (bBuffersProcessed)
1903 for (i = 0; i < n; i++)
1905 ALBufferList = ALSource->queue;
1907 ALSource->queue = ALBufferList->next;
1908 // Record name of buffer
1909 buffers[i] = ALBufferList->buffer;
1910 // Decrement buffer reference counter
1911 if (ALBufferList->buffer)
1912 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1913 // Record size of buffer
1914 if (ALBufferList->buffer)
1915 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1916 else
1917 BufferSize = 0;
1919 DataSize += BufferSize;
1920 // Release memory for buffer list item
1921 free(ALBufferList);
1922 ALSource->BuffersInQueue--;
1925 if (ALSource->state != AL_PLAYING)
1927 if (ALSource->queue)
1928 BufferID = ALSource->queue->buffer;
1929 else
1930 BufferID = 0;
1932 ALSource->ulBufferID = BufferID;
1935 if((ALuint)n > ALSource->BuffersPlayed)
1937 ALSource->BuffersPlayed = 0;
1938 ALSource->BufferPosition = 0;
1940 else
1941 ALSource->BuffersPlayed -= n;
1943 else
1945 // Some buffers can't be unqueue because they have not been processed
1946 alSetError(AL_INVALID_VALUE);
1949 else
1951 // Invalid Source Name
1952 alSetError(AL_INVALID_NAME);
1955 ProcessContext(Context);
1957 else
1959 // Invalid Context
1960 alSetError(AL_INVALID_OPERATION);
1963 return;
1967 static ALvoid InitSourceParams(ALsource *pSource)
1969 pSource->flInnerAngle = 360.0f;
1970 pSource->flOuterAngle = 360.0f;
1971 pSource->flPitch = 1.0f;
1972 pSource->vPosition[0] = 0.0f;
1973 pSource->vPosition[1] = 0.0f;
1974 pSource->vPosition[2] = 0.0f;
1975 pSource->vOrientation[0] = 0.0f;
1976 pSource->vOrientation[1] = 0.0f;
1977 pSource->vOrientation[2] = 0.0f;
1978 pSource->vVelocity[0] = 0.0f;
1979 pSource->vVelocity[1] = 0.0f;
1980 pSource->vVelocity[2] = 0.0f;
1981 pSource->flRefDistance = 1.0f;
1982 pSource->flMaxDistance = FLT_MAX;
1983 pSource->flRollOffFactor = 1.0f;
1984 pSource->bLooping = AL_FALSE;
1985 pSource->flGain = 1.0f;
1986 pSource->flMinGain = 0.0f;
1987 pSource->flMaxGain = 1.0f;
1988 pSource->flOuterGain = 0.0f;
1989 pSource->OuterGainHF = 1.0f;
1991 pSource->DryGainHFAuto = AL_TRUE;
1992 pSource->WetGainAuto = AL_TRUE;
1993 pSource->WetGainHFAuto = AL_TRUE;
1994 pSource->AirAbsorptionFactor = 0.0f;
1995 pSource->RoomRolloffFactor = 0.0f;
1996 pSource->DopplerFactor = 1.0f;
1998 pSource->state = AL_INITIAL;
1999 pSource->lSourceType = AL_UNDETERMINED;
2001 pSource->ulBufferID= 0;
2006 GetSourceOffset
2008 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2009 The offset is relative to the start of the queue (not the start of the current buffer)
2011 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2013 ALbufferlistitem *pBufferList;
2014 ALbuffer *pBuffer;
2015 ALfloat flBufferFreq;
2016 ALint lBytesPlayed, lChannels;
2017 ALenum eOriginalFormat;
2018 ALboolean bReturn = AL_TRUE;
2019 ALint lTotalBufferDataSize;
2021 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2023 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2024 // Get Current Buffer Size and frequency (in milliseconds)
2025 flBufferFreq = (ALfloat)pBuffer->frequency;
2026 eOriginalFormat = pBuffer->eOriginalFormat;
2027 lChannels = aluChannelsFromFormat(pBuffer->format);
2029 // Get Current BytesPlayed
2030 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2031 // Add byte length of any processed buffers in the queue
2032 pBufferList = pSource->queue;
2033 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2035 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2036 pBufferList = pBufferList->next;
2039 lTotalBufferDataSize = 0;
2040 pBufferList = pSource->queue;
2041 while (pBufferList)
2043 if (pBufferList->buffer)
2044 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2045 pBufferList = pBufferList->next;
2048 if (pSource->bLooping)
2050 if (lBytesPlayed < 0)
2051 lBytesPlayed = 0;
2052 else
2053 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2055 else
2057 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2058 if(lBytesPlayed < 0)
2059 lBytesPlayed = 0;
2060 if(lBytesPlayed > lTotalBufferDataSize)
2061 lBytesPlayed = lTotalBufferDataSize;
2064 switch (eName)
2066 case AL_SEC_OFFSET:
2067 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2068 break;
2069 case AL_SAMPLE_OFFSET:
2070 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2071 break;
2072 case AL_BYTE_OFFSET:
2073 // Take into account the original format of the Buffer
2074 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2075 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2077 // Compression rate of the ADPCM supported is 3.6111 to 1
2078 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2079 // Round down to nearest ADPCM block
2080 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2082 else if (eOriginalFormat == AL_FORMAT_REAR8)
2084 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2086 else if (eOriginalFormat == AL_FORMAT_REAR16)
2088 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2090 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2092 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2094 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2096 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2098 else
2100 *pflOffset = (ALfloat)lBytesPlayed;
2102 break;
2105 else
2107 *pflOffset = 0.0f;
2110 return bReturn;
2115 ApplyOffset
2117 Apply a playback offset to the Source. This function will update the queue (to correctly
2118 mark buffers as 'pending' or 'processed' depending upon the new offset.
2120 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2122 ALbufferlistitem *pBufferList;
2123 ALbuffer *pBuffer;
2124 ALint lBufferSize, lTotalBufferSize;
2125 ALint lByteOffset;
2127 // Get true byte offset
2128 lByteOffset = GetByteOffset(pSource);
2130 // If this is a valid offset apply it
2131 if (lByteOffset != -1)
2133 // Sort out the queue (pending and processed states)
2134 pBufferList = pSource->queue;
2135 lTotalBufferSize = 0;
2136 pSource->BuffersPlayed = 0;
2137 while (pBufferList)
2139 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2140 lBufferSize = pBuffer ? pBuffer->size : 0;
2142 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2144 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2145 // update the state to PROCESSED
2146 pSource->BuffersPlayed++;
2148 if (!pSource->bLooping)
2149 pBufferList->bufferstate = PROCESSED;
2151 else if (lTotalBufferSize <= lByteOffset)
2153 // Offset is within this buffer
2154 pBufferList->bufferstate = PENDING;
2156 // Set Current Buffer ID
2157 pSource->ulBufferID = pBufferList->buffer;
2159 // Set current position in this buffer
2160 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2162 // Set Total Bytes Played to Offset
2163 pSource->lBytesPlayed = lByteOffset;
2165 // SW Mixer Positions are in Samples
2166 pSource->position = pSource->BufferPosition /
2167 aluBytesFromFormat(pBuffer->format) /
2168 aluChannelsFromFormat(pBuffer->format);
2170 else
2172 // Offset is before this buffer, so mark as pending
2173 pBufferList->bufferstate = PENDING;
2176 // Increment the TotalBufferSize
2177 lTotalBufferSize += lBufferSize;
2179 // Move on to next buffer in the Queue
2180 pBufferList = pBufferList->next;
2183 else
2185 if (bUpdateContext)
2186 alSetError(AL_INVALID_VALUE);
2189 // Clear Offset
2190 pSource->lOffset = 0;
2195 GetByteOffset
2197 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2198 offset supplied by the application). This takes into account the fact that the buffer format
2199 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2201 static ALint GetByteOffset(ALsource *pSource)
2203 ALbuffer *pBuffer = NULL;
2204 ALbufferlistitem *pBufferList;
2205 ALfloat flBufferFreq;
2206 ALint lChannels;
2207 ALint lByteOffset = -1;
2208 ALint lTotalBufferDataSize;
2210 // Find the first non-NULL Buffer in the Queue
2211 pBufferList = pSource->queue;
2212 while (pBufferList)
2214 if (pBufferList->buffer)
2216 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2217 break;
2219 pBufferList = pBufferList->next;
2222 if (pBuffer)
2224 flBufferFreq = ((ALfloat)pBuffer->frequency);
2225 lChannels = aluChannelsFromFormat(pBuffer->format);
2227 // Determine the ByteOffset (and ensure it is block aligned)
2228 switch (pSource->lOffsetType)
2230 case AL_BYTE_OFFSET:
2231 // Take into consideration the original format
2232 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2233 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2235 // Round down to nearest ADPCM block
2236 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2237 // Multiply by compression rate
2238 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2239 lByteOffset -= (lByteOffset % (lChannels * 2));
2241 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2243 lByteOffset = pSource->lOffset * 4;
2244 lByteOffset -= (lByteOffset % (lChannels * 2));
2246 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2248 lByteOffset = pSource->lOffset * 2;
2249 lByteOffset -= (lByteOffset % (lChannels * 2));
2251 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2253 lByteOffset = pSource->lOffset * 2;
2254 lByteOffset -= (lByteOffset % (lChannels * 2));
2256 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2258 lByteOffset = pSource->lOffset / 2;
2259 lByteOffset -= (lByteOffset % (lChannels * 2));
2261 else
2263 lByteOffset = pSource->lOffset;
2264 lByteOffset -= (lByteOffset % (lChannels * 2));
2266 break;
2268 case AL_SAMPLE_OFFSET:
2269 lByteOffset = pSource->lOffset * lChannels * 2;
2270 break;
2272 case AL_SEC_OFFSET:
2273 // Note - lOffset is internally stored as Milliseconds
2274 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2275 lByteOffset -= (lByteOffset % (lChannels * 2));
2276 break;
2279 lTotalBufferDataSize = 0;
2280 pBufferList = pSource->queue;
2281 while (pBufferList)
2283 if (pBufferList->buffer)
2284 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2285 pBufferList = pBufferList->next;
2288 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2289 if (lByteOffset >= lTotalBufferDataSize)
2290 lByteOffset = -1;
2293 return lByteOffset;
2297 ALvoid ReleaseALSources(ALCcontext *Context)
2299 #ifdef _DEBUG
2300 if(Context->SourceCount > 0)
2301 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2302 #endif
2304 while(Context->Source)
2306 ALsource *temp = Context->Source;
2307 Context->Source = Context->Source->next;
2309 // Release source structure
2310 ALTHUNK_REMOVEENTRY(temp->source);
2311 memset(temp, 0, sizeof(ALsource));
2312 free(temp);
2314 Context->SourceCount = 0;