Don't read stereo layout when output is mono
[openal-soft.git] / OpenAL32 / alSource.c
blobf1ce4e8507b97640b57125d5a9aa951e5cb8972b
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(ALCcontext *Context, 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(Context, *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 case AL_DISTANCE_MODEL:
708 if(lValue == AL_NONE ||
709 lValue == AL_INVERSE_DISTANCE ||
710 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
711 lValue == AL_LINEAR_DISTANCE ||
712 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
713 lValue == AL_EXPONENT_DISTANCE ||
714 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
715 pSource->DistanceModel = lValue;
716 else
717 alSetError(AL_INVALID_VALUE);
718 break;
720 default:
721 alSetError(AL_INVALID_ENUM);
722 break;
725 else
726 alSetError(AL_INVALID_NAME);
728 ProcessContext(pContext);
730 else
731 alSetError(AL_INVALID_OPERATION);
733 return;
737 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
739 ALCcontext *pContext;
741 pContext = alcGetCurrentContext();
742 if (pContext)
744 SuspendContext(pContext);
746 if (alIsSource(source))
748 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
750 switch (eParam)
752 case AL_POSITION:
753 case AL_VELOCITY:
754 case AL_DIRECTION:
755 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
756 break;
758 case AL_AUXILIARY_SEND_FILTER:
759 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
760 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
761 alIsFilter(lValue3))
763 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
764 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
766 /* Release refcount on the previous slot, and add one for
767 * the new slot */
768 if(pSource->Send[lValue2].Slot)
769 pSource->Send[lValue2].Slot->refcount--;
770 pSource->Send[lValue2].Slot = ALEffectSlot;
771 if(pSource->Send[lValue2].Slot)
772 pSource->Send[lValue2].Slot->refcount++;
774 if(!ALFilter)
776 /* Disable filter */
777 pSource->Send[lValue2].WetFilter.type = 0;
778 pSource->Send[lValue2].WetFilter.filter = 0;
780 else
781 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
783 else
784 alSetError(AL_INVALID_VALUE);
785 break;
787 default:
788 alSetError(AL_INVALID_ENUM);
789 break;
792 else
793 alSetError(AL_INVALID_NAME);
795 ProcessContext(pContext);
797 else
798 alSetError(AL_INVALID_OPERATION);
800 return;
804 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
806 ALCcontext *pContext;
808 pContext = alcGetCurrentContext();
809 if (pContext)
811 SuspendContext(pContext);
813 if (plValues)
815 if (alIsSource(source))
817 switch (eParam)
819 case AL_SOURCE_RELATIVE:
820 case AL_CONE_INNER_ANGLE:
821 case AL_CONE_OUTER_ANGLE:
822 case AL_LOOPING:
823 case AL_BUFFER:
824 case AL_SOURCE_STATE:
825 case AL_SEC_OFFSET:
826 case AL_SAMPLE_OFFSET:
827 case AL_BYTE_OFFSET:
828 case AL_MAX_DISTANCE:
829 case AL_ROLLOFF_FACTOR:
830 case AL_REFERENCE_DISTANCE:
831 case AL_DIRECT_FILTER:
832 case AL_DIRECT_FILTER_GAINHF_AUTO:
833 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
834 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
835 case AL_DISTANCE_MODEL:
836 alSourcei(source, eParam, plValues[0]);
837 break;
839 case AL_POSITION:
840 case AL_VELOCITY:
841 case AL_DIRECTION:
842 case AL_AUXILIARY_SEND_FILTER:
843 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
844 break;
846 default:
847 alSetError(AL_INVALID_ENUM);
848 break;
851 else
852 alSetError(AL_INVALID_NAME);
854 else
855 alSetError(AL_INVALID_VALUE);
857 ProcessContext(pContext);
859 else
860 alSetError(AL_INVALID_OPERATION);
862 return;
866 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
868 ALCcontext *pContext;
869 ALsource *pSource;
870 ALfloat flOffset[2];
872 pContext = alcGetCurrentContext();
873 if (pContext)
875 SuspendContext(pContext);
877 if (pflValue)
879 if (alIsSource(source))
881 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
883 switch(eParam)
885 case AL_PITCH:
886 *pflValue = pSource->flPitch;
887 break;
889 case AL_GAIN:
890 *pflValue = pSource->flGain;
891 break;
893 case AL_MIN_GAIN:
894 *pflValue = pSource->flMinGain;
895 break;
897 case AL_MAX_GAIN:
898 *pflValue = pSource->flMaxGain;
899 break;
901 case AL_MAX_DISTANCE:
902 *pflValue = pSource->flMaxDistance;
903 break;
905 case AL_ROLLOFF_FACTOR:
906 *pflValue = pSource->flRollOffFactor;
907 break;
909 case AL_CONE_OUTER_GAIN:
910 *pflValue = pSource->flOuterGain;
911 break;
913 case AL_CONE_OUTER_GAINHF:
914 *pflValue = pSource->OuterGainHF;
915 break;
917 case AL_SEC_OFFSET:
918 case AL_SAMPLE_OFFSET:
919 case AL_BYTE_OFFSET:
920 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
921 *pflValue = flOffset[0];
922 else
923 alSetError(AL_INVALID_OPERATION);
924 break;
926 case AL_SEC_RW_OFFSETS_EXT:
927 case AL_SAMPLE_RW_OFFSETS_EXT:
928 case AL_BYTE_RW_OFFSETS_EXT:
929 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
931 pflValue[0] = flOffset[0];
932 pflValue[1] = flOffset[1];
934 else
935 alSetError(AL_INVALID_OPERATION);
936 break;
938 case AL_CONE_INNER_ANGLE:
939 *pflValue = pSource->flInnerAngle;
940 break;
942 case AL_CONE_OUTER_ANGLE:
943 *pflValue = pSource->flOuterAngle;
944 break;
946 case AL_REFERENCE_DISTANCE:
947 *pflValue = pSource->flRefDistance;
948 break;
950 case AL_AIR_ABSORPTION_FACTOR:
951 *pflValue = pSource->AirAbsorptionFactor;
952 break;
954 case AL_ROOM_ROLLOFF_FACTOR:
955 *pflValue = pSource->RoomRolloffFactor;
956 break;
958 case AL_DOPPLER_FACTOR:
959 *pflValue = pSource->DopplerFactor;
960 break;
962 default:
963 alSetError(AL_INVALID_ENUM);
964 break;
967 else
968 alSetError(AL_INVALID_NAME);
970 else
971 alSetError(AL_INVALID_VALUE);
973 ProcessContext(pContext);
975 else
976 alSetError(AL_INVALID_OPERATION);
978 return;
982 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
984 ALCcontext *pContext;
985 ALsource *pSource;
987 pContext = alcGetCurrentContext();
988 if (pContext)
990 SuspendContext(pContext);
992 if ((pflValue1) && (pflValue2) && (pflValue3))
994 if (alIsSource(source))
996 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
998 switch(eParam)
1000 case AL_POSITION:
1001 *pflValue1 = pSource->vPosition[0];
1002 *pflValue2 = pSource->vPosition[1];
1003 *pflValue3 = pSource->vPosition[2];
1004 break;
1006 case AL_VELOCITY:
1007 *pflValue1 = pSource->vVelocity[0];
1008 *pflValue2 = pSource->vVelocity[1];
1009 *pflValue3 = pSource->vVelocity[2];
1010 break;
1012 case AL_DIRECTION:
1013 *pflValue1 = pSource->vOrientation[0];
1014 *pflValue2 = pSource->vOrientation[1];
1015 *pflValue3 = pSource->vOrientation[2];
1016 break;
1018 default:
1019 alSetError(AL_INVALID_ENUM);
1020 break;
1023 else
1024 alSetError(AL_INVALID_NAME);
1026 else
1027 alSetError(AL_INVALID_VALUE);
1029 ProcessContext(pContext);
1031 else
1032 alSetError(AL_INVALID_OPERATION);
1034 return;
1038 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1040 ALCcontext *pContext;
1041 ALsource *pSource;
1043 pContext = alcGetCurrentContext();
1044 if (pContext)
1046 SuspendContext(pContext);
1048 if (pflValues)
1050 if (alIsSource(source))
1052 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1054 switch(eParam)
1056 case AL_PITCH:
1057 case AL_GAIN:
1058 case AL_MIN_GAIN:
1059 case AL_MAX_GAIN:
1060 case AL_MAX_DISTANCE:
1061 case AL_ROLLOFF_FACTOR:
1062 case AL_DOPPLER_FACTOR:
1063 case AL_CONE_OUTER_GAIN:
1064 case AL_SEC_OFFSET:
1065 case AL_SAMPLE_OFFSET:
1066 case AL_BYTE_OFFSET:
1067 case AL_CONE_INNER_ANGLE:
1068 case AL_CONE_OUTER_ANGLE:
1069 case AL_REFERENCE_DISTANCE:
1070 case AL_CONE_OUTER_GAINHF:
1071 case AL_AIR_ABSORPTION_FACTOR:
1072 case AL_ROOM_ROLLOFF_FACTOR:
1073 alGetSourcef(source, eParam, pflValues);
1074 break;
1076 case AL_POSITION:
1077 pflValues[0] = pSource->vPosition[0];
1078 pflValues[1] = pSource->vPosition[1];
1079 pflValues[2] = pSource->vPosition[2];
1080 break;
1082 case AL_VELOCITY:
1083 pflValues[0] = pSource->vVelocity[0];
1084 pflValues[1] = pSource->vVelocity[1];
1085 pflValues[2] = pSource->vVelocity[2];
1086 break;
1088 case AL_DIRECTION:
1089 pflValues[0] = pSource->vOrientation[0];
1090 pflValues[1] = pSource->vOrientation[1];
1091 pflValues[2] = pSource->vOrientation[2];
1092 break;
1094 default:
1095 alSetError(AL_INVALID_ENUM);
1096 break;
1099 else
1100 alSetError(AL_INVALID_NAME);
1102 else
1103 alSetError(AL_INVALID_VALUE);
1105 ProcessContext(pContext);
1107 else
1108 alSetError(AL_INVALID_OPERATION);
1110 return;
1114 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1116 ALCcontext *pContext;
1117 ALsource *pSource;
1118 ALfloat flOffset[2];
1120 pContext = alcGetCurrentContext();
1121 if (pContext)
1123 SuspendContext(pContext);
1125 if (plValue)
1127 if (alIsSource(source))
1129 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1131 switch(eParam)
1133 case AL_MAX_DISTANCE:
1134 *plValue = (ALint)pSource->flMaxDistance;
1135 break;
1137 case AL_ROLLOFF_FACTOR:
1138 *plValue = (ALint)pSource->flRollOffFactor;
1139 break;
1141 case AL_REFERENCE_DISTANCE:
1142 *plValue = (ALint)pSource->flRefDistance;
1143 break;
1145 case AL_SOURCE_RELATIVE:
1146 *plValue = pSource->bHeadRelative;
1147 break;
1149 case AL_CONE_INNER_ANGLE:
1150 *plValue = (ALint)pSource->flInnerAngle;
1151 break;
1153 case AL_CONE_OUTER_ANGLE:
1154 *plValue = (ALint)pSource->flOuterAngle;
1155 break;
1157 case AL_LOOPING:
1158 *plValue = pSource->bLooping;
1159 break;
1161 case AL_BUFFER:
1162 *plValue = pSource->ulBufferID;
1163 break;
1165 case AL_SOURCE_STATE:
1166 *plValue = pSource->state;
1167 break;
1169 case AL_BUFFERS_QUEUED:
1170 *plValue = pSource->BuffersInQueue;
1171 break;
1173 case AL_BUFFERS_PROCESSED:
1174 if(pSource->bLooping)
1176 /* Buffers on a looping source are in a perpetual state
1177 * of PENDING, so don't report any as PROCESSED */
1178 *plValue = 0;
1180 else
1181 *plValue = pSource->BuffersPlayed;
1182 break;
1184 case AL_SOURCE_TYPE:
1185 *plValue = pSource->lSourceType;
1186 break;
1188 case AL_SEC_OFFSET:
1189 case AL_SAMPLE_OFFSET:
1190 case AL_BYTE_OFFSET:
1191 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1192 *plValue = (ALint)flOffset[0];
1193 else
1194 alSetError(AL_INVALID_OPERATION);
1195 break;
1197 case AL_SEC_RW_OFFSETS_EXT:
1198 case AL_SAMPLE_RW_OFFSETS_EXT:
1199 case AL_BYTE_RW_OFFSETS_EXT:
1200 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1202 plValue[0] = (ALint)flOffset[0];
1203 plValue[1] = (ALint)flOffset[1];
1205 else
1206 alSetError(AL_INVALID_OPERATION);
1207 break;
1209 case AL_DIRECT_FILTER:
1210 *plValue = pSource->DirectFilter.filter;
1211 break;
1213 case AL_DIRECT_FILTER_GAINHF_AUTO:
1214 *plValue = pSource->DryGainHFAuto;
1215 break;
1217 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1218 *plValue = pSource->WetGainAuto;
1219 break;
1221 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1222 *plValue = pSource->WetGainHFAuto;
1223 break;
1225 case AL_DOPPLER_FACTOR:
1226 *plValue = (ALint)pSource->DopplerFactor;
1227 break;
1229 case AL_DISTANCE_MODEL:
1230 *plValue = pSource->DistanceModel;
1231 break;
1233 default:
1234 alSetError(AL_INVALID_ENUM);
1235 break;
1238 else
1239 alSetError(AL_INVALID_NAME);
1241 else
1242 alSetError(AL_INVALID_VALUE);
1244 ProcessContext(pContext);
1246 else
1247 alSetError(AL_INVALID_OPERATION);
1249 return;
1253 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1255 ALCcontext *pContext;
1256 ALsource *pSource;
1258 pContext = alcGetCurrentContext();
1259 if (pContext)
1261 SuspendContext(pContext);
1263 if ((plValue1) && (plValue2) && (plValue3))
1265 if (alIsSource(source))
1267 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1269 switch(eParam)
1271 case AL_POSITION:
1272 *plValue1 = (ALint)pSource->vPosition[0];
1273 *plValue2 = (ALint)pSource->vPosition[1];
1274 *plValue3 = (ALint)pSource->vPosition[2];
1275 break;
1277 case AL_VELOCITY:
1278 *plValue1 = (ALint)pSource->vVelocity[0];
1279 *plValue2 = (ALint)pSource->vVelocity[1];
1280 *plValue3 = (ALint)pSource->vVelocity[2];
1281 break;
1283 case AL_DIRECTION:
1284 *plValue1 = (ALint)pSource->vOrientation[0];
1285 *plValue2 = (ALint)pSource->vOrientation[1];
1286 *plValue3 = (ALint)pSource->vOrientation[2];
1287 break;
1289 default:
1290 alSetError(AL_INVALID_ENUM);
1291 break;
1294 else
1295 alSetError(AL_INVALID_NAME);
1297 else
1298 alSetError(AL_INVALID_VALUE);
1300 ProcessContext(pContext);
1302 else
1303 alSetError(AL_INVALID_OPERATION);
1305 return;
1309 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1311 ALCcontext *pContext;
1312 ALsource *pSource;
1314 pContext = alcGetCurrentContext();
1315 if (pContext)
1317 SuspendContext(pContext);
1319 if (plValues)
1321 if (alIsSource(source))
1323 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1325 switch (eParam)
1327 case AL_SOURCE_RELATIVE:
1328 case AL_CONE_INNER_ANGLE:
1329 case AL_CONE_OUTER_ANGLE:
1330 case AL_LOOPING:
1331 case AL_BUFFER:
1332 case AL_SOURCE_STATE:
1333 case AL_BUFFERS_QUEUED:
1334 case AL_BUFFERS_PROCESSED:
1335 case AL_SEC_OFFSET:
1336 case AL_SAMPLE_OFFSET:
1337 case AL_BYTE_OFFSET:
1338 case AL_MAX_DISTANCE:
1339 case AL_ROLLOFF_FACTOR:
1340 case AL_DOPPLER_FACTOR:
1341 case AL_REFERENCE_DISTANCE:
1342 case AL_SOURCE_TYPE:
1343 case AL_DIRECT_FILTER:
1344 case AL_DIRECT_FILTER_GAINHF_AUTO:
1345 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1346 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1347 case AL_DISTANCE_MODEL:
1348 alGetSourcei(source, eParam, plValues);
1349 break;
1351 case AL_POSITION:
1352 plValues[0] = (ALint)pSource->vPosition[0];
1353 plValues[1] = (ALint)pSource->vPosition[1];
1354 plValues[2] = (ALint)pSource->vPosition[2];
1355 break;
1357 case AL_VELOCITY:
1358 plValues[0] = (ALint)pSource->vVelocity[0];
1359 plValues[1] = (ALint)pSource->vVelocity[1];
1360 plValues[2] = (ALint)pSource->vVelocity[2];
1361 break;
1363 case AL_DIRECTION:
1364 plValues[0] = (ALint)pSource->vOrientation[0];
1365 plValues[1] = (ALint)pSource->vOrientation[1];
1366 plValues[2] = (ALint)pSource->vOrientation[2];
1367 break;
1369 default:
1370 alSetError(AL_INVALID_ENUM);
1371 break;
1374 else
1375 alSetError(AL_INVALID_NAME);
1377 else
1378 alSetError(AL_INVALID_VALUE);
1380 ProcessContext(pContext);
1382 else
1383 alSetError(AL_INVALID_OPERATION);
1385 return;
1389 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1391 alSourcePlayv(1, &source);
1392 return;
1395 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1397 ALCcontext *pContext;
1398 ALsource *pSource;
1399 ALbufferlistitem *ALBufferList;
1400 ALboolean bSourcesValid = AL_TRUE;
1401 ALboolean bPlay;
1402 ALsizei i, j;
1404 pContext = alcGetCurrentContext();
1405 if (pContext)
1407 SuspendContext(pContext);
1409 if (pSourceList)
1411 // Check that all the Sources are valid
1412 for (i = 0; i < n; i++)
1414 if (!alIsSource(pSourceList[i]))
1416 alSetError(AL_INVALID_NAME);
1417 bSourcesValid = AL_FALSE;
1418 break;
1422 if (bSourcesValid)
1424 for (i = 0; i < n; i++)
1426 // Assume Source won't need to play
1427 bPlay = AL_FALSE;
1429 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1431 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1432 ALBufferList = pSource->queue;
1433 while (ALBufferList)
1435 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1437 bPlay = AL_TRUE;
1438 break;
1440 ALBufferList = ALBufferList->next;
1443 if (bPlay)
1445 for(j = 0;j < OUTPUTCHANNELS;j++)
1446 pSource->DryGains[j] = 0.0f;
1447 pSource->WetGain = 0.0f;
1449 if (pSource->state != AL_PAUSED)
1451 pSource->state = AL_PLAYING;
1452 pSource->inuse = AL_TRUE;
1453 pSource->play = AL_TRUE;
1454 pSource->position = 0;
1455 pSource->position_fraction = 0;
1456 pSource->BuffersPlayed = 0;
1457 pSource->FirstStart = AL_TRUE;
1459 pSource->ulBufferID = pSource->queue->buffer;
1461 // Make sure all the Buffers in the queue are marked as PENDING
1462 ALBufferList = pSource->queue;
1463 while (ALBufferList)
1465 ALBufferList->bufferstate = PENDING;
1466 ALBufferList = ALBufferList->next;
1469 else
1471 pSource->state = AL_PLAYING;
1472 pSource->inuse = AL_TRUE;
1473 pSource->play = AL_TRUE;
1474 pSource->FirstStart = AL_FALSE;
1477 // Check if an Offset has been set
1478 if (pSource->lOffset)
1479 ApplyOffset(pSource, AL_FALSE);
1481 else
1483 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1484 ALBufferList = pSource->queue;
1485 while (ALBufferList)
1487 ALBufferList->bufferstate = PROCESSED;
1488 ALBufferList = ALBufferList->next;
1491 pSource->BuffersPlayed = pSource->BuffersInQueue;
1496 else
1498 // sources is a NULL pointer
1499 alSetError(AL_INVALID_VALUE);
1502 ProcessContext(pContext);
1504 else
1506 // Invalid Context
1507 alSetError(AL_INVALID_OPERATION);
1510 return;
1513 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1515 alSourcePausev(1, &source);
1516 return;
1519 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1521 ALCcontext *Context;
1522 ALsource *Source;
1523 ALsizei i;
1524 ALboolean bSourcesValid = AL_TRUE;
1526 Context=alcGetCurrentContext();
1527 if (Context)
1529 SuspendContext(Context);
1531 if (sources)
1533 // Check all the Sources are valid
1534 for (i=0;i<n;i++)
1536 if (!alIsSource(sources[i]))
1538 alSetError(AL_INVALID_NAME);
1539 bSourcesValid = AL_FALSE;
1540 break;
1544 if (bSourcesValid)
1546 for (i=0;i<n;i++)
1548 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1549 if (Source->state==AL_PLAYING)
1551 Source->state=AL_PAUSED;
1552 Source->inuse=AL_FALSE;
1557 else
1559 // sources is a NULL pointer
1560 alSetError(AL_INVALID_VALUE);
1563 ProcessContext(Context);
1565 else
1567 // Invalid Context
1568 alSetError(AL_INVALID_OPERATION);
1571 return;
1574 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1576 alSourceStopv(1, &source);
1577 return;
1580 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1582 ALCcontext *Context;
1583 ALsource *Source;
1584 ALsizei i;
1585 ALbufferlistitem *ALBufferListItem;
1586 ALboolean bSourcesValid = AL_TRUE;
1588 Context=alcGetCurrentContext();
1589 if (Context)
1591 SuspendContext(Context);
1593 if (sources)
1595 // Check all the Sources are valid
1596 for (i=0;i<n;i++)
1598 if (!alIsSource(sources[i]))
1600 alSetError(AL_INVALID_NAME);
1601 bSourcesValid = AL_FALSE;
1602 break;
1606 if (bSourcesValid)
1608 for (i=0;i<n;i++)
1610 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1611 if (Source->state!=AL_INITIAL)
1613 Source->state=AL_STOPPED;
1614 Source->inuse=AL_FALSE;
1615 Source->BuffersPlayed = Source->BuffersInQueue;
1616 ALBufferListItem= Source->queue;
1617 while (ALBufferListItem != NULL)
1619 ALBufferListItem->bufferstate = PROCESSED;
1620 ALBufferListItem = ALBufferListItem->next;
1623 Source->lOffset = 0;
1627 else
1629 // sources is a NULL pointer
1630 alSetError(AL_INVALID_VALUE);
1633 ProcessContext(Context);
1635 else
1637 // Invalid Context
1638 alSetError(AL_INVALID_OPERATION);
1641 return;
1644 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1646 alSourceRewindv(1, &source);
1647 return;
1650 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1652 ALCcontext *Context;
1653 ALsource *Source;
1654 ALsizei i;
1655 ALbufferlistitem *ALBufferListItem;
1656 ALboolean bSourcesValid = AL_TRUE;
1658 Context=alcGetCurrentContext();
1659 if (Context)
1661 SuspendContext(Context);
1663 if (sources)
1665 // Check all the Sources are valid
1666 for (i=0;i<n;i++)
1668 if (!alIsSource(sources[i]))
1670 alSetError(AL_INVALID_NAME);
1671 bSourcesValid = AL_FALSE;
1672 break;
1676 if (bSourcesValid)
1678 for (i=0;i<n;i++)
1680 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1681 if (Source->state!=AL_INITIAL)
1683 Source->state=AL_INITIAL;
1684 Source->inuse=AL_FALSE;
1685 Source->position=0;
1686 Source->position_fraction=0;
1687 Source->BuffersPlayed = 0;
1688 ALBufferListItem= Source->queue;
1689 while (ALBufferListItem != NULL)
1691 ALBufferListItem->bufferstate = PENDING;
1692 ALBufferListItem = ALBufferListItem->next;
1694 if (Source->queue)
1695 Source->ulBufferID = Source->queue->buffer;
1697 Source->lOffset = 0;
1701 else
1703 // sources is a NULL pointer
1704 alSetError(AL_INVALID_VALUE);
1707 ProcessContext(Context);
1709 else
1711 // Invalid Context
1712 alSetError(AL_INVALID_OPERATION);
1715 return;
1719 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1721 ALCcontext *Context;
1722 ALsource *ALSource;
1723 ALsizei i;
1724 ALbufferlistitem *ALBufferList;
1725 ALbufferlistitem *ALBufferListStart;
1726 ALuint DataSize;
1727 ALuint BufferSize;
1728 ALint iFrequency;
1729 ALint iFormat;
1730 ALboolean bBuffersValid = AL_TRUE;
1732 if (n == 0)
1733 return;
1735 Context=alcGetCurrentContext();
1736 if (Context)
1738 SuspendContext(Context);
1740 DataSize = 0;
1741 BufferSize = 0;
1743 // Check that all buffers are valid or zero and that the source is valid
1745 // Check that this is a valid source
1746 if (alIsSource(source))
1748 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1750 // Check that this is not a STATIC Source
1751 if (ALSource->lSourceType != AL_STATIC)
1753 iFrequency = -1;
1754 iFormat = -1;
1756 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1757 ALBufferList = ALSource->queue;
1758 while (ALBufferList)
1760 if (ALBufferList->buffer)
1762 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1763 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1764 break;
1766 ALBufferList = ALBufferList->next;
1769 for (i = 0; i < n; i++)
1771 if (alIsBuffer(buffers[i]))
1773 if (buffers[i])
1775 if ((iFrequency == -1) && (iFormat == -1))
1777 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1778 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1780 else
1782 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1783 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1785 alSetError(AL_INVALID_OPERATION);
1786 bBuffersValid = AL_FALSE;
1787 break;
1792 else
1794 alSetError(AL_INVALID_NAME);
1795 bBuffersValid = AL_FALSE;
1796 break;
1800 if (bBuffersValid)
1802 // Change Source Type
1803 ALSource->lSourceType = AL_STREAMING;
1805 // All buffers are valid - so add them to the list
1806 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1807 ALBufferListStart->buffer = buffers[0];
1808 ALBufferListStart->bufferstate = PENDING;
1809 ALBufferListStart->flag = 0;
1810 ALBufferListStart->next = NULL;
1812 if (buffers[0])
1813 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1814 else
1815 BufferSize = 0;
1817 DataSize += BufferSize;
1819 // Increment reference counter for buffer
1820 if (buffers[0])
1821 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1823 ALBufferList = ALBufferListStart;
1825 for (i = 1; i < n; i++)
1827 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1828 ALBufferList->next->buffer = buffers[i];
1829 ALBufferList->next->bufferstate = PENDING;
1830 ALBufferList->next->flag = 0;
1831 ALBufferList->next->next = NULL;
1833 if (buffers[i])
1834 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1835 else
1836 BufferSize = 0;
1838 DataSize += BufferSize;
1840 // Increment reference counter for buffer
1841 if (buffers[i])
1842 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1844 ALBufferList = ALBufferList->next;
1847 if (ALSource->queue == NULL)
1849 ALSource->queue = ALBufferListStart;
1850 // Update Current Buffer
1851 ALSource->ulBufferID = ALBufferListStart->buffer;
1853 else
1855 // Find end of queue
1856 ALBufferList = ALSource->queue;
1857 while (ALBufferList->next != NULL)
1859 ALBufferList = ALBufferList->next;
1862 ALBufferList->next = ALBufferListStart;
1865 // Update number of buffers in queue
1866 ALSource->BuffersInQueue += n;
1869 else
1871 // Invalid Source Type (can't queue on a Static Source)
1872 alSetError(AL_INVALID_OPERATION);
1875 else
1877 // Invalid Source Name
1878 alSetError(AL_INVALID_NAME);
1881 ProcessContext(Context);
1883 else
1885 // Invalid Context
1886 alSetError(AL_INVALID_OPERATION);
1889 return;
1893 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1894 // an array of buffer IDs that are to be filled with the names of the buffers removed
1895 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1897 ALCcontext *Context;
1898 ALsource *ALSource;
1899 ALsizei i;
1900 ALbufferlistitem *ALBufferList;
1901 ALuint DataSize;
1902 ALuint BufferSize;
1903 ALuint BufferID;
1904 ALboolean bBuffersProcessed;
1906 if (n == 0)
1907 return;
1909 DataSize = 0;
1910 BufferSize = 0;
1911 bBuffersProcessed = AL_TRUE;
1913 Context=alcGetCurrentContext();
1914 if (Context)
1916 SuspendContext(Context);
1918 if (alIsSource(source))
1920 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1922 // Check that all 'n' buffers have been processed
1923 ALBufferList = ALSource->queue;
1924 for (i = 0; i < n; i++)
1926 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1928 ALBufferList = ALBufferList->next;
1930 else
1932 bBuffersProcessed = AL_FALSE;
1933 break;
1937 // If all 'n' buffers have been processed, remove them from the queue
1938 if (bBuffersProcessed)
1940 for (i = 0; i < n; i++)
1942 ALBufferList = ALSource->queue;
1944 ALSource->queue = ALBufferList->next;
1945 // Record name of buffer
1946 buffers[i] = ALBufferList->buffer;
1947 // Decrement buffer reference counter
1948 if (ALBufferList->buffer)
1949 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1950 // Record size of buffer
1951 if (ALBufferList->buffer)
1952 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1953 else
1954 BufferSize = 0;
1956 DataSize += BufferSize;
1957 // Release memory for buffer list item
1958 free(ALBufferList);
1959 ALSource->BuffersInQueue--;
1962 if (ALSource->state != AL_PLAYING)
1964 if (ALSource->queue)
1965 BufferID = ALSource->queue->buffer;
1966 else
1967 BufferID = 0;
1969 ALSource->ulBufferID = BufferID;
1972 if((ALuint)n > ALSource->BuffersPlayed)
1973 ALSource->BuffersPlayed = 0;
1974 else
1975 ALSource->BuffersPlayed -= n;
1977 else
1979 // Some buffers can't be unqueue because they have not been processed
1980 alSetError(AL_INVALID_VALUE);
1983 else
1985 // Invalid Source Name
1986 alSetError(AL_INVALID_NAME);
1989 ProcessContext(Context);
1991 else
1993 // Invalid Context
1994 alSetError(AL_INVALID_OPERATION);
1997 return;
2001 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
2003 pSource->flInnerAngle = 360.0f;
2004 pSource->flOuterAngle = 360.0f;
2005 pSource->flPitch = 1.0f;
2006 pSource->vPosition[0] = 0.0f;
2007 pSource->vPosition[1] = 0.0f;
2008 pSource->vPosition[2] = 0.0f;
2009 pSource->vOrientation[0] = 0.0f;
2010 pSource->vOrientation[1] = 0.0f;
2011 pSource->vOrientation[2] = 0.0f;
2012 pSource->vVelocity[0] = 0.0f;
2013 pSource->vVelocity[1] = 0.0f;
2014 pSource->vVelocity[2] = 0.0f;
2015 pSource->flRefDistance = 1.0f;
2016 pSource->flMaxDistance = FLT_MAX;
2017 pSource->flRollOffFactor = 1.0f;
2018 pSource->bLooping = AL_FALSE;
2019 pSource->flGain = 1.0f;
2020 pSource->flMinGain = 0.0f;
2021 pSource->flMaxGain = 1.0f;
2022 pSource->flOuterGain = 0.0f;
2023 pSource->OuterGainHF = 1.0f;
2025 pSource->DryGainHFAuto = AL_TRUE;
2026 pSource->WetGainAuto = AL_TRUE;
2027 pSource->WetGainHFAuto = AL_TRUE;
2028 pSource->AirAbsorptionFactor = 0.0f;
2029 pSource->RoomRolloffFactor = 0.0f;
2030 pSource->DopplerFactor = 1.0f;
2032 pSource->DistanceModel = Context->DistanceModel;
2034 pSource->state = AL_INITIAL;
2035 pSource->lSourceType = AL_UNDETERMINED;
2037 pSource->ulBufferID= 0;
2042 GetSourceOffset
2044 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2045 The offset is relative to the start of the queue (not the start of the current buffer)
2047 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
2049 ALbufferlistitem *pBufferList;
2050 ALbuffer *pBuffer;
2051 ALfloat flBufferFreq;
2052 ALint lChannels;
2053 ALint readPos, writePos;
2054 ALenum eOriginalFormat;
2055 ALboolean bReturn = AL_TRUE;
2056 ALint lTotalBufferDataSize;
2058 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2060 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2061 // Get Current Buffer Size and frequency (in milliseconds)
2062 flBufferFreq = (ALfloat)pBuffer->frequency;
2063 eOriginalFormat = pBuffer->eOriginalFormat;
2064 lChannels = aluChannelsFromFormat(pBuffer->format);
2066 // Get Current BytesPlayed
2067 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2068 // Add byte length of any processed buffers in the queue
2069 pBufferList = pSource->queue;
2070 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2072 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2073 pBufferList = pBufferList->next;
2076 if(pSource->state == AL_PLAYING)
2077 writePos = readPos + (updateSize * lChannels * 2);
2078 else
2079 writePos = readPos;
2081 lTotalBufferDataSize = 0;
2082 pBufferList = pSource->queue;
2083 while (pBufferList)
2085 if (pBufferList->buffer)
2086 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2087 pBufferList = pBufferList->next;
2090 if (pSource->bLooping)
2092 if(readPos < 0)
2093 readPos = 0;
2094 else
2095 readPos %= lTotalBufferDataSize;
2096 if(writePos < 0)
2097 writePos = 0;
2098 else
2099 writePos %= lTotalBufferDataSize;
2101 else
2103 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2104 if(readPos < 0)
2105 readPos = 0;
2106 else if(readPos > lTotalBufferDataSize)
2107 readPos = lTotalBufferDataSize;
2108 if(writePos < 0)
2109 writePos = 0;
2110 else if(writePos > lTotalBufferDataSize)
2111 writePos = lTotalBufferDataSize;
2114 switch (eName)
2116 case AL_SEC_OFFSET:
2117 case AL_SEC_RW_OFFSETS_EXT:
2118 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
2119 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
2120 break;
2121 case AL_SAMPLE_OFFSET:
2122 case AL_SAMPLE_RW_OFFSETS_EXT:
2123 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
2124 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
2125 break;
2126 case AL_BYTE_OFFSET:
2127 case AL_BYTE_RW_OFFSETS_EXT:
2128 // Take into account the original format of the Buffer
2129 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2130 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2132 // Round down to nearest ADPCM block
2133 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
2134 if(pSource->state == AL_PLAYING)
2136 // Round up to nearest ADPCM block
2137 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
2139 else
2140 pflOffset[1] = pflOffset[0];
2142 else if (eOriginalFormat == AL_FORMAT_REAR8)
2144 pflOffset[0] = (ALfloat)(readPos >> 2);
2145 pflOffset[1] = (ALfloat)(writePos >> 2);
2147 else if (eOriginalFormat == AL_FORMAT_REAR16)
2149 pflOffset[0] = (ALfloat)(readPos >> 1);
2150 pflOffset[1] = (ALfloat)(writePos >> 1);
2152 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2154 pflOffset[0] = (ALfloat)(readPos >> 1);
2155 pflOffset[1] = (ALfloat)(writePos >> 1);
2157 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2159 pflOffset[0] = (ALfloat)(readPos << 1);
2160 pflOffset[1] = (ALfloat)(writePos << 1);
2162 else
2164 pflOffset[0] = (ALfloat)readPos;
2165 pflOffset[1] = (ALfloat)writePos;
2167 break;
2170 else
2172 pflOffset[0] = 0.0f;
2173 pflOffset[1] = 0.0f;
2176 return bReturn;
2181 ApplyOffset
2183 Apply a playback offset to the Source. This function will update the queue (to correctly
2184 mark buffers as 'pending' or 'processed' depending upon the new offset.
2186 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2188 ALbufferlistitem *pBufferList;
2189 ALbuffer *pBuffer;
2190 ALint lBufferSize, lTotalBufferSize;
2191 ALint lByteOffset;
2193 // Get true byte offset
2194 lByteOffset = GetByteOffset(pSource);
2196 // If this is a valid offset apply it
2197 if (lByteOffset != -1)
2199 // Sort out the queue (pending and processed states)
2200 pBufferList = pSource->queue;
2201 lTotalBufferSize = 0;
2202 pSource->BuffersPlayed = 0;
2203 while (pBufferList)
2205 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2206 lBufferSize = pBuffer ? pBuffer->size : 0;
2208 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2210 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2211 // update the state to PROCESSED
2212 pSource->BuffersPlayed++;
2214 if (!pSource->bLooping)
2215 pBufferList->bufferstate = PROCESSED;
2217 else if (lTotalBufferSize <= lByteOffset)
2219 // Offset is within this buffer
2220 pBufferList->bufferstate = PENDING;
2222 // Set Current Buffer ID
2223 pSource->ulBufferID = pBufferList->buffer;
2225 // SW Mixer Positions are in Samples
2226 pSource->position = (lByteOffset - lTotalBufferSize) /
2227 aluBytesFromFormat(pBuffer->format) /
2228 aluChannelsFromFormat(pBuffer->format);
2230 else
2232 // Offset is before this buffer, so mark as pending
2233 pBufferList->bufferstate = PENDING;
2236 // Increment the TotalBufferSize
2237 lTotalBufferSize += lBufferSize;
2239 // Move on to next buffer in the Queue
2240 pBufferList = pBufferList->next;
2243 else
2245 if (bUpdateContext)
2246 alSetError(AL_INVALID_VALUE);
2249 // Clear Offset
2250 pSource->lOffset = 0;
2255 GetByteOffset
2257 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2258 offset supplied by the application). This takes into account the fact that the buffer format
2259 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2261 static ALint GetByteOffset(ALsource *pSource)
2263 ALbuffer *pBuffer = NULL;
2264 ALbufferlistitem *pBufferList;
2265 ALfloat flBufferFreq;
2266 ALint lChannels;
2267 ALint lByteOffset = -1;
2268 ALint lTotalBufferDataSize;
2270 // Find the first non-NULL Buffer in the Queue
2271 pBufferList = pSource->queue;
2272 while (pBufferList)
2274 if (pBufferList->buffer)
2276 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2277 break;
2279 pBufferList = pBufferList->next;
2282 if (pBuffer)
2284 flBufferFreq = ((ALfloat)pBuffer->frequency);
2285 lChannels = aluChannelsFromFormat(pBuffer->format);
2287 // Determine the ByteOffset (and ensure it is block aligned)
2288 switch (pSource->lOffsetType)
2290 case AL_BYTE_OFFSET:
2291 // Take into consideration the original format
2292 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2293 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2295 // Round down to nearest ADPCM block
2296 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2297 // Multiply by compression rate
2298 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2299 lByteOffset -= (lByteOffset % (lChannels * 2));
2301 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2303 lByteOffset = pSource->lOffset * 4;
2304 lByteOffset -= (lByteOffset % (lChannels * 2));
2306 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2308 lByteOffset = pSource->lOffset * 2;
2309 lByteOffset -= (lByteOffset % (lChannels * 2));
2311 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2313 lByteOffset = pSource->lOffset * 2;
2314 lByteOffset -= (lByteOffset % (lChannels * 2));
2316 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2318 lByteOffset = pSource->lOffset / 2;
2319 lByteOffset -= (lByteOffset % (lChannels * 2));
2321 else
2323 lByteOffset = pSource->lOffset;
2324 lByteOffset -= (lByteOffset % (lChannels * 2));
2326 break;
2328 case AL_SAMPLE_OFFSET:
2329 lByteOffset = pSource->lOffset * lChannels * 2;
2330 break;
2332 case AL_SEC_OFFSET:
2333 // Note - lOffset is internally stored as Milliseconds
2334 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2335 lByteOffset -= (lByteOffset % (lChannels * 2));
2336 break;
2339 lTotalBufferDataSize = 0;
2340 pBufferList = pSource->queue;
2341 while (pBufferList)
2343 if (pBufferList->buffer)
2344 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2345 pBufferList = pBufferList->next;
2348 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2349 if (lByteOffset >= lTotalBufferDataSize)
2350 lByteOffset = -1;
2353 return lByteOffset;
2357 ALvoid ReleaseALSources(ALCcontext *Context)
2359 #ifdef _DEBUG
2360 if(Context->SourceCount > 0)
2361 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2362 #endif
2364 while(Context->Source)
2366 ALsource *temp = Context->Source;
2367 Context->Source = Context->Source->next;
2369 // Release source structure
2370 ALTHUNK_REMOVEENTRY(temp->source);
2371 memset(temp, 0, sizeof(ALsource));
2372 free(temp);
2374 Context->SourceCount = 0;