Do not open pulseaudio if it didn't load
[openal-soft.git] / OpenAL32 / alSource.c
blobb30cf6665745691e87811980df044fed8fde30c1
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 <= 10.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 for(j = 0;j < MAX_SENDS;j++)
1448 pSource->WetGains[j] = 0.0f;
1450 if (pSource->state != AL_PAUSED)
1452 pSource->state = AL_PLAYING;
1453 pSource->inuse = AL_TRUE;
1454 pSource->play = AL_TRUE;
1455 pSource->position = 0;
1456 pSource->position_fraction = 0;
1457 pSource->BuffersPlayed = 0;
1458 pSource->FirstStart = AL_TRUE;
1460 pSource->ulBufferID = pSource->queue->buffer;
1462 // Make sure all the Buffers in the queue are marked as PENDING
1463 ALBufferList = pSource->queue;
1464 while (ALBufferList)
1466 ALBufferList->bufferstate = PENDING;
1467 ALBufferList = ALBufferList->next;
1470 else
1472 pSource->state = AL_PLAYING;
1473 pSource->inuse = AL_TRUE;
1474 pSource->play = AL_TRUE;
1475 pSource->FirstStart = AL_FALSE;
1478 // Check if an Offset has been set
1479 if (pSource->lOffset)
1480 ApplyOffset(pSource, AL_FALSE);
1482 else
1484 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1485 ALBufferList = pSource->queue;
1486 while (ALBufferList)
1488 ALBufferList->bufferstate = PROCESSED;
1489 ALBufferList = ALBufferList->next;
1492 pSource->BuffersPlayed = pSource->BuffersInQueue;
1497 else
1499 // sources is a NULL pointer
1500 alSetError(AL_INVALID_VALUE);
1503 ProcessContext(pContext);
1505 else
1507 // Invalid Context
1508 alSetError(AL_INVALID_OPERATION);
1511 return;
1514 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1516 alSourcePausev(1, &source);
1517 return;
1520 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1522 ALCcontext *Context;
1523 ALsource *Source;
1524 ALsizei i;
1525 ALboolean bSourcesValid = AL_TRUE;
1527 Context=alcGetCurrentContext();
1528 if (Context)
1530 SuspendContext(Context);
1532 if (sources)
1534 // Check all the Sources are valid
1535 for (i=0;i<n;i++)
1537 if (!alIsSource(sources[i]))
1539 alSetError(AL_INVALID_NAME);
1540 bSourcesValid = AL_FALSE;
1541 break;
1545 if (bSourcesValid)
1547 for (i=0;i<n;i++)
1549 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1550 if (Source->state==AL_PLAYING)
1552 Source->state=AL_PAUSED;
1553 Source->inuse=AL_FALSE;
1558 else
1560 // sources is a NULL pointer
1561 alSetError(AL_INVALID_VALUE);
1564 ProcessContext(Context);
1566 else
1568 // Invalid Context
1569 alSetError(AL_INVALID_OPERATION);
1572 return;
1575 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1577 alSourceStopv(1, &source);
1578 return;
1581 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1583 ALCcontext *Context;
1584 ALsource *Source;
1585 ALsizei i;
1586 ALbufferlistitem *ALBufferListItem;
1587 ALboolean bSourcesValid = AL_TRUE;
1589 Context=alcGetCurrentContext();
1590 if (Context)
1592 SuspendContext(Context);
1594 if (sources)
1596 // Check all the Sources are valid
1597 for (i=0;i<n;i++)
1599 if (!alIsSource(sources[i]))
1601 alSetError(AL_INVALID_NAME);
1602 bSourcesValid = AL_FALSE;
1603 break;
1607 if (bSourcesValid)
1609 for (i=0;i<n;i++)
1611 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1612 if (Source->state!=AL_INITIAL)
1614 Source->state=AL_STOPPED;
1615 Source->inuse=AL_FALSE;
1616 Source->BuffersPlayed = Source->BuffersInQueue;
1617 ALBufferListItem= Source->queue;
1618 while (ALBufferListItem != NULL)
1620 ALBufferListItem->bufferstate = PROCESSED;
1621 ALBufferListItem = ALBufferListItem->next;
1624 Source->lOffset = 0;
1628 else
1630 // sources is a NULL pointer
1631 alSetError(AL_INVALID_VALUE);
1634 ProcessContext(Context);
1636 else
1638 // Invalid Context
1639 alSetError(AL_INVALID_OPERATION);
1642 return;
1645 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1647 alSourceRewindv(1, &source);
1648 return;
1651 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1653 ALCcontext *Context;
1654 ALsource *Source;
1655 ALsizei i;
1656 ALbufferlistitem *ALBufferListItem;
1657 ALboolean bSourcesValid = AL_TRUE;
1659 Context=alcGetCurrentContext();
1660 if (Context)
1662 SuspendContext(Context);
1664 if (sources)
1666 // Check all the Sources are valid
1667 for (i=0;i<n;i++)
1669 if (!alIsSource(sources[i]))
1671 alSetError(AL_INVALID_NAME);
1672 bSourcesValid = AL_FALSE;
1673 break;
1677 if (bSourcesValid)
1679 for (i=0;i<n;i++)
1681 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1682 if (Source->state!=AL_INITIAL)
1684 Source->state=AL_INITIAL;
1685 Source->inuse=AL_FALSE;
1686 Source->position=0;
1687 Source->position_fraction=0;
1688 Source->BuffersPlayed = 0;
1689 ALBufferListItem= Source->queue;
1690 while (ALBufferListItem != NULL)
1692 ALBufferListItem->bufferstate = PENDING;
1693 ALBufferListItem = ALBufferListItem->next;
1695 if (Source->queue)
1696 Source->ulBufferID = Source->queue->buffer;
1698 Source->lOffset = 0;
1702 else
1704 // sources is a NULL pointer
1705 alSetError(AL_INVALID_VALUE);
1708 ProcessContext(Context);
1710 else
1712 // Invalid Context
1713 alSetError(AL_INVALID_OPERATION);
1716 return;
1720 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1722 ALCcontext *Context;
1723 ALsource *ALSource;
1724 ALsizei i;
1725 ALbufferlistitem *ALBufferList;
1726 ALbufferlistitem *ALBufferListStart;
1727 ALuint DataSize;
1728 ALuint BufferSize;
1729 ALint iFrequency;
1730 ALint iFormat;
1731 ALboolean bBuffersValid = AL_TRUE;
1733 if (n == 0)
1734 return;
1736 Context=alcGetCurrentContext();
1737 if (Context)
1739 SuspendContext(Context);
1741 DataSize = 0;
1742 BufferSize = 0;
1744 // Check that all buffers are valid or zero and that the source is valid
1746 // Check that this is a valid source
1747 if (alIsSource(source))
1749 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1751 // Check that this is not a STATIC Source
1752 if (ALSource->lSourceType != AL_STATIC)
1754 iFrequency = -1;
1755 iFormat = -1;
1757 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1758 ALBufferList = ALSource->queue;
1759 while (ALBufferList)
1761 if (ALBufferList->buffer)
1763 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1764 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1765 break;
1767 ALBufferList = ALBufferList->next;
1770 for (i = 0; i < n; i++)
1772 if (alIsBuffer(buffers[i]))
1774 if (buffers[i])
1776 if ((iFrequency == -1) && (iFormat == -1))
1778 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1779 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1781 else
1783 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1784 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1786 alSetError(AL_INVALID_OPERATION);
1787 bBuffersValid = AL_FALSE;
1788 break;
1793 else
1795 alSetError(AL_INVALID_NAME);
1796 bBuffersValid = AL_FALSE;
1797 break;
1801 if (bBuffersValid)
1803 // Change Source Type
1804 ALSource->lSourceType = AL_STREAMING;
1806 // All buffers are valid - so add them to the list
1807 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1808 ALBufferListStart->buffer = buffers[0];
1809 ALBufferListStart->bufferstate = PENDING;
1810 ALBufferListStart->flag = 0;
1811 ALBufferListStart->next = NULL;
1813 if (buffers[0])
1814 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1815 else
1816 BufferSize = 0;
1818 DataSize += BufferSize;
1820 // Increment reference counter for buffer
1821 if (buffers[0])
1822 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1824 ALBufferList = ALBufferListStart;
1826 for (i = 1; i < n; i++)
1828 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1829 ALBufferList->next->buffer = buffers[i];
1830 ALBufferList->next->bufferstate = PENDING;
1831 ALBufferList->next->flag = 0;
1832 ALBufferList->next->next = NULL;
1834 if (buffers[i])
1835 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1836 else
1837 BufferSize = 0;
1839 DataSize += BufferSize;
1841 // Increment reference counter for buffer
1842 if (buffers[i])
1843 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1845 ALBufferList = ALBufferList->next;
1848 if (ALSource->queue == NULL)
1850 ALSource->queue = ALBufferListStart;
1851 // Update Current Buffer
1852 ALSource->ulBufferID = ALBufferListStart->buffer;
1854 else
1856 // Find end of queue
1857 ALBufferList = ALSource->queue;
1858 while (ALBufferList->next != NULL)
1860 ALBufferList = ALBufferList->next;
1863 ALBufferList->next = ALBufferListStart;
1866 // Update number of buffers in queue
1867 ALSource->BuffersInQueue += n;
1870 else
1872 // Invalid Source Type (can't queue on a Static Source)
1873 alSetError(AL_INVALID_OPERATION);
1876 else
1878 // Invalid Source Name
1879 alSetError(AL_INVALID_NAME);
1882 ProcessContext(Context);
1884 else
1886 // Invalid Context
1887 alSetError(AL_INVALID_OPERATION);
1890 return;
1894 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1895 // an array of buffer IDs that are to be filled with the names of the buffers removed
1896 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1898 ALCcontext *Context;
1899 ALsource *ALSource;
1900 ALsizei i;
1901 ALbufferlistitem *ALBufferList;
1902 ALuint DataSize;
1903 ALuint BufferSize;
1904 ALuint BufferID;
1905 ALboolean bBuffersProcessed;
1907 if (n == 0)
1908 return;
1910 DataSize = 0;
1911 BufferSize = 0;
1912 bBuffersProcessed = AL_TRUE;
1914 Context=alcGetCurrentContext();
1915 if (Context)
1917 SuspendContext(Context);
1919 if (alIsSource(source))
1921 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1923 // Check that all 'n' buffers have been processed
1924 ALBufferList = ALSource->queue;
1925 for (i = 0; i < n; i++)
1927 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1929 ALBufferList = ALBufferList->next;
1931 else
1933 bBuffersProcessed = AL_FALSE;
1934 break;
1938 // If all 'n' buffers have been processed, remove them from the queue
1939 if (bBuffersProcessed)
1941 for (i = 0; i < n; i++)
1943 ALBufferList = ALSource->queue;
1945 ALSource->queue = ALBufferList->next;
1946 // Record name of buffer
1947 buffers[i] = ALBufferList->buffer;
1948 // Decrement buffer reference counter
1949 if (ALBufferList->buffer)
1950 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1951 // Record size of buffer
1952 if (ALBufferList->buffer)
1953 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1954 else
1955 BufferSize = 0;
1957 DataSize += BufferSize;
1958 // Release memory for buffer list item
1959 free(ALBufferList);
1960 ALSource->BuffersInQueue--;
1963 if (ALSource->state != AL_PLAYING)
1965 if (ALSource->queue)
1966 BufferID = ALSource->queue->buffer;
1967 else
1968 BufferID = 0;
1970 ALSource->ulBufferID = BufferID;
1973 if((ALuint)n > ALSource->BuffersPlayed)
1974 ALSource->BuffersPlayed = 0;
1975 else
1976 ALSource->BuffersPlayed -= n;
1978 else
1980 // Some buffers can't be unqueue because they have not been processed
1981 alSetError(AL_INVALID_VALUE);
1984 else
1986 // Invalid Source Name
1987 alSetError(AL_INVALID_NAME);
1990 ProcessContext(Context);
1992 else
1994 // Invalid Context
1995 alSetError(AL_INVALID_OPERATION);
1998 return;
2002 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
2004 pSource->flInnerAngle = 360.0f;
2005 pSource->flOuterAngle = 360.0f;
2006 pSource->flPitch = 1.0f;
2007 pSource->vPosition[0] = 0.0f;
2008 pSource->vPosition[1] = 0.0f;
2009 pSource->vPosition[2] = 0.0f;
2010 pSource->vOrientation[0] = 0.0f;
2011 pSource->vOrientation[1] = 0.0f;
2012 pSource->vOrientation[2] = 0.0f;
2013 pSource->vVelocity[0] = 0.0f;
2014 pSource->vVelocity[1] = 0.0f;
2015 pSource->vVelocity[2] = 0.0f;
2016 pSource->flRefDistance = 1.0f;
2017 pSource->flMaxDistance = FLT_MAX;
2018 pSource->flRollOffFactor = 1.0f;
2019 pSource->bLooping = AL_FALSE;
2020 pSource->flGain = 1.0f;
2021 pSource->flMinGain = 0.0f;
2022 pSource->flMaxGain = 1.0f;
2023 pSource->flOuterGain = 0.0f;
2024 pSource->OuterGainHF = 1.0f;
2026 pSource->DryGainHFAuto = AL_TRUE;
2027 pSource->WetGainAuto = AL_TRUE;
2028 pSource->WetGainHFAuto = AL_TRUE;
2029 pSource->AirAbsorptionFactor = 0.0f;
2030 pSource->RoomRolloffFactor = 0.0f;
2031 pSource->DopplerFactor = 1.0f;
2033 pSource->DistanceModel = Context->DistanceModel;
2035 pSource->state = AL_INITIAL;
2036 pSource->lSourceType = AL_UNDETERMINED;
2038 pSource->ulBufferID= 0;
2043 GetSourceOffset
2045 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2046 The offset is relative to the start of the queue (not the start of the current buffer)
2048 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
2050 ALbufferlistitem *pBufferList;
2051 ALbuffer *pBuffer;
2052 ALfloat flBufferFreq;
2053 ALint lChannels;
2054 ALint readPos, writePos;
2055 ALenum eOriginalFormat;
2056 ALboolean bReturn = AL_TRUE;
2057 ALint lTotalBufferDataSize;
2059 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2061 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2062 // Get Current Buffer Size and frequency (in milliseconds)
2063 flBufferFreq = (ALfloat)pBuffer->frequency;
2064 eOriginalFormat = pBuffer->eOriginalFormat;
2065 lChannels = aluChannelsFromFormat(pBuffer->format);
2067 // Get Current BytesPlayed
2068 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2069 // Add byte length of any processed buffers in the queue
2070 pBufferList = pSource->queue;
2071 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2073 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2074 pBufferList = pBufferList->next;
2077 if(pSource->state == AL_PLAYING)
2078 writePos = readPos + (updateSize * lChannels * 2);
2079 else
2080 writePos = readPos;
2082 lTotalBufferDataSize = 0;
2083 pBufferList = pSource->queue;
2084 while (pBufferList)
2086 if (pBufferList->buffer)
2087 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2088 pBufferList = pBufferList->next;
2091 if (pSource->bLooping)
2093 if(readPos < 0)
2094 readPos = 0;
2095 else
2096 readPos %= lTotalBufferDataSize;
2097 if(writePos < 0)
2098 writePos = 0;
2099 else
2100 writePos %= lTotalBufferDataSize;
2102 else
2104 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2105 if(readPos < 0)
2106 readPos = 0;
2107 else if(readPos > lTotalBufferDataSize)
2108 readPos = lTotalBufferDataSize;
2109 if(writePos < 0)
2110 writePos = 0;
2111 else if(writePos > lTotalBufferDataSize)
2112 writePos = lTotalBufferDataSize;
2115 switch (eName)
2117 case AL_SEC_OFFSET:
2118 case AL_SEC_RW_OFFSETS_EXT:
2119 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
2120 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
2121 break;
2122 case AL_SAMPLE_OFFSET:
2123 case AL_SAMPLE_RW_OFFSETS_EXT:
2124 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
2125 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
2126 break;
2127 case AL_BYTE_OFFSET:
2128 case AL_BYTE_RW_OFFSETS_EXT:
2129 // Take into account the original format of the Buffer
2130 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2131 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2133 // Round down to nearest ADPCM block
2134 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
2135 if(pSource->state == AL_PLAYING)
2137 // Round up to nearest ADPCM block
2138 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
2140 else
2141 pflOffset[1] = pflOffset[0];
2143 else if (eOriginalFormat == AL_FORMAT_REAR8)
2145 pflOffset[0] = (ALfloat)(readPos >> 2);
2146 pflOffset[1] = (ALfloat)(writePos >> 2);
2148 else if (eOriginalFormat == AL_FORMAT_REAR16)
2150 pflOffset[0] = (ALfloat)(readPos >> 1);
2151 pflOffset[1] = (ALfloat)(writePos >> 1);
2153 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2155 pflOffset[0] = (ALfloat)(readPos >> 1);
2156 pflOffset[1] = (ALfloat)(writePos >> 1);
2158 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2160 pflOffset[0] = (ALfloat)(readPos << 1);
2161 pflOffset[1] = (ALfloat)(writePos << 1);
2163 else
2165 pflOffset[0] = (ALfloat)readPos;
2166 pflOffset[1] = (ALfloat)writePos;
2168 break;
2171 else
2173 pflOffset[0] = 0.0f;
2174 pflOffset[1] = 0.0f;
2177 return bReturn;
2182 ApplyOffset
2184 Apply a playback offset to the Source. This function will update the queue (to correctly
2185 mark buffers as 'pending' or 'processed' depending upon the new offset.
2187 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2189 ALbufferlistitem *pBufferList;
2190 ALbuffer *pBuffer;
2191 ALint lBufferSize, lTotalBufferSize;
2192 ALint lByteOffset;
2194 // Get true byte offset
2195 lByteOffset = GetByteOffset(pSource);
2197 // If this is a valid offset apply it
2198 if (lByteOffset != -1)
2200 // Sort out the queue (pending and processed states)
2201 pBufferList = pSource->queue;
2202 lTotalBufferSize = 0;
2203 pSource->BuffersPlayed = 0;
2204 while (pBufferList)
2206 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2207 lBufferSize = pBuffer ? pBuffer->size : 0;
2209 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2211 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2212 // update the state to PROCESSED
2213 pSource->BuffersPlayed++;
2215 if (!pSource->bLooping)
2216 pBufferList->bufferstate = PROCESSED;
2218 else if (lTotalBufferSize <= lByteOffset)
2220 // Offset is within this buffer
2221 pBufferList->bufferstate = PENDING;
2223 // Set Current Buffer ID
2224 pSource->ulBufferID = pBufferList->buffer;
2226 // SW Mixer Positions are in Samples
2227 pSource->position = (lByteOffset - lTotalBufferSize) /
2228 aluBytesFromFormat(pBuffer->format) /
2229 aluChannelsFromFormat(pBuffer->format);
2231 else
2233 // Offset is before this buffer, so mark as pending
2234 pBufferList->bufferstate = PENDING;
2237 // Increment the TotalBufferSize
2238 lTotalBufferSize += lBufferSize;
2240 // Move on to next buffer in the Queue
2241 pBufferList = pBufferList->next;
2244 else
2246 if (bUpdateContext)
2247 alSetError(AL_INVALID_VALUE);
2250 // Clear Offset
2251 pSource->lOffset = 0;
2256 GetByteOffset
2258 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2259 offset supplied by the application). This takes into account the fact that the buffer format
2260 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2262 static ALint GetByteOffset(ALsource *pSource)
2264 ALbuffer *pBuffer = NULL;
2265 ALbufferlistitem *pBufferList;
2266 ALfloat flBufferFreq;
2267 ALint lChannels;
2268 ALint lByteOffset = -1;
2269 ALint lTotalBufferDataSize;
2271 // Find the first non-NULL Buffer in the Queue
2272 pBufferList = pSource->queue;
2273 while (pBufferList)
2275 if (pBufferList->buffer)
2277 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2278 break;
2280 pBufferList = pBufferList->next;
2283 if (pBuffer)
2285 flBufferFreq = ((ALfloat)pBuffer->frequency);
2286 lChannels = aluChannelsFromFormat(pBuffer->format);
2288 // Determine the ByteOffset (and ensure it is block aligned)
2289 switch (pSource->lOffsetType)
2291 case AL_BYTE_OFFSET:
2292 // Take into consideration the original format
2293 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2294 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2296 // Round down to nearest ADPCM block
2297 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2298 // Multiply by compression rate
2299 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2300 lByteOffset -= (lByteOffset % (lChannels * 2));
2302 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2304 lByteOffset = pSource->lOffset * 4;
2305 lByteOffset -= (lByteOffset % (lChannels * 2));
2307 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2309 lByteOffset = pSource->lOffset * 2;
2310 lByteOffset -= (lByteOffset % (lChannels * 2));
2312 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2314 lByteOffset = pSource->lOffset * 2;
2315 lByteOffset -= (lByteOffset % (lChannels * 2));
2317 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2319 lByteOffset = pSource->lOffset / 2;
2320 lByteOffset -= (lByteOffset % (lChannels * 2));
2322 else
2324 lByteOffset = pSource->lOffset;
2325 lByteOffset -= (lByteOffset % (lChannels * 2));
2327 break;
2329 case AL_SAMPLE_OFFSET:
2330 lByteOffset = pSource->lOffset * lChannels * 2;
2331 break;
2333 case AL_SEC_OFFSET:
2334 // Note - lOffset is internally stored as Milliseconds
2335 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2336 lByteOffset -= (lByteOffset % (lChannels * 2));
2337 break;
2340 lTotalBufferDataSize = 0;
2341 pBufferList = pSource->queue;
2342 while (pBufferList)
2344 if (pBufferList->buffer)
2345 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2346 pBufferList = pBufferList->next;
2349 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2350 if (lByteOffset >= lTotalBufferDataSize)
2351 lByteOffset = -1;
2354 return lByteOffset;
2358 ALvoid ReleaseALSources(ALCcontext *Context)
2360 #ifdef _DEBUG
2361 if(Context->SourceCount > 0)
2362 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2363 #endif
2365 while(Context->Source)
2367 ALsource *temp = Context->Source;
2368 Context->Source = Context->Source->next;
2370 // Release source structure
2371 ALTHUNK_REMOVEENTRY(temp->source);
2372 memset(temp, 0, sizeof(ALsource));
2373 free(temp);
2375 Context->SourceCount = 0;