Add missing config.h includes
[openal-soft.git] / OpenAL32 / alSource.c
blob73b298a49801ffb947e220a1a14983e391c53631
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;
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 if ((ALuint)n <= Context->SourceCount)
142 // Check that all Sources are valid (and can therefore be deleted)
143 for (i = 0; i < n; i++)
145 if (!alIsSource(sources[i]))
147 alSetError(AL_INVALID_NAME);
148 bSourcesValid = AL_FALSE;
149 break;
153 if (bSourcesValid)
155 // All Sources are valid, and can be deleted
156 for (i = 0; i < n; i++)
158 // Recheck that the Source is valid, because there could be duplicated Source names
159 if (alIsSource(sources[i]))
161 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
162 alSourceStop((ALuint)ALSource->source);
164 // For each buffer in the source's queue, decrement its reference counter and remove it
165 while (ALSource->queue != NULL)
167 ALBufferList = ALSource->queue;
168 // Decrement buffer's reference counter
169 if (ALBufferList->buffer != 0)
170 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
171 // Update queue to point to next element in list
172 ALSource->queue = ALBufferList->next;
173 // Release memory allocated for buffer list item
174 free(ALBufferList);
177 // Decrement Source count
178 Context->SourceCount--;
180 // Remove Source from list of Sources
181 list = &Context->Source;
182 while(*list && *list != ALSource)
183 list = &(*list)->next;
185 if(*list)
186 *list = (*list)->next;
187 ALTHUNK_REMOVEENTRY(ALSource->source);
189 memset(ALSource,0,sizeof(ALsource));
190 free(ALSource);
196 else
198 // Trying to delete more Sources than have been generated
199 alSetError(AL_INVALID_NAME);
202 else
204 // No Device created, or attached to Context
205 alSetError(AL_INVALID_OPERATION);
208 else
209 alSetError(AL_INVALID_VALUE);
211 ProcessContext(Context);
213 else
215 // Invalid Context
216 alSetError(AL_INVALID_OPERATION);
219 return;
223 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
225 ALboolean result=AL_FALSE;
226 ALCcontext *Context;
227 ALsource *Source;
229 Context=alcGetCurrentContext();
230 if (Context)
232 SuspendContext(Context);
234 // To determine if this is a valid Source name, look through the list of generated Sources
235 Source = Context->Source;
236 while(Source)
238 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
240 result = AL_TRUE;
241 break;
244 Source = Source->next;
247 ProcessContext(Context);
249 else
251 // Invalid Context
252 alSetError(AL_INVALID_OPERATION);
255 return result;
259 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
261 ALCcontext *pContext;
262 ALsource *pSource;
264 pContext = alcGetCurrentContext();
265 if (pContext)
267 SuspendContext(pContext);
269 if (alIsSource(source))
271 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
273 switch (eParam)
275 case AL_PITCH:
276 if (flValue >= 0.0f)
278 pSource->flPitch = flValue;
279 if(pSource->flPitch < 0.001f)
280 pSource->flPitch = 0.001f;
282 else
283 alSetError(AL_INVALID_VALUE);
284 break;
286 case AL_CONE_INNER_ANGLE:
287 if ((flValue >= 0.0f) && (flValue <= 360.0f))
288 pSource->flInnerAngle = flValue;
289 else
290 alSetError(AL_INVALID_VALUE);
291 break;
293 case AL_CONE_OUTER_ANGLE:
294 if ((flValue >= 0.0f) && (flValue <= 360.0f))
295 pSource->flOuterAngle = flValue;
296 else
297 alSetError(AL_INVALID_VALUE);
298 break;
300 case AL_GAIN:
301 if (flValue >= 0.0f)
302 pSource->flGain = flValue;
303 else
304 alSetError(AL_INVALID_VALUE);
305 break;
307 case AL_MAX_DISTANCE:
308 if (flValue >= 0.0f)
309 pSource->flMaxDistance = flValue;
310 else
311 alSetError(AL_INVALID_VALUE);
312 break;
314 case AL_ROLLOFF_FACTOR:
315 if (flValue >= 0.0f)
316 pSource->flRollOffFactor = flValue;
317 else
318 alSetError(AL_INVALID_VALUE);
319 break;
321 case AL_REFERENCE_DISTANCE:
322 if (flValue >= 0.0f)
323 pSource->flRefDistance = flValue;
324 else
325 alSetError(AL_INVALID_VALUE);
326 break;
328 case AL_MIN_GAIN:
329 if ((flValue >= 0.0f) && (flValue <= 1.0f))
330 pSource->flMinGain = flValue;
331 else
332 alSetError(AL_INVALID_VALUE);
333 break;
335 case AL_MAX_GAIN:
336 if ((flValue >= 0.0f) && (flValue <= 1.0f))
337 pSource->flMaxGain = flValue;
338 else
339 alSetError(AL_INVALID_VALUE);
340 break;
342 case AL_CONE_OUTER_GAIN:
343 if ((flValue >= 0.0f) && (flValue <= 1.0f))
344 pSource->flOuterGain = flValue;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 case AL_CONE_OUTER_GAINHF:
350 if ((flValue >= 0.0f) && (flValue <= 1.0f))
351 pSource->OuterGainHF = flValue;
352 else
353 alSetError(AL_INVALID_VALUE);
354 break;
356 case AL_AIR_ABSORPTION_FACTOR:
357 if (flValue >= 0.0f && flValue <= 10.0f)
358 pSource->AirAbsorptionFactor = flValue;
359 else
360 alSetError(AL_INVALID_VALUE);
361 break;
363 case AL_ROOM_ROLLOFF_FACTOR:
364 if (flValue >= 0.0f && flValue <= 1.0f)
365 pSource->RoomRolloffFactor = flValue;
366 else
367 alSetError(AL_INVALID_VALUE);
368 break;
370 case AL_SEC_OFFSET:
371 case AL_SAMPLE_OFFSET:
372 case AL_BYTE_OFFSET:
373 if (flValue >= 0.0f)
375 pSource->lOffsetType = eParam;
377 // Store Offset (convert Seconds into Milliseconds)
378 if (eParam == AL_SEC_OFFSET)
379 pSource->lOffset = (ALint)(flValue * 1000.0f);
380 else
381 pSource->lOffset = (ALint)flValue;
383 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
384 ApplyOffset(pSource, AL_TRUE);
386 else
387 alSetError(AL_INVALID_VALUE);
388 break;
390 default:
391 alSetError(AL_INVALID_ENUM);
392 break;
395 else
397 // Invalid Source Name
398 alSetError(AL_INVALID_NAME);
401 ProcessContext(pContext);
403 else
405 // Invalid context
406 alSetError(AL_INVALID_OPERATION);
409 return;
413 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
415 ALCcontext *pContext;
416 ALsource *pSource;
418 pContext = alcGetCurrentContext();
419 if (pContext)
421 SuspendContext(pContext);
423 if (alIsSource(source))
425 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
426 switch(eParam)
428 case AL_POSITION:
429 pSource->vPosition[0] = flValue1;
430 pSource->vPosition[1] = flValue2;
431 pSource->vPosition[2] = flValue3;
432 break;
434 case AL_VELOCITY:
435 pSource->vVelocity[0] = flValue1;
436 pSource->vVelocity[1] = flValue2;
437 pSource->vVelocity[2] = flValue3;
438 break;
440 case AL_DIRECTION:
441 pSource->vOrientation[0] = flValue1;
442 pSource->vOrientation[1] = flValue2;
443 pSource->vOrientation[2] = flValue3;
444 break;
446 default:
447 alSetError(AL_INVALID_ENUM);
448 break;
451 else
452 alSetError(AL_INVALID_NAME);
454 ProcessContext(pContext);
456 else
458 alSetError(AL_INVALID_OPERATION);
461 return;
465 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
467 ALCcontext *pContext;
469 pContext = alcGetCurrentContext();
470 if (pContext)
472 SuspendContext(pContext);
474 if (pflValues)
476 if (alIsSource(source))
478 switch (eParam)
480 case AL_PITCH:
481 case AL_CONE_INNER_ANGLE:
482 case AL_CONE_OUTER_ANGLE:
483 case AL_GAIN:
484 case AL_MAX_DISTANCE:
485 case AL_ROLLOFF_FACTOR:
486 case AL_REFERENCE_DISTANCE:
487 case AL_MIN_GAIN:
488 case AL_MAX_GAIN:
489 case AL_CONE_OUTER_GAIN:
490 case AL_CONE_OUTER_GAINHF:
491 case AL_SEC_OFFSET:
492 case AL_SAMPLE_OFFSET:
493 case AL_BYTE_OFFSET:
494 case AL_AIR_ABSORPTION_FACTOR:
495 case AL_ROOM_ROLLOFF_FACTOR:
496 alSourcef(source, eParam, pflValues[0]);
497 break;
499 case AL_POSITION:
500 case AL_VELOCITY:
501 case AL_DIRECTION:
502 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
503 break;
505 default:
506 alSetError(AL_INVALID_ENUM);
507 break;
510 else
511 alSetError(AL_INVALID_NAME);
513 else
514 alSetError(AL_INVALID_VALUE);
516 ProcessContext(pContext);
518 else
519 alSetError(AL_INVALID_OPERATION);
521 return;
525 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
527 ALCcontext *pContext;
528 ALsource *pSource;
529 ALbufferlistitem *pALBufferListItem;
530 ALint Counter = 0;
531 ALint DataSize = 0;
532 ALint BufferSize;
534 pContext = alcGetCurrentContext();
535 if (pContext)
537 SuspendContext(pContext);
539 if (alIsSource(source))
541 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
543 switch(eParam)
545 case AL_MAX_DISTANCE:
546 case AL_ROLLOFF_FACTOR:
547 case AL_REFERENCE_DISTANCE:
548 alSourcef(source, eParam, (ALfloat)lValue);
549 break;
551 case AL_SOURCE_RELATIVE:
552 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
553 pSource->bHeadRelative = (ALboolean)lValue;
554 else
555 alSetError(AL_INVALID_VALUE);
556 break;
558 case AL_CONE_INNER_ANGLE:
559 if ((lValue >= 0) && (lValue <= 360))
560 pSource->flInnerAngle = (float)lValue;
561 else
562 alSetError(AL_INVALID_VALUE);
563 break;
565 case AL_CONE_OUTER_ANGLE:
566 if ((lValue >= 0) && (lValue <= 360))
567 pSource->flOuterAngle = (float)lValue;
568 else
569 alSetError(AL_INVALID_VALUE);
570 break;
572 case AL_LOOPING:
573 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
574 pSource->bLooping = (ALboolean)lValue;
575 else
576 alSetError(AL_INVALID_VALUE);
577 break;
579 case AL_BUFFER:
580 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
582 if (alIsBuffer(lValue))
584 // Remove all elements in the queue
585 while (pSource->queue != NULL)
587 pALBufferListItem = pSource->queue;
588 pSource->queue = pALBufferListItem->next;
589 // Decrement reference counter for buffer
590 if (pALBufferListItem->buffer)
591 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
592 // Record size of buffer
593 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
594 DataSize += BufferSize;
595 // Increment the number of buffers removed from queue
596 Counter++;
597 // Release memory for buffer list item
598 free(pALBufferListItem);
599 // Decrement the number of buffers in the queue
600 pSource->BuffersInQueue--;
603 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
604 if (lValue != 0)
606 // Source is now in STATIC mode
607 pSource->lSourceType = AL_STATIC;
609 // Add the selected buffer to the queue
610 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
611 pALBufferListItem->buffer = lValue;
612 pALBufferListItem->bufferstate = PENDING;
613 pALBufferListItem->flag = 0;
614 pALBufferListItem->next = NULL;
616 pSource->queue = pALBufferListItem;
617 pSource->BuffersInQueue = 1;
619 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
621 // Increment reference counter for buffer
622 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
624 else
626 // Source is now in UNDETERMINED mode
627 pSource->lSourceType = AL_UNDETERMINED;
630 // Set Buffers Processed
631 pSource->BuffersProcessed = 0;
633 // Update AL_BUFFER parameter
634 pSource->ulBufferID = lValue;
636 else
637 alSetError(AL_INVALID_VALUE);
639 else
640 alSetError(AL_INVALID_OPERATION);
641 break;
643 case AL_SOURCE_STATE:
644 // Query only
645 alSetError(AL_INVALID_OPERATION);
646 break;
648 case AL_SEC_OFFSET:
649 case AL_SAMPLE_OFFSET:
650 case AL_BYTE_OFFSET:
651 if (lValue >= 0)
653 pSource->lOffsetType = eParam;
655 // Store Offset (convert Seconds into Milliseconds)
656 if (eParam == AL_SEC_OFFSET)
657 pSource->lOffset = lValue * 1000;
658 else
659 pSource->lOffset = lValue;
661 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
662 ApplyOffset(pSource, AL_TRUE);
664 else
665 alSetError(AL_INVALID_VALUE);
666 break;
668 case AL_DIRECT_FILTER:
669 if(alIsFilter(lValue))
671 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
672 if(!filter)
674 pSource->DirectFilter.type = AL_FILTER_NULL;
675 pSource->DirectFilter.filter = 0;
677 else
678 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
680 else
681 alSetError(AL_INVALID_VALUE);
682 break;
684 case AL_DIRECT_FILTER_GAINHF_AUTO:
685 if(lValue == AL_TRUE || lValue == AL_FALSE)
686 pSource->DryGainHFAuto = lValue;
687 else
688 alSetError(AL_INVALID_VALUE);
689 break;
691 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
692 if(lValue == AL_TRUE || lValue == AL_FALSE)
693 pSource->WetGainAuto = lValue;
694 else
695 alSetError(AL_INVALID_VALUE);
696 break;
698 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
699 if(lValue == AL_TRUE || lValue == AL_FALSE)
700 pSource->WetGainHFAuto = lValue;
701 else
702 alSetError(AL_INVALID_VALUE);
703 break;
705 default:
706 alSetError(AL_INVALID_ENUM);
707 break;
710 else
711 alSetError(AL_INVALID_NAME);
713 ProcessContext(pContext);
715 else
716 alSetError(AL_INVALID_OPERATION);
718 return;
722 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
724 ALCcontext *pContext;
726 pContext = alcGetCurrentContext();
727 if (pContext)
729 SuspendContext(pContext);
731 if (alIsSource(source))
733 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
735 switch (eParam)
737 case AL_POSITION:
738 case AL_VELOCITY:
739 case AL_DIRECTION:
740 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
741 break;
743 case AL_AUXILIARY_SEND_FILTER:
744 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
745 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
746 alIsFilter(lValue3))
748 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
749 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
751 /* Release refcount on the previous slot, and add one for
752 * the new slot */
753 if(pSource->Send[lValue2].Slot)
754 pSource->Send[lValue2].Slot->refcount--;
755 pSource->Send[lValue2].Slot = ALEffectSlot;
756 if(pSource->Send[lValue2].Slot)
757 pSource->Send[lValue2].Slot->refcount++;
759 if(!ALFilter)
761 /* Disable filter */
762 pSource->Send[lValue2].WetFilter.type = 0;
763 pSource->Send[lValue2].WetFilter.filter = 0;
765 else
766 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
768 else
769 alSetError(AL_INVALID_VALUE);
770 break;
772 default:
773 alSetError(AL_INVALID_ENUM);
774 break;
777 else
778 alSetError(AL_INVALID_NAME);
780 ProcessContext(pContext);
782 else
783 alSetError(AL_INVALID_OPERATION);
785 return;
789 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
791 ALCcontext *pContext;
793 pContext = alcGetCurrentContext();
794 if (pContext)
796 SuspendContext(pContext);
798 if (plValues)
800 if (alIsSource(source))
802 switch (eParam)
804 case AL_SOURCE_RELATIVE:
805 case AL_CONE_INNER_ANGLE:
806 case AL_CONE_OUTER_ANGLE:
807 case AL_LOOPING:
808 case AL_BUFFER:
809 case AL_SOURCE_STATE:
810 case AL_SEC_OFFSET:
811 case AL_SAMPLE_OFFSET:
812 case AL_BYTE_OFFSET:
813 case AL_MAX_DISTANCE:
814 case AL_ROLLOFF_FACTOR:
815 case AL_REFERENCE_DISTANCE:
816 case AL_DIRECT_FILTER:
817 case AL_DIRECT_FILTER_GAINHF_AUTO:
818 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
819 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
820 alSourcei(source, eParam, plValues[0]);
821 break;
823 case AL_POSITION:
824 case AL_VELOCITY:
825 case AL_DIRECTION:
826 case AL_AUXILIARY_SEND_FILTER:
827 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
828 break;
830 default:
831 alSetError(AL_INVALID_ENUM);
832 break;
835 else
836 alSetError(AL_INVALID_NAME);
838 else
839 alSetError(AL_INVALID_VALUE);
841 ProcessContext(pContext);
843 else
844 alSetError(AL_INVALID_OPERATION);
846 return;
850 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
852 ALCcontext *pContext;
853 ALsource *pSource;
854 ALfloat flOffset;
856 pContext = alcGetCurrentContext();
857 if (pContext)
859 SuspendContext(pContext);
861 if (pflValue)
863 if (alIsSource(source))
865 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
867 switch(eParam)
869 case AL_PITCH:
870 *pflValue = pSource->flPitch;
871 break;
873 case AL_GAIN:
874 *pflValue = pSource->flGain;
875 break;
877 case AL_MIN_GAIN:
878 *pflValue = pSource->flMinGain;
879 break;
881 case AL_MAX_GAIN:
882 *pflValue = pSource->flMaxGain;
883 break;
885 case AL_MAX_DISTANCE:
886 *pflValue = pSource->flMaxDistance;
887 break;
889 case AL_ROLLOFF_FACTOR:
890 *pflValue = pSource->flRollOffFactor;
891 break;
893 case AL_CONE_OUTER_GAIN:
894 *pflValue = pSource->flOuterGain;
895 break;
897 case AL_CONE_OUTER_GAINHF:
898 *pflValue = pSource->OuterGainHF;
899 break;
901 case AL_SEC_OFFSET:
902 case AL_SAMPLE_OFFSET:
903 case AL_BYTE_OFFSET:
904 if (GetSourceOffset(pSource, eParam, &flOffset))
905 *pflValue = flOffset;
906 else
907 alSetError(AL_INVALID_OPERATION);
908 break;
910 case AL_CONE_INNER_ANGLE:
911 *pflValue = pSource->flInnerAngle;
912 break;
914 case AL_CONE_OUTER_ANGLE:
915 *pflValue = pSource->flOuterAngle;
916 break;
918 case AL_REFERENCE_DISTANCE:
919 *pflValue = pSource->flRefDistance;
920 break;
922 case AL_AIR_ABSORPTION_FACTOR:
923 *pflValue = pSource->AirAbsorptionFactor;
924 break;
926 case AL_ROOM_ROLLOFF_FACTOR:
927 *pflValue = pSource->RoomRolloffFactor;
928 break;
930 default:
931 alSetError(AL_INVALID_ENUM);
932 break;
935 else
936 alSetError(AL_INVALID_NAME);
938 else
939 alSetError(AL_INVALID_VALUE);
941 ProcessContext(pContext);
943 else
944 alSetError(AL_INVALID_OPERATION);
946 return;
950 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
952 ALCcontext *pContext;
953 ALsource *pSource;
955 pContext = alcGetCurrentContext();
956 if (pContext)
958 SuspendContext(pContext);
960 if ((pflValue1) && (pflValue2) && (pflValue3))
962 if (alIsSource(source))
964 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
966 switch(eParam)
968 case AL_POSITION:
969 *pflValue1 = pSource->vPosition[0];
970 *pflValue2 = pSource->vPosition[1];
971 *pflValue3 = pSource->vPosition[2];
972 break;
974 case AL_VELOCITY:
975 *pflValue1 = pSource->vVelocity[0];
976 *pflValue2 = pSource->vVelocity[1];
977 *pflValue3 = pSource->vVelocity[2];
978 break;
980 case AL_DIRECTION:
981 *pflValue1 = pSource->vOrientation[0];
982 *pflValue2 = pSource->vOrientation[1];
983 *pflValue3 = pSource->vOrientation[2];
984 break;
986 default:
987 alSetError(AL_INVALID_ENUM);
988 break;
991 else
992 alSetError(AL_INVALID_NAME);
994 else
995 alSetError(AL_INVALID_VALUE);
997 ProcessContext(pContext);
999 else
1000 alSetError(AL_INVALID_OPERATION);
1002 return;
1006 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1008 ALCcontext *pContext;
1009 ALsource *pSource;
1011 pContext = alcGetCurrentContext();
1012 if (pContext)
1014 SuspendContext(pContext);
1016 if (pflValues)
1018 if (alIsSource(source))
1020 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1022 switch(eParam)
1024 case AL_PITCH:
1025 case AL_GAIN:
1026 case AL_MIN_GAIN:
1027 case AL_MAX_GAIN:
1028 case AL_MAX_DISTANCE:
1029 case AL_ROLLOFF_FACTOR:
1030 case AL_CONE_OUTER_GAIN:
1031 case AL_SEC_OFFSET:
1032 case AL_SAMPLE_OFFSET:
1033 case AL_BYTE_OFFSET:
1034 case AL_CONE_INNER_ANGLE:
1035 case AL_CONE_OUTER_ANGLE:
1036 case AL_REFERENCE_DISTANCE:
1037 case AL_CONE_OUTER_GAINHF:
1038 case AL_AIR_ABSORPTION_FACTOR:
1039 case AL_ROOM_ROLLOFF_FACTOR:
1040 alGetSourcef(source, eParam, pflValues);
1041 break;
1043 case AL_POSITION:
1044 pflValues[0] = pSource->vPosition[0];
1045 pflValues[1] = pSource->vPosition[1];
1046 pflValues[2] = pSource->vPosition[2];
1047 break;
1049 case AL_VELOCITY:
1050 pflValues[0] = pSource->vVelocity[0];
1051 pflValues[1] = pSource->vVelocity[1];
1052 pflValues[2] = pSource->vVelocity[2];
1053 break;
1055 case AL_DIRECTION:
1056 pflValues[0] = pSource->vOrientation[0];
1057 pflValues[1] = pSource->vOrientation[1];
1058 pflValues[2] = pSource->vOrientation[2];
1059 break;
1061 default:
1062 alSetError(AL_INVALID_ENUM);
1063 break;
1066 else
1067 alSetError(AL_INVALID_NAME);
1069 else
1070 alSetError(AL_INVALID_VALUE);
1072 ProcessContext(pContext);
1074 else
1075 alSetError(AL_INVALID_OPERATION);
1077 return;
1081 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1083 ALCcontext *pContext;
1084 ALsource *pSource;
1085 ALfloat flOffset;
1087 pContext = alcGetCurrentContext();
1088 if (pContext)
1090 SuspendContext(pContext);
1092 if (plValue)
1094 if (alIsSource(source))
1096 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1098 switch(eParam)
1100 case AL_MAX_DISTANCE:
1101 *plValue = (ALint)pSource->flMaxDistance;
1102 break;
1104 case AL_ROLLOFF_FACTOR:
1105 *plValue = (ALint)pSource->flRollOffFactor;
1106 break;
1108 case AL_REFERENCE_DISTANCE:
1109 *plValue = (ALint)pSource->flRefDistance;
1110 break;
1112 case AL_SOURCE_RELATIVE:
1113 *plValue = pSource->bHeadRelative;
1114 break;
1116 case AL_CONE_INNER_ANGLE:
1117 *plValue = (ALint)pSource->flInnerAngle;
1118 break;
1120 case AL_CONE_OUTER_ANGLE:
1121 *plValue = (ALint)pSource->flOuterAngle;
1122 break;
1124 case AL_LOOPING:
1125 *plValue = pSource->bLooping;
1126 break;
1128 case AL_BUFFER:
1129 *plValue = pSource->ulBufferID;
1130 break;
1132 case AL_SOURCE_STATE:
1133 *plValue = pSource->state;
1134 break;
1136 case AL_BUFFERS_QUEUED:
1137 *plValue = pSource->BuffersInQueue;
1138 break;
1140 case AL_BUFFERS_PROCESSED:
1141 if(pSource->bLooping)
1143 /* Buffers on a looping source are in a perpetual state
1144 * of PENDING, so don't report any as PROCESSED */
1145 *plValue = 0;
1147 else
1148 *plValue = pSource->BuffersProcessed;
1149 break;
1151 case AL_SOURCE_TYPE:
1152 *plValue = pSource->lSourceType;
1153 break;
1155 case AL_SEC_OFFSET:
1156 case AL_SAMPLE_OFFSET:
1157 case AL_BYTE_OFFSET:
1158 if (GetSourceOffset(pSource, eParam, &flOffset))
1159 *plValue = (ALint)flOffset;
1160 else
1161 alSetError(AL_INVALID_OPERATION);
1162 break;
1164 case AL_DIRECT_FILTER:
1165 *plValue = pSource->DirectFilter.filter;
1166 break;
1168 case AL_DIRECT_FILTER_GAINHF_AUTO:
1169 *plValue = pSource->DryGainHFAuto;
1170 break;
1172 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1173 *plValue = pSource->WetGainAuto;
1174 break;
1176 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1177 *plValue = pSource->WetGainHFAuto;
1178 break;
1180 default:
1181 alSetError(AL_INVALID_ENUM);
1182 break;
1185 else
1186 alSetError(AL_INVALID_NAME);
1188 else
1189 alSetError(AL_INVALID_VALUE);
1191 ProcessContext(pContext);
1193 else
1194 alSetError(AL_INVALID_OPERATION);
1196 return;
1200 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1202 ALCcontext *pContext;
1203 ALsource *pSource;
1205 pContext = alcGetCurrentContext();
1206 if (pContext)
1208 SuspendContext(pContext);
1210 if ((plValue1) && (plValue2) && (plValue3))
1212 if (alIsSource(source))
1214 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1216 switch(eParam)
1218 case AL_POSITION:
1219 *plValue1 = (ALint)pSource->vPosition[0];
1220 *plValue2 = (ALint)pSource->vPosition[1];
1221 *plValue3 = (ALint)pSource->vPosition[2];
1222 break;
1224 case AL_VELOCITY:
1225 *plValue1 = (ALint)pSource->vVelocity[0];
1226 *plValue2 = (ALint)pSource->vVelocity[1];
1227 *plValue3 = (ALint)pSource->vVelocity[2];
1228 break;
1230 case AL_DIRECTION:
1231 *plValue1 = (ALint)pSource->vOrientation[0];
1232 *plValue2 = (ALint)pSource->vOrientation[1];
1233 *plValue3 = (ALint)pSource->vOrientation[2];
1234 break;
1236 default:
1237 alSetError(AL_INVALID_ENUM);
1238 break;
1241 else
1242 alSetError(AL_INVALID_NAME);
1244 else
1245 alSetError(AL_INVALID_VALUE);
1247 ProcessContext(pContext);
1249 else
1250 alSetError(AL_INVALID_OPERATION);
1252 return;
1256 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1258 ALCcontext *pContext;
1259 ALsource *pSource;
1261 pContext = alcGetCurrentContext();
1262 if (pContext)
1264 SuspendContext(pContext);
1266 if (plValues)
1268 if (alIsSource(source))
1270 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1272 switch (eParam)
1274 case AL_SOURCE_RELATIVE:
1275 case AL_CONE_INNER_ANGLE:
1276 case AL_CONE_OUTER_ANGLE:
1277 case AL_LOOPING:
1278 case AL_BUFFER:
1279 case AL_SOURCE_STATE:
1280 case AL_BUFFERS_QUEUED:
1281 case AL_BUFFERS_PROCESSED:
1282 case AL_SEC_OFFSET:
1283 case AL_SAMPLE_OFFSET:
1284 case AL_BYTE_OFFSET:
1285 case AL_MAX_DISTANCE:
1286 case AL_ROLLOFF_FACTOR:
1287 case AL_REFERENCE_DISTANCE:
1288 case AL_SOURCE_TYPE:
1289 case AL_DIRECT_FILTER:
1290 case AL_DIRECT_FILTER_GAINHF_AUTO:
1291 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1292 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1293 alGetSourcei(source, eParam, plValues);
1294 break;
1296 case AL_POSITION:
1297 plValues[0] = (ALint)pSource->vPosition[0];
1298 plValues[1] = (ALint)pSource->vPosition[1];
1299 plValues[2] = (ALint)pSource->vPosition[2];
1300 break;
1302 case AL_VELOCITY:
1303 plValues[0] = (ALint)pSource->vVelocity[0];
1304 plValues[1] = (ALint)pSource->vVelocity[1];
1305 plValues[2] = (ALint)pSource->vVelocity[2];
1306 break;
1308 case AL_DIRECTION:
1309 plValues[0] = (ALint)pSource->vOrientation[0];
1310 plValues[1] = (ALint)pSource->vOrientation[1];
1311 plValues[2] = (ALint)pSource->vOrientation[2];
1312 break;
1314 default:
1315 alSetError(AL_INVALID_ENUM);
1316 break;
1319 else
1320 alSetError(AL_INVALID_NAME);
1322 else
1323 alSetError(AL_INVALID_VALUE);
1325 ProcessContext(pContext);
1327 else
1328 alSetError(AL_INVALID_OPERATION);
1330 return;
1334 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1336 alSourcePlayv(1, &source);
1337 return;
1340 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1342 ALCcontext *pContext;
1343 ALsource *pSource;
1344 ALbufferlistitem *ALBufferList;
1345 ALboolean bSourcesValid = AL_TRUE;
1346 ALboolean bPlay;
1347 ALsizei i;
1349 pContext = alcGetCurrentContext();
1350 if (pContext)
1352 SuspendContext(pContext);
1354 if (pSourceList)
1356 // Check that all the Sources are valid
1357 for (i = 0; i < n; i++)
1359 if (!alIsSource(pSourceList[i]))
1361 alSetError(AL_INVALID_NAME);
1362 bSourcesValid = AL_FALSE;
1363 break;
1367 if (bSourcesValid)
1369 for (i = 0; i < n; i++)
1371 // Assume Source won't need to play
1372 bPlay = AL_FALSE;
1374 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1376 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1377 ALBufferList = pSource->queue;
1378 while (ALBufferList)
1380 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1382 bPlay = AL_TRUE;
1383 break;
1385 ALBufferList = ALBufferList->next;
1388 if (bPlay)
1390 if (pSource->state != AL_PAUSED)
1392 pSource->state = AL_PLAYING;
1393 pSource->inuse = AL_TRUE;
1394 pSource->play = AL_TRUE;
1395 pSource->position = 0;
1396 pSource->position_fraction = 0;
1397 pSource->BuffersProcessed = 0;
1398 pSource->BuffersPlayed = 0;
1399 pSource->BufferPosition = 0;
1400 pSource->lBytesPlayed = 0;
1402 pSource->ulBufferID = pSource->queue->buffer;
1404 // Make sure all the Buffers in the queue are marked as PENDING
1405 ALBufferList = pSource->queue;
1406 while (ALBufferList)
1408 ALBufferList->bufferstate = PENDING;
1409 ALBufferList = ALBufferList->next;
1412 else
1414 pSource->state = AL_PLAYING;
1415 pSource->inuse = AL_TRUE;
1416 pSource->play = AL_TRUE;
1419 // Check if an Offset has been set
1420 if (pSource->lOffset)
1421 ApplyOffset(pSource, AL_FALSE);
1423 else
1425 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1426 ALBufferList = pSource->queue;
1427 while (ALBufferList)
1429 ALBufferList->bufferstate = PROCESSED;
1430 ALBufferList = ALBufferList->next;
1433 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1438 else
1440 // sources is a NULL pointer
1441 alSetError(AL_INVALID_VALUE);
1444 ProcessContext(pContext);
1446 else
1448 // Invalid Context
1449 alSetError(AL_INVALID_OPERATION);
1452 return;
1455 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1457 alSourcePausev(1, &source);
1458 return;
1461 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1463 ALCcontext *Context;
1464 ALsource *Source;
1465 ALsizei i;
1466 ALboolean bSourcesValid = AL_TRUE;
1468 Context=alcGetCurrentContext();
1469 if (Context)
1471 SuspendContext(Context);
1473 if (sources)
1475 // Check all the Sources are valid
1476 for (i=0;i<n;i++)
1478 if (!alIsSource(sources[i]))
1480 alSetError(AL_INVALID_NAME);
1481 bSourcesValid = AL_FALSE;
1482 break;
1486 if (bSourcesValid)
1488 for (i=0;i<n;i++)
1490 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1491 if (Source->state==AL_PLAYING)
1493 Source->state=AL_PAUSED;
1494 Source->inuse=AL_FALSE;
1499 else
1501 // sources is a NULL pointer
1502 alSetError(AL_INVALID_VALUE);
1505 ProcessContext(Context);
1507 else
1509 // Invalid Context
1510 alSetError(AL_INVALID_OPERATION);
1513 return;
1516 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1518 alSourceStopv(1, &source);
1519 return;
1522 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1524 ALCcontext *Context;
1525 ALsource *Source;
1526 ALsizei i;
1527 ALbufferlistitem *ALBufferListItem;
1528 ALboolean bSourcesValid = AL_TRUE;
1530 Context=alcGetCurrentContext();
1531 if (Context)
1533 SuspendContext(Context);
1535 if (sources)
1537 // Check all the Sources are valid
1538 for (i=0;i<n;i++)
1540 if (!alIsSource(sources[i]))
1542 alSetError(AL_INVALID_NAME);
1543 bSourcesValid = AL_FALSE;
1544 break;
1548 if (bSourcesValid)
1550 for (i=0;i<n;i++)
1552 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1553 if (Source->state!=AL_INITIAL)
1555 Source->state=AL_STOPPED;
1556 Source->inuse=AL_FALSE;
1557 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1558 ALBufferListItem= Source->queue;
1559 while (ALBufferListItem != NULL)
1561 ALBufferListItem->bufferstate = PROCESSED;
1562 ALBufferListItem = ALBufferListItem->next;
1565 Source->lOffset = 0;
1569 else
1571 // sources is a NULL pointer
1572 alSetError(AL_INVALID_VALUE);
1575 ProcessContext(Context);
1577 else
1579 // Invalid Context
1580 alSetError(AL_INVALID_OPERATION);
1583 return;
1586 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1588 alSourceRewindv(1, &source);
1589 return;
1592 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1594 ALCcontext *Context;
1595 ALsource *Source;
1596 ALsizei i;
1597 ALbufferlistitem *ALBufferListItem;
1598 ALboolean bSourcesValid = AL_TRUE;
1600 Context=alcGetCurrentContext();
1601 if (Context)
1603 SuspendContext(Context);
1605 if (sources)
1607 // Check all the Sources are valid
1608 for (i=0;i<n;i++)
1610 if (!alIsSource(sources[i]))
1612 alSetError(AL_INVALID_NAME);
1613 bSourcesValid = AL_FALSE;
1614 break;
1618 if (bSourcesValid)
1620 for (i=0;i<n;i++)
1622 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1623 if (Source->state!=AL_INITIAL)
1625 Source->state=AL_INITIAL;
1626 Source->inuse=AL_FALSE;
1627 Source->position=0;
1628 Source->position_fraction=0;
1629 Source->BuffersProcessed = 0;
1630 ALBufferListItem= Source->queue;
1631 while (ALBufferListItem != NULL)
1633 ALBufferListItem->bufferstate = PENDING;
1634 ALBufferListItem = ALBufferListItem->next;
1636 if (Source->queue)
1637 Source->ulBufferID = Source->queue->buffer;
1639 Source->lOffset = 0;
1643 else
1645 // sources is a NULL pointer
1646 alSetError(AL_INVALID_VALUE);
1649 ProcessContext(Context);
1651 else
1653 // Invalid Context
1654 alSetError(AL_INVALID_OPERATION);
1657 return;
1661 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1663 ALCcontext *Context;
1664 ALsource *ALSource;
1665 ALsizei i;
1666 ALbufferlistitem *ALBufferList;
1667 ALbufferlistitem *ALBufferListStart;
1668 ALuint DataSize;
1669 ALuint BufferSize;
1670 ALint iFrequency;
1671 ALint iFormat;
1672 ALboolean bBuffersValid = AL_TRUE;
1674 if (n == 0)
1675 return;
1677 Context=alcGetCurrentContext();
1678 if (Context)
1680 SuspendContext(Context);
1682 DataSize = 0;
1683 BufferSize = 0;
1685 // Check that all buffers are valid or zero and that the source is valid
1687 // Check that this is a valid source
1688 if (alIsSource(source))
1690 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1692 // Check that this is not a STATIC Source
1693 if (ALSource->lSourceType != AL_STATIC)
1695 iFrequency = -1;
1696 iFormat = -1;
1698 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1699 ALBufferList = ALSource->queue;
1700 while (ALBufferList)
1702 if (ALBufferList->buffer)
1704 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1705 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1706 break;
1708 ALBufferList = ALBufferList->next;
1711 for (i = 0; i < n; i++)
1713 if (alIsBuffer(buffers[i]))
1715 if (buffers[i])
1717 if ((iFrequency == -1) && (iFormat == -1))
1719 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1720 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1722 else
1724 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1725 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1727 alSetError(AL_INVALID_OPERATION);
1728 bBuffersValid = AL_FALSE;
1729 break;
1734 else
1736 alSetError(AL_INVALID_NAME);
1737 bBuffersValid = AL_FALSE;
1738 break;
1742 if (bBuffersValid)
1744 // Change Source Type
1745 ALSource->lSourceType = AL_STREAMING;
1747 // All buffers are valid - so add them to the list
1748 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1749 ALBufferListStart->buffer = buffers[0];
1750 ALBufferListStart->bufferstate = PENDING;
1751 ALBufferListStart->flag = 0;
1752 ALBufferListStart->next = NULL;
1754 if (buffers[0])
1755 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1756 else
1757 BufferSize = 0;
1759 DataSize += BufferSize;
1761 // Increment reference counter for buffer
1762 if (buffers[0])
1763 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1765 ALBufferList = ALBufferListStart;
1767 for (i = 1; i < n; i++)
1769 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1770 ALBufferList->next->buffer = buffers[i];
1771 ALBufferList->next->bufferstate = PENDING;
1772 ALBufferList->next->flag = 0;
1773 ALBufferList->next->next = NULL;
1775 if (buffers[i])
1776 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1777 else
1778 BufferSize = 0;
1780 DataSize += BufferSize;
1782 // Increment reference counter for buffer
1783 if (buffers[i])
1784 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1786 ALBufferList = ALBufferList->next;
1789 if (ALSource->queue == NULL)
1791 ALSource->queue = ALBufferListStart;
1792 // Update Current Buffer
1793 ALSource->ulBufferID = ALBufferListStart->buffer;
1795 else
1797 // Find end of queue
1798 ALBufferList = ALSource->queue;
1799 while (ALBufferList->next != NULL)
1801 ALBufferList = ALBufferList->next;
1804 ALBufferList->next = ALBufferListStart;
1807 // Update number of buffers in queue
1808 ALSource->BuffersInQueue += n;
1811 else
1813 // Invalid Source Type (can't queue on a Static Source)
1814 alSetError(AL_INVALID_OPERATION);
1817 else
1819 // Invalid Source Name
1820 alSetError(AL_INVALID_NAME);
1823 ProcessContext(Context);
1825 else
1827 // Invalid Context
1828 alSetError(AL_INVALID_OPERATION);
1831 return;
1835 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1836 // an array of buffer IDs that are to be filled with the names of the buffers removed
1837 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1839 ALCcontext *Context;
1840 ALsource *ALSource;
1841 ALsizei i;
1842 ALbufferlistitem *ALBufferList;
1843 ALuint DataSize;
1844 ALuint BufferSize;
1845 ALuint BufferID;
1846 ALboolean bBuffersProcessed;
1848 if (n == 0)
1849 return;
1851 DataSize = 0;
1852 BufferSize = 0;
1853 bBuffersProcessed = AL_TRUE;
1855 Context=alcGetCurrentContext();
1856 if (Context)
1858 SuspendContext(Context);
1860 if (alIsSource(source))
1862 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1864 // Check that all 'n' buffers have been processed
1865 ALBufferList = ALSource->queue;
1866 for (i = 0; i < n; i++)
1868 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1870 ALBufferList = ALBufferList->next;
1872 else
1874 bBuffersProcessed = AL_FALSE;
1875 break;
1879 // If all 'n' buffers have been processed, remove them from the queue
1880 if (bBuffersProcessed)
1882 for (i = 0; i < n; i++)
1884 ALBufferList = ALSource->queue;
1886 ALSource->queue = ALBufferList->next;
1887 // Record name of buffer
1888 buffers[i] = ALBufferList->buffer;
1889 // Decrement buffer reference counter
1890 if (ALBufferList->buffer)
1891 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1892 // Record size of buffer
1893 if (ALBufferList->buffer)
1894 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1895 else
1896 BufferSize = 0;
1898 DataSize += BufferSize;
1899 // Release memory for buffer list item
1900 free(ALBufferList);
1901 ALSource->BuffersInQueue--;
1902 ALSource->BuffersProcessed--;
1905 if (ALSource->state != AL_PLAYING)
1907 if (ALSource->queue)
1908 BufferID = ALSource->queue->buffer;
1909 else
1910 BufferID = 0;
1912 ALSource->ulBufferID = BufferID;
1915 if((ALuint)n > ALSource->BuffersPlayed)
1917 ALSource->BuffersPlayed = 0;
1918 ALSource->BufferPosition = 0;
1920 else
1921 ALSource->BuffersPlayed -= n;
1923 else
1925 // Some buffers can't be unqueue because they have not been processed
1926 alSetError(AL_INVALID_VALUE);
1929 else
1931 // Invalid Source Name
1932 alSetError(AL_INVALID_NAME);
1935 ProcessContext(Context);
1937 else
1939 // Invalid Context
1940 alSetError(AL_INVALID_OPERATION);
1943 return;
1947 static ALvoid InitSourceParams(ALsource *pSource)
1949 pSource->flInnerAngle = 360.0f;
1950 pSource->flOuterAngle = 360.0f;
1951 pSource->flPitch = 1.0f;
1952 pSource->vPosition[0] = 0.0f;
1953 pSource->vPosition[1] = 0.0f;
1954 pSource->vPosition[2] = 0.0f;
1955 pSource->vOrientation[0] = 0.0f;
1956 pSource->vOrientation[1] = 0.0f;
1957 pSource->vOrientation[2] = 0.0f;
1958 pSource->vVelocity[0] = 0.0f;
1959 pSource->vVelocity[1] = 0.0f;
1960 pSource->vVelocity[2] = 0.0f;
1961 pSource->flRefDistance = 1.0f;
1962 pSource->flMaxDistance = FLT_MAX;
1963 pSource->flRollOffFactor = 1.0f;
1964 pSource->bLooping = AL_FALSE;
1965 pSource->flGain = 1.0f;
1966 pSource->flMinGain = 0.0f;
1967 pSource->flMaxGain = 1.0f;
1968 pSource->flOuterGain = 0.0f;
1969 pSource->OuterGainHF = 1.0f;
1971 pSource->DryGainHFAuto = AL_TRUE;
1972 pSource->WetGainAuto = AL_TRUE;
1973 pSource->WetGainHFAuto = AL_TRUE;
1974 pSource->AirAbsorptionFactor = 0.0f;
1975 pSource->RoomRolloffFactor = 0.0f;
1977 pSource->state = AL_INITIAL;
1978 pSource->lSourceType = AL_UNDETERMINED;
1980 pSource->ulBufferID= 0;
1985 GetSourceOffset
1987 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1988 The offset is relative to the start of the queue (not the start of the current buffer)
1990 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1992 ALbufferlistitem *pBufferList;
1993 ALbuffer *pBuffer;
1994 ALfloat flBufferFreq;
1995 ALint lBytesPlayed, lChannels;
1996 ALenum eOriginalFormat;
1997 ALboolean bReturn = AL_TRUE;
1998 ALint lTotalBufferDataSize;
2000 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2002 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2003 // Get Current Buffer Size and frequency (in milliseconds)
2004 flBufferFreq = (ALfloat)pBuffer->frequency;
2005 eOriginalFormat = pBuffer->eOriginalFormat;
2006 lChannels = aluChannelsFromFormat(pBuffer->format);
2008 // Get Current BytesPlayed
2009 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2010 // Add byte length of any processed buffers in the queue
2011 pBufferList = pSource->queue;
2012 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2014 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2015 pBufferList = pBufferList->next;
2018 lTotalBufferDataSize = 0;
2019 pBufferList = pSource->queue;
2020 while (pBufferList)
2022 if (pBufferList->buffer)
2023 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2024 pBufferList = pBufferList->next;
2027 if (pSource->bLooping)
2029 if (lBytesPlayed < 0)
2030 lBytesPlayed = 0;
2031 else
2032 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2034 else
2036 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2037 if(lBytesPlayed < 0)
2038 lBytesPlayed = 0;
2039 if(lBytesPlayed > lTotalBufferDataSize)
2040 lBytesPlayed = lTotalBufferDataSize;
2043 switch (eName)
2045 case AL_SEC_OFFSET:
2046 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2047 break;
2048 case AL_SAMPLE_OFFSET:
2049 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2050 break;
2051 case AL_BYTE_OFFSET:
2052 // Take into account the original format of the Buffer
2053 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2054 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2056 // Compression rate of the ADPCM supported is 3.6111 to 1
2057 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2058 // Round down to nearest ADPCM block
2059 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2061 else if (eOriginalFormat == AL_FORMAT_REAR8)
2063 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2065 else if (eOriginalFormat == AL_FORMAT_REAR16)
2067 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2069 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2071 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2073 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2075 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2077 else
2079 *pflOffset = (ALfloat)lBytesPlayed;
2081 break;
2084 else
2086 *pflOffset = 0.0f;
2089 return bReturn;
2094 ApplyOffset
2096 Apply a playback offset to the Source. This function will update the queue (to correctly
2097 mark buffers as 'pending' or 'processed' depending upon the new offset.
2099 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2101 ALbufferlistitem *pBufferList;
2102 ALbuffer *pBuffer;
2103 ALint lBufferSize, lTotalBufferSize;
2104 ALint lByteOffset;
2106 // Get true byte offset
2107 lByteOffset = GetByteOffset(pSource);
2109 // If this is a valid offset apply it
2110 if (lByteOffset != -1)
2112 // Sort out the queue (pending and processed states)
2113 pBufferList = pSource->queue;
2114 lTotalBufferSize = 0;
2115 pSource->BuffersPlayed = 0;
2116 pSource->BuffersProcessed = 0;
2117 while (pBufferList)
2119 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2120 lBufferSize = pBuffer ? pBuffer->size : 0;
2122 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2124 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2125 // update the state to PROCESSED
2126 pSource->BuffersPlayed++;
2128 if (!pSource->bLooping)
2130 pBufferList->bufferstate = PROCESSED;
2131 pSource->BuffersProcessed++;
2134 else if (lTotalBufferSize <= lByteOffset)
2136 // Offset is within this buffer
2137 pBufferList->bufferstate = PENDING;
2139 // Set Current Buffer ID
2140 pSource->ulBufferID = pBufferList->buffer;
2142 // Set current position in this buffer
2143 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2145 // Set Total Bytes Played to Offset
2146 pSource->lBytesPlayed = lByteOffset;
2148 // SW Mixer Positions are in Samples
2149 pSource->position = pSource->BufferPosition /
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("destroycontext: %d Source(s) NOT deleted\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 memset(temp, 0, sizeof(ALsource));
2294 free(temp);
2296 Context->SourceCount = 0;