Overwrite the input wet sample with the output
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blobb5e36ea6f888d9251a112dddbc1d5b2374c79d47
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_DOPPLER_FACTOR:
371 if (flValue >= 0.0f && flValue <= 1.0f)
372 pSource->DopplerFactor = flValue;
373 else
374 alSetError(AL_INVALID_VALUE);
375 break;
377 case AL_SEC_OFFSET:
378 case AL_SAMPLE_OFFSET:
379 case AL_BYTE_OFFSET:
380 if (flValue >= 0.0f)
382 pSource->lOffsetType = eParam;
384 // Store Offset (convert Seconds into Milliseconds)
385 if (eParam == AL_SEC_OFFSET)
386 pSource->lOffset = (ALint)(flValue * 1000.0f);
387 else
388 pSource->lOffset = (ALint)flValue;
390 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
391 ApplyOffset(pSource, AL_TRUE);
393 else
394 alSetError(AL_INVALID_VALUE);
395 break;
397 default:
398 alSetError(AL_INVALID_ENUM);
399 break;
402 else
404 // Invalid Source Name
405 alSetError(AL_INVALID_NAME);
408 ProcessContext(pContext);
410 else
412 // Invalid context
413 alSetError(AL_INVALID_OPERATION);
416 return;
420 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
422 ALCcontext *pContext;
423 ALsource *pSource;
425 pContext = alcGetCurrentContext();
426 if (pContext)
428 SuspendContext(pContext);
430 if (alIsSource(source))
432 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
433 switch(eParam)
435 case AL_POSITION:
436 pSource->vPosition[0] = flValue1;
437 pSource->vPosition[1] = flValue2;
438 pSource->vPosition[2] = flValue3;
439 break;
441 case AL_VELOCITY:
442 pSource->vVelocity[0] = flValue1;
443 pSource->vVelocity[1] = flValue2;
444 pSource->vVelocity[2] = flValue3;
445 break;
447 case AL_DIRECTION:
448 pSource->vOrientation[0] = flValue1;
449 pSource->vOrientation[1] = flValue2;
450 pSource->vOrientation[2] = flValue3;
451 break;
453 default:
454 alSetError(AL_INVALID_ENUM);
455 break;
458 else
459 alSetError(AL_INVALID_NAME);
461 ProcessContext(pContext);
463 else
465 alSetError(AL_INVALID_OPERATION);
468 return;
472 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
474 ALCcontext *pContext;
476 pContext = alcGetCurrentContext();
477 if (pContext)
479 SuspendContext(pContext);
481 if (pflValues)
483 if (alIsSource(source))
485 switch (eParam)
487 case AL_PITCH:
488 case AL_CONE_INNER_ANGLE:
489 case AL_CONE_OUTER_ANGLE:
490 case AL_GAIN:
491 case AL_MAX_DISTANCE:
492 case AL_ROLLOFF_FACTOR:
493 case AL_REFERENCE_DISTANCE:
494 case AL_MIN_GAIN:
495 case AL_MAX_GAIN:
496 case AL_CONE_OUTER_GAIN:
497 case AL_CONE_OUTER_GAINHF:
498 case AL_SEC_OFFSET:
499 case AL_SAMPLE_OFFSET:
500 case AL_BYTE_OFFSET:
501 case AL_AIR_ABSORPTION_FACTOR:
502 case AL_ROOM_ROLLOFF_FACTOR:
503 alSourcef(source, eParam, pflValues[0]);
504 break;
506 case AL_POSITION:
507 case AL_VELOCITY:
508 case AL_DIRECTION:
509 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
510 break;
512 default:
513 alSetError(AL_INVALID_ENUM);
514 break;
517 else
518 alSetError(AL_INVALID_NAME);
520 else
521 alSetError(AL_INVALID_VALUE);
523 ProcessContext(pContext);
525 else
526 alSetError(AL_INVALID_OPERATION);
528 return;
532 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
534 ALCcontext *pContext;
535 ALsource *pSource;
536 ALbufferlistitem *pALBufferListItem;
537 ALint Counter = 0;
538 ALint DataSize = 0;
539 ALint BufferSize;
541 pContext = alcGetCurrentContext();
542 if (pContext)
544 SuspendContext(pContext);
546 if (alIsSource(source))
548 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
550 switch(eParam)
552 case AL_MAX_DISTANCE:
553 case AL_ROLLOFF_FACTOR:
554 case AL_REFERENCE_DISTANCE:
555 alSourcef(source, eParam, (ALfloat)lValue);
556 break;
558 case AL_SOURCE_RELATIVE:
559 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
560 pSource->bHeadRelative = (ALboolean)lValue;
561 else
562 alSetError(AL_INVALID_VALUE);
563 break;
565 case AL_CONE_INNER_ANGLE:
566 if ((lValue >= 0) && (lValue <= 360))
567 pSource->flInnerAngle = (float)lValue;
568 else
569 alSetError(AL_INVALID_VALUE);
570 break;
572 case AL_CONE_OUTER_ANGLE:
573 if ((lValue >= 0) && (lValue <= 360))
574 pSource->flOuterAngle = (float)lValue;
575 else
576 alSetError(AL_INVALID_VALUE);
577 break;
579 case AL_LOOPING:
580 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
581 pSource->bLooping = (ALboolean)lValue;
582 else
583 alSetError(AL_INVALID_VALUE);
584 break;
586 case AL_BUFFER:
587 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
589 if (alIsBuffer(lValue))
591 // Remove all elements in the queue
592 while (pSource->queue != NULL)
594 pALBufferListItem = pSource->queue;
595 pSource->queue = pALBufferListItem->next;
596 // Decrement reference counter for buffer
597 if (pALBufferListItem->buffer)
598 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
599 // Record size of buffer
600 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
601 DataSize += BufferSize;
602 // Increment the number of buffers removed from queue
603 Counter++;
604 // Release memory for buffer list item
605 free(pALBufferListItem);
606 // Decrement the number of buffers in the queue
607 pSource->BuffersInQueue--;
610 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
611 if (lValue != 0)
613 // Source is now in STATIC mode
614 pSource->lSourceType = AL_STATIC;
616 // Add the selected buffer to the queue
617 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
618 pALBufferListItem->buffer = lValue;
619 pALBufferListItem->bufferstate = PENDING;
620 pALBufferListItem->flag = 0;
621 pALBufferListItem->next = NULL;
623 pSource->queue = pALBufferListItem;
624 pSource->BuffersInQueue = 1;
626 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
628 // Increment reference counter for buffer
629 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
631 else
633 // Source is now in UNDETERMINED mode
634 pSource->lSourceType = AL_UNDETERMINED;
637 // Set Buffers Processed
638 pSource->BuffersProcessed = 0;
640 // Update AL_BUFFER parameter
641 pSource->ulBufferID = lValue;
643 else
644 alSetError(AL_INVALID_VALUE);
646 else
647 alSetError(AL_INVALID_OPERATION);
648 break;
650 case AL_SOURCE_STATE:
651 // Query only
652 alSetError(AL_INVALID_OPERATION);
653 break;
655 case AL_SEC_OFFSET:
656 case AL_SAMPLE_OFFSET:
657 case AL_BYTE_OFFSET:
658 if (lValue >= 0)
660 pSource->lOffsetType = eParam;
662 // Store Offset (convert Seconds into Milliseconds)
663 if (eParam == AL_SEC_OFFSET)
664 pSource->lOffset = lValue * 1000;
665 else
666 pSource->lOffset = lValue;
668 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
669 ApplyOffset(pSource, AL_TRUE);
671 else
672 alSetError(AL_INVALID_VALUE);
673 break;
675 case AL_DIRECT_FILTER:
676 if(alIsFilter(lValue))
678 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
679 if(!filter)
681 pSource->DirectFilter.type = AL_FILTER_NULL;
682 pSource->DirectFilter.filter = 0;
684 else
685 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
687 else
688 alSetError(AL_INVALID_VALUE);
689 break;
691 case AL_DIRECT_FILTER_GAINHF_AUTO:
692 if(lValue == AL_TRUE || lValue == AL_FALSE)
693 pSource->DryGainHFAuto = lValue;
694 else
695 alSetError(AL_INVALID_VALUE);
696 break;
698 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
699 if(lValue == AL_TRUE || lValue == AL_FALSE)
700 pSource->WetGainAuto = lValue;
701 else
702 alSetError(AL_INVALID_VALUE);
703 break;
705 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
706 if(lValue == AL_TRUE || lValue == AL_FALSE)
707 pSource->WetGainHFAuto = lValue;
708 else
709 alSetError(AL_INVALID_VALUE);
710 break;
712 default:
713 alSetError(AL_INVALID_ENUM);
714 break;
717 else
718 alSetError(AL_INVALID_NAME);
720 ProcessContext(pContext);
722 else
723 alSetError(AL_INVALID_OPERATION);
725 return;
729 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
731 ALCcontext *pContext;
733 pContext = alcGetCurrentContext();
734 if (pContext)
736 SuspendContext(pContext);
738 if (alIsSource(source))
740 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
742 switch (eParam)
744 case AL_POSITION:
745 case AL_VELOCITY:
746 case AL_DIRECTION:
747 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
748 break;
750 case AL_AUXILIARY_SEND_FILTER:
751 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
752 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
753 alIsFilter(lValue3))
755 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
756 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
758 /* Release refcount on the previous slot, and add one for
759 * the new slot */
760 if(pSource->Send[lValue2].Slot)
761 pSource->Send[lValue2].Slot->refcount--;
762 pSource->Send[lValue2].Slot = ALEffectSlot;
763 if(pSource->Send[lValue2].Slot)
764 pSource->Send[lValue2].Slot->refcount++;
766 if(!ALFilter)
768 /* Disable filter */
769 pSource->Send[lValue2].WetFilter.type = 0;
770 pSource->Send[lValue2].WetFilter.filter = 0;
772 else
773 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
775 else
776 alSetError(AL_INVALID_VALUE);
777 break;
779 default:
780 alSetError(AL_INVALID_ENUM);
781 break;
784 else
785 alSetError(AL_INVALID_NAME);
787 ProcessContext(pContext);
789 else
790 alSetError(AL_INVALID_OPERATION);
792 return;
796 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
798 ALCcontext *pContext;
800 pContext = alcGetCurrentContext();
801 if (pContext)
803 SuspendContext(pContext);
805 if (plValues)
807 if (alIsSource(source))
809 switch (eParam)
811 case AL_SOURCE_RELATIVE:
812 case AL_CONE_INNER_ANGLE:
813 case AL_CONE_OUTER_ANGLE:
814 case AL_LOOPING:
815 case AL_BUFFER:
816 case AL_SOURCE_STATE:
817 case AL_SEC_OFFSET:
818 case AL_SAMPLE_OFFSET:
819 case AL_BYTE_OFFSET:
820 case AL_MAX_DISTANCE:
821 case AL_ROLLOFF_FACTOR:
822 case AL_REFERENCE_DISTANCE:
823 case AL_DIRECT_FILTER:
824 case AL_DIRECT_FILTER_GAINHF_AUTO:
825 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
826 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
827 alSourcei(source, eParam, plValues[0]);
828 break;
830 case AL_POSITION:
831 case AL_VELOCITY:
832 case AL_DIRECTION:
833 case AL_AUXILIARY_SEND_FILTER:
834 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
835 break;
837 default:
838 alSetError(AL_INVALID_ENUM);
839 break;
842 else
843 alSetError(AL_INVALID_NAME);
845 else
846 alSetError(AL_INVALID_VALUE);
848 ProcessContext(pContext);
850 else
851 alSetError(AL_INVALID_OPERATION);
853 return;
857 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
859 ALCcontext *pContext;
860 ALsource *pSource;
861 ALfloat flOffset;
863 pContext = alcGetCurrentContext();
864 if (pContext)
866 SuspendContext(pContext);
868 if (pflValue)
870 if (alIsSource(source))
872 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
874 switch(eParam)
876 case AL_PITCH:
877 *pflValue = pSource->flPitch;
878 break;
880 case AL_GAIN:
881 *pflValue = pSource->flGain;
882 break;
884 case AL_MIN_GAIN:
885 *pflValue = pSource->flMinGain;
886 break;
888 case AL_MAX_GAIN:
889 *pflValue = pSource->flMaxGain;
890 break;
892 case AL_MAX_DISTANCE:
893 *pflValue = pSource->flMaxDistance;
894 break;
896 case AL_ROLLOFF_FACTOR:
897 *pflValue = pSource->flRollOffFactor;
898 break;
900 case AL_CONE_OUTER_GAIN:
901 *pflValue = pSource->flOuterGain;
902 break;
904 case AL_CONE_OUTER_GAINHF:
905 *pflValue = pSource->OuterGainHF;
906 break;
908 case AL_SEC_OFFSET:
909 case AL_SAMPLE_OFFSET:
910 case AL_BYTE_OFFSET:
911 if (GetSourceOffset(pSource, eParam, &flOffset))
912 *pflValue = flOffset;
913 else
914 alSetError(AL_INVALID_OPERATION);
915 break;
917 case AL_CONE_INNER_ANGLE:
918 *pflValue = pSource->flInnerAngle;
919 break;
921 case AL_CONE_OUTER_ANGLE:
922 *pflValue = pSource->flOuterAngle;
923 break;
925 case AL_REFERENCE_DISTANCE:
926 *pflValue = pSource->flRefDistance;
927 break;
929 case AL_AIR_ABSORPTION_FACTOR:
930 *pflValue = pSource->AirAbsorptionFactor;
931 break;
933 case AL_ROOM_ROLLOFF_FACTOR:
934 *pflValue = pSource->RoomRolloffFactor;
935 break;
937 case AL_DOPPLER_FACTOR:
938 *pflValue = pSource->DopplerFactor;
939 break;
941 default:
942 alSetError(AL_INVALID_ENUM);
943 break;
946 else
947 alSetError(AL_INVALID_NAME);
949 else
950 alSetError(AL_INVALID_VALUE);
952 ProcessContext(pContext);
954 else
955 alSetError(AL_INVALID_OPERATION);
957 return;
961 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
963 ALCcontext *pContext;
964 ALsource *pSource;
966 pContext = alcGetCurrentContext();
967 if (pContext)
969 SuspendContext(pContext);
971 if ((pflValue1) && (pflValue2) && (pflValue3))
973 if (alIsSource(source))
975 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
977 switch(eParam)
979 case AL_POSITION:
980 *pflValue1 = pSource->vPosition[0];
981 *pflValue2 = pSource->vPosition[1];
982 *pflValue3 = pSource->vPosition[2];
983 break;
985 case AL_VELOCITY:
986 *pflValue1 = pSource->vVelocity[0];
987 *pflValue2 = pSource->vVelocity[1];
988 *pflValue3 = pSource->vVelocity[2];
989 break;
991 case AL_DIRECTION:
992 *pflValue1 = pSource->vOrientation[0];
993 *pflValue2 = pSource->vOrientation[1];
994 *pflValue3 = pSource->vOrientation[2];
995 break;
997 default:
998 alSetError(AL_INVALID_ENUM);
999 break;
1002 else
1003 alSetError(AL_INVALID_NAME);
1005 else
1006 alSetError(AL_INVALID_VALUE);
1008 ProcessContext(pContext);
1010 else
1011 alSetError(AL_INVALID_OPERATION);
1013 return;
1017 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1019 ALCcontext *pContext;
1020 ALsource *pSource;
1022 pContext = alcGetCurrentContext();
1023 if (pContext)
1025 SuspendContext(pContext);
1027 if (pflValues)
1029 if (alIsSource(source))
1031 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1033 switch(eParam)
1035 case AL_PITCH:
1036 case AL_GAIN:
1037 case AL_MIN_GAIN:
1038 case AL_MAX_GAIN:
1039 case AL_MAX_DISTANCE:
1040 case AL_ROLLOFF_FACTOR:
1041 case AL_DOPPLER_FACTOR:
1042 case AL_CONE_OUTER_GAIN:
1043 case AL_SEC_OFFSET:
1044 case AL_SAMPLE_OFFSET:
1045 case AL_BYTE_OFFSET:
1046 case AL_CONE_INNER_ANGLE:
1047 case AL_CONE_OUTER_ANGLE:
1048 case AL_REFERENCE_DISTANCE:
1049 case AL_CONE_OUTER_GAINHF:
1050 case AL_AIR_ABSORPTION_FACTOR:
1051 case AL_ROOM_ROLLOFF_FACTOR:
1052 alGetSourcef(source, eParam, pflValues);
1053 break;
1055 case AL_POSITION:
1056 pflValues[0] = pSource->vPosition[0];
1057 pflValues[1] = pSource->vPosition[1];
1058 pflValues[2] = pSource->vPosition[2];
1059 break;
1061 case AL_VELOCITY:
1062 pflValues[0] = pSource->vVelocity[0];
1063 pflValues[1] = pSource->vVelocity[1];
1064 pflValues[2] = pSource->vVelocity[2];
1065 break;
1067 case AL_DIRECTION:
1068 pflValues[0] = pSource->vOrientation[0];
1069 pflValues[1] = pSource->vOrientation[1];
1070 pflValues[2] = pSource->vOrientation[2];
1071 break;
1073 default:
1074 alSetError(AL_INVALID_ENUM);
1075 break;
1078 else
1079 alSetError(AL_INVALID_NAME);
1081 else
1082 alSetError(AL_INVALID_VALUE);
1084 ProcessContext(pContext);
1086 else
1087 alSetError(AL_INVALID_OPERATION);
1089 return;
1093 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1095 ALCcontext *pContext;
1096 ALsource *pSource;
1097 ALfloat flOffset;
1099 pContext = alcGetCurrentContext();
1100 if (pContext)
1102 SuspendContext(pContext);
1104 if (plValue)
1106 if (alIsSource(source))
1108 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1110 switch(eParam)
1112 case AL_MAX_DISTANCE:
1113 *plValue = (ALint)pSource->flMaxDistance;
1114 break;
1116 case AL_ROLLOFF_FACTOR:
1117 *plValue = (ALint)pSource->flRollOffFactor;
1118 break;
1120 case AL_REFERENCE_DISTANCE:
1121 *plValue = (ALint)pSource->flRefDistance;
1122 break;
1124 case AL_SOURCE_RELATIVE:
1125 *plValue = pSource->bHeadRelative;
1126 break;
1128 case AL_CONE_INNER_ANGLE:
1129 *plValue = (ALint)pSource->flInnerAngle;
1130 break;
1132 case AL_CONE_OUTER_ANGLE:
1133 *plValue = (ALint)pSource->flOuterAngle;
1134 break;
1136 case AL_LOOPING:
1137 *plValue = pSource->bLooping;
1138 break;
1140 case AL_BUFFER:
1141 *plValue = pSource->ulBufferID;
1142 break;
1144 case AL_SOURCE_STATE:
1145 *plValue = pSource->state;
1146 break;
1148 case AL_BUFFERS_QUEUED:
1149 *plValue = pSource->BuffersInQueue;
1150 break;
1152 case AL_BUFFERS_PROCESSED:
1153 if(pSource->bLooping)
1155 /* Buffers on a looping source are in a perpetual state
1156 * of PENDING, so don't report any as PROCESSED */
1157 *plValue = 0;
1159 else
1160 *plValue = pSource->BuffersProcessed;
1161 break;
1163 case AL_SOURCE_TYPE:
1164 *plValue = pSource->lSourceType;
1165 break;
1167 case AL_SEC_OFFSET:
1168 case AL_SAMPLE_OFFSET:
1169 case AL_BYTE_OFFSET:
1170 if (GetSourceOffset(pSource, eParam, &flOffset))
1171 *plValue = (ALint)flOffset;
1172 else
1173 alSetError(AL_INVALID_OPERATION);
1174 break;
1176 case AL_DIRECT_FILTER:
1177 *plValue = pSource->DirectFilter.filter;
1178 break;
1180 case AL_DIRECT_FILTER_GAINHF_AUTO:
1181 *plValue = pSource->DryGainHFAuto;
1182 break;
1184 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1185 *plValue = pSource->WetGainAuto;
1186 break;
1188 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1189 *plValue = pSource->WetGainHFAuto;
1190 break;
1192 case AL_DOPPLER_FACTOR:
1193 *plValue = (ALint)pSource->DopplerFactor;
1194 break;
1196 default:
1197 alSetError(AL_INVALID_ENUM);
1198 break;
1201 else
1202 alSetError(AL_INVALID_NAME);
1204 else
1205 alSetError(AL_INVALID_VALUE);
1207 ProcessContext(pContext);
1209 else
1210 alSetError(AL_INVALID_OPERATION);
1212 return;
1216 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1218 ALCcontext *pContext;
1219 ALsource *pSource;
1221 pContext = alcGetCurrentContext();
1222 if (pContext)
1224 SuspendContext(pContext);
1226 if ((plValue1) && (plValue2) && (plValue3))
1228 if (alIsSource(source))
1230 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1232 switch(eParam)
1234 case AL_POSITION:
1235 *plValue1 = (ALint)pSource->vPosition[0];
1236 *plValue2 = (ALint)pSource->vPosition[1];
1237 *plValue3 = (ALint)pSource->vPosition[2];
1238 break;
1240 case AL_VELOCITY:
1241 *plValue1 = (ALint)pSource->vVelocity[0];
1242 *plValue2 = (ALint)pSource->vVelocity[1];
1243 *plValue3 = (ALint)pSource->vVelocity[2];
1244 break;
1246 case AL_DIRECTION:
1247 *plValue1 = (ALint)pSource->vOrientation[0];
1248 *plValue2 = (ALint)pSource->vOrientation[1];
1249 *plValue3 = (ALint)pSource->vOrientation[2];
1250 break;
1252 default:
1253 alSetError(AL_INVALID_ENUM);
1254 break;
1257 else
1258 alSetError(AL_INVALID_NAME);
1260 else
1261 alSetError(AL_INVALID_VALUE);
1263 ProcessContext(pContext);
1265 else
1266 alSetError(AL_INVALID_OPERATION);
1268 return;
1272 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1274 ALCcontext *pContext;
1275 ALsource *pSource;
1277 pContext = alcGetCurrentContext();
1278 if (pContext)
1280 SuspendContext(pContext);
1282 if (plValues)
1284 if (alIsSource(source))
1286 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1288 switch (eParam)
1290 case AL_SOURCE_RELATIVE:
1291 case AL_CONE_INNER_ANGLE:
1292 case AL_CONE_OUTER_ANGLE:
1293 case AL_LOOPING:
1294 case AL_BUFFER:
1295 case AL_SOURCE_STATE:
1296 case AL_BUFFERS_QUEUED:
1297 case AL_BUFFERS_PROCESSED:
1298 case AL_SEC_OFFSET:
1299 case AL_SAMPLE_OFFSET:
1300 case AL_BYTE_OFFSET:
1301 case AL_MAX_DISTANCE:
1302 case AL_ROLLOFF_FACTOR:
1303 case AL_DOPPLER_FACTOR:
1304 case AL_REFERENCE_DISTANCE:
1305 case AL_SOURCE_TYPE:
1306 case AL_DIRECT_FILTER:
1307 case AL_DIRECT_FILTER_GAINHF_AUTO:
1308 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1309 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1310 alGetSourcei(source, eParam, plValues);
1311 break;
1313 case AL_POSITION:
1314 plValues[0] = (ALint)pSource->vPosition[0];
1315 plValues[1] = (ALint)pSource->vPosition[1];
1316 plValues[2] = (ALint)pSource->vPosition[2];
1317 break;
1319 case AL_VELOCITY:
1320 plValues[0] = (ALint)pSource->vVelocity[0];
1321 plValues[1] = (ALint)pSource->vVelocity[1];
1322 plValues[2] = (ALint)pSource->vVelocity[2];
1323 break;
1325 case AL_DIRECTION:
1326 plValues[0] = (ALint)pSource->vOrientation[0];
1327 plValues[1] = (ALint)pSource->vOrientation[1];
1328 plValues[2] = (ALint)pSource->vOrientation[2];
1329 break;
1331 default:
1332 alSetError(AL_INVALID_ENUM);
1333 break;
1336 else
1337 alSetError(AL_INVALID_NAME);
1339 else
1340 alSetError(AL_INVALID_VALUE);
1342 ProcessContext(pContext);
1344 else
1345 alSetError(AL_INVALID_OPERATION);
1347 return;
1351 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1353 alSourcePlayv(1, &source);
1354 return;
1357 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1359 ALCcontext *pContext;
1360 ALsource *pSource;
1361 ALbufferlistitem *ALBufferList;
1362 ALboolean bSourcesValid = AL_TRUE;
1363 ALboolean bPlay;
1364 ALsizei i;
1366 pContext = alcGetCurrentContext();
1367 if (pContext)
1369 SuspendContext(pContext);
1371 if (pSourceList)
1373 // Check that all the Sources are valid
1374 for (i = 0; i < n; i++)
1376 if (!alIsSource(pSourceList[i]))
1378 alSetError(AL_INVALID_NAME);
1379 bSourcesValid = AL_FALSE;
1380 break;
1384 if (bSourcesValid)
1386 for (i = 0; i < n; i++)
1388 // Assume Source won't need to play
1389 bPlay = AL_FALSE;
1391 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1393 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1394 ALBufferList = pSource->queue;
1395 while (ALBufferList)
1397 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1399 bPlay = AL_TRUE;
1400 break;
1402 ALBufferList = ALBufferList->next;
1405 if (bPlay)
1407 if (pSource->state != AL_PAUSED)
1409 pSource->state = AL_PLAYING;
1410 pSource->inuse = AL_TRUE;
1411 pSource->play = AL_TRUE;
1412 pSource->position = 0;
1413 pSource->position_fraction = 0;
1414 pSource->BuffersProcessed = 0;
1415 pSource->BuffersPlayed = 0;
1416 pSource->BufferPosition = 0;
1417 pSource->lBytesPlayed = 0;
1419 pSource->ulBufferID = pSource->queue->buffer;
1421 // Make sure all the Buffers in the queue are marked as PENDING
1422 ALBufferList = pSource->queue;
1423 while (ALBufferList)
1425 ALBufferList->bufferstate = PENDING;
1426 ALBufferList = ALBufferList->next;
1429 else
1431 pSource->state = AL_PLAYING;
1432 pSource->inuse = AL_TRUE;
1433 pSource->play = AL_TRUE;
1436 // Check if an Offset has been set
1437 if (pSource->lOffset)
1438 ApplyOffset(pSource, AL_FALSE);
1440 else
1442 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1443 ALBufferList = pSource->queue;
1444 while (ALBufferList)
1446 ALBufferList->bufferstate = PROCESSED;
1447 ALBufferList = ALBufferList->next;
1450 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1455 else
1457 // sources is a NULL pointer
1458 alSetError(AL_INVALID_VALUE);
1461 ProcessContext(pContext);
1463 else
1465 // Invalid Context
1466 alSetError(AL_INVALID_OPERATION);
1469 return;
1472 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1474 alSourcePausev(1, &source);
1475 return;
1478 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1480 ALCcontext *Context;
1481 ALsource *Source;
1482 ALsizei i;
1483 ALboolean bSourcesValid = AL_TRUE;
1485 Context=alcGetCurrentContext();
1486 if (Context)
1488 SuspendContext(Context);
1490 if (sources)
1492 // Check all the Sources are valid
1493 for (i=0;i<n;i++)
1495 if (!alIsSource(sources[i]))
1497 alSetError(AL_INVALID_NAME);
1498 bSourcesValid = AL_FALSE;
1499 break;
1503 if (bSourcesValid)
1505 for (i=0;i<n;i++)
1507 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1508 if (Source->state==AL_PLAYING)
1510 Source->state=AL_PAUSED;
1511 Source->inuse=AL_FALSE;
1516 else
1518 // sources is a NULL pointer
1519 alSetError(AL_INVALID_VALUE);
1522 ProcessContext(Context);
1524 else
1526 // Invalid Context
1527 alSetError(AL_INVALID_OPERATION);
1530 return;
1533 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1535 alSourceStopv(1, &source);
1536 return;
1539 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1541 ALCcontext *Context;
1542 ALsource *Source;
1543 ALsizei i;
1544 ALbufferlistitem *ALBufferListItem;
1545 ALboolean bSourcesValid = AL_TRUE;
1547 Context=alcGetCurrentContext();
1548 if (Context)
1550 SuspendContext(Context);
1552 if (sources)
1554 // Check all the Sources are valid
1555 for (i=0;i<n;i++)
1557 if (!alIsSource(sources[i]))
1559 alSetError(AL_INVALID_NAME);
1560 bSourcesValid = AL_FALSE;
1561 break;
1565 if (bSourcesValid)
1567 for (i=0;i<n;i++)
1569 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1570 if (Source->state!=AL_INITIAL)
1572 Source->state=AL_STOPPED;
1573 Source->inuse=AL_FALSE;
1574 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1575 ALBufferListItem= Source->queue;
1576 while (ALBufferListItem != NULL)
1578 ALBufferListItem->bufferstate = PROCESSED;
1579 ALBufferListItem = ALBufferListItem->next;
1582 Source->lOffset = 0;
1586 else
1588 // sources is a NULL pointer
1589 alSetError(AL_INVALID_VALUE);
1592 ProcessContext(Context);
1594 else
1596 // Invalid Context
1597 alSetError(AL_INVALID_OPERATION);
1600 return;
1603 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1605 alSourceRewindv(1, &source);
1606 return;
1609 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1611 ALCcontext *Context;
1612 ALsource *Source;
1613 ALsizei i;
1614 ALbufferlistitem *ALBufferListItem;
1615 ALboolean bSourcesValid = AL_TRUE;
1617 Context=alcGetCurrentContext();
1618 if (Context)
1620 SuspendContext(Context);
1622 if (sources)
1624 // Check all the Sources are valid
1625 for (i=0;i<n;i++)
1627 if (!alIsSource(sources[i]))
1629 alSetError(AL_INVALID_NAME);
1630 bSourcesValid = AL_FALSE;
1631 break;
1635 if (bSourcesValid)
1637 for (i=0;i<n;i++)
1639 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1640 if (Source->state!=AL_INITIAL)
1642 Source->state=AL_INITIAL;
1643 Source->inuse=AL_FALSE;
1644 Source->position=0;
1645 Source->position_fraction=0;
1646 Source->BuffersProcessed = 0;
1647 ALBufferListItem= Source->queue;
1648 while (ALBufferListItem != NULL)
1650 ALBufferListItem->bufferstate = PENDING;
1651 ALBufferListItem = ALBufferListItem->next;
1653 if (Source->queue)
1654 Source->ulBufferID = Source->queue->buffer;
1656 Source->lOffset = 0;
1660 else
1662 // sources is a NULL pointer
1663 alSetError(AL_INVALID_VALUE);
1666 ProcessContext(Context);
1668 else
1670 // Invalid Context
1671 alSetError(AL_INVALID_OPERATION);
1674 return;
1678 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1680 ALCcontext *Context;
1681 ALsource *ALSource;
1682 ALsizei i;
1683 ALbufferlistitem *ALBufferList;
1684 ALbufferlistitem *ALBufferListStart;
1685 ALuint DataSize;
1686 ALuint BufferSize;
1687 ALint iFrequency;
1688 ALint iFormat;
1689 ALboolean bBuffersValid = AL_TRUE;
1691 if (n == 0)
1692 return;
1694 Context=alcGetCurrentContext();
1695 if (Context)
1697 SuspendContext(Context);
1699 DataSize = 0;
1700 BufferSize = 0;
1702 // Check that all buffers are valid or zero and that the source is valid
1704 // Check that this is a valid source
1705 if (alIsSource(source))
1707 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1709 // Check that this is not a STATIC Source
1710 if (ALSource->lSourceType != AL_STATIC)
1712 iFrequency = -1;
1713 iFormat = -1;
1715 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1716 ALBufferList = ALSource->queue;
1717 while (ALBufferList)
1719 if (ALBufferList->buffer)
1721 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1722 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1723 break;
1725 ALBufferList = ALBufferList->next;
1728 for (i = 0; i < n; i++)
1730 if (alIsBuffer(buffers[i]))
1732 if (buffers[i])
1734 if ((iFrequency == -1) && (iFormat == -1))
1736 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1737 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1739 else
1741 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1742 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1744 alSetError(AL_INVALID_OPERATION);
1745 bBuffersValid = AL_FALSE;
1746 break;
1751 else
1753 alSetError(AL_INVALID_NAME);
1754 bBuffersValid = AL_FALSE;
1755 break;
1759 if (bBuffersValid)
1761 // Change Source Type
1762 ALSource->lSourceType = AL_STREAMING;
1764 // All buffers are valid - so add them to the list
1765 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1766 ALBufferListStart->buffer = buffers[0];
1767 ALBufferListStart->bufferstate = PENDING;
1768 ALBufferListStart->flag = 0;
1769 ALBufferListStart->next = NULL;
1771 if (buffers[0])
1772 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1773 else
1774 BufferSize = 0;
1776 DataSize += BufferSize;
1778 // Increment reference counter for buffer
1779 if (buffers[0])
1780 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1782 ALBufferList = ALBufferListStart;
1784 for (i = 1; i < n; i++)
1786 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1787 ALBufferList->next->buffer = buffers[i];
1788 ALBufferList->next->bufferstate = PENDING;
1789 ALBufferList->next->flag = 0;
1790 ALBufferList->next->next = NULL;
1792 if (buffers[i])
1793 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1794 else
1795 BufferSize = 0;
1797 DataSize += BufferSize;
1799 // Increment reference counter for buffer
1800 if (buffers[i])
1801 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1803 ALBufferList = ALBufferList->next;
1806 if (ALSource->queue == NULL)
1808 ALSource->queue = ALBufferListStart;
1809 // Update Current Buffer
1810 ALSource->ulBufferID = ALBufferListStart->buffer;
1812 else
1814 // Find end of queue
1815 ALBufferList = ALSource->queue;
1816 while (ALBufferList->next != NULL)
1818 ALBufferList = ALBufferList->next;
1821 ALBufferList->next = ALBufferListStart;
1824 // Update number of buffers in queue
1825 ALSource->BuffersInQueue += n;
1828 else
1830 // Invalid Source Type (can't queue on a Static Source)
1831 alSetError(AL_INVALID_OPERATION);
1834 else
1836 // Invalid Source Name
1837 alSetError(AL_INVALID_NAME);
1840 ProcessContext(Context);
1842 else
1844 // Invalid Context
1845 alSetError(AL_INVALID_OPERATION);
1848 return;
1852 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1853 // an array of buffer IDs that are to be filled with the names of the buffers removed
1854 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1856 ALCcontext *Context;
1857 ALsource *ALSource;
1858 ALsizei i;
1859 ALbufferlistitem *ALBufferList;
1860 ALuint DataSize;
1861 ALuint BufferSize;
1862 ALuint BufferID;
1863 ALboolean bBuffersProcessed;
1865 if (n == 0)
1866 return;
1868 DataSize = 0;
1869 BufferSize = 0;
1870 bBuffersProcessed = AL_TRUE;
1872 Context=alcGetCurrentContext();
1873 if (Context)
1875 SuspendContext(Context);
1877 if (alIsSource(source))
1879 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1881 // Check that all 'n' buffers have been processed
1882 ALBufferList = ALSource->queue;
1883 for (i = 0; i < n; i++)
1885 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1887 ALBufferList = ALBufferList->next;
1889 else
1891 bBuffersProcessed = AL_FALSE;
1892 break;
1896 // If all 'n' buffers have been processed, remove them from the queue
1897 if (bBuffersProcessed)
1899 for (i = 0; i < n; i++)
1901 ALBufferList = ALSource->queue;
1903 ALSource->queue = ALBufferList->next;
1904 // Record name of buffer
1905 buffers[i] = ALBufferList->buffer;
1906 // Decrement buffer reference counter
1907 if (ALBufferList->buffer)
1908 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1909 // Record size of buffer
1910 if (ALBufferList->buffer)
1911 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1912 else
1913 BufferSize = 0;
1915 DataSize += BufferSize;
1916 // Release memory for buffer list item
1917 free(ALBufferList);
1918 ALSource->BuffersInQueue--;
1919 ALSource->BuffersProcessed--;
1922 if (ALSource->state != AL_PLAYING)
1924 if (ALSource->queue)
1925 BufferID = ALSource->queue->buffer;
1926 else
1927 BufferID = 0;
1929 ALSource->ulBufferID = BufferID;
1932 if((ALuint)n > ALSource->BuffersPlayed)
1934 ALSource->BuffersPlayed = 0;
1935 ALSource->BufferPosition = 0;
1937 else
1938 ALSource->BuffersPlayed -= n;
1940 else
1942 // Some buffers can't be unqueue because they have not been processed
1943 alSetError(AL_INVALID_VALUE);
1946 else
1948 // Invalid Source Name
1949 alSetError(AL_INVALID_NAME);
1952 ProcessContext(Context);
1954 else
1956 // Invalid Context
1957 alSetError(AL_INVALID_OPERATION);
1960 return;
1964 static ALvoid InitSourceParams(ALsource *pSource)
1966 pSource->flInnerAngle = 360.0f;
1967 pSource->flOuterAngle = 360.0f;
1968 pSource->flPitch = 1.0f;
1969 pSource->vPosition[0] = 0.0f;
1970 pSource->vPosition[1] = 0.0f;
1971 pSource->vPosition[2] = 0.0f;
1972 pSource->vOrientation[0] = 0.0f;
1973 pSource->vOrientation[1] = 0.0f;
1974 pSource->vOrientation[2] = 0.0f;
1975 pSource->vVelocity[0] = 0.0f;
1976 pSource->vVelocity[1] = 0.0f;
1977 pSource->vVelocity[2] = 0.0f;
1978 pSource->flRefDistance = 1.0f;
1979 pSource->flMaxDistance = FLT_MAX;
1980 pSource->flRollOffFactor = 1.0f;
1981 pSource->bLooping = AL_FALSE;
1982 pSource->flGain = 1.0f;
1983 pSource->flMinGain = 0.0f;
1984 pSource->flMaxGain = 1.0f;
1985 pSource->flOuterGain = 0.0f;
1986 pSource->OuterGainHF = 1.0f;
1988 pSource->DryGainHFAuto = AL_TRUE;
1989 pSource->WetGainAuto = AL_TRUE;
1990 pSource->WetGainHFAuto = AL_TRUE;
1991 pSource->AirAbsorptionFactor = 0.0f;
1992 pSource->RoomRolloffFactor = 0.0f;
1993 pSource->DopplerFactor = 1.0f;
1995 pSource->state = AL_INITIAL;
1996 pSource->lSourceType = AL_UNDETERMINED;
1998 pSource->ulBufferID= 0;
2003 GetSourceOffset
2005 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2006 The offset is relative to the start of the queue (not the start of the current buffer)
2008 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
2010 ALbufferlistitem *pBufferList;
2011 ALbuffer *pBuffer;
2012 ALfloat flBufferFreq;
2013 ALint lBytesPlayed, lChannels;
2014 ALenum eOriginalFormat;
2015 ALboolean bReturn = AL_TRUE;
2016 ALint lTotalBufferDataSize;
2018 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2020 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2021 // Get Current Buffer Size and frequency (in milliseconds)
2022 flBufferFreq = (ALfloat)pBuffer->frequency;
2023 eOriginalFormat = pBuffer->eOriginalFormat;
2024 lChannels = aluChannelsFromFormat(pBuffer->format);
2026 // Get Current BytesPlayed
2027 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2028 // Add byte length of any processed buffers in the queue
2029 pBufferList = pSource->queue;
2030 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2032 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2033 pBufferList = pBufferList->next;
2036 lTotalBufferDataSize = 0;
2037 pBufferList = pSource->queue;
2038 while (pBufferList)
2040 if (pBufferList->buffer)
2041 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2042 pBufferList = pBufferList->next;
2045 if (pSource->bLooping)
2047 if (lBytesPlayed < 0)
2048 lBytesPlayed = 0;
2049 else
2050 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2052 else
2054 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2055 if(lBytesPlayed < 0)
2056 lBytesPlayed = 0;
2057 if(lBytesPlayed > lTotalBufferDataSize)
2058 lBytesPlayed = lTotalBufferDataSize;
2061 switch (eName)
2063 case AL_SEC_OFFSET:
2064 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2065 break;
2066 case AL_SAMPLE_OFFSET:
2067 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2068 break;
2069 case AL_BYTE_OFFSET:
2070 // Take into account the original format of the Buffer
2071 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2072 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2074 // Compression rate of the ADPCM supported is 3.6111 to 1
2075 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2076 // Round down to nearest ADPCM block
2077 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2079 else if (eOriginalFormat == AL_FORMAT_REAR8)
2081 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2083 else if (eOriginalFormat == AL_FORMAT_REAR16)
2085 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2087 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2089 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2091 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2093 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2095 else
2097 *pflOffset = (ALfloat)lBytesPlayed;
2099 break;
2102 else
2104 *pflOffset = 0.0f;
2107 return bReturn;
2112 ApplyOffset
2114 Apply a playback offset to the Source. This function will update the queue (to correctly
2115 mark buffers as 'pending' or 'processed' depending upon the new offset.
2117 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2119 ALbufferlistitem *pBufferList;
2120 ALbuffer *pBuffer;
2121 ALint lBufferSize, lTotalBufferSize;
2122 ALint lByteOffset;
2124 // Get true byte offset
2125 lByteOffset = GetByteOffset(pSource);
2127 // If this is a valid offset apply it
2128 if (lByteOffset != -1)
2130 // Sort out the queue (pending and processed states)
2131 pBufferList = pSource->queue;
2132 lTotalBufferSize = 0;
2133 pSource->BuffersPlayed = 0;
2134 pSource->BuffersProcessed = 0;
2135 while (pBufferList)
2137 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2138 lBufferSize = pBuffer ? pBuffer->size : 0;
2140 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2142 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2143 // update the state to PROCESSED
2144 pSource->BuffersPlayed++;
2146 if (!pSource->bLooping)
2148 pBufferList->bufferstate = PROCESSED;
2149 pSource->BuffersProcessed++;
2152 else if (lTotalBufferSize <= lByteOffset)
2154 // Offset is within this buffer
2155 pBufferList->bufferstate = PENDING;
2157 // Set Current Buffer ID
2158 pSource->ulBufferID = pBufferList->buffer;
2160 // Set current position in this buffer
2161 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2163 // Set Total Bytes Played to Offset
2164 pSource->lBytesPlayed = lByteOffset;
2166 // SW Mixer Positions are in Samples
2167 pSource->position = pSource->BufferPosition /
2168 aluBytesFromFormat(pBuffer->format) /
2169 aluChannelsFromFormat(pBuffer->format);
2171 else
2173 // Offset is before this buffer, so mark as pending
2174 pBufferList->bufferstate = PENDING;
2177 // Increment the TotalBufferSize
2178 lTotalBufferSize += lBufferSize;
2180 // Move on to next buffer in the Queue
2181 pBufferList = pBufferList->next;
2184 else
2186 if (bUpdateContext)
2187 alSetError(AL_INVALID_VALUE);
2190 // Clear Offset
2191 pSource->lOffset = 0;
2196 GetByteOffset
2198 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2199 offset supplied by the application). This takes into account the fact that the buffer format
2200 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2202 static ALint GetByteOffset(ALsource *pSource)
2204 ALbuffer *pBuffer = NULL;
2205 ALbufferlistitem *pBufferList;
2206 ALfloat flBufferFreq;
2207 ALint lChannels;
2208 ALint lByteOffset = -1;
2209 ALint lTotalBufferDataSize;
2211 // Find the first non-NULL Buffer in the Queue
2212 pBufferList = pSource->queue;
2213 while (pBufferList)
2215 if (pBufferList->buffer)
2217 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2218 break;
2220 pBufferList = pBufferList->next;
2223 if (pBuffer)
2225 flBufferFreq = ((ALfloat)pBuffer->frequency);
2226 lChannels = aluChannelsFromFormat(pBuffer->format);
2228 // Determine the ByteOffset (and ensure it is block aligned)
2229 switch (pSource->lOffsetType)
2231 case AL_BYTE_OFFSET:
2232 // Take into consideration the original format
2233 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2234 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2236 // Round down to nearest ADPCM block
2237 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2238 // Multiply by compression rate
2239 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2240 lByteOffset -= (lByteOffset % (lChannels * 2));
2242 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2244 lByteOffset = pSource->lOffset * 4;
2245 lByteOffset -= (lByteOffset % (lChannels * 2));
2247 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2249 lByteOffset = pSource->lOffset * 2;
2250 lByteOffset -= (lByteOffset % (lChannels * 2));
2252 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2254 lByteOffset = pSource->lOffset * 2;
2255 lByteOffset -= (lByteOffset % (lChannels * 2));
2257 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2259 lByteOffset = pSource->lOffset / 2;
2260 lByteOffset -= (lByteOffset % (lChannels * 2));
2262 else
2264 lByteOffset = pSource->lOffset;
2265 lByteOffset -= (lByteOffset % (lChannels * 2));
2267 break;
2269 case AL_SAMPLE_OFFSET:
2270 lByteOffset = pSource->lOffset * lChannels * 2;
2271 break;
2273 case AL_SEC_OFFSET:
2274 // Note - lOffset is internally stored as Milliseconds
2275 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2276 lByteOffset -= (lByteOffset % (lChannels * 2));
2277 break;
2280 lTotalBufferDataSize = 0;
2281 pBufferList = pSource->queue;
2282 while (pBufferList)
2284 if (pBufferList->buffer)
2285 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2286 pBufferList = pBufferList->next;
2289 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2290 if (lByteOffset >= lTotalBufferDataSize)
2291 lByteOffset = -1;
2294 return lByteOffset;
2298 ALvoid ReleaseALSources(ALCcontext *Context)
2300 #ifdef _DEBUG
2301 if(Context->SourceCount > 0)
2302 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2303 #endif
2305 while(Context->Source)
2307 ALsource *temp = Context->Source;
2308 Context->Source = Context->Source->next;
2310 // Release source structure
2311 ALTHUNK_REMOVEENTRY(temp->source);
2312 memset(temp, 0, sizeof(ALsource));
2313 free(temp);
2315 Context->SourceCount = 0;