Implement AL_EXT_FLOAT32
[openal-soft.git] / OpenAL32 / alSource.c
blob7c022e6c797a4dd6e3b7d69008b6a491cebd698d
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include <stdlib.h>
22 #include <math.h>
23 #include <float.h>
24 #include "alMain.h"
25 #include "AL/al.h"
26 #include "AL/alc.h"
27 #include "alError.h"
28 #include "alSource.h"
30 static ALvoid InitSourceParams(ALsource *pSource);
31 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
32 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
33 static ALint GetByteOffset(ALsource *pSource);
35 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
37 ALCcontext *Context;
38 ALCdevice *Device;
39 ALsizei i=0;
41 Context = alcGetCurrentContext();
42 if (Context)
44 SuspendContext(Context);
46 if (n > 0)
48 Device = alcGetContextsDevice(Context);
50 if (Device)
52 // Check that enough memory has been allocted in the 'sources' array for n Sources
53 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
55 // Check that the requested number of sources can be generated
56 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
58 ALsource **list = &Context->Source;
59 while(*list)
60 list = &(*list)->next;
62 // Add additional sources to the list (Source->next points to the location for the next Source structure)
63 while(i < n)
65 *list = calloc(1, sizeof(ALsource));
66 if(*list)
68 sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list);
69 (*list)->source = sources[i];
71 InitSourceParams(*list);
72 Context->SourceCount++;
73 i++;
75 list = &(*list)->next;
79 // If we didn't create all the Sources, we must have run out or memory
80 if(i != n)
81 alSetError(AL_OUT_OF_MEMORY);
83 else
85 // Not enough resources to create the Sources
86 alSetError(AL_INVALID_VALUE);
89 else
91 // Bad pointer
92 alSetError(AL_INVALID_VALUE);
95 else
97 // No Device created, or attached to Context
98 alSetError(AL_INVALID_OPERATION);
102 ProcessContext(Context);
104 else
106 // Invalid Context
107 alSetError(AL_INVALID_OPERATION);
110 return;
114 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
116 ALCcontext *Context;
117 ALCdevice *Device;
118 ALsource *ALSource;
119 ALsource **list;
120 ALsizei i;
121 ALbufferlistitem *ALBufferList;
122 ALboolean bSourcesValid = AL_TRUE;
124 Context = alcGetCurrentContext();
125 if (Context)
127 SuspendContext(Context);
129 if (n >= 0)
131 Device = alcGetContextsDevice(Context);
133 if (Device)
135 if ((ALuint)n <= Context->SourceCount)
137 // Check that all Sources are valid (and can therefore be deleted)
138 for (i = 0; i < n; i++)
140 if (!alIsSource(sources[i]))
142 alSetError(AL_INVALID_NAME);
143 bSourcesValid = AL_FALSE;
144 break;
148 if (bSourcesValid)
150 // All Sources are valid, and can be deleted
151 for (i = 0; i < n; i++)
153 // Recheck that the Source is valid, because there could be duplicated Source names
154 if (alIsSource(sources[i]))
156 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
157 alSourceStop((ALuint)ALSource->source);
159 // For each buffer in the source's queue, decrement its reference counter and remove it
160 while (ALSource->queue != NULL)
162 ALBufferList = ALSource->queue;
163 // Decrement buffer's reference counter
164 if (ALBufferList->buffer != 0)
165 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
166 // Update queue to point to next element in list
167 ALSource->queue = ALBufferList->next;
168 // Release memory allocated for buffer list item
169 free(ALBufferList);
172 // Decrement Source count
173 Context->SourceCount--;
175 // Remove Source from list of Sources
176 list = &Context->Source;
177 while(*list && *list != ALSource)
178 list = &(*list)->next;
180 if(*list)
181 *list = (*list)->next;
182 ALTHUNK_REMOVEENTRY(ALSource->source);
184 memset(ALSource,0,sizeof(ALsource));
185 free(ALSource);
191 else
193 // Trying to delete more Sources than have been generated
194 alSetError(AL_INVALID_NAME);
197 else
199 // No Device created, or attached to Context
200 alSetError(AL_INVALID_OPERATION);
203 else
204 alSetError(AL_INVALID_VALUE);
206 ProcessContext(Context);
208 else
210 // Invalid Context
211 alSetError(AL_INVALID_OPERATION);
214 return;
218 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
220 ALboolean result=AL_FALSE;
221 ALCcontext *Context;
222 ALsource *Source;
224 Context=alcGetCurrentContext();
225 if (Context)
227 SuspendContext(Context);
229 // To determine if this is a valid Source name, look through the list of generated Sources
230 Source = Context->Source;
231 while(Source)
233 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
235 result = AL_TRUE;
236 break;
239 Source = Source->next;
242 ProcessContext(Context);
244 else
246 // Invalid Context
247 alSetError(AL_INVALID_OPERATION);
250 return result;
254 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
256 ALCcontext *pContext;
257 ALsource *pSource;
259 pContext = alcGetCurrentContext();
260 if (pContext)
262 SuspendContext(pContext);
264 if (alIsSource(source))
266 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
268 switch (eParam)
270 case AL_PITCH:
271 if (flValue >= 0.0f)
273 pSource->flPitch = flValue;
274 if(pSource->flPitch < 0.001f)
275 pSource->flPitch = 0.001f;
277 else
278 alSetError(AL_INVALID_VALUE);
279 break;
281 case AL_CONE_INNER_ANGLE:
282 if ((flValue >= 0.0f) && (flValue <= 360.0f))
283 pSource->flInnerAngle = flValue;
284 else
285 alSetError(AL_INVALID_VALUE);
286 break;
288 case AL_CONE_OUTER_ANGLE:
289 if ((flValue >= 0.0f) && (flValue <= 360.0f))
290 pSource->flOuterAngle = flValue;
291 else
292 alSetError(AL_INVALID_VALUE);
293 break;
295 case AL_GAIN:
296 if (flValue >= 0.0f)
297 pSource->flGain = flValue;
298 else
299 alSetError(AL_INVALID_VALUE);
300 break;
302 case AL_MAX_DISTANCE:
303 if (flValue >= 0.0f)
304 pSource->flMaxDistance = flValue;
305 else
306 alSetError(AL_INVALID_VALUE);
307 break;
309 case AL_ROLLOFF_FACTOR:
310 if (flValue >= 0.0f)
311 pSource->flRollOffFactor = flValue;
312 else
313 alSetError(AL_INVALID_VALUE);
314 break;
316 case AL_REFERENCE_DISTANCE:
317 if (flValue >= 0.0f)
318 pSource->flRefDistance = flValue;
319 else
320 alSetError(AL_INVALID_VALUE);
321 break;
323 case AL_MIN_GAIN:
324 if ((flValue >= 0.0f) && (flValue <= 1.0f))
325 pSource->flMinGain = flValue;
326 else
327 alSetError(AL_INVALID_VALUE);
328 break;
330 case AL_MAX_GAIN:
331 if ((flValue >= 0.0f) && (flValue <= 1.0f))
332 pSource->flMaxGain = flValue;
333 else
334 alSetError(AL_INVALID_VALUE);
335 break;
337 case AL_CONE_OUTER_GAIN:
338 if ((flValue >= 0.0f) && (flValue <= 1.0f))
339 pSource->flOuterGain = flValue;
340 else
341 alSetError(AL_INVALID_VALUE);
342 break;
344 case AL_SEC_OFFSET:
345 case AL_SAMPLE_OFFSET:
346 case AL_BYTE_OFFSET:
347 if (flValue >= 0.0f)
349 pSource->lOffsetType = eParam;
351 // Store Offset (convert Seconds into Milliseconds)
352 if (eParam == AL_SEC_OFFSET)
353 pSource->lOffset = (ALint)(flValue * 1000.0f);
354 else
355 pSource->lOffset = (ALint)flValue;
357 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
358 ApplyOffset(pSource, AL_TRUE);
360 else
361 alSetError(AL_INVALID_VALUE);
362 break;
364 default:
365 alSetError(AL_INVALID_ENUM);
366 break;
369 else
371 // Invalid Source Name
372 alSetError(AL_INVALID_NAME);
375 ProcessContext(pContext);
377 else
379 // Invalid context
380 alSetError(AL_INVALID_OPERATION);
383 return;
387 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
389 ALCcontext *pContext;
390 ALsource *pSource;
392 pContext = alcGetCurrentContext();
393 if (pContext)
395 SuspendContext(pContext);
397 if (alIsSource(source))
399 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
400 switch(eParam)
402 case AL_POSITION:
403 pSource->vPosition[0] = flValue1;
404 pSource->vPosition[1] = flValue2;
405 pSource->vPosition[2] = flValue3;
406 break;
408 case AL_VELOCITY:
409 pSource->vVelocity[0] = flValue1;
410 pSource->vVelocity[1] = flValue2;
411 pSource->vVelocity[2] = flValue3;
412 break;
414 case AL_DIRECTION:
415 pSource->vOrientation[0] = flValue1;
416 pSource->vOrientation[1] = flValue2;
417 pSource->vOrientation[2] = flValue3;
418 break;
420 default:
421 alSetError(AL_INVALID_ENUM);
422 break;
425 else
426 alSetError(AL_INVALID_NAME);
428 ProcessContext(pContext);
430 else
432 alSetError(AL_INVALID_OPERATION);
435 return;
439 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
441 ALCcontext *pContext;
443 pContext = alcGetCurrentContext();
444 if (pContext)
446 SuspendContext(pContext);
448 if (pflValues)
450 if (alIsSource(source))
452 switch (eParam)
454 case AL_PITCH:
455 case AL_CONE_INNER_ANGLE:
456 case AL_CONE_OUTER_ANGLE:
457 case AL_GAIN:
458 case AL_MAX_DISTANCE:
459 case AL_ROLLOFF_FACTOR:
460 case AL_REFERENCE_DISTANCE:
461 case AL_MIN_GAIN:
462 case AL_MAX_GAIN:
463 case AL_CONE_OUTER_GAIN:
464 case AL_SEC_OFFSET:
465 case AL_SAMPLE_OFFSET:
466 case AL_BYTE_OFFSET:
467 alSourcef(source, eParam, pflValues[0]);
468 break;
470 case AL_POSITION:
471 case AL_VELOCITY:
472 case AL_DIRECTION:
473 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
474 break;
476 default:
477 alSetError(AL_INVALID_ENUM);
478 break;
481 else
482 alSetError(AL_INVALID_NAME);
484 else
485 alSetError(AL_INVALID_VALUE);
487 ProcessContext(pContext);
489 else
490 alSetError(AL_INVALID_OPERATION);
492 return;
496 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
498 ALCcontext *pContext;
499 ALsource *pSource;
500 ALbufferlistitem *pALBufferListItem;
501 ALint Counter = 0;
502 ALint DataSize = 0;
503 ALint BufferSize;
505 pContext = alcGetCurrentContext();
506 if (pContext)
508 SuspendContext(pContext);
510 if (alIsSource(source))
512 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
514 switch(eParam)
516 case AL_MAX_DISTANCE:
517 case AL_ROLLOFF_FACTOR:
518 case AL_REFERENCE_DISTANCE:
519 alSourcef(source, eParam, (ALfloat)lValue);
520 break;
522 case AL_SOURCE_RELATIVE:
523 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
524 pSource->bHeadRelative = (ALboolean)lValue;
525 else
526 alSetError(AL_INVALID_VALUE);
527 break;
529 case AL_CONE_INNER_ANGLE:
530 if ((lValue >= 0) && (lValue <= 360))
531 pSource->flInnerAngle = (float)lValue;
532 else
533 alSetError(AL_INVALID_VALUE);
534 break;
536 case AL_CONE_OUTER_ANGLE:
537 if ((lValue >= 0) && (lValue <= 360))
538 pSource->flOuterAngle = (float)lValue;
539 else
540 alSetError(AL_INVALID_VALUE);
541 break;
543 case AL_LOOPING:
544 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
545 pSource->bLooping = (ALboolean)lValue;
546 else
547 alSetError(AL_INVALID_VALUE);
548 break;
550 case AL_BUFFER:
551 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
553 if (alIsBuffer(lValue))
555 // Remove all elements in the queue
556 while (pSource->queue != NULL)
558 pALBufferListItem = pSource->queue;
559 pSource->queue = pALBufferListItem->next;
560 // Decrement reference counter for buffer
561 if (pALBufferListItem->buffer)
562 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
563 // Record size of buffer
564 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
565 DataSize += BufferSize;
566 // Increment the number of buffers removed from queue
567 Counter++;
568 // Release memory for buffer list item
569 free(pALBufferListItem);
570 // Decrement the number of buffers in the queue
571 pSource->BuffersInQueue--;
574 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
575 if (lValue != 0)
577 // Source is now in STATIC mode
578 pSource->lSourceType = AL_STATIC;
580 // Add the selected buffer to the queue
581 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
582 pALBufferListItem->buffer = lValue;
583 pALBufferListItem->bufferstate = PENDING;
584 pALBufferListItem->flag = 0;
585 pALBufferListItem->next = NULL;
587 pSource->queue = pALBufferListItem;
588 pSource->BuffersInQueue = 1;
590 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
592 // Increment reference counter for buffer
593 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
595 else
597 // Source is now in UNDETERMINED mode
598 pSource->lSourceType = AL_UNDETERMINED;
601 // Set Buffers Processed
602 pSource->BuffersProcessed = 0;
604 // Update AL_BUFFER parameter
605 pSource->ulBufferID = lValue;
607 else
608 alSetError(AL_INVALID_VALUE);
610 else
611 alSetError(AL_INVALID_OPERATION);
612 break;
614 case AL_SOURCE_STATE:
615 // Query only
616 alSetError(AL_INVALID_OPERATION);
617 break;
619 case AL_SEC_OFFSET:
620 case AL_SAMPLE_OFFSET:
621 case AL_BYTE_OFFSET:
622 if (lValue >= 0)
624 pSource->lOffsetType = eParam;
626 // Store Offset (convert Seconds into Milliseconds)
627 if (eParam == AL_SEC_OFFSET)
628 pSource->lOffset = lValue * 1000;
629 else
630 pSource->lOffset = lValue;
632 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
633 ApplyOffset(pSource, AL_TRUE);
635 else
636 alSetError(AL_INVALID_VALUE);
637 break;
639 default:
640 alSetError(AL_INVALID_ENUM);
641 break;
644 else
645 alSetError(AL_INVALID_NAME);
647 ProcessContext(pContext);
649 else
650 alSetError(AL_INVALID_OPERATION);
652 return;
656 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
658 ALCcontext *pContext;
660 pContext = alcGetCurrentContext();
661 if (pContext)
663 SuspendContext(pContext);
665 if (alIsSource(source))
667 switch (eParam)
669 case AL_POSITION:
670 case AL_VELOCITY:
671 case AL_DIRECTION:
672 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
673 break;
675 default:
676 alSetError(AL_INVALID_ENUM);
677 break;
680 else
681 alSetError(AL_INVALID_NAME);
683 ProcessContext(pContext);
685 else
686 alSetError(AL_INVALID_OPERATION);
688 return;
692 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
694 ALCcontext *pContext;
696 pContext = alcGetCurrentContext();
697 if (pContext)
699 SuspendContext(pContext);
701 if (plValues)
703 if (alIsSource(source))
705 switch (eParam)
707 case AL_SOURCE_RELATIVE:
708 case AL_CONE_INNER_ANGLE:
709 case AL_CONE_OUTER_ANGLE:
710 case AL_LOOPING:
711 case AL_BUFFER:
712 case AL_SOURCE_STATE:
713 case AL_SEC_OFFSET:
714 case AL_SAMPLE_OFFSET:
715 case AL_BYTE_OFFSET:
716 case AL_MAX_DISTANCE:
717 case AL_ROLLOFF_FACTOR:
718 case AL_REFERENCE_DISTANCE:
719 alSourcei(source, eParam, plValues[0]);
720 break;
722 case AL_POSITION:
723 case AL_VELOCITY:
724 case AL_DIRECTION:
725 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
726 break;
728 default:
729 alSetError(AL_INVALID_ENUM);
730 break;
733 else
734 alSetError(AL_INVALID_NAME);
736 else
737 alSetError(AL_INVALID_VALUE);
739 ProcessContext(pContext);
741 else
742 alSetError(AL_INVALID_OPERATION);
744 return;
748 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
750 ALCcontext *pContext;
751 ALsource *pSource;
752 ALfloat flOffset;
754 pContext = alcGetCurrentContext();
755 if (pContext)
757 SuspendContext(pContext);
759 if (pflValue)
761 if (alIsSource(source))
763 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
765 switch(eParam)
767 case AL_PITCH:
768 *pflValue = pSource->flPitch;
769 break;
771 case AL_GAIN:
772 *pflValue = pSource->flGain;
773 break;
775 case AL_MIN_GAIN:
776 *pflValue = pSource->flMinGain;
777 break;
779 case AL_MAX_GAIN:
780 *pflValue = pSource->flMaxGain;
781 break;
783 case AL_MAX_DISTANCE:
784 *pflValue = pSource->flMaxDistance;
785 break;
787 case AL_ROLLOFF_FACTOR:
788 *pflValue = pSource->flRollOffFactor;
789 break;
791 case AL_CONE_OUTER_GAIN:
792 *pflValue = pSource->flOuterGain;
793 break;
795 case AL_SEC_OFFSET:
796 case AL_SAMPLE_OFFSET:
797 case AL_BYTE_OFFSET:
798 if (GetSourceOffset(pSource, eParam, &flOffset))
799 *pflValue = flOffset;
800 else
801 alSetError(AL_INVALID_OPERATION);
802 break;
804 case AL_CONE_INNER_ANGLE:
805 *pflValue = pSource->flInnerAngle;
806 break;
808 case AL_CONE_OUTER_ANGLE:
809 *pflValue = pSource->flOuterAngle;
810 break;
812 case AL_REFERENCE_DISTANCE:
813 *pflValue = pSource->flRefDistance;
814 break;
816 default:
817 alSetError(AL_INVALID_ENUM);
818 break;
821 else
822 alSetError(AL_INVALID_NAME);
824 else
825 alSetError(AL_INVALID_VALUE);
827 ProcessContext(pContext);
829 else
830 alSetError(AL_INVALID_OPERATION);
832 return;
836 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
838 ALCcontext *pContext;
839 ALsource *pSource;
841 pContext = alcGetCurrentContext();
842 if (pContext)
844 SuspendContext(pContext);
846 if ((pflValue1) && (pflValue2) && (pflValue3))
848 if (alIsSource(source))
850 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
852 switch(eParam)
854 case AL_POSITION:
855 *pflValue1 = pSource->vPosition[0];
856 *pflValue2 = pSource->vPosition[1];
857 *pflValue3 = pSource->vPosition[2];
858 break;
860 case AL_VELOCITY:
861 *pflValue1 = pSource->vVelocity[0];
862 *pflValue2 = pSource->vVelocity[1];
863 *pflValue3 = pSource->vVelocity[2];
864 break;
866 case AL_DIRECTION:
867 *pflValue1 = pSource->vOrientation[0];
868 *pflValue2 = pSource->vOrientation[1];
869 *pflValue3 = pSource->vOrientation[2];
870 break;
872 default:
873 alSetError(AL_INVALID_ENUM);
874 break;
877 else
878 alSetError(AL_INVALID_NAME);
880 else
881 alSetError(AL_INVALID_VALUE);
883 ProcessContext(pContext);
885 else
886 alSetError(AL_INVALID_OPERATION);
888 return;
892 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
894 ALCcontext *pContext;
895 ALsource *pSource;
897 pContext = alcGetCurrentContext();
898 if (pContext)
900 SuspendContext(pContext);
902 if (pflValues)
904 if (alIsSource(source))
906 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
908 switch(eParam)
910 case AL_PITCH:
911 case AL_GAIN:
912 case AL_MIN_GAIN:
913 case AL_MAX_GAIN:
914 case AL_MAX_DISTANCE:
915 case AL_ROLLOFF_FACTOR:
916 case AL_CONE_OUTER_GAIN:
917 case AL_SEC_OFFSET:
918 case AL_SAMPLE_OFFSET:
919 case AL_BYTE_OFFSET:
920 case AL_CONE_INNER_ANGLE:
921 case AL_CONE_OUTER_ANGLE:
922 case AL_REFERENCE_DISTANCE:
923 alGetSourcef(source, eParam, pflValues);
924 break;
926 case AL_POSITION:
927 pflValues[0] = pSource->vPosition[0];
928 pflValues[1] = pSource->vPosition[1];
929 pflValues[2] = pSource->vPosition[2];
930 break;
932 case AL_VELOCITY:
933 pflValues[0] = pSource->vVelocity[0];
934 pflValues[1] = pSource->vVelocity[1];
935 pflValues[2] = pSource->vVelocity[2];
936 break;
938 case AL_DIRECTION:
939 pflValues[0] = pSource->vOrientation[0];
940 pflValues[1] = pSource->vOrientation[1];
941 pflValues[2] = pSource->vOrientation[2];
942 break;
944 default:
945 alSetError(AL_INVALID_ENUM);
946 break;
949 else
950 alSetError(AL_INVALID_NAME);
952 else
953 alSetError(AL_INVALID_VALUE);
955 ProcessContext(pContext);
957 else
958 alSetError(AL_INVALID_OPERATION);
960 return;
964 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
966 ALCcontext *pContext;
967 ALsource *pSource;
968 ALfloat flOffset;
970 pContext = alcGetCurrentContext();
971 if (pContext)
973 SuspendContext(pContext);
975 if (plValue)
977 if (alIsSource(source))
979 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
981 switch(eParam)
983 case AL_MAX_DISTANCE:
984 *plValue = (ALint)pSource->flMaxDistance;
985 break;
987 case AL_ROLLOFF_FACTOR:
988 *plValue = (ALint)pSource->flRollOffFactor;
989 break;
991 case AL_REFERENCE_DISTANCE:
992 *plValue = (ALint)pSource->flRefDistance;
993 break;
995 case AL_SOURCE_RELATIVE:
996 *plValue = pSource->bHeadRelative;
997 break;
999 case AL_CONE_INNER_ANGLE:
1000 *plValue = (ALint)pSource->flInnerAngle;
1001 break;
1003 case AL_CONE_OUTER_ANGLE:
1004 *plValue = (ALint)pSource->flOuterAngle;
1005 break;
1007 case AL_LOOPING:
1008 *plValue = pSource->bLooping;
1009 break;
1011 case AL_BUFFER:
1012 *plValue = pSource->ulBufferID;
1013 break;
1015 case AL_SOURCE_STATE:
1016 *plValue = pSource->state;
1017 break;
1019 case AL_BUFFERS_QUEUED:
1020 *plValue = pSource->BuffersInQueue;
1021 break;
1023 case AL_BUFFERS_PROCESSED:
1024 if(pSource->bLooping)
1026 /* Buffers on a looping source are in a perpetual state
1027 * of PENDING, so don't report any as PROCESSED */
1028 *plValue = 0;
1030 else
1031 *plValue = pSource->BuffersProcessed;
1032 break;
1034 case AL_SOURCE_TYPE:
1035 *plValue = pSource->lSourceType;
1036 break;
1038 case AL_SEC_OFFSET:
1039 case AL_SAMPLE_OFFSET:
1040 case AL_BYTE_OFFSET:
1041 if (GetSourceOffset(pSource, eParam, &flOffset))
1042 *plValue = (ALint)flOffset;
1043 else
1044 alSetError(AL_INVALID_OPERATION);
1045 break;
1047 default:
1048 alSetError(AL_INVALID_ENUM);
1049 break;
1052 else
1053 alSetError(AL_INVALID_NAME);
1055 else
1056 alSetError(AL_INVALID_VALUE);
1058 ProcessContext(pContext);
1060 else
1061 alSetError(AL_INVALID_OPERATION);
1063 return;
1067 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1069 ALCcontext *pContext;
1070 ALsource *pSource;
1072 pContext = alcGetCurrentContext();
1073 if (pContext)
1075 SuspendContext(pContext);
1077 if ((plValue1) && (plValue2) && (plValue3))
1079 if (alIsSource(source))
1081 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1083 switch(eParam)
1085 case AL_POSITION:
1086 *plValue1 = (ALint)pSource->vPosition[0];
1087 *plValue2 = (ALint)pSource->vPosition[1];
1088 *plValue3 = (ALint)pSource->vPosition[2];
1089 break;
1091 case AL_VELOCITY:
1092 *plValue1 = (ALint)pSource->vVelocity[0];
1093 *plValue2 = (ALint)pSource->vVelocity[1];
1094 *plValue3 = (ALint)pSource->vVelocity[2];
1095 break;
1097 case AL_DIRECTION:
1098 *plValue1 = (ALint)pSource->vOrientation[0];
1099 *plValue2 = (ALint)pSource->vOrientation[1];
1100 *plValue3 = (ALint)pSource->vOrientation[2];
1101 break;
1103 default:
1104 alSetError(AL_INVALID_ENUM);
1105 break;
1108 else
1109 alSetError(AL_INVALID_NAME);
1111 else
1112 alSetError(AL_INVALID_VALUE);
1114 ProcessContext(pContext);
1116 else
1117 alSetError(AL_INVALID_OPERATION);
1119 return;
1123 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1125 ALCcontext *pContext;
1126 ALsource *pSource;
1128 pContext = alcGetCurrentContext();
1129 if (pContext)
1131 SuspendContext(pContext);
1133 if (plValues)
1135 if (alIsSource(source))
1137 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1139 switch (eParam)
1141 case AL_SOURCE_RELATIVE:
1142 case AL_CONE_INNER_ANGLE:
1143 case AL_CONE_OUTER_ANGLE:
1144 case AL_LOOPING:
1145 case AL_BUFFER:
1146 case AL_SOURCE_STATE:
1147 case AL_BUFFERS_QUEUED:
1148 case AL_BUFFERS_PROCESSED:
1149 case AL_SEC_OFFSET:
1150 case AL_SAMPLE_OFFSET:
1151 case AL_BYTE_OFFSET:
1152 case AL_MAX_DISTANCE:
1153 case AL_ROLLOFF_FACTOR:
1154 case AL_REFERENCE_DISTANCE:
1155 case AL_SOURCE_TYPE:
1156 alGetSourcei(source, eParam, plValues);
1157 break;
1159 case AL_POSITION:
1160 plValues[0] = (ALint)pSource->vPosition[0];
1161 plValues[1] = (ALint)pSource->vPosition[1];
1162 plValues[2] = (ALint)pSource->vPosition[2];
1163 break;
1165 case AL_VELOCITY:
1166 plValues[0] = (ALint)pSource->vVelocity[0];
1167 plValues[1] = (ALint)pSource->vVelocity[1];
1168 plValues[2] = (ALint)pSource->vVelocity[2];
1169 break;
1171 case AL_DIRECTION:
1172 plValues[0] = (ALint)pSource->vOrientation[0];
1173 plValues[1] = (ALint)pSource->vOrientation[1];
1174 plValues[2] = (ALint)pSource->vOrientation[2];
1175 break;
1177 default:
1178 alSetError(AL_INVALID_ENUM);
1179 break;
1182 else
1183 alSetError(AL_INVALID_NAME);
1185 else
1186 alSetError(AL_INVALID_VALUE);
1188 ProcessContext(pContext);
1190 else
1191 alSetError(AL_INVALID_OPERATION);
1193 return;
1197 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1199 alSourcePlayv(1, &source);
1200 return;
1203 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1205 ALCcontext *pContext;
1206 ALsource *pSource;
1207 ALbufferlistitem *ALBufferList;
1208 ALboolean bSourcesValid = AL_TRUE;
1209 ALboolean bPlay;
1210 ALsizei i;
1212 pContext = alcGetCurrentContext();
1213 if (pContext)
1215 SuspendContext(pContext);
1217 if (pSourceList)
1219 // Check that all the Sources are valid
1220 for (i = 0; i < n; i++)
1222 if (!alIsSource(pSourceList[i]))
1224 alSetError(AL_INVALID_NAME);
1225 bSourcesValid = AL_FALSE;
1226 break;
1230 if (bSourcesValid)
1232 for (i = 0; i < n; i++)
1234 // Assume Source won't need to play
1235 bPlay = AL_FALSE;
1237 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1239 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1240 ALBufferList = pSource->queue;
1241 while (ALBufferList)
1243 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1245 bPlay = AL_TRUE;
1246 break;
1248 ALBufferList = ALBufferList->next;
1251 if (bPlay)
1253 if (pSource->state != AL_PAUSED)
1255 pSource->state = AL_PLAYING;
1256 pSource->inuse = AL_TRUE;
1257 pSource->play = AL_TRUE;
1258 pSource->position = 0;
1259 pSource->position_fraction = 0;
1260 pSource->BuffersProcessed = 0;
1261 pSource->BuffersPlayed = 0;
1262 pSource->BufferPosition = 0;
1263 pSource->lBytesPlayed = 0;
1265 pSource->ulBufferID = pSource->queue->buffer;
1267 // Make sure all the Buffers in the queue are marked as PENDING
1268 ALBufferList = pSource->queue;
1269 while (ALBufferList)
1271 ALBufferList->bufferstate = PENDING;
1272 ALBufferList = ALBufferList->next;
1275 else
1277 pSource->state = AL_PLAYING;
1278 pSource->inuse = AL_TRUE;
1279 pSource->play = AL_TRUE;
1282 // Check if an Offset has been set
1283 if (pSource->lOffset)
1284 ApplyOffset(pSource, AL_FALSE);
1286 else
1288 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1289 ALBufferList = pSource->queue;
1290 while (ALBufferList)
1292 ALBufferList->bufferstate = PROCESSED;
1293 ALBufferList = ALBufferList->next;
1296 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1301 else
1303 // sources is a NULL pointer
1304 alSetError(AL_INVALID_VALUE);
1307 ProcessContext(pContext);
1309 else
1311 // Invalid Context
1312 alSetError(AL_INVALID_OPERATION);
1315 return;
1318 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1320 alSourcePausev(1, &source);
1321 return;
1324 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1326 ALCcontext *Context;
1327 ALsource *Source;
1328 ALsizei i;
1329 ALboolean bSourcesValid = AL_TRUE;
1331 Context=alcGetCurrentContext();
1332 if (Context)
1334 SuspendContext(Context);
1336 if (sources)
1338 // Check all the Sources are valid
1339 for (i=0;i<n;i++)
1341 if (!alIsSource(sources[i]))
1343 alSetError(AL_INVALID_NAME);
1344 bSourcesValid = AL_FALSE;
1345 break;
1349 if (bSourcesValid)
1351 for (i=0;i<n;i++)
1353 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1354 if (Source->state==AL_PLAYING)
1356 Source->state=AL_PAUSED;
1357 Source->inuse=AL_FALSE;
1362 else
1364 // sources is a NULL pointer
1365 alSetError(AL_INVALID_VALUE);
1368 ProcessContext(Context);
1370 else
1372 // Invalid Context
1373 alSetError(AL_INVALID_OPERATION);
1376 return;
1379 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1381 alSourceStopv(1, &source);
1382 return;
1385 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1387 ALCcontext *Context;
1388 ALsource *Source;
1389 ALsizei i;
1390 ALbufferlistitem *ALBufferListItem;
1391 ALboolean bSourcesValid = AL_TRUE;
1393 Context=alcGetCurrentContext();
1394 if (Context)
1396 SuspendContext(Context);
1398 if (sources)
1400 // Check all the Sources are valid
1401 for (i=0;i<n;i++)
1403 if (!alIsSource(sources[i]))
1405 alSetError(AL_INVALID_NAME);
1406 bSourcesValid = AL_FALSE;
1407 break;
1411 if (bSourcesValid)
1413 for (i=0;i<n;i++)
1415 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1416 if (Source->state!=AL_INITIAL)
1418 Source->state=AL_STOPPED;
1419 Source->inuse=AL_FALSE;
1420 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1421 ALBufferListItem= Source->queue;
1422 while (ALBufferListItem != NULL)
1424 ALBufferListItem->bufferstate = PROCESSED;
1425 ALBufferListItem = ALBufferListItem->next;
1428 Source->lOffset = 0;
1432 else
1434 // sources is a NULL pointer
1435 alSetError(AL_INVALID_VALUE);
1438 ProcessContext(Context);
1440 else
1442 // Invalid Context
1443 alSetError(AL_INVALID_OPERATION);
1446 return;
1449 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1451 alSourceRewindv(1, &source);
1452 return;
1455 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1457 ALCcontext *Context;
1458 ALsource *Source;
1459 ALsizei i;
1460 ALbufferlistitem *ALBufferListItem;
1461 ALboolean bSourcesValid = AL_TRUE;
1463 Context=alcGetCurrentContext();
1464 if (Context)
1466 SuspendContext(Context);
1468 if (sources)
1470 // Check all the Sources are valid
1471 for (i=0;i<n;i++)
1473 if (!alIsSource(sources[i]))
1475 alSetError(AL_INVALID_NAME);
1476 bSourcesValid = AL_FALSE;
1477 break;
1481 if (bSourcesValid)
1483 for (i=0;i<n;i++)
1485 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1486 if (Source->state!=AL_INITIAL)
1488 Source->state=AL_INITIAL;
1489 Source->inuse=AL_FALSE;
1490 Source->position=0;
1491 Source->position_fraction=0;
1492 Source->BuffersProcessed = 0;
1493 ALBufferListItem= Source->queue;
1494 while (ALBufferListItem != NULL)
1496 ALBufferListItem->bufferstate = PENDING;
1497 ALBufferListItem = ALBufferListItem->next;
1499 if (Source->queue)
1500 Source->ulBufferID = Source->queue->buffer;
1502 Source->lOffset = 0;
1506 else
1508 // sources is a NULL pointer
1509 alSetError(AL_INVALID_VALUE);
1512 ProcessContext(Context);
1514 else
1516 // Invalid Context
1517 alSetError(AL_INVALID_OPERATION);
1520 return;
1524 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1526 ALCcontext *Context;
1527 ALsource *ALSource;
1528 ALsizei i;
1529 ALbufferlistitem *ALBufferList;
1530 ALbufferlistitem *ALBufferListStart;
1531 ALuint DataSize;
1532 ALuint BufferSize;
1533 ALint iFrequency;
1534 ALint iFormat;
1535 ALboolean bBuffersValid = AL_TRUE;
1537 if (n == 0)
1538 return;
1540 Context=alcGetCurrentContext();
1541 if (Context)
1543 SuspendContext(Context);
1545 DataSize = 0;
1546 BufferSize = 0;
1548 // Check that all buffers are valid or zero and that the source is valid
1550 // Check that this is a valid source
1551 if (alIsSource(source))
1553 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1555 // Check that this is not a STATIC Source
1556 if (ALSource->lSourceType != AL_STATIC)
1558 iFrequency = -1;
1559 iFormat = -1;
1561 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1562 ALBufferList = ALSource->queue;
1563 while (ALBufferList)
1565 if (ALBufferList->buffer)
1567 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1568 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1569 break;
1571 ALBufferList = ALBufferList->next;
1574 for (i = 0; i < n; i++)
1576 if (alIsBuffer(buffers[i]))
1578 if (buffers[i])
1580 if ((iFrequency == -1) && (iFormat == -1))
1582 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1583 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1585 else
1587 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1588 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1590 alSetError(AL_INVALID_OPERATION);
1591 bBuffersValid = AL_FALSE;
1592 break;
1597 else
1599 alSetError(AL_INVALID_NAME);
1600 bBuffersValid = AL_FALSE;
1601 break;
1605 if (bBuffersValid)
1607 // Change Source Type
1608 ALSource->lSourceType = AL_STREAMING;
1610 // All buffers are valid - so add them to the list
1611 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1612 ALBufferListStart->buffer = buffers[0];
1613 ALBufferListStart->bufferstate = PENDING;
1614 ALBufferListStart->flag = 0;
1615 ALBufferListStart->next = NULL;
1617 if (buffers[0])
1618 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1619 else
1620 BufferSize = 0;
1622 DataSize += BufferSize;
1624 // Increment reference counter for buffer
1625 if (buffers[0])
1626 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1628 ALBufferList = ALBufferListStart;
1630 for (i = 1; i < n; i++)
1632 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1633 ALBufferList->next->buffer = buffers[i];
1634 ALBufferList->next->bufferstate = PENDING;
1635 ALBufferList->next->flag = 0;
1636 ALBufferList->next->next = NULL;
1638 if (buffers[i])
1639 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1640 else
1641 BufferSize = 0;
1643 DataSize += BufferSize;
1645 // Increment reference counter for buffer
1646 if (buffers[i])
1647 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1649 ALBufferList = ALBufferList->next;
1652 if (ALSource->queue == NULL)
1654 ALSource->queue = ALBufferListStart;
1655 // Update Current Buffer
1656 ALSource->ulBufferID = ALBufferListStart->buffer;
1658 else
1660 // Find end of queue
1661 ALBufferList = ALSource->queue;
1662 while (ALBufferList->next != NULL)
1664 ALBufferList = ALBufferList->next;
1667 ALBufferList->next = ALBufferListStart;
1670 // Update number of buffers in queue
1671 ALSource->BuffersInQueue += n;
1674 else
1676 // Invalid Source Type (can't queue on a Static Source)
1677 alSetError(AL_INVALID_OPERATION);
1680 else
1682 // Invalid Source Name
1683 alSetError(AL_INVALID_NAME);
1686 ProcessContext(Context);
1688 else
1690 // Invalid Context
1691 alSetError(AL_INVALID_OPERATION);
1694 return;
1698 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1699 // an array of buffer IDs that are to be filled with the names of the buffers removed
1700 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1702 ALCcontext *Context;
1703 ALsource *ALSource;
1704 ALsizei i;
1705 ALbufferlistitem *ALBufferList;
1706 ALuint DataSize;
1707 ALuint BufferSize;
1708 ALuint BufferID;
1709 ALboolean bBuffersProcessed;
1711 if (n == 0)
1712 return;
1714 DataSize = 0;
1715 BufferSize = 0;
1716 bBuffersProcessed = AL_TRUE;
1718 Context=alcGetCurrentContext();
1719 if (Context)
1721 SuspendContext(Context);
1723 if (alIsSource(source))
1725 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1727 // Check that all 'n' buffers have been processed
1728 ALBufferList = ALSource->queue;
1729 for (i = 0; i < n; i++)
1731 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1733 ALBufferList = ALBufferList->next;
1735 else
1737 bBuffersProcessed = AL_FALSE;
1738 break;
1742 // If all 'n' buffers have been processed, remove them from the queue
1743 if (bBuffersProcessed)
1745 for (i = 0; i < n; i++)
1747 ALBufferList = ALSource->queue;
1749 ALSource->queue = ALBufferList->next;
1750 // Record name of buffer
1751 buffers[i] = ALBufferList->buffer;
1752 // Decrement buffer reference counter
1753 if (ALBufferList->buffer)
1754 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1755 // Record size of buffer
1756 if (ALBufferList->buffer)
1757 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1758 else
1759 BufferSize = 0;
1761 DataSize += BufferSize;
1762 // Release memory for buffer list item
1763 free(ALBufferList);
1764 ALSource->BuffersInQueue--;
1765 ALSource->BuffersProcessed--;
1768 if (ALSource->state != AL_PLAYING)
1770 if (ALSource->queue)
1771 BufferID = ALSource->queue->buffer;
1772 else
1773 BufferID = 0;
1775 ALSource->ulBufferID = BufferID;
1778 if((ALuint)n > ALSource->BuffersPlayed)
1780 ALSource->BuffersPlayed = 0;
1781 ALSource->BufferPosition = 0;
1783 else
1784 ALSource->BuffersPlayed -= n;
1786 else
1788 // Some buffers can't be unqueue because they have not been processed
1789 alSetError(AL_INVALID_VALUE);
1792 else
1794 // Invalid Source Name
1795 alSetError(AL_INVALID_NAME);
1798 ProcessContext(Context);
1800 else
1802 // Invalid Context
1803 alSetError(AL_INVALID_OPERATION);
1806 return;
1810 static ALvoid InitSourceParams(ALsource *pSource)
1812 pSource->flInnerAngle = 360.0f;
1813 pSource->flOuterAngle = 360.0f;
1814 pSource->flPitch = 1.0f;
1815 pSource->vPosition[0] = 0.0f;
1816 pSource->vPosition[1] = 0.0f;
1817 pSource->vPosition[2] = 0.0f;
1818 pSource->vOrientation[0] = 0.0f;
1819 pSource->vOrientation[1] = 0.0f;
1820 pSource->vOrientation[2] = 0.0f;
1821 pSource->vVelocity[0] = 0.0f;
1822 pSource->vVelocity[1] = 0.0f;
1823 pSource->vVelocity[2] = 0.0f;
1824 pSource->flRefDistance = 1.0f;
1825 pSource->flMaxDistance = FLT_MAX;
1826 pSource->flRollOffFactor = 1.0f;
1827 pSource->bLooping = AL_FALSE;
1828 pSource->flGain = 1.0f;
1829 pSource->flMinGain = 0.0f;
1830 pSource->flMaxGain = 1.0f;
1831 pSource->flOuterGain = 0.0f;
1833 pSource->state = AL_INITIAL;
1834 pSource->lSourceType = AL_UNDETERMINED;
1836 pSource->ulBufferID= 0;
1841 GetSourceOffset
1843 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1844 The offset is relative to the start of the queue (not the start of the current buffer)
1846 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1848 ALbufferlistitem *pBufferList;
1849 ALbuffer *pBuffer;
1850 ALfloat flBufferFreq;
1851 ALint lBytesPlayed, lChannels;
1852 ALenum eOriginalFormat;
1853 ALboolean bReturn = AL_TRUE;
1854 ALint lTotalBufferDataSize;
1856 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1858 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
1859 // Get Current Buffer Size and frequency (in milliseconds)
1860 flBufferFreq = (ALfloat)pBuffer->frequency;
1861 eOriginalFormat = pBuffer->eOriginalFormat;
1862 lChannels = aluChannelsFromFormat(pBuffer->format);
1864 // Get Current BytesPlayed
1865 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1866 // Add byte length of any processed buffers in the queue
1867 pBufferList = pSource->queue;
1868 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1870 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1871 pBufferList = pBufferList->next;
1874 lTotalBufferDataSize = 0;
1875 pBufferList = pSource->queue;
1876 while (pBufferList)
1878 if (pBufferList->buffer)
1879 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1880 pBufferList = pBufferList->next;
1883 if (pSource->bLooping)
1885 if (lBytesPlayed < 0)
1886 lBytesPlayed = 0;
1887 else
1888 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1890 else
1892 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1893 if(lBytesPlayed < 0)
1894 lBytesPlayed = 0;
1895 if(lBytesPlayed > lTotalBufferDataSize)
1896 lBytesPlayed = lTotalBufferDataSize;
1899 switch (eName)
1901 case AL_SEC_OFFSET:
1902 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1903 break;
1904 case AL_SAMPLE_OFFSET:
1905 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1906 break;
1907 case AL_BYTE_OFFSET:
1908 // Take into account the original format of the Buffer
1909 if (aluBytesFromFormat(eOriginalFormat) == 1)
1911 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1913 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1915 *pflOffset = (ALfloat)(lBytesPlayed << 1);
1917 else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1918 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1920 // Compression rate of the ADPCM supported is 3.6111 to 1
1921 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1922 // Round down to nearest ADPCM block
1923 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1925 else
1927 *pflOffset = (ALfloat)lBytesPlayed;
1929 break;
1932 else
1934 *pflOffset = 0.0f;
1937 return bReturn;
1942 ApplyOffset
1944 Apply a playback offset to the Source. This function will update the queue (to correctly
1945 mark buffers as 'pending' or 'processed' depending upon the new offset.
1947 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1949 ALbufferlistitem *pBufferList;
1950 ALbuffer *pBuffer;
1951 ALint lBufferSize, lTotalBufferSize;
1952 ALint lByteOffset;
1954 // Get true byte offset
1955 lByteOffset = GetByteOffset(pSource);
1957 // If this is a valid offset apply it
1958 if (lByteOffset != -1)
1960 // Sort out the queue (pending and processed states)
1961 pBufferList = pSource->queue;
1962 lTotalBufferSize = 0;
1963 pSource->BuffersPlayed = 0;
1964 pSource->BuffersProcessed = 0;
1965 while (pBufferList)
1967 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
1968 lBufferSize = pBuffer ? pBuffer->size : 0;
1970 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1972 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
1973 // update the state to PROCESSED
1974 pSource->BuffersPlayed++;
1976 if (!pSource->bLooping)
1978 pBufferList->bufferstate = PROCESSED;
1979 pSource->BuffersProcessed++;
1982 else if (lTotalBufferSize <= lByteOffset)
1984 // Offset is within this buffer
1985 pBufferList->bufferstate = PENDING;
1987 // Set Current Buffer ID
1988 pSource->ulBufferID = pBufferList->buffer;
1990 // Set current position in this buffer
1991 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
1993 // Set Total Bytes Played to Offset
1994 pSource->lBytesPlayed = lByteOffset;
1996 // SW Mixer Positions are in Samples
1997 pSource->position = pSource->BufferPosition /
1998 aluBytesFromFormat(pBuffer->format) /
1999 aluChannelsFromFormat(pBuffer->format);
2001 else
2003 // Offset is before this buffer, so mark as pending
2004 pBufferList->bufferstate = PENDING;
2007 // Increment the TotalBufferSize
2008 lTotalBufferSize += lBufferSize;
2010 // Move on to next buffer in the Queue
2011 pBufferList = pBufferList->next;
2014 else
2016 if (bUpdateContext)
2017 alSetError(AL_INVALID_VALUE);
2020 // Clear Offset
2021 pSource->lOffset = 0;
2026 GetByteOffset
2028 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2029 offset supplied by the application). This takes into account the fact that the buffer format
2030 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2032 static ALint GetByteOffset(ALsource *pSource)
2034 ALbuffer *pBuffer = NULL;
2035 ALbufferlistitem *pBufferList;
2036 ALfloat flBufferFreq;
2037 ALint lChannels;
2038 ALint lByteOffset = -1;
2039 ALint lTotalBufferDataSize;
2041 // Find the first non-NULL Buffer in the Queue
2042 pBufferList = pSource->queue;
2043 while (pBufferList)
2045 if (pBufferList->buffer)
2047 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2048 break;
2050 pBufferList = pBufferList->next;
2053 if (pBuffer)
2055 flBufferFreq = ((ALfloat)pBuffer->frequency);
2056 lChannels = aluChannelsFromFormat(pBuffer->format);
2058 // Determine the ByteOffset (and ensure it is block aligned)
2059 switch (pSource->lOffsetType)
2061 case AL_BYTE_OFFSET:
2062 // Take into consideration the original format
2063 if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2065 lByteOffset = pSource->lOffset * 2;
2066 lByteOffset -= (lByteOffset % (lChannels * 2));
2068 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2070 lByteOffset = pSource->lOffset / 2;
2071 lByteOffset -= (lByteOffset % (lChannels * 2));
2073 else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2074 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2076 // Round down to nearest ADPCM block
2077 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2078 // Multiply by compression rate
2079 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2080 lByteOffset -= (lByteOffset % (lChannels * 2));
2082 else
2084 lByteOffset = pSource->lOffset;
2085 lByteOffset -= (lByteOffset % (lChannels * 2));
2087 break;
2089 case AL_SAMPLE_OFFSET:
2090 lByteOffset = pSource->lOffset * lChannels * 2;
2091 break;
2093 case AL_SEC_OFFSET:
2094 // Note - lOffset is internally stored as Milliseconds
2095 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2096 lByteOffset -= (lByteOffset % (lChannels * 2));
2097 break;
2100 lTotalBufferDataSize = 0;
2101 pBufferList = pSource->queue;
2102 while (pBufferList)
2104 if (pBufferList->buffer)
2105 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2106 pBufferList = pBufferList->next;
2109 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2110 if (lByteOffset >= lTotalBufferDataSize)
2111 lByteOffset = -1;
2114 return lByteOffset;