Implement yet another low-pass filter
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob1960b676efdea22c693ace7954e8be1e1325417b
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 free(ALSource->iirFilter.coef);
185 free(ALSource->iirFilter.history);
187 // Decrement Source count
188 Context->SourceCount--;
190 // Remove Source from list of Sources
191 list = &Context->Source;
192 while(*list && *list != ALSource)
193 list = &(*list)->next;
195 if(*list)
196 *list = (*list)->next;
197 ALTHUNK_REMOVEENTRY(ALSource->source);
199 memset(ALSource,0,sizeof(ALsource));
200 free(ALSource);
205 else
207 // No Device created, or attached to Context
208 alSetError(AL_INVALID_OPERATION);
211 else
212 alSetError(AL_INVALID_VALUE);
214 ProcessContext(Context);
216 else
218 // Invalid Context
219 alSetError(AL_INVALID_OPERATION);
222 return;
226 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
228 ALboolean result=AL_FALSE;
229 ALCcontext *Context;
230 ALsource *Source;
232 Context=alcGetCurrentContext();
233 if (Context)
235 SuspendContext(Context);
237 // To determine if this is a valid Source name, look through the list of generated Sources
238 Source = Context->Source;
239 while(Source)
241 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
243 result = AL_TRUE;
244 break;
247 Source = Source->next;
250 ProcessContext(Context);
252 else
254 // Invalid Context
255 alSetError(AL_INVALID_OPERATION);
258 return result;
262 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
264 ALCcontext *pContext;
265 ALsource *pSource;
267 pContext = alcGetCurrentContext();
268 if (pContext)
270 SuspendContext(pContext);
272 if (alIsSource(source))
274 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
276 switch (eParam)
278 case AL_PITCH:
279 if (flValue >= 0.0f)
281 pSource->flPitch = flValue;
282 if(pSource->flPitch < 0.001f)
283 pSource->flPitch = 0.001f;
285 else
286 alSetError(AL_INVALID_VALUE);
287 break;
289 case AL_CONE_INNER_ANGLE:
290 if ((flValue >= 0.0f) && (flValue <= 360.0f))
291 pSource->flInnerAngle = flValue;
292 else
293 alSetError(AL_INVALID_VALUE);
294 break;
296 case AL_CONE_OUTER_ANGLE:
297 if ((flValue >= 0.0f) && (flValue <= 360.0f))
298 pSource->flOuterAngle = flValue;
299 else
300 alSetError(AL_INVALID_VALUE);
301 break;
303 case AL_GAIN:
304 if (flValue >= 0.0f)
305 pSource->flGain = flValue;
306 else
307 alSetError(AL_INVALID_VALUE);
308 break;
310 case AL_MAX_DISTANCE:
311 if (flValue >= 0.0f)
312 pSource->flMaxDistance = flValue;
313 else
314 alSetError(AL_INVALID_VALUE);
315 break;
317 case AL_ROLLOFF_FACTOR:
318 if (flValue >= 0.0f)
319 pSource->flRollOffFactor = flValue;
320 else
321 alSetError(AL_INVALID_VALUE);
322 break;
324 case AL_REFERENCE_DISTANCE:
325 if (flValue >= 0.0f)
326 pSource->flRefDistance = flValue;
327 else
328 alSetError(AL_INVALID_VALUE);
329 break;
331 case AL_MIN_GAIN:
332 if ((flValue >= 0.0f) && (flValue <= 1.0f))
333 pSource->flMinGain = flValue;
334 else
335 alSetError(AL_INVALID_VALUE);
336 break;
338 case AL_MAX_GAIN:
339 if ((flValue >= 0.0f) && (flValue <= 1.0f))
340 pSource->flMaxGain = flValue;
341 else
342 alSetError(AL_INVALID_VALUE);
343 break;
345 case AL_CONE_OUTER_GAIN:
346 if ((flValue >= 0.0f) && (flValue <= 1.0f))
347 pSource->flOuterGain = flValue;
348 else
349 alSetError(AL_INVALID_VALUE);
350 break;
352 case AL_CONE_OUTER_GAINHF:
353 if ((flValue >= 0.0f) && (flValue <= 1.0f))
354 pSource->OuterGainHF = flValue;
355 else
356 alSetError(AL_INVALID_VALUE);
357 break;
359 case AL_AIR_ABSORPTION_FACTOR:
360 if (flValue >= 0.0f && flValue <= 10.0f)
361 pSource->AirAbsorptionFactor = flValue;
362 else
363 alSetError(AL_INVALID_VALUE);
364 break;
366 case AL_ROOM_ROLLOFF_FACTOR:
367 if (flValue >= 0.0f && flValue <= 1.0f)
368 pSource->RoomRolloffFactor = flValue;
369 else
370 alSetError(AL_INVALID_VALUE);
371 break;
373 case AL_SEC_OFFSET:
374 case AL_SAMPLE_OFFSET:
375 case AL_BYTE_OFFSET:
376 if (flValue >= 0.0f)
378 pSource->lOffsetType = eParam;
380 // Store Offset (convert Seconds into Milliseconds)
381 if (eParam == AL_SEC_OFFSET)
382 pSource->lOffset = (ALint)(flValue * 1000.0f);
383 else
384 pSource->lOffset = (ALint)flValue;
386 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
387 ApplyOffset(pSource, AL_TRUE);
389 else
390 alSetError(AL_INVALID_VALUE);
391 break;
393 default:
394 alSetError(AL_INVALID_ENUM);
395 break;
398 else
400 // Invalid Source Name
401 alSetError(AL_INVALID_NAME);
404 ProcessContext(pContext);
406 else
408 // Invalid context
409 alSetError(AL_INVALID_OPERATION);
412 return;
416 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
418 ALCcontext *pContext;
419 ALsource *pSource;
421 pContext = alcGetCurrentContext();
422 if (pContext)
424 SuspendContext(pContext);
426 if (alIsSource(source))
428 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
429 switch(eParam)
431 case AL_POSITION:
432 pSource->vPosition[0] = flValue1;
433 pSource->vPosition[1] = flValue2;
434 pSource->vPosition[2] = flValue3;
435 break;
437 case AL_VELOCITY:
438 pSource->vVelocity[0] = flValue1;
439 pSource->vVelocity[1] = flValue2;
440 pSource->vVelocity[2] = flValue3;
441 break;
443 case AL_DIRECTION:
444 pSource->vOrientation[0] = flValue1;
445 pSource->vOrientation[1] = flValue2;
446 pSource->vOrientation[2] = flValue3;
447 break;
449 default:
450 alSetError(AL_INVALID_ENUM);
451 break;
454 else
455 alSetError(AL_INVALID_NAME);
457 ProcessContext(pContext);
459 else
461 alSetError(AL_INVALID_OPERATION);
464 return;
468 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
470 ALCcontext *pContext;
472 pContext = alcGetCurrentContext();
473 if (pContext)
475 SuspendContext(pContext);
477 if (pflValues)
479 if (alIsSource(source))
481 switch (eParam)
483 case AL_PITCH:
484 case AL_CONE_INNER_ANGLE:
485 case AL_CONE_OUTER_ANGLE:
486 case AL_GAIN:
487 case AL_MAX_DISTANCE:
488 case AL_ROLLOFF_FACTOR:
489 case AL_REFERENCE_DISTANCE:
490 case AL_MIN_GAIN:
491 case AL_MAX_GAIN:
492 case AL_CONE_OUTER_GAIN:
493 case AL_CONE_OUTER_GAINHF:
494 case AL_SEC_OFFSET:
495 case AL_SAMPLE_OFFSET:
496 case AL_BYTE_OFFSET:
497 case AL_AIR_ABSORPTION_FACTOR:
498 case AL_ROOM_ROLLOFF_FACTOR:
499 alSourcef(source, eParam, pflValues[0]);
500 break;
502 case AL_POSITION:
503 case AL_VELOCITY:
504 case AL_DIRECTION:
505 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
506 break;
508 default:
509 alSetError(AL_INVALID_ENUM);
510 break;
513 else
514 alSetError(AL_INVALID_NAME);
516 else
517 alSetError(AL_INVALID_VALUE);
519 ProcessContext(pContext);
521 else
522 alSetError(AL_INVALID_OPERATION);
524 return;
528 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
530 ALCcontext *pContext;
531 ALsource *pSource;
532 ALbufferlistitem *pALBufferListItem;
533 ALint Counter = 0;
534 ALint DataSize = 0;
535 ALint BufferSize;
537 pContext = alcGetCurrentContext();
538 if (pContext)
540 SuspendContext(pContext);
542 if (alIsSource(source))
544 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
546 switch(eParam)
548 case AL_MAX_DISTANCE:
549 case AL_ROLLOFF_FACTOR:
550 case AL_REFERENCE_DISTANCE:
551 alSourcef(source, eParam, (ALfloat)lValue);
552 break;
554 case AL_SOURCE_RELATIVE:
555 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
556 pSource->bHeadRelative = (ALboolean)lValue;
557 else
558 alSetError(AL_INVALID_VALUE);
559 break;
561 case AL_CONE_INNER_ANGLE:
562 if ((lValue >= 0) && (lValue <= 360))
563 pSource->flInnerAngle = (float)lValue;
564 else
565 alSetError(AL_INVALID_VALUE);
566 break;
568 case AL_CONE_OUTER_ANGLE:
569 if ((lValue >= 0) && (lValue <= 360))
570 pSource->flOuterAngle = (float)lValue;
571 else
572 alSetError(AL_INVALID_VALUE);
573 break;
575 case AL_LOOPING:
576 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
577 pSource->bLooping = (ALboolean)lValue;
578 else
579 alSetError(AL_INVALID_VALUE);
580 break;
582 case AL_BUFFER:
583 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
585 if (alIsBuffer(lValue))
587 // Remove all elements in the queue
588 while (pSource->queue != NULL)
590 pALBufferListItem = pSource->queue;
591 pSource->queue = pALBufferListItem->next;
592 // Decrement reference counter for buffer
593 if (pALBufferListItem->buffer)
594 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
595 // Record size of buffer
596 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
597 DataSize += BufferSize;
598 // Increment the number of buffers removed from queue
599 Counter++;
600 // Release memory for buffer list item
601 free(pALBufferListItem);
602 // Decrement the number of buffers in the queue
603 pSource->BuffersInQueue--;
606 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
607 if (lValue != 0)
609 // Source is now in STATIC mode
610 pSource->lSourceType = AL_STATIC;
612 // Add the selected buffer to the queue
613 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
614 pALBufferListItem->buffer = lValue;
615 pALBufferListItem->bufferstate = PENDING;
616 pALBufferListItem->flag = 0;
617 pALBufferListItem->next = NULL;
619 pSource->queue = pALBufferListItem;
620 pSource->BuffersInQueue = 1;
622 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
624 // Increment reference counter for buffer
625 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
627 else
629 // Source is now in UNDETERMINED mode
630 pSource->lSourceType = AL_UNDETERMINED;
633 // Set Buffers Processed
634 pSource->BuffersProcessed = 0;
636 // Update AL_BUFFER parameter
637 pSource->ulBufferID = lValue;
639 else
640 alSetError(AL_INVALID_VALUE);
642 else
643 alSetError(AL_INVALID_OPERATION);
644 break;
646 case AL_SOURCE_STATE:
647 // Query only
648 alSetError(AL_INVALID_OPERATION);
649 break;
651 case AL_SEC_OFFSET:
652 case AL_SAMPLE_OFFSET:
653 case AL_BYTE_OFFSET:
654 if (lValue >= 0)
656 pSource->lOffsetType = eParam;
658 // Store Offset (convert Seconds into Milliseconds)
659 if (eParam == AL_SEC_OFFSET)
660 pSource->lOffset = lValue * 1000;
661 else
662 pSource->lOffset = lValue;
664 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
665 ApplyOffset(pSource, AL_TRUE);
667 else
668 alSetError(AL_INVALID_VALUE);
669 break;
671 case AL_DIRECT_FILTER:
672 if(alIsFilter(lValue))
674 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
675 if(!filter)
677 pSource->DirectFilter.type = AL_FILTER_NULL;
678 pSource->DirectFilter.filter = 0;
680 else
681 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
683 else
684 alSetError(AL_INVALID_VALUE);
685 break;
687 case AL_DIRECT_FILTER_GAINHF_AUTO:
688 if(lValue == AL_TRUE || lValue == AL_FALSE)
689 pSource->DryGainHFAuto = lValue;
690 else
691 alSetError(AL_INVALID_VALUE);
692 break;
694 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
695 if(lValue == AL_TRUE || lValue == AL_FALSE)
696 pSource->WetGainAuto = lValue;
697 else
698 alSetError(AL_INVALID_VALUE);
699 break;
701 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
702 if(lValue == AL_TRUE || lValue == AL_FALSE)
703 pSource->WetGainHFAuto = lValue;
704 else
705 alSetError(AL_INVALID_VALUE);
706 break;
708 default:
709 alSetError(AL_INVALID_ENUM);
710 break;
713 else
714 alSetError(AL_INVALID_NAME);
716 ProcessContext(pContext);
718 else
719 alSetError(AL_INVALID_OPERATION);
721 return;
725 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
727 ALCcontext *pContext;
729 pContext = alcGetCurrentContext();
730 if (pContext)
732 SuspendContext(pContext);
734 if (alIsSource(source))
736 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
738 switch (eParam)
740 case AL_POSITION:
741 case AL_VELOCITY:
742 case AL_DIRECTION:
743 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
744 break;
746 case AL_AUXILIARY_SEND_FILTER:
747 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
748 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
749 alIsFilter(lValue3))
751 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
752 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
754 /* Release refcount on the previous slot, and add one for
755 * the new slot */
756 if(pSource->Send[lValue2].Slot)
757 pSource->Send[lValue2].Slot->refcount--;
758 pSource->Send[lValue2].Slot = ALEffectSlot;
759 if(pSource->Send[lValue2].Slot)
760 pSource->Send[lValue2].Slot->refcount++;
762 if(!ALFilter)
764 /* Disable filter */
765 pSource->Send[lValue2].WetFilter.type = 0;
766 pSource->Send[lValue2].WetFilter.filter = 0;
768 else
769 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
771 else
772 alSetError(AL_INVALID_VALUE);
773 break;
775 default:
776 alSetError(AL_INVALID_ENUM);
777 break;
780 else
781 alSetError(AL_INVALID_NAME);
783 ProcessContext(pContext);
785 else
786 alSetError(AL_INVALID_OPERATION);
788 return;
792 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
794 ALCcontext *pContext;
796 pContext = alcGetCurrentContext();
797 if (pContext)
799 SuspendContext(pContext);
801 if (plValues)
803 if (alIsSource(source))
805 switch (eParam)
807 case AL_SOURCE_RELATIVE:
808 case AL_CONE_INNER_ANGLE:
809 case AL_CONE_OUTER_ANGLE:
810 case AL_LOOPING:
811 case AL_BUFFER:
812 case AL_SOURCE_STATE:
813 case AL_SEC_OFFSET:
814 case AL_SAMPLE_OFFSET:
815 case AL_BYTE_OFFSET:
816 case AL_MAX_DISTANCE:
817 case AL_ROLLOFF_FACTOR:
818 case AL_REFERENCE_DISTANCE:
819 case AL_DIRECT_FILTER:
820 case AL_DIRECT_FILTER_GAINHF_AUTO:
821 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
822 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
823 alSourcei(source, eParam, plValues[0]);
824 break;
826 case AL_POSITION:
827 case AL_VELOCITY:
828 case AL_DIRECTION:
829 case AL_AUXILIARY_SEND_FILTER:
830 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
831 break;
833 default:
834 alSetError(AL_INVALID_ENUM);
835 break;
838 else
839 alSetError(AL_INVALID_NAME);
841 else
842 alSetError(AL_INVALID_VALUE);
844 ProcessContext(pContext);
846 else
847 alSetError(AL_INVALID_OPERATION);
849 return;
853 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
855 ALCcontext *pContext;
856 ALsource *pSource;
857 ALfloat flOffset;
859 pContext = alcGetCurrentContext();
860 if (pContext)
862 SuspendContext(pContext);
864 if (pflValue)
866 if (alIsSource(source))
868 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
870 switch(eParam)
872 case AL_PITCH:
873 *pflValue = pSource->flPitch;
874 break;
876 case AL_GAIN:
877 *pflValue = pSource->flGain;
878 break;
880 case AL_MIN_GAIN:
881 *pflValue = pSource->flMinGain;
882 break;
884 case AL_MAX_GAIN:
885 *pflValue = pSource->flMaxGain;
886 break;
888 case AL_MAX_DISTANCE:
889 *pflValue = pSource->flMaxDistance;
890 break;
892 case AL_ROLLOFF_FACTOR:
893 *pflValue = pSource->flRollOffFactor;
894 break;
896 case AL_CONE_OUTER_GAIN:
897 *pflValue = pSource->flOuterGain;
898 break;
900 case AL_CONE_OUTER_GAINHF:
901 *pflValue = pSource->OuterGainHF;
902 break;
904 case AL_SEC_OFFSET:
905 case AL_SAMPLE_OFFSET:
906 case AL_BYTE_OFFSET:
907 if (GetSourceOffset(pSource, eParam, &flOffset))
908 *pflValue = flOffset;
909 else
910 alSetError(AL_INVALID_OPERATION);
911 break;
913 case AL_CONE_INNER_ANGLE:
914 *pflValue = pSource->flInnerAngle;
915 break;
917 case AL_CONE_OUTER_ANGLE:
918 *pflValue = pSource->flOuterAngle;
919 break;
921 case AL_REFERENCE_DISTANCE:
922 *pflValue = pSource->flRefDistance;
923 break;
925 case AL_AIR_ABSORPTION_FACTOR:
926 *pflValue = pSource->AirAbsorptionFactor;
927 break;
929 case AL_ROOM_ROLLOFF_FACTOR:
930 *pflValue = pSource->RoomRolloffFactor;
931 break;
933 case AL_DOPPLER_FACTOR:
934 *pflValue = pSource->DopplerFactor;
935 break;
937 default:
938 alSetError(AL_INVALID_ENUM);
939 break;
942 else
943 alSetError(AL_INVALID_NAME);
945 else
946 alSetError(AL_INVALID_VALUE);
948 ProcessContext(pContext);
950 else
951 alSetError(AL_INVALID_OPERATION);
953 return;
957 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
959 ALCcontext *pContext;
960 ALsource *pSource;
962 pContext = alcGetCurrentContext();
963 if (pContext)
965 SuspendContext(pContext);
967 if ((pflValue1) && (pflValue2) && (pflValue3))
969 if (alIsSource(source))
971 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
973 switch(eParam)
975 case AL_POSITION:
976 *pflValue1 = pSource->vPosition[0];
977 *pflValue2 = pSource->vPosition[1];
978 *pflValue3 = pSource->vPosition[2];
979 break;
981 case AL_VELOCITY:
982 *pflValue1 = pSource->vVelocity[0];
983 *pflValue2 = pSource->vVelocity[1];
984 *pflValue3 = pSource->vVelocity[2];
985 break;
987 case AL_DIRECTION:
988 *pflValue1 = pSource->vOrientation[0];
989 *pflValue2 = pSource->vOrientation[1];
990 *pflValue3 = pSource->vOrientation[2];
991 break;
993 default:
994 alSetError(AL_INVALID_ENUM);
995 break;
998 else
999 alSetError(AL_INVALID_NAME);
1001 else
1002 alSetError(AL_INVALID_VALUE);
1004 ProcessContext(pContext);
1006 else
1007 alSetError(AL_INVALID_OPERATION);
1009 return;
1013 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1015 ALCcontext *pContext;
1016 ALsource *pSource;
1018 pContext = alcGetCurrentContext();
1019 if (pContext)
1021 SuspendContext(pContext);
1023 if (pflValues)
1025 if (alIsSource(source))
1027 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1029 switch(eParam)
1031 case AL_PITCH:
1032 case AL_GAIN:
1033 case AL_MIN_GAIN:
1034 case AL_MAX_GAIN:
1035 case AL_MAX_DISTANCE:
1036 case AL_ROLLOFF_FACTOR:
1037 case AL_DOPPLER_FACTOR:
1038 case AL_CONE_OUTER_GAIN:
1039 case AL_SEC_OFFSET:
1040 case AL_SAMPLE_OFFSET:
1041 case AL_BYTE_OFFSET:
1042 case AL_CONE_INNER_ANGLE:
1043 case AL_CONE_OUTER_ANGLE:
1044 case AL_REFERENCE_DISTANCE:
1045 case AL_CONE_OUTER_GAINHF:
1046 case AL_AIR_ABSORPTION_FACTOR:
1047 case AL_ROOM_ROLLOFF_FACTOR:
1048 alGetSourcef(source, eParam, pflValues);
1049 break;
1051 case AL_POSITION:
1052 pflValues[0] = pSource->vPosition[0];
1053 pflValues[1] = pSource->vPosition[1];
1054 pflValues[2] = pSource->vPosition[2];
1055 break;
1057 case AL_VELOCITY:
1058 pflValues[0] = pSource->vVelocity[0];
1059 pflValues[1] = pSource->vVelocity[1];
1060 pflValues[2] = pSource->vVelocity[2];
1061 break;
1063 case AL_DIRECTION:
1064 pflValues[0] = pSource->vOrientation[0];
1065 pflValues[1] = pSource->vOrientation[1];
1066 pflValues[2] = pSource->vOrientation[2];
1067 break;
1069 default:
1070 alSetError(AL_INVALID_ENUM);
1071 break;
1074 else
1075 alSetError(AL_INVALID_NAME);
1077 else
1078 alSetError(AL_INVALID_VALUE);
1080 ProcessContext(pContext);
1082 else
1083 alSetError(AL_INVALID_OPERATION);
1085 return;
1089 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1091 ALCcontext *pContext;
1092 ALsource *pSource;
1093 ALfloat flOffset;
1095 pContext = alcGetCurrentContext();
1096 if (pContext)
1098 SuspendContext(pContext);
1100 if (plValue)
1102 if (alIsSource(source))
1104 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1106 switch(eParam)
1108 case AL_MAX_DISTANCE:
1109 *plValue = (ALint)pSource->flMaxDistance;
1110 break;
1112 case AL_ROLLOFF_FACTOR:
1113 *plValue = (ALint)pSource->flRollOffFactor;
1114 break;
1116 case AL_REFERENCE_DISTANCE:
1117 *plValue = (ALint)pSource->flRefDistance;
1118 break;
1120 case AL_SOURCE_RELATIVE:
1121 *plValue = pSource->bHeadRelative;
1122 break;
1124 case AL_CONE_INNER_ANGLE:
1125 *plValue = (ALint)pSource->flInnerAngle;
1126 break;
1128 case AL_CONE_OUTER_ANGLE:
1129 *plValue = (ALint)pSource->flOuterAngle;
1130 break;
1132 case AL_LOOPING:
1133 *plValue = pSource->bLooping;
1134 break;
1136 case AL_BUFFER:
1137 *plValue = pSource->ulBufferID;
1138 break;
1140 case AL_SOURCE_STATE:
1141 *plValue = pSource->state;
1142 break;
1144 case AL_BUFFERS_QUEUED:
1145 *plValue = pSource->BuffersInQueue;
1146 break;
1148 case AL_BUFFERS_PROCESSED:
1149 if(pSource->bLooping)
1151 /* Buffers on a looping source are in a perpetual state
1152 * of PENDING, so don't report any as PROCESSED */
1153 *plValue = 0;
1155 else
1156 *plValue = pSource->BuffersProcessed;
1157 break;
1159 case AL_SOURCE_TYPE:
1160 *plValue = pSource->lSourceType;
1161 break;
1163 case AL_SEC_OFFSET:
1164 case AL_SAMPLE_OFFSET:
1165 case AL_BYTE_OFFSET:
1166 if (GetSourceOffset(pSource, eParam, &flOffset))
1167 *plValue = (ALint)flOffset;
1168 else
1169 alSetError(AL_INVALID_OPERATION);
1170 break;
1172 case AL_DIRECT_FILTER:
1173 *plValue = pSource->DirectFilter.filter;
1174 break;
1176 case AL_DIRECT_FILTER_GAINHF_AUTO:
1177 *plValue = pSource->DryGainHFAuto;
1178 break;
1180 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1181 *plValue = pSource->WetGainAuto;
1182 break;
1184 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1185 *plValue = pSource->WetGainHFAuto;
1186 break;
1188 case AL_DOPPLER_FACTOR:
1189 *plValue = (ALint)pSource->DopplerFactor;
1190 break;
1192 default:
1193 alSetError(AL_INVALID_ENUM);
1194 break;
1197 else
1198 alSetError(AL_INVALID_NAME);
1200 else
1201 alSetError(AL_INVALID_VALUE);
1203 ProcessContext(pContext);
1205 else
1206 alSetError(AL_INVALID_OPERATION);
1208 return;
1212 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1214 ALCcontext *pContext;
1215 ALsource *pSource;
1217 pContext = alcGetCurrentContext();
1218 if (pContext)
1220 SuspendContext(pContext);
1222 if ((plValue1) && (plValue2) && (plValue3))
1224 if (alIsSource(source))
1226 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1228 switch(eParam)
1230 case AL_POSITION:
1231 *plValue1 = (ALint)pSource->vPosition[0];
1232 *plValue2 = (ALint)pSource->vPosition[1];
1233 *plValue3 = (ALint)pSource->vPosition[2];
1234 break;
1236 case AL_VELOCITY:
1237 *plValue1 = (ALint)pSource->vVelocity[0];
1238 *plValue2 = (ALint)pSource->vVelocity[1];
1239 *plValue3 = (ALint)pSource->vVelocity[2];
1240 break;
1242 case AL_DIRECTION:
1243 *plValue1 = (ALint)pSource->vOrientation[0];
1244 *plValue2 = (ALint)pSource->vOrientation[1];
1245 *plValue3 = (ALint)pSource->vOrientation[2];
1246 break;
1248 default:
1249 alSetError(AL_INVALID_ENUM);
1250 break;
1253 else
1254 alSetError(AL_INVALID_NAME);
1256 else
1257 alSetError(AL_INVALID_VALUE);
1259 ProcessContext(pContext);
1261 else
1262 alSetError(AL_INVALID_OPERATION);
1264 return;
1268 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1270 ALCcontext *pContext;
1271 ALsource *pSource;
1273 pContext = alcGetCurrentContext();
1274 if (pContext)
1276 SuspendContext(pContext);
1278 if (plValues)
1280 if (alIsSource(source))
1282 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1284 switch (eParam)
1286 case AL_SOURCE_RELATIVE:
1287 case AL_CONE_INNER_ANGLE:
1288 case AL_CONE_OUTER_ANGLE:
1289 case AL_LOOPING:
1290 case AL_BUFFER:
1291 case AL_SOURCE_STATE:
1292 case AL_BUFFERS_QUEUED:
1293 case AL_BUFFERS_PROCESSED:
1294 case AL_SEC_OFFSET:
1295 case AL_SAMPLE_OFFSET:
1296 case AL_BYTE_OFFSET:
1297 case AL_MAX_DISTANCE:
1298 case AL_ROLLOFF_FACTOR:
1299 case AL_DOPPLER_FACTOR:
1300 case AL_REFERENCE_DISTANCE:
1301 case AL_SOURCE_TYPE:
1302 case AL_DIRECT_FILTER:
1303 case AL_DIRECT_FILTER_GAINHF_AUTO:
1304 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1305 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1306 alGetSourcei(source, eParam, plValues);
1307 break;
1309 case AL_POSITION:
1310 plValues[0] = (ALint)pSource->vPosition[0];
1311 plValues[1] = (ALint)pSource->vPosition[1];
1312 plValues[2] = (ALint)pSource->vPosition[2];
1313 break;
1315 case AL_VELOCITY:
1316 plValues[0] = (ALint)pSource->vVelocity[0];
1317 plValues[1] = (ALint)pSource->vVelocity[1];
1318 plValues[2] = (ALint)pSource->vVelocity[2];
1319 break;
1321 case AL_DIRECTION:
1322 plValues[0] = (ALint)pSource->vOrientation[0];
1323 plValues[1] = (ALint)pSource->vOrientation[1];
1324 plValues[2] = (ALint)pSource->vOrientation[2];
1325 break;
1327 default:
1328 alSetError(AL_INVALID_ENUM);
1329 break;
1332 else
1333 alSetError(AL_INVALID_NAME);
1335 else
1336 alSetError(AL_INVALID_VALUE);
1338 ProcessContext(pContext);
1340 else
1341 alSetError(AL_INVALID_OPERATION);
1343 return;
1347 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1349 alSourcePlayv(1, &source);
1350 return;
1353 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1355 ALCcontext *pContext;
1356 ALsource *pSource;
1357 ALbufferlistitem *ALBufferList;
1358 ALboolean bSourcesValid = AL_TRUE;
1359 ALboolean bPlay;
1360 ALsizei i;
1362 pContext = alcGetCurrentContext();
1363 if (pContext)
1365 SuspendContext(pContext);
1367 if (pSourceList)
1369 // Check that all the Sources are valid
1370 for (i = 0; i < n; i++)
1372 if (!alIsSource(pSourceList[i]))
1374 alSetError(AL_INVALID_NAME);
1375 bSourcesValid = AL_FALSE;
1376 break;
1380 if (bSourcesValid)
1382 for (i = 0; i < n; i++)
1384 // Assume Source won't need to play
1385 bPlay = AL_FALSE;
1387 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1389 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1390 ALBufferList = pSource->queue;
1391 while (ALBufferList)
1393 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1395 bPlay = AL_TRUE;
1396 break;
1398 ALBufferList = ALBufferList->next;
1401 if (bPlay)
1403 if (pSource->state != AL_PAUSED)
1405 pSource->state = AL_PLAYING;
1406 pSource->inuse = AL_TRUE;
1407 pSource->play = AL_TRUE;
1408 pSource->position = 0;
1409 pSource->position_fraction = 0;
1410 pSource->BuffersProcessed = 0;
1411 pSource->BuffersPlayed = 0;
1412 pSource->BufferPosition = 0;
1413 pSource->lBytesPlayed = 0;
1415 pSource->ulBufferID = pSource->queue->buffer;
1417 // Make sure all the Buffers in the queue are marked as PENDING
1418 ALBufferList = pSource->queue;
1419 while (ALBufferList)
1421 ALBufferList->bufferstate = PENDING;
1422 ALBufferList = ALBufferList->next;
1425 else
1427 pSource->state = AL_PLAYING;
1428 pSource->inuse = AL_TRUE;
1429 pSource->play = AL_TRUE;
1432 // Check if an Offset has been set
1433 if (pSource->lOffset)
1434 ApplyOffset(pSource, AL_FALSE);
1436 else
1438 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1439 ALBufferList = pSource->queue;
1440 while (ALBufferList)
1442 ALBufferList->bufferstate = PROCESSED;
1443 ALBufferList = ALBufferList->next;
1446 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1451 else
1453 // sources is a NULL pointer
1454 alSetError(AL_INVALID_VALUE);
1457 ProcessContext(pContext);
1459 else
1461 // Invalid Context
1462 alSetError(AL_INVALID_OPERATION);
1465 return;
1468 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1470 alSourcePausev(1, &source);
1471 return;
1474 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1476 ALCcontext *Context;
1477 ALsource *Source;
1478 ALsizei i;
1479 ALboolean bSourcesValid = AL_TRUE;
1481 Context=alcGetCurrentContext();
1482 if (Context)
1484 SuspendContext(Context);
1486 if (sources)
1488 // Check all the Sources are valid
1489 for (i=0;i<n;i++)
1491 if (!alIsSource(sources[i]))
1493 alSetError(AL_INVALID_NAME);
1494 bSourcesValid = AL_FALSE;
1495 break;
1499 if (bSourcesValid)
1501 for (i=0;i<n;i++)
1503 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1504 if (Source->state==AL_PLAYING)
1506 Source->state=AL_PAUSED;
1507 Source->inuse=AL_FALSE;
1512 else
1514 // sources is a NULL pointer
1515 alSetError(AL_INVALID_VALUE);
1518 ProcessContext(Context);
1520 else
1522 // Invalid Context
1523 alSetError(AL_INVALID_OPERATION);
1526 return;
1529 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1531 alSourceStopv(1, &source);
1532 return;
1535 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1537 ALCcontext *Context;
1538 ALsource *Source;
1539 ALsizei i;
1540 ALbufferlistitem *ALBufferListItem;
1541 ALboolean bSourcesValid = AL_TRUE;
1543 Context=alcGetCurrentContext();
1544 if (Context)
1546 SuspendContext(Context);
1548 if (sources)
1550 // Check all the Sources are valid
1551 for (i=0;i<n;i++)
1553 if (!alIsSource(sources[i]))
1555 alSetError(AL_INVALID_NAME);
1556 bSourcesValid = AL_FALSE;
1557 break;
1561 if (bSourcesValid)
1563 for (i=0;i<n;i++)
1565 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1566 if (Source->state!=AL_INITIAL)
1568 Source->state=AL_STOPPED;
1569 Source->inuse=AL_FALSE;
1570 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1571 ALBufferListItem= Source->queue;
1572 while (ALBufferListItem != NULL)
1574 ALBufferListItem->bufferstate = PROCESSED;
1575 ALBufferListItem = ALBufferListItem->next;
1578 Source->lOffset = 0;
1582 else
1584 // sources is a NULL pointer
1585 alSetError(AL_INVALID_VALUE);
1588 ProcessContext(Context);
1590 else
1592 // Invalid Context
1593 alSetError(AL_INVALID_OPERATION);
1596 return;
1599 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1601 alSourceRewindv(1, &source);
1602 return;
1605 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1607 ALCcontext *Context;
1608 ALsource *Source;
1609 ALsizei i;
1610 ALbufferlistitem *ALBufferListItem;
1611 ALboolean bSourcesValid = AL_TRUE;
1613 Context=alcGetCurrentContext();
1614 if (Context)
1616 SuspendContext(Context);
1618 if (sources)
1620 // Check all the Sources are valid
1621 for (i=0;i<n;i++)
1623 if (!alIsSource(sources[i]))
1625 alSetError(AL_INVALID_NAME);
1626 bSourcesValid = AL_FALSE;
1627 break;
1631 if (bSourcesValid)
1633 for (i=0;i<n;i++)
1635 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1636 if (Source->state!=AL_INITIAL)
1638 Source->state=AL_INITIAL;
1639 Source->inuse=AL_FALSE;
1640 Source->position=0;
1641 Source->position_fraction=0;
1642 Source->BuffersProcessed = 0;
1643 ALBufferListItem= Source->queue;
1644 while (ALBufferListItem != NULL)
1646 ALBufferListItem->bufferstate = PENDING;
1647 ALBufferListItem = ALBufferListItem->next;
1649 if (Source->queue)
1650 Source->ulBufferID = Source->queue->buffer;
1652 Source->lOffset = 0;
1656 else
1658 // sources is a NULL pointer
1659 alSetError(AL_INVALID_VALUE);
1662 ProcessContext(Context);
1664 else
1666 // Invalid Context
1667 alSetError(AL_INVALID_OPERATION);
1670 return;
1674 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1676 ALCcontext *Context;
1677 ALsource *ALSource;
1678 ALsizei i;
1679 ALbufferlistitem *ALBufferList;
1680 ALbufferlistitem *ALBufferListStart;
1681 ALuint DataSize;
1682 ALuint BufferSize;
1683 ALint iFrequency;
1684 ALint iFormat;
1685 ALboolean bBuffersValid = AL_TRUE;
1687 if (n == 0)
1688 return;
1690 Context=alcGetCurrentContext();
1691 if (Context)
1693 SuspendContext(Context);
1695 DataSize = 0;
1696 BufferSize = 0;
1698 // Check that all buffers are valid or zero and that the source is valid
1700 // Check that this is a valid source
1701 if (alIsSource(source))
1703 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1705 // Check that this is not a STATIC Source
1706 if (ALSource->lSourceType != AL_STATIC)
1708 iFrequency = -1;
1709 iFormat = -1;
1711 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1712 ALBufferList = ALSource->queue;
1713 while (ALBufferList)
1715 if (ALBufferList->buffer)
1717 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1718 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1719 break;
1721 ALBufferList = ALBufferList->next;
1724 for (i = 0; i < n; i++)
1726 if (alIsBuffer(buffers[i]))
1728 if (buffers[i])
1730 if ((iFrequency == -1) && (iFormat == -1))
1732 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1733 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1735 else
1737 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1738 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1740 alSetError(AL_INVALID_OPERATION);
1741 bBuffersValid = AL_FALSE;
1742 break;
1747 else
1749 alSetError(AL_INVALID_NAME);
1750 bBuffersValid = AL_FALSE;
1751 break;
1755 if (bBuffersValid)
1757 // Change Source Type
1758 ALSource->lSourceType = AL_STREAMING;
1760 // All buffers are valid - so add them to the list
1761 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1762 ALBufferListStart->buffer = buffers[0];
1763 ALBufferListStart->bufferstate = PENDING;
1764 ALBufferListStart->flag = 0;
1765 ALBufferListStart->next = NULL;
1767 if (buffers[0])
1768 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1769 else
1770 BufferSize = 0;
1772 DataSize += BufferSize;
1774 // Increment reference counter for buffer
1775 if (buffers[0])
1776 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1778 ALBufferList = ALBufferListStart;
1780 for (i = 1; i < n; i++)
1782 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1783 ALBufferList->next->buffer = buffers[i];
1784 ALBufferList->next->bufferstate = PENDING;
1785 ALBufferList->next->flag = 0;
1786 ALBufferList->next->next = NULL;
1788 if (buffers[i])
1789 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1790 else
1791 BufferSize = 0;
1793 DataSize += BufferSize;
1795 // Increment reference counter for buffer
1796 if (buffers[i])
1797 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1799 ALBufferList = ALBufferList->next;
1802 if (ALSource->queue == NULL)
1804 ALSource->queue = ALBufferListStart;
1805 // Update Current Buffer
1806 ALSource->ulBufferID = ALBufferListStart->buffer;
1808 else
1810 // Find end of queue
1811 ALBufferList = ALSource->queue;
1812 while (ALBufferList->next != NULL)
1814 ALBufferList = ALBufferList->next;
1817 ALBufferList->next = ALBufferListStart;
1820 // Update number of buffers in queue
1821 ALSource->BuffersInQueue += n;
1824 else
1826 // Invalid Source Type (can't queue on a Static Source)
1827 alSetError(AL_INVALID_OPERATION);
1830 else
1832 // Invalid Source Name
1833 alSetError(AL_INVALID_NAME);
1836 ProcessContext(Context);
1838 else
1840 // Invalid Context
1841 alSetError(AL_INVALID_OPERATION);
1844 return;
1848 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1849 // an array of buffer IDs that are to be filled with the names of the buffers removed
1850 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1852 ALCcontext *Context;
1853 ALsource *ALSource;
1854 ALsizei i;
1855 ALbufferlistitem *ALBufferList;
1856 ALuint DataSize;
1857 ALuint BufferSize;
1858 ALuint BufferID;
1859 ALboolean bBuffersProcessed;
1861 if (n == 0)
1862 return;
1864 DataSize = 0;
1865 BufferSize = 0;
1866 bBuffersProcessed = AL_TRUE;
1868 Context=alcGetCurrentContext();
1869 if (Context)
1871 SuspendContext(Context);
1873 if (alIsSource(source))
1875 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1877 // Check that all 'n' buffers have been processed
1878 ALBufferList = ALSource->queue;
1879 for (i = 0; i < n; i++)
1881 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1883 ALBufferList = ALBufferList->next;
1885 else
1887 bBuffersProcessed = AL_FALSE;
1888 break;
1892 // If all 'n' buffers have been processed, remove them from the queue
1893 if (bBuffersProcessed)
1895 for (i = 0; i < n; i++)
1897 ALBufferList = ALSource->queue;
1899 ALSource->queue = ALBufferList->next;
1900 // Record name of buffer
1901 buffers[i] = ALBufferList->buffer;
1902 // Decrement buffer reference counter
1903 if (ALBufferList->buffer)
1904 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1905 // Record size of buffer
1906 if (ALBufferList->buffer)
1907 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1908 else
1909 BufferSize = 0;
1911 DataSize += BufferSize;
1912 // Release memory for buffer list item
1913 free(ALBufferList);
1914 ALSource->BuffersInQueue--;
1915 ALSource->BuffersProcessed--;
1918 if (ALSource->state != AL_PLAYING)
1920 if (ALSource->queue)
1921 BufferID = ALSource->queue->buffer;
1922 else
1923 BufferID = 0;
1925 ALSource->ulBufferID = BufferID;
1928 if((ALuint)n > ALSource->BuffersPlayed)
1930 ALSource->BuffersPlayed = 0;
1931 ALSource->BufferPosition = 0;
1933 else
1934 ALSource->BuffersPlayed -= n;
1936 else
1938 // Some buffers can't be unqueue because they have not been processed
1939 alSetError(AL_INVALID_VALUE);
1942 else
1944 // Invalid Source Name
1945 alSetError(AL_INVALID_NAME);
1948 ProcessContext(Context);
1950 else
1952 // Invalid Context
1953 alSetError(AL_INVALID_OPERATION);
1956 return;
1960 static ALvoid InitSourceParams(ALsource *pSource)
1962 pSource->flInnerAngle = 360.0f;
1963 pSource->flOuterAngle = 360.0f;
1964 pSource->flPitch = 1.0f;
1965 pSource->vPosition[0] = 0.0f;
1966 pSource->vPosition[1] = 0.0f;
1967 pSource->vPosition[2] = 0.0f;
1968 pSource->vOrientation[0] = 0.0f;
1969 pSource->vOrientation[1] = 0.0f;
1970 pSource->vOrientation[2] = 0.0f;
1971 pSource->vVelocity[0] = 0.0f;
1972 pSource->vVelocity[1] = 0.0f;
1973 pSource->vVelocity[2] = 0.0f;
1974 pSource->flRefDistance = 1.0f;
1975 pSource->flMaxDistance = FLT_MAX;
1976 pSource->flRollOffFactor = 1.0f;
1977 pSource->bLooping = AL_FALSE;
1978 pSource->flGain = 1.0f;
1979 pSource->flMinGain = 0.0f;
1980 pSource->flMaxGain = 1.0f;
1981 pSource->flOuterGain = 0.0f;
1982 pSource->OuterGainHF = 1.0f;
1984 pSource->DryGainHFAuto = AL_TRUE;
1985 pSource->WetGainAuto = AL_TRUE;
1986 pSource->WetGainHFAuto = AL_TRUE;
1987 pSource->AirAbsorptionFactor = 0.0f;
1988 pSource->RoomRolloffFactor = 0.0f;
1989 pSource->DopplerFactor = 1.0f;
1991 pSource->state = AL_INITIAL;
1992 pSource->lSourceType = AL_UNDETERMINED;
1994 pSource->ulBufferID= 0;
1999 GetSourceOffset
2001 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2002 The offset is relative to the start of the queue (not the start of the current buffer)
2004 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2006 ALbufferlistitem *pBufferList;
2007 ALbuffer *pBuffer;
2008 ALfloat flBufferFreq;
2009 ALint lBytesPlayed, lChannels;
2010 ALenum eOriginalFormat;
2011 ALboolean bReturn = AL_TRUE;
2012 ALint lTotalBufferDataSize;
2014 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2016 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2017 // Get Current Buffer Size and frequency (in milliseconds)
2018 flBufferFreq = (ALfloat)pBuffer->frequency;
2019 eOriginalFormat = pBuffer->eOriginalFormat;
2020 lChannels = aluChannelsFromFormat(pBuffer->format);
2022 // Get Current BytesPlayed
2023 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2024 // Add byte length of any processed buffers in the queue
2025 pBufferList = pSource->queue;
2026 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2028 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2029 pBufferList = pBufferList->next;
2032 lTotalBufferDataSize = 0;
2033 pBufferList = pSource->queue;
2034 while (pBufferList)
2036 if (pBufferList->buffer)
2037 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2038 pBufferList = pBufferList->next;
2041 if (pSource->bLooping)
2043 if (lBytesPlayed < 0)
2044 lBytesPlayed = 0;
2045 else
2046 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2048 else
2050 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2051 if(lBytesPlayed < 0)
2052 lBytesPlayed = 0;
2053 if(lBytesPlayed > lTotalBufferDataSize)
2054 lBytesPlayed = lTotalBufferDataSize;
2057 switch (eName)
2059 case AL_SEC_OFFSET:
2060 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2061 break;
2062 case AL_SAMPLE_OFFSET:
2063 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2064 break;
2065 case AL_BYTE_OFFSET:
2066 // Take into account the original format of the Buffer
2067 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2068 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2070 // Compression rate of the ADPCM supported is 3.6111 to 1
2071 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2072 // Round down to nearest ADPCM block
2073 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2075 else if (eOriginalFormat == AL_FORMAT_REAR8)
2077 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2079 else if (eOriginalFormat == AL_FORMAT_REAR16)
2081 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2083 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2085 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2087 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2089 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2091 else
2093 *pflOffset = (ALfloat)lBytesPlayed;
2095 break;
2098 else
2100 *pflOffset = 0.0f;
2103 return bReturn;
2108 ApplyOffset
2110 Apply a playback offset to the Source. This function will update the queue (to correctly
2111 mark buffers as 'pending' or 'processed' depending upon the new offset.
2113 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2115 ALbufferlistitem *pBufferList;
2116 ALbuffer *pBuffer;
2117 ALint lBufferSize, lTotalBufferSize;
2118 ALint lByteOffset;
2120 // Get true byte offset
2121 lByteOffset = GetByteOffset(pSource);
2123 // If this is a valid offset apply it
2124 if (lByteOffset != -1)
2126 // Sort out the queue (pending and processed states)
2127 pBufferList = pSource->queue;
2128 lTotalBufferSize = 0;
2129 pSource->BuffersPlayed = 0;
2130 pSource->BuffersProcessed = 0;
2131 while (pBufferList)
2133 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2134 lBufferSize = pBuffer ? pBuffer->size : 0;
2136 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2138 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2139 // update the state to PROCESSED
2140 pSource->BuffersPlayed++;
2142 if (!pSource->bLooping)
2144 pBufferList->bufferstate = PROCESSED;
2145 pSource->BuffersProcessed++;
2148 else if (lTotalBufferSize <= lByteOffset)
2150 // Offset is within this buffer
2151 pBufferList->bufferstate = PENDING;
2153 // Set Current Buffer ID
2154 pSource->ulBufferID = pBufferList->buffer;
2156 // Set current position in this buffer
2157 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2159 // Set Total Bytes Played to Offset
2160 pSource->lBytesPlayed = lByteOffset;
2162 // SW Mixer Positions are in Samples
2163 pSource->position = pSource->BufferPosition /
2164 aluBytesFromFormat(pBuffer->format) /
2165 aluChannelsFromFormat(pBuffer->format);
2167 else
2169 // Offset is before this buffer, so mark as pending
2170 pBufferList->bufferstate = PENDING;
2173 // Increment the TotalBufferSize
2174 lTotalBufferSize += lBufferSize;
2176 // Move on to next buffer in the Queue
2177 pBufferList = pBufferList->next;
2180 else
2182 if (bUpdateContext)
2183 alSetError(AL_INVALID_VALUE);
2186 // Clear Offset
2187 pSource->lOffset = 0;
2192 GetByteOffset
2194 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2195 offset supplied by the application). This takes into account the fact that the buffer format
2196 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2198 static ALint GetByteOffset(ALsource *pSource)
2200 ALbuffer *pBuffer = NULL;
2201 ALbufferlistitem *pBufferList;
2202 ALfloat flBufferFreq;
2203 ALint lChannels;
2204 ALint lByteOffset = -1;
2205 ALint lTotalBufferDataSize;
2207 // Find the first non-NULL Buffer in the Queue
2208 pBufferList = pSource->queue;
2209 while (pBufferList)
2211 if (pBufferList->buffer)
2213 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2214 break;
2216 pBufferList = pBufferList->next;
2219 if (pBuffer)
2221 flBufferFreq = ((ALfloat)pBuffer->frequency);
2222 lChannels = aluChannelsFromFormat(pBuffer->format);
2224 // Determine the ByteOffset (and ensure it is block aligned)
2225 switch (pSource->lOffsetType)
2227 case AL_BYTE_OFFSET:
2228 // Take into consideration the original format
2229 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2230 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2232 // Round down to nearest ADPCM block
2233 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2234 // Multiply by compression rate
2235 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2236 lByteOffset -= (lByteOffset % (lChannels * 2));
2238 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2240 lByteOffset = pSource->lOffset * 4;
2241 lByteOffset -= (lByteOffset % (lChannels * 2));
2243 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2245 lByteOffset = pSource->lOffset * 2;
2246 lByteOffset -= (lByteOffset % (lChannels * 2));
2248 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2250 lByteOffset = pSource->lOffset * 2;
2251 lByteOffset -= (lByteOffset % (lChannels * 2));
2253 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2255 lByteOffset = pSource->lOffset / 2;
2256 lByteOffset -= (lByteOffset % (lChannels * 2));
2258 else
2260 lByteOffset = pSource->lOffset;
2261 lByteOffset -= (lByteOffset % (lChannels * 2));
2263 break;
2265 case AL_SAMPLE_OFFSET:
2266 lByteOffset = pSource->lOffset * lChannels * 2;
2267 break;
2269 case AL_SEC_OFFSET:
2270 // Note - lOffset is internally stored as Milliseconds
2271 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2272 lByteOffset -= (lByteOffset % (lChannels * 2));
2273 break;
2276 lTotalBufferDataSize = 0;
2277 pBufferList = pSource->queue;
2278 while (pBufferList)
2280 if (pBufferList->buffer)
2281 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2282 pBufferList = pBufferList->next;
2285 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2286 if (lByteOffset >= lTotalBufferDataSize)
2287 lByteOffset = -1;
2290 return lByteOffset;
2294 ALvoid ReleaseALSources(ALCcontext *Context)
2296 #ifdef _DEBUG
2297 if(Context->SourceCount > 0)
2298 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2299 #endif
2301 while(Context->Source)
2303 ALsource *temp = Context->Source;
2304 Context->Source = Context->Source->next;
2306 // Release source structure
2307 ALTHUNK_REMOVEENTRY(temp->source);
2308 memset(temp, 0, sizeof(ALsource));
2309 free(temp);
2311 Context->SourceCount = 0;