Don't check the number of objects being deleted with the number currently allocated
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob88c699cd4167d7dd67834246f037f947caba637b
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_SEC_OFFSET:
369 case AL_SAMPLE_OFFSET:
370 case AL_BYTE_OFFSET:
371 if (flValue >= 0.0f)
373 pSource->lOffsetType = eParam;
375 // Store Offset (convert Seconds into Milliseconds)
376 if (eParam == AL_SEC_OFFSET)
377 pSource->lOffset = (ALint)(flValue * 1000.0f);
378 else
379 pSource->lOffset = (ALint)flValue;
381 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
382 ApplyOffset(pSource, AL_TRUE);
384 else
385 alSetError(AL_INVALID_VALUE);
386 break;
388 default:
389 alSetError(AL_INVALID_ENUM);
390 break;
393 else
395 // Invalid Source Name
396 alSetError(AL_INVALID_NAME);
399 ProcessContext(pContext);
401 else
403 // Invalid context
404 alSetError(AL_INVALID_OPERATION);
407 return;
411 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
413 ALCcontext *pContext;
414 ALsource *pSource;
416 pContext = alcGetCurrentContext();
417 if (pContext)
419 SuspendContext(pContext);
421 if (alIsSource(source))
423 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
424 switch(eParam)
426 case AL_POSITION:
427 pSource->vPosition[0] = flValue1;
428 pSource->vPosition[1] = flValue2;
429 pSource->vPosition[2] = flValue3;
430 break;
432 case AL_VELOCITY:
433 pSource->vVelocity[0] = flValue1;
434 pSource->vVelocity[1] = flValue2;
435 pSource->vVelocity[2] = flValue3;
436 break;
438 case AL_DIRECTION:
439 pSource->vOrientation[0] = flValue1;
440 pSource->vOrientation[1] = flValue2;
441 pSource->vOrientation[2] = flValue3;
442 break;
444 default:
445 alSetError(AL_INVALID_ENUM);
446 break;
449 else
450 alSetError(AL_INVALID_NAME);
452 ProcessContext(pContext);
454 else
456 alSetError(AL_INVALID_OPERATION);
459 return;
463 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
465 ALCcontext *pContext;
467 pContext = alcGetCurrentContext();
468 if (pContext)
470 SuspendContext(pContext);
472 if (pflValues)
474 if (alIsSource(source))
476 switch (eParam)
478 case AL_PITCH:
479 case AL_CONE_INNER_ANGLE:
480 case AL_CONE_OUTER_ANGLE:
481 case AL_GAIN:
482 case AL_MAX_DISTANCE:
483 case AL_ROLLOFF_FACTOR:
484 case AL_REFERENCE_DISTANCE:
485 case AL_MIN_GAIN:
486 case AL_MAX_GAIN:
487 case AL_CONE_OUTER_GAIN:
488 case AL_CONE_OUTER_GAINHF:
489 case AL_SEC_OFFSET:
490 case AL_SAMPLE_OFFSET:
491 case AL_BYTE_OFFSET:
492 case AL_AIR_ABSORPTION_FACTOR:
493 case AL_ROOM_ROLLOFF_FACTOR:
494 alSourcef(source, eParam, pflValues[0]);
495 break;
497 case AL_POSITION:
498 case AL_VELOCITY:
499 case AL_DIRECTION:
500 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
501 break;
503 default:
504 alSetError(AL_INVALID_ENUM);
505 break;
508 else
509 alSetError(AL_INVALID_NAME);
511 else
512 alSetError(AL_INVALID_VALUE);
514 ProcessContext(pContext);
516 else
517 alSetError(AL_INVALID_OPERATION);
519 return;
523 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
525 ALCcontext *pContext;
526 ALsource *pSource;
527 ALbufferlistitem *pALBufferListItem;
528 ALint Counter = 0;
529 ALint DataSize = 0;
530 ALint BufferSize;
532 pContext = alcGetCurrentContext();
533 if (pContext)
535 SuspendContext(pContext);
537 if (alIsSource(source))
539 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
541 switch(eParam)
543 case AL_MAX_DISTANCE:
544 case AL_ROLLOFF_FACTOR:
545 case AL_REFERENCE_DISTANCE:
546 alSourcef(source, eParam, (ALfloat)lValue);
547 break;
549 case AL_SOURCE_RELATIVE:
550 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
551 pSource->bHeadRelative = (ALboolean)lValue;
552 else
553 alSetError(AL_INVALID_VALUE);
554 break;
556 case AL_CONE_INNER_ANGLE:
557 if ((lValue >= 0) && (lValue <= 360))
558 pSource->flInnerAngle = (float)lValue;
559 else
560 alSetError(AL_INVALID_VALUE);
561 break;
563 case AL_CONE_OUTER_ANGLE:
564 if ((lValue >= 0) && (lValue <= 360))
565 pSource->flOuterAngle = (float)lValue;
566 else
567 alSetError(AL_INVALID_VALUE);
568 break;
570 case AL_LOOPING:
571 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
572 pSource->bLooping = (ALboolean)lValue;
573 else
574 alSetError(AL_INVALID_VALUE);
575 break;
577 case AL_BUFFER:
578 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
580 if (alIsBuffer(lValue))
582 // Remove all elements in the queue
583 while (pSource->queue != NULL)
585 pALBufferListItem = pSource->queue;
586 pSource->queue = pALBufferListItem->next;
587 // Decrement reference counter for buffer
588 if (pALBufferListItem->buffer)
589 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
590 // Record size of buffer
591 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
592 DataSize += BufferSize;
593 // Increment the number of buffers removed from queue
594 Counter++;
595 // Release memory for buffer list item
596 free(pALBufferListItem);
597 // Decrement the number of buffers in the queue
598 pSource->BuffersInQueue--;
601 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
602 if (lValue != 0)
604 // Source is now in STATIC mode
605 pSource->lSourceType = AL_STATIC;
607 // Add the selected buffer to the queue
608 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
609 pALBufferListItem->buffer = lValue;
610 pALBufferListItem->bufferstate = PENDING;
611 pALBufferListItem->flag = 0;
612 pALBufferListItem->next = NULL;
614 pSource->queue = pALBufferListItem;
615 pSource->BuffersInQueue = 1;
617 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
619 // Increment reference counter for buffer
620 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
622 else
624 // Source is now in UNDETERMINED mode
625 pSource->lSourceType = AL_UNDETERMINED;
628 // Set Buffers Processed
629 pSource->BuffersProcessed = 0;
631 // Update AL_BUFFER parameter
632 pSource->ulBufferID = lValue;
634 else
635 alSetError(AL_INVALID_VALUE);
637 else
638 alSetError(AL_INVALID_OPERATION);
639 break;
641 case AL_SOURCE_STATE:
642 // Query only
643 alSetError(AL_INVALID_OPERATION);
644 break;
646 case AL_SEC_OFFSET:
647 case AL_SAMPLE_OFFSET:
648 case AL_BYTE_OFFSET:
649 if (lValue >= 0)
651 pSource->lOffsetType = eParam;
653 // Store Offset (convert Seconds into Milliseconds)
654 if (eParam == AL_SEC_OFFSET)
655 pSource->lOffset = lValue * 1000;
656 else
657 pSource->lOffset = lValue;
659 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
660 ApplyOffset(pSource, AL_TRUE);
662 else
663 alSetError(AL_INVALID_VALUE);
664 break;
666 case AL_DIRECT_FILTER:
667 if(alIsFilter(lValue))
669 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
670 if(!filter)
672 pSource->DirectFilter.type = AL_FILTER_NULL;
673 pSource->DirectFilter.filter = 0;
675 else
676 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
678 else
679 alSetError(AL_INVALID_VALUE);
680 break;
682 case AL_DIRECT_FILTER_GAINHF_AUTO:
683 if(lValue == AL_TRUE || lValue == AL_FALSE)
684 pSource->DryGainHFAuto = lValue;
685 else
686 alSetError(AL_INVALID_VALUE);
687 break;
689 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
690 if(lValue == AL_TRUE || lValue == AL_FALSE)
691 pSource->WetGainAuto = lValue;
692 else
693 alSetError(AL_INVALID_VALUE);
694 break;
696 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
697 if(lValue == AL_TRUE || lValue == AL_FALSE)
698 pSource->WetGainHFAuto = lValue;
699 else
700 alSetError(AL_INVALID_VALUE);
701 break;
703 default:
704 alSetError(AL_INVALID_ENUM);
705 break;
708 else
709 alSetError(AL_INVALID_NAME);
711 ProcessContext(pContext);
713 else
714 alSetError(AL_INVALID_OPERATION);
716 return;
720 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
722 ALCcontext *pContext;
724 pContext = alcGetCurrentContext();
725 if (pContext)
727 SuspendContext(pContext);
729 if (alIsSource(source))
731 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
733 switch (eParam)
735 case AL_POSITION:
736 case AL_VELOCITY:
737 case AL_DIRECTION:
738 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
739 break;
741 case AL_AUXILIARY_SEND_FILTER:
742 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
743 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
744 alIsFilter(lValue3))
746 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
747 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
749 /* Release refcount on the previous slot, and add one for
750 * the new slot */
751 if(pSource->Send[lValue2].Slot)
752 pSource->Send[lValue2].Slot->refcount--;
753 pSource->Send[lValue2].Slot = ALEffectSlot;
754 if(pSource->Send[lValue2].Slot)
755 pSource->Send[lValue2].Slot->refcount++;
757 if(!ALFilter)
759 /* Disable filter */
760 pSource->Send[lValue2].WetFilter.type = 0;
761 pSource->Send[lValue2].WetFilter.filter = 0;
763 else
764 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
766 else
767 alSetError(AL_INVALID_VALUE);
768 break;
770 default:
771 alSetError(AL_INVALID_ENUM);
772 break;
775 else
776 alSetError(AL_INVALID_NAME);
778 ProcessContext(pContext);
780 else
781 alSetError(AL_INVALID_OPERATION);
783 return;
787 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
789 ALCcontext *pContext;
791 pContext = alcGetCurrentContext();
792 if (pContext)
794 SuspendContext(pContext);
796 if (plValues)
798 if (alIsSource(source))
800 switch (eParam)
802 case AL_SOURCE_RELATIVE:
803 case AL_CONE_INNER_ANGLE:
804 case AL_CONE_OUTER_ANGLE:
805 case AL_LOOPING:
806 case AL_BUFFER:
807 case AL_SOURCE_STATE:
808 case AL_SEC_OFFSET:
809 case AL_SAMPLE_OFFSET:
810 case AL_BYTE_OFFSET:
811 case AL_MAX_DISTANCE:
812 case AL_ROLLOFF_FACTOR:
813 case AL_REFERENCE_DISTANCE:
814 case AL_DIRECT_FILTER:
815 case AL_DIRECT_FILTER_GAINHF_AUTO:
816 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
817 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
818 alSourcei(source, eParam, plValues[0]);
819 break;
821 case AL_POSITION:
822 case AL_VELOCITY:
823 case AL_DIRECTION:
824 case AL_AUXILIARY_SEND_FILTER:
825 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
826 break;
828 default:
829 alSetError(AL_INVALID_ENUM);
830 break;
833 else
834 alSetError(AL_INVALID_NAME);
836 else
837 alSetError(AL_INVALID_VALUE);
839 ProcessContext(pContext);
841 else
842 alSetError(AL_INVALID_OPERATION);
844 return;
848 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
850 ALCcontext *pContext;
851 ALsource *pSource;
852 ALfloat flOffset;
854 pContext = alcGetCurrentContext();
855 if (pContext)
857 SuspendContext(pContext);
859 if (pflValue)
861 if (alIsSource(source))
863 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
865 switch(eParam)
867 case AL_PITCH:
868 *pflValue = pSource->flPitch;
869 break;
871 case AL_GAIN:
872 *pflValue = pSource->flGain;
873 break;
875 case AL_MIN_GAIN:
876 *pflValue = pSource->flMinGain;
877 break;
879 case AL_MAX_GAIN:
880 *pflValue = pSource->flMaxGain;
881 break;
883 case AL_MAX_DISTANCE:
884 *pflValue = pSource->flMaxDistance;
885 break;
887 case AL_ROLLOFF_FACTOR:
888 *pflValue = pSource->flRollOffFactor;
889 break;
891 case AL_CONE_OUTER_GAIN:
892 *pflValue = pSource->flOuterGain;
893 break;
895 case AL_CONE_OUTER_GAINHF:
896 *pflValue = pSource->OuterGainHF;
897 break;
899 case AL_SEC_OFFSET:
900 case AL_SAMPLE_OFFSET:
901 case AL_BYTE_OFFSET:
902 if (GetSourceOffset(pSource, eParam, &flOffset))
903 *pflValue = flOffset;
904 else
905 alSetError(AL_INVALID_OPERATION);
906 break;
908 case AL_CONE_INNER_ANGLE:
909 *pflValue = pSource->flInnerAngle;
910 break;
912 case AL_CONE_OUTER_ANGLE:
913 *pflValue = pSource->flOuterAngle;
914 break;
916 case AL_REFERENCE_DISTANCE:
917 *pflValue = pSource->flRefDistance;
918 break;
920 case AL_AIR_ABSORPTION_FACTOR:
921 *pflValue = pSource->AirAbsorptionFactor;
922 break;
924 case AL_ROOM_ROLLOFF_FACTOR:
925 *pflValue = pSource->RoomRolloffFactor;
926 break;
928 default:
929 alSetError(AL_INVALID_ENUM);
930 break;
933 else
934 alSetError(AL_INVALID_NAME);
936 else
937 alSetError(AL_INVALID_VALUE);
939 ProcessContext(pContext);
941 else
942 alSetError(AL_INVALID_OPERATION);
944 return;
948 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
950 ALCcontext *pContext;
951 ALsource *pSource;
953 pContext = alcGetCurrentContext();
954 if (pContext)
956 SuspendContext(pContext);
958 if ((pflValue1) && (pflValue2) && (pflValue3))
960 if (alIsSource(source))
962 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
964 switch(eParam)
966 case AL_POSITION:
967 *pflValue1 = pSource->vPosition[0];
968 *pflValue2 = pSource->vPosition[1];
969 *pflValue3 = pSource->vPosition[2];
970 break;
972 case AL_VELOCITY:
973 *pflValue1 = pSource->vVelocity[0];
974 *pflValue2 = pSource->vVelocity[1];
975 *pflValue3 = pSource->vVelocity[2];
976 break;
978 case AL_DIRECTION:
979 *pflValue1 = pSource->vOrientation[0];
980 *pflValue2 = pSource->vOrientation[1];
981 *pflValue3 = pSource->vOrientation[2];
982 break;
984 default:
985 alSetError(AL_INVALID_ENUM);
986 break;
989 else
990 alSetError(AL_INVALID_NAME);
992 else
993 alSetError(AL_INVALID_VALUE);
995 ProcessContext(pContext);
997 else
998 alSetError(AL_INVALID_OPERATION);
1000 return;
1004 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1006 ALCcontext *pContext;
1007 ALsource *pSource;
1009 pContext = alcGetCurrentContext();
1010 if (pContext)
1012 SuspendContext(pContext);
1014 if (pflValues)
1016 if (alIsSource(source))
1018 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1020 switch(eParam)
1022 case AL_PITCH:
1023 case AL_GAIN:
1024 case AL_MIN_GAIN:
1025 case AL_MAX_GAIN:
1026 case AL_MAX_DISTANCE:
1027 case AL_ROLLOFF_FACTOR:
1028 case AL_CONE_OUTER_GAIN:
1029 case AL_SEC_OFFSET:
1030 case AL_SAMPLE_OFFSET:
1031 case AL_BYTE_OFFSET:
1032 case AL_CONE_INNER_ANGLE:
1033 case AL_CONE_OUTER_ANGLE:
1034 case AL_REFERENCE_DISTANCE:
1035 case AL_CONE_OUTER_GAINHF:
1036 case AL_AIR_ABSORPTION_FACTOR:
1037 case AL_ROOM_ROLLOFF_FACTOR:
1038 alGetSourcef(source, eParam, pflValues);
1039 break;
1041 case AL_POSITION:
1042 pflValues[0] = pSource->vPosition[0];
1043 pflValues[1] = pSource->vPosition[1];
1044 pflValues[2] = pSource->vPosition[2];
1045 break;
1047 case AL_VELOCITY:
1048 pflValues[0] = pSource->vVelocity[0];
1049 pflValues[1] = pSource->vVelocity[1];
1050 pflValues[2] = pSource->vVelocity[2];
1051 break;
1053 case AL_DIRECTION:
1054 pflValues[0] = pSource->vOrientation[0];
1055 pflValues[1] = pSource->vOrientation[1];
1056 pflValues[2] = pSource->vOrientation[2];
1057 break;
1059 default:
1060 alSetError(AL_INVALID_ENUM);
1061 break;
1064 else
1065 alSetError(AL_INVALID_NAME);
1067 else
1068 alSetError(AL_INVALID_VALUE);
1070 ProcessContext(pContext);
1072 else
1073 alSetError(AL_INVALID_OPERATION);
1075 return;
1079 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1081 ALCcontext *pContext;
1082 ALsource *pSource;
1083 ALfloat flOffset;
1085 pContext = alcGetCurrentContext();
1086 if (pContext)
1088 SuspendContext(pContext);
1090 if (plValue)
1092 if (alIsSource(source))
1094 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1096 switch(eParam)
1098 case AL_MAX_DISTANCE:
1099 *plValue = (ALint)pSource->flMaxDistance;
1100 break;
1102 case AL_ROLLOFF_FACTOR:
1103 *plValue = (ALint)pSource->flRollOffFactor;
1104 break;
1106 case AL_REFERENCE_DISTANCE:
1107 *plValue = (ALint)pSource->flRefDistance;
1108 break;
1110 case AL_SOURCE_RELATIVE:
1111 *plValue = pSource->bHeadRelative;
1112 break;
1114 case AL_CONE_INNER_ANGLE:
1115 *plValue = (ALint)pSource->flInnerAngle;
1116 break;
1118 case AL_CONE_OUTER_ANGLE:
1119 *plValue = (ALint)pSource->flOuterAngle;
1120 break;
1122 case AL_LOOPING:
1123 *plValue = pSource->bLooping;
1124 break;
1126 case AL_BUFFER:
1127 *plValue = pSource->ulBufferID;
1128 break;
1130 case AL_SOURCE_STATE:
1131 *plValue = pSource->state;
1132 break;
1134 case AL_BUFFERS_QUEUED:
1135 *plValue = pSource->BuffersInQueue;
1136 break;
1138 case AL_BUFFERS_PROCESSED:
1139 if(pSource->bLooping)
1141 /* Buffers on a looping source are in a perpetual state
1142 * of PENDING, so don't report any as PROCESSED */
1143 *plValue = 0;
1145 else
1146 *plValue = pSource->BuffersProcessed;
1147 break;
1149 case AL_SOURCE_TYPE:
1150 *plValue = pSource->lSourceType;
1151 break;
1153 case AL_SEC_OFFSET:
1154 case AL_SAMPLE_OFFSET:
1155 case AL_BYTE_OFFSET:
1156 if (GetSourceOffset(pSource, eParam, &flOffset))
1157 *plValue = (ALint)flOffset;
1158 else
1159 alSetError(AL_INVALID_OPERATION);
1160 break;
1162 case AL_DIRECT_FILTER:
1163 *plValue = pSource->DirectFilter.filter;
1164 break;
1166 case AL_DIRECT_FILTER_GAINHF_AUTO:
1167 *plValue = pSource->DryGainHFAuto;
1168 break;
1170 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1171 *plValue = pSource->WetGainAuto;
1172 break;
1174 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1175 *plValue = pSource->WetGainHFAuto;
1176 break;
1178 default:
1179 alSetError(AL_INVALID_ENUM);
1180 break;
1183 else
1184 alSetError(AL_INVALID_NAME);
1186 else
1187 alSetError(AL_INVALID_VALUE);
1189 ProcessContext(pContext);
1191 else
1192 alSetError(AL_INVALID_OPERATION);
1194 return;
1198 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1200 ALCcontext *pContext;
1201 ALsource *pSource;
1203 pContext = alcGetCurrentContext();
1204 if (pContext)
1206 SuspendContext(pContext);
1208 if ((plValue1) && (plValue2) && (plValue3))
1210 if (alIsSource(source))
1212 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1214 switch(eParam)
1216 case AL_POSITION:
1217 *plValue1 = (ALint)pSource->vPosition[0];
1218 *plValue2 = (ALint)pSource->vPosition[1];
1219 *plValue3 = (ALint)pSource->vPosition[2];
1220 break;
1222 case AL_VELOCITY:
1223 *plValue1 = (ALint)pSource->vVelocity[0];
1224 *plValue2 = (ALint)pSource->vVelocity[1];
1225 *plValue3 = (ALint)pSource->vVelocity[2];
1226 break;
1228 case AL_DIRECTION:
1229 *plValue1 = (ALint)pSource->vOrientation[0];
1230 *plValue2 = (ALint)pSource->vOrientation[1];
1231 *plValue3 = (ALint)pSource->vOrientation[2];
1232 break;
1234 default:
1235 alSetError(AL_INVALID_ENUM);
1236 break;
1239 else
1240 alSetError(AL_INVALID_NAME);
1242 else
1243 alSetError(AL_INVALID_VALUE);
1245 ProcessContext(pContext);
1247 else
1248 alSetError(AL_INVALID_OPERATION);
1250 return;
1254 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1256 ALCcontext *pContext;
1257 ALsource *pSource;
1259 pContext = alcGetCurrentContext();
1260 if (pContext)
1262 SuspendContext(pContext);
1264 if (plValues)
1266 if (alIsSource(source))
1268 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1270 switch (eParam)
1272 case AL_SOURCE_RELATIVE:
1273 case AL_CONE_INNER_ANGLE:
1274 case AL_CONE_OUTER_ANGLE:
1275 case AL_LOOPING:
1276 case AL_BUFFER:
1277 case AL_SOURCE_STATE:
1278 case AL_BUFFERS_QUEUED:
1279 case AL_BUFFERS_PROCESSED:
1280 case AL_SEC_OFFSET:
1281 case AL_SAMPLE_OFFSET:
1282 case AL_BYTE_OFFSET:
1283 case AL_MAX_DISTANCE:
1284 case AL_ROLLOFF_FACTOR:
1285 case AL_REFERENCE_DISTANCE:
1286 case AL_SOURCE_TYPE:
1287 case AL_DIRECT_FILTER:
1288 case AL_DIRECT_FILTER_GAINHF_AUTO:
1289 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1290 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1291 alGetSourcei(source, eParam, plValues);
1292 break;
1294 case AL_POSITION:
1295 plValues[0] = (ALint)pSource->vPosition[0];
1296 plValues[1] = (ALint)pSource->vPosition[1];
1297 plValues[2] = (ALint)pSource->vPosition[2];
1298 break;
1300 case AL_VELOCITY:
1301 plValues[0] = (ALint)pSource->vVelocity[0];
1302 plValues[1] = (ALint)pSource->vVelocity[1];
1303 plValues[2] = (ALint)pSource->vVelocity[2];
1304 break;
1306 case AL_DIRECTION:
1307 plValues[0] = (ALint)pSource->vOrientation[0];
1308 plValues[1] = (ALint)pSource->vOrientation[1];
1309 plValues[2] = (ALint)pSource->vOrientation[2];
1310 break;
1312 default:
1313 alSetError(AL_INVALID_ENUM);
1314 break;
1317 else
1318 alSetError(AL_INVALID_NAME);
1320 else
1321 alSetError(AL_INVALID_VALUE);
1323 ProcessContext(pContext);
1325 else
1326 alSetError(AL_INVALID_OPERATION);
1328 return;
1332 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1334 alSourcePlayv(1, &source);
1335 return;
1338 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1340 ALCcontext *pContext;
1341 ALsource *pSource;
1342 ALbufferlistitem *ALBufferList;
1343 ALboolean bSourcesValid = AL_TRUE;
1344 ALboolean bPlay;
1345 ALsizei i;
1347 pContext = alcGetCurrentContext();
1348 if (pContext)
1350 SuspendContext(pContext);
1352 if (pSourceList)
1354 // Check that all the Sources are valid
1355 for (i = 0; i < n; i++)
1357 if (!alIsSource(pSourceList[i]))
1359 alSetError(AL_INVALID_NAME);
1360 bSourcesValid = AL_FALSE;
1361 break;
1365 if (bSourcesValid)
1367 for (i = 0; i < n; i++)
1369 // Assume Source won't need to play
1370 bPlay = AL_FALSE;
1372 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1374 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1375 ALBufferList = pSource->queue;
1376 while (ALBufferList)
1378 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1380 bPlay = AL_TRUE;
1381 break;
1383 ALBufferList = ALBufferList->next;
1386 if (bPlay)
1388 if (pSource->state != AL_PAUSED)
1390 pSource->state = AL_PLAYING;
1391 pSource->inuse = AL_TRUE;
1392 pSource->play = AL_TRUE;
1393 pSource->position = 0;
1394 pSource->position_fraction = 0;
1395 pSource->BuffersProcessed = 0;
1396 pSource->BuffersPlayed = 0;
1397 pSource->BufferPosition = 0;
1398 pSource->lBytesPlayed = 0;
1400 pSource->ulBufferID = pSource->queue->buffer;
1402 // Make sure all the Buffers in the queue are marked as PENDING
1403 ALBufferList = pSource->queue;
1404 while (ALBufferList)
1406 ALBufferList->bufferstate = PENDING;
1407 ALBufferList = ALBufferList->next;
1410 else
1412 pSource->state = AL_PLAYING;
1413 pSource->inuse = AL_TRUE;
1414 pSource->play = AL_TRUE;
1417 // Check if an Offset has been set
1418 if (pSource->lOffset)
1419 ApplyOffset(pSource, AL_FALSE);
1421 else
1423 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1424 ALBufferList = pSource->queue;
1425 while (ALBufferList)
1427 ALBufferList->bufferstate = PROCESSED;
1428 ALBufferList = ALBufferList->next;
1431 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1436 else
1438 // sources is a NULL pointer
1439 alSetError(AL_INVALID_VALUE);
1442 ProcessContext(pContext);
1444 else
1446 // Invalid Context
1447 alSetError(AL_INVALID_OPERATION);
1450 return;
1453 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1455 alSourcePausev(1, &source);
1456 return;
1459 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1461 ALCcontext *Context;
1462 ALsource *Source;
1463 ALsizei i;
1464 ALboolean bSourcesValid = AL_TRUE;
1466 Context=alcGetCurrentContext();
1467 if (Context)
1469 SuspendContext(Context);
1471 if (sources)
1473 // Check all the Sources are valid
1474 for (i=0;i<n;i++)
1476 if (!alIsSource(sources[i]))
1478 alSetError(AL_INVALID_NAME);
1479 bSourcesValid = AL_FALSE;
1480 break;
1484 if (bSourcesValid)
1486 for (i=0;i<n;i++)
1488 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1489 if (Source->state==AL_PLAYING)
1491 Source->state=AL_PAUSED;
1492 Source->inuse=AL_FALSE;
1497 else
1499 // sources is a NULL pointer
1500 alSetError(AL_INVALID_VALUE);
1503 ProcessContext(Context);
1505 else
1507 // Invalid Context
1508 alSetError(AL_INVALID_OPERATION);
1511 return;
1514 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1516 alSourceStopv(1, &source);
1517 return;
1520 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1522 ALCcontext *Context;
1523 ALsource *Source;
1524 ALsizei i;
1525 ALbufferlistitem *ALBufferListItem;
1526 ALboolean bSourcesValid = AL_TRUE;
1528 Context=alcGetCurrentContext();
1529 if (Context)
1531 SuspendContext(Context);
1533 if (sources)
1535 // Check all the Sources are valid
1536 for (i=0;i<n;i++)
1538 if (!alIsSource(sources[i]))
1540 alSetError(AL_INVALID_NAME);
1541 bSourcesValid = AL_FALSE;
1542 break;
1546 if (bSourcesValid)
1548 for (i=0;i<n;i++)
1550 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1551 if (Source->state!=AL_INITIAL)
1553 Source->state=AL_STOPPED;
1554 Source->inuse=AL_FALSE;
1555 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1556 ALBufferListItem= Source->queue;
1557 while (ALBufferListItem != NULL)
1559 ALBufferListItem->bufferstate = PROCESSED;
1560 ALBufferListItem = ALBufferListItem->next;
1563 Source->lOffset = 0;
1567 else
1569 // sources is a NULL pointer
1570 alSetError(AL_INVALID_VALUE);
1573 ProcessContext(Context);
1575 else
1577 // Invalid Context
1578 alSetError(AL_INVALID_OPERATION);
1581 return;
1584 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1586 alSourceRewindv(1, &source);
1587 return;
1590 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1592 ALCcontext *Context;
1593 ALsource *Source;
1594 ALsizei i;
1595 ALbufferlistitem *ALBufferListItem;
1596 ALboolean bSourcesValid = AL_TRUE;
1598 Context=alcGetCurrentContext();
1599 if (Context)
1601 SuspendContext(Context);
1603 if (sources)
1605 // Check all the Sources are valid
1606 for (i=0;i<n;i++)
1608 if (!alIsSource(sources[i]))
1610 alSetError(AL_INVALID_NAME);
1611 bSourcesValid = AL_FALSE;
1612 break;
1616 if (bSourcesValid)
1618 for (i=0;i<n;i++)
1620 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1621 if (Source->state!=AL_INITIAL)
1623 Source->state=AL_INITIAL;
1624 Source->inuse=AL_FALSE;
1625 Source->position=0;
1626 Source->position_fraction=0;
1627 Source->BuffersProcessed = 0;
1628 ALBufferListItem= Source->queue;
1629 while (ALBufferListItem != NULL)
1631 ALBufferListItem->bufferstate = PENDING;
1632 ALBufferListItem = ALBufferListItem->next;
1634 if (Source->queue)
1635 Source->ulBufferID = Source->queue->buffer;
1637 Source->lOffset = 0;
1641 else
1643 // sources is a NULL pointer
1644 alSetError(AL_INVALID_VALUE);
1647 ProcessContext(Context);
1649 else
1651 // Invalid Context
1652 alSetError(AL_INVALID_OPERATION);
1655 return;
1659 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1661 ALCcontext *Context;
1662 ALsource *ALSource;
1663 ALsizei i;
1664 ALbufferlistitem *ALBufferList;
1665 ALbufferlistitem *ALBufferListStart;
1666 ALuint DataSize;
1667 ALuint BufferSize;
1668 ALint iFrequency;
1669 ALint iFormat;
1670 ALboolean bBuffersValid = AL_TRUE;
1672 if (n == 0)
1673 return;
1675 Context=alcGetCurrentContext();
1676 if (Context)
1678 SuspendContext(Context);
1680 DataSize = 0;
1681 BufferSize = 0;
1683 // Check that all buffers are valid or zero and that the source is valid
1685 // Check that this is a valid source
1686 if (alIsSource(source))
1688 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1690 // Check that this is not a STATIC Source
1691 if (ALSource->lSourceType != AL_STATIC)
1693 iFrequency = -1;
1694 iFormat = -1;
1696 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1697 ALBufferList = ALSource->queue;
1698 while (ALBufferList)
1700 if (ALBufferList->buffer)
1702 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1703 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1704 break;
1706 ALBufferList = ALBufferList->next;
1709 for (i = 0; i < n; i++)
1711 if (alIsBuffer(buffers[i]))
1713 if (buffers[i])
1715 if ((iFrequency == -1) && (iFormat == -1))
1717 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1718 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1720 else
1722 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1723 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1725 alSetError(AL_INVALID_OPERATION);
1726 bBuffersValid = AL_FALSE;
1727 break;
1732 else
1734 alSetError(AL_INVALID_NAME);
1735 bBuffersValid = AL_FALSE;
1736 break;
1740 if (bBuffersValid)
1742 // Change Source Type
1743 ALSource->lSourceType = AL_STREAMING;
1745 // All buffers are valid - so add them to the list
1746 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1747 ALBufferListStart->buffer = buffers[0];
1748 ALBufferListStart->bufferstate = PENDING;
1749 ALBufferListStart->flag = 0;
1750 ALBufferListStart->next = NULL;
1752 if (buffers[0])
1753 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1754 else
1755 BufferSize = 0;
1757 DataSize += BufferSize;
1759 // Increment reference counter for buffer
1760 if (buffers[0])
1761 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1763 ALBufferList = ALBufferListStart;
1765 for (i = 1; i < n; i++)
1767 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1768 ALBufferList->next->buffer = buffers[i];
1769 ALBufferList->next->bufferstate = PENDING;
1770 ALBufferList->next->flag = 0;
1771 ALBufferList->next->next = NULL;
1773 if (buffers[i])
1774 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1775 else
1776 BufferSize = 0;
1778 DataSize += BufferSize;
1780 // Increment reference counter for buffer
1781 if (buffers[i])
1782 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1784 ALBufferList = ALBufferList->next;
1787 if (ALSource->queue == NULL)
1789 ALSource->queue = ALBufferListStart;
1790 // Update Current Buffer
1791 ALSource->ulBufferID = ALBufferListStart->buffer;
1793 else
1795 // Find end of queue
1796 ALBufferList = ALSource->queue;
1797 while (ALBufferList->next != NULL)
1799 ALBufferList = ALBufferList->next;
1802 ALBufferList->next = ALBufferListStart;
1805 // Update number of buffers in queue
1806 ALSource->BuffersInQueue += n;
1809 else
1811 // Invalid Source Type (can't queue on a Static Source)
1812 alSetError(AL_INVALID_OPERATION);
1815 else
1817 // Invalid Source Name
1818 alSetError(AL_INVALID_NAME);
1821 ProcessContext(Context);
1823 else
1825 // Invalid Context
1826 alSetError(AL_INVALID_OPERATION);
1829 return;
1833 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1834 // an array of buffer IDs that are to be filled with the names of the buffers removed
1835 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1837 ALCcontext *Context;
1838 ALsource *ALSource;
1839 ALsizei i;
1840 ALbufferlistitem *ALBufferList;
1841 ALuint DataSize;
1842 ALuint BufferSize;
1843 ALuint BufferID;
1844 ALboolean bBuffersProcessed;
1846 if (n == 0)
1847 return;
1849 DataSize = 0;
1850 BufferSize = 0;
1851 bBuffersProcessed = AL_TRUE;
1853 Context=alcGetCurrentContext();
1854 if (Context)
1856 SuspendContext(Context);
1858 if (alIsSource(source))
1860 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1862 // Check that all 'n' buffers have been processed
1863 ALBufferList = ALSource->queue;
1864 for (i = 0; i < n; i++)
1866 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1868 ALBufferList = ALBufferList->next;
1870 else
1872 bBuffersProcessed = AL_FALSE;
1873 break;
1877 // If all 'n' buffers have been processed, remove them from the queue
1878 if (bBuffersProcessed)
1880 for (i = 0; i < n; i++)
1882 ALBufferList = ALSource->queue;
1884 ALSource->queue = ALBufferList->next;
1885 // Record name of buffer
1886 buffers[i] = ALBufferList->buffer;
1887 // Decrement buffer reference counter
1888 if (ALBufferList->buffer)
1889 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1890 // Record size of buffer
1891 if (ALBufferList->buffer)
1892 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1893 else
1894 BufferSize = 0;
1896 DataSize += BufferSize;
1897 // Release memory for buffer list item
1898 free(ALBufferList);
1899 ALSource->BuffersInQueue--;
1900 ALSource->BuffersProcessed--;
1903 if (ALSource->state != AL_PLAYING)
1905 if (ALSource->queue)
1906 BufferID = ALSource->queue->buffer;
1907 else
1908 BufferID = 0;
1910 ALSource->ulBufferID = BufferID;
1913 if((ALuint)n > ALSource->BuffersPlayed)
1915 ALSource->BuffersPlayed = 0;
1916 ALSource->BufferPosition = 0;
1918 else
1919 ALSource->BuffersPlayed -= n;
1921 else
1923 // Some buffers can't be unqueue because they have not been processed
1924 alSetError(AL_INVALID_VALUE);
1927 else
1929 // Invalid Source Name
1930 alSetError(AL_INVALID_NAME);
1933 ProcessContext(Context);
1935 else
1937 // Invalid Context
1938 alSetError(AL_INVALID_OPERATION);
1941 return;
1945 static ALvoid InitSourceParams(ALsource *pSource)
1947 pSource->flInnerAngle = 360.0f;
1948 pSource->flOuterAngle = 360.0f;
1949 pSource->flPitch = 1.0f;
1950 pSource->vPosition[0] = 0.0f;
1951 pSource->vPosition[1] = 0.0f;
1952 pSource->vPosition[2] = 0.0f;
1953 pSource->vOrientation[0] = 0.0f;
1954 pSource->vOrientation[1] = 0.0f;
1955 pSource->vOrientation[2] = 0.0f;
1956 pSource->vVelocity[0] = 0.0f;
1957 pSource->vVelocity[1] = 0.0f;
1958 pSource->vVelocity[2] = 0.0f;
1959 pSource->flRefDistance = 1.0f;
1960 pSource->flMaxDistance = FLT_MAX;
1961 pSource->flRollOffFactor = 1.0f;
1962 pSource->bLooping = AL_FALSE;
1963 pSource->flGain = 1.0f;
1964 pSource->flMinGain = 0.0f;
1965 pSource->flMaxGain = 1.0f;
1966 pSource->flOuterGain = 0.0f;
1967 pSource->OuterGainHF = 1.0f;
1969 pSource->DryGainHFAuto = AL_TRUE;
1970 pSource->WetGainAuto = AL_TRUE;
1971 pSource->WetGainHFAuto = AL_TRUE;
1972 pSource->AirAbsorptionFactor = 0.0f;
1973 pSource->RoomRolloffFactor = 0.0f;
1975 pSource->state = AL_INITIAL;
1976 pSource->lSourceType = AL_UNDETERMINED;
1978 pSource->ulBufferID= 0;
1983 GetSourceOffset
1985 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1986 The offset is relative to the start of the queue (not the start of the current buffer)
1988 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1990 ALbufferlistitem *pBufferList;
1991 ALbuffer *pBuffer;
1992 ALfloat flBufferFreq;
1993 ALint lBytesPlayed, lChannels;
1994 ALenum eOriginalFormat;
1995 ALboolean bReturn = AL_TRUE;
1996 ALint lTotalBufferDataSize;
1998 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2000 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2001 // Get Current Buffer Size and frequency (in milliseconds)
2002 flBufferFreq = (ALfloat)pBuffer->frequency;
2003 eOriginalFormat = pBuffer->eOriginalFormat;
2004 lChannels = aluChannelsFromFormat(pBuffer->format);
2006 // Get Current BytesPlayed
2007 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2008 // Add byte length of any processed buffers in the queue
2009 pBufferList = pSource->queue;
2010 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2012 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2013 pBufferList = pBufferList->next;
2016 lTotalBufferDataSize = 0;
2017 pBufferList = pSource->queue;
2018 while (pBufferList)
2020 if (pBufferList->buffer)
2021 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2022 pBufferList = pBufferList->next;
2025 if (pSource->bLooping)
2027 if (lBytesPlayed < 0)
2028 lBytesPlayed = 0;
2029 else
2030 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2032 else
2034 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2035 if(lBytesPlayed < 0)
2036 lBytesPlayed = 0;
2037 if(lBytesPlayed > lTotalBufferDataSize)
2038 lBytesPlayed = lTotalBufferDataSize;
2041 switch (eName)
2043 case AL_SEC_OFFSET:
2044 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2045 break;
2046 case AL_SAMPLE_OFFSET:
2047 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2048 break;
2049 case AL_BYTE_OFFSET:
2050 // Take into account the original format of the Buffer
2051 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2052 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2054 // Compression rate of the ADPCM supported is 3.6111 to 1
2055 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2056 // Round down to nearest ADPCM block
2057 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2059 else if (eOriginalFormat == AL_FORMAT_REAR8)
2061 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2063 else if (eOriginalFormat == AL_FORMAT_REAR16)
2065 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2067 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2069 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2071 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2073 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2075 else
2077 *pflOffset = (ALfloat)lBytesPlayed;
2079 break;
2082 else
2084 *pflOffset = 0.0f;
2087 return bReturn;
2092 ApplyOffset
2094 Apply a playback offset to the Source. This function will update the queue (to correctly
2095 mark buffers as 'pending' or 'processed' depending upon the new offset.
2097 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2099 ALbufferlistitem *pBufferList;
2100 ALbuffer *pBuffer;
2101 ALint lBufferSize, lTotalBufferSize;
2102 ALint lByteOffset;
2104 // Get true byte offset
2105 lByteOffset = GetByteOffset(pSource);
2107 // If this is a valid offset apply it
2108 if (lByteOffset != -1)
2110 // Sort out the queue (pending and processed states)
2111 pBufferList = pSource->queue;
2112 lTotalBufferSize = 0;
2113 pSource->BuffersPlayed = 0;
2114 pSource->BuffersProcessed = 0;
2115 while (pBufferList)
2117 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2118 lBufferSize = pBuffer ? pBuffer->size : 0;
2120 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2122 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2123 // update the state to PROCESSED
2124 pSource->BuffersPlayed++;
2126 if (!pSource->bLooping)
2128 pBufferList->bufferstate = PROCESSED;
2129 pSource->BuffersProcessed++;
2132 else if (lTotalBufferSize <= lByteOffset)
2134 // Offset is within this buffer
2135 pBufferList->bufferstate = PENDING;
2137 // Set Current Buffer ID
2138 pSource->ulBufferID = pBufferList->buffer;
2140 // Set current position in this buffer
2141 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2143 // Set Total Bytes Played to Offset
2144 pSource->lBytesPlayed = lByteOffset;
2146 // SW Mixer Positions are in Samples
2147 pSource->position = pSource->BufferPosition /
2148 aluBytesFromFormat(pBuffer->format) /
2149 aluChannelsFromFormat(pBuffer->format);
2151 else
2153 // Offset is before this buffer, so mark as pending
2154 pBufferList->bufferstate = PENDING;
2157 // Increment the TotalBufferSize
2158 lTotalBufferSize += lBufferSize;
2160 // Move on to next buffer in the Queue
2161 pBufferList = pBufferList->next;
2164 else
2166 if (bUpdateContext)
2167 alSetError(AL_INVALID_VALUE);
2170 // Clear Offset
2171 pSource->lOffset = 0;
2176 GetByteOffset
2178 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2179 offset supplied by the application). This takes into account the fact that the buffer format
2180 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2182 static ALint GetByteOffset(ALsource *pSource)
2184 ALbuffer *pBuffer = NULL;
2185 ALbufferlistitem *pBufferList;
2186 ALfloat flBufferFreq;
2187 ALint lChannels;
2188 ALint lByteOffset = -1;
2189 ALint lTotalBufferDataSize;
2191 // Find the first non-NULL Buffer in the Queue
2192 pBufferList = pSource->queue;
2193 while (pBufferList)
2195 if (pBufferList->buffer)
2197 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2198 break;
2200 pBufferList = pBufferList->next;
2203 if (pBuffer)
2205 flBufferFreq = ((ALfloat)pBuffer->frequency);
2206 lChannels = aluChannelsFromFormat(pBuffer->format);
2208 // Determine the ByteOffset (and ensure it is block aligned)
2209 switch (pSource->lOffsetType)
2211 case AL_BYTE_OFFSET:
2212 // Take into consideration the original format
2213 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2214 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2216 // Round down to nearest ADPCM block
2217 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2218 // Multiply by compression rate
2219 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2220 lByteOffset -= (lByteOffset % (lChannels * 2));
2222 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2224 lByteOffset = pSource->lOffset * 4;
2225 lByteOffset -= (lByteOffset % (lChannels * 2));
2227 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2229 lByteOffset = pSource->lOffset * 2;
2230 lByteOffset -= (lByteOffset % (lChannels * 2));
2232 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2234 lByteOffset = pSource->lOffset * 2;
2235 lByteOffset -= (lByteOffset % (lChannels * 2));
2237 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2239 lByteOffset = pSource->lOffset / 2;
2240 lByteOffset -= (lByteOffset % (lChannels * 2));
2242 else
2244 lByteOffset = pSource->lOffset;
2245 lByteOffset -= (lByteOffset % (lChannels * 2));
2247 break;
2249 case AL_SAMPLE_OFFSET:
2250 lByteOffset = pSource->lOffset * lChannels * 2;
2251 break;
2253 case AL_SEC_OFFSET:
2254 // Note - lOffset is internally stored as Milliseconds
2255 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2256 lByteOffset -= (lByteOffset % (lChannels * 2));
2257 break;
2260 lTotalBufferDataSize = 0;
2261 pBufferList = pSource->queue;
2262 while (pBufferList)
2264 if (pBufferList->buffer)
2265 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2266 pBufferList = pBufferList->next;
2269 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2270 if (lByteOffset >= lTotalBufferDataSize)
2271 lByteOffset = -1;
2274 return lByteOffset;
2278 ALvoid ReleaseALSources(ALCcontext *Context)
2280 #ifdef _DEBUG
2281 if(Context->SourceCount > 0)
2282 AL_PRINT("alcDestroyContext(): %d Source(s) NOT deleted\n", Context->SourceCount);
2283 #endif
2285 while(Context->Source)
2287 ALsource *temp = Context->Source;
2288 Context->Source = Context->Source->next;
2290 // Release source structure
2291 ALTHUNK_REMOVEENTRY(temp->source);
2292 memset(temp, 0, sizeof(ALsource));
2293 free(temp);
2295 Context->SourceCount = 0;