Release 1.1.93
[openal-soft/openbsd.git] / OpenAL32 / alSource.c
blob7fad9b90e11b75b2cdc9ebc5ef0eded27453521f
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"
29 #include "alBuffer.h"
30 #include "alThunk.h"
32 static ALvoid InitSourceParams(ALsource *pSource);
33 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
34 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
35 static ALint GetByteOffset(ALsource *pSource);
37 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
39 ALCcontext *Context;
40 ALCdevice *Device;
41 ALsizei i=0;
43 Context = alcGetCurrentContext();
44 if (Context)
46 SuspendContext(Context);
48 if (n > 0)
50 Device = alcGetContextsDevice(Context);
52 if (Device)
54 // Check that enough memory has been allocted in the 'sources' array for n Sources
55 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
57 // Check that the requested number of sources can be generated
58 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
60 ALsource **list = &Context->Source;
61 while(*list)
62 list = &(*list)->next;
64 // Add additional sources to the list (Source->next points to the location for the next Source structure)
65 while(i < n)
67 *list = calloc(1, sizeof(ALsource));
68 if(*list)
70 sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list);
71 (*list)->source = sources[i];
73 InitSourceParams(*list);
74 Context->SourceCount++;
75 i++;
77 list = &(*list)->next;
81 // If we didn't create all the Sources, we must have run out or memory
82 if(i != n)
83 alSetError(AL_OUT_OF_MEMORY);
85 else
87 // Not enough resources to create the Sources
88 alSetError(AL_INVALID_VALUE);
91 else
93 // Bad pointer
94 alSetError(AL_INVALID_VALUE);
97 else
99 // No Device created, or attached to Context
100 alSetError(AL_INVALID_OPERATION);
104 ProcessContext(Context);
106 else
108 // Invalid Context
109 alSetError(AL_INVALID_OPERATION);
112 return;
116 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
118 ALCcontext *Context;
119 ALCdevice *Device;
120 ALsource *ALSource;
121 ALsource **list;
122 ALsizei i;
123 ALbufferlistitem *ALBufferList;
124 ALboolean bSourcesValid = AL_TRUE;
126 Context = alcGetCurrentContext();
127 if (Context)
129 SuspendContext(Context);
131 if (n >= 0)
133 Device = alcGetContextsDevice(Context);
135 if (Device)
137 if ((ALuint)n <= Context->SourceCount)
139 // Check that all Sources are valid (and can therefore be deleted)
140 for (i = 0; i < n; i++)
142 if (!alIsSource(sources[i]))
144 alSetError(AL_INVALID_NAME);
145 bSourcesValid = AL_FALSE;
146 break;
150 if (bSourcesValid)
152 // All Sources are valid, and can be deleted
153 for (i = 0; i < n; i++)
155 // Recheck that the Source is valid, because there could be duplicated Source names
156 if (alIsSource(sources[i]))
158 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
159 alSourceStop((ALuint)ALSource->source);
161 // For each buffer in the source's queue, decrement its reference counter and remove it
162 while (ALSource->queue != NULL)
164 ALBufferList = ALSource->queue;
165 // Decrement buffer's reference counter
166 if (ALBufferList->buffer != 0)
167 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
168 // Update queue to point to next element in list
169 ALSource->queue = ALBufferList->next;
170 // Release memory allocated for buffer list item
171 free(ALBufferList);
174 // Decrement Source count
175 Context->SourceCount--;
177 // Remove Source from list of Sources
178 list = &Context->Source;
179 while(*list && *list != ALSource)
180 list = &(*list)->next;
182 if(*list)
183 *list = (*list)->next;
184 ALTHUNK_REMOVEENTRY(ALSource->source);
186 memset(ALSource,0,sizeof(ALsource));
187 free(ALSource);
193 else
195 // Trying to delete more Sources than have been generated
196 alSetError(AL_INVALID_NAME);
199 else
201 // No Device created, or attached to Context
202 alSetError(AL_INVALID_OPERATION);
205 else
206 alSetError(AL_INVALID_VALUE);
208 ProcessContext(Context);
210 else
212 // Invalid Context
213 alSetError(AL_INVALID_OPERATION);
216 return;
220 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
222 ALboolean result=AL_FALSE;
223 ALCcontext *Context;
224 ALsource *Source;
226 Context=alcGetCurrentContext();
227 if (Context)
229 SuspendContext(Context);
231 // To determine if this is a valid Source name, look through the list of generated Sources
232 Source = Context->Source;
233 while(Source)
235 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
237 result = AL_TRUE;
238 break;
241 Source = Source->next;
244 ProcessContext(Context);
246 else
248 // Invalid Context
249 alSetError(AL_INVALID_OPERATION);
252 return result;
256 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
258 ALCcontext *pContext;
259 ALsource *pSource;
261 pContext = alcGetCurrentContext();
262 if (pContext)
264 SuspendContext(pContext);
266 if (alIsSource(source))
268 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
270 switch (eParam)
272 case AL_PITCH:
273 if (flValue >= 0.0f)
275 pSource->flPitch = flValue;
276 if(pSource->flPitch < 0.001f)
277 pSource->flPitch = 0.001f;
279 else
280 alSetError(AL_INVALID_VALUE);
281 break;
283 case AL_CONE_INNER_ANGLE:
284 if ((flValue >= 0.0f) && (flValue <= 360.0f))
285 pSource->flInnerAngle = flValue;
286 else
287 alSetError(AL_INVALID_VALUE);
288 break;
290 case AL_CONE_OUTER_ANGLE:
291 if ((flValue >= 0.0f) && (flValue <= 360.0f))
292 pSource->flOuterAngle = flValue;
293 else
294 alSetError(AL_INVALID_VALUE);
295 break;
297 case AL_GAIN:
298 if (flValue >= 0.0f)
299 pSource->flGain = flValue;
300 else
301 alSetError(AL_INVALID_VALUE);
302 break;
304 case AL_MAX_DISTANCE:
305 if (flValue >= 0.0f)
306 pSource->flMaxDistance = flValue;
307 else
308 alSetError(AL_INVALID_VALUE);
309 break;
311 case AL_ROLLOFF_FACTOR:
312 if (flValue >= 0.0f)
313 pSource->flRollOffFactor = flValue;
314 else
315 alSetError(AL_INVALID_VALUE);
316 break;
318 case AL_REFERENCE_DISTANCE:
319 if (flValue >= 0.0f)
320 pSource->flRefDistance = flValue;
321 else
322 alSetError(AL_INVALID_VALUE);
323 break;
325 case AL_MIN_GAIN:
326 if ((flValue >= 0.0f) && (flValue <= 1.0f))
327 pSource->flMinGain = flValue;
328 else
329 alSetError(AL_INVALID_VALUE);
330 break;
332 case AL_MAX_GAIN:
333 if ((flValue >= 0.0f) && (flValue <= 1.0f))
334 pSource->flMaxGain = flValue;
335 else
336 alSetError(AL_INVALID_VALUE);
337 break;
339 case AL_CONE_OUTER_GAIN:
340 if ((flValue >= 0.0f) && (flValue <= 1.0f))
341 pSource->flOuterGain = flValue;
342 else
343 alSetError(AL_INVALID_VALUE);
344 break;
346 case AL_SEC_OFFSET:
347 case AL_SAMPLE_OFFSET:
348 case AL_BYTE_OFFSET:
349 if (flValue >= 0.0f)
351 pSource->lOffsetType = eParam;
353 // Store Offset (convert Seconds into Milliseconds)
354 if (eParam == AL_SEC_OFFSET)
355 pSource->lOffset = (ALint)(flValue * 1000.0f);
356 else
357 pSource->lOffset = (ALint)flValue;
359 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
360 ApplyOffset(pSource, AL_TRUE);
362 else
363 alSetError(AL_INVALID_VALUE);
364 break;
366 default:
367 alSetError(AL_INVALID_ENUM);
368 break;
371 else
373 // Invalid Source Name
374 alSetError(AL_INVALID_NAME);
377 ProcessContext(pContext);
379 else
381 // Invalid context
382 alSetError(AL_INVALID_OPERATION);
385 return;
389 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
391 ALCcontext *pContext;
392 ALsource *pSource;
394 pContext = alcGetCurrentContext();
395 if (pContext)
397 SuspendContext(pContext);
399 if (alIsSource(source))
401 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
402 switch(eParam)
404 case AL_POSITION:
405 pSource->vPosition[0] = flValue1;
406 pSource->vPosition[1] = flValue2;
407 pSource->vPosition[2] = flValue3;
408 break;
410 case AL_VELOCITY:
411 pSource->vVelocity[0] = flValue1;
412 pSource->vVelocity[1] = flValue2;
413 pSource->vVelocity[2] = flValue3;
414 break;
416 case AL_DIRECTION:
417 pSource->vOrientation[0] = flValue1;
418 pSource->vOrientation[1] = flValue2;
419 pSource->vOrientation[2] = flValue3;
420 break;
422 default:
423 alSetError(AL_INVALID_ENUM);
424 break;
427 else
428 alSetError(AL_INVALID_NAME);
430 ProcessContext(pContext);
432 else
434 alSetError(AL_INVALID_OPERATION);
437 return;
441 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
443 ALCcontext *pContext;
445 pContext = alcGetCurrentContext();
446 if (pContext)
448 SuspendContext(pContext);
450 if (pflValues)
452 if (alIsSource(source))
454 switch (eParam)
456 case AL_PITCH:
457 case AL_CONE_INNER_ANGLE:
458 case AL_CONE_OUTER_ANGLE:
459 case AL_GAIN:
460 case AL_MAX_DISTANCE:
461 case AL_ROLLOFF_FACTOR:
462 case AL_REFERENCE_DISTANCE:
463 case AL_MIN_GAIN:
464 case AL_MAX_GAIN:
465 case AL_CONE_OUTER_GAIN:
466 case AL_SEC_OFFSET:
467 case AL_SAMPLE_OFFSET:
468 case AL_BYTE_OFFSET:
469 alSourcef(source, eParam, pflValues[0]);
470 break;
472 case AL_POSITION:
473 case AL_VELOCITY:
474 case AL_DIRECTION:
475 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
476 break;
478 default:
479 alSetError(AL_INVALID_ENUM);
480 break;
483 else
484 alSetError(AL_INVALID_NAME);
486 else
487 alSetError(AL_INVALID_VALUE);
489 ProcessContext(pContext);
491 else
492 alSetError(AL_INVALID_OPERATION);
494 return;
498 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
500 ALCcontext *pContext;
501 ALsource *pSource;
502 ALbufferlistitem *pALBufferListItem;
503 ALint Counter = 0;
504 ALint DataSize = 0;
505 ALint BufferSize;
507 pContext = alcGetCurrentContext();
508 if (pContext)
510 SuspendContext(pContext);
512 if (alIsSource(source))
514 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
516 switch(eParam)
518 case AL_MAX_DISTANCE:
519 case AL_ROLLOFF_FACTOR:
520 case AL_REFERENCE_DISTANCE:
521 alSourcef(source, eParam, (ALfloat)lValue);
522 break;
524 case AL_SOURCE_RELATIVE:
525 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
526 pSource->bHeadRelative = (ALboolean)lValue;
527 else
528 alSetError(AL_INVALID_VALUE);
529 break;
531 case AL_CONE_INNER_ANGLE:
532 if ((lValue >= 0) && (lValue <= 360))
533 pSource->flInnerAngle = (float)lValue;
534 else
535 alSetError(AL_INVALID_VALUE);
536 break;
538 case AL_CONE_OUTER_ANGLE:
539 if ((lValue >= 0) && (lValue <= 360))
540 pSource->flOuterAngle = (float)lValue;
541 else
542 alSetError(AL_INVALID_VALUE);
543 break;
545 case AL_LOOPING:
546 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
547 pSource->bLooping = (ALboolean)lValue;
548 else
549 alSetError(AL_INVALID_VALUE);
550 break;
552 case AL_BUFFER:
553 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
555 if (alIsBuffer(lValue))
557 // Remove all elements in the queue
558 while (pSource->queue != NULL)
560 pALBufferListItem = pSource->queue;
561 pSource->queue = pALBufferListItem->next;
562 // Decrement reference counter for buffer
563 if (pALBufferListItem->buffer)
564 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
565 // Record size of buffer
566 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
567 DataSize += BufferSize;
568 // Increment the number of buffers removed from queue
569 Counter++;
570 // Release memory for buffer list item
571 free(pALBufferListItem);
572 // Decrement the number of buffers in the queue
573 pSource->BuffersInQueue--;
576 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
577 if (lValue != 0)
579 // Source is now in STATIC mode
580 pSource->lSourceType = AL_STATIC;
582 // Add the selected buffer to the queue
583 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
584 pALBufferListItem->buffer = lValue;
585 pALBufferListItem->bufferstate = PENDING;
586 pALBufferListItem->flag = 0;
587 pALBufferListItem->next = NULL;
589 pSource->queue = pALBufferListItem;
590 pSource->BuffersInQueue = 1;
592 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
594 // Increment reference counter for buffer
595 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
597 else
599 // Source is now in UNDETERMINED mode
600 pSource->lSourceType = AL_UNDETERMINED;
603 // Set Buffers Processed
604 pSource->BuffersProcessed = 0;
606 // Update AL_BUFFER parameter
607 pSource->ulBufferID = lValue;
609 else
610 alSetError(AL_INVALID_VALUE);
612 else
613 alSetError(AL_INVALID_OPERATION);
614 break;
616 case AL_SOURCE_STATE:
617 // Query only
618 alSetError(AL_INVALID_OPERATION);
619 break;
621 case AL_SEC_OFFSET:
622 case AL_SAMPLE_OFFSET:
623 case AL_BYTE_OFFSET:
624 if (lValue >= 0)
626 pSource->lOffsetType = eParam;
628 // Store Offset (convert Seconds into Milliseconds)
629 if (eParam == AL_SEC_OFFSET)
630 pSource->lOffset = lValue * 1000;
631 else
632 pSource->lOffset = lValue;
634 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
635 ApplyOffset(pSource, AL_TRUE);
637 else
638 alSetError(AL_INVALID_VALUE);
639 break;
641 default:
642 alSetError(AL_INVALID_ENUM);
643 break;
646 else
647 alSetError(AL_INVALID_NAME);
649 ProcessContext(pContext);
651 else
652 alSetError(AL_INVALID_OPERATION);
654 return;
658 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
660 ALCcontext *pContext;
662 pContext = alcGetCurrentContext();
663 if (pContext)
665 SuspendContext(pContext);
667 if (alIsSource(source))
669 switch (eParam)
671 case AL_POSITION:
672 case AL_VELOCITY:
673 case AL_DIRECTION:
674 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
675 break;
677 default:
678 alSetError(AL_INVALID_ENUM);
679 break;
682 else
683 alSetError(AL_INVALID_NAME);
685 ProcessContext(pContext);
687 else
688 alSetError(AL_INVALID_OPERATION);
690 return;
694 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
696 ALCcontext *pContext;
698 pContext = alcGetCurrentContext();
699 if (pContext)
701 SuspendContext(pContext);
703 if (plValues)
705 if (alIsSource(source))
707 switch (eParam)
709 case AL_SOURCE_RELATIVE:
710 case AL_CONE_INNER_ANGLE:
711 case AL_CONE_OUTER_ANGLE:
712 case AL_LOOPING:
713 case AL_BUFFER:
714 case AL_SOURCE_STATE:
715 case AL_SEC_OFFSET:
716 case AL_SAMPLE_OFFSET:
717 case AL_BYTE_OFFSET:
718 case AL_MAX_DISTANCE:
719 case AL_ROLLOFF_FACTOR:
720 case AL_REFERENCE_DISTANCE:
721 alSourcei(source, eParam, plValues[0]);
722 break;
724 case AL_POSITION:
725 case AL_VELOCITY:
726 case AL_DIRECTION:
727 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
728 break;
730 default:
731 alSetError(AL_INVALID_ENUM);
732 break;
735 else
736 alSetError(AL_INVALID_NAME);
738 else
739 alSetError(AL_INVALID_VALUE);
741 ProcessContext(pContext);
743 else
744 alSetError(AL_INVALID_OPERATION);
746 return;
750 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
752 ALCcontext *pContext;
753 ALsource *pSource;
754 ALfloat flOffset;
756 pContext = alcGetCurrentContext();
757 if (pContext)
759 SuspendContext(pContext);
761 if (pflValue)
763 if (alIsSource(source))
765 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
767 switch(eParam)
769 case AL_PITCH:
770 *pflValue = pSource->flPitch;
771 break;
773 case AL_GAIN:
774 *pflValue = pSource->flGain;
775 break;
777 case AL_MIN_GAIN:
778 *pflValue = pSource->flMinGain;
779 break;
781 case AL_MAX_GAIN:
782 *pflValue = pSource->flMaxGain;
783 break;
785 case AL_MAX_DISTANCE:
786 *pflValue = pSource->flMaxDistance;
787 break;
789 case AL_ROLLOFF_FACTOR:
790 *pflValue = pSource->flRollOffFactor;
791 break;
793 case AL_CONE_OUTER_GAIN:
794 *pflValue = pSource->flOuterGain;
795 break;
797 case AL_SEC_OFFSET:
798 case AL_SAMPLE_OFFSET:
799 case AL_BYTE_OFFSET:
800 if (GetSourceOffset(pSource, eParam, &flOffset))
801 *pflValue = flOffset;
802 else
803 alSetError(AL_INVALID_OPERATION);
804 break;
806 case AL_CONE_INNER_ANGLE:
807 *pflValue = pSource->flInnerAngle;
808 break;
810 case AL_CONE_OUTER_ANGLE:
811 *pflValue = pSource->flOuterAngle;
812 break;
814 case AL_REFERENCE_DISTANCE:
815 *pflValue = pSource->flRefDistance;
816 break;
818 default:
819 alSetError(AL_INVALID_ENUM);
820 break;
823 else
824 alSetError(AL_INVALID_NAME);
826 else
827 alSetError(AL_INVALID_VALUE);
829 ProcessContext(pContext);
831 else
832 alSetError(AL_INVALID_OPERATION);
834 return;
838 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
840 ALCcontext *pContext;
841 ALsource *pSource;
843 pContext = alcGetCurrentContext();
844 if (pContext)
846 SuspendContext(pContext);
848 if ((pflValue1) && (pflValue2) && (pflValue3))
850 if (alIsSource(source))
852 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
854 switch(eParam)
856 case AL_POSITION:
857 *pflValue1 = pSource->vPosition[0];
858 *pflValue2 = pSource->vPosition[1];
859 *pflValue3 = pSource->vPosition[2];
860 break;
862 case AL_VELOCITY:
863 *pflValue1 = pSource->vVelocity[0];
864 *pflValue2 = pSource->vVelocity[1];
865 *pflValue3 = pSource->vVelocity[2];
866 break;
868 case AL_DIRECTION:
869 *pflValue1 = pSource->vOrientation[0];
870 *pflValue2 = pSource->vOrientation[1];
871 *pflValue3 = pSource->vOrientation[2];
872 break;
874 default:
875 alSetError(AL_INVALID_ENUM);
876 break;
879 else
880 alSetError(AL_INVALID_NAME);
882 else
883 alSetError(AL_INVALID_VALUE);
885 ProcessContext(pContext);
887 else
888 alSetError(AL_INVALID_OPERATION);
890 return;
894 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
896 ALCcontext *pContext;
897 ALsource *pSource;
899 pContext = alcGetCurrentContext();
900 if (pContext)
902 SuspendContext(pContext);
904 if (pflValues)
906 if (alIsSource(source))
908 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
910 switch(eParam)
912 case AL_PITCH:
913 case AL_GAIN:
914 case AL_MIN_GAIN:
915 case AL_MAX_GAIN:
916 case AL_MAX_DISTANCE:
917 case AL_ROLLOFF_FACTOR:
918 case AL_CONE_OUTER_GAIN:
919 case AL_SEC_OFFSET:
920 case AL_SAMPLE_OFFSET:
921 case AL_BYTE_OFFSET:
922 case AL_CONE_INNER_ANGLE:
923 case AL_CONE_OUTER_ANGLE:
924 case AL_REFERENCE_DISTANCE:
925 alGetSourcef(source, eParam, pflValues);
926 break;
928 case AL_POSITION:
929 pflValues[0] = pSource->vPosition[0];
930 pflValues[1] = pSource->vPosition[1];
931 pflValues[2] = pSource->vPosition[2];
932 break;
934 case AL_VELOCITY:
935 pflValues[0] = pSource->vVelocity[0];
936 pflValues[1] = pSource->vVelocity[1];
937 pflValues[2] = pSource->vVelocity[2];
938 break;
940 case AL_DIRECTION:
941 pflValues[0] = pSource->vOrientation[0];
942 pflValues[1] = pSource->vOrientation[1];
943 pflValues[2] = pSource->vOrientation[2];
944 break;
946 default:
947 alSetError(AL_INVALID_ENUM);
948 break;
951 else
952 alSetError(AL_INVALID_NAME);
954 else
955 alSetError(AL_INVALID_VALUE);
957 ProcessContext(pContext);
959 else
960 alSetError(AL_INVALID_OPERATION);
962 return;
966 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
968 ALCcontext *pContext;
969 ALsource *pSource;
970 ALfloat flOffset;
972 pContext = alcGetCurrentContext();
973 if (pContext)
975 SuspendContext(pContext);
977 if (plValue)
979 if (alIsSource(source))
981 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
983 switch(eParam)
985 case AL_MAX_DISTANCE:
986 *plValue = (ALint)pSource->flMaxDistance;
987 break;
989 case AL_ROLLOFF_FACTOR:
990 *plValue = (ALint)pSource->flRollOffFactor;
991 break;
993 case AL_REFERENCE_DISTANCE:
994 *plValue = (ALint)pSource->flRefDistance;
995 break;
997 case AL_SOURCE_RELATIVE:
998 *plValue = pSource->bHeadRelative;
999 break;
1001 case AL_CONE_INNER_ANGLE:
1002 *plValue = (ALint)pSource->flInnerAngle;
1003 break;
1005 case AL_CONE_OUTER_ANGLE:
1006 *plValue = (ALint)pSource->flOuterAngle;
1007 break;
1009 case AL_LOOPING:
1010 *plValue = pSource->bLooping;
1011 break;
1013 case AL_BUFFER:
1014 *plValue = pSource->ulBufferID;
1015 break;
1017 case AL_SOURCE_STATE:
1018 *plValue = pSource->state;
1019 break;
1021 case AL_BUFFERS_QUEUED:
1022 *plValue = pSource->BuffersInQueue;
1023 break;
1025 case AL_BUFFERS_PROCESSED:
1026 if(pSource->bLooping)
1028 /* Buffers on a looping source are in a perpetual state
1029 * of PENDING, so don't report any as PROCESSED */
1030 *plValue = 0;
1032 else
1033 *plValue = pSource->BuffersProcessed;
1034 break;
1036 case AL_SOURCE_TYPE:
1037 *plValue = pSource->lSourceType;
1038 break;
1040 case AL_SEC_OFFSET:
1041 case AL_SAMPLE_OFFSET:
1042 case AL_BYTE_OFFSET:
1043 if (GetSourceOffset(pSource, eParam, &flOffset))
1044 *plValue = (ALint)flOffset;
1045 else
1046 alSetError(AL_INVALID_OPERATION);
1047 break;
1049 default:
1050 alSetError(AL_INVALID_ENUM);
1051 break;
1054 else
1055 alSetError(AL_INVALID_NAME);
1057 else
1058 alSetError(AL_INVALID_VALUE);
1060 ProcessContext(pContext);
1062 else
1063 alSetError(AL_INVALID_OPERATION);
1065 return;
1069 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1071 ALCcontext *pContext;
1072 ALsource *pSource;
1074 pContext = alcGetCurrentContext();
1075 if (pContext)
1077 SuspendContext(pContext);
1079 if ((plValue1) && (plValue2) && (plValue3))
1081 if (alIsSource(source))
1083 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1085 switch(eParam)
1087 case AL_POSITION:
1088 *plValue1 = (ALint)pSource->vPosition[0];
1089 *plValue2 = (ALint)pSource->vPosition[1];
1090 *plValue3 = (ALint)pSource->vPosition[2];
1091 break;
1093 case AL_VELOCITY:
1094 *plValue1 = (ALint)pSource->vVelocity[0];
1095 *plValue2 = (ALint)pSource->vVelocity[1];
1096 *plValue3 = (ALint)pSource->vVelocity[2];
1097 break;
1099 case AL_DIRECTION:
1100 *plValue1 = (ALint)pSource->vOrientation[0];
1101 *plValue2 = (ALint)pSource->vOrientation[1];
1102 *plValue3 = (ALint)pSource->vOrientation[2];
1103 break;
1105 default:
1106 alSetError(AL_INVALID_ENUM);
1107 break;
1110 else
1111 alSetError(AL_INVALID_NAME);
1113 else
1114 alSetError(AL_INVALID_VALUE);
1116 ProcessContext(pContext);
1118 else
1119 alSetError(AL_INVALID_OPERATION);
1121 return;
1125 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1127 ALCcontext *pContext;
1128 ALsource *pSource;
1130 pContext = alcGetCurrentContext();
1131 if (pContext)
1133 SuspendContext(pContext);
1135 if (plValues)
1137 if (alIsSource(source))
1139 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1141 switch (eParam)
1143 case AL_SOURCE_RELATIVE:
1144 case AL_CONE_INNER_ANGLE:
1145 case AL_CONE_OUTER_ANGLE:
1146 case AL_LOOPING:
1147 case AL_BUFFER:
1148 case AL_SOURCE_STATE:
1149 case AL_BUFFERS_QUEUED:
1150 case AL_BUFFERS_PROCESSED:
1151 case AL_SEC_OFFSET:
1152 case AL_SAMPLE_OFFSET:
1153 case AL_BYTE_OFFSET:
1154 case AL_MAX_DISTANCE:
1155 case AL_ROLLOFF_FACTOR:
1156 case AL_REFERENCE_DISTANCE:
1157 case AL_SOURCE_TYPE:
1158 alGetSourcei(source, eParam, plValues);
1159 break;
1161 case AL_POSITION:
1162 plValues[0] = (ALint)pSource->vPosition[0];
1163 plValues[1] = (ALint)pSource->vPosition[1];
1164 plValues[2] = (ALint)pSource->vPosition[2];
1165 break;
1167 case AL_VELOCITY:
1168 plValues[0] = (ALint)pSource->vVelocity[0];
1169 plValues[1] = (ALint)pSource->vVelocity[1];
1170 plValues[2] = (ALint)pSource->vVelocity[2];
1171 break;
1173 case AL_DIRECTION:
1174 plValues[0] = (ALint)pSource->vOrientation[0];
1175 plValues[1] = (ALint)pSource->vOrientation[1];
1176 plValues[2] = (ALint)pSource->vOrientation[2];
1177 break;
1179 default:
1180 alSetError(AL_INVALID_ENUM);
1181 break;
1184 else
1185 alSetError(AL_INVALID_NAME);
1187 else
1188 alSetError(AL_INVALID_VALUE);
1190 ProcessContext(pContext);
1192 else
1193 alSetError(AL_INVALID_OPERATION);
1195 return;
1199 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1201 alSourcePlayv(1, &source);
1202 return;
1205 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1207 ALCcontext *pContext;
1208 ALsource *pSource;
1209 ALbufferlistitem *ALBufferList;
1210 ALboolean bSourcesValid = AL_TRUE;
1211 ALboolean bPlay;
1212 ALsizei i;
1214 pContext = alcGetCurrentContext();
1215 if (pContext)
1217 SuspendContext(pContext);
1219 if (pSourceList)
1221 // Check that all the Sources are valid
1222 for (i = 0; i < n; i++)
1224 if (!alIsSource(pSourceList[i]))
1226 alSetError(AL_INVALID_NAME);
1227 bSourcesValid = AL_FALSE;
1228 break;
1232 if (bSourcesValid)
1234 for (i = 0; i < n; i++)
1236 // Assume Source won't need to play
1237 bPlay = AL_FALSE;
1239 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1241 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1242 ALBufferList = pSource->queue;
1243 while (ALBufferList)
1245 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1247 bPlay = AL_TRUE;
1248 break;
1250 ALBufferList = ALBufferList->next;
1253 if (bPlay)
1255 if (pSource->state != AL_PAUSED)
1257 pSource->state = AL_PLAYING;
1258 pSource->inuse = AL_TRUE;
1259 pSource->play = AL_TRUE;
1260 pSource->position = 0;
1261 pSource->position_fraction = 0;
1262 pSource->BuffersProcessed = 0;
1263 pSource->BuffersPlayed = 0;
1264 pSource->BufferPosition = 0;
1265 pSource->lBytesPlayed = 0;
1267 pSource->ulBufferID = pSource->queue->buffer;
1269 // Make sure all the Buffers in the queue are marked as PENDING
1270 ALBufferList = pSource->queue;
1271 while (ALBufferList)
1273 ALBufferList->bufferstate = PENDING;
1274 ALBufferList = ALBufferList->next;
1277 else
1279 pSource->state = AL_PLAYING;
1280 pSource->inuse = AL_TRUE;
1281 pSource->play = AL_TRUE;
1284 // Check if an Offset has been set
1285 if (pSource->lOffset)
1286 ApplyOffset(pSource, AL_FALSE);
1288 else
1290 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1291 ALBufferList = pSource->queue;
1292 while (ALBufferList)
1294 ALBufferList->bufferstate = PROCESSED;
1295 ALBufferList = ALBufferList->next;
1298 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1303 else
1305 // sources is a NULL pointer
1306 alSetError(AL_INVALID_VALUE);
1309 ProcessContext(pContext);
1311 else
1313 // Invalid Context
1314 alSetError(AL_INVALID_OPERATION);
1317 return;
1320 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1322 alSourcePausev(1, &source);
1323 return;
1326 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1328 ALCcontext *Context;
1329 ALsource *Source;
1330 ALsizei i;
1331 ALboolean bSourcesValid = AL_TRUE;
1333 Context=alcGetCurrentContext();
1334 if (Context)
1336 SuspendContext(Context);
1338 if (sources)
1340 // Check all the Sources are valid
1341 for (i=0;i<n;i++)
1343 if (!alIsSource(sources[i]))
1345 alSetError(AL_INVALID_NAME);
1346 bSourcesValid = AL_FALSE;
1347 break;
1351 if (bSourcesValid)
1353 for (i=0;i<n;i++)
1355 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1356 if (Source->state==AL_PLAYING)
1358 Source->state=AL_PAUSED;
1359 Source->inuse=AL_FALSE;
1364 else
1366 // sources is a NULL pointer
1367 alSetError(AL_INVALID_VALUE);
1370 ProcessContext(Context);
1372 else
1374 // Invalid Context
1375 alSetError(AL_INVALID_OPERATION);
1378 return;
1381 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1383 alSourceStopv(1, &source);
1384 return;
1387 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1389 ALCcontext *Context;
1390 ALsource *Source;
1391 ALsizei i;
1392 ALbufferlistitem *ALBufferListItem;
1393 ALboolean bSourcesValid = AL_TRUE;
1395 Context=alcGetCurrentContext();
1396 if (Context)
1398 SuspendContext(Context);
1400 if (sources)
1402 // Check all the Sources are valid
1403 for (i=0;i<n;i++)
1405 if (!alIsSource(sources[i]))
1407 alSetError(AL_INVALID_NAME);
1408 bSourcesValid = AL_FALSE;
1409 break;
1413 if (bSourcesValid)
1415 for (i=0;i<n;i++)
1417 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1418 if (Source->state!=AL_INITIAL)
1420 Source->state=AL_STOPPED;
1421 Source->inuse=AL_FALSE;
1422 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1423 ALBufferListItem= Source->queue;
1424 while (ALBufferListItem != NULL)
1426 ALBufferListItem->bufferstate = PROCESSED;
1427 ALBufferListItem = ALBufferListItem->next;
1430 Source->lOffset = 0;
1434 else
1436 // sources is a NULL pointer
1437 alSetError(AL_INVALID_VALUE);
1440 ProcessContext(Context);
1442 else
1444 // Invalid Context
1445 alSetError(AL_INVALID_OPERATION);
1448 return;
1451 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1453 alSourceRewindv(1, &source);
1454 return;
1457 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1459 ALCcontext *Context;
1460 ALsource *Source;
1461 ALsizei i;
1462 ALbufferlistitem *ALBufferListItem;
1463 ALboolean bSourcesValid = AL_TRUE;
1465 Context=alcGetCurrentContext();
1466 if (Context)
1468 SuspendContext(Context);
1470 if (sources)
1472 // Check all the Sources are valid
1473 for (i=0;i<n;i++)
1475 if (!alIsSource(sources[i]))
1477 alSetError(AL_INVALID_NAME);
1478 bSourcesValid = AL_FALSE;
1479 break;
1483 if (bSourcesValid)
1485 for (i=0;i<n;i++)
1487 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1488 if (Source->state!=AL_INITIAL)
1490 Source->state=AL_INITIAL;
1491 Source->inuse=AL_FALSE;
1492 Source->position=0;
1493 Source->position_fraction=0;
1494 Source->BuffersProcessed = 0;
1495 ALBufferListItem= Source->queue;
1496 while (ALBufferListItem != NULL)
1498 ALBufferListItem->bufferstate = PENDING;
1499 ALBufferListItem = ALBufferListItem->next;
1501 if (Source->queue)
1502 Source->ulBufferID = Source->queue->buffer;
1504 Source->lOffset = 0;
1508 else
1510 // sources is a NULL pointer
1511 alSetError(AL_INVALID_VALUE);
1514 ProcessContext(Context);
1516 else
1518 // Invalid Context
1519 alSetError(AL_INVALID_OPERATION);
1522 return;
1526 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1528 ALCcontext *Context;
1529 ALsource *ALSource;
1530 ALsizei i;
1531 ALbufferlistitem *ALBufferList;
1532 ALbufferlistitem *ALBufferListStart;
1533 ALuint DataSize;
1534 ALuint BufferSize;
1535 ALint iFrequency;
1536 ALint iFormat;
1537 ALboolean bBuffersValid = AL_TRUE;
1539 if (n == 0)
1540 return;
1542 Context=alcGetCurrentContext();
1543 if (Context)
1545 SuspendContext(Context);
1547 DataSize = 0;
1548 BufferSize = 0;
1550 // Check that all buffers are valid or zero and that the source is valid
1552 // Check that this is a valid source
1553 if (alIsSource(source))
1555 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1557 // Check that this is not a STATIC Source
1558 if (ALSource->lSourceType != AL_STATIC)
1560 iFrequency = -1;
1561 iFormat = -1;
1563 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1564 ALBufferList = ALSource->queue;
1565 while (ALBufferList)
1567 if (ALBufferList->buffer)
1569 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1570 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1571 break;
1573 ALBufferList = ALBufferList->next;
1576 for (i = 0; i < n; i++)
1578 if (alIsBuffer(buffers[i]))
1580 if (buffers[i])
1582 if ((iFrequency == -1) && (iFormat == -1))
1584 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1585 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1587 else
1589 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1590 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1592 alSetError(AL_INVALID_OPERATION);
1593 bBuffersValid = AL_FALSE;
1594 break;
1599 else
1601 alSetError(AL_INVALID_NAME);
1602 bBuffersValid = AL_FALSE;
1603 break;
1607 if (bBuffersValid)
1609 // Change Source Type
1610 ALSource->lSourceType = AL_STREAMING;
1612 // All buffers are valid - so add them to the list
1613 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1614 ALBufferListStart->buffer = buffers[0];
1615 ALBufferListStart->bufferstate = PENDING;
1616 ALBufferListStart->flag = 0;
1617 ALBufferListStart->next = NULL;
1619 if (buffers[0])
1620 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1621 else
1622 BufferSize = 0;
1624 DataSize += BufferSize;
1626 // Increment reference counter for buffer
1627 if (buffers[0])
1628 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1630 ALBufferList = ALBufferListStart;
1632 for (i = 1; i < n; i++)
1634 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1635 ALBufferList->next->buffer = buffers[i];
1636 ALBufferList->next->bufferstate = PENDING;
1637 ALBufferList->next->flag = 0;
1638 ALBufferList->next->next = NULL;
1640 if (buffers[i])
1641 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1642 else
1643 BufferSize = 0;
1645 DataSize += BufferSize;
1647 // Increment reference counter for buffer
1648 if (buffers[i])
1649 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1651 ALBufferList = ALBufferList->next;
1654 if (ALSource->queue == NULL)
1656 ALSource->queue = ALBufferListStart;
1657 // Update Current Buffer
1658 ALSource->ulBufferID = ALBufferListStart->buffer;
1660 else
1662 // Find end of queue
1663 ALBufferList = ALSource->queue;
1664 while (ALBufferList->next != NULL)
1666 ALBufferList = ALBufferList->next;
1669 ALBufferList->next = ALBufferListStart;
1672 // Update number of buffers in queue
1673 ALSource->BuffersInQueue += n;
1676 else
1678 // Invalid Source Type (can't queue on a Static Source)
1679 alSetError(AL_INVALID_OPERATION);
1682 else
1684 // Invalid Source Name
1685 alSetError(AL_INVALID_NAME);
1688 ProcessContext(Context);
1690 else
1692 // Invalid Context
1693 alSetError(AL_INVALID_OPERATION);
1696 return;
1700 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1701 // an array of buffer IDs that are to be filled with the names of the buffers removed
1702 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1704 ALCcontext *Context;
1705 ALsource *ALSource;
1706 ALsizei i;
1707 ALbufferlistitem *ALBufferList;
1708 ALuint DataSize;
1709 ALuint BufferSize;
1710 ALuint BufferID;
1711 ALboolean bBuffersProcessed;
1713 if (n == 0)
1714 return;
1716 DataSize = 0;
1717 BufferSize = 0;
1718 bBuffersProcessed = AL_TRUE;
1720 Context=alcGetCurrentContext();
1721 if (Context)
1723 SuspendContext(Context);
1725 if (alIsSource(source))
1727 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1729 // Check that all 'n' buffers have been processed
1730 ALBufferList = ALSource->queue;
1731 for (i = 0; i < n; i++)
1733 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1735 ALBufferList = ALBufferList->next;
1737 else
1739 bBuffersProcessed = AL_FALSE;
1740 break;
1744 // If all 'n' buffers have been processed, remove them from the queue
1745 if (bBuffersProcessed)
1747 for (i = 0; i < n; i++)
1749 ALBufferList = ALSource->queue;
1751 ALSource->queue = ALBufferList->next;
1752 // Record name of buffer
1753 buffers[i] = ALBufferList->buffer;
1754 // Decrement buffer reference counter
1755 if (ALBufferList->buffer)
1756 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1757 // Record size of buffer
1758 if (ALBufferList->buffer)
1759 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1760 else
1761 BufferSize = 0;
1763 DataSize += BufferSize;
1764 // Release memory for buffer list item
1765 free(ALBufferList);
1766 ALSource->BuffersInQueue--;
1767 ALSource->BuffersProcessed--;
1770 if (ALSource->state != AL_PLAYING)
1772 if (ALSource->queue)
1773 BufferID = ALSource->queue->buffer;
1774 else
1775 BufferID = 0;
1777 ALSource->ulBufferID = BufferID;
1780 if((ALuint)n > ALSource->BuffersPlayed)
1782 ALSource->BuffersPlayed = 0;
1783 ALSource->BufferPosition = 0;
1785 else
1786 ALSource->BuffersPlayed -= n;
1788 else
1790 // Some buffers can't be unqueue because they have not been processed
1791 alSetError(AL_INVALID_VALUE);
1794 else
1796 // Invalid Source Name
1797 alSetError(AL_INVALID_NAME);
1800 ProcessContext(Context);
1802 else
1804 // Invalid Context
1805 alSetError(AL_INVALID_OPERATION);
1808 return;
1812 static ALvoid InitSourceParams(ALsource *pSource)
1814 pSource->flInnerAngle = 360.0f;
1815 pSource->flOuterAngle = 360.0f;
1816 pSource->flPitch = 1.0f;
1817 pSource->vPosition[0] = 0.0f;
1818 pSource->vPosition[1] = 0.0f;
1819 pSource->vPosition[2] = 0.0f;
1820 pSource->vOrientation[0] = 0.0f;
1821 pSource->vOrientation[1] = 0.0f;
1822 pSource->vOrientation[2] = 0.0f;
1823 pSource->vVelocity[0] = 0.0f;
1824 pSource->vVelocity[1] = 0.0f;
1825 pSource->vVelocity[2] = 0.0f;
1826 pSource->flRefDistance = 1.0f;
1827 pSource->flMaxDistance = FLT_MAX;
1828 pSource->flRollOffFactor = 1.0f;
1829 pSource->bLooping = AL_FALSE;
1830 pSource->flGain = 1.0f;
1831 pSource->flMinGain = 0.0f;
1832 pSource->flMaxGain = 1.0f;
1833 pSource->flOuterGain = 0.0f;
1835 pSource->state = AL_INITIAL;
1836 pSource->lSourceType = AL_UNDETERMINED;
1838 pSource->ulBufferID= 0;
1843 GetSourceOffset
1845 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1846 The offset is relative to the start of the queue (not the start of the current buffer)
1848 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1850 ALbufferlistitem *pBufferList;
1851 ALbuffer *pBuffer;
1852 ALfloat flBufferFreq;
1853 ALint lBytesPlayed, lChannels;
1854 ALenum eOriginalFormat;
1855 ALboolean bReturn = AL_TRUE;
1856 ALint lTotalBufferDataSize;
1858 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1860 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
1861 // Get Current Buffer Size and frequency (in milliseconds)
1862 flBufferFreq = (ALfloat)pBuffer->frequency;
1863 eOriginalFormat = pBuffer->eOriginalFormat;
1864 lChannels = aluChannelsFromFormat(pBuffer->format);
1866 // Get Current BytesPlayed
1867 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1868 // Add byte length of any processed buffers in the queue
1869 pBufferList = pSource->queue;
1870 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1872 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1873 pBufferList = pBufferList->next;
1876 lTotalBufferDataSize = 0;
1877 pBufferList = pSource->queue;
1878 while (pBufferList)
1880 if (pBufferList->buffer)
1881 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1882 pBufferList = pBufferList->next;
1885 if (pSource->bLooping)
1887 if (lBytesPlayed < 0)
1888 lBytesPlayed = 0;
1889 else
1890 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
1892 else
1894 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1895 if(lBytesPlayed < 0)
1896 lBytesPlayed = 0;
1897 if(lBytesPlayed > lTotalBufferDataSize)
1898 lBytesPlayed = lTotalBufferDataSize;
1901 switch (eName)
1903 case AL_SEC_OFFSET:
1904 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
1905 break;
1906 case AL_SAMPLE_OFFSET:
1907 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
1908 break;
1909 case AL_BYTE_OFFSET:
1910 // Take into account the original format of the Buffer
1911 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1912 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1914 // Compression rate of the ADPCM supported is 3.6111 to 1
1915 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
1916 // Round down to nearest ADPCM block
1917 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
1919 else if (eOriginalFormat == AL_FORMAT_REAR8)
1921 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
1923 else if (eOriginalFormat == AL_FORMAT_REAR16)
1925 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1927 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1929 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
1931 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1933 *pflOffset = (ALfloat)(lBytesPlayed << 1);
1935 else
1937 *pflOffset = (ALfloat)lBytesPlayed;
1939 break;
1942 else
1944 *pflOffset = 0.0f;
1947 return bReturn;
1952 ApplyOffset
1954 Apply a playback offset to the Source. This function will update the queue (to correctly
1955 mark buffers as 'pending' or 'processed' depending upon the new offset.
1957 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1959 ALbufferlistitem *pBufferList;
1960 ALbuffer *pBuffer;
1961 ALint lBufferSize, lTotalBufferSize;
1962 ALint lByteOffset;
1964 // Get true byte offset
1965 lByteOffset = GetByteOffset(pSource);
1967 // If this is a valid offset apply it
1968 if (lByteOffset != -1)
1970 // Sort out the queue (pending and processed states)
1971 pBufferList = pSource->queue;
1972 lTotalBufferSize = 0;
1973 pSource->BuffersPlayed = 0;
1974 pSource->BuffersProcessed = 0;
1975 while (pBufferList)
1977 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
1978 lBufferSize = pBuffer ? pBuffer->size : 0;
1980 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1982 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
1983 // update the state to PROCESSED
1984 pSource->BuffersPlayed++;
1986 if (!pSource->bLooping)
1988 pBufferList->bufferstate = PROCESSED;
1989 pSource->BuffersProcessed++;
1992 else if (lTotalBufferSize <= lByteOffset)
1994 // Offset is within this buffer
1995 pBufferList->bufferstate = PENDING;
1997 // Set Current Buffer ID
1998 pSource->ulBufferID = pBufferList->buffer;
2000 // Set current position in this buffer
2001 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2003 // Set Total Bytes Played to Offset
2004 pSource->lBytesPlayed = lByteOffset;
2006 // SW Mixer Positions are in Samples
2007 pSource->position = pSource->BufferPosition /
2008 aluBytesFromFormat(pBuffer->format) /
2009 aluChannelsFromFormat(pBuffer->format);
2011 else
2013 // Offset is before this buffer, so mark as pending
2014 pBufferList->bufferstate = PENDING;
2017 // Increment the TotalBufferSize
2018 lTotalBufferSize += lBufferSize;
2020 // Move on to next buffer in the Queue
2021 pBufferList = pBufferList->next;
2024 else
2026 if (bUpdateContext)
2027 alSetError(AL_INVALID_VALUE);
2030 // Clear Offset
2031 pSource->lOffset = 0;
2036 GetByteOffset
2038 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2039 offset supplied by the application). This takes into account the fact that the buffer format
2040 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2042 static ALint GetByteOffset(ALsource *pSource)
2044 ALbuffer *pBuffer = NULL;
2045 ALbufferlistitem *pBufferList;
2046 ALfloat flBufferFreq;
2047 ALint lChannels;
2048 ALint lByteOffset = -1;
2049 ALint lTotalBufferDataSize;
2051 // Find the first non-NULL Buffer in the Queue
2052 pBufferList = pSource->queue;
2053 while (pBufferList)
2055 if (pBufferList->buffer)
2057 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2058 break;
2060 pBufferList = pBufferList->next;
2063 if (pBuffer)
2065 flBufferFreq = ((ALfloat)pBuffer->frequency);
2066 lChannels = aluChannelsFromFormat(pBuffer->format);
2068 // Determine the ByteOffset (and ensure it is block aligned)
2069 switch (pSource->lOffsetType)
2071 case AL_BYTE_OFFSET:
2072 // Take into consideration the original format
2073 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 if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2084 lByteOffset = pSource->lOffset * 4;
2085 lByteOffset -= (lByteOffset % (lChannels * 2));
2087 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2089 lByteOffset = pSource->lOffset * 2;
2090 lByteOffset -= (lByteOffset % (lChannels * 2));
2092 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2094 lByteOffset = pSource->lOffset * 2;
2095 lByteOffset -= (lByteOffset % (lChannels * 2));
2097 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2099 lByteOffset = pSource->lOffset / 2;
2100 lByteOffset -= (lByteOffset % (lChannels * 2));
2102 else
2104 lByteOffset = pSource->lOffset;
2105 lByteOffset -= (lByteOffset % (lChannels * 2));
2107 break;
2109 case AL_SAMPLE_OFFSET:
2110 lByteOffset = pSource->lOffset * lChannels * 2;
2111 break;
2113 case AL_SEC_OFFSET:
2114 // Note - lOffset is internally stored as Milliseconds
2115 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2116 lByteOffset -= (lByteOffset % (lChannels * 2));
2117 break;
2120 lTotalBufferDataSize = 0;
2121 pBufferList = pSource->queue;
2122 while (pBufferList)
2124 if (pBufferList->buffer)
2125 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2126 pBufferList = pBufferList->next;
2129 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2130 if (lByteOffset >= lTotalBufferDataSize)
2131 lByteOffset = -1;
2134 return lByteOffset;