Remove outdated comments and add copyright header
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blobe130e044d5b713ad43336f13ac34c8345f71db66
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, ALuint updateSize);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = alcGetCurrentContext();
47 if (Context)
49 SuspendContext(Context);
51 if (n > 0)
53 Device = alcGetContextsDevice(Context);
55 if (Device)
57 // Check that enough memory has been allocted in the 'sources' array for n Sources
58 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
60 // Check that the requested number of sources can be generated
61 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
63 ALsource **list = &Context->Source;
64 while(*list)
65 list = &(*list)->next;
67 // Add additional sources to the list (Source->next points to the location for the next Source structure)
68 while(i < n)
70 *list = calloc(1, sizeof(ALsource));
71 if(!(*list))
73 alDeleteSources(i, sources);
74 alSetError(AL_OUT_OF_MEMORY);
75 break;
78 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->source = sources[i];
81 InitSourceParams(*list);
82 Context->SourceCount++;
83 i++;
85 list = &(*list)->next;
88 else
90 // Not enough resources to create the Sources
91 alSetError(AL_INVALID_VALUE);
94 else
96 // Bad pointer
97 alSetError(AL_INVALID_VALUE);
100 else
102 // No Device created, or attached to Context
103 alSetError(AL_INVALID_OPERATION);
107 ProcessContext(Context);
109 else
111 // Invalid Context
112 alSetError(AL_INVALID_OPERATION);
115 return;
119 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
121 ALCcontext *Context;
122 ALCdevice *Device;
123 ALsource *ALSource;
124 ALsource **list;
125 ALsizei i, j;
126 ALbufferlistitem *ALBufferList;
127 ALboolean bSourcesValid = AL_TRUE;
129 Context = alcGetCurrentContext();
130 if (Context)
132 SuspendContext(Context);
134 if (n >= 0)
136 Device = alcGetContextsDevice(Context);
138 if (Device)
140 // Check that all Sources are valid (and can therefore be deleted)
141 for (i = 0; i < n; i++)
143 if (!alIsSource(sources[i]))
145 alSetError(AL_INVALID_NAME);
146 bSourcesValid = AL_FALSE;
147 break;
151 if (bSourcesValid)
153 // All Sources are valid, and can be deleted
154 for (i = 0; i < n; i++)
156 // Recheck that the Source is valid, because there could be duplicated Source names
157 if (alIsSource(sources[i]))
159 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
160 alSourceStop((ALuint)ALSource->source);
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while (ALSource->queue != NULL)
165 ALBufferList = ALSource->queue;
166 // Decrement buffer's reference counter
167 if (ALBufferList->buffer != 0)
168 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
169 // Update queue to point to next element in list
170 ALSource->queue = ALBufferList->next;
171 // Release memory allocated for buffer list item
172 free(ALBufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(ALSource->Send[j].Slot)
178 ALSource->Send[j].Slot->refcount--;
179 ALSource->Send[j].Slot = NULL;
182 // Decrement Source count
183 Context->SourceCount--;
185 // Remove Source from list of Sources
186 list = &Context->Source;
187 while(*list && *list != ALSource)
188 list = &(*list)->next;
190 if(*list)
191 *list = (*list)->next;
192 ALTHUNK_REMOVEENTRY(ALSource->source);
194 memset(ALSource,0,sizeof(ALsource));
195 free(ALSource);
200 else
202 // No Device created, or attached to Context
203 alSetError(AL_INVALID_OPERATION);
206 else
207 alSetError(AL_INVALID_VALUE);
209 ProcessContext(Context);
211 else
213 // Invalid Context
214 alSetError(AL_INVALID_OPERATION);
217 return;
221 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
223 ALboolean result=AL_FALSE;
224 ALCcontext *Context;
225 ALsource *Source;
227 Context=alcGetCurrentContext();
228 if (Context)
230 SuspendContext(Context);
232 // To determine if this is a valid Source name, look through the list of generated Sources
233 Source = Context->Source;
234 while(Source)
236 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
238 result = AL_TRUE;
239 break;
242 Source = Source->next;
245 ProcessContext(Context);
247 else
249 // Invalid Context
250 alSetError(AL_INVALID_OPERATION);
253 return result;
257 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
259 ALCcontext *pContext;
260 ALsource *pSource;
262 pContext = alcGetCurrentContext();
263 if (pContext)
265 SuspendContext(pContext);
267 if (alIsSource(source))
269 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
271 switch (eParam)
273 case AL_PITCH:
274 if (flValue >= 0.0f)
276 pSource->flPitch = flValue;
277 if(pSource->flPitch < 0.001f)
278 pSource->flPitch = 0.001f;
280 else
281 alSetError(AL_INVALID_VALUE);
282 break;
284 case AL_CONE_INNER_ANGLE:
285 if ((flValue >= 0.0f) && (flValue <= 360.0f))
286 pSource->flInnerAngle = flValue;
287 else
288 alSetError(AL_INVALID_VALUE);
289 break;
291 case AL_CONE_OUTER_ANGLE:
292 if ((flValue >= 0.0f) && (flValue <= 360.0f))
293 pSource->flOuterAngle = flValue;
294 else
295 alSetError(AL_INVALID_VALUE);
296 break;
298 case AL_GAIN:
299 if (flValue >= 0.0f)
300 pSource->flGain = flValue;
301 else
302 alSetError(AL_INVALID_VALUE);
303 break;
305 case AL_MAX_DISTANCE:
306 if (flValue >= 0.0f)
307 pSource->flMaxDistance = flValue;
308 else
309 alSetError(AL_INVALID_VALUE);
310 break;
312 case AL_ROLLOFF_FACTOR:
313 if (flValue >= 0.0f)
314 pSource->flRollOffFactor = flValue;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_REFERENCE_DISTANCE:
320 if (flValue >= 0.0f)
321 pSource->flRefDistance = flValue;
322 else
323 alSetError(AL_INVALID_VALUE);
324 break;
326 case AL_MIN_GAIN:
327 if ((flValue >= 0.0f) && (flValue <= 1.0f))
328 pSource->flMinGain = flValue;
329 else
330 alSetError(AL_INVALID_VALUE);
331 break;
333 case AL_MAX_GAIN:
334 if ((flValue >= 0.0f) && (flValue <= 1.0f))
335 pSource->flMaxGain = flValue;
336 else
337 alSetError(AL_INVALID_VALUE);
338 break;
340 case AL_CONE_OUTER_GAIN:
341 if ((flValue >= 0.0f) && (flValue <= 1.0f))
342 pSource->flOuterGain = flValue;
343 else
344 alSetError(AL_INVALID_VALUE);
345 break;
347 case AL_CONE_OUTER_GAINHF:
348 if ((flValue >= 0.0f) && (flValue <= 1.0f))
349 pSource->OuterGainHF = flValue;
350 else
351 alSetError(AL_INVALID_VALUE);
352 break;
354 case AL_AIR_ABSORPTION_FACTOR:
355 if (flValue >= 0.0f && flValue <= 10.0f)
356 pSource->AirAbsorptionFactor = flValue;
357 else
358 alSetError(AL_INVALID_VALUE);
359 break;
361 case AL_ROOM_ROLLOFF_FACTOR:
362 if (flValue >= 0.0f && flValue <= 1.0f)
363 pSource->RoomRolloffFactor = flValue;
364 else
365 alSetError(AL_INVALID_VALUE);
366 break;
368 case AL_DOPPLER_FACTOR:
369 if (flValue >= 0.0f && flValue <= 1.0f)
370 pSource->DopplerFactor = flValue;
371 else
372 alSetError(AL_INVALID_VALUE);
373 break;
375 case AL_SEC_OFFSET:
376 case AL_SAMPLE_OFFSET:
377 case AL_BYTE_OFFSET:
378 if (flValue >= 0.0f)
380 pSource->lOffsetType = eParam;
382 // Store Offset (convert Seconds into Milliseconds)
383 if (eParam == AL_SEC_OFFSET)
384 pSource->lOffset = (ALint)(flValue * 1000.0f);
385 else
386 pSource->lOffset = (ALint)flValue;
388 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
389 ApplyOffset(pSource, AL_TRUE);
391 else
392 alSetError(AL_INVALID_VALUE);
393 break;
395 default:
396 alSetError(AL_INVALID_ENUM);
397 break;
400 else
402 // Invalid Source Name
403 alSetError(AL_INVALID_NAME);
406 ProcessContext(pContext);
408 else
410 // Invalid context
411 alSetError(AL_INVALID_OPERATION);
414 return;
418 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
420 ALCcontext *pContext;
421 ALsource *pSource;
423 pContext = alcGetCurrentContext();
424 if (pContext)
426 SuspendContext(pContext);
428 if (alIsSource(source))
430 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
431 switch(eParam)
433 case AL_POSITION:
434 pSource->vPosition[0] = flValue1;
435 pSource->vPosition[1] = flValue2;
436 pSource->vPosition[2] = flValue3;
437 break;
439 case AL_VELOCITY:
440 pSource->vVelocity[0] = flValue1;
441 pSource->vVelocity[1] = flValue2;
442 pSource->vVelocity[2] = flValue3;
443 break;
445 case AL_DIRECTION:
446 pSource->vOrientation[0] = flValue1;
447 pSource->vOrientation[1] = flValue2;
448 pSource->vOrientation[2] = flValue3;
449 break;
451 default:
452 alSetError(AL_INVALID_ENUM);
453 break;
456 else
457 alSetError(AL_INVALID_NAME);
459 ProcessContext(pContext);
461 else
463 alSetError(AL_INVALID_OPERATION);
466 return;
470 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
472 ALCcontext *pContext;
474 pContext = alcGetCurrentContext();
475 if (pContext)
477 SuspendContext(pContext);
479 if (pflValues)
481 if (alIsSource(source))
483 switch (eParam)
485 case AL_PITCH:
486 case AL_CONE_INNER_ANGLE:
487 case AL_CONE_OUTER_ANGLE:
488 case AL_GAIN:
489 case AL_MAX_DISTANCE:
490 case AL_ROLLOFF_FACTOR:
491 case AL_REFERENCE_DISTANCE:
492 case AL_MIN_GAIN:
493 case AL_MAX_GAIN:
494 case AL_CONE_OUTER_GAIN:
495 case AL_CONE_OUTER_GAINHF:
496 case AL_SEC_OFFSET:
497 case AL_SAMPLE_OFFSET:
498 case AL_BYTE_OFFSET:
499 case AL_AIR_ABSORPTION_FACTOR:
500 case AL_ROOM_ROLLOFF_FACTOR:
501 alSourcef(source, eParam, pflValues[0]);
502 break;
504 case AL_POSITION:
505 case AL_VELOCITY:
506 case AL_DIRECTION:
507 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
508 break;
510 default:
511 alSetError(AL_INVALID_ENUM);
512 break;
515 else
516 alSetError(AL_INVALID_NAME);
518 else
519 alSetError(AL_INVALID_VALUE);
521 ProcessContext(pContext);
523 else
524 alSetError(AL_INVALID_OPERATION);
526 return;
530 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
532 ALCcontext *pContext;
533 ALsource *pSource;
534 ALbufferlistitem *pALBufferListItem;
535 ALint Counter = 0;
536 ALint DataSize = 0;
537 ALint BufferSize;
539 pContext = alcGetCurrentContext();
540 if (pContext)
542 SuspendContext(pContext);
544 if (alIsSource(source))
546 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
548 switch(eParam)
550 case AL_MAX_DISTANCE:
551 case AL_ROLLOFF_FACTOR:
552 case AL_REFERENCE_DISTANCE:
553 alSourcef(source, eParam, (ALfloat)lValue);
554 break;
556 case AL_SOURCE_RELATIVE:
557 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
558 pSource->bHeadRelative = (ALboolean)lValue;
559 else
560 alSetError(AL_INVALID_VALUE);
561 break;
563 case AL_CONE_INNER_ANGLE:
564 if ((lValue >= 0) && (lValue <= 360))
565 pSource->flInnerAngle = (float)lValue;
566 else
567 alSetError(AL_INVALID_VALUE);
568 break;
570 case AL_CONE_OUTER_ANGLE:
571 if ((lValue >= 0) && (lValue <= 360))
572 pSource->flOuterAngle = (float)lValue;
573 else
574 alSetError(AL_INVALID_VALUE);
575 break;
577 case AL_LOOPING:
578 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
579 pSource->bLooping = (ALboolean)lValue;
580 else
581 alSetError(AL_INVALID_VALUE);
582 break;
584 case AL_BUFFER:
585 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
587 if (alIsBuffer(lValue))
589 // Remove all elements in the queue
590 while (pSource->queue != NULL)
592 pALBufferListItem = pSource->queue;
593 pSource->queue = pALBufferListItem->next;
594 // Decrement reference counter for buffer
595 if (pALBufferListItem->buffer)
596 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
597 // Record size of buffer
598 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
599 DataSize += BufferSize;
600 // Increment the number of buffers removed from queue
601 Counter++;
602 // Release memory for buffer list item
603 free(pALBufferListItem);
604 // Decrement the number of buffers in the queue
605 pSource->BuffersInQueue--;
608 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
609 if (lValue != 0)
611 // Source is now in STATIC mode
612 pSource->lSourceType = AL_STATIC;
614 // Add the selected buffer to the queue
615 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
616 pALBufferListItem->buffer = lValue;
617 pALBufferListItem->bufferstate = PENDING;
618 pALBufferListItem->flag = 0;
619 pALBufferListItem->next = NULL;
621 pSource->queue = pALBufferListItem;
622 pSource->BuffersInQueue = 1;
624 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
626 // Increment reference counter for buffer
627 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
629 else
631 // Source is now in UNDETERMINED mode
632 pSource->lSourceType = AL_UNDETERMINED;
635 // Update AL_BUFFER parameter
636 pSource->ulBufferID = lValue;
638 else
639 alSetError(AL_INVALID_VALUE);
641 else
642 alSetError(AL_INVALID_OPERATION);
643 break;
645 case AL_SOURCE_STATE:
646 // Query only
647 alSetError(AL_INVALID_OPERATION);
648 break;
650 case AL_SEC_OFFSET:
651 case AL_SAMPLE_OFFSET:
652 case AL_BYTE_OFFSET:
653 if (lValue >= 0)
655 pSource->lOffsetType = eParam;
657 // Store Offset (convert Seconds into Milliseconds)
658 if (eParam == AL_SEC_OFFSET)
659 pSource->lOffset = lValue * 1000;
660 else
661 pSource->lOffset = lValue;
663 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
664 ApplyOffset(pSource, AL_TRUE);
666 else
667 alSetError(AL_INVALID_VALUE);
668 break;
670 case AL_DIRECT_FILTER:
671 if(alIsFilter(lValue))
673 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
674 if(!filter)
676 pSource->DirectFilter.type = AL_FILTER_NULL;
677 pSource->DirectFilter.filter = 0;
679 else
680 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
682 else
683 alSetError(AL_INVALID_VALUE);
684 break;
686 case AL_DIRECT_FILTER_GAINHF_AUTO:
687 if(lValue == AL_TRUE || lValue == AL_FALSE)
688 pSource->DryGainHFAuto = lValue;
689 else
690 alSetError(AL_INVALID_VALUE);
691 break;
693 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
694 if(lValue == AL_TRUE || lValue == AL_FALSE)
695 pSource->WetGainAuto = lValue;
696 else
697 alSetError(AL_INVALID_VALUE);
698 break;
700 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
701 if(lValue == AL_TRUE || lValue == AL_FALSE)
702 pSource->WetGainHFAuto = lValue;
703 else
704 alSetError(AL_INVALID_VALUE);
705 break;
707 default:
708 alSetError(AL_INVALID_ENUM);
709 break;
712 else
713 alSetError(AL_INVALID_NAME);
715 ProcessContext(pContext);
717 else
718 alSetError(AL_INVALID_OPERATION);
720 return;
724 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
726 ALCcontext *pContext;
728 pContext = alcGetCurrentContext();
729 if (pContext)
731 SuspendContext(pContext);
733 if (alIsSource(source))
735 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
737 switch (eParam)
739 case AL_POSITION:
740 case AL_VELOCITY:
741 case AL_DIRECTION:
742 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
743 break;
745 case AL_AUXILIARY_SEND_FILTER:
746 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
747 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
748 alIsFilter(lValue3))
750 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
751 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
753 /* Release refcount on the previous slot, and add one for
754 * the new slot */
755 if(pSource->Send[lValue2].Slot)
756 pSource->Send[lValue2].Slot->refcount--;
757 pSource->Send[lValue2].Slot = ALEffectSlot;
758 if(pSource->Send[lValue2].Slot)
759 pSource->Send[lValue2].Slot->refcount++;
761 if(!ALFilter)
763 /* Disable filter */
764 pSource->Send[lValue2].WetFilter.type = 0;
765 pSource->Send[lValue2].WetFilter.filter = 0;
767 else
768 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
770 else
771 alSetError(AL_INVALID_VALUE);
772 break;
774 default:
775 alSetError(AL_INVALID_ENUM);
776 break;
779 else
780 alSetError(AL_INVALID_NAME);
782 ProcessContext(pContext);
784 else
785 alSetError(AL_INVALID_OPERATION);
787 return;
791 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
793 ALCcontext *pContext;
795 pContext = alcGetCurrentContext();
796 if (pContext)
798 SuspendContext(pContext);
800 if (plValues)
802 if (alIsSource(source))
804 switch (eParam)
806 case AL_SOURCE_RELATIVE:
807 case AL_CONE_INNER_ANGLE:
808 case AL_CONE_OUTER_ANGLE:
809 case AL_LOOPING:
810 case AL_BUFFER:
811 case AL_SOURCE_STATE:
812 case AL_SEC_OFFSET:
813 case AL_SAMPLE_OFFSET:
814 case AL_BYTE_OFFSET:
815 case AL_MAX_DISTANCE:
816 case AL_ROLLOFF_FACTOR:
817 case AL_REFERENCE_DISTANCE:
818 case AL_DIRECT_FILTER:
819 case AL_DIRECT_FILTER_GAINHF_AUTO:
820 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
821 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
822 alSourcei(source, eParam, plValues[0]);
823 break;
825 case AL_POSITION:
826 case AL_VELOCITY:
827 case AL_DIRECTION:
828 case AL_AUXILIARY_SEND_FILTER:
829 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
830 break;
832 default:
833 alSetError(AL_INVALID_ENUM);
834 break;
837 else
838 alSetError(AL_INVALID_NAME);
840 else
841 alSetError(AL_INVALID_VALUE);
843 ProcessContext(pContext);
845 else
846 alSetError(AL_INVALID_OPERATION);
848 return;
852 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
854 ALCcontext *pContext;
855 ALsource *pSource;
856 ALfloat flOffset[2];
858 pContext = alcGetCurrentContext();
859 if (pContext)
861 SuspendContext(pContext);
863 if (pflValue)
865 if (alIsSource(source))
867 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
869 switch(eParam)
871 case AL_PITCH:
872 *pflValue = pSource->flPitch;
873 break;
875 case AL_GAIN:
876 *pflValue = pSource->flGain;
877 break;
879 case AL_MIN_GAIN:
880 *pflValue = pSource->flMinGain;
881 break;
883 case AL_MAX_GAIN:
884 *pflValue = pSource->flMaxGain;
885 break;
887 case AL_MAX_DISTANCE:
888 *pflValue = pSource->flMaxDistance;
889 break;
891 case AL_ROLLOFF_FACTOR:
892 *pflValue = pSource->flRollOffFactor;
893 break;
895 case AL_CONE_OUTER_GAIN:
896 *pflValue = pSource->flOuterGain;
897 break;
899 case AL_CONE_OUTER_GAINHF:
900 *pflValue = pSource->OuterGainHF;
901 break;
903 case AL_SEC_OFFSET:
904 case AL_SAMPLE_OFFSET:
905 case AL_BYTE_OFFSET:
906 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
907 *pflValue = flOffset[0];
908 else
909 alSetError(AL_INVALID_OPERATION);
910 break;
912 case AL_SEC_RW_OFFSETS_EXT:
913 case AL_SAMPLE_RW_OFFSETS_EXT:
914 case AL_BYTE_RW_OFFSETS_EXT:
915 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
917 pflValue[0] = flOffset[0];
918 pflValue[1] = flOffset[1];
920 else
921 alSetError(AL_INVALID_OPERATION);
922 break;
924 case AL_CONE_INNER_ANGLE:
925 *pflValue = pSource->flInnerAngle;
926 break;
928 case AL_CONE_OUTER_ANGLE:
929 *pflValue = pSource->flOuterAngle;
930 break;
932 case AL_REFERENCE_DISTANCE:
933 *pflValue = pSource->flRefDistance;
934 break;
936 case AL_AIR_ABSORPTION_FACTOR:
937 *pflValue = pSource->AirAbsorptionFactor;
938 break;
940 case AL_ROOM_ROLLOFF_FACTOR:
941 *pflValue = pSource->RoomRolloffFactor;
942 break;
944 case AL_DOPPLER_FACTOR:
945 *pflValue = pSource->DopplerFactor;
946 break;
948 default:
949 alSetError(AL_INVALID_ENUM);
950 break;
953 else
954 alSetError(AL_INVALID_NAME);
956 else
957 alSetError(AL_INVALID_VALUE);
959 ProcessContext(pContext);
961 else
962 alSetError(AL_INVALID_OPERATION);
964 return;
968 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
970 ALCcontext *pContext;
971 ALsource *pSource;
973 pContext = alcGetCurrentContext();
974 if (pContext)
976 SuspendContext(pContext);
978 if ((pflValue1) && (pflValue2) && (pflValue3))
980 if (alIsSource(source))
982 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
984 switch(eParam)
986 case AL_POSITION:
987 *pflValue1 = pSource->vPosition[0];
988 *pflValue2 = pSource->vPosition[1];
989 *pflValue3 = pSource->vPosition[2];
990 break;
992 case AL_VELOCITY:
993 *pflValue1 = pSource->vVelocity[0];
994 *pflValue2 = pSource->vVelocity[1];
995 *pflValue3 = pSource->vVelocity[2];
996 break;
998 case AL_DIRECTION:
999 *pflValue1 = pSource->vOrientation[0];
1000 *pflValue2 = pSource->vOrientation[1];
1001 *pflValue3 = pSource->vOrientation[2];
1002 break;
1004 default:
1005 alSetError(AL_INVALID_ENUM);
1006 break;
1009 else
1010 alSetError(AL_INVALID_NAME);
1012 else
1013 alSetError(AL_INVALID_VALUE);
1015 ProcessContext(pContext);
1017 else
1018 alSetError(AL_INVALID_OPERATION);
1020 return;
1024 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1026 ALCcontext *pContext;
1027 ALsource *pSource;
1029 pContext = alcGetCurrentContext();
1030 if (pContext)
1032 SuspendContext(pContext);
1034 if (pflValues)
1036 if (alIsSource(source))
1038 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1040 switch(eParam)
1042 case AL_PITCH:
1043 case AL_GAIN:
1044 case AL_MIN_GAIN:
1045 case AL_MAX_GAIN:
1046 case AL_MAX_DISTANCE:
1047 case AL_ROLLOFF_FACTOR:
1048 case AL_DOPPLER_FACTOR:
1049 case AL_CONE_OUTER_GAIN:
1050 case AL_SEC_OFFSET:
1051 case AL_SAMPLE_OFFSET:
1052 case AL_BYTE_OFFSET:
1053 case AL_CONE_INNER_ANGLE:
1054 case AL_CONE_OUTER_ANGLE:
1055 case AL_REFERENCE_DISTANCE:
1056 case AL_CONE_OUTER_GAINHF:
1057 case AL_AIR_ABSORPTION_FACTOR:
1058 case AL_ROOM_ROLLOFF_FACTOR:
1059 alGetSourcef(source, eParam, pflValues);
1060 break;
1062 case AL_POSITION:
1063 pflValues[0] = pSource->vPosition[0];
1064 pflValues[1] = pSource->vPosition[1];
1065 pflValues[2] = pSource->vPosition[2];
1066 break;
1068 case AL_VELOCITY:
1069 pflValues[0] = pSource->vVelocity[0];
1070 pflValues[1] = pSource->vVelocity[1];
1071 pflValues[2] = pSource->vVelocity[2];
1072 break;
1074 case AL_DIRECTION:
1075 pflValues[0] = pSource->vOrientation[0];
1076 pflValues[1] = pSource->vOrientation[1];
1077 pflValues[2] = pSource->vOrientation[2];
1078 break;
1080 default:
1081 alSetError(AL_INVALID_ENUM);
1082 break;
1085 else
1086 alSetError(AL_INVALID_NAME);
1088 else
1089 alSetError(AL_INVALID_VALUE);
1091 ProcessContext(pContext);
1093 else
1094 alSetError(AL_INVALID_OPERATION);
1096 return;
1100 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1102 ALCcontext *pContext;
1103 ALsource *pSource;
1104 ALfloat flOffset[2];
1106 pContext = alcGetCurrentContext();
1107 if (pContext)
1109 SuspendContext(pContext);
1111 if (plValue)
1113 if (alIsSource(source))
1115 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1117 switch(eParam)
1119 case AL_MAX_DISTANCE:
1120 *plValue = (ALint)pSource->flMaxDistance;
1121 break;
1123 case AL_ROLLOFF_FACTOR:
1124 *plValue = (ALint)pSource->flRollOffFactor;
1125 break;
1127 case AL_REFERENCE_DISTANCE:
1128 *plValue = (ALint)pSource->flRefDistance;
1129 break;
1131 case AL_SOURCE_RELATIVE:
1132 *plValue = pSource->bHeadRelative;
1133 break;
1135 case AL_CONE_INNER_ANGLE:
1136 *plValue = (ALint)pSource->flInnerAngle;
1137 break;
1139 case AL_CONE_OUTER_ANGLE:
1140 *plValue = (ALint)pSource->flOuterAngle;
1141 break;
1143 case AL_LOOPING:
1144 *plValue = pSource->bLooping;
1145 break;
1147 case AL_BUFFER:
1148 *plValue = pSource->ulBufferID;
1149 break;
1151 case AL_SOURCE_STATE:
1152 *plValue = pSource->state;
1153 break;
1155 case AL_BUFFERS_QUEUED:
1156 *plValue = pSource->BuffersInQueue;
1157 break;
1159 case AL_BUFFERS_PROCESSED:
1160 if(pSource->bLooping)
1162 /* Buffers on a looping source are in a perpetual state
1163 * of PENDING, so don't report any as PROCESSED */
1164 *plValue = 0;
1166 else
1167 *plValue = pSource->BuffersPlayed;
1168 break;
1170 case AL_SOURCE_TYPE:
1171 *plValue = pSource->lSourceType;
1172 break;
1174 case AL_SEC_OFFSET:
1175 case AL_SAMPLE_OFFSET:
1176 case AL_BYTE_OFFSET:
1177 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1178 *plValue = (ALint)flOffset[0];
1179 else
1180 alSetError(AL_INVALID_OPERATION);
1181 break;
1183 case AL_SEC_RW_OFFSETS_EXT:
1184 case AL_SAMPLE_RW_OFFSETS_EXT:
1185 case AL_BYTE_RW_OFFSETS_EXT:
1186 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1188 plValue[0] = (ALint)flOffset[0];
1189 plValue[1] = (ALint)flOffset[1];
1191 else
1192 alSetError(AL_INVALID_OPERATION);
1193 break;
1195 case AL_DIRECT_FILTER:
1196 *plValue = pSource->DirectFilter.filter;
1197 break;
1199 case AL_DIRECT_FILTER_GAINHF_AUTO:
1200 *plValue = pSource->DryGainHFAuto;
1201 break;
1203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1204 *plValue = pSource->WetGainAuto;
1205 break;
1207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1208 *plValue = pSource->WetGainHFAuto;
1209 break;
1211 case AL_DOPPLER_FACTOR:
1212 *plValue = (ALint)pSource->DopplerFactor;
1213 break;
1215 default:
1216 alSetError(AL_INVALID_ENUM);
1217 break;
1220 else
1221 alSetError(AL_INVALID_NAME);
1223 else
1224 alSetError(AL_INVALID_VALUE);
1226 ProcessContext(pContext);
1228 else
1229 alSetError(AL_INVALID_OPERATION);
1231 return;
1235 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1237 ALCcontext *pContext;
1238 ALsource *pSource;
1240 pContext = alcGetCurrentContext();
1241 if (pContext)
1243 SuspendContext(pContext);
1245 if ((plValue1) && (plValue2) && (plValue3))
1247 if (alIsSource(source))
1249 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1251 switch(eParam)
1253 case AL_POSITION:
1254 *plValue1 = (ALint)pSource->vPosition[0];
1255 *plValue2 = (ALint)pSource->vPosition[1];
1256 *plValue3 = (ALint)pSource->vPosition[2];
1257 break;
1259 case AL_VELOCITY:
1260 *plValue1 = (ALint)pSource->vVelocity[0];
1261 *plValue2 = (ALint)pSource->vVelocity[1];
1262 *plValue3 = (ALint)pSource->vVelocity[2];
1263 break;
1265 case AL_DIRECTION:
1266 *plValue1 = (ALint)pSource->vOrientation[0];
1267 *plValue2 = (ALint)pSource->vOrientation[1];
1268 *plValue3 = (ALint)pSource->vOrientation[2];
1269 break;
1271 default:
1272 alSetError(AL_INVALID_ENUM);
1273 break;
1276 else
1277 alSetError(AL_INVALID_NAME);
1279 else
1280 alSetError(AL_INVALID_VALUE);
1282 ProcessContext(pContext);
1284 else
1285 alSetError(AL_INVALID_OPERATION);
1287 return;
1291 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1293 ALCcontext *pContext;
1294 ALsource *pSource;
1296 pContext = alcGetCurrentContext();
1297 if (pContext)
1299 SuspendContext(pContext);
1301 if (plValues)
1303 if (alIsSource(source))
1305 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1307 switch (eParam)
1309 case AL_SOURCE_RELATIVE:
1310 case AL_CONE_INNER_ANGLE:
1311 case AL_CONE_OUTER_ANGLE:
1312 case AL_LOOPING:
1313 case AL_BUFFER:
1314 case AL_SOURCE_STATE:
1315 case AL_BUFFERS_QUEUED:
1316 case AL_BUFFERS_PROCESSED:
1317 case AL_SEC_OFFSET:
1318 case AL_SAMPLE_OFFSET:
1319 case AL_BYTE_OFFSET:
1320 case AL_MAX_DISTANCE:
1321 case AL_ROLLOFF_FACTOR:
1322 case AL_DOPPLER_FACTOR:
1323 case AL_REFERENCE_DISTANCE:
1324 case AL_SOURCE_TYPE:
1325 case AL_DIRECT_FILTER:
1326 case AL_DIRECT_FILTER_GAINHF_AUTO:
1327 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1328 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1329 alGetSourcei(source, eParam, plValues);
1330 break;
1332 case AL_POSITION:
1333 plValues[0] = (ALint)pSource->vPosition[0];
1334 plValues[1] = (ALint)pSource->vPosition[1];
1335 plValues[2] = (ALint)pSource->vPosition[2];
1336 break;
1338 case AL_VELOCITY:
1339 plValues[0] = (ALint)pSource->vVelocity[0];
1340 plValues[1] = (ALint)pSource->vVelocity[1];
1341 plValues[2] = (ALint)pSource->vVelocity[2];
1342 break;
1344 case AL_DIRECTION:
1345 plValues[0] = (ALint)pSource->vOrientation[0];
1346 plValues[1] = (ALint)pSource->vOrientation[1];
1347 plValues[2] = (ALint)pSource->vOrientation[2];
1348 break;
1350 default:
1351 alSetError(AL_INVALID_ENUM);
1352 break;
1355 else
1356 alSetError(AL_INVALID_NAME);
1358 else
1359 alSetError(AL_INVALID_VALUE);
1361 ProcessContext(pContext);
1363 else
1364 alSetError(AL_INVALID_OPERATION);
1366 return;
1370 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1372 alSourcePlayv(1, &source);
1373 return;
1376 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1378 ALCcontext *pContext;
1379 ALsource *pSource;
1380 ALbufferlistitem *ALBufferList;
1381 ALboolean bSourcesValid = AL_TRUE;
1382 ALboolean bPlay;
1383 ALsizei i, j;
1385 pContext = alcGetCurrentContext();
1386 if (pContext)
1388 SuspendContext(pContext);
1390 if (pSourceList)
1392 // Check that all the Sources are valid
1393 for (i = 0; i < n; i++)
1395 if (!alIsSource(pSourceList[i]))
1397 alSetError(AL_INVALID_NAME);
1398 bSourcesValid = AL_FALSE;
1399 break;
1403 if (bSourcesValid)
1405 for (i = 0; i < n; i++)
1407 // Assume Source won't need to play
1408 bPlay = AL_FALSE;
1410 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1412 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1413 ALBufferList = pSource->queue;
1414 while (ALBufferList)
1416 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1418 bPlay = AL_TRUE;
1419 break;
1421 ALBufferList = ALBufferList->next;
1424 if (bPlay)
1426 for(j = 0;j < OUTPUTCHANNELS;j++)
1427 pSource->DryGains[j] = 0.0f;
1428 pSource->WetGain = 0.0f;
1430 if (pSource->state != AL_PAUSED)
1432 pSource->state = AL_PLAYING;
1433 pSource->inuse = AL_TRUE;
1434 pSource->play = AL_TRUE;
1435 pSource->position = 0;
1436 pSource->position_fraction = 0;
1437 pSource->BuffersPlayed = 0;
1438 pSource->FirstStart = AL_TRUE;
1440 pSource->ulBufferID = pSource->queue->buffer;
1442 // Make sure all the Buffers in the queue are marked as PENDING
1443 ALBufferList = pSource->queue;
1444 while (ALBufferList)
1446 ALBufferList->bufferstate = PENDING;
1447 ALBufferList = ALBufferList->next;
1450 else
1452 pSource->state = AL_PLAYING;
1453 pSource->inuse = AL_TRUE;
1454 pSource->play = AL_TRUE;
1455 pSource->FirstStart = AL_FALSE;
1458 // Check if an Offset has been set
1459 if (pSource->lOffset)
1460 ApplyOffset(pSource, AL_FALSE);
1462 else
1464 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1465 ALBufferList = pSource->queue;
1466 while (ALBufferList)
1468 ALBufferList->bufferstate = PROCESSED;
1469 ALBufferList = ALBufferList->next;
1472 pSource->BuffersPlayed = pSource->BuffersInQueue;
1477 else
1479 // sources is a NULL pointer
1480 alSetError(AL_INVALID_VALUE);
1483 ProcessContext(pContext);
1485 else
1487 // Invalid Context
1488 alSetError(AL_INVALID_OPERATION);
1491 return;
1494 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1496 alSourcePausev(1, &source);
1497 return;
1500 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1502 ALCcontext *Context;
1503 ALsource *Source;
1504 ALsizei i;
1505 ALboolean bSourcesValid = AL_TRUE;
1507 Context=alcGetCurrentContext();
1508 if (Context)
1510 SuspendContext(Context);
1512 if (sources)
1514 // Check all the Sources are valid
1515 for (i=0;i<n;i++)
1517 if (!alIsSource(sources[i]))
1519 alSetError(AL_INVALID_NAME);
1520 bSourcesValid = AL_FALSE;
1521 break;
1525 if (bSourcesValid)
1527 for (i=0;i<n;i++)
1529 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1530 if (Source->state==AL_PLAYING)
1532 Source->state=AL_PAUSED;
1533 Source->inuse=AL_FALSE;
1538 else
1540 // sources is a NULL pointer
1541 alSetError(AL_INVALID_VALUE);
1544 ProcessContext(Context);
1546 else
1548 // Invalid Context
1549 alSetError(AL_INVALID_OPERATION);
1552 return;
1555 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1557 alSourceStopv(1, &source);
1558 return;
1561 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1563 ALCcontext *Context;
1564 ALsource *Source;
1565 ALsizei i;
1566 ALbufferlistitem *ALBufferListItem;
1567 ALboolean bSourcesValid = AL_TRUE;
1569 Context=alcGetCurrentContext();
1570 if (Context)
1572 SuspendContext(Context);
1574 if (sources)
1576 // Check all the Sources are valid
1577 for (i=0;i<n;i++)
1579 if (!alIsSource(sources[i]))
1581 alSetError(AL_INVALID_NAME);
1582 bSourcesValid = AL_FALSE;
1583 break;
1587 if (bSourcesValid)
1589 for (i=0;i<n;i++)
1591 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1592 if (Source->state!=AL_INITIAL)
1594 Source->state=AL_STOPPED;
1595 Source->inuse=AL_FALSE;
1596 Source->BuffersPlayed = Source->BuffersInQueue;
1597 ALBufferListItem= Source->queue;
1598 while (ALBufferListItem != NULL)
1600 ALBufferListItem->bufferstate = PROCESSED;
1601 ALBufferListItem = ALBufferListItem->next;
1604 Source->lOffset = 0;
1608 else
1610 // sources is a NULL pointer
1611 alSetError(AL_INVALID_VALUE);
1614 ProcessContext(Context);
1616 else
1618 // Invalid Context
1619 alSetError(AL_INVALID_OPERATION);
1622 return;
1625 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1627 alSourceRewindv(1, &source);
1628 return;
1631 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1633 ALCcontext *Context;
1634 ALsource *Source;
1635 ALsizei i;
1636 ALbufferlistitem *ALBufferListItem;
1637 ALboolean bSourcesValid = AL_TRUE;
1639 Context=alcGetCurrentContext();
1640 if (Context)
1642 SuspendContext(Context);
1644 if (sources)
1646 // Check all the Sources are valid
1647 for (i=0;i<n;i++)
1649 if (!alIsSource(sources[i]))
1651 alSetError(AL_INVALID_NAME);
1652 bSourcesValid = AL_FALSE;
1653 break;
1657 if (bSourcesValid)
1659 for (i=0;i<n;i++)
1661 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1662 if (Source->state!=AL_INITIAL)
1664 Source->state=AL_INITIAL;
1665 Source->inuse=AL_FALSE;
1666 Source->position=0;
1667 Source->position_fraction=0;
1668 Source->BuffersPlayed = 0;
1669 ALBufferListItem= Source->queue;
1670 while (ALBufferListItem != NULL)
1672 ALBufferListItem->bufferstate = PENDING;
1673 ALBufferListItem = ALBufferListItem->next;
1675 if (Source->queue)
1676 Source->ulBufferID = Source->queue->buffer;
1678 Source->lOffset = 0;
1682 else
1684 // sources is a NULL pointer
1685 alSetError(AL_INVALID_VALUE);
1688 ProcessContext(Context);
1690 else
1692 // Invalid Context
1693 alSetError(AL_INVALID_OPERATION);
1696 return;
1700 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1702 ALCcontext *Context;
1703 ALsource *ALSource;
1704 ALsizei i;
1705 ALbufferlistitem *ALBufferList;
1706 ALbufferlistitem *ALBufferListStart;
1707 ALuint DataSize;
1708 ALuint BufferSize;
1709 ALint iFrequency;
1710 ALint iFormat;
1711 ALboolean bBuffersValid = AL_TRUE;
1713 if (n == 0)
1714 return;
1716 Context=alcGetCurrentContext();
1717 if (Context)
1719 SuspendContext(Context);
1721 DataSize = 0;
1722 BufferSize = 0;
1724 // Check that all buffers are valid or zero and that the source is valid
1726 // Check that this is a valid source
1727 if (alIsSource(source))
1729 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1731 // Check that this is not a STATIC Source
1732 if (ALSource->lSourceType != AL_STATIC)
1734 iFrequency = -1;
1735 iFormat = -1;
1737 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1738 ALBufferList = ALSource->queue;
1739 while (ALBufferList)
1741 if (ALBufferList->buffer)
1743 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1744 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1745 break;
1747 ALBufferList = ALBufferList->next;
1750 for (i = 0; i < n; i++)
1752 if (alIsBuffer(buffers[i]))
1754 if (buffers[i])
1756 if ((iFrequency == -1) && (iFormat == -1))
1758 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1759 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1761 else
1763 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1764 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1766 alSetError(AL_INVALID_OPERATION);
1767 bBuffersValid = AL_FALSE;
1768 break;
1773 else
1775 alSetError(AL_INVALID_NAME);
1776 bBuffersValid = AL_FALSE;
1777 break;
1781 if (bBuffersValid)
1783 // Change Source Type
1784 ALSource->lSourceType = AL_STREAMING;
1786 // All buffers are valid - so add them to the list
1787 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1788 ALBufferListStart->buffer = buffers[0];
1789 ALBufferListStart->bufferstate = PENDING;
1790 ALBufferListStart->flag = 0;
1791 ALBufferListStart->next = NULL;
1793 if (buffers[0])
1794 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1795 else
1796 BufferSize = 0;
1798 DataSize += BufferSize;
1800 // Increment reference counter for buffer
1801 if (buffers[0])
1802 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1804 ALBufferList = ALBufferListStart;
1806 for (i = 1; i < n; i++)
1808 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1809 ALBufferList->next->buffer = buffers[i];
1810 ALBufferList->next->bufferstate = PENDING;
1811 ALBufferList->next->flag = 0;
1812 ALBufferList->next->next = NULL;
1814 if (buffers[i])
1815 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1816 else
1817 BufferSize = 0;
1819 DataSize += BufferSize;
1821 // Increment reference counter for buffer
1822 if (buffers[i])
1823 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1825 ALBufferList = ALBufferList->next;
1828 if (ALSource->queue == NULL)
1830 ALSource->queue = ALBufferListStart;
1831 // Update Current Buffer
1832 ALSource->ulBufferID = ALBufferListStart->buffer;
1834 else
1836 // Find end of queue
1837 ALBufferList = ALSource->queue;
1838 while (ALBufferList->next != NULL)
1840 ALBufferList = ALBufferList->next;
1843 ALBufferList->next = ALBufferListStart;
1846 // Update number of buffers in queue
1847 ALSource->BuffersInQueue += n;
1850 else
1852 // Invalid Source Type (can't queue on a Static Source)
1853 alSetError(AL_INVALID_OPERATION);
1856 else
1858 // Invalid Source Name
1859 alSetError(AL_INVALID_NAME);
1862 ProcessContext(Context);
1864 else
1866 // Invalid Context
1867 alSetError(AL_INVALID_OPERATION);
1870 return;
1874 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1875 // an array of buffer IDs that are to be filled with the names of the buffers removed
1876 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1878 ALCcontext *Context;
1879 ALsource *ALSource;
1880 ALsizei i;
1881 ALbufferlistitem *ALBufferList;
1882 ALuint DataSize;
1883 ALuint BufferSize;
1884 ALuint BufferID;
1885 ALboolean bBuffersProcessed;
1887 if (n == 0)
1888 return;
1890 DataSize = 0;
1891 BufferSize = 0;
1892 bBuffersProcessed = AL_TRUE;
1894 Context=alcGetCurrentContext();
1895 if (Context)
1897 SuspendContext(Context);
1899 if (alIsSource(source))
1901 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1903 // Check that all 'n' buffers have been processed
1904 ALBufferList = ALSource->queue;
1905 for (i = 0; i < n; i++)
1907 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1909 ALBufferList = ALBufferList->next;
1911 else
1913 bBuffersProcessed = AL_FALSE;
1914 break;
1918 // If all 'n' buffers have been processed, remove them from the queue
1919 if (bBuffersProcessed)
1921 for (i = 0; i < n; i++)
1923 ALBufferList = ALSource->queue;
1925 ALSource->queue = ALBufferList->next;
1926 // Record name of buffer
1927 buffers[i] = ALBufferList->buffer;
1928 // Decrement buffer reference counter
1929 if (ALBufferList->buffer)
1930 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1931 // Record size of buffer
1932 if (ALBufferList->buffer)
1933 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1934 else
1935 BufferSize = 0;
1937 DataSize += BufferSize;
1938 // Release memory for buffer list item
1939 free(ALBufferList);
1940 ALSource->BuffersInQueue--;
1943 if (ALSource->state != AL_PLAYING)
1945 if (ALSource->queue)
1946 BufferID = ALSource->queue->buffer;
1947 else
1948 BufferID = 0;
1950 ALSource->ulBufferID = BufferID;
1953 if((ALuint)n > ALSource->BuffersPlayed)
1954 ALSource->BuffersPlayed = 0;
1955 else
1956 ALSource->BuffersPlayed -= n;
1958 else
1960 // Some buffers can't be unqueue because they have not been processed
1961 alSetError(AL_INVALID_VALUE);
1964 else
1966 // Invalid Source Name
1967 alSetError(AL_INVALID_NAME);
1970 ProcessContext(Context);
1972 else
1974 // Invalid Context
1975 alSetError(AL_INVALID_OPERATION);
1978 return;
1982 static ALvoid InitSourceParams(ALsource *pSource)
1984 pSource->flInnerAngle = 360.0f;
1985 pSource->flOuterAngle = 360.0f;
1986 pSource->flPitch = 1.0f;
1987 pSource->vPosition[0] = 0.0f;
1988 pSource->vPosition[1] = 0.0f;
1989 pSource->vPosition[2] = 0.0f;
1990 pSource->vOrientation[0] = 0.0f;
1991 pSource->vOrientation[1] = 0.0f;
1992 pSource->vOrientation[2] = 0.0f;
1993 pSource->vVelocity[0] = 0.0f;
1994 pSource->vVelocity[1] = 0.0f;
1995 pSource->vVelocity[2] = 0.0f;
1996 pSource->flRefDistance = 1.0f;
1997 pSource->flMaxDistance = FLT_MAX;
1998 pSource->flRollOffFactor = 1.0f;
1999 pSource->bLooping = AL_FALSE;
2000 pSource->flGain = 1.0f;
2001 pSource->flMinGain = 0.0f;
2002 pSource->flMaxGain = 1.0f;
2003 pSource->flOuterGain = 0.0f;
2004 pSource->OuterGainHF = 1.0f;
2006 pSource->DryGainHFAuto = AL_TRUE;
2007 pSource->WetGainAuto = AL_TRUE;
2008 pSource->WetGainHFAuto = AL_TRUE;
2009 pSource->AirAbsorptionFactor = 0.0f;
2010 pSource->RoomRolloffFactor = 0.0f;
2011 pSource->DopplerFactor = 1.0f;
2013 pSource->state = AL_INITIAL;
2014 pSource->lSourceType = AL_UNDETERMINED;
2016 pSource->ulBufferID= 0;
2021 GetSourceOffset
2023 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2024 The offset is relative to the start of the queue (not the start of the current buffer)
2026 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
2028 ALbufferlistitem *pBufferList;
2029 ALbuffer *pBuffer;
2030 ALfloat flBufferFreq;
2031 ALint lChannels;
2032 ALint readPos, writePos;
2033 ALenum eOriginalFormat;
2034 ALboolean bReturn = AL_TRUE;
2035 ALint lTotalBufferDataSize;
2037 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2039 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2040 // Get Current Buffer Size and frequency (in milliseconds)
2041 flBufferFreq = (ALfloat)pBuffer->frequency;
2042 eOriginalFormat = pBuffer->eOriginalFormat;
2043 lChannels = aluChannelsFromFormat(pBuffer->format);
2045 // Get Current BytesPlayed
2046 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2047 // Add byte length of any processed buffers in the queue
2048 pBufferList = pSource->queue;
2049 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2051 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2052 pBufferList = pBufferList->next;
2055 if(pSource->state == AL_PLAYING)
2056 writePos = readPos + (updateSize * lChannels * 2);
2057 else
2058 writePos = readPos;
2060 lTotalBufferDataSize = 0;
2061 pBufferList = pSource->queue;
2062 while (pBufferList)
2064 if (pBufferList->buffer)
2065 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2066 pBufferList = pBufferList->next;
2069 if (pSource->bLooping)
2071 if(readPos < 0)
2072 readPos = 0;
2073 else
2074 readPos %= lTotalBufferDataSize;
2075 if(writePos < 0)
2076 writePos = 0;
2077 else
2078 writePos %= lTotalBufferDataSize;
2080 else
2082 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2083 if(readPos < 0)
2084 readPos = 0;
2085 else if(readPos > lTotalBufferDataSize)
2086 readPos = lTotalBufferDataSize;
2087 if(writePos < 0)
2088 writePos = 0;
2089 else if(writePos > lTotalBufferDataSize)
2090 writePos = lTotalBufferDataSize;
2093 switch (eName)
2095 case AL_SEC_OFFSET:
2096 case AL_SEC_RW_OFFSETS_EXT:
2097 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
2098 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
2099 break;
2100 case AL_SAMPLE_OFFSET:
2101 case AL_SAMPLE_RW_OFFSETS_EXT:
2102 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
2103 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
2104 break;
2105 case AL_BYTE_OFFSET:
2106 case AL_BYTE_RW_OFFSETS_EXT:
2107 // Take into account the original format of the Buffer
2108 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2109 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2111 // Round down to nearest ADPCM block
2112 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
2113 if(pSource->state == AL_PLAYING)
2115 // Round up to nearest ADPCM block
2116 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
2118 else
2119 pflOffset[1] = pflOffset[0];
2121 else if (eOriginalFormat == AL_FORMAT_REAR8)
2123 pflOffset[0] = (ALfloat)(readPos >> 2);
2124 pflOffset[1] = (ALfloat)(writePos >> 2);
2126 else if (eOriginalFormat == AL_FORMAT_REAR16)
2128 pflOffset[0] = (ALfloat)(readPos >> 1);
2129 pflOffset[1] = (ALfloat)(writePos >> 1);
2131 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2133 pflOffset[0] = (ALfloat)(readPos >> 1);
2134 pflOffset[1] = (ALfloat)(writePos >> 1);
2136 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2138 pflOffset[0] = (ALfloat)(readPos << 1);
2139 pflOffset[1] = (ALfloat)(writePos << 1);
2141 else
2143 pflOffset[0] = (ALfloat)readPos;
2144 pflOffset[1] = (ALfloat)writePos;
2146 break;
2149 else
2151 pflOffset[0] = 0.0f;
2152 pflOffset[1] = 0.0f;
2155 return bReturn;
2160 ApplyOffset
2162 Apply a playback offset to the Source. This function will update the queue (to correctly
2163 mark buffers as 'pending' or 'processed' depending upon the new offset.
2165 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2167 ALbufferlistitem *pBufferList;
2168 ALbuffer *pBuffer;
2169 ALint lBufferSize, lTotalBufferSize;
2170 ALint lByteOffset;
2172 // Get true byte offset
2173 lByteOffset = GetByteOffset(pSource);
2175 // If this is a valid offset apply it
2176 if (lByteOffset != -1)
2178 // Sort out the queue (pending and processed states)
2179 pBufferList = pSource->queue;
2180 lTotalBufferSize = 0;
2181 pSource->BuffersPlayed = 0;
2182 while (pBufferList)
2184 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2185 lBufferSize = pBuffer ? pBuffer->size : 0;
2187 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2189 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2190 // update the state to PROCESSED
2191 pSource->BuffersPlayed++;
2193 if (!pSource->bLooping)
2194 pBufferList->bufferstate = PROCESSED;
2196 else if (lTotalBufferSize <= lByteOffset)
2198 // Offset is within this buffer
2199 pBufferList->bufferstate = PENDING;
2201 // Set Current Buffer ID
2202 pSource->ulBufferID = pBufferList->buffer;
2204 // SW Mixer Positions are in Samples
2205 pSource->position = (lByteOffset - lTotalBufferSize) /
2206 aluBytesFromFormat(pBuffer->format) /
2207 aluChannelsFromFormat(pBuffer->format);
2209 else
2211 // Offset is before this buffer, so mark as pending
2212 pBufferList->bufferstate = PENDING;
2215 // Increment the TotalBufferSize
2216 lTotalBufferSize += lBufferSize;
2218 // Move on to next buffer in the Queue
2219 pBufferList = pBufferList->next;
2222 else
2224 if (bUpdateContext)
2225 alSetError(AL_INVALID_VALUE);
2228 // Clear Offset
2229 pSource->lOffset = 0;
2234 GetByteOffset
2236 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2237 offset supplied by the application). This takes into account the fact that the buffer format
2238 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2240 static ALint GetByteOffset(ALsource *pSource)
2242 ALbuffer *pBuffer = NULL;
2243 ALbufferlistitem *pBufferList;
2244 ALfloat flBufferFreq;
2245 ALint lChannels;
2246 ALint lByteOffset = -1;
2247 ALint lTotalBufferDataSize;
2249 // Find the first non-NULL Buffer in the Queue
2250 pBufferList = pSource->queue;
2251 while (pBufferList)
2253 if (pBufferList->buffer)
2255 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2256 break;
2258 pBufferList = pBufferList->next;
2261 if (pBuffer)
2263 flBufferFreq = ((ALfloat)pBuffer->frequency);
2264 lChannels = aluChannelsFromFormat(pBuffer->format);
2266 // Determine the ByteOffset (and ensure it is block aligned)
2267 switch (pSource->lOffsetType)
2269 case AL_BYTE_OFFSET:
2270 // Take into consideration the original format
2271 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2272 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2274 // Round down to nearest ADPCM block
2275 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2276 // Multiply by compression rate
2277 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2278 lByteOffset -= (lByteOffset % (lChannels * 2));
2280 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2282 lByteOffset = pSource->lOffset * 4;
2283 lByteOffset -= (lByteOffset % (lChannels * 2));
2285 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2287 lByteOffset = pSource->lOffset * 2;
2288 lByteOffset -= (lByteOffset % (lChannels * 2));
2290 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2292 lByteOffset = pSource->lOffset * 2;
2293 lByteOffset -= (lByteOffset % (lChannels * 2));
2295 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2297 lByteOffset = pSource->lOffset / 2;
2298 lByteOffset -= (lByteOffset % (lChannels * 2));
2300 else
2302 lByteOffset = pSource->lOffset;
2303 lByteOffset -= (lByteOffset % (lChannels * 2));
2305 break;
2307 case AL_SAMPLE_OFFSET:
2308 lByteOffset = pSource->lOffset * lChannels * 2;
2309 break;
2311 case AL_SEC_OFFSET:
2312 // Note - lOffset is internally stored as Milliseconds
2313 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2314 lByteOffset -= (lByteOffset % (lChannels * 2));
2315 break;
2318 lTotalBufferDataSize = 0;
2319 pBufferList = pSource->queue;
2320 while (pBufferList)
2322 if (pBufferList->buffer)
2323 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2324 pBufferList = pBufferList->next;
2327 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2328 if (lByteOffset >= lTotalBufferDataSize)
2329 lByteOffset = -1;
2332 return lByteOffset;
2336 ALvoid ReleaseALSources(ALCcontext *Context)
2338 #ifdef _DEBUG
2339 if(Context->SourceCount > 0)
2340 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2341 #endif
2343 while(Context->Source)
2345 ALsource *temp = Context->Source;
2346 Context->Source = Context->Source->next;
2348 // Release source structure
2349 ALTHUNK_REMOVEENTRY(temp->source);
2350 memset(temp, 0, sizeof(ALsource));
2351 free(temp);
2353 Context->SourceCount = 0;