Seperate data converters into reusable functions
[openal-soft.git] / OpenAL32 / alSource.c
blobdd88ed08adfd030c63230c6c55d7f42f27e0068e
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 "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = alcGetCurrentContext();
47 if (Context)
49 SuspendContext(Context);
51 if (n > 0)
53 Device = alcGetContextsDevice(Context);
55 if (Device)
57 // Check that enough memory has been allocted in the 'sources' array for n Sources
58 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
60 // Check that the requested number of sources can be generated
61 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
63 ALsource **list = &Context->Source;
64 while(*list)
65 list = &(*list)->next;
67 // Add additional sources to the list (Source->next points to the location for the next Source structure)
68 while(i < n)
70 *list = calloc(1, sizeof(ALsource));
71 if(!(*list))
73 alDeleteSources(i, sources);
74 alSetError(AL_OUT_OF_MEMORY);
75 break;
78 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->source = sources[i];
81 InitSourceParams(*list);
82 Context->SourceCount++;
83 i++;
85 list = &(*list)->next;
88 else
90 // Not enough resources to create the Sources
91 alSetError(AL_INVALID_VALUE);
94 else
96 // Bad pointer
97 alSetError(AL_INVALID_VALUE);
100 else
102 // No Device created, or attached to Context
103 alSetError(AL_INVALID_OPERATION);
107 ProcessContext(Context);
109 else
111 // Invalid Context
112 alSetError(AL_INVALID_OPERATION);
115 return;
119 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
121 ALCcontext *Context;
122 ALCdevice *Device;
123 ALsource *ALSource;
124 ALsource **list;
125 ALsizei i, j;
126 ALbufferlistitem *ALBufferList;
127 ALboolean bSourcesValid = AL_TRUE;
129 Context = alcGetCurrentContext();
130 if (Context)
132 SuspendContext(Context);
134 if (n >= 0)
136 Device = alcGetContextsDevice(Context);
138 if (Device)
140 // Check that all Sources are valid (and can therefore be deleted)
141 for (i = 0; i < n; i++)
143 if (!alIsSource(sources[i]))
145 alSetError(AL_INVALID_NAME);
146 bSourcesValid = AL_FALSE;
147 break;
151 if (bSourcesValid)
153 // All Sources are valid, and can be deleted
154 for (i = 0; i < n; i++)
156 // Recheck that the Source is valid, because there could be duplicated Source names
157 if (alIsSource(sources[i]))
159 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
160 alSourceStop((ALuint)ALSource->source);
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while (ALSource->queue != NULL)
165 ALBufferList = ALSource->queue;
166 // Decrement buffer's reference counter
167 if (ALBufferList->buffer != 0)
168 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
169 // Update queue to point to next element in list
170 ALSource->queue = ALBufferList->next;
171 // Release memory allocated for buffer list item
172 free(ALBufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(ALSource->Send[j].Slot)
178 ALSource->Send[j].Slot->refcount--;
179 ALSource->Send[j].Slot = NULL;
182 // Decrement Source count
183 Context->SourceCount--;
185 // Remove Source from list of Sources
186 list = &Context->Source;
187 while(*list && *list != ALSource)
188 list = &(*list)->next;
190 if(*list)
191 *list = (*list)->next;
192 ALTHUNK_REMOVEENTRY(ALSource->source);
194 memset(ALSource,0,sizeof(ALsource));
195 free(ALSource);
200 else
202 // No Device created, or attached to Context
203 alSetError(AL_INVALID_OPERATION);
206 else
207 alSetError(AL_INVALID_VALUE);
209 ProcessContext(Context);
211 else
213 // Invalid Context
214 alSetError(AL_INVALID_OPERATION);
217 return;
221 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
223 ALboolean result=AL_FALSE;
224 ALCcontext *Context;
225 ALsource *Source;
227 Context=alcGetCurrentContext();
228 if (Context)
230 SuspendContext(Context);
232 // To determine if this is a valid Source name, look through the list of generated Sources
233 Source = Context->Source;
234 while(Source)
236 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
238 result = AL_TRUE;
239 break;
242 Source = Source->next;
245 ProcessContext(Context);
247 else
249 // Invalid Context
250 alSetError(AL_INVALID_OPERATION);
253 return result;
257 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
259 ALCcontext *pContext;
260 ALsource *pSource;
262 pContext = alcGetCurrentContext();
263 if (pContext)
265 SuspendContext(pContext);
267 if (alIsSource(source))
269 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
271 switch (eParam)
273 case AL_PITCH:
274 if (flValue >= 0.0f)
276 pSource->flPitch = flValue;
277 if(pSource->flPitch < 0.001f)
278 pSource->flPitch = 0.001f;
280 else
281 alSetError(AL_INVALID_VALUE);
282 break;
284 case AL_CONE_INNER_ANGLE:
285 if ((flValue >= 0.0f) && (flValue <= 360.0f))
286 pSource->flInnerAngle = flValue;
287 else
288 alSetError(AL_INVALID_VALUE);
289 break;
291 case AL_CONE_OUTER_ANGLE:
292 if ((flValue >= 0.0f) && (flValue <= 360.0f))
293 pSource->flOuterAngle = flValue;
294 else
295 alSetError(AL_INVALID_VALUE);
296 break;
298 case AL_GAIN:
299 if (flValue >= 0.0f)
300 pSource->flGain = flValue;
301 else
302 alSetError(AL_INVALID_VALUE);
303 break;
305 case AL_MAX_DISTANCE:
306 if (flValue >= 0.0f)
307 pSource->flMaxDistance = flValue;
308 else
309 alSetError(AL_INVALID_VALUE);
310 break;
312 case AL_ROLLOFF_FACTOR:
313 if (flValue >= 0.0f)
314 pSource->flRollOffFactor = flValue;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_REFERENCE_DISTANCE:
320 if (flValue >= 0.0f)
321 pSource->flRefDistance = flValue;
322 else
323 alSetError(AL_INVALID_VALUE);
324 break;
326 case AL_MIN_GAIN:
327 if ((flValue >= 0.0f) && (flValue <= 1.0f))
328 pSource->flMinGain = flValue;
329 else
330 alSetError(AL_INVALID_VALUE);
331 break;
333 case AL_MAX_GAIN:
334 if ((flValue >= 0.0f) && (flValue <= 1.0f))
335 pSource->flMaxGain = flValue;
336 else
337 alSetError(AL_INVALID_VALUE);
338 break;
340 case AL_CONE_OUTER_GAIN:
341 if ((flValue >= 0.0f) && (flValue <= 1.0f))
342 pSource->flOuterGain = flValue;
343 else
344 alSetError(AL_INVALID_VALUE);
345 break;
347 case AL_CONE_OUTER_GAINHF:
348 if ((flValue >= 0.0f) && (flValue <= 1.0f))
349 pSource->OuterGainHF = flValue;
350 else
351 alSetError(AL_INVALID_VALUE);
352 break;
354 case AL_AIR_ABSORPTION_FACTOR:
355 if (flValue >= 0.0f && flValue <= 10.0f)
356 pSource->AirAbsorptionFactor = flValue;
357 else
358 alSetError(AL_INVALID_VALUE);
359 break;
361 case AL_ROOM_ROLLOFF_FACTOR:
362 if (flValue >= 0.0f && flValue <= 1.0f)
363 pSource->RoomRolloffFactor = flValue;
364 else
365 alSetError(AL_INVALID_VALUE);
366 break;
368 case AL_DOPPLER_FACTOR:
369 if (flValue >= 0.0f && flValue <= 1.0f)
370 pSource->DopplerFactor = flValue;
371 else
372 alSetError(AL_INVALID_VALUE);
373 break;
375 case AL_SEC_OFFSET:
376 case AL_SAMPLE_OFFSET:
377 case AL_BYTE_OFFSET:
378 if (flValue >= 0.0f)
380 pSource->lOffsetType = eParam;
382 // Store Offset (convert Seconds into Milliseconds)
383 if (eParam == AL_SEC_OFFSET)
384 pSource->lOffset = (ALint)(flValue * 1000.0f);
385 else
386 pSource->lOffset = (ALint)flValue;
388 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
389 ApplyOffset(pSource, AL_TRUE);
391 else
392 alSetError(AL_INVALID_VALUE);
393 break;
395 default:
396 alSetError(AL_INVALID_ENUM);
397 break;
400 else
402 // Invalid Source Name
403 alSetError(AL_INVALID_NAME);
406 ProcessContext(pContext);
408 else
410 // Invalid context
411 alSetError(AL_INVALID_OPERATION);
414 return;
418 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
420 ALCcontext *pContext;
421 ALsource *pSource;
423 pContext = alcGetCurrentContext();
424 if (pContext)
426 SuspendContext(pContext);
428 if (alIsSource(source))
430 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
431 switch(eParam)
433 case AL_POSITION:
434 pSource->vPosition[0] = flValue1;
435 pSource->vPosition[1] = flValue2;
436 pSource->vPosition[2] = flValue3;
437 break;
439 case AL_VELOCITY:
440 pSource->vVelocity[0] = flValue1;
441 pSource->vVelocity[1] = flValue2;
442 pSource->vVelocity[2] = flValue3;
443 break;
445 case AL_DIRECTION:
446 pSource->vOrientation[0] = flValue1;
447 pSource->vOrientation[1] = flValue2;
448 pSource->vOrientation[2] = flValue3;
449 break;
451 default:
452 alSetError(AL_INVALID_ENUM);
453 break;
456 else
457 alSetError(AL_INVALID_NAME);
459 ProcessContext(pContext);
461 else
463 alSetError(AL_INVALID_OPERATION);
466 return;
470 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
472 ALCcontext *pContext;
474 pContext = alcGetCurrentContext();
475 if (pContext)
477 SuspendContext(pContext);
479 if (pflValues)
481 if (alIsSource(source))
483 switch (eParam)
485 case AL_PITCH:
486 case AL_CONE_INNER_ANGLE:
487 case AL_CONE_OUTER_ANGLE:
488 case AL_GAIN:
489 case AL_MAX_DISTANCE:
490 case AL_ROLLOFF_FACTOR:
491 case AL_REFERENCE_DISTANCE:
492 case AL_MIN_GAIN:
493 case AL_MAX_GAIN:
494 case AL_CONE_OUTER_GAIN:
495 case AL_CONE_OUTER_GAINHF:
496 case AL_SEC_OFFSET:
497 case AL_SAMPLE_OFFSET:
498 case AL_BYTE_OFFSET:
499 case AL_AIR_ABSORPTION_FACTOR:
500 case AL_ROOM_ROLLOFF_FACTOR:
501 alSourcef(source, eParam, pflValues[0]);
502 break;
504 case AL_POSITION:
505 case AL_VELOCITY:
506 case AL_DIRECTION:
507 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
508 break;
510 default:
511 alSetError(AL_INVALID_ENUM);
512 break;
515 else
516 alSetError(AL_INVALID_NAME);
518 else
519 alSetError(AL_INVALID_VALUE);
521 ProcessContext(pContext);
523 else
524 alSetError(AL_INVALID_OPERATION);
526 return;
530 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
532 ALCcontext *pContext;
533 ALsource *pSource;
534 ALbufferlistitem *pALBufferListItem;
535 ALint Counter = 0;
536 ALint DataSize = 0;
537 ALint BufferSize;
539 pContext = alcGetCurrentContext();
540 if (pContext)
542 SuspendContext(pContext);
544 if (alIsSource(source))
546 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
548 switch(eParam)
550 case AL_MAX_DISTANCE:
551 case AL_ROLLOFF_FACTOR:
552 case AL_REFERENCE_DISTANCE:
553 alSourcef(source, eParam, (ALfloat)lValue);
554 break;
556 case AL_SOURCE_RELATIVE:
557 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
558 pSource->bHeadRelative = (ALboolean)lValue;
559 else
560 alSetError(AL_INVALID_VALUE);
561 break;
563 case AL_CONE_INNER_ANGLE:
564 if ((lValue >= 0) && (lValue <= 360))
565 pSource->flInnerAngle = (float)lValue;
566 else
567 alSetError(AL_INVALID_VALUE);
568 break;
570 case AL_CONE_OUTER_ANGLE:
571 if ((lValue >= 0) && (lValue <= 360))
572 pSource->flOuterAngle = (float)lValue;
573 else
574 alSetError(AL_INVALID_VALUE);
575 break;
577 case AL_LOOPING:
578 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
579 pSource->bLooping = (ALboolean)lValue;
580 else
581 alSetError(AL_INVALID_VALUE);
582 break;
584 case AL_BUFFER:
585 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
587 if (alIsBuffer(lValue))
589 // Remove all elements in the queue
590 while (pSource->queue != NULL)
592 pALBufferListItem = pSource->queue;
593 pSource->queue = pALBufferListItem->next;
594 // Decrement reference counter for buffer
595 if (pALBufferListItem->buffer)
596 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
597 // Record size of buffer
598 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
599 DataSize += BufferSize;
600 // Increment the number of buffers removed from queue
601 Counter++;
602 // Release memory for buffer list item
603 free(pALBufferListItem);
604 // Decrement the number of buffers in the queue
605 pSource->BuffersInQueue--;
608 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
609 if (lValue != 0)
611 // Source is now in STATIC mode
612 pSource->lSourceType = AL_STATIC;
614 // Add the selected buffer to the queue
615 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
616 pALBufferListItem->buffer = lValue;
617 pALBufferListItem->bufferstate = PENDING;
618 pALBufferListItem->flag = 0;
619 pALBufferListItem->next = NULL;
621 pSource->queue = pALBufferListItem;
622 pSource->BuffersInQueue = 1;
624 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
626 // Increment reference counter for buffer
627 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
629 else
631 // Source is now in UNDETERMINED mode
632 pSource->lSourceType = AL_UNDETERMINED;
635 // Update AL_BUFFER parameter
636 pSource->ulBufferID = lValue;
638 else
639 alSetError(AL_INVALID_VALUE);
641 else
642 alSetError(AL_INVALID_OPERATION);
643 break;
645 case AL_SOURCE_STATE:
646 // Query only
647 alSetError(AL_INVALID_OPERATION);
648 break;
650 case AL_SEC_OFFSET:
651 case AL_SAMPLE_OFFSET:
652 case AL_BYTE_OFFSET:
653 if (lValue >= 0)
655 pSource->lOffsetType = eParam;
657 // Store Offset (convert Seconds into Milliseconds)
658 if (eParam == AL_SEC_OFFSET)
659 pSource->lOffset = lValue * 1000;
660 else
661 pSource->lOffset = lValue;
663 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
664 ApplyOffset(pSource, AL_TRUE);
666 else
667 alSetError(AL_INVALID_VALUE);
668 break;
670 case AL_DIRECT_FILTER:
671 if(alIsFilter(lValue))
673 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
674 if(!filter)
676 pSource->DirectFilter.type = AL_FILTER_NULL;
677 pSource->DirectFilter.filter = 0;
679 else
680 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
682 else
683 alSetError(AL_INVALID_VALUE);
684 break;
686 case AL_DIRECT_FILTER_GAINHF_AUTO:
687 if(lValue == AL_TRUE || lValue == AL_FALSE)
688 pSource->DryGainHFAuto = lValue;
689 else
690 alSetError(AL_INVALID_VALUE);
691 break;
693 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
694 if(lValue == AL_TRUE || lValue == AL_FALSE)
695 pSource->WetGainAuto = lValue;
696 else
697 alSetError(AL_INVALID_VALUE);
698 break;
700 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
701 if(lValue == AL_TRUE || lValue == AL_FALSE)
702 pSource->WetGainHFAuto = lValue;
703 else
704 alSetError(AL_INVALID_VALUE);
705 break;
707 default:
708 alSetError(AL_INVALID_ENUM);
709 break;
712 else
713 alSetError(AL_INVALID_NAME);
715 ProcessContext(pContext);
717 else
718 alSetError(AL_INVALID_OPERATION);
720 return;
724 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
726 ALCcontext *pContext;
728 pContext = alcGetCurrentContext();
729 if (pContext)
731 SuspendContext(pContext);
733 if (alIsSource(source))
735 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
737 switch (eParam)
739 case AL_POSITION:
740 case AL_VELOCITY:
741 case AL_DIRECTION:
742 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
743 break;
745 case AL_AUXILIARY_SEND_FILTER:
746 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
747 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
748 alIsFilter(lValue3))
750 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
751 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
753 /* Release refcount on the previous slot, and add one for
754 * the new slot */
755 if(pSource->Send[lValue2].Slot)
756 pSource->Send[lValue2].Slot->refcount--;
757 pSource->Send[lValue2].Slot = ALEffectSlot;
758 if(pSource->Send[lValue2].Slot)
759 pSource->Send[lValue2].Slot->refcount++;
761 if(!ALFilter)
763 /* Disable filter */
764 pSource->Send[lValue2].WetFilter.type = 0;
765 pSource->Send[lValue2].WetFilter.filter = 0;
767 else
768 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
770 else
771 alSetError(AL_INVALID_VALUE);
772 break;
774 default:
775 alSetError(AL_INVALID_ENUM);
776 break;
779 else
780 alSetError(AL_INVALID_NAME);
782 ProcessContext(pContext);
784 else
785 alSetError(AL_INVALID_OPERATION);
787 return;
791 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
793 ALCcontext *pContext;
795 pContext = alcGetCurrentContext();
796 if (pContext)
798 SuspendContext(pContext);
800 if (plValues)
802 if (alIsSource(source))
804 switch (eParam)
806 case AL_SOURCE_RELATIVE:
807 case AL_CONE_INNER_ANGLE:
808 case AL_CONE_OUTER_ANGLE:
809 case AL_LOOPING:
810 case AL_BUFFER:
811 case AL_SOURCE_STATE:
812 case AL_SEC_OFFSET:
813 case AL_SAMPLE_OFFSET:
814 case AL_BYTE_OFFSET:
815 case AL_MAX_DISTANCE:
816 case AL_ROLLOFF_FACTOR:
817 case AL_REFERENCE_DISTANCE:
818 case AL_DIRECT_FILTER:
819 case AL_DIRECT_FILTER_GAINHF_AUTO:
820 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
821 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
822 alSourcei(source, eParam, plValues[0]);
823 break;
825 case AL_POSITION:
826 case AL_VELOCITY:
827 case AL_DIRECTION:
828 case AL_AUXILIARY_SEND_FILTER:
829 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
830 break;
832 default:
833 alSetError(AL_INVALID_ENUM);
834 break;
837 else
838 alSetError(AL_INVALID_NAME);
840 else
841 alSetError(AL_INVALID_VALUE);
843 ProcessContext(pContext);
845 else
846 alSetError(AL_INVALID_OPERATION);
848 return;
852 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
854 ALCcontext *pContext;
855 ALsource *pSource;
856 ALfloat flOffset;
858 pContext = alcGetCurrentContext();
859 if (pContext)
861 SuspendContext(pContext);
863 if (pflValue)
865 if (alIsSource(source))
867 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
869 switch(eParam)
871 case AL_PITCH:
872 *pflValue = pSource->flPitch;
873 break;
875 case AL_GAIN:
876 *pflValue = pSource->flGain;
877 break;
879 case AL_MIN_GAIN:
880 *pflValue = pSource->flMinGain;
881 break;
883 case AL_MAX_GAIN:
884 *pflValue = pSource->flMaxGain;
885 break;
887 case AL_MAX_DISTANCE:
888 *pflValue = pSource->flMaxDistance;
889 break;
891 case AL_ROLLOFF_FACTOR:
892 *pflValue = pSource->flRollOffFactor;
893 break;
895 case AL_CONE_OUTER_GAIN:
896 *pflValue = pSource->flOuterGain;
897 break;
899 case AL_CONE_OUTER_GAINHF:
900 *pflValue = pSource->OuterGainHF;
901 break;
903 case AL_SEC_OFFSET:
904 case AL_SAMPLE_OFFSET:
905 case AL_BYTE_OFFSET:
906 if (GetSourceOffset(pSource, eParam, &flOffset))
907 *pflValue = flOffset;
908 else
909 alSetError(AL_INVALID_OPERATION);
910 break;
912 case AL_CONE_INNER_ANGLE:
913 *pflValue = pSource->flInnerAngle;
914 break;
916 case AL_CONE_OUTER_ANGLE:
917 *pflValue = pSource->flOuterAngle;
918 break;
920 case AL_REFERENCE_DISTANCE:
921 *pflValue = pSource->flRefDistance;
922 break;
924 case AL_AIR_ABSORPTION_FACTOR:
925 *pflValue = pSource->AirAbsorptionFactor;
926 break;
928 case AL_ROOM_ROLLOFF_FACTOR:
929 *pflValue = pSource->RoomRolloffFactor;
930 break;
932 case AL_DOPPLER_FACTOR:
933 *pflValue = pSource->DopplerFactor;
934 break;
936 default:
937 alSetError(AL_INVALID_ENUM);
938 break;
941 else
942 alSetError(AL_INVALID_NAME);
944 else
945 alSetError(AL_INVALID_VALUE);
947 ProcessContext(pContext);
949 else
950 alSetError(AL_INVALID_OPERATION);
952 return;
956 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
958 ALCcontext *pContext;
959 ALsource *pSource;
961 pContext = alcGetCurrentContext();
962 if (pContext)
964 SuspendContext(pContext);
966 if ((pflValue1) && (pflValue2) && (pflValue3))
968 if (alIsSource(source))
970 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
972 switch(eParam)
974 case AL_POSITION:
975 *pflValue1 = pSource->vPosition[0];
976 *pflValue2 = pSource->vPosition[1];
977 *pflValue3 = pSource->vPosition[2];
978 break;
980 case AL_VELOCITY:
981 *pflValue1 = pSource->vVelocity[0];
982 *pflValue2 = pSource->vVelocity[1];
983 *pflValue3 = pSource->vVelocity[2];
984 break;
986 case AL_DIRECTION:
987 *pflValue1 = pSource->vOrientation[0];
988 *pflValue2 = pSource->vOrientation[1];
989 *pflValue3 = pSource->vOrientation[2];
990 break;
992 default:
993 alSetError(AL_INVALID_ENUM);
994 break;
997 else
998 alSetError(AL_INVALID_NAME);
1000 else
1001 alSetError(AL_INVALID_VALUE);
1003 ProcessContext(pContext);
1005 else
1006 alSetError(AL_INVALID_OPERATION);
1008 return;
1012 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1014 ALCcontext *pContext;
1015 ALsource *pSource;
1017 pContext = alcGetCurrentContext();
1018 if (pContext)
1020 SuspendContext(pContext);
1022 if (pflValues)
1024 if (alIsSource(source))
1026 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1028 switch(eParam)
1030 case AL_PITCH:
1031 case AL_GAIN:
1032 case AL_MIN_GAIN:
1033 case AL_MAX_GAIN:
1034 case AL_MAX_DISTANCE:
1035 case AL_ROLLOFF_FACTOR:
1036 case AL_DOPPLER_FACTOR:
1037 case AL_CONE_OUTER_GAIN:
1038 case AL_SEC_OFFSET:
1039 case AL_SAMPLE_OFFSET:
1040 case AL_BYTE_OFFSET:
1041 case AL_CONE_INNER_ANGLE:
1042 case AL_CONE_OUTER_ANGLE:
1043 case AL_REFERENCE_DISTANCE:
1044 case AL_CONE_OUTER_GAINHF:
1045 case AL_AIR_ABSORPTION_FACTOR:
1046 case AL_ROOM_ROLLOFF_FACTOR:
1047 alGetSourcef(source, eParam, pflValues);
1048 break;
1050 case AL_POSITION:
1051 pflValues[0] = pSource->vPosition[0];
1052 pflValues[1] = pSource->vPosition[1];
1053 pflValues[2] = pSource->vPosition[2];
1054 break;
1056 case AL_VELOCITY:
1057 pflValues[0] = pSource->vVelocity[0];
1058 pflValues[1] = pSource->vVelocity[1];
1059 pflValues[2] = pSource->vVelocity[2];
1060 break;
1062 case AL_DIRECTION:
1063 pflValues[0] = pSource->vOrientation[0];
1064 pflValues[1] = pSource->vOrientation[1];
1065 pflValues[2] = pSource->vOrientation[2];
1066 break;
1068 default:
1069 alSetError(AL_INVALID_ENUM);
1070 break;
1073 else
1074 alSetError(AL_INVALID_NAME);
1076 else
1077 alSetError(AL_INVALID_VALUE);
1079 ProcessContext(pContext);
1081 else
1082 alSetError(AL_INVALID_OPERATION);
1084 return;
1088 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1090 ALCcontext *pContext;
1091 ALsource *pSource;
1092 ALfloat flOffset;
1094 pContext = alcGetCurrentContext();
1095 if (pContext)
1097 SuspendContext(pContext);
1099 if (plValue)
1101 if (alIsSource(source))
1103 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1105 switch(eParam)
1107 case AL_MAX_DISTANCE:
1108 *plValue = (ALint)pSource->flMaxDistance;
1109 break;
1111 case AL_ROLLOFF_FACTOR:
1112 *plValue = (ALint)pSource->flRollOffFactor;
1113 break;
1115 case AL_REFERENCE_DISTANCE:
1116 *plValue = (ALint)pSource->flRefDistance;
1117 break;
1119 case AL_SOURCE_RELATIVE:
1120 *plValue = pSource->bHeadRelative;
1121 break;
1123 case AL_CONE_INNER_ANGLE:
1124 *plValue = (ALint)pSource->flInnerAngle;
1125 break;
1127 case AL_CONE_OUTER_ANGLE:
1128 *plValue = (ALint)pSource->flOuterAngle;
1129 break;
1131 case AL_LOOPING:
1132 *plValue = pSource->bLooping;
1133 break;
1135 case AL_BUFFER:
1136 *plValue = pSource->ulBufferID;
1137 break;
1139 case AL_SOURCE_STATE:
1140 *plValue = pSource->state;
1141 break;
1143 case AL_BUFFERS_QUEUED:
1144 *plValue = pSource->BuffersInQueue;
1145 break;
1147 case AL_BUFFERS_PROCESSED:
1148 if(pSource->bLooping)
1150 /* Buffers on a looping source are in a perpetual state
1151 * of PENDING, so don't report any as PROCESSED */
1152 *plValue = 0;
1154 else
1155 *plValue = pSource->BuffersPlayed;
1156 break;
1158 case AL_SOURCE_TYPE:
1159 *plValue = pSource->lSourceType;
1160 break;
1162 case AL_SEC_OFFSET:
1163 case AL_SAMPLE_OFFSET:
1164 case AL_BYTE_OFFSET:
1165 if (GetSourceOffset(pSource, eParam, &flOffset))
1166 *plValue = (ALint)flOffset;
1167 else
1168 alSetError(AL_INVALID_OPERATION);
1169 break;
1171 case AL_DIRECT_FILTER:
1172 *plValue = pSource->DirectFilter.filter;
1173 break;
1175 case AL_DIRECT_FILTER_GAINHF_AUTO:
1176 *plValue = pSource->DryGainHFAuto;
1177 break;
1179 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1180 *plValue = pSource->WetGainAuto;
1181 break;
1183 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1184 *plValue = pSource->WetGainHFAuto;
1185 break;
1187 case AL_DOPPLER_FACTOR:
1188 *plValue = (ALint)pSource->DopplerFactor;
1189 break;
1191 default:
1192 alSetError(AL_INVALID_ENUM);
1193 break;
1196 else
1197 alSetError(AL_INVALID_NAME);
1199 else
1200 alSetError(AL_INVALID_VALUE);
1202 ProcessContext(pContext);
1204 else
1205 alSetError(AL_INVALID_OPERATION);
1207 return;
1211 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1213 ALCcontext *pContext;
1214 ALsource *pSource;
1216 pContext = alcGetCurrentContext();
1217 if (pContext)
1219 SuspendContext(pContext);
1221 if ((plValue1) && (plValue2) && (plValue3))
1223 if (alIsSource(source))
1225 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1227 switch(eParam)
1229 case AL_POSITION:
1230 *plValue1 = (ALint)pSource->vPosition[0];
1231 *plValue2 = (ALint)pSource->vPosition[1];
1232 *plValue3 = (ALint)pSource->vPosition[2];
1233 break;
1235 case AL_VELOCITY:
1236 *plValue1 = (ALint)pSource->vVelocity[0];
1237 *plValue2 = (ALint)pSource->vVelocity[1];
1238 *plValue3 = (ALint)pSource->vVelocity[2];
1239 break;
1241 case AL_DIRECTION:
1242 *plValue1 = (ALint)pSource->vOrientation[0];
1243 *plValue2 = (ALint)pSource->vOrientation[1];
1244 *plValue3 = (ALint)pSource->vOrientation[2];
1245 break;
1247 default:
1248 alSetError(AL_INVALID_ENUM);
1249 break;
1252 else
1253 alSetError(AL_INVALID_NAME);
1255 else
1256 alSetError(AL_INVALID_VALUE);
1258 ProcessContext(pContext);
1260 else
1261 alSetError(AL_INVALID_OPERATION);
1263 return;
1267 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1269 ALCcontext *pContext;
1270 ALsource *pSource;
1272 pContext = alcGetCurrentContext();
1273 if (pContext)
1275 SuspendContext(pContext);
1277 if (plValues)
1279 if (alIsSource(source))
1281 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1283 switch (eParam)
1285 case AL_SOURCE_RELATIVE:
1286 case AL_CONE_INNER_ANGLE:
1287 case AL_CONE_OUTER_ANGLE:
1288 case AL_LOOPING:
1289 case AL_BUFFER:
1290 case AL_SOURCE_STATE:
1291 case AL_BUFFERS_QUEUED:
1292 case AL_BUFFERS_PROCESSED:
1293 case AL_SEC_OFFSET:
1294 case AL_SAMPLE_OFFSET:
1295 case AL_BYTE_OFFSET:
1296 case AL_MAX_DISTANCE:
1297 case AL_ROLLOFF_FACTOR:
1298 case AL_DOPPLER_FACTOR:
1299 case AL_REFERENCE_DISTANCE:
1300 case AL_SOURCE_TYPE:
1301 case AL_DIRECT_FILTER:
1302 case AL_DIRECT_FILTER_GAINHF_AUTO:
1303 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1304 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1305 alGetSourcei(source, eParam, plValues);
1306 break;
1308 case AL_POSITION:
1309 plValues[0] = (ALint)pSource->vPosition[0];
1310 plValues[1] = (ALint)pSource->vPosition[1];
1311 plValues[2] = (ALint)pSource->vPosition[2];
1312 break;
1314 case AL_VELOCITY:
1315 plValues[0] = (ALint)pSource->vVelocity[0];
1316 plValues[1] = (ALint)pSource->vVelocity[1];
1317 plValues[2] = (ALint)pSource->vVelocity[2];
1318 break;
1320 case AL_DIRECTION:
1321 plValues[0] = (ALint)pSource->vOrientation[0];
1322 plValues[1] = (ALint)pSource->vOrientation[1];
1323 plValues[2] = (ALint)pSource->vOrientation[2];
1324 break;
1326 default:
1327 alSetError(AL_INVALID_ENUM);
1328 break;
1331 else
1332 alSetError(AL_INVALID_NAME);
1334 else
1335 alSetError(AL_INVALID_VALUE);
1337 ProcessContext(pContext);
1339 else
1340 alSetError(AL_INVALID_OPERATION);
1342 return;
1346 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1348 alSourcePlayv(1, &source);
1349 return;
1352 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1354 ALCcontext *pContext;
1355 ALsource *pSource;
1356 ALbufferlistitem *ALBufferList;
1357 ALboolean bSourcesValid = AL_TRUE;
1358 ALboolean bPlay;
1359 ALsizei i, j;
1361 pContext = alcGetCurrentContext();
1362 if (pContext)
1364 SuspendContext(pContext);
1366 if (pSourceList)
1368 // Check that all the Sources are valid
1369 for (i = 0; i < n; i++)
1371 if (!alIsSource(pSourceList[i]))
1373 alSetError(AL_INVALID_NAME);
1374 bSourcesValid = AL_FALSE;
1375 break;
1379 if (bSourcesValid)
1381 for (i = 0; i < n; i++)
1383 // Assume Source won't need to play
1384 bPlay = AL_FALSE;
1386 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1388 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1389 ALBufferList = pSource->queue;
1390 while (ALBufferList)
1392 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1394 bPlay = AL_TRUE;
1395 break;
1397 ALBufferList = ALBufferList->next;
1400 if (bPlay)
1402 for(j = 0;j < OUTPUTCHANNELS;j++)
1403 pSource->DryGains[j] = 0.0f;
1404 pSource->WetGain = 0.0f;
1406 if (pSource->state != AL_PAUSED)
1408 pSource->state = AL_PLAYING;
1409 pSource->inuse = AL_TRUE;
1410 pSource->play = AL_TRUE;
1411 pSource->position = 0;
1412 pSource->position_fraction = 0;
1413 pSource->BuffersPlayed = 0;
1415 pSource->ulBufferID = pSource->queue->buffer;
1417 // Make sure all the Buffers in the queue are marked as PENDING
1418 ALBufferList = pSource->queue;
1419 while (ALBufferList)
1421 ALBufferList->bufferstate = PENDING;
1422 ALBufferList = ALBufferList->next;
1425 else
1427 pSource->state = AL_PLAYING;
1428 pSource->inuse = AL_TRUE;
1429 pSource->play = AL_TRUE;
1432 // Check if an Offset has been set
1433 if (pSource->lOffset)
1434 ApplyOffset(pSource, AL_FALSE);
1436 else
1438 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1439 ALBufferList = pSource->queue;
1440 while (ALBufferList)
1442 ALBufferList->bufferstate = PROCESSED;
1443 ALBufferList = ALBufferList->next;
1446 pSource->BuffersPlayed = pSource->BuffersInQueue;
1451 else
1453 // sources is a NULL pointer
1454 alSetError(AL_INVALID_VALUE);
1457 ProcessContext(pContext);
1459 else
1461 // Invalid Context
1462 alSetError(AL_INVALID_OPERATION);
1465 return;
1468 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1470 alSourcePausev(1, &source);
1471 return;
1474 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1476 ALCcontext *Context;
1477 ALsource *Source;
1478 ALsizei i;
1479 ALboolean bSourcesValid = AL_TRUE;
1481 Context=alcGetCurrentContext();
1482 if (Context)
1484 SuspendContext(Context);
1486 if (sources)
1488 // Check all the Sources are valid
1489 for (i=0;i<n;i++)
1491 if (!alIsSource(sources[i]))
1493 alSetError(AL_INVALID_NAME);
1494 bSourcesValid = AL_FALSE;
1495 break;
1499 if (bSourcesValid)
1501 for (i=0;i<n;i++)
1503 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1504 if (Source->state==AL_PLAYING)
1506 Source->state=AL_PAUSED;
1507 Source->inuse=AL_FALSE;
1512 else
1514 // sources is a NULL pointer
1515 alSetError(AL_INVALID_VALUE);
1518 ProcessContext(Context);
1520 else
1522 // Invalid Context
1523 alSetError(AL_INVALID_OPERATION);
1526 return;
1529 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1531 alSourceStopv(1, &source);
1532 return;
1535 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1537 ALCcontext *Context;
1538 ALsource *Source;
1539 ALsizei i;
1540 ALbufferlistitem *ALBufferListItem;
1541 ALboolean bSourcesValid = AL_TRUE;
1543 Context=alcGetCurrentContext();
1544 if (Context)
1546 SuspendContext(Context);
1548 if (sources)
1550 // Check all the Sources are valid
1551 for (i=0;i<n;i++)
1553 if (!alIsSource(sources[i]))
1555 alSetError(AL_INVALID_NAME);
1556 bSourcesValid = AL_FALSE;
1557 break;
1561 if (bSourcesValid)
1563 for (i=0;i<n;i++)
1565 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1566 if (Source->state!=AL_INITIAL)
1568 Source->state=AL_STOPPED;
1569 Source->inuse=AL_FALSE;
1570 Source->BuffersPlayed = Source->BuffersInQueue;
1571 ALBufferListItem= Source->queue;
1572 while (ALBufferListItem != NULL)
1574 ALBufferListItem->bufferstate = PROCESSED;
1575 ALBufferListItem = ALBufferListItem->next;
1578 Source->lOffset = 0;
1582 else
1584 // sources is a NULL pointer
1585 alSetError(AL_INVALID_VALUE);
1588 ProcessContext(Context);
1590 else
1592 // Invalid Context
1593 alSetError(AL_INVALID_OPERATION);
1596 return;
1599 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1601 alSourceRewindv(1, &source);
1602 return;
1605 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1607 ALCcontext *Context;
1608 ALsource *Source;
1609 ALsizei i;
1610 ALbufferlistitem *ALBufferListItem;
1611 ALboolean bSourcesValid = AL_TRUE;
1613 Context=alcGetCurrentContext();
1614 if (Context)
1616 SuspendContext(Context);
1618 if (sources)
1620 // Check all the Sources are valid
1621 for (i=0;i<n;i++)
1623 if (!alIsSource(sources[i]))
1625 alSetError(AL_INVALID_NAME);
1626 bSourcesValid = AL_FALSE;
1627 break;
1631 if (bSourcesValid)
1633 for (i=0;i<n;i++)
1635 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1636 if (Source->state!=AL_INITIAL)
1638 Source->state=AL_INITIAL;
1639 Source->inuse=AL_FALSE;
1640 Source->position=0;
1641 Source->position_fraction=0;
1642 Source->BuffersPlayed = 0;
1643 ALBufferListItem= Source->queue;
1644 while (ALBufferListItem != NULL)
1646 ALBufferListItem->bufferstate = PENDING;
1647 ALBufferListItem = ALBufferListItem->next;
1649 if (Source->queue)
1650 Source->ulBufferID = Source->queue->buffer;
1652 Source->lOffset = 0;
1656 else
1658 // sources is a NULL pointer
1659 alSetError(AL_INVALID_VALUE);
1662 ProcessContext(Context);
1664 else
1666 // Invalid Context
1667 alSetError(AL_INVALID_OPERATION);
1670 return;
1674 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1676 ALCcontext *Context;
1677 ALsource *ALSource;
1678 ALsizei i;
1679 ALbufferlistitem *ALBufferList;
1680 ALbufferlistitem *ALBufferListStart;
1681 ALuint DataSize;
1682 ALuint BufferSize;
1683 ALint iFrequency;
1684 ALint iFormat;
1685 ALboolean bBuffersValid = AL_TRUE;
1687 if (n == 0)
1688 return;
1690 Context=alcGetCurrentContext();
1691 if (Context)
1693 SuspendContext(Context);
1695 DataSize = 0;
1696 BufferSize = 0;
1698 // Check that all buffers are valid or zero and that the source is valid
1700 // Check that this is a valid source
1701 if (alIsSource(source))
1703 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1705 // Check that this is not a STATIC Source
1706 if (ALSource->lSourceType != AL_STATIC)
1708 iFrequency = -1;
1709 iFormat = -1;
1711 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1712 ALBufferList = ALSource->queue;
1713 while (ALBufferList)
1715 if (ALBufferList->buffer)
1717 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1718 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1719 break;
1721 ALBufferList = ALBufferList->next;
1724 for (i = 0; i < n; i++)
1726 if (alIsBuffer(buffers[i]))
1728 if (buffers[i])
1730 if ((iFrequency == -1) && (iFormat == -1))
1732 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1733 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1735 else
1737 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1738 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1740 alSetError(AL_INVALID_OPERATION);
1741 bBuffersValid = AL_FALSE;
1742 break;
1747 else
1749 alSetError(AL_INVALID_NAME);
1750 bBuffersValid = AL_FALSE;
1751 break;
1755 if (bBuffersValid)
1757 // Change Source Type
1758 ALSource->lSourceType = AL_STREAMING;
1760 // All buffers are valid - so add them to the list
1761 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1762 ALBufferListStart->buffer = buffers[0];
1763 ALBufferListStart->bufferstate = PENDING;
1764 ALBufferListStart->flag = 0;
1765 ALBufferListStart->next = NULL;
1767 if (buffers[0])
1768 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1769 else
1770 BufferSize = 0;
1772 DataSize += BufferSize;
1774 // Increment reference counter for buffer
1775 if (buffers[0])
1776 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1778 ALBufferList = ALBufferListStart;
1780 for (i = 1; i < n; i++)
1782 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1783 ALBufferList->next->buffer = buffers[i];
1784 ALBufferList->next->bufferstate = PENDING;
1785 ALBufferList->next->flag = 0;
1786 ALBufferList->next->next = NULL;
1788 if (buffers[i])
1789 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1790 else
1791 BufferSize = 0;
1793 DataSize += BufferSize;
1795 // Increment reference counter for buffer
1796 if (buffers[i])
1797 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1799 ALBufferList = ALBufferList->next;
1802 if (ALSource->queue == NULL)
1804 ALSource->queue = ALBufferListStart;
1805 // Update Current Buffer
1806 ALSource->ulBufferID = ALBufferListStart->buffer;
1808 else
1810 // Find end of queue
1811 ALBufferList = ALSource->queue;
1812 while (ALBufferList->next != NULL)
1814 ALBufferList = ALBufferList->next;
1817 ALBufferList->next = ALBufferListStart;
1820 // Update number of buffers in queue
1821 ALSource->BuffersInQueue += n;
1824 else
1826 // Invalid Source Type (can't queue on a Static Source)
1827 alSetError(AL_INVALID_OPERATION);
1830 else
1832 // Invalid Source Name
1833 alSetError(AL_INVALID_NAME);
1836 ProcessContext(Context);
1838 else
1840 // Invalid Context
1841 alSetError(AL_INVALID_OPERATION);
1844 return;
1848 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1849 // an array of buffer IDs that are to be filled with the names of the buffers removed
1850 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1852 ALCcontext *Context;
1853 ALsource *ALSource;
1854 ALsizei i;
1855 ALbufferlistitem *ALBufferList;
1856 ALuint DataSize;
1857 ALuint BufferSize;
1858 ALuint BufferID;
1859 ALboolean bBuffersProcessed;
1861 if (n == 0)
1862 return;
1864 DataSize = 0;
1865 BufferSize = 0;
1866 bBuffersProcessed = AL_TRUE;
1868 Context=alcGetCurrentContext();
1869 if (Context)
1871 SuspendContext(Context);
1873 if (alIsSource(source))
1875 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1877 // Check that all 'n' buffers have been processed
1878 ALBufferList = ALSource->queue;
1879 for (i = 0; i < n; i++)
1881 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1883 ALBufferList = ALBufferList->next;
1885 else
1887 bBuffersProcessed = AL_FALSE;
1888 break;
1892 // If all 'n' buffers have been processed, remove them from the queue
1893 if (bBuffersProcessed)
1895 for (i = 0; i < n; i++)
1897 ALBufferList = ALSource->queue;
1899 ALSource->queue = ALBufferList->next;
1900 // Record name of buffer
1901 buffers[i] = ALBufferList->buffer;
1902 // Decrement buffer reference counter
1903 if (ALBufferList->buffer)
1904 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1905 // Record size of buffer
1906 if (ALBufferList->buffer)
1907 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1908 else
1909 BufferSize = 0;
1911 DataSize += BufferSize;
1912 // Release memory for buffer list item
1913 free(ALBufferList);
1914 ALSource->BuffersInQueue--;
1917 if (ALSource->state != AL_PLAYING)
1919 if (ALSource->queue)
1920 BufferID = ALSource->queue->buffer;
1921 else
1922 BufferID = 0;
1924 ALSource->ulBufferID = BufferID;
1927 if((ALuint)n > ALSource->BuffersPlayed)
1928 ALSource->BuffersPlayed = 0;
1929 else
1930 ALSource->BuffersPlayed -= n;
1932 else
1934 // Some buffers can't be unqueue because they have not been processed
1935 alSetError(AL_INVALID_VALUE);
1938 else
1940 // Invalid Source Name
1941 alSetError(AL_INVALID_NAME);
1944 ProcessContext(Context);
1946 else
1948 // Invalid Context
1949 alSetError(AL_INVALID_OPERATION);
1952 return;
1956 static ALvoid InitSourceParams(ALsource *pSource)
1958 pSource->flInnerAngle = 360.0f;
1959 pSource->flOuterAngle = 360.0f;
1960 pSource->flPitch = 1.0f;
1961 pSource->vPosition[0] = 0.0f;
1962 pSource->vPosition[1] = 0.0f;
1963 pSource->vPosition[2] = 0.0f;
1964 pSource->vOrientation[0] = 0.0f;
1965 pSource->vOrientation[1] = 0.0f;
1966 pSource->vOrientation[2] = 0.0f;
1967 pSource->vVelocity[0] = 0.0f;
1968 pSource->vVelocity[1] = 0.0f;
1969 pSource->vVelocity[2] = 0.0f;
1970 pSource->flRefDistance = 1.0f;
1971 pSource->flMaxDistance = FLT_MAX;
1972 pSource->flRollOffFactor = 1.0f;
1973 pSource->bLooping = AL_FALSE;
1974 pSource->flGain = 1.0f;
1975 pSource->flMinGain = 0.0f;
1976 pSource->flMaxGain = 1.0f;
1977 pSource->flOuterGain = 0.0f;
1978 pSource->OuterGainHF = 1.0f;
1980 pSource->DryGainHFAuto = AL_TRUE;
1981 pSource->WetGainAuto = AL_TRUE;
1982 pSource->WetGainHFAuto = AL_TRUE;
1983 pSource->AirAbsorptionFactor = 0.0f;
1984 pSource->RoomRolloffFactor = 0.0f;
1985 pSource->DopplerFactor = 1.0f;
1987 pSource->state = AL_INITIAL;
1988 pSource->lSourceType = AL_UNDETERMINED;
1990 pSource->ulBufferID= 0;
1995 GetSourceOffset
1997 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1998 The offset is relative to the start of the queue (not the start of the current buffer)
2000 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2002 ALbufferlistitem *pBufferList;
2003 ALbuffer *pBuffer;
2004 ALfloat flBufferFreq;
2005 ALint lBytesPlayed, lChannels;
2006 ALenum eOriginalFormat;
2007 ALboolean bReturn = AL_TRUE;
2008 ALint lTotalBufferDataSize;
2010 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2012 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2013 // Get Current Buffer Size and frequency (in milliseconds)
2014 flBufferFreq = (ALfloat)pBuffer->frequency;
2015 eOriginalFormat = pBuffer->eOriginalFormat;
2016 lChannels = aluChannelsFromFormat(pBuffer->format);
2018 // Get Current BytesPlayed
2019 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2020 // Add byte length of any processed buffers in the queue
2021 pBufferList = pSource->queue;
2022 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2024 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2025 pBufferList = pBufferList->next;
2028 lTotalBufferDataSize = 0;
2029 pBufferList = pSource->queue;
2030 while (pBufferList)
2032 if (pBufferList->buffer)
2033 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2034 pBufferList = pBufferList->next;
2037 if (pSource->bLooping)
2039 if (lBytesPlayed < 0)
2040 lBytesPlayed = 0;
2041 else
2042 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2044 else
2046 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2047 if(lBytesPlayed < 0)
2048 lBytesPlayed = 0;
2049 if(lBytesPlayed > lTotalBufferDataSize)
2050 lBytesPlayed = lTotalBufferDataSize;
2053 switch (eName)
2055 case AL_SEC_OFFSET:
2056 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2057 break;
2058 case AL_SAMPLE_OFFSET:
2059 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2060 break;
2061 case AL_BYTE_OFFSET:
2062 // Take into account the original format of the Buffer
2063 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2064 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2066 // Compression rate of the ADPCM supported is 3.6111 to 1
2067 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2068 // Round down to nearest ADPCM block
2069 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2071 else if (eOriginalFormat == AL_FORMAT_REAR8)
2073 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2075 else if (eOriginalFormat == AL_FORMAT_REAR16)
2077 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2079 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2081 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2083 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2085 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2087 else
2089 *pflOffset = (ALfloat)lBytesPlayed;
2091 break;
2094 else
2096 *pflOffset = 0.0f;
2099 return bReturn;
2104 ApplyOffset
2106 Apply a playback offset to the Source. This function will update the queue (to correctly
2107 mark buffers as 'pending' or 'processed' depending upon the new offset.
2109 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2111 ALbufferlistitem *pBufferList;
2112 ALbuffer *pBuffer;
2113 ALint lBufferSize, lTotalBufferSize;
2114 ALint lByteOffset;
2116 // Get true byte offset
2117 lByteOffset = GetByteOffset(pSource);
2119 // If this is a valid offset apply it
2120 if (lByteOffset != -1)
2122 // Sort out the queue (pending and processed states)
2123 pBufferList = pSource->queue;
2124 lTotalBufferSize = 0;
2125 pSource->BuffersPlayed = 0;
2126 while (pBufferList)
2128 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2129 lBufferSize = pBuffer ? pBuffer->size : 0;
2131 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2133 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2134 // update the state to PROCESSED
2135 pSource->BuffersPlayed++;
2137 if (!pSource->bLooping)
2138 pBufferList->bufferstate = PROCESSED;
2140 else if (lTotalBufferSize <= lByteOffset)
2142 // Offset is within this buffer
2143 pBufferList->bufferstate = PENDING;
2145 // Set Current Buffer ID
2146 pSource->ulBufferID = pBufferList->buffer;
2148 // SW Mixer Positions are in Samples
2149 pSource->position = (lByteOffset - lTotalBufferSize) /
2150 aluBytesFromFormat(pBuffer->format) /
2151 aluChannelsFromFormat(pBuffer->format);
2153 else
2155 // Offset is before this buffer, so mark as pending
2156 pBufferList->bufferstate = PENDING;
2159 // Increment the TotalBufferSize
2160 lTotalBufferSize += lBufferSize;
2162 // Move on to next buffer in the Queue
2163 pBufferList = pBufferList->next;
2166 else
2168 if (bUpdateContext)
2169 alSetError(AL_INVALID_VALUE);
2172 // Clear Offset
2173 pSource->lOffset = 0;
2178 GetByteOffset
2180 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2181 offset supplied by the application). This takes into account the fact that the buffer format
2182 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2184 static ALint GetByteOffset(ALsource *pSource)
2186 ALbuffer *pBuffer = NULL;
2187 ALbufferlistitem *pBufferList;
2188 ALfloat flBufferFreq;
2189 ALint lChannels;
2190 ALint lByteOffset = -1;
2191 ALint lTotalBufferDataSize;
2193 // Find the first non-NULL Buffer in the Queue
2194 pBufferList = pSource->queue;
2195 while (pBufferList)
2197 if (pBufferList->buffer)
2199 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2200 break;
2202 pBufferList = pBufferList->next;
2205 if (pBuffer)
2207 flBufferFreq = ((ALfloat)pBuffer->frequency);
2208 lChannels = aluChannelsFromFormat(pBuffer->format);
2210 // Determine the ByteOffset (and ensure it is block aligned)
2211 switch (pSource->lOffsetType)
2213 case AL_BYTE_OFFSET:
2214 // Take into consideration the original format
2215 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2216 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2218 // Round down to nearest ADPCM block
2219 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2220 // Multiply by compression rate
2221 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2222 lByteOffset -= (lByteOffset % (lChannels * 2));
2224 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2226 lByteOffset = pSource->lOffset * 4;
2227 lByteOffset -= (lByteOffset % (lChannels * 2));
2229 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2231 lByteOffset = pSource->lOffset * 2;
2232 lByteOffset -= (lByteOffset % (lChannels * 2));
2234 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2236 lByteOffset = pSource->lOffset * 2;
2237 lByteOffset -= (lByteOffset % (lChannels * 2));
2239 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2241 lByteOffset = pSource->lOffset / 2;
2242 lByteOffset -= (lByteOffset % (lChannels * 2));
2244 else
2246 lByteOffset = pSource->lOffset;
2247 lByteOffset -= (lByteOffset % (lChannels * 2));
2249 break;
2251 case AL_SAMPLE_OFFSET:
2252 lByteOffset = pSource->lOffset * lChannels * 2;
2253 break;
2255 case AL_SEC_OFFSET:
2256 // Note - lOffset is internally stored as Milliseconds
2257 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2258 lByteOffset -= (lByteOffset % (lChannels * 2));
2259 break;
2262 lTotalBufferDataSize = 0;
2263 pBufferList = pSource->queue;
2264 while (pBufferList)
2266 if (pBufferList->buffer)
2267 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2268 pBufferList = pBufferList->next;
2271 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2272 if (lByteOffset >= lTotalBufferDataSize)
2273 lByteOffset = -1;
2276 return lByteOffset;
2280 ALvoid ReleaseALSources(ALCcontext *Context)
2282 #ifdef _DEBUG
2283 if(Context->SourceCount > 0)
2284 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2285 #endif
2287 while(Context->Source)
2289 ALsource *temp = Context->Source;
2290 Context->Source = Context->Source->next;
2292 // Release source structure
2293 ALTHUNK_REMOVEENTRY(temp->source);
2294 memset(temp, 0, sizeof(ALsource));
2295 free(temp);
2297 Context->SourceCount = 0;