Implement AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO property
[openal-soft.git] / OpenAL32 / alSource.c
blob03ae10b64a572320464271b3fc451529f15649e1
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include <stdlib.h>
22 #include <math.h>
23 #include <float.h>
24 #include "alMain.h"
25 #include "AL/al.h"
26 #include "AL/alc.h"
27 #include "alError.h"
28 #include "alSource.h"
30 static ALvoid InitSourceParams(ALsource *pSource);
31 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
32 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
33 static ALint GetByteOffset(ALsource *pSource);
35 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
37 ALCcontext *Context;
38 ALCdevice *Device;
39 ALsizei i=0;
41 Context = alcGetCurrentContext();
42 if (Context)
44 SuspendContext(Context);
46 if (n > 0)
48 Device = alcGetContextsDevice(Context);
50 if (Device)
52 // Check that enough memory has been allocted in the 'sources' array for n Sources
53 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
55 // Check that the requested number of sources can be generated
56 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
58 ALsource **list = &Context->Source;
59 while(*list)
60 list = &(*list)->next;
62 // Add additional sources to the list (Source->next points to the location for the next Source structure)
63 while(i < n)
65 *list = calloc(1, sizeof(ALsource));
66 if(*list)
68 sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list);
69 (*list)->source = sources[i];
71 InitSourceParams(*list);
72 Context->SourceCount++;
73 i++;
75 list = &(*list)->next;
79 // If we didn't create all the Sources, we must have run out or memory
80 if(i != n)
81 alSetError(AL_OUT_OF_MEMORY);
83 else
85 // Not enough resources to create the Sources
86 alSetError(AL_INVALID_VALUE);
89 else
91 // Bad pointer
92 alSetError(AL_INVALID_VALUE);
95 else
97 // No Device created, or attached to Context
98 alSetError(AL_INVALID_OPERATION);
102 ProcessContext(Context);
104 else
106 // Invalid Context
107 alSetError(AL_INVALID_OPERATION);
110 return;
114 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
116 ALCcontext *Context;
117 ALCdevice *Device;
118 ALsource *ALSource;
119 ALsource **list;
120 ALsizei i;
121 ALbufferlistitem *ALBufferList;
122 ALboolean bSourcesValid = AL_TRUE;
124 Context = alcGetCurrentContext();
125 if (Context)
127 SuspendContext(Context);
129 if (n >= 0)
131 Device = alcGetContextsDevice(Context);
133 if (Device)
135 if ((ALuint)n <= Context->SourceCount)
137 // Check that all Sources are valid (and can therefore be deleted)
138 for (i = 0; i < n; i++)
140 if (!alIsSource(sources[i]))
142 alSetError(AL_INVALID_NAME);
143 bSourcesValid = AL_FALSE;
144 break;
148 if (bSourcesValid)
150 // All Sources are valid, and can be deleted
151 for (i = 0; i < n; i++)
153 // Recheck that the Source is valid, because there could be duplicated Source names
154 if (alIsSource(sources[i]))
156 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
157 alSourceStop((ALuint)ALSource->source);
159 // For each buffer in the source's queue, decrement its reference counter and remove it
160 while (ALSource->queue != NULL)
162 ALBufferList = ALSource->queue;
163 // Decrement buffer's reference counter
164 if (ALBufferList->buffer != 0)
165 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
166 // Update queue to point to next element in list
167 ALSource->queue = ALBufferList->next;
168 // Release memory allocated for buffer list item
169 free(ALBufferList);
172 // Decrement Source count
173 Context->SourceCount--;
175 // Remove Source from list of Sources
176 list = &Context->Source;
177 while(*list && *list != ALSource)
178 list = &(*list)->next;
180 if(*list)
181 *list = (*list)->next;
182 ALTHUNK_REMOVEENTRY(ALSource->source);
184 memset(ALSource,0,sizeof(ALsource));
185 free(ALSource);
191 else
193 // Trying to delete more Sources than have been generated
194 alSetError(AL_INVALID_NAME);
197 else
199 // No Device created, or attached to Context
200 alSetError(AL_INVALID_OPERATION);
203 else
204 alSetError(AL_INVALID_VALUE);
206 ProcessContext(Context);
208 else
210 // Invalid Context
211 alSetError(AL_INVALID_OPERATION);
214 return;
218 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
220 ALboolean result=AL_FALSE;
221 ALCcontext *Context;
222 ALsource *Source;
224 Context=alcGetCurrentContext();
225 if (Context)
227 SuspendContext(Context);
229 // To determine if this is a valid Source name, look through the list of generated Sources
230 Source = Context->Source;
231 while(Source)
233 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
235 result = AL_TRUE;
236 break;
239 Source = Source->next;
242 ProcessContext(Context);
244 else
246 // Invalid Context
247 alSetError(AL_INVALID_OPERATION);
250 return result;
254 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
256 ALCcontext *pContext;
257 ALsource *pSource;
259 pContext = alcGetCurrentContext();
260 if (pContext)
262 SuspendContext(pContext);
264 if (alIsSource(source))
266 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
268 switch (eParam)
270 case AL_PITCH:
271 if (flValue >= 0.0f)
273 pSource->flPitch = flValue;
274 if(pSource->flPitch < 0.001f)
275 pSource->flPitch = 0.001f;
277 else
278 alSetError(AL_INVALID_VALUE);
279 break;
281 case AL_CONE_INNER_ANGLE:
282 if ((flValue >= 0.0f) && (flValue <= 360.0f))
283 pSource->flInnerAngle = flValue;
284 else
285 alSetError(AL_INVALID_VALUE);
286 break;
288 case AL_CONE_OUTER_ANGLE:
289 if ((flValue >= 0.0f) && (flValue <= 360.0f))
290 pSource->flOuterAngle = flValue;
291 else
292 alSetError(AL_INVALID_VALUE);
293 break;
295 case AL_GAIN:
296 if (flValue >= 0.0f)
297 pSource->flGain = flValue;
298 else
299 alSetError(AL_INVALID_VALUE);
300 break;
302 case AL_MAX_DISTANCE:
303 if (flValue >= 0.0f)
304 pSource->flMaxDistance = flValue;
305 else
306 alSetError(AL_INVALID_VALUE);
307 break;
309 case AL_ROLLOFF_FACTOR:
310 if (flValue >= 0.0f)
311 pSource->flRollOffFactor = flValue;
312 else
313 alSetError(AL_INVALID_VALUE);
314 break;
316 case AL_REFERENCE_DISTANCE:
317 if (flValue >= 0.0f)
318 pSource->flRefDistance = flValue;
319 else
320 alSetError(AL_INVALID_VALUE);
321 break;
323 case AL_MIN_GAIN:
324 if ((flValue >= 0.0f) && (flValue <= 1.0f))
325 pSource->flMinGain = flValue;
326 else
327 alSetError(AL_INVALID_VALUE);
328 break;
330 case AL_MAX_GAIN:
331 if ((flValue >= 0.0f) && (flValue <= 1.0f))
332 pSource->flMaxGain = flValue;
333 else
334 alSetError(AL_INVALID_VALUE);
335 break;
337 case AL_CONE_OUTER_GAIN:
338 if ((flValue >= 0.0f) && (flValue <= 1.0f))
339 pSource->flOuterGain = flValue;
340 else
341 alSetError(AL_INVALID_VALUE);
342 break;
344 case AL_CONE_OUTER_GAINHF:
345 if ((flValue >= 0.0f) && (flValue <= 1.0f))
346 pSource->OuterGainHF = flValue;
347 else
348 alSetError(AL_INVALID_VALUE);
349 break;
351 case AL_AIR_ABSORPTION_FACTOR:
352 if (flValue >= 0.0f && flValue <= 10.0f)
353 pSource->AirAbsorptionFactor = flValue;
354 else
355 alSetError(AL_INVALID_VALUE);
356 break;
358 case AL_SEC_OFFSET:
359 case AL_SAMPLE_OFFSET:
360 case AL_BYTE_OFFSET:
361 if (flValue >= 0.0f)
363 pSource->lOffsetType = eParam;
365 // Store Offset (convert Seconds into Milliseconds)
366 if (eParam == AL_SEC_OFFSET)
367 pSource->lOffset = (ALint)(flValue * 1000.0f);
368 else
369 pSource->lOffset = (ALint)flValue;
371 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
372 ApplyOffset(pSource, AL_TRUE);
374 else
375 alSetError(AL_INVALID_VALUE);
376 break;
378 default:
379 alSetError(AL_INVALID_ENUM);
380 break;
383 else
385 // Invalid Source Name
386 alSetError(AL_INVALID_NAME);
389 ProcessContext(pContext);
391 else
393 // Invalid context
394 alSetError(AL_INVALID_OPERATION);
397 return;
401 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
403 ALCcontext *pContext;
404 ALsource *pSource;
406 pContext = alcGetCurrentContext();
407 if (pContext)
409 SuspendContext(pContext);
411 if (alIsSource(source))
413 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
414 switch(eParam)
416 case AL_POSITION:
417 pSource->vPosition[0] = flValue1;
418 pSource->vPosition[1] = flValue2;
419 pSource->vPosition[2] = flValue3;
420 break;
422 case AL_VELOCITY:
423 pSource->vVelocity[0] = flValue1;
424 pSource->vVelocity[1] = flValue2;
425 pSource->vVelocity[2] = flValue3;
426 break;
428 case AL_DIRECTION:
429 pSource->vOrientation[0] = flValue1;
430 pSource->vOrientation[1] = flValue2;
431 pSource->vOrientation[2] = flValue3;
432 break;
434 default:
435 alSetError(AL_INVALID_ENUM);
436 break;
439 else
440 alSetError(AL_INVALID_NAME);
442 ProcessContext(pContext);
444 else
446 alSetError(AL_INVALID_OPERATION);
449 return;
453 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
455 ALCcontext *pContext;
457 pContext = alcGetCurrentContext();
458 if (pContext)
460 SuspendContext(pContext);
462 if (pflValues)
464 if (alIsSource(source))
466 switch (eParam)
468 case AL_PITCH:
469 case AL_CONE_INNER_ANGLE:
470 case AL_CONE_OUTER_ANGLE:
471 case AL_GAIN:
472 case AL_MAX_DISTANCE:
473 case AL_ROLLOFF_FACTOR:
474 case AL_REFERENCE_DISTANCE:
475 case AL_MIN_GAIN:
476 case AL_MAX_GAIN:
477 case AL_CONE_OUTER_GAIN:
478 case AL_CONE_OUTER_GAINHF:
479 case AL_SEC_OFFSET:
480 case AL_SAMPLE_OFFSET:
481 case AL_BYTE_OFFSET:
482 case AL_AIR_ABSORPTION_FACTOR:
483 alSourcef(source, eParam, pflValues[0]);
484 break;
486 case AL_POSITION:
487 case AL_VELOCITY:
488 case AL_DIRECTION:
489 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
490 break;
492 default:
493 alSetError(AL_INVALID_ENUM);
494 break;
497 else
498 alSetError(AL_INVALID_NAME);
500 else
501 alSetError(AL_INVALID_VALUE);
503 ProcessContext(pContext);
505 else
506 alSetError(AL_INVALID_OPERATION);
508 return;
512 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
514 ALCcontext *pContext;
515 ALsource *pSource;
516 ALbufferlistitem *pALBufferListItem;
517 ALint Counter = 0;
518 ALint DataSize = 0;
519 ALint BufferSize;
521 pContext = alcGetCurrentContext();
522 if (pContext)
524 SuspendContext(pContext);
526 if (alIsSource(source))
528 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
530 switch(eParam)
532 case AL_MAX_DISTANCE:
533 case AL_ROLLOFF_FACTOR:
534 case AL_REFERENCE_DISTANCE:
535 alSourcef(source, eParam, (ALfloat)lValue);
536 break;
538 case AL_SOURCE_RELATIVE:
539 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
540 pSource->bHeadRelative = (ALboolean)lValue;
541 else
542 alSetError(AL_INVALID_VALUE);
543 break;
545 case AL_CONE_INNER_ANGLE:
546 if ((lValue >= 0) && (lValue <= 360))
547 pSource->flInnerAngle = (float)lValue;
548 else
549 alSetError(AL_INVALID_VALUE);
550 break;
552 case AL_CONE_OUTER_ANGLE:
553 if ((lValue >= 0) && (lValue <= 360))
554 pSource->flOuterAngle = (float)lValue;
555 else
556 alSetError(AL_INVALID_VALUE);
557 break;
559 case AL_LOOPING:
560 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
561 pSource->bLooping = (ALboolean)lValue;
562 else
563 alSetError(AL_INVALID_VALUE);
564 break;
566 case AL_BUFFER:
567 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
569 if (alIsBuffer(lValue))
571 // Remove all elements in the queue
572 while (pSource->queue != NULL)
574 pALBufferListItem = pSource->queue;
575 pSource->queue = pALBufferListItem->next;
576 // Decrement reference counter for buffer
577 if (pALBufferListItem->buffer)
578 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
579 // Record size of buffer
580 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
581 DataSize += BufferSize;
582 // Increment the number of buffers removed from queue
583 Counter++;
584 // Release memory for buffer list item
585 free(pALBufferListItem);
586 // Decrement the number of buffers in the queue
587 pSource->BuffersInQueue--;
590 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
591 if (lValue != 0)
593 // Source is now in STATIC mode
594 pSource->lSourceType = AL_STATIC;
596 // Add the selected buffer to the queue
597 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
598 pALBufferListItem->buffer = lValue;
599 pALBufferListItem->bufferstate = PENDING;
600 pALBufferListItem->flag = 0;
601 pALBufferListItem->next = NULL;
603 pSource->queue = pALBufferListItem;
604 pSource->BuffersInQueue = 1;
606 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
608 // Increment reference counter for buffer
609 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
611 else
613 // Source is now in UNDETERMINED mode
614 pSource->lSourceType = AL_UNDETERMINED;
617 // Set Buffers Processed
618 pSource->BuffersProcessed = 0;
620 // Update AL_BUFFER parameter
621 pSource->ulBufferID = lValue;
623 else
624 alSetError(AL_INVALID_VALUE);
626 else
627 alSetError(AL_INVALID_OPERATION);
628 break;
630 case AL_SOURCE_STATE:
631 // Query only
632 alSetError(AL_INVALID_OPERATION);
633 break;
635 case AL_SEC_OFFSET:
636 case AL_SAMPLE_OFFSET:
637 case AL_BYTE_OFFSET:
638 if (lValue >= 0)
640 pSource->lOffsetType = eParam;
642 // Store Offset (convert Seconds into Milliseconds)
643 if (eParam == AL_SEC_OFFSET)
644 pSource->lOffset = lValue * 1000;
645 else
646 pSource->lOffset = lValue;
648 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
649 ApplyOffset(pSource, AL_TRUE);
651 else
652 alSetError(AL_INVALID_VALUE);
653 break;
655 case AL_DIRECT_FILTER:
656 if(alIsFilter(lValue))
658 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
659 if(!filter)
661 pSource->DirectFilter.type = AL_FILTER_NULL;
662 pSource->DirectFilter.filter = 0;
664 else
665 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
667 else
668 alSetError(AL_INVALID_VALUE);
669 break;
671 case AL_DIRECT_FILTER_GAINHF_AUTO:
672 if(lValue == AL_TRUE || lValue == AL_FALSE)
673 pSource->DryGainHFAuto = lValue;
674 else
675 alSetError(AL_INVALID_VALUE);
676 break;
678 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
679 if(lValue == AL_TRUE || lValue == AL_FALSE)
680 pSource->WetGainHFAuto = lValue;
681 else
682 alSetError(AL_INVALID_VALUE);
683 break;
685 default:
686 alSetError(AL_INVALID_ENUM);
687 break;
690 else
691 alSetError(AL_INVALID_NAME);
693 ProcessContext(pContext);
695 else
696 alSetError(AL_INVALID_OPERATION);
698 return;
702 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
704 ALCcontext *pContext;
706 pContext = alcGetCurrentContext();
707 if (pContext)
709 SuspendContext(pContext);
711 if (alIsSource(source))
713 switch (eParam)
715 case AL_POSITION:
716 case AL_VELOCITY:
717 case AL_DIRECTION:
718 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
719 break;
721 default:
722 alSetError(AL_INVALID_ENUM);
723 break;
726 else
727 alSetError(AL_INVALID_NAME);
729 ProcessContext(pContext);
731 else
732 alSetError(AL_INVALID_OPERATION);
734 return;
738 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
740 ALCcontext *pContext;
742 pContext = alcGetCurrentContext();
743 if (pContext)
745 SuspendContext(pContext);
747 if (plValues)
749 if (alIsSource(source))
751 switch (eParam)
753 case AL_SOURCE_RELATIVE:
754 case AL_CONE_INNER_ANGLE:
755 case AL_CONE_OUTER_ANGLE:
756 case AL_LOOPING:
757 case AL_BUFFER:
758 case AL_SOURCE_STATE:
759 case AL_SEC_OFFSET:
760 case AL_SAMPLE_OFFSET:
761 case AL_BYTE_OFFSET:
762 case AL_MAX_DISTANCE:
763 case AL_ROLLOFF_FACTOR:
764 case AL_REFERENCE_DISTANCE:
765 case AL_DIRECT_FILTER:
766 case AL_DIRECT_FILTER_GAINHF_AUTO:
767 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
768 alSourcei(source, eParam, plValues[0]);
769 break;
771 case AL_POSITION:
772 case AL_VELOCITY:
773 case AL_DIRECTION:
774 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
775 break;
777 default:
778 alSetError(AL_INVALID_ENUM);
779 break;
782 else
783 alSetError(AL_INVALID_NAME);
785 else
786 alSetError(AL_INVALID_VALUE);
788 ProcessContext(pContext);
790 else
791 alSetError(AL_INVALID_OPERATION);
793 return;
797 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
799 ALCcontext *pContext;
800 ALsource *pSource;
801 ALfloat flOffset;
803 pContext = alcGetCurrentContext();
804 if (pContext)
806 SuspendContext(pContext);
808 if (pflValue)
810 if (alIsSource(source))
812 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
814 switch(eParam)
816 case AL_PITCH:
817 *pflValue = pSource->flPitch;
818 break;
820 case AL_GAIN:
821 *pflValue = pSource->flGain;
822 break;
824 case AL_MIN_GAIN:
825 *pflValue = pSource->flMinGain;
826 break;
828 case AL_MAX_GAIN:
829 *pflValue = pSource->flMaxGain;
830 break;
832 case AL_MAX_DISTANCE:
833 *pflValue = pSource->flMaxDistance;
834 break;
836 case AL_ROLLOFF_FACTOR:
837 *pflValue = pSource->flRollOffFactor;
838 break;
840 case AL_CONE_OUTER_GAIN:
841 *pflValue = pSource->flOuterGain;
842 break;
844 case AL_CONE_OUTER_GAINHF:
845 *pflValue = pSource->OuterGainHF;
846 break;
848 case AL_SEC_OFFSET:
849 case AL_SAMPLE_OFFSET:
850 case AL_BYTE_OFFSET:
851 if (GetSourceOffset(pSource, eParam, &flOffset))
852 *pflValue = flOffset;
853 else
854 alSetError(AL_INVALID_OPERATION);
855 break;
857 case AL_CONE_INNER_ANGLE:
858 *pflValue = pSource->flInnerAngle;
859 break;
861 case AL_CONE_OUTER_ANGLE:
862 *pflValue = pSource->flOuterAngle;
863 break;
865 case AL_REFERENCE_DISTANCE:
866 *pflValue = pSource->flRefDistance;
867 break;
869 case AL_AIR_ABSORPTION_FACTOR:
870 *pflValue = pSource->AirAbsorptionFactor;
871 break;
873 default:
874 alSetError(AL_INVALID_ENUM);
875 break;
878 else
879 alSetError(AL_INVALID_NAME);
881 else
882 alSetError(AL_INVALID_VALUE);
884 ProcessContext(pContext);
886 else
887 alSetError(AL_INVALID_OPERATION);
889 return;
893 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
895 ALCcontext *pContext;
896 ALsource *pSource;
898 pContext = alcGetCurrentContext();
899 if (pContext)
901 SuspendContext(pContext);
903 if ((pflValue1) && (pflValue2) && (pflValue3))
905 if (alIsSource(source))
907 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
909 switch(eParam)
911 case AL_POSITION:
912 *pflValue1 = pSource->vPosition[0];
913 *pflValue2 = pSource->vPosition[1];
914 *pflValue3 = pSource->vPosition[2];
915 break;
917 case AL_VELOCITY:
918 *pflValue1 = pSource->vVelocity[0];
919 *pflValue2 = pSource->vVelocity[1];
920 *pflValue3 = pSource->vVelocity[2];
921 break;
923 case AL_DIRECTION:
924 *pflValue1 = pSource->vOrientation[0];
925 *pflValue2 = pSource->vOrientation[1];
926 *pflValue3 = pSource->vOrientation[2];
927 break;
929 default:
930 alSetError(AL_INVALID_ENUM);
931 break;
934 else
935 alSetError(AL_INVALID_NAME);
937 else
938 alSetError(AL_INVALID_VALUE);
940 ProcessContext(pContext);
942 else
943 alSetError(AL_INVALID_OPERATION);
945 return;
949 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
951 ALCcontext *pContext;
952 ALsource *pSource;
954 pContext = alcGetCurrentContext();
955 if (pContext)
957 SuspendContext(pContext);
959 if (pflValues)
961 if (alIsSource(source))
963 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
965 switch(eParam)
967 case AL_PITCH:
968 case AL_GAIN:
969 case AL_MIN_GAIN:
970 case AL_MAX_GAIN:
971 case AL_MAX_DISTANCE:
972 case AL_ROLLOFF_FACTOR:
973 case AL_CONE_OUTER_GAIN:
974 case AL_SEC_OFFSET:
975 case AL_SAMPLE_OFFSET:
976 case AL_BYTE_OFFSET:
977 case AL_CONE_INNER_ANGLE:
978 case AL_CONE_OUTER_ANGLE:
979 case AL_REFERENCE_DISTANCE:
980 case AL_CONE_OUTER_GAINHF:
981 case AL_AIR_ABSORPTION_FACTOR:
982 alGetSourcef(source, eParam, pflValues);
983 break;
985 case AL_POSITION:
986 pflValues[0] = pSource->vPosition[0];
987 pflValues[1] = pSource->vPosition[1];
988 pflValues[2] = pSource->vPosition[2];
989 break;
991 case AL_VELOCITY:
992 pflValues[0] = pSource->vVelocity[0];
993 pflValues[1] = pSource->vVelocity[1];
994 pflValues[2] = pSource->vVelocity[2];
995 break;
997 case AL_DIRECTION:
998 pflValues[0] = pSource->vOrientation[0];
999 pflValues[1] = pSource->vOrientation[1];
1000 pflValues[2] = pSource->vOrientation[2];
1001 break;
1003 default:
1004 alSetError(AL_INVALID_ENUM);
1005 break;
1008 else
1009 alSetError(AL_INVALID_NAME);
1011 else
1012 alSetError(AL_INVALID_VALUE);
1014 ProcessContext(pContext);
1016 else
1017 alSetError(AL_INVALID_OPERATION);
1019 return;
1023 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1025 ALCcontext *pContext;
1026 ALsource *pSource;
1027 ALfloat flOffset;
1029 pContext = alcGetCurrentContext();
1030 if (pContext)
1032 SuspendContext(pContext);
1034 if (plValue)
1036 if (alIsSource(source))
1038 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1040 switch(eParam)
1042 case AL_MAX_DISTANCE:
1043 *plValue = (ALint)pSource->flMaxDistance;
1044 break;
1046 case AL_ROLLOFF_FACTOR:
1047 *plValue = (ALint)pSource->flRollOffFactor;
1048 break;
1050 case AL_REFERENCE_DISTANCE:
1051 *plValue = (ALint)pSource->flRefDistance;
1052 break;
1054 case AL_SOURCE_RELATIVE:
1055 *plValue = pSource->bHeadRelative;
1056 break;
1058 case AL_CONE_INNER_ANGLE:
1059 *plValue = (ALint)pSource->flInnerAngle;
1060 break;
1062 case AL_CONE_OUTER_ANGLE:
1063 *plValue = (ALint)pSource->flOuterAngle;
1064 break;
1066 case AL_LOOPING:
1067 *plValue = pSource->bLooping;
1068 break;
1070 case AL_BUFFER:
1071 *plValue = pSource->ulBufferID;
1072 break;
1074 case AL_SOURCE_STATE:
1075 *plValue = pSource->state;
1076 break;
1078 case AL_BUFFERS_QUEUED:
1079 *plValue = pSource->BuffersInQueue;
1080 break;
1082 case AL_BUFFERS_PROCESSED:
1083 if(pSource->bLooping)
1085 /* Buffers on a looping source are in a perpetual state
1086 * of PENDING, so don't report any as PROCESSED */
1087 *plValue = 0;
1089 else
1090 *plValue = pSource->BuffersProcessed;
1091 break;
1093 case AL_SOURCE_TYPE:
1094 *plValue = pSource->lSourceType;
1095 break;
1097 case AL_SEC_OFFSET:
1098 case AL_SAMPLE_OFFSET:
1099 case AL_BYTE_OFFSET:
1100 if (GetSourceOffset(pSource, eParam, &flOffset))
1101 *plValue = (ALint)flOffset;
1102 else
1103 alSetError(AL_INVALID_OPERATION);
1104 break;
1106 case AL_DIRECT_FILTER:
1107 *plValue = pSource->DirectFilter.filter;
1108 break;
1110 case AL_DIRECT_FILTER_GAINHF_AUTO:
1111 *plValue = pSource->DryGainHFAuto;
1112 break;
1114 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1115 *plValue = pSource->WetGainHFAuto;
1116 break;
1118 default:
1119 alSetError(AL_INVALID_ENUM);
1120 break;
1123 else
1124 alSetError(AL_INVALID_NAME);
1126 else
1127 alSetError(AL_INVALID_VALUE);
1129 ProcessContext(pContext);
1131 else
1132 alSetError(AL_INVALID_OPERATION);
1134 return;
1138 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1140 ALCcontext *pContext;
1141 ALsource *pSource;
1143 pContext = alcGetCurrentContext();
1144 if (pContext)
1146 SuspendContext(pContext);
1148 if ((plValue1) && (plValue2) && (plValue3))
1150 if (alIsSource(source))
1152 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1154 switch(eParam)
1156 case AL_POSITION:
1157 *plValue1 = (ALint)pSource->vPosition[0];
1158 *plValue2 = (ALint)pSource->vPosition[1];
1159 *plValue3 = (ALint)pSource->vPosition[2];
1160 break;
1162 case AL_VELOCITY:
1163 *plValue1 = (ALint)pSource->vVelocity[0];
1164 *plValue2 = (ALint)pSource->vVelocity[1];
1165 *plValue3 = (ALint)pSource->vVelocity[2];
1166 break;
1168 case AL_DIRECTION:
1169 *plValue1 = (ALint)pSource->vOrientation[0];
1170 *plValue2 = (ALint)pSource->vOrientation[1];
1171 *plValue3 = (ALint)pSource->vOrientation[2];
1172 break;
1174 default:
1175 alSetError(AL_INVALID_ENUM);
1176 break;
1179 else
1180 alSetError(AL_INVALID_NAME);
1182 else
1183 alSetError(AL_INVALID_VALUE);
1185 ProcessContext(pContext);
1187 else
1188 alSetError(AL_INVALID_OPERATION);
1190 return;
1194 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1196 ALCcontext *pContext;
1197 ALsource *pSource;
1199 pContext = alcGetCurrentContext();
1200 if (pContext)
1202 SuspendContext(pContext);
1204 if (plValues)
1206 if (alIsSource(source))
1208 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1210 switch (eParam)
1212 case AL_SOURCE_RELATIVE:
1213 case AL_CONE_INNER_ANGLE:
1214 case AL_CONE_OUTER_ANGLE:
1215 case AL_LOOPING:
1216 case AL_BUFFER:
1217 case AL_SOURCE_STATE:
1218 case AL_BUFFERS_QUEUED:
1219 case AL_BUFFERS_PROCESSED:
1220 case AL_SEC_OFFSET:
1221 case AL_SAMPLE_OFFSET:
1222 case AL_BYTE_OFFSET:
1223 case AL_MAX_DISTANCE:
1224 case AL_ROLLOFF_FACTOR:
1225 case AL_REFERENCE_DISTANCE:
1226 case AL_SOURCE_TYPE:
1227 case AL_DIRECT_FILTER:
1228 case AL_DIRECT_FILTER_GAINHF_AUTO:
1229 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1230 alGetSourcei(source, eParam, plValues);
1231 break;
1233 case AL_POSITION:
1234 plValues[0] = (ALint)pSource->vPosition[0];
1235 plValues[1] = (ALint)pSource->vPosition[1];
1236 plValues[2] = (ALint)pSource->vPosition[2];
1237 break;
1239 case AL_VELOCITY:
1240 plValues[0] = (ALint)pSource->vVelocity[0];
1241 plValues[1] = (ALint)pSource->vVelocity[1];
1242 plValues[2] = (ALint)pSource->vVelocity[2];
1243 break;
1245 case AL_DIRECTION:
1246 plValues[0] = (ALint)pSource->vOrientation[0];
1247 plValues[1] = (ALint)pSource->vOrientation[1];
1248 plValues[2] = (ALint)pSource->vOrientation[2];
1249 break;
1251 default:
1252 alSetError(AL_INVALID_ENUM);
1253 break;
1256 else
1257 alSetError(AL_INVALID_NAME);
1259 else
1260 alSetError(AL_INVALID_VALUE);
1262 ProcessContext(pContext);
1264 else
1265 alSetError(AL_INVALID_OPERATION);
1267 return;
1271 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1273 alSourcePlayv(1, &source);
1274 return;
1277 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1279 ALCcontext *pContext;
1280 ALsource *pSource;
1281 ALbufferlistitem *ALBufferList;
1282 ALboolean bSourcesValid = AL_TRUE;
1283 ALboolean bPlay;
1284 ALsizei i;
1286 pContext = alcGetCurrentContext();
1287 if (pContext)
1289 SuspendContext(pContext);
1291 if (pSourceList)
1293 // Check that all the Sources are valid
1294 for (i = 0; i < n; i++)
1296 if (!alIsSource(pSourceList[i]))
1298 alSetError(AL_INVALID_NAME);
1299 bSourcesValid = AL_FALSE;
1300 break;
1304 if (bSourcesValid)
1306 for (i = 0; i < n; i++)
1308 // Assume Source won't need to play
1309 bPlay = AL_FALSE;
1311 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1313 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1314 ALBufferList = pSource->queue;
1315 while (ALBufferList)
1317 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1319 bPlay = AL_TRUE;
1320 break;
1322 ALBufferList = ALBufferList->next;
1325 if (bPlay)
1327 if (pSource->state != AL_PAUSED)
1329 pSource->state = AL_PLAYING;
1330 pSource->inuse = AL_TRUE;
1331 pSource->play = AL_TRUE;
1332 pSource->position = 0;
1333 pSource->position_fraction = 0;
1334 pSource->BuffersProcessed = 0;
1335 pSource->BuffersPlayed = 0;
1336 pSource->BufferPosition = 0;
1337 pSource->lBytesPlayed = 0;
1339 pSource->ulBufferID = pSource->queue->buffer;
1341 // Make sure all the Buffers in the queue are marked as PENDING
1342 ALBufferList = pSource->queue;
1343 while (ALBufferList)
1345 ALBufferList->bufferstate = PENDING;
1346 ALBufferList = ALBufferList->next;
1349 else
1351 pSource->state = AL_PLAYING;
1352 pSource->inuse = AL_TRUE;
1353 pSource->play = AL_TRUE;
1356 // Check if an Offset has been set
1357 if (pSource->lOffset)
1358 ApplyOffset(pSource, AL_FALSE);
1360 else
1362 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1363 ALBufferList = pSource->queue;
1364 while (ALBufferList)
1366 ALBufferList->bufferstate = PROCESSED;
1367 ALBufferList = ALBufferList->next;
1370 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1375 else
1377 // sources is a NULL pointer
1378 alSetError(AL_INVALID_VALUE);
1381 ProcessContext(pContext);
1383 else
1385 // Invalid Context
1386 alSetError(AL_INVALID_OPERATION);
1389 return;
1392 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1394 alSourcePausev(1, &source);
1395 return;
1398 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1400 ALCcontext *Context;
1401 ALsource *Source;
1402 ALsizei i;
1403 ALboolean bSourcesValid = AL_TRUE;
1405 Context=alcGetCurrentContext();
1406 if (Context)
1408 SuspendContext(Context);
1410 if (sources)
1412 // Check all the Sources are valid
1413 for (i=0;i<n;i++)
1415 if (!alIsSource(sources[i]))
1417 alSetError(AL_INVALID_NAME);
1418 bSourcesValid = AL_FALSE;
1419 break;
1423 if (bSourcesValid)
1425 for (i=0;i<n;i++)
1427 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1428 if (Source->state==AL_PLAYING)
1430 Source->state=AL_PAUSED;
1431 Source->inuse=AL_FALSE;
1436 else
1438 // sources is a NULL pointer
1439 alSetError(AL_INVALID_VALUE);
1442 ProcessContext(Context);
1444 else
1446 // Invalid Context
1447 alSetError(AL_INVALID_OPERATION);
1450 return;
1453 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1455 alSourceStopv(1, &source);
1456 return;
1459 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1461 ALCcontext *Context;
1462 ALsource *Source;
1463 ALsizei i;
1464 ALbufferlistitem *ALBufferListItem;
1465 ALboolean bSourcesValid = AL_TRUE;
1467 Context=alcGetCurrentContext();
1468 if (Context)
1470 SuspendContext(Context);
1472 if (sources)
1474 // Check all the Sources are valid
1475 for (i=0;i<n;i++)
1477 if (!alIsSource(sources[i]))
1479 alSetError(AL_INVALID_NAME);
1480 bSourcesValid = AL_FALSE;
1481 break;
1485 if (bSourcesValid)
1487 for (i=0;i<n;i++)
1489 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1490 if (Source->state!=AL_INITIAL)
1492 Source->state=AL_STOPPED;
1493 Source->inuse=AL_FALSE;
1494 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1495 ALBufferListItem= Source->queue;
1496 while (ALBufferListItem != NULL)
1498 ALBufferListItem->bufferstate = PROCESSED;
1499 ALBufferListItem = ALBufferListItem->next;
1502 Source->lOffset = 0;
1506 else
1508 // sources is a NULL pointer
1509 alSetError(AL_INVALID_VALUE);
1512 ProcessContext(Context);
1514 else
1516 // Invalid Context
1517 alSetError(AL_INVALID_OPERATION);
1520 return;
1523 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1525 alSourceRewindv(1, &source);
1526 return;
1529 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1531 ALCcontext *Context;
1532 ALsource *Source;
1533 ALsizei i;
1534 ALbufferlistitem *ALBufferListItem;
1535 ALboolean bSourcesValid = AL_TRUE;
1537 Context=alcGetCurrentContext();
1538 if (Context)
1540 SuspendContext(Context);
1542 if (sources)
1544 // Check all the Sources are valid
1545 for (i=0;i<n;i++)
1547 if (!alIsSource(sources[i]))
1549 alSetError(AL_INVALID_NAME);
1550 bSourcesValid = AL_FALSE;
1551 break;
1555 if (bSourcesValid)
1557 for (i=0;i<n;i++)
1559 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1560 if (Source->state!=AL_INITIAL)
1562 Source->state=AL_INITIAL;
1563 Source->inuse=AL_FALSE;
1564 Source->position=0;
1565 Source->position_fraction=0;
1566 Source->BuffersProcessed = 0;
1567 ALBufferListItem= Source->queue;
1568 while (ALBufferListItem != NULL)
1570 ALBufferListItem->bufferstate = PENDING;
1571 ALBufferListItem = ALBufferListItem->next;
1573 if (Source->queue)
1574 Source->ulBufferID = Source->queue->buffer;
1576 Source->lOffset = 0;
1580 else
1582 // sources is a NULL pointer
1583 alSetError(AL_INVALID_VALUE);
1586 ProcessContext(Context);
1588 else
1590 // Invalid Context
1591 alSetError(AL_INVALID_OPERATION);
1594 return;
1598 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1600 ALCcontext *Context;
1601 ALsource *ALSource;
1602 ALsizei i;
1603 ALbufferlistitem *ALBufferList;
1604 ALbufferlistitem *ALBufferListStart;
1605 ALuint DataSize;
1606 ALuint BufferSize;
1607 ALint iFrequency;
1608 ALint iFormat;
1609 ALboolean bBuffersValid = AL_TRUE;
1611 if (n == 0)
1612 return;
1614 Context=alcGetCurrentContext();
1615 if (Context)
1617 SuspendContext(Context);
1619 DataSize = 0;
1620 BufferSize = 0;
1622 // Check that all buffers are valid or zero and that the source is valid
1624 // Check that this is a valid source
1625 if (alIsSource(source))
1627 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1629 // Check that this is not a STATIC Source
1630 if (ALSource->lSourceType != AL_STATIC)
1632 iFrequency = -1;
1633 iFormat = -1;
1635 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1636 ALBufferList = ALSource->queue;
1637 while (ALBufferList)
1639 if (ALBufferList->buffer)
1641 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1642 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1643 break;
1645 ALBufferList = ALBufferList->next;
1648 for (i = 0; i < n; i++)
1650 if (alIsBuffer(buffers[i]))
1652 if (buffers[i])
1654 if ((iFrequency == -1) && (iFormat == -1))
1656 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1657 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1659 else
1661 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1662 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1664 alSetError(AL_INVALID_OPERATION);
1665 bBuffersValid = AL_FALSE;
1666 break;
1671 else
1673 alSetError(AL_INVALID_NAME);
1674 bBuffersValid = AL_FALSE;
1675 break;
1679 if (bBuffersValid)
1681 // Change Source Type
1682 ALSource->lSourceType = AL_STREAMING;
1684 // All buffers are valid - so add them to the list
1685 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1686 ALBufferListStart->buffer = buffers[0];
1687 ALBufferListStart->bufferstate = PENDING;
1688 ALBufferListStart->flag = 0;
1689 ALBufferListStart->next = NULL;
1691 if (buffers[0])
1692 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1693 else
1694 BufferSize = 0;
1696 DataSize += BufferSize;
1698 // Increment reference counter for buffer
1699 if (buffers[0])
1700 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1702 ALBufferList = ALBufferListStart;
1704 for (i = 1; i < n; i++)
1706 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1707 ALBufferList->next->buffer = buffers[i];
1708 ALBufferList->next->bufferstate = PENDING;
1709 ALBufferList->next->flag = 0;
1710 ALBufferList->next->next = NULL;
1712 if (buffers[i])
1713 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1714 else
1715 BufferSize = 0;
1717 DataSize += BufferSize;
1719 // Increment reference counter for buffer
1720 if (buffers[i])
1721 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1723 ALBufferList = ALBufferList->next;
1726 if (ALSource->queue == NULL)
1728 ALSource->queue = ALBufferListStart;
1729 // Update Current Buffer
1730 ALSource->ulBufferID = ALBufferListStart->buffer;
1732 else
1734 // Find end of queue
1735 ALBufferList = ALSource->queue;
1736 while (ALBufferList->next != NULL)
1738 ALBufferList = ALBufferList->next;
1741 ALBufferList->next = ALBufferListStart;
1744 // Update number of buffers in queue
1745 ALSource->BuffersInQueue += n;
1748 else
1750 // Invalid Source Type (can't queue on a Static Source)
1751 alSetError(AL_INVALID_OPERATION);
1754 else
1756 // Invalid Source Name
1757 alSetError(AL_INVALID_NAME);
1760 ProcessContext(Context);
1762 else
1764 // Invalid Context
1765 alSetError(AL_INVALID_OPERATION);
1768 return;
1772 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1773 // an array of buffer IDs that are to be filled with the names of the buffers removed
1774 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1776 ALCcontext *Context;
1777 ALsource *ALSource;
1778 ALsizei i;
1779 ALbufferlistitem *ALBufferList;
1780 ALuint DataSize;
1781 ALuint BufferSize;
1782 ALuint BufferID;
1783 ALboolean bBuffersProcessed;
1785 if (n == 0)
1786 return;
1788 DataSize = 0;
1789 BufferSize = 0;
1790 bBuffersProcessed = AL_TRUE;
1792 Context=alcGetCurrentContext();
1793 if (Context)
1795 SuspendContext(Context);
1797 if (alIsSource(source))
1799 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1801 // Check that all 'n' buffers have been processed
1802 ALBufferList = ALSource->queue;
1803 for (i = 0; i < n; i++)
1805 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1807 ALBufferList = ALBufferList->next;
1809 else
1811 bBuffersProcessed = AL_FALSE;
1812 break;
1816 // If all 'n' buffers have been processed, remove them from the queue
1817 if (bBuffersProcessed)
1819 for (i = 0; i < n; i++)
1821 ALBufferList = ALSource->queue;
1823 ALSource->queue = ALBufferList->next;
1824 // Record name of buffer
1825 buffers[i] = ALBufferList->buffer;
1826 // Decrement buffer reference counter
1827 if (ALBufferList->buffer)
1828 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1829 // Record size of buffer
1830 if (ALBufferList->buffer)
1831 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1832 else
1833 BufferSize = 0;
1835 DataSize += BufferSize;
1836 // Release memory for buffer list item
1837 free(ALBufferList);
1838 ALSource->BuffersInQueue--;
1839 ALSource->BuffersProcessed--;
1842 if (ALSource->state != AL_PLAYING)
1844 if (ALSource->queue)
1845 BufferID = ALSource->queue->buffer;
1846 else
1847 BufferID = 0;
1849 ALSource->ulBufferID = BufferID;
1852 if((ALuint)n > ALSource->BuffersPlayed)
1854 ALSource->BuffersPlayed = 0;
1855 ALSource->BufferPosition = 0;
1857 else
1858 ALSource->BuffersPlayed -= n;
1860 else
1862 // Some buffers can't be unqueue because they have not been processed
1863 alSetError(AL_INVALID_VALUE);
1866 else
1868 // Invalid Source Name
1869 alSetError(AL_INVALID_NAME);
1872 ProcessContext(Context);
1874 else
1876 // Invalid Context
1877 alSetError(AL_INVALID_OPERATION);
1880 return;
1884 static ALvoid InitSourceParams(ALsource *pSource)
1886 pSource->flInnerAngle = 360.0f;
1887 pSource->flOuterAngle = 360.0f;
1888 pSource->flPitch = 1.0f;
1889 pSource->vPosition[0] = 0.0f;
1890 pSource->vPosition[1] = 0.0f;
1891 pSource->vPosition[2] = 0.0f;
1892 pSource->vOrientation[0] = 0.0f;
1893 pSource->vOrientation[1] = 0.0f;
1894 pSource->vOrientation[2] = 0.0f;
1895 pSource->vVelocity[0] = 0.0f;
1896 pSource->vVelocity[1] = 0.0f;
1897 pSource->vVelocity[2] = 0.0f;
1898 pSource->flRefDistance = 1.0f;
1899 pSource->flMaxDistance = FLT_MAX;
1900 pSource->flRollOffFactor = 1.0f;
1901 pSource->bLooping = AL_FALSE;
1902 pSource->flGain = 1.0f;
1903 pSource->flMinGain = 0.0f;
1904 pSource->flMaxGain = 1.0f;
1905 pSource->flOuterGain = 0.0f;
1907 pSource->DryGainHFAuto = AL_TRUE;
1908 pSource->WetGainHFAuto = AL_TRUE;
1909 pSource->AirAbsorptionFactor = 0.0f;
1911 pSource->state = AL_INITIAL;
1912 pSource->lSourceType = AL_UNDETERMINED;
1914 pSource->ulBufferID= 0;
1919 GetSourceOffset
1921 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1922 The offset is relative to the start of the queue (not the start of the current buffer)
1924 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1926 ALbufferlistitem *pBufferList;
1927 ALfloat flBufferFreq;
1928 ALint lBytesPlayed, lChannels;
1929 ALenum eOriginalFormat;
1930 ALboolean bReturn = AL_TRUE;
1931 ALint lTotalBufferDataSize;
1933 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1935 // Get Current Buffer Size and frequency (in milliseconds)
1936 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1937 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1938 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1940 // Get Current BytesPlayed
1941 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1942 // Add byte length of any processed buffers in the queue
1943 pBufferList = pSource->queue;
1944 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1946 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1947 pBufferList = pBufferList->next;
1950 lTotalBufferDataSize = 0;
1951 pBufferList = pSource->queue;
1952 while (pBufferList)
1954 if (pBufferList->buffer)
1955 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1956 pBufferList = pBufferList->next;
1959 if (pSource->bLooping)
1961 if (lBytesPlayed < 0)
1962 lBytesPlayed = 0;
1963 else
1964 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1966 else
1968 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1969 if(lBytesPlayed < 0)
1970 lBytesPlayed = 0;
1971 if(lBytesPlayed > lTotalBufferDataSize)
1972 lBytesPlayed = lTotalBufferDataSize;
1975 switch (eName)
1977 case AL_SEC_OFFSET:
1978 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1979 break;
1980 case AL_SAMPLE_OFFSET:
1981 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1982 break;
1983 case AL_BYTE_OFFSET:
1984 // Take into account the original format of the Buffer
1985 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
1987 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1989 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1991 // Compression rate of the ADPCM supported is 3.6111 to 1
1992 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1993 // Round down to nearest ADPCM block
1994 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1996 else
1998 *pflOffset = (ALfloat)lBytesPlayed;
2000 break;
2003 else
2005 *pflOffset = 0.0f;
2008 return bReturn;
2013 ApplyOffset
2015 Apply a playback offset to the Source. This function will update the queue (to correctly
2016 mark buffers as 'pending' or 'processed' depending upon the new offset.
2018 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2020 ALbufferlistitem *pBufferList;
2021 ALint lBufferSize, lTotalBufferSize;
2022 ALint lByteOffset;
2024 // Get true byte offset
2025 lByteOffset = GetByteOffset(pSource);
2027 // If this is a valid offset apply it
2028 if (lByteOffset != -1)
2030 // Sort out the queue (pending and processed states)
2031 pBufferList = pSource->queue;
2032 lTotalBufferSize = 0;
2033 pSource->BuffersPlayed = 0;
2034 pSource->BuffersProcessed = 0;
2035 while (pBufferList)
2037 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
2039 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2041 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2042 // update the state to PROCESSED
2043 pSource->BuffersPlayed++;
2045 if (!pSource->bLooping)
2047 pBufferList->bufferstate = PROCESSED;
2048 pSource->BuffersProcessed++;
2051 else if (lTotalBufferSize <= lByteOffset)
2053 // Offset is within this buffer
2054 pBufferList->bufferstate = PENDING;
2056 // Set Current Buffer ID
2057 pSource->ulBufferID = pBufferList->buffer;
2059 // Set current position in this buffer
2060 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2062 // Set Total Bytes Played to Offset
2063 pSource->lBytesPlayed = lByteOffset;
2065 // SW Mixer Positions are in Samples
2066 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2068 else
2070 // Offset is before this buffer, so mark as pending
2071 pBufferList->bufferstate = PENDING;
2074 // Increment the TotalBufferSize
2075 lTotalBufferSize += lBufferSize;
2077 // Move on to next buffer in the Queue
2078 pBufferList = pBufferList->next;
2081 else
2083 if (bUpdateContext)
2084 alSetError(AL_INVALID_VALUE);
2087 // Clear Offset
2088 pSource->lOffset = 0;
2093 GetByteOffset
2095 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2096 offset supplied by the application). This takes into account the fact that the buffer format
2097 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2099 static ALint GetByteOffset(ALsource *pSource)
2101 ALbuffer *pBuffer = NULL;
2102 ALbufferlistitem *pBufferList;
2103 ALfloat flBufferFreq;
2104 ALint lChannels;
2105 ALint lByteOffset = -1;
2106 ALint lTotalBufferDataSize;
2108 // Find the first non-NULL Buffer in the Queue
2109 pBufferList = pSource->queue;
2110 while (pBufferList)
2112 if (pBufferList->buffer)
2114 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2115 break;
2117 pBufferList = pBufferList->next;
2120 if (pBuffer)
2122 flBufferFreq = ((ALfloat)pBuffer->frequency);
2123 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2125 // Determine the ByteOffset (and ensure it is block aligned)
2126 switch (pSource->lOffsetType)
2128 case AL_BYTE_OFFSET:
2129 // Take into consideration the original format
2130 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2132 lByteOffset = pSource->lOffset * 2;
2133 lByteOffset -= (lByteOffset % (lChannels * 2));
2135 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2137 // Round down to nearest ADPCM block
2138 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2139 // Multiply by compression rate
2140 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2141 lByteOffset -= (lByteOffset % (lChannels * 2));
2143 else
2145 lByteOffset = pSource->lOffset;
2146 lByteOffset -= (lByteOffset % (lChannels * 2));
2148 break;
2150 case AL_SAMPLE_OFFSET:
2151 lByteOffset = pSource->lOffset * lChannels * 2;
2152 break;
2154 case AL_SEC_OFFSET:
2155 // Note - lOffset is internally stored as Milliseconds
2156 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2157 lByteOffset -= (lByteOffset % (lChannels * 2));
2158 break;
2161 lTotalBufferDataSize = 0;
2162 pBufferList = pSource->queue;
2163 while (pBufferList)
2165 if (pBufferList->buffer)
2166 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2167 pBufferList = pBufferList->next;
2170 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2171 if (lByteOffset >= lTotalBufferDataSize)
2172 lByteOffset = -1;
2175 return lByteOffset;