Implement AL_CONE_OUTER_GAINHF source property
[openal-soft.git] / OpenAL32 / alSource.c
blob1e30b1dbf3564ff44de33ef59a84b4ccb452ef53
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_SEC_OFFSET:
352 case AL_SAMPLE_OFFSET:
353 case AL_BYTE_OFFSET:
354 if (flValue >= 0.0f)
356 pSource->lOffsetType = eParam;
358 // Store Offset (convert Seconds into Milliseconds)
359 if (eParam == AL_SEC_OFFSET)
360 pSource->lOffset = (ALint)(flValue * 1000.0f);
361 else
362 pSource->lOffset = (ALint)flValue;
364 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
365 ApplyOffset(pSource, AL_TRUE);
367 else
368 alSetError(AL_INVALID_VALUE);
369 break;
371 default:
372 alSetError(AL_INVALID_ENUM);
373 break;
376 else
378 // Invalid Source Name
379 alSetError(AL_INVALID_NAME);
382 ProcessContext(pContext);
384 else
386 // Invalid context
387 alSetError(AL_INVALID_OPERATION);
390 return;
394 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
396 ALCcontext *pContext;
397 ALsource *pSource;
399 pContext = alcGetCurrentContext();
400 if (pContext)
402 SuspendContext(pContext);
404 if (alIsSource(source))
406 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
407 switch(eParam)
409 case AL_POSITION:
410 pSource->vPosition[0] = flValue1;
411 pSource->vPosition[1] = flValue2;
412 pSource->vPosition[2] = flValue3;
413 break;
415 case AL_VELOCITY:
416 pSource->vVelocity[0] = flValue1;
417 pSource->vVelocity[1] = flValue2;
418 pSource->vVelocity[2] = flValue3;
419 break;
421 case AL_DIRECTION:
422 pSource->vOrientation[0] = flValue1;
423 pSource->vOrientation[1] = flValue2;
424 pSource->vOrientation[2] = flValue3;
425 break;
427 default:
428 alSetError(AL_INVALID_ENUM);
429 break;
432 else
433 alSetError(AL_INVALID_NAME);
435 ProcessContext(pContext);
437 else
439 alSetError(AL_INVALID_OPERATION);
442 return;
446 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
448 ALCcontext *pContext;
450 pContext = alcGetCurrentContext();
451 if (pContext)
453 SuspendContext(pContext);
455 if (pflValues)
457 if (alIsSource(source))
459 switch (eParam)
461 case AL_PITCH:
462 case AL_CONE_INNER_ANGLE:
463 case AL_CONE_OUTER_ANGLE:
464 case AL_GAIN:
465 case AL_MAX_DISTANCE:
466 case AL_ROLLOFF_FACTOR:
467 case AL_REFERENCE_DISTANCE:
468 case AL_MIN_GAIN:
469 case AL_MAX_GAIN:
470 case AL_CONE_OUTER_GAIN:
471 case AL_CONE_OUTER_GAINHF:
472 case AL_SEC_OFFSET:
473 case AL_SAMPLE_OFFSET:
474 case AL_BYTE_OFFSET:
475 alSourcef(source, eParam, pflValues[0]);
476 break;
478 case AL_POSITION:
479 case AL_VELOCITY:
480 case AL_DIRECTION:
481 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
482 break;
484 default:
485 alSetError(AL_INVALID_ENUM);
486 break;
489 else
490 alSetError(AL_INVALID_NAME);
492 else
493 alSetError(AL_INVALID_VALUE);
495 ProcessContext(pContext);
497 else
498 alSetError(AL_INVALID_OPERATION);
500 return;
504 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
506 ALCcontext *pContext;
507 ALsource *pSource;
508 ALbufferlistitem *pALBufferListItem;
509 ALint Counter = 0;
510 ALint DataSize = 0;
511 ALint BufferSize;
513 pContext = alcGetCurrentContext();
514 if (pContext)
516 SuspendContext(pContext);
518 if (alIsSource(source))
520 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
522 switch(eParam)
524 case AL_MAX_DISTANCE:
525 case AL_ROLLOFF_FACTOR:
526 case AL_REFERENCE_DISTANCE:
527 alSourcef(source, eParam, (ALfloat)lValue);
528 break;
530 case AL_SOURCE_RELATIVE:
531 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
532 pSource->bHeadRelative = (ALboolean)lValue;
533 else
534 alSetError(AL_INVALID_VALUE);
535 break;
537 case AL_CONE_INNER_ANGLE:
538 if ((lValue >= 0) && (lValue <= 360))
539 pSource->flInnerAngle = (float)lValue;
540 else
541 alSetError(AL_INVALID_VALUE);
542 break;
544 case AL_CONE_OUTER_ANGLE:
545 if ((lValue >= 0) && (lValue <= 360))
546 pSource->flOuterAngle = (float)lValue;
547 else
548 alSetError(AL_INVALID_VALUE);
549 break;
551 case AL_LOOPING:
552 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
553 pSource->bLooping = (ALboolean)lValue;
554 else
555 alSetError(AL_INVALID_VALUE);
556 break;
558 case AL_BUFFER:
559 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
561 if (alIsBuffer(lValue))
563 // Remove all elements in the queue
564 while (pSource->queue != NULL)
566 pALBufferListItem = pSource->queue;
567 pSource->queue = pALBufferListItem->next;
568 // Decrement reference counter for buffer
569 if (pALBufferListItem->buffer)
570 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
571 // Record size of buffer
572 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
573 DataSize += BufferSize;
574 // Increment the number of buffers removed from queue
575 Counter++;
576 // Release memory for buffer list item
577 free(pALBufferListItem);
578 // Decrement the number of buffers in the queue
579 pSource->BuffersInQueue--;
582 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
583 if (lValue != 0)
585 // Source is now in STATIC mode
586 pSource->lSourceType = AL_STATIC;
588 // Add the selected buffer to the queue
589 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
590 pALBufferListItem->buffer = lValue;
591 pALBufferListItem->bufferstate = PENDING;
592 pALBufferListItem->flag = 0;
593 pALBufferListItem->next = NULL;
595 pSource->queue = pALBufferListItem;
596 pSource->BuffersInQueue = 1;
598 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
600 // Increment reference counter for buffer
601 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
603 else
605 // Source is now in UNDETERMINED mode
606 pSource->lSourceType = AL_UNDETERMINED;
609 // Set Buffers Processed
610 pSource->BuffersProcessed = 0;
612 // Update AL_BUFFER parameter
613 pSource->ulBufferID = lValue;
615 else
616 alSetError(AL_INVALID_VALUE);
618 else
619 alSetError(AL_INVALID_OPERATION);
620 break;
622 case AL_SOURCE_STATE:
623 // Query only
624 alSetError(AL_INVALID_OPERATION);
625 break;
627 case AL_SEC_OFFSET:
628 case AL_SAMPLE_OFFSET:
629 case AL_BYTE_OFFSET:
630 if (lValue >= 0)
632 pSource->lOffsetType = eParam;
634 // Store Offset (convert Seconds into Milliseconds)
635 if (eParam == AL_SEC_OFFSET)
636 pSource->lOffset = lValue * 1000;
637 else
638 pSource->lOffset = lValue;
640 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
641 ApplyOffset(pSource, AL_TRUE);
643 else
644 alSetError(AL_INVALID_VALUE);
645 break;
647 case AL_DIRECT_FILTER:
648 if(alIsFilter(lValue))
650 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
651 if(!filter)
653 pSource->DirectFilter.type = AL_FILTER_NULL;
654 pSource->DirectFilter.filter = 0;
656 else
657 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
659 else
660 alSetError(AL_INVALID_VALUE);
661 break;
663 case AL_DIRECT_FILTER_GAINHF_AUTO:
664 if(lValue == AL_TRUE || lValue == AL_FALSE)
665 pSource->DryGainHFAuto = lValue;
666 else
667 alSetError(AL_INVALID_VALUE);
668 break;
670 default:
671 alSetError(AL_INVALID_ENUM);
672 break;
675 else
676 alSetError(AL_INVALID_NAME);
678 ProcessContext(pContext);
680 else
681 alSetError(AL_INVALID_OPERATION);
683 return;
687 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
689 ALCcontext *pContext;
691 pContext = alcGetCurrentContext();
692 if (pContext)
694 SuspendContext(pContext);
696 if (alIsSource(source))
698 switch (eParam)
700 case AL_POSITION:
701 case AL_VELOCITY:
702 case AL_DIRECTION:
703 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
704 break;
706 default:
707 alSetError(AL_INVALID_ENUM);
708 break;
711 else
712 alSetError(AL_INVALID_NAME);
714 ProcessContext(pContext);
716 else
717 alSetError(AL_INVALID_OPERATION);
719 return;
723 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
725 ALCcontext *pContext;
727 pContext = alcGetCurrentContext();
728 if (pContext)
730 SuspendContext(pContext);
732 if (plValues)
734 if (alIsSource(source))
736 switch (eParam)
738 case AL_SOURCE_RELATIVE:
739 case AL_CONE_INNER_ANGLE:
740 case AL_CONE_OUTER_ANGLE:
741 case AL_LOOPING:
742 case AL_BUFFER:
743 case AL_SOURCE_STATE:
744 case AL_SEC_OFFSET:
745 case AL_SAMPLE_OFFSET:
746 case AL_BYTE_OFFSET:
747 case AL_MAX_DISTANCE:
748 case AL_ROLLOFF_FACTOR:
749 case AL_REFERENCE_DISTANCE:
750 case AL_DIRECT_FILTER:
751 case AL_DIRECT_FILTER_GAINHF_AUTO:
752 alSourcei(source, eParam, plValues[0]);
753 break;
755 case AL_POSITION:
756 case AL_VELOCITY:
757 case AL_DIRECTION:
758 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
759 break;
761 default:
762 alSetError(AL_INVALID_ENUM);
763 break;
766 else
767 alSetError(AL_INVALID_NAME);
769 else
770 alSetError(AL_INVALID_VALUE);
772 ProcessContext(pContext);
774 else
775 alSetError(AL_INVALID_OPERATION);
777 return;
781 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
783 ALCcontext *pContext;
784 ALsource *pSource;
785 ALfloat flOffset;
787 pContext = alcGetCurrentContext();
788 if (pContext)
790 SuspendContext(pContext);
792 if (pflValue)
794 if (alIsSource(source))
796 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
798 switch(eParam)
800 case AL_PITCH:
801 *pflValue = pSource->flPitch;
802 break;
804 case AL_GAIN:
805 *pflValue = pSource->flGain;
806 break;
808 case AL_MIN_GAIN:
809 *pflValue = pSource->flMinGain;
810 break;
812 case AL_MAX_GAIN:
813 *pflValue = pSource->flMaxGain;
814 break;
816 case AL_MAX_DISTANCE:
817 *pflValue = pSource->flMaxDistance;
818 break;
820 case AL_ROLLOFF_FACTOR:
821 *pflValue = pSource->flRollOffFactor;
822 break;
824 case AL_CONE_OUTER_GAIN:
825 *pflValue = pSource->flOuterGain;
826 break;
828 case AL_CONE_OUTER_GAINHF:
829 *pflValue = pSource->OuterGainHF;
830 break;
832 case AL_SEC_OFFSET:
833 case AL_SAMPLE_OFFSET:
834 case AL_BYTE_OFFSET:
835 if (GetSourceOffset(pSource, eParam, &flOffset))
836 *pflValue = flOffset;
837 else
838 alSetError(AL_INVALID_OPERATION);
839 break;
841 case AL_CONE_INNER_ANGLE:
842 *pflValue = pSource->flInnerAngle;
843 break;
845 case AL_CONE_OUTER_ANGLE:
846 *pflValue = pSource->flOuterAngle;
847 break;
849 case AL_REFERENCE_DISTANCE:
850 *pflValue = pSource->flRefDistance;
851 break;
853 default:
854 alSetError(AL_INVALID_ENUM);
855 break;
858 else
859 alSetError(AL_INVALID_NAME);
861 else
862 alSetError(AL_INVALID_VALUE);
864 ProcessContext(pContext);
866 else
867 alSetError(AL_INVALID_OPERATION);
869 return;
873 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
875 ALCcontext *pContext;
876 ALsource *pSource;
878 pContext = alcGetCurrentContext();
879 if (pContext)
881 SuspendContext(pContext);
883 if ((pflValue1) && (pflValue2) && (pflValue3))
885 if (alIsSource(source))
887 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
889 switch(eParam)
891 case AL_POSITION:
892 *pflValue1 = pSource->vPosition[0];
893 *pflValue2 = pSource->vPosition[1];
894 *pflValue3 = pSource->vPosition[2];
895 break;
897 case AL_VELOCITY:
898 *pflValue1 = pSource->vVelocity[0];
899 *pflValue2 = pSource->vVelocity[1];
900 *pflValue3 = pSource->vVelocity[2];
901 break;
903 case AL_DIRECTION:
904 *pflValue1 = pSource->vOrientation[0];
905 *pflValue2 = pSource->vOrientation[1];
906 *pflValue3 = pSource->vOrientation[2];
907 break;
909 default:
910 alSetError(AL_INVALID_ENUM);
911 break;
914 else
915 alSetError(AL_INVALID_NAME);
917 else
918 alSetError(AL_INVALID_VALUE);
920 ProcessContext(pContext);
922 else
923 alSetError(AL_INVALID_OPERATION);
925 return;
929 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
931 ALCcontext *pContext;
932 ALsource *pSource;
934 pContext = alcGetCurrentContext();
935 if (pContext)
937 SuspendContext(pContext);
939 if (pflValues)
941 if (alIsSource(source))
943 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
945 switch(eParam)
947 case AL_PITCH:
948 case AL_GAIN:
949 case AL_MIN_GAIN:
950 case AL_MAX_GAIN:
951 case AL_MAX_DISTANCE:
952 case AL_ROLLOFF_FACTOR:
953 case AL_CONE_OUTER_GAIN:
954 case AL_SEC_OFFSET:
955 case AL_SAMPLE_OFFSET:
956 case AL_BYTE_OFFSET:
957 case AL_CONE_INNER_ANGLE:
958 case AL_CONE_OUTER_ANGLE:
959 case AL_REFERENCE_DISTANCE:
960 case AL_CONE_OUTER_GAINHF:
961 alGetSourcef(source, eParam, pflValues);
962 break;
964 case AL_POSITION:
965 pflValues[0] = pSource->vPosition[0];
966 pflValues[1] = pSource->vPosition[1];
967 pflValues[2] = pSource->vPosition[2];
968 break;
970 case AL_VELOCITY:
971 pflValues[0] = pSource->vVelocity[0];
972 pflValues[1] = pSource->vVelocity[1];
973 pflValues[2] = pSource->vVelocity[2];
974 break;
976 case AL_DIRECTION:
977 pflValues[0] = pSource->vOrientation[0];
978 pflValues[1] = pSource->vOrientation[1];
979 pflValues[2] = pSource->vOrientation[2];
980 break;
982 default:
983 alSetError(AL_INVALID_ENUM);
984 break;
987 else
988 alSetError(AL_INVALID_NAME);
990 else
991 alSetError(AL_INVALID_VALUE);
993 ProcessContext(pContext);
995 else
996 alSetError(AL_INVALID_OPERATION);
998 return;
1002 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1004 ALCcontext *pContext;
1005 ALsource *pSource;
1006 ALfloat flOffset;
1008 pContext = alcGetCurrentContext();
1009 if (pContext)
1011 SuspendContext(pContext);
1013 if (plValue)
1015 if (alIsSource(source))
1017 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1019 switch(eParam)
1021 case AL_MAX_DISTANCE:
1022 *plValue = (ALint)pSource->flMaxDistance;
1023 break;
1025 case AL_ROLLOFF_FACTOR:
1026 *plValue = (ALint)pSource->flRollOffFactor;
1027 break;
1029 case AL_REFERENCE_DISTANCE:
1030 *plValue = (ALint)pSource->flRefDistance;
1031 break;
1033 case AL_SOURCE_RELATIVE:
1034 *plValue = pSource->bHeadRelative;
1035 break;
1037 case AL_CONE_INNER_ANGLE:
1038 *plValue = (ALint)pSource->flInnerAngle;
1039 break;
1041 case AL_CONE_OUTER_ANGLE:
1042 *plValue = (ALint)pSource->flOuterAngle;
1043 break;
1045 case AL_LOOPING:
1046 *plValue = pSource->bLooping;
1047 break;
1049 case AL_BUFFER:
1050 *plValue = pSource->ulBufferID;
1051 break;
1053 case AL_SOURCE_STATE:
1054 *plValue = pSource->state;
1055 break;
1057 case AL_BUFFERS_QUEUED:
1058 *plValue = pSource->BuffersInQueue;
1059 break;
1061 case AL_BUFFERS_PROCESSED:
1062 if(pSource->bLooping)
1064 /* Buffers on a looping source are in a perpetual state
1065 * of PENDING, so don't report any as PROCESSED */
1066 *plValue = 0;
1068 else
1069 *plValue = pSource->BuffersProcessed;
1070 break;
1072 case AL_SOURCE_TYPE:
1073 *plValue = pSource->lSourceType;
1074 break;
1076 case AL_SEC_OFFSET:
1077 case AL_SAMPLE_OFFSET:
1078 case AL_BYTE_OFFSET:
1079 if (GetSourceOffset(pSource, eParam, &flOffset))
1080 *plValue = (ALint)flOffset;
1081 else
1082 alSetError(AL_INVALID_OPERATION);
1083 break;
1085 case AL_DIRECT_FILTER:
1086 *plValue = pSource->DirectFilter.filter;
1087 break;
1089 case AL_DIRECT_FILTER_GAINHF_AUTO:
1090 *plValue = pSource->DryGainHFAuto;
1091 break;
1093 default:
1094 alSetError(AL_INVALID_ENUM);
1095 break;
1098 else
1099 alSetError(AL_INVALID_NAME);
1101 else
1102 alSetError(AL_INVALID_VALUE);
1104 ProcessContext(pContext);
1106 else
1107 alSetError(AL_INVALID_OPERATION);
1109 return;
1113 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1115 ALCcontext *pContext;
1116 ALsource *pSource;
1118 pContext = alcGetCurrentContext();
1119 if (pContext)
1121 SuspendContext(pContext);
1123 if ((plValue1) && (plValue2) && (plValue3))
1125 if (alIsSource(source))
1127 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1129 switch(eParam)
1131 case AL_POSITION:
1132 *plValue1 = (ALint)pSource->vPosition[0];
1133 *plValue2 = (ALint)pSource->vPosition[1];
1134 *plValue3 = (ALint)pSource->vPosition[2];
1135 break;
1137 case AL_VELOCITY:
1138 *plValue1 = (ALint)pSource->vVelocity[0];
1139 *plValue2 = (ALint)pSource->vVelocity[1];
1140 *plValue3 = (ALint)pSource->vVelocity[2];
1141 break;
1143 case AL_DIRECTION:
1144 *plValue1 = (ALint)pSource->vOrientation[0];
1145 *plValue2 = (ALint)pSource->vOrientation[1];
1146 *plValue3 = (ALint)pSource->vOrientation[2];
1147 break;
1149 default:
1150 alSetError(AL_INVALID_ENUM);
1151 break;
1154 else
1155 alSetError(AL_INVALID_NAME);
1157 else
1158 alSetError(AL_INVALID_VALUE);
1160 ProcessContext(pContext);
1162 else
1163 alSetError(AL_INVALID_OPERATION);
1165 return;
1169 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1171 ALCcontext *pContext;
1172 ALsource *pSource;
1174 pContext = alcGetCurrentContext();
1175 if (pContext)
1177 SuspendContext(pContext);
1179 if (plValues)
1181 if (alIsSource(source))
1183 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1185 switch (eParam)
1187 case AL_SOURCE_RELATIVE:
1188 case AL_CONE_INNER_ANGLE:
1189 case AL_CONE_OUTER_ANGLE:
1190 case AL_LOOPING:
1191 case AL_BUFFER:
1192 case AL_SOURCE_STATE:
1193 case AL_BUFFERS_QUEUED:
1194 case AL_BUFFERS_PROCESSED:
1195 case AL_SEC_OFFSET:
1196 case AL_SAMPLE_OFFSET:
1197 case AL_BYTE_OFFSET:
1198 case AL_MAX_DISTANCE:
1199 case AL_ROLLOFF_FACTOR:
1200 case AL_REFERENCE_DISTANCE:
1201 case AL_SOURCE_TYPE:
1202 case AL_DIRECT_FILTER:
1203 case AL_DIRECT_FILTER_GAINHF_AUTO:
1204 alGetSourcei(source, eParam, plValues);
1205 break;
1207 case AL_POSITION:
1208 plValues[0] = (ALint)pSource->vPosition[0];
1209 plValues[1] = (ALint)pSource->vPosition[1];
1210 plValues[2] = (ALint)pSource->vPosition[2];
1211 break;
1213 case AL_VELOCITY:
1214 plValues[0] = (ALint)pSource->vVelocity[0];
1215 plValues[1] = (ALint)pSource->vVelocity[1];
1216 plValues[2] = (ALint)pSource->vVelocity[2];
1217 break;
1219 case AL_DIRECTION:
1220 plValues[0] = (ALint)pSource->vOrientation[0];
1221 plValues[1] = (ALint)pSource->vOrientation[1];
1222 plValues[2] = (ALint)pSource->vOrientation[2];
1223 break;
1225 default:
1226 alSetError(AL_INVALID_ENUM);
1227 break;
1230 else
1231 alSetError(AL_INVALID_NAME);
1233 else
1234 alSetError(AL_INVALID_VALUE);
1236 ProcessContext(pContext);
1238 else
1239 alSetError(AL_INVALID_OPERATION);
1241 return;
1245 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1247 alSourcePlayv(1, &source);
1248 return;
1251 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1253 ALCcontext *pContext;
1254 ALsource *pSource;
1255 ALbufferlistitem *ALBufferList;
1256 ALboolean bSourcesValid = AL_TRUE;
1257 ALboolean bPlay;
1258 ALsizei i;
1260 pContext = alcGetCurrentContext();
1261 if (pContext)
1263 SuspendContext(pContext);
1265 if (pSourceList)
1267 // Check that all the Sources are valid
1268 for (i = 0; i < n; i++)
1270 if (!alIsSource(pSourceList[i]))
1272 alSetError(AL_INVALID_NAME);
1273 bSourcesValid = AL_FALSE;
1274 break;
1278 if (bSourcesValid)
1280 for (i = 0; i < n; i++)
1282 // Assume Source won't need to play
1283 bPlay = AL_FALSE;
1285 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1287 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1288 ALBufferList = pSource->queue;
1289 while (ALBufferList)
1291 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1293 bPlay = AL_TRUE;
1294 break;
1296 ALBufferList = ALBufferList->next;
1299 if (bPlay)
1301 if (pSource->state != AL_PAUSED)
1303 pSource->state = AL_PLAYING;
1304 pSource->inuse = AL_TRUE;
1305 pSource->play = AL_TRUE;
1306 pSource->position = 0;
1307 pSource->position_fraction = 0;
1308 pSource->BuffersProcessed = 0;
1309 pSource->BuffersPlayed = 0;
1310 pSource->BufferPosition = 0;
1311 pSource->lBytesPlayed = 0;
1313 pSource->ulBufferID = pSource->queue->buffer;
1315 // Make sure all the Buffers in the queue are marked as PENDING
1316 ALBufferList = pSource->queue;
1317 while (ALBufferList)
1319 ALBufferList->bufferstate = PENDING;
1320 ALBufferList = ALBufferList->next;
1323 else
1325 pSource->state = AL_PLAYING;
1326 pSource->inuse = AL_TRUE;
1327 pSource->play = AL_TRUE;
1330 // Check if an Offset has been set
1331 if (pSource->lOffset)
1332 ApplyOffset(pSource, AL_FALSE);
1334 else
1336 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1337 ALBufferList = pSource->queue;
1338 while (ALBufferList)
1340 ALBufferList->bufferstate = PROCESSED;
1341 ALBufferList = ALBufferList->next;
1344 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1349 else
1351 // sources is a NULL pointer
1352 alSetError(AL_INVALID_VALUE);
1355 ProcessContext(pContext);
1357 else
1359 // Invalid Context
1360 alSetError(AL_INVALID_OPERATION);
1363 return;
1366 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1368 alSourcePausev(1, &source);
1369 return;
1372 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1374 ALCcontext *Context;
1375 ALsource *Source;
1376 ALsizei i;
1377 ALboolean bSourcesValid = AL_TRUE;
1379 Context=alcGetCurrentContext();
1380 if (Context)
1382 SuspendContext(Context);
1384 if (sources)
1386 // Check all the Sources are valid
1387 for (i=0;i<n;i++)
1389 if (!alIsSource(sources[i]))
1391 alSetError(AL_INVALID_NAME);
1392 bSourcesValid = AL_FALSE;
1393 break;
1397 if (bSourcesValid)
1399 for (i=0;i<n;i++)
1401 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1402 if (Source->state==AL_PLAYING)
1404 Source->state=AL_PAUSED;
1405 Source->inuse=AL_FALSE;
1410 else
1412 // sources is a NULL pointer
1413 alSetError(AL_INVALID_VALUE);
1416 ProcessContext(Context);
1418 else
1420 // Invalid Context
1421 alSetError(AL_INVALID_OPERATION);
1424 return;
1427 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1429 alSourceStopv(1, &source);
1430 return;
1433 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1435 ALCcontext *Context;
1436 ALsource *Source;
1437 ALsizei i;
1438 ALbufferlistitem *ALBufferListItem;
1439 ALboolean bSourcesValid = AL_TRUE;
1441 Context=alcGetCurrentContext();
1442 if (Context)
1444 SuspendContext(Context);
1446 if (sources)
1448 // Check all the Sources are valid
1449 for (i=0;i<n;i++)
1451 if (!alIsSource(sources[i]))
1453 alSetError(AL_INVALID_NAME);
1454 bSourcesValid = AL_FALSE;
1455 break;
1459 if (bSourcesValid)
1461 for (i=0;i<n;i++)
1463 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1464 if (Source->state!=AL_INITIAL)
1466 Source->state=AL_STOPPED;
1467 Source->inuse=AL_FALSE;
1468 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1469 ALBufferListItem= Source->queue;
1470 while (ALBufferListItem != NULL)
1472 ALBufferListItem->bufferstate = PROCESSED;
1473 ALBufferListItem = ALBufferListItem->next;
1476 Source->lOffset = 0;
1480 else
1482 // sources is a NULL pointer
1483 alSetError(AL_INVALID_VALUE);
1486 ProcessContext(Context);
1488 else
1490 // Invalid Context
1491 alSetError(AL_INVALID_OPERATION);
1494 return;
1497 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1499 alSourceRewindv(1, &source);
1500 return;
1503 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1505 ALCcontext *Context;
1506 ALsource *Source;
1507 ALsizei i;
1508 ALbufferlistitem *ALBufferListItem;
1509 ALboolean bSourcesValid = AL_TRUE;
1511 Context=alcGetCurrentContext();
1512 if (Context)
1514 SuspendContext(Context);
1516 if (sources)
1518 // Check all the Sources are valid
1519 for (i=0;i<n;i++)
1521 if (!alIsSource(sources[i]))
1523 alSetError(AL_INVALID_NAME);
1524 bSourcesValid = AL_FALSE;
1525 break;
1529 if (bSourcesValid)
1531 for (i=0;i<n;i++)
1533 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1534 if (Source->state!=AL_INITIAL)
1536 Source->state=AL_INITIAL;
1537 Source->inuse=AL_FALSE;
1538 Source->position=0;
1539 Source->position_fraction=0;
1540 Source->BuffersProcessed = 0;
1541 ALBufferListItem= Source->queue;
1542 while (ALBufferListItem != NULL)
1544 ALBufferListItem->bufferstate = PENDING;
1545 ALBufferListItem = ALBufferListItem->next;
1547 if (Source->queue)
1548 Source->ulBufferID = Source->queue->buffer;
1550 Source->lOffset = 0;
1554 else
1556 // sources is a NULL pointer
1557 alSetError(AL_INVALID_VALUE);
1560 ProcessContext(Context);
1562 else
1564 // Invalid Context
1565 alSetError(AL_INVALID_OPERATION);
1568 return;
1572 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1574 ALCcontext *Context;
1575 ALsource *ALSource;
1576 ALsizei i;
1577 ALbufferlistitem *ALBufferList;
1578 ALbufferlistitem *ALBufferListStart;
1579 ALuint DataSize;
1580 ALuint BufferSize;
1581 ALint iFrequency;
1582 ALint iFormat;
1583 ALboolean bBuffersValid = AL_TRUE;
1585 if (n == 0)
1586 return;
1588 Context=alcGetCurrentContext();
1589 if (Context)
1591 SuspendContext(Context);
1593 DataSize = 0;
1594 BufferSize = 0;
1596 // Check that all buffers are valid or zero and that the source is valid
1598 // Check that this is a valid source
1599 if (alIsSource(source))
1601 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1603 // Check that this is not a STATIC Source
1604 if (ALSource->lSourceType != AL_STATIC)
1606 iFrequency = -1;
1607 iFormat = -1;
1609 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1610 ALBufferList = ALSource->queue;
1611 while (ALBufferList)
1613 if (ALBufferList->buffer)
1615 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1616 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1617 break;
1619 ALBufferList = ALBufferList->next;
1622 for (i = 0; i < n; i++)
1624 if (alIsBuffer(buffers[i]))
1626 if (buffers[i])
1628 if ((iFrequency == -1) && (iFormat == -1))
1630 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1631 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1633 else
1635 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1636 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1638 alSetError(AL_INVALID_OPERATION);
1639 bBuffersValid = AL_FALSE;
1640 break;
1645 else
1647 alSetError(AL_INVALID_NAME);
1648 bBuffersValid = AL_FALSE;
1649 break;
1653 if (bBuffersValid)
1655 // Change Source Type
1656 ALSource->lSourceType = AL_STREAMING;
1658 // All buffers are valid - so add them to the list
1659 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1660 ALBufferListStart->buffer = buffers[0];
1661 ALBufferListStart->bufferstate = PENDING;
1662 ALBufferListStart->flag = 0;
1663 ALBufferListStart->next = NULL;
1665 if (buffers[0])
1666 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1667 else
1668 BufferSize = 0;
1670 DataSize += BufferSize;
1672 // Increment reference counter for buffer
1673 if (buffers[0])
1674 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1676 ALBufferList = ALBufferListStart;
1678 for (i = 1; i < n; i++)
1680 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1681 ALBufferList->next->buffer = buffers[i];
1682 ALBufferList->next->bufferstate = PENDING;
1683 ALBufferList->next->flag = 0;
1684 ALBufferList->next->next = NULL;
1686 if (buffers[i])
1687 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1688 else
1689 BufferSize = 0;
1691 DataSize += BufferSize;
1693 // Increment reference counter for buffer
1694 if (buffers[i])
1695 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1697 ALBufferList = ALBufferList->next;
1700 if (ALSource->queue == NULL)
1702 ALSource->queue = ALBufferListStart;
1703 // Update Current Buffer
1704 ALSource->ulBufferID = ALBufferListStart->buffer;
1706 else
1708 // Find end of queue
1709 ALBufferList = ALSource->queue;
1710 while (ALBufferList->next != NULL)
1712 ALBufferList = ALBufferList->next;
1715 ALBufferList->next = ALBufferListStart;
1718 // Update number of buffers in queue
1719 ALSource->BuffersInQueue += n;
1722 else
1724 // Invalid Source Type (can't queue on a Static Source)
1725 alSetError(AL_INVALID_OPERATION);
1728 else
1730 // Invalid Source Name
1731 alSetError(AL_INVALID_NAME);
1734 ProcessContext(Context);
1736 else
1738 // Invalid Context
1739 alSetError(AL_INVALID_OPERATION);
1742 return;
1746 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1747 // an array of buffer IDs that are to be filled with the names of the buffers removed
1748 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1750 ALCcontext *Context;
1751 ALsource *ALSource;
1752 ALsizei i;
1753 ALbufferlistitem *ALBufferList;
1754 ALuint DataSize;
1755 ALuint BufferSize;
1756 ALuint BufferID;
1757 ALboolean bBuffersProcessed;
1759 if (n == 0)
1760 return;
1762 DataSize = 0;
1763 BufferSize = 0;
1764 bBuffersProcessed = AL_TRUE;
1766 Context=alcGetCurrentContext();
1767 if (Context)
1769 SuspendContext(Context);
1771 if (alIsSource(source))
1773 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1775 // Check that all 'n' buffers have been processed
1776 ALBufferList = ALSource->queue;
1777 for (i = 0; i < n; i++)
1779 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1781 ALBufferList = ALBufferList->next;
1783 else
1785 bBuffersProcessed = AL_FALSE;
1786 break;
1790 // If all 'n' buffers have been processed, remove them from the queue
1791 if (bBuffersProcessed)
1793 for (i = 0; i < n; i++)
1795 ALBufferList = ALSource->queue;
1797 ALSource->queue = ALBufferList->next;
1798 // Record name of buffer
1799 buffers[i] = ALBufferList->buffer;
1800 // Decrement buffer reference counter
1801 if (ALBufferList->buffer)
1802 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1803 // Record size of buffer
1804 if (ALBufferList->buffer)
1805 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1806 else
1807 BufferSize = 0;
1809 DataSize += BufferSize;
1810 // Release memory for buffer list item
1811 free(ALBufferList);
1812 ALSource->BuffersInQueue--;
1813 ALSource->BuffersProcessed--;
1816 if (ALSource->state != AL_PLAYING)
1818 if (ALSource->queue)
1819 BufferID = ALSource->queue->buffer;
1820 else
1821 BufferID = 0;
1823 ALSource->ulBufferID = BufferID;
1826 if((ALuint)n > ALSource->BuffersPlayed)
1828 ALSource->BuffersPlayed = 0;
1829 ALSource->BufferPosition = 0;
1831 else
1832 ALSource->BuffersPlayed -= n;
1834 else
1836 // Some buffers can't be unqueue because they have not been processed
1837 alSetError(AL_INVALID_VALUE);
1840 else
1842 // Invalid Source Name
1843 alSetError(AL_INVALID_NAME);
1846 ProcessContext(Context);
1848 else
1850 // Invalid Context
1851 alSetError(AL_INVALID_OPERATION);
1854 return;
1858 static ALvoid InitSourceParams(ALsource *pSource)
1860 pSource->flInnerAngle = 360.0f;
1861 pSource->flOuterAngle = 360.0f;
1862 pSource->flPitch = 1.0f;
1863 pSource->vPosition[0] = 0.0f;
1864 pSource->vPosition[1] = 0.0f;
1865 pSource->vPosition[2] = 0.0f;
1866 pSource->vOrientation[0] = 0.0f;
1867 pSource->vOrientation[1] = 0.0f;
1868 pSource->vOrientation[2] = 0.0f;
1869 pSource->vVelocity[0] = 0.0f;
1870 pSource->vVelocity[1] = 0.0f;
1871 pSource->vVelocity[2] = 0.0f;
1872 pSource->flRefDistance = 1.0f;
1873 pSource->flMaxDistance = FLT_MAX;
1874 pSource->flRollOffFactor = 1.0f;
1875 pSource->bLooping = AL_FALSE;
1876 pSource->flGain = 1.0f;
1877 pSource->flMinGain = 0.0f;
1878 pSource->flMaxGain = 1.0f;
1879 pSource->flOuterGain = 0.0f;
1881 pSource->DryGainHFAuto = AL_TRUE;
1883 pSource->state = AL_INITIAL;
1884 pSource->lSourceType = AL_UNDETERMINED;
1886 pSource->ulBufferID= 0;
1891 GetSourceOffset
1893 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1894 The offset is relative to the start of the queue (not the start of the current buffer)
1896 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1898 ALbufferlistitem *pBufferList;
1899 ALfloat flBufferFreq;
1900 ALint lBytesPlayed, lChannels;
1901 ALenum eOriginalFormat;
1902 ALboolean bReturn = AL_TRUE;
1903 ALint lTotalBufferDataSize;
1905 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1907 // Get Current Buffer Size and frequency (in milliseconds)
1908 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1909 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1910 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1912 // Get Current BytesPlayed
1913 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1914 // Add byte length of any processed buffers in the queue
1915 pBufferList = pSource->queue;
1916 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1918 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1919 pBufferList = pBufferList->next;
1922 lTotalBufferDataSize = 0;
1923 pBufferList = pSource->queue;
1924 while (pBufferList)
1926 if (pBufferList->buffer)
1927 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1928 pBufferList = pBufferList->next;
1931 if (pSource->bLooping)
1933 if (lBytesPlayed < 0)
1934 lBytesPlayed = 0;
1935 else
1936 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1938 else
1940 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1941 if(lBytesPlayed < 0)
1942 lBytesPlayed = 0;
1943 if(lBytesPlayed > lTotalBufferDataSize)
1944 lBytesPlayed = lTotalBufferDataSize;
1947 switch (eName)
1949 case AL_SEC_OFFSET:
1950 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1951 break;
1952 case AL_SAMPLE_OFFSET:
1953 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1954 break;
1955 case AL_BYTE_OFFSET:
1956 // Take into account the original format of the Buffer
1957 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
1959 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1961 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1963 // Compression rate of the ADPCM supported is 3.6111 to 1
1964 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1965 // Round down to nearest ADPCM block
1966 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1968 else
1970 *pflOffset = (ALfloat)lBytesPlayed;
1972 break;
1975 else
1977 *pflOffset = 0.0f;
1980 return bReturn;
1985 ApplyOffset
1987 Apply a playback offset to the Source. This function will update the queue (to correctly
1988 mark buffers as 'pending' or 'processed' depending upon the new offset.
1990 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1992 ALbufferlistitem *pBufferList;
1993 ALint lBufferSize, lTotalBufferSize;
1994 ALint lByteOffset;
1996 // Get true byte offset
1997 lByteOffset = GetByteOffset(pSource);
1999 // If this is a valid offset apply it
2000 if (lByteOffset != -1)
2002 // Sort out the queue (pending and processed states)
2003 pBufferList = pSource->queue;
2004 lTotalBufferSize = 0;
2005 pSource->BuffersPlayed = 0;
2006 pSource->BuffersProcessed = 0;
2007 while (pBufferList)
2009 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
2011 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2013 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2014 // update the state to PROCESSED
2015 pSource->BuffersPlayed++;
2017 if (!pSource->bLooping)
2019 pBufferList->bufferstate = PROCESSED;
2020 pSource->BuffersProcessed++;
2023 else if (lTotalBufferSize <= lByteOffset)
2025 // Offset is within this buffer
2026 pBufferList->bufferstate = PENDING;
2028 // Set Current Buffer ID
2029 pSource->ulBufferID = pBufferList->buffer;
2031 // Set current position in this buffer
2032 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2034 // Set Total Bytes Played to Offset
2035 pSource->lBytesPlayed = lByteOffset;
2037 // SW Mixer Positions are in Samples
2038 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2040 else
2042 // Offset is before this buffer, so mark as pending
2043 pBufferList->bufferstate = PENDING;
2046 // Increment the TotalBufferSize
2047 lTotalBufferSize += lBufferSize;
2049 // Move on to next buffer in the Queue
2050 pBufferList = pBufferList->next;
2053 else
2055 if (bUpdateContext)
2056 alSetError(AL_INVALID_VALUE);
2059 // Clear Offset
2060 pSource->lOffset = 0;
2065 GetByteOffset
2067 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2068 offset supplied by the application). This takes into account the fact that the buffer format
2069 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2071 static ALint GetByteOffset(ALsource *pSource)
2073 ALbuffer *pBuffer = NULL;
2074 ALbufferlistitem *pBufferList;
2075 ALfloat flBufferFreq;
2076 ALint lChannels;
2077 ALint lByteOffset = -1;
2078 ALint lTotalBufferDataSize;
2080 // Find the first non-NULL Buffer in the Queue
2081 pBufferList = pSource->queue;
2082 while (pBufferList)
2084 if (pBufferList->buffer)
2086 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2087 break;
2089 pBufferList = pBufferList->next;
2092 if (pBuffer)
2094 flBufferFreq = ((ALfloat)pBuffer->frequency);
2095 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2097 // Determine the ByteOffset (and ensure it is block aligned)
2098 switch (pSource->lOffsetType)
2100 case AL_BYTE_OFFSET:
2101 // Take into consideration the original format
2102 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2104 lByteOffset = pSource->lOffset * 2;
2105 lByteOffset -= (lByteOffset % (lChannels * 2));
2107 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2109 // Round down to nearest ADPCM block
2110 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2111 // Multiply by compression rate
2112 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2113 lByteOffset -= (lByteOffset % (lChannels * 2));
2115 else
2117 lByteOffset = pSource->lOffset;
2118 lByteOffset -= (lByteOffset % (lChannels * 2));
2120 break;
2122 case AL_SAMPLE_OFFSET:
2123 lByteOffset = pSource->lOffset * lChannels * 2;
2124 break;
2126 case AL_SEC_OFFSET:
2127 // Note - lOffset is internally stored as Milliseconds
2128 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2129 lByteOffset -= (lByteOffset % (lChannels * 2));
2130 break;
2133 lTotalBufferDataSize = 0;
2134 pBufferList = pSource->queue;
2135 while (pBufferList)
2137 if (pBufferList->buffer)
2138 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2139 pBufferList = pBufferList->next;
2142 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2143 if (lByteOffset >= lTotalBufferDataSize)
2144 lByteOffset = -1;
2147 return lByteOffset;