Implement AL_DIRECT_FILTER_GAINHF_AUTO source property
[openal-soft.git] / OpenAL32 / alSource.c
blobd7d428891afa18e328bca826d06b8a2540f0c0f1
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_SEC_OFFSET:
345 case AL_SAMPLE_OFFSET:
346 case AL_BYTE_OFFSET:
347 if (flValue >= 0.0f)
349 pSource->lOffsetType = eParam;
351 // Store Offset (convert Seconds into Milliseconds)
352 if (eParam == AL_SEC_OFFSET)
353 pSource->lOffset = (ALint)(flValue * 1000.0f);
354 else
355 pSource->lOffset = (ALint)flValue;
357 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
358 ApplyOffset(pSource, AL_TRUE);
360 else
361 alSetError(AL_INVALID_VALUE);
362 break;
364 default:
365 alSetError(AL_INVALID_ENUM);
366 break;
369 else
371 // Invalid Source Name
372 alSetError(AL_INVALID_NAME);
375 ProcessContext(pContext);
377 else
379 // Invalid context
380 alSetError(AL_INVALID_OPERATION);
383 return;
387 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
389 ALCcontext *pContext;
390 ALsource *pSource;
392 pContext = alcGetCurrentContext();
393 if (pContext)
395 SuspendContext(pContext);
397 if (alIsSource(source))
399 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
400 switch(eParam)
402 case AL_POSITION:
403 pSource->vPosition[0] = flValue1;
404 pSource->vPosition[1] = flValue2;
405 pSource->vPosition[2] = flValue3;
406 break;
408 case AL_VELOCITY:
409 pSource->vVelocity[0] = flValue1;
410 pSource->vVelocity[1] = flValue2;
411 pSource->vVelocity[2] = flValue3;
412 break;
414 case AL_DIRECTION:
415 pSource->vOrientation[0] = flValue1;
416 pSource->vOrientation[1] = flValue2;
417 pSource->vOrientation[2] = flValue3;
418 break;
420 default:
421 alSetError(AL_INVALID_ENUM);
422 break;
425 else
426 alSetError(AL_INVALID_NAME);
428 ProcessContext(pContext);
430 else
432 alSetError(AL_INVALID_OPERATION);
435 return;
439 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
441 ALCcontext *pContext;
443 pContext = alcGetCurrentContext();
444 if (pContext)
446 SuspendContext(pContext);
448 if (pflValues)
450 if (alIsSource(source))
452 switch (eParam)
454 case AL_PITCH:
455 case AL_CONE_INNER_ANGLE:
456 case AL_CONE_OUTER_ANGLE:
457 case AL_GAIN:
458 case AL_MAX_DISTANCE:
459 case AL_ROLLOFF_FACTOR:
460 case AL_REFERENCE_DISTANCE:
461 case AL_MIN_GAIN:
462 case AL_MAX_GAIN:
463 case AL_CONE_OUTER_GAIN:
464 case AL_SEC_OFFSET:
465 case AL_SAMPLE_OFFSET:
466 case AL_BYTE_OFFSET:
467 alSourcef(source, eParam, pflValues[0]);
468 break;
470 case AL_POSITION:
471 case AL_VELOCITY:
472 case AL_DIRECTION:
473 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
474 break;
476 default:
477 alSetError(AL_INVALID_ENUM);
478 break;
481 else
482 alSetError(AL_INVALID_NAME);
484 else
485 alSetError(AL_INVALID_VALUE);
487 ProcessContext(pContext);
489 else
490 alSetError(AL_INVALID_OPERATION);
492 return;
496 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
498 ALCcontext *pContext;
499 ALsource *pSource;
500 ALbufferlistitem *pALBufferListItem;
501 ALint Counter = 0;
502 ALint DataSize = 0;
503 ALint BufferSize;
505 pContext = alcGetCurrentContext();
506 if (pContext)
508 SuspendContext(pContext);
510 if (alIsSource(source))
512 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
514 switch(eParam)
516 case AL_MAX_DISTANCE:
517 case AL_ROLLOFF_FACTOR:
518 case AL_REFERENCE_DISTANCE:
519 alSourcef(source, eParam, (ALfloat)lValue);
520 break;
522 case AL_SOURCE_RELATIVE:
523 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
524 pSource->bHeadRelative = (ALboolean)lValue;
525 else
526 alSetError(AL_INVALID_VALUE);
527 break;
529 case AL_CONE_INNER_ANGLE:
530 if ((lValue >= 0) && (lValue <= 360))
531 pSource->flInnerAngle = (float)lValue;
532 else
533 alSetError(AL_INVALID_VALUE);
534 break;
536 case AL_CONE_OUTER_ANGLE:
537 if ((lValue >= 0) && (lValue <= 360))
538 pSource->flOuterAngle = (float)lValue;
539 else
540 alSetError(AL_INVALID_VALUE);
541 break;
543 case AL_LOOPING:
544 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
545 pSource->bLooping = (ALboolean)lValue;
546 else
547 alSetError(AL_INVALID_VALUE);
548 break;
550 case AL_BUFFER:
551 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
553 if (alIsBuffer(lValue))
555 // Remove all elements in the queue
556 while (pSource->queue != NULL)
558 pALBufferListItem = pSource->queue;
559 pSource->queue = pALBufferListItem->next;
560 // Decrement reference counter for buffer
561 if (pALBufferListItem->buffer)
562 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
563 // Record size of buffer
564 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
565 DataSize += BufferSize;
566 // Increment the number of buffers removed from queue
567 Counter++;
568 // Release memory for buffer list item
569 free(pALBufferListItem);
570 // Decrement the number of buffers in the queue
571 pSource->BuffersInQueue--;
574 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
575 if (lValue != 0)
577 // Source is now in STATIC mode
578 pSource->lSourceType = AL_STATIC;
580 // Add the selected buffer to the queue
581 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
582 pALBufferListItem->buffer = lValue;
583 pALBufferListItem->bufferstate = PENDING;
584 pALBufferListItem->flag = 0;
585 pALBufferListItem->next = NULL;
587 pSource->queue = pALBufferListItem;
588 pSource->BuffersInQueue = 1;
590 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
592 // Increment reference counter for buffer
593 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
595 else
597 // Source is now in UNDETERMINED mode
598 pSource->lSourceType = AL_UNDETERMINED;
601 // Set Buffers Processed
602 pSource->BuffersProcessed = 0;
604 // Update AL_BUFFER parameter
605 pSource->ulBufferID = lValue;
607 else
608 alSetError(AL_INVALID_VALUE);
610 else
611 alSetError(AL_INVALID_OPERATION);
612 break;
614 case AL_SOURCE_STATE:
615 // Query only
616 alSetError(AL_INVALID_OPERATION);
617 break;
619 case AL_SEC_OFFSET:
620 case AL_SAMPLE_OFFSET:
621 case AL_BYTE_OFFSET:
622 if (lValue >= 0)
624 pSource->lOffsetType = eParam;
626 // Store Offset (convert Seconds into Milliseconds)
627 if (eParam == AL_SEC_OFFSET)
628 pSource->lOffset = lValue * 1000;
629 else
630 pSource->lOffset = lValue;
632 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
633 ApplyOffset(pSource, AL_TRUE);
635 else
636 alSetError(AL_INVALID_VALUE);
637 break;
639 case AL_DIRECT_FILTER:
640 if(alIsFilter(lValue))
642 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
643 if(!filter)
645 pSource->DirectFilter.type = AL_FILTER_NULL;
646 pSource->DirectFilter.filter = 0;
648 else
649 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
651 else
652 alSetError(AL_INVALID_VALUE);
653 break;
655 case AL_DIRECT_FILTER_GAINHF_AUTO:
656 if(lValue == AL_TRUE || lValue == AL_FALSE)
657 pSource->DryGainHFAuto = lValue;
658 else
659 alSetError(AL_INVALID_VALUE);
660 break;
662 default:
663 alSetError(AL_INVALID_ENUM);
664 break;
667 else
668 alSetError(AL_INVALID_NAME);
670 ProcessContext(pContext);
672 else
673 alSetError(AL_INVALID_OPERATION);
675 return;
679 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
681 ALCcontext *pContext;
683 pContext = alcGetCurrentContext();
684 if (pContext)
686 SuspendContext(pContext);
688 if (alIsSource(source))
690 switch (eParam)
692 case AL_POSITION:
693 case AL_VELOCITY:
694 case AL_DIRECTION:
695 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
696 break;
698 default:
699 alSetError(AL_INVALID_ENUM);
700 break;
703 else
704 alSetError(AL_INVALID_NAME);
706 ProcessContext(pContext);
708 else
709 alSetError(AL_INVALID_OPERATION);
711 return;
715 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
717 ALCcontext *pContext;
719 pContext = alcGetCurrentContext();
720 if (pContext)
722 SuspendContext(pContext);
724 if (plValues)
726 if (alIsSource(source))
728 switch (eParam)
730 case AL_SOURCE_RELATIVE:
731 case AL_CONE_INNER_ANGLE:
732 case AL_CONE_OUTER_ANGLE:
733 case AL_LOOPING:
734 case AL_BUFFER:
735 case AL_SOURCE_STATE:
736 case AL_SEC_OFFSET:
737 case AL_SAMPLE_OFFSET:
738 case AL_BYTE_OFFSET:
739 case AL_MAX_DISTANCE:
740 case AL_ROLLOFF_FACTOR:
741 case AL_REFERENCE_DISTANCE:
742 case AL_DIRECT_FILTER:
743 case AL_DIRECT_FILTER_GAINHF_AUTO:
744 alSourcei(source, eParam, plValues[0]);
745 break;
747 case AL_POSITION:
748 case AL_VELOCITY:
749 case AL_DIRECTION:
750 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
751 break;
753 default:
754 alSetError(AL_INVALID_ENUM);
755 break;
758 else
759 alSetError(AL_INVALID_NAME);
761 else
762 alSetError(AL_INVALID_VALUE);
764 ProcessContext(pContext);
766 else
767 alSetError(AL_INVALID_OPERATION);
769 return;
773 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
775 ALCcontext *pContext;
776 ALsource *pSource;
777 ALfloat flOffset;
779 pContext = alcGetCurrentContext();
780 if (pContext)
782 SuspendContext(pContext);
784 if (pflValue)
786 if (alIsSource(source))
788 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
790 switch(eParam)
792 case AL_PITCH:
793 *pflValue = pSource->flPitch;
794 break;
796 case AL_GAIN:
797 *pflValue = pSource->flGain;
798 break;
800 case AL_MIN_GAIN:
801 *pflValue = pSource->flMinGain;
802 break;
804 case AL_MAX_GAIN:
805 *pflValue = pSource->flMaxGain;
806 break;
808 case AL_MAX_DISTANCE:
809 *pflValue = pSource->flMaxDistance;
810 break;
812 case AL_ROLLOFF_FACTOR:
813 *pflValue = pSource->flRollOffFactor;
814 break;
816 case AL_CONE_OUTER_GAIN:
817 *pflValue = pSource->flOuterGain;
818 break;
820 case AL_SEC_OFFSET:
821 case AL_SAMPLE_OFFSET:
822 case AL_BYTE_OFFSET:
823 if (GetSourceOffset(pSource, eParam, &flOffset))
824 *pflValue = flOffset;
825 else
826 alSetError(AL_INVALID_OPERATION);
827 break;
829 case AL_CONE_INNER_ANGLE:
830 *pflValue = pSource->flInnerAngle;
831 break;
833 case AL_CONE_OUTER_ANGLE:
834 *pflValue = pSource->flOuterAngle;
835 break;
837 case AL_REFERENCE_DISTANCE:
838 *pflValue = pSource->flRefDistance;
839 break;
841 default:
842 alSetError(AL_INVALID_ENUM);
843 break;
846 else
847 alSetError(AL_INVALID_NAME);
849 else
850 alSetError(AL_INVALID_VALUE);
852 ProcessContext(pContext);
854 else
855 alSetError(AL_INVALID_OPERATION);
857 return;
861 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
863 ALCcontext *pContext;
864 ALsource *pSource;
866 pContext = alcGetCurrentContext();
867 if (pContext)
869 SuspendContext(pContext);
871 if ((pflValue1) && (pflValue2) && (pflValue3))
873 if (alIsSource(source))
875 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
877 switch(eParam)
879 case AL_POSITION:
880 *pflValue1 = pSource->vPosition[0];
881 *pflValue2 = pSource->vPosition[1];
882 *pflValue3 = pSource->vPosition[2];
883 break;
885 case AL_VELOCITY:
886 *pflValue1 = pSource->vVelocity[0];
887 *pflValue2 = pSource->vVelocity[1];
888 *pflValue3 = pSource->vVelocity[2];
889 break;
891 case AL_DIRECTION:
892 *pflValue1 = pSource->vOrientation[0];
893 *pflValue2 = pSource->vOrientation[1];
894 *pflValue3 = pSource->vOrientation[2];
895 break;
897 default:
898 alSetError(AL_INVALID_ENUM);
899 break;
902 else
903 alSetError(AL_INVALID_NAME);
905 else
906 alSetError(AL_INVALID_VALUE);
908 ProcessContext(pContext);
910 else
911 alSetError(AL_INVALID_OPERATION);
913 return;
917 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
919 ALCcontext *pContext;
920 ALsource *pSource;
922 pContext = alcGetCurrentContext();
923 if (pContext)
925 SuspendContext(pContext);
927 if (pflValues)
929 if (alIsSource(source))
931 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
933 switch(eParam)
935 case AL_PITCH:
936 case AL_GAIN:
937 case AL_MIN_GAIN:
938 case AL_MAX_GAIN:
939 case AL_MAX_DISTANCE:
940 case AL_ROLLOFF_FACTOR:
941 case AL_CONE_OUTER_GAIN:
942 case AL_SEC_OFFSET:
943 case AL_SAMPLE_OFFSET:
944 case AL_BYTE_OFFSET:
945 case AL_CONE_INNER_ANGLE:
946 case AL_CONE_OUTER_ANGLE:
947 case AL_REFERENCE_DISTANCE:
948 alGetSourcef(source, eParam, pflValues);
949 break;
951 case AL_POSITION:
952 pflValues[0] = pSource->vPosition[0];
953 pflValues[1] = pSource->vPosition[1];
954 pflValues[2] = pSource->vPosition[2];
955 break;
957 case AL_VELOCITY:
958 pflValues[0] = pSource->vVelocity[0];
959 pflValues[1] = pSource->vVelocity[1];
960 pflValues[2] = pSource->vVelocity[2];
961 break;
963 case AL_DIRECTION:
964 pflValues[0] = pSource->vOrientation[0];
965 pflValues[1] = pSource->vOrientation[1];
966 pflValues[2] = pSource->vOrientation[2];
967 break;
969 default:
970 alSetError(AL_INVALID_ENUM);
971 break;
974 else
975 alSetError(AL_INVALID_NAME);
977 else
978 alSetError(AL_INVALID_VALUE);
980 ProcessContext(pContext);
982 else
983 alSetError(AL_INVALID_OPERATION);
985 return;
989 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
991 ALCcontext *pContext;
992 ALsource *pSource;
993 ALfloat flOffset;
995 pContext = alcGetCurrentContext();
996 if (pContext)
998 SuspendContext(pContext);
1000 if (plValue)
1002 if (alIsSource(source))
1004 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1006 switch(eParam)
1008 case AL_MAX_DISTANCE:
1009 *plValue = (ALint)pSource->flMaxDistance;
1010 break;
1012 case AL_ROLLOFF_FACTOR:
1013 *plValue = (ALint)pSource->flRollOffFactor;
1014 break;
1016 case AL_REFERENCE_DISTANCE:
1017 *plValue = (ALint)pSource->flRefDistance;
1018 break;
1020 case AL_SOURCE_RELATIVE:
1021 *plValue = pSource->bHeadRelative;
1022 break;
1024 case AL_CONE_INNER_ANGLE:
1025 *plValue = (ALint)pSource->flInnerAngle;
1026 break;
1028 case AL_CONE_OUTER_ANGLE:
1029 *plValue = (ALint)pSource->flOuterAngle;
1030 break;
1032 case AL_LOOPING:
1033 *plValue = pSource->bLooping;
1034 break;
1036 case AL_BUFFER:
1037 *plValue = pSource->ulBufferID;
1038 break;
1040 case AL_SOURCE_STATE:
1041 *plValue = pSource->state;
1042 break;
1044 case AL_BUFFERS_QUEUED:
1045 *plValue = pSource->BuffersInQueue;
1046 break;
1048 case AL_BUFFERS_PROCESSED:
1049 if(pSource->bLooping)
1051 /* Buffers on a looping source are in a perpetual state
1052 * of PENDING, so don't report any as PROCESSED */
1053 *plValue = 0;
1055 else
1056 *plValue = pSource->BuffersProcessed;
1057 break;
1059 case AL_SOURCE_TYPE:
1060 *plValue = pSource->lSourceType;
1061 break;
1063 case AL_SEC_OFFSET:
1064 case AL_SAMPLE_OFFSET:
1065 case AL_BYTE_OFFSET:
1066 if (GetSourceOffset(pSource, eParam, &flOffset))
1067 *plValue = (ALint)flOffset;
1068 else
1069 alSetError(AL_INVALID_OPERATION);
1070 break;
1072 case AL_DIRECT_FILTER:
1073 *plValue = pSource->DirectFilter.filter;
1074 break;
1076 case AL_DIRECT_FILTER_GAINHF_AUTO:
1077 *plValue = pSource->DryGainHFAuto;
1078 break;
1080 default:
1081 alSetError(AL_INVALID_ENUM);
1082 break;
1085 else
1086 alSetError(AL_INVALID_NAME);
1088 else
1089 alSetError(AL_INVALID_VALUE);
1091 ProcessContext(pContext);
1093 else
1094 alSetError(AL_INVALID_OPERATION);
1096 return;
1100 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1102 ALCcontext *pContext;
1103 ALsource *pSource;
1105 pContext = alcGetCurrentContext();
1106 if (pContext)
1108 SuspendContext(pContext);
1110 if ((plValue1) && (plValue2) && (plValue3))
1112 if (alIsSource(source))
1114 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1116 switch(eParam)
1118 case AL_POSITION:
1119 *plValue1 = (ALint)pSource->vPosition[0];
1120 *plValue2 = (ALint)pSource->vPosition[1];
1121 *plValue3 = (ALint)pSource->vPosition[2];
1122 break;
1124 case AL_VELOCITY:
1125 *plValue1 = (ALint)pSource->vVelocity[0];
1126 *plValue2 = (ALint)pSource->vVelocity[1];
1127 *plValue3 = (ALint)pSource->vVelocity[2];
1128 break;
1130 case AL_DIRECTION:
1131 *plValue1 = (ALint)pSource->vOrientation[0];
1132 *plValue2 = (ALint)pSource->vOrientation[1];
1133 *plValue3 = (ALint)pSource->vOrientation[2];
1134 break;
1136 default:
1137 alSetError(AL_INVALID_ENUM);
1138 break;
1141 else
1142 alSetError(AL_INVALID_NAME);
1144 else
1145 alSetError(AL_INVALID_VALUE);
1147 ProcessContext(pContext);
1149 else
1150 alSetError(AL_INVALID_OPERATION);
1152 return;
1156 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1158 ALCcontext *pContext;
1159 ALsource *pSource;
1161 pContext = alcGetCurrentContext();
1162 if (pContext)
1164 SuspendContext(pContext);
1166 if (plValues)
1168 if (alIsSource(source))
1170 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1172 switch (eParam)
1174 case AL_SOURCE_RELATIVE:
1175 case AL_CONE_INNER_ANGLE:
1176 case AL_CONE_OUTER_ANGLE:
1177 case AL_LOOPING:
1178 case AL_BUFFER:
1179 case AL_SOURCE_STATE:
1180 case AL_BUFFERS_QUEUED:
1181 case AL_BUFFERS_PROCESSED:
1182 case AL_SEC_OFFSET:
1183 case AL_SAMPLE_OFFSET:
1184 case AL_BYTE_OFFSET:
1185 case AL_MAX_DISTANCE:
1186 case AL_ROLLOFF_FACTOR:
1187 case AL_REFERENCE_DISTANCE:
1188 case AL_SOURCE_TYPE:
1189 case AL_DIRECT_FILTER:
1190 case AL_DIRECT_FILTER_GAINHF_AUTO:
1191 alGetSourcei(source, eParam, plValues);
1192 break;
1194 case AL_POSITION:
1195 plValues[0] = (ALint)pSource->vPosition[0];
1196 plValues[1] = (ALint)pSource->vPosition[1];
1197 plValues[2] = (ALint)pSource->vPosition[2];
1198 break;
1200 case AL_VELOCITY:
1201 plValues[0] = (ALint)pSource->vVelocity[0];
1202 plValues[1] = (ALint)pSource->vVelocity[1];
1203 plValues[2] = (ALint)pSource->vVelocity[2];
1204 break;
1206 case AL_DIRECTION:
1207 plValues[0] = (ALint)pSource->vOrientation[0];
1208 plValues[1] = (ALint)pSource->vOrientation[1];
1209 plValues[2] = (ALint)pSource->vOrientation[2];
1210 break;
1212 default:
1213 alSetError(AL_INVALID_ENUM);
1214 break;
1217 else
1218 alSetError(AL_INVALID_NAME);
1220 else
1221 alSetError(AL_INVALID_VALUE);
1223 ProcessContext(pContext);
1225 else
1226 alSetError(AL_INVALID_OPERATION);
1228 return;
1232 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1234 alSourcePlayv(1, &source);
1235 return;
1238 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1240 ALCcontext *pContext;
1241 ALsource *pSource;
1242 ALbufferlistitem *ALBufferList;
1243 ALboolean bSourcesValid = AL_TRUE;
1244 ALboolean bPlay;
1245 ALsizei i;
1247 pContext = alcGetCurrentContext();
1248 if (pContext)
1250 SuspendContext(pContext);
1252 if (pSourceList)
1254 // Check that all the Sources are valid
1255 for (i = 0; i < n; i++)
1257 if (!alIsSource(pSourceList[i]))
1259 alSetError(AL_INVALID_NAME);
1260 bSourcesValid = AL_FALSE;
1261 break;
1265 if (bSourcesValid)
1267 for (i = 0; i < n; i++)
1269 // Assume Source won't need to play
1270 bPlay = AL_FALSE;
1272 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1274 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1275 ALBufferList = pSource->queue;
1276 while (ALBufferList)
1278 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1280 bPlay = AL_TRUE;
1281 break;
1283 ALBufferList = ALBufferList->next;
1286 if (bPlay)
1288 if (pSource->state != AL_PAUSED)
1290 pSource->state = AL_PLAYING;
1291 pSource->inuse = AL_TRUE;
1292 pSource->play = AL_TRUE;
1293 pSource->position = 0;
1294 pSource->position_fraction = 0;
1295 pSource->BuffersProcessed = 0;
1296 pSource->BuffersPlayed = 0;
1297 pSource->BufferPosition = 0;
1298 pSource->lBytesPlayed = 0;
1300 pSource->ulBufferID = pSource->queue->buffer;
1302 // Make sure all the Buffers in the queue are marked as PENDING
1303 ALBufferList = pSource->queue;
1304 while (ALBufferList)
1306 ALBufferList->bufferstate = PENDING;
1307 ALBufferList = ALBufferList->next;
1310 else
1312 pSource->state = AL_PLAYING;
1313 pSource->inuse = AL_TRUE;
1314 pSource->play = AL_TRUE;
1317 // Check if an Offset has been set
1318 if (pSource->lOffset)
1319 ApplyOffset(pSource, AL_FALSE);
1321 else
1323 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1324 ALBufferList = pSource->queue;
1325 while (ALBufferList)
1327 ALBufferList->bufferstate = PROCESSED;
1328 ALBufferList = ALBufferList->next;
1331 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1336 else
1338 // sources is a NULL pointer
1339 alSetError(AL_INVALID_VALUE);
1342 ProcessContext(pContext);
1344 else
1346 // Invalid Context
1347 alSetError(AL_INVALID_OPERATION);
1350 return;
1353 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1355 alSourcePausev(1, &source);
1356 return;
1359 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1361 ALCcontext *Context;
1362 ALsource *Source;
1363 ALsizei i;
1364 ALboolean bSourcesValid = AL_TRUE;
1366 Context=alcGetCurrentContext();
1367 if (Context)
1369 SuspendContext(Context);
1371 if (sources)
1373 // Check all the Sources are valid
1374 for (i=0;i<n;i++)
1376 if (!alIsSource(sources[i]))
1378 alSetError(AL_INVALID_NAME);
1379 bSourcesValid = AL_FALSE;
1380 break;
1384 if (bSourcesValid)
1386 for (i=0;i<n;i++)
1388 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1389 if (Source->state==AL_PLAYING)
1391 Source->state=AL_PAUSED;
1392 Source->inuse=AL_FALSE;
1397 else
1399 // sources is a NULL pointer
1400 alSetError(AL_INVALID_VALUE);
1403 ProcessContext(Context);
1405 else
1407 // Invalid Context
1408 alSetError(AL_INVALID_OPERATION);
1411 return;
1414 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1416 alSourceStopv(1, &source);
1417 return;
1420 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1422 ALCcontext *Context;
1423 ALsource *Source;
1424 ALsizei i;
1425 ALbufferlistitem *ALBufferListItem;
1426 ALboolean bSourcesValid = AL_TRUE;
1428 Context=alcGetCurrentContext();
1429 if (Context)
1431 SuspendContext(Context);
1433 if (sources)
1435 // Check all the Sources are valid
1436 for (i=0;i<n;i++)
1438 if (!alIsSource(sources[i]))
1440 alSetError(AL_INVALID_NAME);
1441 bSourcesValid = AL_FALSE;
1442 break;
1446 if (bSourcesValid)
1448 for (i=0;i<n;i++)
1450 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1451 if (Source->state!=AL_INITIAL)
1453 Source->state=AL_STOPPED;
1454 Source->inuse=AL_FALSE;
1455 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1456 ALBufferListItem= Source->queue;
1457 while (ALBufferListItem != NULL)
1459 ALBufferListItem->bufferstate = PROCESSED;
1460 ALBufferListItem = ALBufferListItem->next;
1463 Source->lOffset = 0;
1467 else
1469 // sources is a NULL pointer
1470 alSetError(AL_INVALID_VALUE);
1473 ProcessContext(Context);
1475 else
1477 // Invalid Context
1478 alSetError(AL_INVALID_OPERATION);
1481 return;
1484 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1486 alSourceRewindv(1, &source);
1487 return;
1490 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1492 ALCcontext *Context;
1493 ALsource *Source;
1494 ALsizei i;
1495 ALbufferlistitem *ALBufferListItem;
1496 ALboolean bSourcesValid = AL_TRUE;
1498 Context=alcGetCurrentContext();
1499 if (Context)
1501 SuspendContext(Context);
1503 if (sources)
1505 // Check all the Sources are valid
1506 for (i=0;i<n;i++)
1508 if (!alIsSource(sources[i]))
1510 alSetError(AL_INVALID_NAME);
1511 bSourcesValid = AL_FALSE;
1512 break;
1516 if (bSourcesValid)
1518 for (i=0;i<n;i++)
1520 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1521 if (Source->state!=AL_INITIAL)
1523 Source->state=AL_INITIAL;
1524 Source->inuse=AL_FALSE;
1525 Source->position=0;
1526 Source->position_fraction=0;
1527 Source->BuffersProcessed = 0;
1528 ALBufferListItem= Source->queue;
1529 while (ALBufferListItem != NULL)
1531 ALBufferListItem->bufferstate = PENDING;
1532 ALBufferListItem = ALBufferListItem->next;
1534 if (Source->queue)
1535 Source->ulBufferID = Source->queue->buffer;
1537 Source->lOffset = 0;
1541 else
1543 // sources is a NULL pointer
1544 alSetError(AL_INVALID_VALUE);
1547 ProcessContext(Context);
1549 else
1551 // Invalid Context
1552 alSetError(AL_INVALID_OPERATION);
1555 return;
1559 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1561 ALCcontext *Context;
1562 ALsource *ALSource;
1563 ALsizei i;
1564 ALbufferlistitem *ALBufferList;
1565 ALbufferlistitem *ALBufferListStart;
1566 ALuint DataSize;
1567 ALuint BufferSize;
1568 ALint iFrequency;
1569 ALint iFormat;
1570 ALboolean bBuffersValid = AL_TRUE;
1572 if (n == 0)
1573 return;
1575 Context=alcGetCurrentContext();
1576 if (Context)
1578 SuspendContext(Context);
1580 DataSize = 0;
1581 BufferSize = 0;
1583 // Check that all buffers are valid or zero and that the source is valid
1585 // Check that this is a valid source
1586 if (alIsSource(source))
1588 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1590 // Check that this is not a STATIC Source
1591 if (ALSource->lSourceType != AL_STATIC)
1593 iFrequency = -1;
1594 iFormat = -1;
1596 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1597 ALBufferList = ALSource->queue;
1598 while (ALBufferList)
1600 if (ALBufferList->buffer)
1602 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1603 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1604 break;
1606 ALBufferList = ALBufferList->next;
1609 for (i = 0; i < n; i++)
1611 if (alIsBuffer(buffers[i]))
1613 if (buffers[i])
1615 if ((iFrequency == -1) && (iFormat == -1))
1617 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1618 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1620 else
1622 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1623 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1625 alSetError(AL_INVALID_OPERATION);
1626 bBuffersValid = AL_FALSE;
1627 break;
1632 else
1634 alSetError(AL_INVALID_NAME);
1635 bBuffersValid = AL_FALSE;
1636 break;
1640 if (bBuffersValid)
1642 // Change Source Type
1643 ALSource->lSourceType = AL_STREAMING;
1645 // All buffers are valid - so add them to the list
1646 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1647 ALBufferListStart->buffer = buffers[0];
1648 ALBufferListStart->bufferstate = PENDING;
1649 ALBufferListStart->flag = 0;
1650 ALBufferListStart->next = NULL;
1652 if (buffers[0])
1653 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1654 else
1655 BufferSize = 0;
1657 DataSize += BufferSize;
1659 // Increment reference counter for buffer
1660 if (buffers[0])
1661 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1663 ALBufferList = ALBufferListStart;
1665 for (i = 1; i < n; i++)
1667 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1668 ALBufferList->next->buffer = buffers[i];
1669 ALBufferList->next->bufferstate = PENDING;
1670 ALBufferList->next->flag = 0;
1671 ALBufferList->next->next = NULL;
1673 if (buffers[i])
1674 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1675 else
1676 BufferSize = 0;
1678 DataSize += BufferSize;
1680 // Increment reference counter for buffer
1681 if (buffers[i])
1682 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1684 ALBufferList = ALBufferList->next;
1687 if (ALSource->queue == NULL)
1689 ALSource->queue = ALBufferListStart;
1690 // Update Current Buffer
1691 ALSource->ulBufferID = ALBufferListStart->buffer;
1693 else
1695 // Find end of queue
1696 ALBufferList = ALSource->queue;
1697 while (ALBufferList->next != NULL)
1699 ALBufferList = ALBufferList->next;
1702 ALBufferList->next = ALBufferListStart;
1705 // Update number of buffers in queue
1706 ALSource->BuffersInQueue += n;
1709 else
1711 // Invalid Source Type (can't queue on a Static Source)
1712 alSetError(AL_INVALID_OPERATION);
1715 else
1717 // Invalid Source Name
1718 alSetError(AL_INVALID_NAME);
1721 ProcessContext(Context);
1723 else
1725 // Invalid Context
1726 alSetError(AL_INVALID_OPERATION);
1729 return;
1733 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1734 // an array of buffer IDs that are to be filled with the names of the buffers removed
1735 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1737 ALCcontext *Context;
1738 ALsource *ALSource;
1739 ALsizei i;
1740 ALbufferlistitem *ALBufferList;
1741 ALuint DataSize;
1742 ALuint BufferSize;
1743 ALuint BufferID;
1744 ALboolean bBuffersProcessed;
1746 if (n == 0)
1747 return;
1749 DataSize = 0;
1750 BufferSize = 0;
1751 bBuffersProcessed = AL_TRUE;
1753 Context=alcGetCurrentContext();
1754 if (Context)
1756 SuspendContext(Context);
1758 if (alIsSource(source))
1760 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1762 // Check that all 'n' buffers have been processed
1763 ALBufferList = ALSource->queue;
1764 for (i = 0; i < n; i++)
1766 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1768 ALBufferList = ALBufferList->next;
1770 else
1772 bBuffersProcessed = AL_FALSE;
1773 break;
1777 // If all 'n' buffers have been processed, remove them from the queue
1778 if (bBuffersProcessed)
1780 for (i = 0; i < n; i++)
1782 ALBufferList = ALSource->queue;
1784 ALSource->queue = ALBufferList->next;
1785 // Record name of buffer
1786 buffers[i] = ALBufferList->buffer;
1787 // Decrement buffer reference counter
1788 if (ALBufferList->buffer)
1789 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1790 // Record size of buffer
1791 if (ALBufferList->buffer)
1792 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1793 else
1794 BufferSize = 0;
1796 DataSize += BufferSize;
1797 // Release memory for buffer list item
1798 free(ALBufferList);
1799 ALSource->BuffersInQueue--;
1800 ALSource->BuffersProcessed--;
1803 if (ALSource->state != AL_PLAYING)
1805 if (ALSource->queue)
1806 BufferID = ALSource->queue->buffer;
1807 else
1808 BufferID = 0;
1810 ALSource->ulBufferID = BufferID;
1813 if((ALuint)n > ALSource->BuffersPlayed)
1815 ALSource->BuffersPlayed = 0;
1816 ALSource->BufferPosition = 0;
1818 else
1819 ALSource->BuffersPlayed -= n;
1821 else
1823 // Some buffers can't be unqueue because they have not been processed
1824 alSetError(AL_INVALID_VALUE);
1827 else
1829 // Invalid Source Name
1830 alSetError(AL_INVALID_NAME);
1833 ProcessContext(Context);
1835 else
1837 // Invalid Context
1838 alSetError(AL_INVALID_OPERATION);
1841 return;
1845 static ALvoid InitSourceParams(ALsource *pSource)
1847 pSource->flInnerAngle = 360.0f;
1848 pSource->flOuterAngle = 360.0f;
1849 pSource->flPitch = 1.0f;
1850 pSource->vPosition[0] = 0.0f;
1851 pSource->vPosition[1] = 0.0f;
1852 pSource->vPosition[2] = 0.0f;
1853 pSource->vOrientation[0] = 0.0f;
1854 pSource->vOrientation[1] = 0.0f;
1855 pSource->vOrientation[2] = 0.0f;
1856 pSource->vVelocity[0] = 0.0f;
1857 pSource->vVelocity[1] = 0.0f;
1858 pSource->vVelocity[2] = 0.0f;
1859 pSource->flRefDistance = 1.0f;
1860 pSource->flMaxDistance = FLT_MAX;
1861 pSource->flRollOffFactor = 1.0f;
1862 pSource->bLooping = AL_FALSE;
1863 pSource->flGain = 1.0f;
1864 pSource->flMinGain = 0.0f;
1865 pSource->flMaxGain = 1.0f;
1866 pSource->flOuterGain = 0.0f;
1868 pSource->DryGainHFAuto = AL_TRUE;
1870 pSource->state = AL_INITIAL;
1871 pSource->lSourceType = AL_UNDETERMINED;
1873 pSource->ulBufferID= 0;
1878 GetSourceOffset
1880 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1881 The offset is relative to the start of the queue (not the start of the current buffer)
1883 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1885 ALbufferlistitem *pBufferList;
1886 ALfloat flBufferFreq;
1887 ALint lBytesPlayed, lChannels;
1888 ALenum eOriginalFormat;
1889 ALboolean bReturn = AL_TRUE;
1890 ALint lTotalBufferDataSize;
1892 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1894 // Get Current Buffer Size and frequency (in milliseconds)
1895 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1896 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1897 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1899 // Get Current BytesPlayed
1900 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1901 // Add byte length of any processed buffers in the queue
1902 pBufferList = pSource->queue;
1903 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1905 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1906 pBufferList = pBufferList->next;
1909 lTotalBufferDataSize = 0;
1910 pBufferList = pSource->queue;
1911 while (pBufferList)
1913 if (pBufferList->buffer)
1914 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1915 pBufferList = pBufferList->next;
1918 if (pSource->bLooping)
1920 if (lBytesPlayed < 0)
1921 lBytesPlayed = 0;
1922 else
1923 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1925 else
1927 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1928 if(lBytesPlayed < 0)
1929 lBytesPlayed = 0;
1930 if(lBytesPlayed > lTotalBufferDataSize)
1931 lBytesPlayed = lTotalBufferDataSize;
1934 switch (eName)
1936 case AL_SEC_OFFSET:
1937 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1938 break;
1939 case AL_SAMPLE_OFFSET:
1940 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1941 break;
1942 case AL_BYTE_OFFSET:
1943 // Take into account the original format of the Buffer
1944 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
1946 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1948 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1950 // Compression rate of the ADPCM supported is 3.6111 to 1
1951 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1952 // Round down to nearest ADPCM block
1953 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1955 else
1957 *pflOffset = (ALfloat)lBytesPlayed;
1959 break;
1962 else
1964 *pflOffset = 0.0f;
1967 return bReturn;
1972 ApplyOffset
1974 Apply a playback offset to the Source. This function will update the queue (to correctly
1975 mark buffers as 'pending' or 'processed' depending upon the new offset.
1977 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1979 ALbufferlistitem *pBufferList;
1980 ALint lBufferSize, lTotalBufferSize;
1981 ALint lByteOffset;
1983 // Get true byte offset
1984 lByteOffset = GetByteOffset(pSource);
1986 // If this is a valid offset apply it
1987 if (lByteOffset != -1)
1989 // Sort out the queue (pending and processed states)
1990 pBufferList = pSource->queue;
1991 lTotalBufferSize = 0;
1992 pSource->BuffersPlayed = 0;
1993 pSource->BuffersProcessed = 0;
1994 while (pBufferList)
1996 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
1998 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2000 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2001 // update the state to PROCESSED
2002 pSource->BuffersPlayed++;
2004 if (!pSource->bLooping)
2006 pBufferList->bufferstate = PROCESSED;
2007 pSource->BuffersProcessed++;
2010 else if (lTotalBufferSize <= lByteOffset)
2012 // Offset is within this buffer
2013 pBufferList->bufferstate = PENDING;
2015 // Set Current Buffer ID
2016 pSource->ulBufferID = pBufferList->buffer;
2018 // Set current position in this buffer
2019 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2021 // Set Total Bytes Played to Offset
2022 pSource->lBytesPlayed = lByteOffset;
2024 // SW Mixer Positions are in Samples
2025 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2027 else
2029 // Offset is before this buffer, so mark as pending
2030 pBufferList->bufferstate = PENDING;
2033 // Increment the TotalBufferSize
2034 lTotalBufferSize += lBufferSize;
2036 // Move on to next buffer in the Queue
2037 pBufferList = pBufferList->next;
2040 else
2042 if (bUpdateContext)
2043 alSetError(AL_INVALID_VALUE);
2046 // Clear Offset
2047 pSource->lOffset = 0;
2052 GetByteOffset
2054 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2055 offset supplied by the application). This takes into account the fact that the buffer format
2056 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2058 static ALint GetByteOffset(ALsource *pSource)
2060 ALbuffer *pBuffer = NULL;
2061 ALbufferlistitem *pBufferList;
2062 ALfloat flBufferFreq;
2063 ALint lChannels;
2064 ALint lByteOffset = -1;
2065 ALint lTotalBufferDataSize;
2067 // Find the first non-NULL Buffer in the Queue
2068 pBufferList = pSource->queue;
2069 while (pBufferList)
2071 if (pBufferList->buffer)
2073 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2074 break;
2076 pBufferList = pBufferList->next;
2079 if (pBuffer)
2081 flBufferFreq = ((ALfloat)pBuffer->frequency);
2082 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2084 // Determine the ByteOffset (and ensure it is block aligned)
2085 switch (pSource->lOffsetType)
2087 case AL_BYTE_OFFSET:
2088 // Take into consideration the original format
2089 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2091 lByteOffset = pSource->lOffset * 2;
2092 lByteOffset -= (lByteOffset % (lChannels * 2));
2094 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2096 // Round down to nearest ADPCM block
2097 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2098 // Multiply by compression rate
2099 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2100 lByteOffset -= (lByteOffset % (lChannels * 2));
2102 else
2104 lByteOffset = pSource->lOffset;
2105 lByteOffset -= (lByteOffset % (lChannels * 2));
2107 break;
2109 case AL_SAMPLE_OFFSET:
2110 lByteOffset = pSource->lOffset * lChannels * 2;
2111 break;
2113 case AL_SEC_OFFSET:
2114 // Note - lOffset is internally stored as Milliseconds
2115 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2116 lByteOffset -= (lByteOffset % (lChannels * 2));
2117 break;
2120 lTotalBufferDataSize = 0;
2121 pBufferList = pSource->queue;
2122 while (pBufferList)
2124 if (pBufferList->buffer)
2125 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2126 pBufferList = pBufferList->next;
2129 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2130 if (lByteOffset >= lTotalBufferDataSize)
2131 lByteOffset = -1;
2134 return lByteOffset;