Add initial AL_EXTX_buffer_sub_data support
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blobaa2d5719fa163752f749928440234a4d88e29791
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = alcGetCurrentContext();
47 if (Context)
49 SuspendContext(Context);
51 if (n > 0)
53 Device = alcGetContextsDevice(Context);
55 if (Device)
57 // Check that enough memory has been allocted in the 'sources' array for n Sources
58 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
60 // Check that the requested number of sources can be generated
61 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
63 ALsource **list = &Context->Source;
64 while(*list)
65 list = &(*list)->next;
67 // Add additional sources to the list (Source->next points to the location for the next Source structure)
68 while(i < n)
70 *list = calloc(1, sizeof(ALsource));
71 if(!(*list))
73 alDeleteSources(i, sources);
74 alSetError(AL_OUT_OF_MEMORY);
75 break;
78 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->source = sources[i];
81 InitSourceParams(*list);
82 Context->SourceCount++;
83 i++;
85 list = &(*list)->next;
88 else
90 // Not enough resources to create the Sources
91 alSetError(AL_INVALID_VALUE);
94 else
96 // Bad pointer
97 alSetError(AL_INVALID_VALUE);
100 else
102 // No Device created, or attached to Context
103 alSetError(AL_INVALID_OPERATION);
107 ProcessContext(Context);
109 else
111 // Invalid Context
112 alSetError(AL_INVALID_OPERATION);
115 return;
119 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
121 ALCcontext *Context;
122 ALCdevice *Device;
123 ALsource *ALSource;
124 ALsource **list;
125 ALsizei i, j;
126 ALbufferlistitem *ALBufferList;
127 ALboolean bSourcesValid = AL_TRUE;
129 Context = alcGetCurrentContext();
130 if (Context)
132 SuspendContext(Context);
134 if (n >= 0)
136 Device = alcGetContextsDevice(Context);
138 if (Device)
140 // Check that all Sources are valid (and can therefore be deleted)
141 for (i = 0; i < n; i++)
143 if (!alIsSource(sources[i]))
145 alSetError(AL_INVALID_NAME);
146 bSourcesValid = AL_FALSE;
147 break;
151 if (bSourcesValid)
153 // All Sources are valid, and can be deleted
154 for (i = 0; i < n; i++)
156 // Recheck that the Source is valid, because there could be duplicated Source names
157 if (alIsSource(sources[i]))
159 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
160 alSourceStop((ALuint)ALSource->source);
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while (ALSource->queue != NULL)
165 ALBufferList = ALSource->queue;
166 // Decrement buffer's reference counter
167 if (ALBufferList->buffer != 0)
168 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
169 // Update queue to point to next element in list
170 ALSource->queue = ALBufferList->next;
171 // Release memory allocated for buffer list item
172 free(ALBufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(ALSource->Send[j].Slot)
178 ALSource->Send[j].Slot->refcount--;
179 ALSource->Send[j].Slot = NULL;
182 // Decrement Source count
183 Context->SourceCount--;
185 // Remove Source from list of Sources
186 list = &Context->Source;
187 while(*list && *list != ALSource)
188 list = &(*list)->next;
190 if(*list)
191 *list = (*list)->next;
192 ALTHUNK_REMOVEENTRY(ALSource->source);
194 memset(ALSource,0,sizeof(ALsource));
195 free(ALSource);
200 else
202 // No Device created, or attached to Context
203 alSetError(AL_INVALID_OPERATION);
206 else
207 alSetError(AL_INVALID_VALUE);
209 ProcessContext(Context);
211 else
213 // Invalid Context
214 alSetError(AL_INVALID_OPERATION);
217 return;
221 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
223 ALboolean result=AL_FALSE;
224 ALCcontext *Context;
225 ALsource *Source;
227 Context=alcGetCurrentContext();
228 if (Context)
230 SuspendContext(Context);
232 // To determine if this is a valid Source name, look through the list of generated Sources
233 Source = Context->Source;
234 while(Source)
236 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
238 result = AL_TRUE;
239 break;
242 Source = Source->next;
245 ProcessContext(Context);
247 else
249 // Invalid Context
250 alSetError(AL_INVALID_OPERATION);
253 return result;
257 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
259 ALCcontext *pContext;
260 ALsource *pSource;
262 pContext = alcGetCurrentContext();
263 if (pContext)
265 SuspendContext(pContext);
267 if (alIsSource(source))
269 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
271 switch (eParam)
273 case AL_PITCH:
274 if (flValue >= 0.0f)
276 pSource->flPitch = flValue;
277 if(pSource->flPitch < 0.001f)
278 pSource->flPitch = 0.001f;
280 else
281 alSetError(AL_INVALID_VALUE);
282 break;
284 case AL_CONE_INNER_ANGLE:
285 if ((flValue >= 0.0f) && (flValue <= 360.0f))
286 pSource->flInnerAngle = flValue;
287 else
288 alSetError(AL_INVALID_VALUE);
289 break;
291 case AL_CONE_OUTER_ANGLE:
292 if ((flValue >= 0.0f) && (flValue <= 360.0f))
293 pSource->flOuterAngle = flValue;
294 else
295 alSetError(AL_INVALID_VALUE);
296 break;
298 case AL_GAIN:
299 if (flValue >= 0.0f)
300 pSource->flGain = flValue;
301 else
302 alSetError(AL_INVALID_VALUE);
303 break;
305 case AL_MAX_DISTANCE:
306 if (flValue >= 0.0f)
307 pSource->flMaxDistance = flValue;
308 else
309 alSetError(AL_INVALID_VALUE);
310 break;
312 case AL_ROLLOFF_FACTOR:
313 if (flValue >= 0.0f)
314 pSource->flRollOffFactor = flValue;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_REFERENCE_DISTANCE:
320 if (flValue >= 0.0f)
321 pSource->flRefDistance = flValue;
322 else
323 alSetError(AL_INVALID_VALUE);
324 break;
326 case AL_MIN_GAIN:
327 if ((flValue >= 0.0f) && (flValue <= 1.0f))
328 pSource->flMinGain = flValue;
329 else
330 alSetError(AL_INVALID_VALUE);
331 break;
333 case AL_MAX_GAIN:
334 if ((flValue >= 0.0f) && (flValue <= 1.0f))
335 pSource->flMaxGain = flValue;
336 else
337 alSetError(AL_INVALID_VALUE);
338 break;
340 case AL_CONE_OUTER_GAIN:
341 if ((flValue >= 0.0f) && (flValue <= 1.0f))
342 pSource->flOuterGain = flValue;
343 else
344 alSetError(AL_INVALID_VALUE);
345 break;
347 case AL_CONE_OUTER_GAINHF:
348 if ((flValue >= 0.0f) && (flValue <= 1.0f))
349 pSource->OuterGainHF = flValue;
350 else
351 alSetError(AL_INVALID_VALUE);
352 break;
354 case AL_AIR_ABSORPTION_FACTOR:
355 if (flValue >= 0.0f && flValue <= 10.0f)
356 pSource->AirAbsorptionFactor = flValue;
357 else
358 alSetError(AL_INVALID_VALUE);
359 break;
361 case AL_ROOM_ROLLOFF_FACTOR:
362 if (flValue >= 0.0f && flValue <= 1.0f)
363 pSource->RoomRolloffFactor = flValue;
364 else
365 alSetError(AL_INVALID_VALUE);
366 break;
368 case AL_DOPPLER_FACTOR:
369 if (flValue >= 0.0f && flValue <= 1.0f)
370 pSource->DopplerFactor = flValue;
371 else
372 alSetError(AL_INVALID_VALUE);
373 break;
375 case AL_SEC_OFFSET:
376 case AL_SAMPLE_OFFSET:
377 case AL_BYTE_OFFSET:
378 if (flValue >= 0.0f)
380 pSource->lOffsetType = eParam;
382 // Store Offset (convert Seconds into Milliseconds)
383 if (eParam == AL_SEC_OFFSET)
384 pSource->lOffset = (ALint)(flValue * 1000.0f);
385 else
386 pSource->lOffset = (ALint)flValue;
388 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
389 ApplyOffset(pSource, AL_TRUE);
391 else
392 alSetError(AL_INVALID_VALUE);
393 break;
395 default:
396 alSetError(AL_INVALID_ENUM);
397 break;
400 else
402 // Invalid Source Name
403 alSetError(AL_INVALID_NAME);
406 ProcessContext(pContext);
408 else
410 // Invalid context
411 alSetError(AL_INVALID_OPERATION);
414 return;
418 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
420 ALCcontext *pContext;
421 ALsource *pSource;
423 pContext = alcGetCurrentContext();
424 if (pContext)
426 SuspendContext(pContext);
428 if (alIsSource(source))
430 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
431 switch(eParam)
433 case AL_POSITION:
434 pSource->vPosition[0] = flValue1;
435 pSource->vPosition[1] = flValue2;
436 pSource->vPosition[2] = flValue3;
437 break;
439 case AL_VELOCITY:
440 pSource->vVelocity[0] = flValue1;
441 pSource->vVelocity[1] = flValue2;
442 pSource->vVelocity[2] = flValue3;
443 break;
445 case AL_DIRECTION:
446 pSource->vOrientation[0] = flValue1;
447 pSource->vOrientation[1] = flValue2;
448 pSource->vOrientation[2] = flValue3;
449 break;
451 default:
452 alSetError(AL_INVALID_ENUM);
453 break;
456 else
457 alSetError(AL_INVALID_NAME);
459 ProcessContext(pContext);
461 else
463 alSetError(AL_INVALID_OPERATION);
466 return;
470 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
472 ALCcontext *pContext;
474 pContext = alcGetCurrentContext();
475 if (pContext)
477 SuspendContext(pContext);
479 if (pflValues)
481 if (alIsSource(source))
483 switch (eParam)
485 case AL_PITCH:
486 case AL_CONE_INNER_ANGLE:
487 case AL_CONE_OUTER_ANGLE:
488 case AL_GAIN:
489 case AL_MAX_DISTANCE:
490 case AL_ROLLOFF_FACTOR:
491 case AL_REFERENCE_DISTANCE:
492 case AL_MIN_GAIN:
493 case AL_MAX_GAIN:
494 case AL_CONE_OUTER_GAIN:
495 case AL_CONE_OUTER_GAINHF:
496 case AL_SEC_OFFSET:
497 case AL_SAMPLE_OFFSET:
498 case AL_BYTE_OFFSET:
499 case AL_AIR_ABSORPTION_FACTOR:
500 case AL_ROOM_ROLLOFF_FACTOR:
501 alSourcef(source, eParam, pflValues[0]);
502 break;
504 case AL_POSITION:
505 case AL_VELOCITY:
506 case AL_DIRECTION:
507 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
508 break;
510 default:
511 alSetError(AL_INVALID_ENUM);
512 break;
515 else
516 alSetError(AL_INVALID_NAME);
518 else
519 alSetError(AL_INVALID_VALUE);
521 ProcessContext(pContext);
523 else
524 alSetError(AL_INVALID_OPERATION);
526 return;
530 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
532 ALCcontext *pContext;
533 ALsource *pSource;
534 ALbufferlistitem *pALBufferListItem;
535 ALint Counter = 0;
536 ALint DataSize = 0;
537 ALint BufferSize;
539 pContext = alcGetCurrentContext();
540 if (pContext)
542 SuspendContext(pContext);
544 if (alIsSource(source))
546 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
548 switch(eParam)
550 case AL_MAX_DISTANCE:
551 case AL_ROLLOFF_FACTOR:
552 case AL_REFERENCE_DISTANCE:
553 alSourcef(source, eParam, (ALfloat)lValue);
554 break;
556 case AL_SOURCE_RELATIVE:
557 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
558 pSource->bHeadRelative = (ALboolean)lValue;
559 else
560 alSetError(AL_INVALID_VALUE);
561 break;
563 case AL_CONE_INNER_ANGLE:
564 if ((lValue >= 0) && (lValue <= 360))
565 pSource->flInnerAngle = (float)lValue;
566 else
567 alSetError(AL_INVALID_VALUE);
568 break;
570 case AL_CONE_OUTER_ANGLE:
571 if ((lValue >= 0) && (lValue <= 360))
572 pSource->flOuterAngle = (float)lValue;
573 else
574 alSetError(AL_INVALID_VALUE);
575 break;
577 case AL_LOOPING:
578 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
579 pSource->bLooping = (ALboolean)lValue;
580 else
581 alSetError(AL_INVALID_VALUE);
582 break;
584 case AL_BUFFER:
585 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
587 if (alIsBuffer(lValue))
589 // Remove all elements in the queue
590 while (pSource->queue != NULL)
592 pALBufferListItem = pSource->queue;
593 pSource->queue = pALBufferListItem->next;
594 // Decrement reference counter for buffer
595 if (pALBufferListItem->buffer)
596 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
597 // Record size of buffer
598 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
599 DataSize += BufferSize;
600 // Increment the number of buffers removed from queue
601 Counter++;
602 // Release memory for buffer list item
603 free(pALBufferListItem);
604 // Decrement the number of buffers in the queue
605 pSource->BuffersInQueue--;
608 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
609 if (lValue != 0)
611 // Source is now in STATIC mode
612 pSource->lSourceType = AL_STATIC;
614 // Add the selected buffer to the queue
615 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
616 pALBufferListItem->buffer = lValue;
617 pALBufferListItem->bufferstate = PENDING;
618 pALBufferListItem->flag = 0;
619 pALBufferListItem->next = NULL;
621 pSource->queue = pALBufferListItem;
622 pSource->BuffersInQueue = 1;
624 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
626 // Increment reference counter for buffer
627 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
629 else
631 // Source is now in UNDETERMINED mode
632 pSource->lSourceType = AL_UNDETERMINED;
635 // Update AL_BUFFER parameter
636 pSource->ulBufferID = lValue;
638 else
639 alSetError(AL_INVALID_VALUE);
641 else
642 alSetError(AL_INVALID_OPERATION);
643 break;
645 case AL_SOURCE_STATE:
646 // Query only
647 alSetError(AL_INVALID_OPERATION);
648 break;
650 case AL_SEC_OFFSET:
651 case AL_SAMPLE_OFFSET:
652 case AL_BYTE_OFFSET:
653 if (lValue >= 0)
655 pSource->lOffsetType = eParam;
657 // Store Offset (convert Seconds into Milliseconds)
658 if (eParam == AL_SEC_OFFSET)
659 pSource->lOffset = lValue * 1000;
660 else
661 pSource->lOffset = lValue;
663 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
664 ApplyOffset(pSource, AL_TRUE);
666 else
667 alSetError(AL_INVALID_VALUE);
668 break;
670 case AL_DIRECT_FILTER:
671 if(alIsFilter(lValue))
673 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
674 if(!filter)
676 pSource->DirectFilter.type = AL_FILTER_NULL;
677 pSource->DirectFilter.filter = 0;
679 else
680 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
682 else
683 alSetError(AL_INVALID_VALUE);
684 break;
686 case AL_DIRECT_FILTER_GAINHF_AUTO:
687 if(lValue == AL_TRUE || lValue == AL_FALSE)
688 pSource->DryGainHFAuto = lValue;
689 else
690 alSetError(AL_INVALID_VALUE);
691 break;
693 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
694 if(lValue == AL_TRUE || lValue == AL_FALSE)
695 pSource->WetGainAuto = lValue;
696 else
697 alSetError(AL_INVALID_VALUE);
698 break;
700 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
701 if(lValue == AL_TRUE || lValue == AL_FALSE)
702 pSource->WetGainHFAuto = lValue;
703 else
704 alSetError(AL_INVALID_VALUE);
705 break;
707 default:
708 alSetError(AL_INVALID_ENUM);
709 break;
712 else
713 alSetError(AL_INVALID_NAME);
715 ProcessContext(pContext);
717 else
718 alSetError(AL_INVALID_OPERATION);
720 return;
724 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
726 ALCcontext *pContext;
728 pContext = alcGetCurrentContext();
729 if (pContext)
731 SuspendContext(pContext);
733 if (alIsSource(source))
735 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
737 switch (eParam)
739 case AL_POSITION:
740 case AL_VELOCITY:
741 case AL_DIRECTION:
742 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
743 break;
745 case AL_AUXILIARY_SEND_FILTER:
746 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
747 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
748 alIsFilter(lValue3))
750 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
751 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
753 /* Release refcount on the previous slot, and add one for
754 * the new slot */
755 if(pSource->Send[lValue2].Slot)
756 pSource->Send[lValue2].Slot->refcount--;
757 pSource->Send[lValue2].Slot = ALEffectSlot;
758 if(pSource->Send[lValue2].Slot)
759 pSource->Send[lValue2].Slot->refcount++;
761 if(!ALFilter)
763 /* Disable filter */
764 pSource->Send[lValue2].WetFilter.type = 0;
765 pSource->Send[lValue2].WetFilter.filter = 0;
767 else
768 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
770 else
771 alSetError(AL_INVALID_VALUE);
772 break;
774 default:
775 alSetError(AL_INVALID_ENUM);
776 break;
779 else
780 alSetError(AL_INVALID_NAME);
782 ProcessContext(pContext);
784 else
785 alSetError(AL_INVALID_OPERATION);
787 return;
791 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
793 ALCcontext *pContext;
795 pContext = alcGetCurrentContext();
796 if (pContext)
798 SuspendContext(pContext);
800 if (plValues)
802 if (alIsSource(source))
804 switch (eParam)
806 case AL_SOURCE_RELATIVE:
807 case AL_CONE_INNER_ANGLE:
808 case AL_CONE_OUTER_ANGLE:
809 case AL_LOOPING:
810 case AL_BUFFER:
811 case AL_SOURCE_STATE:
812 case AL_SEC_OFFSET:
813 case AL_SAMPLE_OFFSET:
814 case AL_BYTE_OFFSET:
815 case AL_MAX_DISTANCE:
816 case AL_ROLLOFF_FACTOR:
817 case AL_REFERENCE_DISTANCE:
818 case AL_DIRECT_FILTER:
819 case AL_DIRECT_FILTER_GAINHF_AUTO:
820 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
821 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
822 alSourcei(source, eParam, plValues[0]);
823 break;
825 case AL_POSITION:
826 case AL_VELOCITY:
827 case AL_DIRECTION:
828 case AL_AUXILIARY_SEND_FILTER:
829 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
830 break;
832 default:
833 alSetError(AL_INVALID_ENUM);
834 break;
837 else
838 alSetError(AL_INVALID_NAME);
840 else
841 alSetError(AL_INVALID_VALUE);
843 ProcessContext(pContext);
845 else
846 alSetError(AL_INVALID_OPERATION);
848 return;
852 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
854 ALCcontext *pContext;
855 ALsource *pSource;
856 ALfloat flOffset[2];
858 pContext = alcGetCurrentContext();
859 if (pContext)
861 SuspendContext(pContext);
863 if (pflValue)
865 if (alIsSource(source))
867 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
869 switch(eParam)
871 case AL_PITCH:
872 *pflValue = pSource->flPitch;
873 break;
875 case AL_GAIN:
876 *pflValue = pSource->flGain;
877 break;
879 case AL_MIN_GAIN:
880 *pflValue = pSource->flMinGain;
881 break;
883 case AL_MAX_GAIN:
884 *pflValue = pSource->flMaxGain;
885 break;
887 case AL_MAX_DISTANCE:
888 *pflValue = pSource->flMaxDistance;
889 break;
891 case AL_ROLLOFF_FACTOR:
892 *pflValue = pSource->flRollOffFactor;
893 break;
895 case AL_CONE_OUTER_GAIN:
896 *pflValue = pSource->flOuterGain;
897 break;
899 case AL_CONE_OUTER_GAINHF:
900 *pflValue = pSource->OuterGainHF;
901 break;
903 case AL_SEC_OFFSET:
904 case AL_SAMPLE_OFFSET:
905 case AL_BYTE_OFFSET:
906 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
907 *pflValue = flOffset[0];
908 else
909 alSetError(AL_INVALID_OPERATION);
910 break;
912 case AL_SEC_RW_OFFSETS_EXT:
913 case AL_SAMPLE_RW_OFFSETS_EXT:
914 case AL_BYTE_RW_OFFSETS_EXT:
915 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
917 pflValue[0] = flOffset[0];
918 pflValue[1] = flOffset[1];
920 else
921 alSetError(AL_INVALID_OPERATION);
922 break;
924 case AL_CONE_INNER_ANGLE:
925 *pflValue = pSource->flInnerAngle;
926 break;
928 case AL_CONE_OUTER_ANGLE:
929 *pflValue = pSource->flOuterAngle;
930 break;
932 case AL_REFERENCE_DISTANCE:
933 *pflValue = pSource->flRefDistance;
934 break;
936 case AL_AIR_ABSORPTION_FACTOR:
937 *pflValue = pSource->AirAbsorptionFactor;
938 break;
940 case AL_ROOM_ROLLOFF_FACTOR:
941 *pflValue = pSource->RoomRolloffFactor;
942 break;
944 case AL_DOPPLER_FACTOR:
945 *pflValue = pSource->DopplerFactor;
946 break;
948 default:
949 alSetError(AL_INVALID_ENUM);
950 break;
953 else
954 alSetError(AL_INVALID_NAME);
956 else
957 alSetError(AL_INVALID_VALUE);
959 ProcessContext(pContext);
961 else
962 alSetError(AL_INVALID_OPERATION);
964 return;
968 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
970 ALCcontext *pContext;
971 ALsource *pSource;
973 pContext = alcGetCurrentContext();
974 if (pContext)
976 SuspendContext(pContext);
978 if ((pflValue1) && (pflValue2) && (pflValue3))
980 if (alIsSource(source))
982 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
984 switch(eParam)
986 case AL_POSITION:
987 *pflValue1 = pSource->vPosition[0];
988 *pflValue2 = pSource->vPosition[1];
989 *pflValue3 = pSource->vPosition[2];
990 break;
992 case AL_VELOCITY:
993 *pflValue1 = pSource->vVelocity[0];
994 *pflValue2 = pSource->vVelocity[1];
995 *pflValue3 = pSource->vVelocity[2];
996 break;
998 case AL_DIRECTION:
999 *pflValue1 = pSource->vOrientation[0];
1000 *pflValue2 = pSource->vOrientation[1];
1001 *pflValue3 = pSource->vOrientation[2];
1002 break;
1004 default:
1005 alSetError(AL_INVALID_ENUM);
1006 break;
1009 else
1010 alSetError(AL_INVALID_NAME);
1012 else
1013 alSetError(AL_INVALID_VALUE);
1015 ProcessContext(pContext);
1017 else
1018 alSetError(AL_INVALID_OPERATION);
1020 return;
1024 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1026 ALCcontext *pContext;
1027 ALsource *pSource;
1029 pContext = alcGetCurrentContext();
1030 if (pContext)
1032 SuspendContext(pContext);
1034 if (pflValues)
1036 if (alIsSource(source))
1038 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1040 switch(eParam)
1042 case AL_PITCH:
1043 case AL_GAIN:
1044 case AL_MIN_GAIN:
1045 case AL_MAX_GAIN:
1046 case AL_MAX_DISTANCE:
1047 case AL_ROLLOFF_FACTOR:
1048 case AL_DOPPLER_FACTOR:
1049 case AL_CONE_OUTER_GAIN:
1050 case AL_SEC_OFFSET:
1051 case AL_SAMPLE_OFFSET:
1052 case AL_BYTE_OFFSET:
1053 case AL_CONE_INNER_ANGLE:
1054 case AL_CONE_OUTER_ANGLE:
1055 case AL_REFERENCE_DISTANCE:
1056 case AL_CONE_OUTER_GAINHF:
1057 case AL_AIR_ABSORPTION_FACTOR:
1058 case AL_ROOM_ROLLOFF_FACTOR:
1059 alGetSourcef(source, eParam, pflValues);
1060 break;
1062 case AL_POSITION:
1063 pflValues[0] = pSource->vPosition[0];
1064 pflValues[1] = pSource->vPosition[1];
1065 pflValues[2] = pSource->vPosition[2];
1066 break;
1068 case AL_VELOCITY:
1069 pflValues[0] = pSource->vVelocity[0];
1070 pflValues[1] = pSource->vVelocity[1];
1071 pflValues[2] = pSource->vVelocity[2];
1072 break;
1074 case AL_DIRECTION:
1075 pflValues[0] = pSource->vOrientation[0];
1076 pflValues[1] = pSource->vOrientation[1];
1077 pflValues[2] = pSource->vOrientation[2];
1078 break;
1080 default:
1081 alSetError(AL_INVALID_ENUM);
1082 break;
1085 else
1086 alSetError(AL_INVALID_NAME);
1088 else
1089 alSetError(AL_INVALID_VALUE);
1091 ProcessContext(pContext);
1093 else
1094 alSetError(AL_INVALID_OPERATION);
1096 return;
1100 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1102 ALCcontext *pContext;
1103 ALsource *pSource;
1104 ALfloat flOffset[2];
1106 pContext = alcGetCurrentContext();
1107 if (pContext)
1109 SuspendContext(pContext);
1111 if (plValue)
1113 if (alIsSource(source))
1115 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1117 switch(eParam)
1119 case AL_MAX_DISTANCE:
1120 *plValue = (ALint)pSource->flMaxDistance;
1121 break;
1123 case AL_ROLLOFF_FACTOR:
1124 *plValue = (ALint)pSource->flRollOffFactor;
1125 break;
1127 case AL_REFERENCE_DISTANCE:
1128 *plValue = (ALint)pSource->flRefDistance;
1129 break;
1131 case AL_SOURCE_RELATIVE:
1132 *plValue = pSource->bHeadRelative;
1133 break;
1135 case AL_CONE_INNER_ANGLE:
1136 *plValue = (ALint)pSource->flInnerAngle;
1137 break;
1139 case AL_CONE_OUTER_ANGLE:
1140 *plValue = (ALint)pSource->flOuterAngle;
1141 break;
1143 case AL_LOOPING:
1144 *plValue = pSource->bLooping;
1145 break;
1147 case AL_BUFFER:
1148 *plValue = pSource->ulBufferID;
1149 break;
1151 case AL_SOURCE_STATE:
1152 *plValue = pSource->state;
1153 break;
1155 case AL_BUFFERS_QUEUED:
1156 *plValue = pSource->BuffersInQueue;
1157 break;
1159 case AL_BUFFERS_PROCESSED:
1160 if(pSource->bLooping)
1162 /* Buffers on a looping source are in a perpetual state
1163 * of PENDING, so don't report any as PROCESSED */
1164 *plValue = 0;
1166 else
1167 *plValue = pSource->BuffersPlayed;
1168 break;
1170 case AL_SOURCE_TYPE:
1171 *plValue = pSource->lSourceType;
1172 break;
1174 case AL_SEC_OFFSET:
1175 case AL_SAMPLE_OFFSET:
1176 case AL_BYTE_OFFSET:
1177 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1178 *plValue = (ALint)flOffset[0];
1179 else
1180 alSetError(AL_INVALID_OPERATION);
1181 break;
1183 case AL_SEC_RW_OFFSETS_EXT:
1184 case AL_SAMPLE_RW_OFFSETS_EXT:
1185 case AL_BYTE_RW_OFFSETS_EXT:
1186 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1188 plValue[0] = (ALint)flOffset[0];
1189 plValue[1] = (ALint)flOffset[1];
1191 else
1192 alSetError(AL_INVALID_OPERATION);
1193 break;
1195 case AL_DIRECT_FILTER:
1196 *plValue = pSource->DirectFilter.filter;
1197 break;
1199 case AL_DIRECT_FILTER_GAINHF_AUTO:
1200 *plValue = pSource->DryGainHFAuto;
1201 break;
1203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1204 *plValue = pSource->WetGainAuto;
1205 break;
1207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1208 *plValue = pSource->WetGainHFAuto;
1209 break;
1211 case AL_DOPPLER_FACTOR:
1212 *plValue = (ALint)pSource->DopplerFactor;
1213 break;
1215 default:
1216 alSetError(AL_INVALID_ENUM);
1217 break;
1220 else
1221 alSetError(AL_INVALID_NAME);
1223 else
1224 alSetError(AL_INVALID_VALUE);
1226 ProcessContext(pContext);
1228 else
1229 alSetError(AL_INVALID_OPERATION);
1231 return;
1235 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1237 ALCcontext *pContext;
1238 ALsource *pSource;
1240 pContext = alcGetCurrentContext();
1241 if (pContext)
1243 SuspendContext(pContext);
1245 if ((plValue1) && (plValue2) && (plValue3))
1247 if (alIsSource(source))
1249 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1251 switch(eParam)
1253 case AL_POSITION:
1254 *plValue1 = (ALint)pSource->vPosition[0];
1255 *plValue2 = (ALint)pSource->vPosition[1];
1256 *plValue3 = (ALint)pSource->vPosition[2];
1257 break;
1259 case AL_VELOCITY:
1260 *plValue1 = (ALint)pSource->vVelocity[0];
1261 *plValue2 = (ALint)pSource->vVelocity[1];
1262 *plValue3 = (ALint)pSource->vVelocity[2];
1263 break;
1265 case AL_DIRECTION:
1266 *plValue1 = (ALint)pSource->vOrientation[0];
1267 *plValue2 = (ALint)pSource->vOrientation[1];
1268 *plValue3 = (ALint)pSource->vOrientation[2];
1269 break;
1271 default:
1272 alSetError(AL_INVALID_ENUM);
1273 break;
1276 else
1277 alSetError(AL_INVALID_NAME);
1279 else
1280 alSetError(AL_INVALID_VALUE);
1282 ProcessContext(pContext);
1284 else
1285 alSetError(AL_INVALID_OPERATION);
1287 return;
1291 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1293 ALCcontext *pContext;
1294 ALsource *pSource;
1296 pContext = alcGetCurrentContext();
1297 if (pContext)
1299 SuspendContext(pContext);
1301 if (plValues)
1303 if (alIsSource(source))
1305 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1307 switch (eParam)
1309 case AL_SOURCE_RELATIVE:
1310 case AL_CONE_INNER_ANGLE:
1311 case AL_CONE_OUTER_ANGLE:
1312 case AL_LOOPING:
1313 case AL_BUFFER:
1314 case AL_SOURCE_STATE:
1315 case AL_BUFFERS_QUEUED:
1316 case AL_BUFFERS_PROCESSED:
1317 case AL_SEC_OFFSET:
1318 case AL_SAMPLE_OFFSET:
1319 case AL_BYTE_OFFSET:
1320 case AL_MAX_DISTANCE:
1321 case AL_ROLLOFF_FACTOR:
1322 case AL_DOPPLER_FACTOR:
1323 case AL_REFERENCE_DISTANCE:
1324 case AL_SOURCE_TYPE:
1325 case AL_DIRECT_FILTER:
1326 case AL_DIRECT_FILTER_GAINHF_AUTO:
1327 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1328 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1329 alGetSourcei(source, eParam, plValues);
1330 break;
1332 case AL_POSITION:
1333 plValues[0] = (ALint)pSource->vPosition[0];
1334 plValues[1] = (ALint)pSource->vPosition[1];
1335 plValues[2] = (ALint)pSource->vPosition[2];
1336 break;
1338 case AL_VELOCITY:
1339 plValues[0] = (ALint)pSource->vVelocity[0];
1340 plValues[1] = (ALint)pSource->vVelocity[1];
1341 plValues[2] = (ALint)pSource->vVelocity[2];
1342 break;
1344 case AL_DIRECTION:
1345 plValues[0] = (ALint)pSource->vOrientation[0];
1346 plValues[1] = (ALint)pSource->vOrientation[1];
1347 plValues[2] = (ALint)pSource->vOrientation[2];
1348 break;
1350 default:
1351 alSetError(AL_INVALID_ENUM);
1352 break;
1355 else
1356 alSetError(AL_INVALID_NAME);
1358 else
1359 alSetError(AL_INVALID_VALUE);
1361 ProcessContext(pContext);
1363 else
1364 alSetError(AL_INVALID_OPERATION);
1366 return;
1370 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1372 alSourcePlayv(1, &source);
1373 return;
1376 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1378 ALCcontext *pContext;
1379 ALsource *pSource;
1380 ALbufferlistitem *ALBufferList;
1381 ALboolean bSourcesValid = AL_TRUE;
1382 ALboolean bPlay;
1383 ALsizei i, j;
1385 pContext = alcGetCurrentContext();
1386 if (pContext)
1388 SuspendContext(pContext);
1390 if (pSourceList)
1392 // Check that all the Sources are valid
1393 for (i = 0; i < n; i++)
1395 if (!alIsSource(pSourceList[i]))
1397 alSetError(AL_INVALID_NAME);
1398 bSourcesValid = AL_FALSE;
1399 break;
1403 if (bSourcesValid)
1405 for (i = 0; i < n; i++)
1407 // Assume Source won't need to play
1408 bPlay = AL_FALSE;
1410 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1412 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1413 ALBufferList = pSource->queue;
1414 while (ALBufferList)
1416 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1418 bPlay = AL_TRUE;
1419 break;
1421 ALBufferList = ALBufferList->next;
1424 if (bPlay)
1426 for(j = 0;j < OUTPUTCHANNELS;j++)
1427 pSource->DryGains[j] = 0.0f;
1428 pSource->WetGain = 0.0f;
1430 if (pSource->state != AL_PAUSED)
1432 pSource->state = AL_PLAYING;
1433 pSource->inuse = AL_TRUE;
1434 pSource->play = AL_TRUE;
1435 pSource->position = 0;
1436 pSource->position_fraction = 0;
1437 pSource->BuffersPlayed = 0;
1439 pSource->ulBufferID = pSource->queue->buffer;
1441 // Make sure all the Buffers in the queue are marked as PENDING
1442 ALBufferList = pSource->queue;
1443 while (ALBufferList)
1445 ALBufferList->bufferstate = PENDING;
1446 ALBufferList = ALBufferList->next;
1449 else
1451 pSource->state = AL_PLAYING;
1452 pSource->inuse = AL_TRUE;
1453 pSource->play = AL_TRUE;
1456 // Check if an Offset has been set
1457 if (pSource->lOffset)
1458 ApplyOffset(pSource, AL_FALSE);
1460 else
1462 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1463 ALBufferList = pSource->queue;
1464 while (ALBufferList)
1466 ALBufferList->bufferstate = PROCESSED;
1467 ALBufferList = ALBufferList->next;
1470 pSource->BuffersPlayed = pSource->BuffersInQueue;
1475 else
1477 // sources is a NULL pointer
1478 alSetError(AL_INVALID_VALUE);
1481 ProcessContext(pContext);
1483 else
1485 // Invalid Context
1486 alSetError(AL_INVALID_OPERATION);
1489 return;
1492 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1494 alSourcePausev(1, &source);
1495 return;
1498 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1500 ALCcontext *Context;
1501 ALsource *Source;
1502 ALsizei i;
1503 ALboolean bSourcesValid = AL_TRUE;
1505 Context=alcGetCurrentContext();
1506 if (Context)
1508 SuspendContext(Context);
1510 if (sources)
1512 // Check all the Sources are valid
1513 for (i=0;i<n;i++)
1515 if (!alIsSource(sources[i]))
1517 alSetError(AL_INVALID_NAME);
1518 bSourcesValid = AL_FALSE;
1519 break;
1523 if (bSourcesValid)
1525 for (i=0;i<n;i++)
1527 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1528 if (Source->state==AL_PLAYING)
1530 Source->state=AL_PAUSED;
1531 Source->inuse=AL_FALSE;
1536 else
1538 // sources is a NULL pointer
1539 alSetError(AL_INVALID_VALUE);
1542 ProcessContext(Context);
1544 else
1546 // Invalid Context
1547 alSetError(AL_INVALID_OPERATION);
1550 return;
1553 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1555 alSourceStopv(1, &source);
1556 return;
1559 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1561 ALCcontext *Context;
1562 ALsource *Source;
1563 ALsizei i;
1564 ALbufferlistitem *ALBufferListItem;
1565 ALboolean bSourcesValid = AL_TRUE;
1567 Context=alcGetCurrentContext();
1568 if (Context)
1570 SuspendContext(Context);
1572 if (sources)
1574 // Check all the Sources are valid
1575 for (i=0;i<n;i++)
1577 if (!alIsSource(sources[i]))
1579 alSetError(AL_INVALID_NAME);
1580 bSourcesValid = AL_FALSE;
1581 break;
1585 if (bSourcesValid)
1587 for (i=0;i<n;i++)
1589 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1590 if (Source->state!=AL_INITIAL)
1592 Source->state=AL_STOPPED;
1593 Source->inuse=AL_FALSE;
1594 Source->BuffersPlayed = Source->BuffersInQueue;
1595 ALBufferListItem= Source->queue;
1596 while (ALBufferListItem != NULL)
1598 ALBufferListItem->bufferstate = PROCESSED;
1599 ALBufferListItem = ALBufferListItem->next;
1602 Source->lOffset = 0;
1606 else
1608 // sources is a NULL pointer
1609 alSetError(AL_INVALID_VALUE);
1612 ProcessContext(Context);
1614 else
1616 // Invalid Context
1617 alSetError(AL_INVALID_OPERATION);
1620 return;
1623 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1625 alSourceRewindv(1, &source);
1626 return;
1629 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1631 ALCcontext *Context;
1632 ALsource *Source;
1633 ALsizei i;
1634 ALbufferlistitem *ALBufferListItem;
1635 ALboolean bSourcesValid = AL_TRUE;
1637 Context=alcGetCurrentContext();
1638 if (Context)
1640 SuspendContext(Context);
1642 if (sources)
1644 // Check all the Sources are valid
1645 for (i=0;i<n;i++)
1647 if (!alIsSource(sources[i]))
1649 alSetError(AL_INVALID_NAME);
1650 bSourcesValid = AL_FALSE;
1651 break;
1655 if (bSourcesValid)
1657 for (i=0;i<n;i++)
1659 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1660 if (Source->state!=AL_INITIAL)
1662 Source->state=AL_INITIAL;
1663 Source->inuse=AL_FALSE;
1664 Source->position=0;
1665 Source->position_fraction=0;
1666 Source->BuffersPlayed = 0;
1667 ALBufferListItem= Source->queue;
1668 while (ALBufferListItem != NULL)
1670 ALBufferListItem->bufferstate = PENDING;
1671 ALBufferListItem = ALBufferListItem->next;
1673 if (Source->queue)
1674 Source->ulBufferID = Source->queue->buffer;
1676 Source->lOffset = 0;
1680 else
1682 // sources is a NULL pointer
1683 alSetError(AL_INVALID_VALUE);
1686 ProcessContext(Context);
1688 else
1690 // Invalid Context
1691 alSetError(AL_INVALID_OPERATION);
1694 return;
1698 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1700 ALCcontext *Context;
1701 ALsource *ALSource;
1702 ALsizei i;
1703 ALbufferlistitem *ALBufferList;
1704 ALbufferlistitem *ALBufferListStart;
1705 ALuint DataSize;
1706 ALuint BufferSize;
1707 ALint iFrequency;
1708 ALint iFormat;
1709 ALboolean bBuffersValid = AL_TRUE;
1711 if (n == 0)
1712 return;
1714 Context=alcGetCurrentContext();
1715 if (Context)
1717 SuspendContext(Context);
1719 DataSize = 0;
1720 BufferSize = 0;
1722 // Check that all buffers are valid or zero and that the source is valid
1724 // Check that this is a valid source
1725 if (alIsSource(source))
1727 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1729 // Check that this is not a STATIC Source
1730 if (ALSource->lSourceType != AL_STATIC)
1732 iFrequency = -1;
1733 iFormat = -1;
1735 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1736 ALBufferList = ALSource->queue;
1737 while (ALBufferList)
1739 if (ALBufferList->buffer)
1741 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1742 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1743 break;
1745 ALBufferList = ALBufferList->next;
1748 for (i = 0; i < n; i++)
1750 if (alIsBuffer(buffers[i]))
1752 if (buffers[i])
1754 if ((iFrequency == -1) && (iFormat == -1))
1756 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1757 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1759 else
1761 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1762 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1764 alSetError(AL_INVALID_OPERATION);
1765 bBuffersValid = AL_FALSE;
1766 break;
1771 else
1773 alSetError(AL_INVALID_NAME);
1774 bBuffersValid = AL_FALSE;
1775 break;
1779 if (bBuffersValid)
1781 // Change Source Type
1782 ALSource->lSourceType = AL_STREAMING;
1784 // All buffers are valid - so add them to the list
1785 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1786 ALBufferListStart->buffer = buffers[0];
1787 ALBufferListStart->bufferstate = PENDING;
1788 ALBufferListStart->flag = 0;
1789 ALBufferListStart->next = NULL;
1791 if (buffers[0])
1792 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1793 else
1794 BufferSize = 0;
1796 DataSize += BufferSize;
1798 // Increment reference counter for buffer
1799 if (buffers[0])
1800 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1802 ALBufferList = ALBufferListStart;
1804 for (i = 1; i < n; i++)
1806 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1807 ALBufferList->next->buffer = buffers[i];
1808 ALBufferList->next->bufferstate = PENDING;
1809 ALBufferList->next->flag = 0;
1810 ALBufferList->next->next = NULL;
1812 if (buffers[i])
1813 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1814 else
1815 BufferSize = 0;
1817 DataSize += BufferSize;
1819 // Increment reference counter for buffer
1820 if (buffers[i])
1821 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1823 ALBufferList = ALBufferList->next;
1826 if (ALSource->queue == NULL)
1828 ALSource->queue = ALBufferListStart;
1829 // Update Current Buffer
1830 ALSource->ulBufferID = ALBufferListStart->buffer;
1832 else
1834 // Find end of queue
1835 ALBufferList = ALSource->queue;
1836 while (ALBufferList->next != NULL)
1838 ALBufferList = ALBufferList->next;
1841 ALBufferList->next = ALBufferListStart;
1844 // Update number of buffers in queue
1845 ALSource->BuffersInQueue += n;
1848 else
1850 // Invalid Source Type (can't queue on a Static Source)
1851 alSetError(AL_INVALID_OPERATION);
1854 else
1856 // Invalid Source Name
1857 alSetError(AL_INVALID_NAME);
1860 ProcessContext(Context);
1862 else
1864 // Invalid Context
1865 alSetError(AL_INVALID_OPERATION);
1868 return;
1872 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1873 // an array of buffer IDs that are to be filled with the names of the buffers removed
1874 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1876 ALCcontext *Context;
1877 ALsource *ALSource;
1878 ALsizei i;
1879 ALbufferlistitem *ALBufferList;
1880 ALuint DataSize;
1881 ALuint BufferSize;
1882 ALuint BufferID;
1883 ALboolean bBuffersProcessed;
1885 if (n == 0)
1886 return;
1888 DataSize = 0;
1889 BufferSize = 0;
1890 bBuffersProcessed = AL_TRUE;
1892 Context=alcGetCurrentContext();
1893 if (Context)
1895 SuspendContext(Context);
1897 if (alIsSource(source))
1899 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1901 // Check that all 'n' buffers have been processed
1902 ALBufferList = ALSource->queue;
1903 for (i = 0; i < n; i++)
1905 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1907 ALBufferList = ALBufferList->next;
1909 else
1911 bBuffersProcessed = AL_FALSE;
1912 break;
1916 // If all 'n' buffers have been processed, remove them from the queue
1917 if (bBuffersProcessed)
1919 for (i = 0; i < n; i++)
1921 ALBufferList = ALSource->queue;
1923 ALSource->queue = ALBufferList->next;
1924 // Record name of buffer
1925 buffers[i] = ALBufferList->buffer;
1926 // Decrement buffer reference counter
1927 if (ALBufferList->buffer)
1928 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1929 // Record size of buffer
1930 if (ALBufferList->buffer)
1931 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1932 else
1933 BufferSize = 0;
1935 DataSize += BufferSize;
1936 // Release memory for buffer list item
1937 free(ALBufferList);
1938 ALSource->BuffersInQueue--;
1941 if (ALSource->state != AL_PLAYING)
1943 if (ALSource->queue)
1944 BufferID = ALSource->queue->buffer;
1945 else
1946 BufferID = 0;
1948 ALSource->ulBufferID = BufferID;
1951 if((ALuint)n > ALSource->BuffersPlayed)
1952 ALSource->BuffersPlayed = 0;
1953 else
1954 ALSource->BuffersPlayed -= n;
1956 else
1958 // Some buffers can't be unqueue because they have not been processed
1959 alSetError(AL_INVALID_VALUE);
1962 else
1964 // Invalid Source Name
1965 alSetError(AL_INVALID_NAME);
1968 ProcessContext(Context);
1970 else
1972 // Invalid Context
1973 alSetError(AL_INVALID_OPERATION);
1976 return;
1980 static ALvoid InitSourceParams(ALsource *pSource)
1982 pSource->flInnerAngle = 360.0f;
1983 pSource->flOuterAngle = 360.0f;
1984 pSource->flPitch = 1.0f;
1985 pSource->vPosition[0] = 0.0f;
1986 pSource->vPosition[1] = 0.0f;
1987 pSource->vPosition[2] = 0.0f;
1988 pSource->vOrientation[0] = 0.0f;
1989 pSource->vOrientation[1] = 0.0f;
1990 pSource->vOrientation[2] = 0.0f;
1991 pSource->vVelocity[0] = 0.0f;
1992 pSource->vVelocity[1] = 0.0f;
1993 pSource->vVelocity[2] = 0.0f;
1994 pSource->flRefDistance = 1.0f;
1995 pSource->flMaxDistance = FLT_MAX;
1996 pSource->flRollOffFactor = 1.0f;
1997 pSource->bLooping = AL_FALSE;
1998 pSource->flGain = 1.0f;
1999 pSource->flMinGain = 0.0f;
2000 pSource->flMaxGain = 1.0f;
2001 pSource->flOuterGain = 0.0f;
2002 pSource->OuterGainHF = 1.0f;
2004 pSource->DryGainHFAuto = AL_TRUE;
2005 pSource->WetGainAuto = AL_TRUE;
2006 pSource->WetGainHFAuto = AL_TRUE;
2007 pSource->AirAbsorptionFactor = 0.0f;
2008 pSource->RoomRolloffFactor = 0.0f;
2009 pSource->DopplerFactor = 1.0f;
2011 pSource->state = AL_INITIAL;
2012 pSource->lSourceType = AL_UNDETERMINED;
2014 pSource->ulBufferID= 0;
2019 GetSourceOffset
2021 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
2022 The offset is relative to the start of the queue (not the start of the current buffer)
2024 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
2026 ALbufferlistitem *pBufferList;
2027 ALbuffer *pBuffer;
2028 ALfloat flBufferFreq;
2029 ALint lChannels;
2030 ALint readPos, writePos;
2031 ALenum eOriginalFormat;
2032 ALboolean bReturn = AL_TRUE;
2033 ALint lTotalBufferDataSize;
2035 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2037 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2038 // Get Current Buffer Size and frequency (in milliseconds)
2039 flBufferFreq = (ALfloat)pBuffer->frequency;
2040 eOriginalFormat = pBuffer->eOriginalFormat;
2041 lChannels = aluChannelsFromFormat(pBuffer->format);
2043 // Get Current BytesPlayed
2044 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2045 // Add byte length of any processed buffers in the queue
2046 pBufferList = pSource->queue;
2047 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2049 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2050 pBufferList = pBufferList->next;
2053 if(pSource->state == AL_PLAYING)
2054 writePos = readPos + (updateSize * lChannels * 2);
2055 else
2056 writePos = readPos;
2058 lTotalBufferDataSize = 0;
2059 pBufferList = pSource->queue;
2060 while (pBufferList)
2062 if (pBufferList->buffer)
2063 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2064 pBufferList = pBufferList->next;
2067 if (pSource->bLooping)
2069 if(readPos < 0)
2070 readPos = 0;
2071 else
2072 readPos %= lTotalBufferDataSize;
2073 if(writePos < 0)
2074 writePos = 0;
2075 else
2076 writePos %= lTotalBufferDataSize;
2078 else
2080 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2081 if(readPos < 0)
2082 readPos = 0;
2083 else if(readPos > lTotalBufferDataSize)
2084 readPos = lTotalBufferDataSize;
2085 if(writePos < 0)
2086 writePos = 0;
2087 else if(writePos > lTotalBufferDataSize)
2088 writePos = lTotalBufferDataSize;
2091 switch (eName)
2093 case AL_SEC_OFFSET:
2094 case AL_SEC_RW_OFFSETS_EXT:
2095 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
2096 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
2097 break;
2098 case AL_SAMPLE_OFFSET:
2099 case AL_SAMPLE_RW_OFFSETS_EXT:
2100 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
2101 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
2102 break;
2103 case AL_BYTE_OFFSET:
2104 case AL_BYTE_RW_OFFSETS_EXT:
2105 // Take into account the original format of the Buffer
2106 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2107 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2109 // Compression rate of the ADPCM supported is 3.6111 to 1
2110 readPos = (ALint)((ALfloat)readPos / 3.6111f);
2111 writePos = (ALint)((ALfloat)writePos / 3.6111f);
2112 // Round down to nearest ADPCM block
2113 pflOffset[0] = (ALfloat)((readPos / (36 * lChannels)) * 36 * lChannels);
2114 if(pSource->state == AL_PLAYING)
2116 // Round up to nearest ADPCM block
2117 pflOffset[1] = (ALfloat)(((writePos + (36 * lChannels) - 1) / (36 * lChannels)) * 36 * lChannels);
2119 else
2120 pflOffset[1] = pflOffset[0];
2122 else if (eOriginalFormat == AL_FORMAT_REAR8)
2124 pflOffset[0] = (ALfloat)(readPos >> 2);
2125 pflOffset[1] = (ALfloat)(writePos >> 2);
2127 else if (eOriginalFormat == AL_FORMAT_REAR16)
2129 pflOffset[0] = (ALfloat)(readPos >> 1);
2130 pflOffset[1] = (ALfloat)(writePos >> 1);
2132 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2134 pflOffset[0] = (ALfloat)(readPos >> 1);
2135 pflOffset[1] = (ALfloat)(writePos >> 1);
2137 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2139 pflOffset[0] = (ALfloat)(readPos << 1);
2140 pflOffset[1] = (ALfloat)(writePos << 1);
2142 else
2144 pflOffset[0] = (ALfloat)readPos;
2145 pflOffset[1] = (ALfloat)writePos;
2147 break;
2150 else
2152 pflOffset[0] = 0.0f;
2153 pflOffset[1] = 0.0f;
2156 return bReturn;
2161 ApplyOffset
2163 Apply a playback offset to the Source. This function will update the queue (to correctly
2164 mark buffers as 'pending' or 'processed' depending upon the new offset.
2166 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2168 ALbufferlistitem *pBufferList;
2169 ALbuffer *pBuffer;
2170 ALint lBufferSize, lTotalBufferSize;
2171 ALint lByteOffset;
2173 // Get true byte offset
2174 lByteOffset = GetByteOffset(pSource);
2176 // If this is a valid offset apply it
2177 if (lByteOffset != -1)
2179 // Sort out the queue (pending and processed states)
2180 pBufferList = pSource->queue;
2181 lTotalBufferSize = 0;
2182 pSource->BuffersPlayed = 0;
2183 while (pBufferList)
2185 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2186 lBufferSize = pBuffer ? pBuffer->size : 0;
2188 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2190 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2191 // update the state to PROCESSED
2192 pSource->BuffersPlayed++;
2194 if (!pSource->bLooping)
2195 pBufferList->bufferstate = PROCESSED;
2197 else if (lTotalBufferSize <= lByteOffset)
2199 // Offset is within this buffer
2200 pBufferList->bufferstate = PENDING;
2202 // Set Current Buffer ID
2203 pSource->ulBufferID = pBufferList->buffer;
2205 // SW Mixer Positions are in Samples
2206 pSource->position = (lByteOffset - lTotalBufferSize) /
2207 aluBytesFromFormat(pBuffer->format) /
2208 aluChannelsFromFormat(pBuffer->format);
2210 else
2212 // Offset is before this buffer, so mark as pending
2213 pBufferList->bufferstate = PENDING;
2216 // Increment the TotalBufferSize
2217 lTotalBufferSize += lBufferSize;
2219 // Move on to next buffer in the Queue
2220 pBufferList = pBufferList->next;
2223 else
2225 if (bUpdateContext)
2226 alSetError(AL_INVALID_VALUE);
2229 // Clear Offset
2230 pSource->lOffset = 0;
2235 GetByteOffset
2237 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2238 offset supplied by the application). This takes into account the fact that the buffer format
2239 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2241 static ALint GetByteOffset(ALsource *pSource)
2243 ALbuffer *pBuffer = NULL;
2244 ALbufferlistitem *pBufferList;
2245 ALfloat flBufferFreq;
2246 ALint lChannels;
2247 ALint lByteOffset = -1;
2248 ALint lTotalBufferDataSize;
2250 // Find the first non-NULL Buffer in the Queue
2251 pBufferList = pSource->queue;
2252 while (pBufferList)
2254 if (pBufferList->buffer)
2256 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2257 break;
2259 pBufferList = pBufferList->next;
2262 if (pBuffer)
2264 flBufferFreq = ((ALfloat)pBuffer->frequency);
2265 lChannels = aluChannelsFromFormat(pBuffer->format);
2267 // Determine the ByteOffset (and ensure it is block aligned)
2268 switch (pSource->lOffsetType)
2270 case AL_BYTE_OFFSET:
2271 // Take into consideration the original format
2272 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2273 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2275 // Round down to nearest ADPCM block
2276 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2277 // Multiply by compression rate
2278 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2279 lByteOffset -= (lByteOffset % (lChannels * 2));
2281 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2283 lByteOffset = pSource->lOffset * 4;
2284 lByteOffset -= (lByteOffset % (lChannels * 2));
2286 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2288 lByteOffset = pSource->lOffset * 2;
2289 lByteOffset -= (lByteOffset % (lChannels * 2));
2291 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2293 lByteOffset = pSource->lOffset * 2;
2294 lByteOffset -= (lByteOffset % (lChannels * 2));
2296 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2298 lByteOffset = pSource->lOffset / 2;
2299 lByteOffset -= (lByteOffset % (lChannels * 2));
2301 else
2303 lByteOffset = pSource->lOffset;
2304 lByteOffset -= (lByteOffset % (lChannels * 2));
2306 break;
2308 case AL_SAMPLE_OFFSET:
2309 lByteOffset = pSource->lOffset * lChannels * 2;
2310 break;
2312 case AL_SEC_OFFSET:
2313 // Note - lOffset is internally stored as Milliseconds
2314 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2315 lByteOffset -= (lByteOffset % (lChannels * 2));
2316 break;
2319 lTotalBufferDataSize = 0;
2320 pBufferList = pSource->queue;
2321 while (pBufferList)
2323 if (pBufferList->buffer)
2324 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2325 pBufferList = pBufferList->next;
2328 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2329 if (lByteOffset >= lTotalBufferDataSize)
2330 lByteOffset = -1;
2333 return lByteOffset;
2337 ALvoid ReleaseALSources(ALCcontext *Context)
2339 #ifdef _DEBUG
2340 if(Context->SourceCount > 0)
2341 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2342 #endif
2344 while(Context->Source)
2346 ALsource *temp = Context->Source;
2347 Context->Source = Context->Source->next;
2349 // Release source structure
2350 ALTHUNK_REMOVEENTRY(temp->source);
2351 memset(temp, 0, sizeof(ALsource));
2352 free(temp);
2354 Context->SourceCount = 0;