Remove Router code and test
[openal-soft.git] / OpenAL32 / alSource.c
blob90d70939359c9195296f38a867e89c6ae326deb2
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 ALvoid InitSourceParams(ALsource *pSource);
31 ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
32 ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
33 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;
442 ALsource *pSource;
444 pContext = alcGetCurrentContext();
445 if (pContext)
447 SuspendContext(pContext);
449 if (pflValues)
451 if (alIsSource(source))
453 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
455 switch (eParam)
457 case AL_PITCH:
458 case AL_CONE_INNER_ANGLE:
459 case AL_CONE_OUTER_ANGLE:
460 case AL_GAIN:
461 case AL_MAX_DISTANCE:
462 case AL_ROLLOFF_FACTOR:
463 case AL_REFERENCE_DISTANCE:
464 case AL_MIN_GAIN:
465 case AL_MAX_GAIN:
466 case AL_CONE_OUTER_GAIN:
467 case AL_SEC_OFFSET:
468 case AL_SAMPLE_OFFSET:
469 case AL_BYTE_OFFSET:
470 alSourcef(source, eParam, pflValues[0]);
471 break;
473 case AL_POSITION:
474 case AL_VELOCITY:
475 case AL_DIRECTION:
476 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
477 break;
479 default:
480 alSetError(AL_INVALID_ENUM);
481 break;
484 else
485 alSetError(AL_INVALID_NAME);
487 else
488 alSetError(AL_INVALID_VALUE);
490 ProcessContext(pContext);
492 else
493 alSetError(AL_INVALID_OPERATION);
495 return;
499 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
501 ALCcontext *pContext;
502 ALsource *pSource;
503 ALbufferlistitem *pALBufferListItem;
504 ALint Counter = 0;
505 ALint DataSize = 0;
506 ALint BufferSize;
508 pContext = alcGetCurrentContext();
509 if (pContext)
511 SuspendContext(pContext);
513 if (alIsSource(source))
515 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
517 switch(eParam)
519 case AL_MAX_DISTANCE:
520 case AL_ROLLOFF_FACTOR:
521 case AL_REFERENCE_DISTANCE:
522 alSourcef(source, eParam, (ALfloat)lValue);
523 break;
525 case AL_SOURCE_RELATIVE:
526 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
527 pSource->bHeadRelative = (ALboolean)lValue;
528 else
529 alSetError(AL_INVALID_VALUE);
530 break;
532 case AL_CONE_INNER_ANGLE:
533 if ((lValue >= 0) && (lValue <= 360))
534 pSource->flInnerAngle = (float)lValue;
535 else
536 alSetError(AL_INVALID_VALUE);
537 break;
539 case AL_CONE_OUTER_ANGLE:
540 if ((lValue >= 0) && (lValue <= 360))
541 pSource->flOuterAngle = (float)lValue;
542 else
543 alSetError(AL_INVALID_VALUE);
544 break;
546 case AL_LOOPING:
547 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
548 pSource->bLooping = (ALboolean)lValue;
549 else
550 alSetError(AL_INVALID_VALUE);
551 break;
553 case AL_BUFFER:
554 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
556 if (alIsBuffer(lValue))
558 // Remove all elements in the queue
559 while (pSource->queue != NULL)
561 pALBufferListItem = pSource->queue;
562 pSource->queue = pALBufferListItem->next;
563 // Decrement reference counter for buffer
564 if (pALBufferListItem->buffer)
565 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
566 // Record size of buffer
567 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
568 DataSize += BufferSize;
569 // Increment the number of buffers removed from queue
570 Counter++;
571 // Release memory for buffer list item
572 free(pALBufferListItem);
573 // Decrement the number of buffers in the queue
574 pSource->BuffersInQueue--;
577 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
578 if (lValue != 0)
580 // Source is now in STATIC mode
581 pSource->lSourceType = AL_STATIC;
583 // Add the selected buffer to the queue
584 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
585 pALBufferListItem->buffer = lValue;
586 pALBufferListItem->bufferstate = PENDING;
587 pALBufferListItem->flag = 0;
588 pALBufferListItem->next = NULL;
590 pSource->queue = pALBufferListItem;
591 pSource->BuffersInQueue = 1;
593 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
595 // Increment reference counter for buffer
596 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
598 else
600 // Source is now in UNDETERMINED mode
601 pSource->lSourceType = AL_UNDETERMINED;
604 // Set Buffers Processed
605 pSource->BuffersProcessed = 0;
607 // Update AL_BUFFER parameter
608 pSource->ulBufferID = lValue;
610 else
611 alSetError(AL_INVALID_VALUE);
613 else
614 alSetError(AL_INVALID_OPERATION);
615 break;
617 case AL_SOURCE_STATE:
618 // Query only
619 alSetError(AL_INVALID_OPERATION);
620 break;
622 case AL_SEC_OFFSET:
623 case AL_SAMPLE_OFFSET:
624 case AL_BYTE_OFFSET:
625 if (lValue >= 0)
627 pSource->lOffsetType = eParam;
629 // Store Offset (convert Seconds into Milliseconds)
630 if (eParam == AL_SEC_OFFSET)
631 pSource->lOffset = lValue * 1000;
632 else
633 pSource->lOffset = lValue;
635 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
636 ApplyOffset(pSource, AL_TRUE);
638 else
639 alSetError(AL_INVALID_VALUE);
640 break;
642 default:
643 alSetError(AL_INVALID_ENUM);
644 break;
647 else
648 alSetError(AL_INVALID_NAME);
650 ProcessContext(pContext);
652 else
653 alSetError(AL_INVALID_OPERATION);
655 return;
659 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
661 ALCcontext *pContext;
662 ALsource *pSource;
664 pContext = alcGetCurrentContext();
665 if (pContext)
667 SuspendContext(pContext);
669 if (alIsSource(source))
671 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
673 switch (eParam)
675 case AL_POSITION:
676 case AL_VELOCITY:
677 case AL_DIRECTION:
678 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
679 break;
681 default:
682 alSetError(AL_INVALID_ENUM);
683 break;
686 else
687 alSetError(AL_INVALID_NAME);
689 ProcessContext(pContext);
691 else
692 alSetError(AL_INVALID_OPERATION);
694 return;
698 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
700 ALCcontext *pContext;
701 ALsource *pSource;
703 pContext = alcGetCurrentContext();
704 if (pContext)
706 SuspendContext(pContext);
708 if (plValues)
710 if (alIsSource(source))
712 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
714 switch (eParam)
716 case AL_SOURCE_RELATIVE:
717 case AL_CONE_INNER_ANGLE:
718 case AL_CONE_OUTER_ANGLE:
719 case AL_LOOPING:
720 case AL_BUFFER:
721 case AL_SOURCE_STATE:
722 case AL_SEC_OFFSET:
723 case AL_SAMPLE_OFFSET:
724 case AL_BYTE_OFFSET:
725 case AL_MAX_DISTANCE:
726 case AL_ROLLOFF_FACTOR:
727 case AL_REFERENCE_DISTANCE:
728 alSourcei(source, eParam, plValues[0]);
729 break;
731 case AL_POSITION:
732 case AL_VELOCITY:
733 case AL_DIRECTION:
734 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
735 break;
737 default:
738 alSetError(AL_INVALID_ENUM);
739 break;
742 else
743 alSetError(AL_INVALID_NAME);
745 else
746 alSetError(AL_INVALID_VALUE);
748 ProcessContext(pContext);
750 else
751 alSetError(AL_INVALID_OPERATION);
753 return;
757 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
759 ALCcontext *pContext;
760 ALsource *pSource;
761 ALfloat flOffset;
763 pContext = alcGetCurrentContext();
764 if (pContext)
766 SuspendContext(pContext);
768 if (pflValue)
770 if (alIsSource(source))
772 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
774 switch(eParam)
776 case AL_PITCH:
777 *pflValue = pSource->flPitch;
778 break;
780 case AL_GAIN:
781 *pflValue = pSource->flGain;
782 break;
784 case AL_MIN_GAIN:
785 *pflValue = pSource->flMinGain;
786 break;
788 case AL_MAX_GAIN:
789 *pflValue = pSource->flMaxGain;
790 break;
792 case AL_MAX_DISTANCE:
793 *pflValue = pSource->flMaxDistance;
794 break;
796 case AL_ROLLOFF_FACTOR:
797 *pflValue = pSource->flRollOffFactor;
798 break;
800 case AL_CONE_OUTER_GAIN:
801 *pflValue = pSource->flOuterGain;
802 break;
804 case AL_SEC_OFFSET:
805 case AL_SAMPLE_OFFSET:
806 case AL_BYTE_OFFSET:
807 if (GetSourceOffset(pSource, eParam, &flOffset))
808 *pflValue = flOffset;
809 else
810 alSetError(AL_INVALID_OPERATION);
811 break;
813 case AL_CONE_INNER_ANGLE:
814 *pflValue = pSource->flInnerAngle;
815 break;
817 case AL_CONE_OUTER_ANGLE:
818 *pflValue = pSource->flOuterAngle;
819 break;
821 case AL_REFERENCE_DISTANCE:
822 *pflValue = pSource->flRefDistance;
823 break;
825 default:
826 alSetError(AL_INVALID_ENUM);
827 break;
830 else
831 alSetError(AL_INVALID_NAME);
833 else
834 alSetError(AL_INVALID_VALUE);
836 ProcessContext(pContext);
838 else
839 alSetError(AL_INVALID_OPERATION);
841 return;
845 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
847 ALCcontext *pContext;
848 ALsource *pSource;
850 pContext = alcGetCurrentContext();
851 if (pContext)
853 SuspendContext(pContext);
855 if ((pflValue1) && (pflValue2) && (pflValue3))
857 if (alIsSource(source))
859 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
861 switch(eParam)
863 case AL_POSITION:
864 *pflValue1 = pSource->vPosition[0];
865 *pflValue2 = pSource->vPosition[1];
866 *pflValue3 = pSource->vPosition[2];
867 break;
869 case AL_VELOCITY:
870 *pflValue1 = pSource->vVelocity[0];
871 *pflValue2 = pSource->vVelocity[1];
872 *pflValue3 = pSource->vVelocity[2];
873 break;
875 case AL_DIRECTION:
876 *pflValue1 = pSource->vOrientation[0];
877 *pflValue2 = pSource->vOrientation[1];
878 *pflValue3 = pSource->vOrientation[2];
879 break;
881 default:
882 alSetError(AL_INVALID_ENUM);
883 break;
886 else
887 alSetError(AL_INVALID_NAME);
889 else
890 alSetError(AL_INVALID_VALUE);
892 ProcessContext(pContext);
894 else
895 alSetError(AL_INVALID_OPERATION);
897 return;
901 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
903 ALCcontext *pContext;
904 ALsource *pSource;
906 pContext = alcGetCurrentContext();
907 if (pContext)
909 SuspendContext(pContext);
911 if (pflValues)
913 if (alIsSource(source))
915 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
917 switch(eParam)
919 case AL_PITCH:
920 case AL_GAIN:
921 case AL_MIN_GAIN:
922 case AL_MAX_GAIN:
923 case AL_MAX_DISTANCE:
924 case AL_ROLLOFF_FACTOR:
925 case AL_CONE_OUTER_GAIN:
926 case AL_SEC_OFFSET:
927 case AL_SAMPLE_OFFSET:
928 case AL_BYTE_OFFSET:
929 case AL_CONE_INNER_ANGLE:
930 case AL_CONE_OUTER_ANGLE:
931 case AL_REFERENCE_DISTANCE:
932 alGetSourcef(source, eParam, pflValues);
933 break;
935 case AL_POSITION:
936 pflValues[0] = pSource->vPosition[0];
937 pflValues[1] = pSource->vPosition[1];
938 pflValues[2] = pSource->vPosition[2];
939 break;
941 case AL_VELOCITY:
942 pflValues[0] = pSource->vVelocity[0];
943 pflValues[1] = pSource->vVelocity[1];
944 pflValues[2] = pSource->vVelocity[2];
945 break;
947 case AL_DIRECTION:
948 pflValues[0] = pSource->vOrientation[0];
949 pflValues[1] = pSource->vOrientation[1];
950 pflValues[2] = pSource->vOrientation[2];
951 break;
953 default:
954 alSetError(AL_INVALID_ENUM);
955 break;
958 else
959 alSetError(AL_INVALID_NAME);
961 else
962 alSetError(AL_INVALID_VALUE);
964 ProcessContext(pContext);
966 else
967 alSetError(AL_INVALID_OPERATION);
969 return;
973 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
975 ALCcontext *pContext;
976 ALsource *pSource;
977 ALfloat flOffset;
979 pContext = alcGetCurrentContext();
980 if (pContext)
982 SuspendContext(pContext);
984 if (plValue)
986 if (alIsSource(source))
988 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
990 switch(eParam)
992 case AL_MAX_DISTANCE:
993 *plValue = (ALint)pSource->flMaxDistance;
994 break;
996 case AL_ROLLOFF_FACTOR:
997 *plValue = (ALint)pSource->flRollOffFactor;
998 break;
1000 case AL_REFERENCE_DISTANCE:
1001 *plValue = (ALint)pSource->flRefDistance;
1002 break;
1004 case AL_SOURCE_RELATIVE:
1005 *plValue = pSource->bHeadRelative;
1006 break;
1008 case AL_CONE_INNER_ANGLE:
1009 *plValue = (ALint)pSource->flInnerAngle;
1010 break;
1012 case AL_CONE_OUTER_ANGLE:
1013 *plValue = (ALint)pSource->flOuterAngle;
1014 break;
1016 case AL_LOOPING:
1017 *plValue = pSource->bLooping;
1018 break;
1020 case AL_BUFFER:
1021 *plValue = pSource->ulBufferID;
1022 break;
1024 case AL_SOURCE_STATE:
1025 *plValue = pSource->state;
1026 break;
1028 case AL_BUFFERS_QUEUED:
1029 *plValue = pSource->BuffersInQueue;
1030 break;
1032 case AL_BUFFERS_PROCESSED:
1033 if(pSource->bLooping)
1035 /* Buffers on a looping source are in a perpetual state
1036 * of PENDING, so don't report any as PROCESSED */
1037 *plValue = 0;
1039 else
1040 *plValue = pSource->BuffersProcessed;
1041 break;
1043 case AL_SOURCE_TYPE:
1044 *plValue = pSource->lSourceType;
1045 break;
1047 case AL_SEC_OFFSET:
1048 case AL_SAMPLE_OFFSET:
1049 case AL_BYTE_OFFSET:
1050 if (GetSourceOffset(pSource, eParam, &flOffset))
1051 *plValue = (ALint)flOffset;
1052 else
1053 alSetError(AL_INVALID_OPERATION);
1054 break;
1056 default:
1057 alSetError(AL_INVALID_ENUM);
1058 break;
1061 else
1062 alSetError(AL_INVALID_NAME);
1064 else
1065 alSetError(AL_INVALID_VALUE);
1067 ProcessContext(pContext);
1069 else
1070 alSetError(AL_INVALID_OPERATION);
1072 return;
1076 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1078 ALCcontext *pContext;
1079 ALsource *pSource;
1081 pContext = alcGetCurrentContext();
1082 if (pContext)
1084 SuspendContext(pContext);
1086 if ((plValue1) && (plValue2) && (plValue3))
1088 if (alIsSource(source))
1090 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1092 switch(eParam)
1094 case AL_POSITION:
1095 *plValue1 = (ALint)pSource->vPosition[0];
1096 *plValue2 = (ALint)pSource->vPosition[1];
1097 *plValue3 = (ALint)pSource->vPosition[2];
1098 break;
1100 case AL_VELOCITY:
1101 *plValue1 = (ALint)pSource->vVelocity[0];
1102 *plValue2 = (ALint)pSource->vVelocity[1];
1103 *plValue3 = (ALint)pSource->vVelocity[2];
1104 break;
1106 case AL_DIRECTION:
1107 *plValue1 = (ALint)pSource->vOrientation[0];
1108 *plValue2 = (ALint)pSource->vOrientation[1];
1109 *plValue3 = (ALint)pSource->vOrientation[2];
1110 break;
1112 default:
1113 alSetError(AL_INVALID_ENUM);
1114 break;
1117 else
1118 alSetError(AL_INVALID_NAME);
1120 else
1121 alSetError(AL_INVALID_VALUE);
1123 ProcessContext(pContext);
1125 else
1126 alSetError(AL_INVALID_OPERATION);
1128 return;
1132 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1134 ALCcontext *pContext;
1135 ALsource *pSource;
1137 pContext = alcGetCurrentContext();
1138 if (pContext)
1140 SuspendContext(pContext);
1142 if (plValues)
1144 if (alIsSource(source))
1146 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1148 switch (eParam)
1150 case AL_SOURCE_RELATIVE:
1151 case AL_CONE_INNER_ANGLE:
1152 case AL_CONE_OUTER_ANGLE:
1153 case AL_LOOPING:
1154 case AL_BUFFER:
1155 case AL_SOURCE_STATE:
1156 case AL_BUFFERS_QUEUED:
1157 case AL_BUFFERS_PROCESSED:
1158 case AL_SEC_OFFSET:
1159 case AL_SAMPLE_OFFSET:
1160 case AL_BYTE_OFFSET:
1161 case AL_MAX_DISTANCE:
1162 case AL_ROLLOFF_FACTOR:
1163 case AL_REFERENCE_DISTANCE:
1164 case AL_SOURCE_TYPE:
1165 alGetSourcei(source, eParam, plValues);
1166 break;
1168 case AL_POSITION:
1169 plValues[0] = (ALint)pSource->vPosition[0];
1170 plValues[1] = (ALint)pSource->vPosition[1];
1171 plValues[2] = (ALint)pSource->vPosition[2];
1172 break;
1174 case AL_VELOCITY:
1175 plValues[0] = (ALint)pSource->vVelocity[0];
1176 plValues[1] = (ALint)pSource->vVelocity[1];
1177 plValues[2] = (ALint)pSource->vVelocity[2];
1178 break;
1180 case AL_DIRECTION:
1181 plValues[0] = (ALint)pSource->vOrientation[0];
1182 plValues[1] = (ALint)pSource->vOrientation[1];
1183 plValues[2] = (ALint)pSource->vOrientation[2];
1184 break;
1186 default:
1187 alSetError(AL_INVALID_ENUM);
1188 break;
1191 else
1192 alSetError(AL_INVALID_NAME);
1194 else
1195 alSetError(AL_INVALID_VALUE);
1197 ProcessContext(pContext);
1199 else
1200 alSetError(AL_INVALID_OPERATION);
1202 return;
1206 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1208 alSourcePlayv(1, &source);
1209 return;
1212 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1214 ALCcontext *pContext;
1215 ALsource *pSource;
1216 ALbufferlistitem *ALBufferList;
1217 ALboolean bSourcesValid = AL_TRUE;
1218 ALboolean bPlay;
1219 ALsizei i;
1221 pContext = alcGetCurrentContext();
1222 if (pContext)
1224 SuspendContext(pContext);
1226 if (pSourceList)
1228 // Check that all the Sources are valid
1229 for (i = 0; i < n; i++)
1231 if (!alIsSource(pSourceList[i]))
1233 alSetError(AL_INVALID_NAME);
1234 bSourcesValid = AL_FALSE;
1235 break;
1239 if (bSourcesValid)
1241 for (i = 0; i < n; i++)
1243 // Assume Source won't need to play
1244 bPlay = AL_FALSE;
1246 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1248 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1249 ALBufferList = pSource->queue;
1250 while (ALBufferList)
1252 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1254 bPlay = AL_TRUE;
1255 break;
1257 ALBufferList = ALBufferList->next;
1260 if (bPlay)
1262 if (pSource->state != AL_PAUSED)
1264 pSource->state = AL_PLAYING;
1265 pSource->inuse = AL_TRUE;
1266 pSource->play = AL_TRUE;
1267 pSource->position = 0;
1268 pSource->position_fraction = 0;
1269 pSource->BuffersProcessed = 0;
1270 pSource->BuffersPlayed = 0;
1271 pSource->BufferPosition = 0;
1272 pSource->lBytesPlayed = 0;
1274 pSource->ulBufferID = pSource->queue->buffer;
1276 // Make sure all the Buffers in the queue are marked as PENDING
1277 ALBufferList = pSource->queue;
1278 while (ALBufferList)
1280 ALBufferList->bufferstate = PENDING;
1281 ALBufferList = ALBufferList->next;
1284 else
1286 pSource->state = AL_PLAYING;
1287 pSource->inuse = AL_TRUE;
1288 pSource->play = AL_TRUE;
1291 // Check if an Offset has been set
1292 if (pSource->lOffset)
1293 ApplyOffset(pSource, AL_FALSE);
1295 else
1297 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1298 ALBufferList = pSource->queue;
1299 while (ALBufferList)
1301 ALBufferList->bufferstate = PROCESSED;
1302 ALBufferList = ALBufferList->next;
1305 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1310 else
1312 // sources is a NULL pointer
1313 alSetError(AL_INVALID_VALUE);
1316 ProcessContext(pContext);
1318 else
1320 // Invalid Context
1321 alSetError(AL_INVALID_OPERATION);
1324 return;
1327 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1329 alSourcePausev(1, &source);
1330 return;
1333 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1335 ALCcontext *Context;
1336 ALsource *Source;
1337 ALsizei i;
1338 ALboolean bSourcesValid = AL_TRUE;
1340 Context=alcGetCurrentContext();
1341 if (Context)
1343 SuspendContext(Context);
1345 if (sources)
1347 // Check all the Sources are valid
1348 for (i=0;i<n;i++)
1350 if (!alIsSource(sources[i]))
1352 alSetError(AL_INVALID_NAME);
1353 bSourcesValid = AL_FALSE;
1354 break;
1358 if (bSourcesValid)
1360 for (i=0;i<n;i++)
1362 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1363 if (Source->state==AL_PLAYING)
1365 Source->state=AL_PAUSED;
1366 Source->inuse=AL_FALSE;
1371 else
1373 // sources is a NULL pointer
1374 alSetError(AL_INVALID_VALUE);
1377 ProcessContext(Context);
1379 else
1381 // Invalid Context
1382 alSetError(AL_INVALID_OPERATION);
1385 return;
1388 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1390 alSourceStopv(1, &source);
1391 return;
1394 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1396 ALCcontext *Context;
1397 ALsource *Source;
1398 ALsizei i;
1399 ALbufferlistitem *ALBufferListItem;
1400 ALboolean bSourcesValid = AL_TRUE;
1402 Context=alcGetCurrentContext();
1403 if (Context)
1405 SuspendContext(Context);
1407 if (sources)
1409 // Check all the Sources are valid
1410 for (i=0;i<n;i++)
1412 if (!alIsSource(sources[i]))
1414 alSetError(AL_INVALID_NAME);
1415 bSourcesValid = AL_FALSE;
1416 break;
1420 if (bSourcesValid)
1422 for (i=0;i<n;i++)
1424 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1425 if (Source->state!=AL_INITIAL)
1427 Source->state=AL_STOPPED;
1428 Source->inuse=AL_FALSE;
1429 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1430 ALBufferListItem= Source->queue;
1431 while (ALBufferListItem != NULL)
1433 ALBufferListItem->bufferstate = PROCESSED;
1434 ALBufferListItem = ALBufferListItem->next;
1437 Source->lOffset = 0;
1441 else
1443 // sources is a NULL pointer
1444 alSetError(AL_INVALID_VALUE);
1447 ProcessContext(Context);
1449 else
1451 // Invalid Context
1452 alSetError(AL_INVALID_OPERATION);
1455 return;
1458 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1460 alSourceRewindv(1, &source);
1461 return;
1464 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1466 ALCcontext *Context;
1467 ALsource *Source;
1468 ALsizei i;
1469 ALbufferlistitem *ALBufferListItem;
1470 ALboolean bSourcesValid = AL_TRUE;
1472 Context=alcGetCurrentContext();
1473 if (Context)
1475 SuspendContext(Context);
1477 if (sources)
1479 // Check all the Sources are valid
1480 for (i=0;i<n;i++)
1482 if (!alIsSource(sources[i]))
1484 alSetError(AL_INVALID_NAME);
1485 bSourcesValid = AL_FALSE;
1486 break;
1490 if (bSourcesValid)
1492 for (i=0;i<n;i++)
1494 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1495 if (Source->state!=AL_INITIAL)
1497 Source->state=AL_INITIAL;
1498 Source->inuse=AL_FALSE;
1499 Source->position=0;
1500 Source->position_fraction=0;
1501 Source->BuffersProcessed = 0;
1502 ALBufferListItem= Source->queue;
1503 while (ALBufferListItem != NULL)
1505 ALBufferListItem->bufferstate = PENDING;
1506 ALBufferListItem = ALBufferListItem->next;
1508 if (Source->queue)
1509 Source->ulBufferID = Source->queue->buffer;
1511 Source->lOffset = 0;
1515 else
1517 // sources is a NULL pointer
1518 alSetError(AL_INVALID_VALUE);
1521 ProcessContext(Context);
1523 else
1525 // Invalid Context
1526 alSetError(AL_INVALID_OPERATION);
1529 return;
1533 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1535 ALCcontext *Context;
1536 ALsource *ALSource;
1537 ALsizei i;
1538 ALbufferlistitem *ALBufferList;
1539 ALbufferlistitem *ALBufferListStart;
1540 ALuint DataSize;
1541 ALuint BufferSize;
1542 ALint iFrequency;
1543 ALint iFormat;
1544 ALboolean bBuffersValid = AL_TRUE;
1546 if (n == 0)
1547 return;
1549 Context=alcGetCurrentContext();
1550 if (Context)
1552 SuspendContext(Context);
1554 DataSize = 0;
1555 BufferSize = 0;
1557 // Check that all buffers are valid or zero and that the source is valid
1559 // Check that this is a valid source
1560 if (alIsSource(source))
1562 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1564 // Check that this is not a STATIC Source
1565 if (ALSource->lSourceType != AL_STATIC)
1567 iFrequency = -1;
1568 iFormat = -1;
1570 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1571 ALBufferList = ALSource->queue;
1572 while (ALBufferList)
1574 if (ALBufferList->buffer)
1576 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1577 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1578 break;
1580 ALBufferList = ALBufferList->next;
1583 for (i = 0; i < n; i++)
1585 if (alIsBuffer(buffers[i]))
1587 if (buffers[i])
1589 if ((iFrequency == -1) && (iFormat == -1))
1591 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1592 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1594 else
1596 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1597 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1599 alSetError(AL_INVALID_OPERATION);
1600 bBuffersValid = AL_FALSE;
1601 break;
1606 else
1608 alSetError(AL_INVALID_NAME);
1609 bBuffersValid = AL_FALSE;
1610 break;
1614 if (bBuffersValid)
1616 // Change Source Type
1617 ALSource->lSourceType = AL_STREAMING;
1619 // All buffers are valid - so add them to the list
1620 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1621 ALBufferListStart->buffer = buffers[0];
1622 ALBufferListStart->bufferstate = PENDING;
1623 ALBufferListStart->flag = 0;
1624 ALBufferListStart->next = NULL;
1626 if (buffers[0])
1627 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1628 else
1629 BufferSize = 0;
1631 DataSize += BufferSize;
1633 // Increment reference counter for buffer
1634 if (buffers[0])
1635 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1637 ALBufferList = ALBufferListStart;
1639 for (i = 1; i < n; i++)
1641 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1642 ALBufferList->next->buffer = buffers[i];
1643 ALBufferList->next->bufferstate = PENDING;
1644 ALBufferList->next->flag = 0;
1645 ALBufferList->next->next = NULL;
1647 if (buffers[i])
1648 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1649 else
1650 BufferSize = 0;
1652 DataSize += BufferSize;
1654 // Increment reference counter for buffer
1655 if (buffers[i])
1656 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1658 ALBufferList = ALBufferList->next;
1661 if (ALSource->queue == NULL)
1663 ALSource->queue = ALBufferListStart;
1664 // Update Current Buffer
1665 ALSource->ulBufferID = ALBufferListStart->buffer;
1667 else
1669 // Find end of queue
1670 ALBufferList = ALSource->queue;
1671 while (ALBufferList->next != NULL)
1673 ALBufferList = ALBufferList->next;
1676 ALBufferList->next = ALBufferListStart;
1679 // Update number of buffers in queue
1680 ALSource->BuffersInQueue += n;
1683 else
1685 // Invalid Source Type (can't queue on a Static Source)
1686 alSetError(AL_INVALID_OPERATION);
1689 else
1691 // Invalid Source Name
1692 alSetError(AL_INVALID_NAME);
1695 ProcessContext(Context);
1697 else
1699 // Invalid Context
1700 alSetError(AL_INVALID_OPERATION);
1703 return;
1707 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1708 // an array of buffer IDs that are to be filled with the names of the buffers removed
1709 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1711 ALCcontext *Context;
1712 ALsource *ALSource;
1713 ALsizei i;
1714 ALbufferlistitem *ALBufferList;
1715 ALuint DataSize;
1716 ALuint BufferSize;
1717 ALuint BufferID;
1718 ALboolean bBuffersProcessed;
1720 if (n == 0)
1721 return;
1723 DataSize = 0;
1724 BufferSize = 0;
1725 bBuffersProcessed = AL_TRUE;
1727 Context=alcGetCurrentContext();
1728 if (Context)
1730 SuspendContext(Context);
1732 if (alIsSource(source))
1734 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1736 // Check that all 'n' buffers have been processed
1737 ALBufferList = ALSource->queue;
1738 for (i = 0; i < n; i++)
1740 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1742 ALBufferList = ALBufferList->next;
1744 else
1746 bBuffersProcessed = AL_FALSE;
1747 break;
1751 // If all 'n' buffers have been processed, remove them from the queue
1752 if (bBuffersProcessed)
1754 for (i = 0; i < n; i++)
1756 ALBufferList = ALSource->queue;
1758 ALSource->queue = ALBufferList->next;
1759 // Record name of buffer
1760 buffers[i] = ALBufferList->buffer;
1761 // Decrement buffer reference counter
1762 if (ALBufferList->buffer)
1763 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1764 // Record size of buffer
1765 if (ALBufferList->buffer)
1766 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1767 else
1768 BufferSize = 0;
1770 DataSize += BufferSize;
1771 // Release memory for buffer list item
1772 free(ALBufferList);
1773 ALSource->BuffersInQueue--;
1774 ALSource->BuffersProcessed--;
1777 if (ALSource->state != AL_PLAYING)
1779 if (ALSource->queue)
1780 BufferID = ALSource->queue->buffer;
1781 else
1782 BufferID = 0;
1784 ALSource->ulBufferID = BufferID;
1787 if((ALuint)n > ALSource->BuffersPlayed)
1789 ALSource->BuffersPlayed = 0;
1790 ALSource->BufferPosition = 0;
1792 else
1793 ALSource->BuffersPlayed -= n;
1795 else
1797 // Some buffers can't be unqueue because they have not been processed
1798 alSetError(AL_INVALID_VALUE);
1801 else
1803 // Invalid Source Name
1804 alSetError(AL_INVALID_NAME);
1807 ProcessContext(Context);
1809 else
1811 // Invalid Context
1812 alSetError(AL_INVALID_OPERATION);
1815 return;
1819 ALvoid InitSourceParams(ALsource *pSource)
1821 pSource->flInnerAngle = 360.0f;
1822 pSource->flOuterAngle = 360.0f;
1823 pSource->flPitch = 1.0f;
1824 pSource->vPosition[0] = 0.0f;
1825 pSource->vPosition[1] = 0.0f;
1826 pSource->vPosition[2] = 0.0f;
1827 pSource->vOrientation[0] = 0.0f;
1828 pSource->vOrientation[1] = 0.0f;
1829 pSource->vOrientation[2] = 0.0f;
1830 pSource->vVelocity[0] = 0.0f;
1831 pSource->vVelocity[1] = 0.0f;
1832 pSource->vVelocity[2] = 0.0f;
1833 pSource->flRefDistance = 1.0f;
1834 pSource->flMaxDistance = FLT_MAX;
1835 pSource->flRollOffFactor = 1.0f;
1836 pSource->bLooping = AL_FALSE;
1837 pSource->flGain = 1.0f;
1838 pSource->flMinGain = 0.0f;
1839 pSource->flMaxGain = 1.0f;
1840 pSource->flOuterGain = 0.0f;
1842 pSource->state = AL_INITIAL;
1843 pSource->lSourceType = AL_UNDETERMINED;
1845 pSource->ulBufferID= 0;
1850 GetSourceOffset
1852 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1853 The offset is relative to the start of the queue (not the start of the current buffer)
1855 ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1857 ALbufferlistitem *pBufferList;
1858 ALfloat flBufferFreq;
1859 ALint lBufferSize, lBytesPlayed, lChannels;
1860 ALenum eOriginalFormat;
1861 ALboolean bReturn = AL_TRUE;
1862 ALint lTotalBufferDataSize;
1864 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1866 // Get Current Buffer Size and frequency (in milliseconds)
1867 lBufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->size;
1868 flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
1869 eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
1870 lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
1872 // Get Current BytesPlayed
1873 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1874 // Add byte length of any processed buffers in the queue
1875 pBufferList = pSource->queue;
1876 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1878 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1879 pBufferList = pBufferList->next;
1882 lTotalBufferDataSize = 0;
1883 pBufferList = pSource->queue;
1884 while (pBufferList)
1886 if (pBufferList->buffer)
1887 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1888 pBufferList = pBufferList->next;
1891 if (pSource->bLooping)
1893 if (lBytesPlayed < 0)
1894 lBytesPlayed = 0;
1895 else
1896 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1898 else
1900 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1901 if(lBytesPlayed < 0)
1902 lBytesPlayed = 0;
1903 if(lBytesPlayed > lTotalBufferDataSize)
1904 lBytesPlayed = lTotalBufferDataSize;
1907 switch (eName)
1909 case AL_SEC_OFFSET:
1910 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1911 break;
1912 case AL_SAMPLE_OFFSET:
1913 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1914 break;
1915 case AL_BYTE_OFFSET:
1916 // Take into account the original format of the Buffer
1917 if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
1919 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1921 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1923 // Compression rate of the ADPCM supported is 3.6111 to 1
1924 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1925 // Round down to nearest ADPCM block
1926 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1928 else
1930 *pflOffset = (ALfloat)lBytesPlayed;
1932 break;
1935 else
1937 *pflOffset = 0.0f;
1940 return bReturn;
1945 ApplyOffset
1947 Apply a playback offset to the Source. This function will update the queue (to correctly
1948 mark buffers as 'pending' or 'processed' depending upon the new offset.
1950 void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1952 ALbufferlistitem *pBufferList;
1953 ALint lBufferSize, lTotalBufferSize;
1954 ALint lByteOffset;
1956 // Get true byte offset
1957 lByteOffset = GetByteOffset(pSource);
1959 // If this is a valid offset apply it
1960 if (lByteOffset != -1)
1962 // Sort out the queue (pending and processed states)
1963 pBufferList = pSource->queue;
1964 lTotalBufferSize = 0;
1965 pSource->BuffersPlayed = 0;
1966 pSource->BuffersProcessed = 0;
1967 while (pBufferList)
1969 lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
1971 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1973 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
1974 // update the state to PROCESSED
1975 pSource->BuffersPlayed++;
1977 if (!pSource->bLooping)
1979 pBufferList->bufferstate = PROCESSED;
1980 pSource->BuffersProcessed++;
1983 else if (lTotalBufferSize <= lByteOffset)
1985 // Offset is within this buffer
1986 pBufferList->bufferstate = PENDING;
1988 // Set Current Buffer ID
1989 pSource->ulBufferID = pBufferList->buffer;
1991 // Set current position in this buffer
1992 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
1994 // Set Total Bytes Played to Offset
1995 pSource->lBytesPlayed = lByteOffset;
1997 // SW Mixer Positions are in Samples
1998 pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
2000 else
2002 // Offset is before this buffer, so mark as pending
2003 pBufferList->bufferstate = PENDING;
2006 // Increment the TotalBufferSize
2007 lTotalBufferSize += lBufferSize;
2009 // Move on to next buffer in the Queue
2010 pBufferList = pBufferList->next;
2013 else
2015 if (bUpdateContext)
2016 alSetError(AL_INVALID_VALUE);
2019 // Clear Offset
2020 pSource->lOffset = 0;
2025 GetByteOffset
2027 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2028 offset supplied by the application). This takes into account the fact that the buffer format
2029 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2031 ALint GetByteOffset(ALsource *pSource)
2033 ALbuffer *pBuffer = NULL;
2034 ALbufferlistitem *pBufferList;
2035 ALfloat flBufferFreq;
2036 ALint lChannels;
2037 ALint lByteOffset = -1;
2038 ALint lTotalBufferDataSize;
2040 // Find the first non-NULL Buffer in the Queue
2041 pBufferList = pSource->queue;
2042 while (pBufferList)
2044 if (pBufferList->buffer)
2046 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2047 break;
2049 pBufferList = pBufferList->next;
2052 if (pBuffer)
2054 flBufferFreq = ((ALfloat)pBuffer->frequency);
2055 lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
2057 // Determine the ByteOffset (and ensure it is block aligned)
2058 switch (pSource->lOffsetType)
2060 case AL_BYTE_OFFSET:
2061 // Take into consideration the original format
2062 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
2064 lByteOffset = pSource->lOffset * 2;
2065 lByteOffset -= (lByteOffset % (lChannels * 2));
2067 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2069 // Round down to nearest ADPCM block
2070 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2071 // Multiply by compression rate
2072 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2073 lByteOffset -= (lByteOffset % (lChannels * 2));
2075 else
2077 lByteOffset = pSource->lOffset;
2078 lByteOffset -= (lByteOffset % (lChannels * 2));
2080 break;
2082 case AL_SAMPLE_OFFSET:
2083 lByteOffset = pSource->lOffset * lChannels * 2;
2084 break;
2086 case AL_SEC_OFFSET:
2087 // Note - lOffset is internally stored as Milliseconds
2088 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2089 lByteOffset -= (lByteOffset % (lChannels * 2));
2090 break;
2093 lTotalBufferDataSize = 0;
2094 pBufferList = pSource->queue;
2095 while (pBufferList)
2097 if (pBufferList->buffer)
2098 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2099 pBufferList = pBufferList->next;
2102 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2103 if (lByteOffset >= lTotalBufferDataSize)
2104 lByteOffset = -1;
2107 return lByteOffset;