Reduce the default buffer size to 4096
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blobd7095f0fef4d6efdd78d68ad24f63702c9dec88e
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 InitLowPassFilter(Context, &(*list)->iirFilter);
80 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
81 (*list)->source = sources[i];
83 InitSourceParams(*list);
84 Context->SourceCount++;
85 i++;
87 list = &(*list)->next;
90 else
92 // Not enough resources to create the Sources
93 alSetError(AL_INVALID_VALUE);
96 else
98 // Bad pointer
99 alSetError(AL_INVALID_VALUE);
102 else
104 // No Device created, or attached to Context
105 alSetError(AL_INVALID_OPERATION);
109 ProcessContext(Context);
111 else
113 // Invalid Context
114 alSetError(AL_INVALID_OPERATION);
117 return;
121 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
123 ALCcontext *Context;
124 ALCdevice *Device;
125 ALsource *ALSource;
126 ALsource **list;
127 ALsizei i, j;
128 ALbufferlistitem *ALBufferList;
129 ALboolean bSourcesValid = AL_TRUE;
131 Context = alcGetCurrentContext();
132 if (Context)
134 SuspendContext(Context);
136 if (n >= 0)
138 Device = alcGetContextsDevice(Context);
140 if (Device)
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 for(j = 0;j < MAX_SENDS;++j)
179 if(ALSource->Send[j].Slot)
180 ALSource->Send[j].Slot->refcount--;
181 ALSource->Send[j].Slot = NULL;
184 // Decrement Source count
185 Context->SourceCount--;
187 // Remove Source from list of Sources
188 list = &Context->Source;
189 while(*list && *list != ALSource)
190 list = &(*list)->next;
192 if(*list)
193 *list = (*list)->next;
194 ALTHUNK_REMOVEENTRY(ALSource->source);
196 memset(ALSource,0,sizeof(ALsource));
197 free(ALSource);
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 case AL_DOPPLER_FACTOR:
931 *pflValue = pSource->DopplerFactor;
932 break;
934 default:
935 alSetError(AL_INVALID_ENUM);
936 break;
939 else
940 alSetError(AL_INVALID_NAME);
942 else
943 alSetError(AL_INVALID_VALUE);
945 ProcessContext(pContext);
947 else
948 alSetError(AL_INVALID_OPERATION);
950 return;
954 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
956 ALCcontext *pContext;
957 ALsource *pSource;
959 pContext = alcGetCurrentContext();
960 if (pContext)
962 SuspendContext(pContext);
964 if ((pflValue1) && (pflValue2) && (pflValue3))
966 if (alIsSource(source))
968 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
970 switch(eParam)
972 case AL_POSITION:
973 *pflValue1 = pSource->vPosition[0];
974 *pflValue2 = pSource->vPosition[1];
975 *pflValue3 = pSource->vPosition[2];
976 break;
978 case AL_VELOCITY:
979 *pflValue1 = pSource->vVelocity[0];
980 *pflValue2 = pSource->vVelocity[1];
981 *pflValue3 = pSource->vVelocity[2];
982 break;
984 case AL_DIRECTION:
985 *pflValue1 = pSource->vOrientation[0];
986 *pflValue2 = pSource->vOrientation[1];
987 *pflValue3 = pSource->vOrientation[2];
988 break;
990 default:
991 alSetError(AL_INVALID_ENUM);
992 break;
995 else
996 alSetError(AL_INVALID_NAME);
998 else
999 alSetError(AL_INVALID_VALUE);
1001 ProcessContext(pContext);
1003 else
1004 alSetError(AL_INVALID_OPERATION);
1006 return;
1010 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1012 ALCcontext *pContext;
1013 ALsource *pSource;
1015 pContext = alcGetCurrentContext();
1016 if (pContext)
1018 SuspendContext(pContext);
1020 if (pflValues)
1022 if (alIsSource(source))
1024 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1026 switch(eParam)
1028 case AL_PITCH:
1029 case AL_GAIN:
1030 case AL_MIN_GAIN:
1031 case AL_MAX_GAIN:
1032 case AL_MAX_DISTANCE:
1033 case AL_ROLLOFF_FACTOR:
1034 case AL_DOPPLER_FACTOR:
1035 case AL_CONE_OUTER_GAIN:
1036 case AL_SEC_OFFSET:
1037 case AL_SAMPLE_OFFSET:
1038 case AL_BYTE_OFFSET:
1039 case AL_CONE_INNER_ANGLE:
1040 case AL_CONE_OUTER_ANGLE:
1041 case AL_REFERENCE_DISTANCE:
1042 case AL_CONE_OUTER_GAINHF:
1043 case AL_AIR_ABSORPTION_FACTOR:
1044 case AL_ROOM_ROLLOFF_FACTOR:
1045 alGetSourcef(source, eParam, pflValues);
1046 break;
1048 case AL_POSITION:
1049 pflValues[0] = pSource->vPosition[0];
1050 pflValues[1] = pSource->vPosition[1];
1051 pflValues[2] = pSource->vPosition[2];
1052 break;
1054 case AL_VELOCITY:
1055 pflValues[0] = pSource->vVelocity[0];
1056 pflValues[1] = pSource->vVelocity[1];
1057 pflValues[2] = pSource->vVelocity[2];
1058 break;
1060 case AL_DIRECTION:
1061 pflValues[0] = pSource->vOrientation[0];
1062 pflValues[1] = pSource->vOrientation[1];
1063 pflValues[2] = pSource->vOrientation[2];
1064 break;
1066 default:
1067 alSetError(AL_INVALID_ENUM);
1068 break;
1071 else
1072 alSetError(AL_INVALID_NAME);
1074 else
1075 alSetError(AL_INVALID_VALUE);
1077 ProcessContext(pContext);
1079 else
1080 alSetError(AL_INVALID_OPERATION);
1082 return;
1086 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1088 ALCcontext *pContext;
1089 ALsource *pSource;
1090 ALfloat flOffset;
1092 pContext = alcGetCurrentContext();
1093 if (pContext)
1095 SuspendContext(pContext);
1097 if (plValue)
1099 if (alIsSource(source))
1101 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1103 switch(eParam)
1105 case AL_MAX_DISTANCE:
1106 *plValue = (ALint)pSource->flMaxDistance;
1107 break;
1109 case AL_ROLLOFF_FACTOR:
1110 *plValue = (ALint)pSource->flRollOffFactor;
1111 break;
1113 case AL_REFERENCE_DISTANCE:
1114 *plValue = (ALint)pSource->flRefDistance;
1115 break;
1117 case AL_SOURCE_RELATIVE:
1118 *plValue = pSource->bHeadRelative;
1119 break;
1121 case AL_CONE_INNER_ANGLE:
1122 *plValue = (ALint)pSource->flInnerAngle;
1123 break;
1125 case AL_CONE_OUTER_ANGLE:
1126 *plValue = (ALint)pSource->flOuterAngle;
1127 break;
1129 case AL_LOOPING:
1130 *plValue = pSource->bLooping;
1131 break;
1133 case AL_BUFFER:
1134 *plValue = pSource->ulBufferID;
1135 break;
1137 case AL_SOURCE_STATE:
1138 *plValue = pSource->state;
1139 break;
1141 case AL_BUFFERS_QUEUED:
1142 *plValue = pSource->BuffersInQueue;
1143 break;
1145 case AL_BUFFERS_PROCESSED:
1146 if(pSource->bLooping)
1148 /* Buffers on a looping source are in a perpetual state
1149 * of PENDING, so don't report any as PROCESSED */
1150 *plValue = 0;
1152 else
1153 *plValue = pSource->BuffersProcessed;
1154 break;
1156 case AL_SOURCE_TYPE:
1157 *plValue = pSource->lSourceType;
1158 break;
1160 case AL_SEC_OFFSET:
1161 case AL_SAMPLE_OFFSET:
1162 case AL_BYTE_OFFSET:
1163 if (GetSourceOffset(pSource, eParam, &flOffset))
1164 *plValue = (ALint)flOffset;
1165 else
1166 alSetError(AL_INVALID_OPERATION);
1167 break;
1169 case AL_DIRECT_FILTER:
1170 *plValue = pSource->DirectFilter.filter;
1171 break;
1173 case AL_DIRECT_FILTER_GAINHF_AUTO:
1174 *plValue = pSource->DryGainHFAuto;
1175 break;
1177 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1178 *plValue = pSource->WetGainAuto;
1179 break;
1181 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1182 *plValue = pSource->WetGainHFAuto;
1183 break;
1185 case AL_DOPPLER_FACTOR:
1186 *plValue = (ALint)pSource->DopplerFactor;
1187 break;
1189 default:
1190 alSetError(AL_INVALID_ENUM);
1191 break;
1194 else
1195 alSetError(AL_INVALID_NAME);
1197 else
1198 alSetError(AL_INVALID_VALUE);
1200 ProcessContext(pContext);
1202 else
1203 alSetError(AL_INVALID_OPERATION);
1205 return;
1209 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1211 ALCcontext *pContext;
1212 ALsource *pSource;
1214 pContext = alcGetCurrentContext();
1215 if (pContext)
1217 SuspendContext(pContext);
1219 if ((plValue1) && (plValue2) && (plValue3))
1221 if (alIsSource(source))
1223 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1225 switch(eParam)
1227 case AL_POSITION:
1228 *plValue1 = (ALint)pSource->vPosition[0];
1229 *plValue2 = (ALint)pSource->vPosition[1];
1230 *plValue3 = (ALint)pSource->vPosition[2];
1231 break;
1233 case AL_VELOCITY:
1234 *plValue1 = (ALint)pSource->vVelocity[0];
1235 *plValue2 = (ALint)pSource->vVelocity[1];
1236 *plValue3 = (ALint)pSource->vVelocity[2];
1237 break;
1239 case AL_DIRECTION:
1240 *plValue1 = (ALint)pSource->vOrientation[0];
1241 *plValue2 = (ALint)pSource->vOrientation[1];
1242 *plValue3 = (ALint)pSource->vOrientation[2];
1243 break;
1245 default:
1246 alSetError(AL_INVALID_ENUM);
1247 break;
1250 else
1251 alSetError(AL_INVALID_NAME);
1253 else
1254 alSetError(AL_INVALID_VALUE);
1256 ProcessContext(pContext);
1258 else
1259 alSetError(AL_INVALID_OPERATION);
1261 return;
1265 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1267 ALCcontext *pContext;
1268 ALsource *pSource;
1270 pContext = alcGetCurrentContext();
1271 if (pContext)
1273 SuspendContext(pContext);
1275 if (plValues)
1277 if (alIsSource(source))
1279 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1281 switch (eParam)
1283 case AL_SOURCE_RELATIVE:
1284 case AL_CONE_INNER_ANGLE:
1285 case AL_CONE_OUTER_ANGLE:
1286 case AL_LOOPING:
1287 case AL_BUFFER:
1288 case AL_SOURCE_STATE:
1289 case AL_BUFFERS_QUEUED:
1290 case AL_BUFFERS_PROCESSED:
1291 case AL_SEC_OFFSET:
1292 case AL_SAMPLE_OFFSET:
1293 case AL_BYTE_OFFSET:
1294 case AL_MAX_DISTANCE:
1295 case AL_ROLLOFF_FACTOR:
1296 case AL_DOPPLER_FACTOR:
1297 case AL_REFERENCE_DISTANCE:
1298 case AL_SOURCE_TYPE:
1299 case AL_DIRECT_FILTER:
1300 case AL_DIRECT_FILTER_GAINHF_AUTO:
1301 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1302 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1303 alGetSourcei(source, eParam, plValues);
1304 break;
1306 case AL_POSITION:
1307 plValues[0] = (ALint)pSource->vPosition[0];
1308 plValues[1] = (ALint)pSource->vPosition[1];
1309 plValues[2] = (ALint)pSource->vPosition[2];
1310 break;
1312 case AL_VELOCITY:
1313 plValues[0] = (ALint)pSource->vVelocity[0];
1314 plValues[1] = (ALint)pSource->vVelocity[1];
1315 plValues[2] = (ALint)pSource->vVelocity[2];
1316 break;
1318 case AL_DIRECTION:
1319 plValues[0] = (ALint)pSource->vOrientation[0];
1320 plValues[1] = (ALint)pSource->vOrientation[1];
1321 plValues[2] = (ALint)pSource->vOrientation[2];
1322 break;
1324 default:
1325 alSetError(AL_INVALID_ENUM);
1326 break;
1329 else
1330 alSetError(AL_INVALID_NAME);
1332 else
1333 alSetError(AL_INVALID_VALUE);
1335 ProcessContext(pContext);
1337 else
1338 alSetError(AL_INVALID_OPERATION);
1340 return;
1344 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1346 alSourcePlayv(1, &source);
1347 return;
1350 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1352 ALCcontext *pContext;
1353 ALsource *pSource;
1354 ALbufferlistitem *ALBufferList;
1355 ALboolean bSourcesValid = AL_TRUE;
1356 ALboolean bPlay;
1357 ALsizei i;
1359 pContext = alcGetCurrentContext();
1360 if (pContext)
1362 SuspendContext(pContext);
1364 if (pSourceList)
1366 // Check that all the Sources are valid
1367 for (i = 0; i < n; i++)
1369 if (!alIsSource(pSourceList[i]))
1371 alSetError(AL_INVALID_NAME);
1372 bSourcesValid = AL_FALSE;
1373 break;
1377 if (bSourcesValid)
1379 for (i = 0; i < n; i++)
1381 // Assume Source won't need to play
1382 bPlay = AL_FALSE;
1384 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1386 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1387 ALBufferList = pSource->queue;
1388 while (ALBufferList)
1390 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1392 bPlay = AL_TRUE;
1393 break;
1395 ALBufferList = ALBufferList->next;
1398 if (bPlay)
1400 if (pSource->state != AL_PAUSED)
1402 pSource->state = AL_PLAYING;
1403 pSource->inuse = AL_TRUE;
1404 pSource->play = AL_TRUE;
1405 pSource->position = 0;
1406 pSource->position_fraction = 0;
1407 pSource->BuffersProcessed = 0;
1408 pSource->BuffersPlayed = 0;
1409 pSource->BufferPosition = 0;
1410 pSource->lBytesPlayed = 0;
1412 pSource->ulBufferID = pSource->queue->buffer;
1414 // Make sure all the Buffers in the queue are marked as PENDING
1415 ALBufferList = pSource->queue;
1416 while (ALBufferList)
1418 ALBufferList->bufferstate = PENDING;
1419 ALBufferList = ALBufferList->next;
1422 else
1424 pSource->state = AL_PLAYING;
1425 pSource->inuse = AL_TRUE;
1426 pSource->play = AL_TRUE;
1429 // Check if an Offset has been set
1430 if (pSource->lOffset)
1431 ApplyOffset(pSource, AL_FALSE);
1433 else
1435 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1436 ALBufferList = pSource->queue;
1437 while (ALBufferList)
1439 ALBufferList->bufferstate = PROCESSED;
1440 ALBufferList = ALBufferList->next;
1443 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1448 else
1450 // sources is a NULL pointer
1451 alSetError(AL_INVALID_VALUE);
1454 ProcessContext(pContext);
1456 else
1458 // Invalid Context
1459 alSetError(AL_INVALID_OPERATION);
1462 return;
1465 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1467 alSourcePausev(1, &source);
1468 return;
1471 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1473 ALCcontext *Context;
1474 ALsource *Source;
1475 ALsizei i;
1476 ALboolean bSourcesValid = AL_TRUE;
1478 Context=alcGetCurrentContext();
1479 if (Context)
1481 SuspendContext(Context);
1483 if (sources)
1485 // Check all the Sources are valid
1486 for (i=0;i<n;i++)
1488 if (!alIsSource(sources[i]))
1490 alSetError(AL_INVALID_NAME);
1491 bSourcesValid = AL_FALSE;
1492 break;
1496 if (bSourcesValid)
1498 for (i=0;i<n;i++)
1500 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1501 if (Source->state==AL_PLAYING)
1503 Source->state=AL_PAUSED;
1504 Source->inuse=AL_FALSE;
1509 else
1511 // sources is a NULL pointer
1512 alSetError(AL_INVALID_VALUE);
1515 ProcessContext(Context);
1517 else
1519 // Invalid Context
1520 alSetError(AL_INVALID_OPERATION);
1523 return;
1526 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1528 alSourceStopv(1, &source);
1529 return;
1532 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1534 ALCcontext *Context;
1535 ALsource *Source;
1536 ALsizei i;
1537 ALbufferlistitem *ALBufferListItem;
1538 ALboolean bSourcesValid = AL_TRUE;
1540 Context=alcGetCurrentContext();
1541 if (Context)
1543 SuspendContext(Context);
1545 if (sources)
1547 // Check all the Sources are valid
1548 for (i=0;i<n;i++)
1550 if (!alIsSource(sources[i]))
1552 alSetError(AL_INVALID_NAME);
1553 bSourcesValid = AL_FALSE;
1554 break;
1558 if (bSourcesValid)
1560 for (i=0;i<n;i++)
1562 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1563 if (Source->state!=AL_INITIAL)
1565 Source->state=AL_STOPPED;
1566 Source->inuse=AL_FALSE;
1567 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1568 ALBufferListItem= Source->queue;
1569 while (ALBufferListItem != NULL)
1571 ALBufferListItem->bufferstate = PROCESSED;
1572 ALBufferListItem = ALBufferListItem->next;
1575 Source->lOffset = 0;
1579 else
1581 // sources is a NULL pointer
1582 alSetError(AL_INVALID_VALUE);
1585 ProcessContext(Context);
1587 else
1589 // Invalid Context
1590 alSetError(AL_INVALID_OPERATION);
1593 return;
1596 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1598 alSourceRewindv(1, &source);
1599 return;
1602 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1604 ALCcontext *Context;
1605 ALsource *Source;
1606 ALsizei i;
1607 ALbufferlistitem *ALBufferListItem;
1608 ALboolean bSourcesValid = AL_TRUE;
1610 Context=alcGetCurrentContext();
1611 if (Context)
1613 SuspendContext(Context);
1615 if (sources)
1617 // Check all the Sources are valid
1618 for (i=0;i<n;i++)
1620 if (!alIsSource(sources[i]))
1622 alSetError(AL_INVALID_NAME);
1623 bSourcesValid = AL_FALSE;
1624 break;
1628 if (bSourcesValid)
1630 for (i=0;i<n;i++)
1632 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1633 if (Source->state!=AL_INITIAL)
1635 Source->state=AL_INITIAL;
1636 Source->inuse=AL_FALSE;
1637 Source->position=0;
1638 Source->position_fraction=0;
1639 Source->BuffersProcessed = 0;
1640 ALBufferListItem= Source->queue;
1641 while (ALBufferListItem != NULL)
1643 ALBufferListItem->bufferstate = PENDING;
1644 ALBufferListItem = ALBufferListItem->next;
1646 if (Source->queue)
1647 Source->ulBufferID = Source->queue->buffer;
1649 Source->lOffset = 0;
1653 else
1655 // sources is a NULL pointer
1656 alSetError(AL_INVALID_VALUE);
1659 ProcessContext(Context);
1661 else
1663 // Invalid Context
1664 alSetError(AL_INVALID_OPERATION);
1667 return;
1671 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1673 ALCcontext *Context;
1674 ALsource *ALSource;
1675 ALsizei i;
1676 ALbufferlistitem *ALBufferList;
1677 ALbufferlistitem *ALBufferListStart;
1678 ALuint DataSize;
1679 ALuint BufferSize;
1680 ALint iFrequency;
1681 ALint iFormat;
1682 ALboolean bBuffersValid = AL_TRUE;
1684 if (n == 0)
1685 return;
1687 Context=alcGetCurrentContext();
1688 if (Context)
1690 SuspendContext(Context);
1692 DataSize = 0;
1693 BufferSize = 0;
1695 // Check that all buffers are valid or zero and that the source is valid
1697 // Check that this is a valid source
1698 if (alIsSource(source))
1700 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1702 // Check that this is not a STATIC Source
1703 if (ALSource->lSourceType != AL_STATIC)
1705 iFrequency = -1;
1706 iFormat = -1;
1708 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1709 ALBufferList = ALSource->queue;
1710 while (ALBufferList)
1712 if (ALBufferList->buffer)
1714 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1715 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1716 break;
1718 ALBufferList = ALBufferList->next;
1721 for (i = 0; i < n; i++)
1723 if (alIsBuffer(buffers[i]))
1725 if (buffers[i])
1727 if ((iFrequency == -1) && (iFormat == -1))
1729 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1730 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1732 else
1734 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1735 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1737 alSetError(AL_INVALID_OPERATION);
1738 bBuffersValid = AL_FALSE;
1739 break;
1744 else
1746 alSetError(AL_INVALID_NAME);
1747 bBuffersValid = AL_FALSE;
1748 break;
1752 if (bBuffersValid)
1754 // Change Source Type
1755 ALSource->lSourceType = AL_STREAMING;
1757 // All buffers are valid - so add them to the list
1758 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1759 ALBufferListStart->buffer = buffers[0];
1760 ALBufferListStart->bufferstate = PENDING;
1761 ALBufferListStart->flag = 0;
1762 ALBufferListStart->next = NULL;
1764 if (buffers[0])
1765 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1766 else
1767 BufferSize = 0;
1769 DataSize += BufferSize;
1771 // Increment reference counter for buffer
1772 if (buffers[0])
1773 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1775 ALBufferList = ALBufferListStart;
1777 for (i = 1; i < n; i++)
1779 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1780 ALBufferList->next->buffer = buffers[i];
1781 ALBufferList->next->bufferstate = PENDING;
1782 ALBufferList->next->flag = 0;
1783 ALBufferList->next->next = NULL;
1785 if (buffers[i])
1786 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1787 else
1788 BufferSize = 0;
1790 DataSize += BufferSize;
1792 // Increment reference counter for buffer
1793 if (buffers[i])
1794 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1796 ALBufferList = ALBufferList->next;
1799 if (ALSource->queue == NULL)
1801 ALSource->queue = ALBufferListStart;
1802 // Update Current Buffer
1803 ALSource->ulBufferID = ALBufferListStart->buffer;
1805 else
1807 // Find end of queue
1808 ALBufferList = ALSource->queue;
1809 while (ALBufferList->next != NULL)
1811 ALBufferList = ALBufferList->next;
1814 ALBufferList->next = ALBufferListStart;
1817 // Update number of buffers in queue
1818 ALSource->BuffersInQueue += n;
1821 else
1823 // Invalid Source Type (can't queue on a Static Source)
1824 alSetError(AL_INVALID_OPERATION);
1827 else
1829 // Invalid Source Name
1830 alSetError(AL_INVALID_NAME);
1833 ProcessContext(Context);
1835 else
1837 // Invalid Context
1838 alSetError(AL_INVALID_OPERATION);
1841 return;
1845 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1846 // an array of buffer IDs that are to be filled with the names of the buffers removed
1847 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1849 ALCcontext *Context;
1850 ALsource *ALSource;
1851 ALsizei i;
1852 ALbufferlistitem *ALBufferList;
1853 ALuint DataSize;
1854 ALuint BufferSize;
1855 ALuint BufferID;
1856 ALboolean bBuffersProcessed;
1858 if (n == 0)
1859 return;
1861 DataSize = 0;
1862 BufferSize = 0;
1863 bBuffersProcessed = AL_TRUE;
1865 Context=alcGetCurrentContext();
1866 if (Context)
1868 SuspendContext(Context);
1870 if (alIsSource(source))
1872 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1874 // Check that all 'n' buffers have been processed
1875 ALBufferList = ALSource->queue;
1876 for (i = 0; i < n; i++)
1878 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1880 ALBufferList = ALBufferList->next;
1882 else
1884 bBuffersProcessed = AL_FALSE;
1885 break;
1889 // If all 'n' buffers have been processed, remove them from the queue
1890 if (bBuffersProcessed)
1892 for (i = 0; i < n; i++)
1894 ALBufferList = ALSource->queue;
1896 ALSource->queue = ALBufferList->next;
1897 // Record name of buffer
1898 buffers[i] = ALBufferList->buffer;
1899 // Decrement buffer reference counter
1900 if (ALBufferList->buffer)
1901 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1902 // Record size of buffer
1903 if (ALBufferList->buffer)
1904 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1905 else
1906 BufferSize = 0;
1908 DataSize += BufferSize;
1909 // Release memory for buffer list item
1910 free(ALBufferList);
1911 ALSource->BuffersInQueue--;
1912 ALSource->BuffersProcessed--;
1915 if (ALSource->state != AL_PLAYING)
1917 if (ALSource->queue)
1918 BufferID = ALSource->queue->buffer;
1919 else
1920 BufferID = 0;
1922 ALSource->ulBufferID = BufferID;
1925 if((ALuint)n > ALSource->BuffersPlayed)
1927 ALSource->BuffersPlayed = 0;
1928 ALSource->BufferPosition = 0;
1930 else
1931 ALSource->BuffersPlayed -= n;
1933 else
1935 // Some buffers can't be unqueue because they have not been processed
1936 alSetError(AL_INVALID_VALUE);
1939 else
1941 // Invalid Source Name
1942 alSetError(AL_INVALID_NAME);
1945 ProcessContext(Context);
1947 else
1949 // Invalid Context
1950 alSetError(AL_INVALID_OPERATION);
1953 return;
1957 static ALvoid InitSourceParams(ALsource *pSource)
1959 pSource->flInnerAngle = 360.0f;
1960 pSource->flOuterAngle = 360.0f;
1961 pSource->flPitch = 1.0f;
1962 pSource->vPosition[0] = 0.0f;
1963 pSource->vPosition[1] = 0.0f;
1964 pSource->vPosition[2] = 0.0f;
1965 pSource->vOrientation[0] = 0.0f;
1966 pSource->vOrientation[1] = 0.0f;
1967 pSource->vOrientation[2] = 0.0f;
1968 pSource->vVelocity[0] = 0.0f;
1969 pSource->vVelocity[1] = 0.0f;
1970 pSource->vVelocity[2] = 0.0f;
1971 pSource->flRefDistance = 1.0f;
1972 pSource->flMaxDistance = FLT_MAX;
1973 pSource->flRollOffFactor = 1.0f;
1974 pSource->bLooping = AL_FALSE;
1975 pSource->flGain = 1.0f;
1976 pSource->flMinGain = 0.0f;
1977 pSource->flMaxGain = 1.0f;
1978 pSource->flOuterGain = 0.0f;
1979 pSource->OuterGainHF = 1.0f;
1981 pSource->DryGainHFAuto = AL_TRUE;
1982 pSource->WetGainAuto = AL_TRUE;
1983 pSource->WetGainHFAuto = AL_TRUE;
1984 pSource->AirAbsorptionFactor = 0.0f;
1985 pSource->RoomRolloffFactor = 0.0f;
1986 pSource->DopplerFactor = 1.0f;
1988 pSource->state = AL_INITIAL;
1989 pSource->lSourceType = AL_UNDETERMINED;
1991 pSource->ulBufferID= 0;
1996 GetSourceOffset
1998 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1999 The offset is relative to the start of the queue (not the start of the current buffer)
2001 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2003 ALbufferlistitem *pBufferList;
2004 ALbuffer *pBuffer;
2005 ALfloat flBufferFreq;
2006 ALint lBytesPlayed, lChannels;
2007 ALenum eOriginalFormat;
2008 ALboolean bReturn = AL_TRUE;
2009 ALint lTotalBufferDataSize;
2011 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2013 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2014 // Get Current Buffer Size and frequency (in milliseconds)
2015 flBufferFreq = (ALfloat)pBuffer->frequency;
2016 eOriginalFormat = pBuffer->eOriginalFormat;
2017 lChannels = aluChannelsFromFormat(pBuffer->format);
2019 // Get Current BytesPlayed
2020 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2021 // Add byte length of any processed buffers in the queue
2022 pBufferList = pSource->queue;
2023 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2025 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2026 pBufferList = pBufferList->next;
2029 lTotalBufferDataSize = 0;
2030 pBufferList = pSource->queue;
2031 while (pBufferList)
2033 if (pBufferList->buffer)
2034 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2035 pBufferList = pBufferList->next;
2038 if (pSource->bLooping)
2040 if (lBytesPlayed < 0)
2041 lBytesPlayed = 0;
2042 else
2043 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2045 else
2047 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2048 if(lBytesPlayed < 0)
2049 lBytesPlayed = 0;
2050 if(lBytesPlayed > lTotalBufferDataSize)
2051 lBytesPlayed = lTotalBufferDataSize;
2054 switch (eName)
2056 case AL_SEC_OFFSET:
2057 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2058 break;
2059 case AL_SAMPLE_OFFSET:
2060 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2061 break;
2062 case AL_BYTE_OFFSET:
2063 // Take into account the original format of the Buffer
2064 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2065 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2067 // Compression rate of the ADPCM supported is 3.6111 to 1
2068 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2069 // Round down to nearest ADPCM block
2070 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2072 else if (eOriginalFormat == AL_FORMAT_REAR8)
2074 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2076 else if (eOriginalFormat == AL_FORMAT_REAR16)
2078 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2080 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2082 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2084 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2086 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2088 else
2090 *pflOffset = (ALfloat)lBytesPlayed;
2092 break;
2095 else
2097 *pflOffset = 0.0f;
2100 return bReturn;
2105 ApplyOffset
2107 Apply a playback offset to the Source. This function will update the queue (to correctly
2108 mark buffers as 'pending' or 'processed' depending upon the new offset.
2110 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2112 ALbufferlistitem *pBufferList;
2113 ALbuffer *pBuffer;
2114 ALint lBufferSize, lTotalBufferSize;
2115 ALint lByteOffset;
2117 // Get true byte offset
2118 lByteOffset = GetByteOffset(pSource);
2120 // If this is a valid offset apply it
2121 if (lByteOffset != -1)
2123 // Sort out the queue (pending and processed states)
2124 pBufferList = pSource->queue;
2125 lTotalBufferSize = 0;
2126 pSource->BuffersPlayed = 0;
2127 pSource->BuffersProcessed = 0;
2128 while (pBufferList)
2130 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2131 lBufferSize = pBuffer ? pBuffer->size : 0;
2133 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2135 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2136 // update the state to PROCESSED
2137 pSource->BuffersPlayed++;
2139 if (!pSource->bLooping)
2141 pBufferList->bufferstate = PROCESSED;
2142 pSource->BuffersProcessed++;
2145 else if (lTotalBufferSize <= lByteOffset)
2147 // Offset is within this buffer
2148 pBufferList->bufferstate = PENDING;
2150 // Set Current Buffer ID
2151 pSource->ulBufferID = pBufferList->buffer;
2153 // Set current position in this buffer
2154 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2156 // Set Total Bytes Played to Offset
2157 pSource->lBytesPlayed = lByteOffset;
2159 // SW Mixer Positions are in Samples
2160 pSource->position = pSource->BufferPosition /
2161 aluBytesFromFormat(pBuffer->format) /
2162 aluChannelsFromFormat(pBuffer->format);
2164 else
2166 // Offset is before this buffer, so mark as pending
2167 pBufferList->bufferstate = PENDING;
2170 // Increment the TotalBufferSize
2171 lTotalBufferSize += lBufferSize;
2173 // Move on to next buffer in the Queue
2174 pBufferList = pBufferList->next;
2177 else
2179 if (bUpdateContext)
2180 alSetError(AL_INVALID_VALUE);
2183 // Clear Offset
2184 pSource->lOffset = 0;
2189 GetByteOffset
2191 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2192 offset supplied by the application). This takes into account the fact that the buffer format
2193 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2195 static ALint GetByteOffset(ALsource *pSource)
2197 ALbuffer *pBuffer = NULL;
2198 ALbufferlistitem *pBufferList;
2199 ALfloat flBufferFreq;
2200 ALint lChannels;
2201 ALint lByteOffset = -1;
2202 ALint lTotalBufferDataSize;
2204 // Find the first non-NULL Buffer in the Queue
2205 pBufferList = pSource->queue;
2206 while (pBufferList)
2208 if (pBufferList->buffer)
2210 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2211 break;
2213 pBufferList = pBufferList->next;
2216 if (pBuffer)
2218 flBufferFreq = ((ALfloat)pBuffer->frequency);
2219 lChannels = aluChannelsFromFormat(pBuffer->format);
2221 // Determine the ByteOffset (and ensure it is block aligned)
2222 switch (pSource->lOffsetType)
2224 case AL_BYTE_OFFSET:
2225 // Take into consideration the original format
2226 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2227 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2229 // Round down to nearest ADPCM block
2230 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2231 // Multiply by compression rate
2232 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2233 lByteOffset -= (lByteOffset % (lChannels * 2));
2235 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2237 lByteOffset = pSource->lOffset * 4;
2238 lByteOffset -= (lByteOffset % (lChannels * 2));
2240 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2242 lByteOffset = pSource->lOffset * 2;
2243 lByteOffset -= (lByteOffset % (lChannels * 2));
2245 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2247 lByteOffset = pSource->lOffset * 2;
2248 lByteOffset -= (lByteOffset % (lChannels * 2));
2250 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2252 lByteOffset = pSource->lOffset / 2;
2253 lByteOffset -= (lByteOffset % (lChannels * 2));
2255 else
2257 lByteOffset = pSource->lOffset;
2258 lByteOffset -= (lByteOffset % (lChannels * 2));
2260 break;
2262 case AL_SAMPLE_OFFSET:
2263 lByteOffset = pSource->lOffset * lChannels * 2;
2264 break;
2266 case AL_SEC_OFFSET:
2267 // Note - lOffset is internally stored as Milliseconds
2268 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2269 lByteOffset -= (lByteOffset % (lChannels * 2));
2270 break;
2273 lTotalBufferDataSize = 0;
2274 pBufferList = pSource->queue;
2275 while (pBufferList)
2277 if (pBufferList->buffer)
2278 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2279 pBufferList = pBufferList->next;
2282 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2283 if (lByteOffset >= lTotalBufferDataSize)
2284 lByteOffset = -1;
2287 return lByteOffset;
2291 ALvoid ReleaseALSources(ALCcontext *Context)
2293 #ifdef _DEBUG
2294 if(Context->SourceCount > 0)
2295 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2296 #endif
2298 while(Context->Source)
2300 ALsource *temp = Context->Source;
2301 Context->Source = Context->Source->next;
2303 // Release source structure
2304 ALTHUNK_REMOVEENTRY(temp->source);
2305 memset(temp, 0, sizeof(ALsource));
2306 free(temp);
2308 Context->SourceCount = 0;