Make sure sources are deleted with the context
[openal-soft.git] / OpenAL32 / alSource.c
blob13cca8e36bbdcd2f4bb3b660a742572debea7e68
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 <stdlib.h>
22 #include <math.h>
23 #include <float.h>
24 #include "alMain.h"
25 #include "AL/al.h"
26 #include "AL/alc.h"
27 #include "alError.h"
28 #include "alSource.h"
29 #include "alBuffer.h"
30 #include "alThunk.h"
32 static ALvoid InitSourceParams(ALsource *pSource);
33 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
34 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
35 static ALint GetByteOffset(ALsource *pSource);
37 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
39 ALCcontext *Context;
40 ALCdevice *Device;
41 ALsizei i=0;
43 Context = alcGetCurrentContext();
44 if (Context)
46 SuspendContext(Context);
48 if (n > 0)
50 Device = alcGetContextsDevice(Context);
52 if (Device)
54 // Check that enough memory has been allocted in the 'sources' array for n Sources
55 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
57 // Check that the requested number of sources can be generated
58 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
60 ALsource **list = &Context->Source;
61 while(*list)
62 list = &(*list)->next;
64 // Add additional sources to the list (Source->next points to the location for the next Source structure)
65 while(i < n)
67 *list = calloc(1, sizeof(ALsource));
68 if(!(*list))
70 alDeleteSources(i, sources);
71 alSetError(AL_OUT_OF_MEMORY);
72 break;
75 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
76 (*list)->source = sources[i];
78 InitSourceParams(*list);
79 Context->SourceCount++;
80 i++;
82 list = &(*list)->next;
85 else
87 // Not enough resources to create the Sources
88 alSetError(AL_INVALID_VALUE);
91 else
93 // Bad pointer
94 alSetError(AL_INVALID_VALUE);
97 else
99 // No Device created, or attached to Context
100 alSetError(AL_INVALID_OPERATION);
104 ProcessContext(Context);
106 else
108 // Invalid Context
109 alSetError(AL_INVALID_OPERATION);
112 return;
116 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
118 ALCcontext *Context;
119 ALCdevice *Device;
120 ALsource *ALSource;
121 ALsource **list;
122 ALsizei i;
123 ALbufferlistitem *ALBufferList;
124 ALboolean bSourcesValid = AL_TRUE;
126 Context = alcGetCurrentContext();
127 if (Context)
129 SuspendContext(Context);
131 if (n >= 0)
133 Device = alcGetContextsDevice(Context);
135 if (Device)
137 if ((ALuint)n <= Context->SourceCount)
139 // Check that all Sources are valid (and can therefore be deleted)
140 for (i = 0; i < n; i++)
142 if (!alIsSource(sources[i]))
144 alSetError(AL_INVALID_NAME);
145 bSourcesValid = AL_FALSE;
146 break;
150 if (bSourcesValid)
152 // All Sources are valid, and can be deleted
153 for (i = 0; i < n; i++)
155 // Recheck that the Source is valid, because there could be duplicated Source names
156 if (alIsSource(sources[i]))
158 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
159 alSourceStop((ALuint)ALSource->source);
161 // For each buffer in the source's queue, decrement its reference counter and remove it
162 while (ALSource->queue != NULL)
164 ALBufferList = ALSource->queue;
165 // Decrement buffer's reference counter
166 if (ALBufferList->buffer != 0)
167 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
168 // Update queue to point to next element in list
169 ALSource->queue = ALBufferList->next;
170 // Release memory allocated for buffer list item
171 free(ALBufferList);
174 // Decrement Source count
175 Context->SourceCount--;
177 // Remove Source from list of Sources
178 list = &Context->Source;
179 while(*list && *list != ALSource)
180 list = &(*list)->next;
182 if(*list)
183 *list = (*list)->next;
184 ALTHUNK_REMOVEENTRY(ALSource->source);
186 memset(ALSource,0,sizeof(ALsource));
187 free(ALSource);
193 else
195 // Trying to delete more Sources than have been generated
196 alSetError(AL_INVALID_NAME);
199 else
201 // No Device created, or attached to Context
202 alSetError(AL_INVALID_OPERATION);
205 else
206 alSetError(AL_INVALID_VALUE);
208 ProcessContext(Context);
210 else
212 // Invalid Context
213 alSetError(AL_INVALID_OPERATION);
216 return;
220 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
222 ALboolean result=AL_FALSE;
223 ALCcontext *Context;
224 ALsource *Source;
226 Context=alcGetCurrentContext();
227 if (Context)
229 SuspendContext(Context);
231 // To determine if this is a valid Source name, look through the list of generated Sources
232 Source = Context->Source;
233 while(Source)
235 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
237 result = AL_TRUE;
238 break;
241 Source = Source->next;
244 ProcessContext(Context);
246 else
248 // Invalid Context
249 alSetError(AL_INVALID_OPERATION);
252 return result;
256 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
258 ALCcontext *pContext;
259 ALsource *pSource;
261 pContext = alcGetCurrentContext();
262 if (pContext)
264 SuspendContext(pContext);
266 if (alIsSource(source))
268 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
270 switch (eParam)
272 case AL_PITCH:
273 if (flValue >= 0.0f)
275 pSource->flPitch = flValue;
276 if(pSource->flPitch < 0.001f)
277 pSource->flPitch = 0.001f;
279 else
280 alSetError(AL_INVALID_VALUE);
281 break;
283 case AL_CONE_INNER_ANGLE:
284 if ((flValue >= 0.0f) && (flValue <= 360.0f))
285 pSource->flInnerAngle = flValue;
286 else
287 alSetError(AL_INVALID_VALUE);
288 break;
290 case AL_CONE_OUTER_ANGLE:
291 if ((flValue >= 0.0f) && (flValue <= 360.0f))
292 pSource->flOuterAngle = flValue;
293 else
294 alSetError(AL_INVALID_VALUE);
295 break;
297 case AL_GAIN:
298 if (flValue >= 0.0f)
299 pSource->flGain = flValue;
300 else
301 alSetError(AL_INVALID_VALUE);
302 break;
304 case AL_MAX_DISTANCE:
305 if (flValue >= 0.0f)
306 pSource->flMaxDistance = flValue;
307 else
308 alSetError(AL_INVALID_VALUE);
309 break;
311 case AL_ROLLOFF_FACTOR:
312 if (flValue >= 0.0f)
313 pSource->flRollOffFactor = flValue;
314 else
315 alSetError(AL_INVALID_VALUE);
316 break;
318 case AL_REFERENCE_DISTANCE:
319 if (flValue >= 0.0f)
320 pSource->flRefDistance = flValue;
321 else
322 alSetError(AL_INVALID_VALUE);
323 break;
325 case AL_MIN_GAIN:
326 if ((flValue >= 0.0f) && (flValue <= 1.0f))
327 pSource->flMinGain = flValue;
328 else
329 alSetError(AL_INVALID_VALUE);
330 break;
332 case AL_MAX_GAIN:
333 if ((flValue >= 0.0f) && (flValue <= 1.0f))
334 pSource->flMaxGain = flValue;
335 else
336 alSetError(AL_INVALID_VALUE);
337 break;
339 case AL_CONE_OUTER_GAIN:
340 if ((flValue >= 0.0f) && (flValue <= 1.0f))
341 pSource->flOuterGain = flValue;
342 else
343 alSetError(AL_INVALID_VALUE);
344 break;
346 case AL_CONE_OUTER_GAINHF:
347 if ((flValue >= 0.0f) && (flValue <= 1.0f))
348 pSource->OuterGainHF = flValue;
349 else
350 alSetError(AL_INVALID_VALUE);
351 break;
353 case AL_AIR_ABSORPTION_FACTOR:
354 if (flValue >= 0.0f && flValue <= 10.0f)
355 pSource->AirAbsorptionFactor = flValue;
356 else
357 alSetError(AL_INVALID_VALUE);
358 break;
360 case AL_ROOM_ROLLOFF_FACTOR:
361 if (flValue >= 0.0f && flValue <= 1.0f)
362 pSource->RoomRolloffFactor = flValue;
363 else
364 alSetError(AL_INVALID_VALUE);
365 break;
367 case AL_SEC_OFFSET:
368 case AL_SAMPLE_OFFSET:
369 case AL_BYTE_OFFSET:
370 if (flValue >= 0.0f)
372 pSource->lOffsetType = eParam;
374 // Store Offset (convert Seconds into Milliseconds)
375 if (eParam == AL_SEC_OFFSET)
376 pSource->lOffset = (ALint)(flValue * 1000.0f);
377 else
378 pSource->lOffset = (ALint)flValue;
380 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
381 ApplyOffset(pSource, AL_TRUE);
383 else
384 alSetError(AL_INVALID_VALUE);
385 break;
387 default:
388 alSetError(AL_INVALID_ENUM);
389 break;
392 else
394 // Invalid Source Name
395 alSetError(AL_INVALID_NAME);
398 ProcessContext(pContext);
400 else
402 // Invalid context
403 alSetError(AL_INVALID_OPERATION);
406 return;
410 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
412 ALCcontext *pContext;
413 ALsource *pSource;
415 pContext = alcGetCurrentContext();
416 if (pContext)
418 SuspendContext(pContext);
420 if (alIsSource(source))
422 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
423 switch(eParam)
425 case AL_POSITION:
426 pSource->vPosition[0] = flValue1;
427 pSource->vPosition[1] = flValue2;
428 pSource->vPosition[2] = flValue3;
429 break;
431 case AL_VELOCITY:
432 pSource->vVelocity[0] = flValue1;
433 pSource->vVelocity[1] = flValue2;
434 pSource->vVelocity[2] = flValue3;
435 break;
437 case AL_DIRECTION:
438 pSource->vOrientation[0] = flValue1;
439 pSource->vOrientation[1] = flValue2;
440 pSource->vOrientation[2] = flValue3;
441 break;
443 default:
444 alSetError(AL_INVALID_ENUM);
445 break;
448 else
449 alSetError(AL_INVALID_NAME);
451 ProcessContext(pContext);
453 else
455 alSetError(AL_INVALID_OPERATION);
458 return;
462 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
464 ALCcontext *pContext;
466 pContext = alcGetCurrentContext();
467 if (pContext)
469 SuspendContext(pContext);
471 if (pflValues)
473 if (alIsSource(source))
475 switch (eParam)
477 case AL_PITCH:
478 case AL_CONE_INNER_ANGLE:
479 case AL_CONE_OUTER_ANGLE:
480 case AL_GAIN:
481 case AL_MAX_DISTANCE:
482 case AL_ROLLOFF_FACTOR:
483 case AL_REFERENCE_DISTANCE:
484 case AL_MIN_GAIN:
485 case AL_MAX_GAIN:
486 case AL_CONE_OUTER_GAIN:
487 case AL_CONE_OUTER_GAINHF:
488 case AL_SEC_OFFSET:
489 case AL_SAMPLE_OFFSET:
490 case AL_BYTE_OFFSET:
491 case AL_AIR_ABSORPTION_FACTOR:
492 case AL_ROOM_ROLLOFF_FACTOR:
493 alSourcef(source, eParam, pflValues[0]);
494 break;
496 case AL_POSITION:
497 case AL_VELOCITY:
498 case AL_DIRECTION:
499 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
500 break;
502 default:
503 alSetError(AL_INVALID_ENUM);
504 break;
507 else
508 alSetError(AL_INVALID_NAME);
510 else
511 alSetError(AL_INVALID_VALUE);
513 ProcessContext(pContext);
515 else
516 alSetError(AL_INVALID_OPERATION);
518 return;
522 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
524 ALCcontext *pContext;
525 ALsource *pSource;
526 ALbufferlistitem *pALBufferListItem;
527 ALint Counter = 0;
528 ALint DataSize = 0;
529 ALint BufferSize;
531 pContext = alcGetCurrentContext();
532 if (pContext)
534 SuspendContext(pContext);
536 if (alIsSource(source))
538 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
540 switch(eParam)
542 case AL_MAX_DISTANCE:
543 case AL_ROLLOFF_FACTOR:
544 case AL_REFERENCE_DISTANCE:
545 alSourcef(source, eParam, (ALfloat)lValue);
546 break;
548 case AL_SOURCE_RELATIVE:
549 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
550 pSource->bHeadRelative = (ALboolean)lValue;
551 else
552 alSetError(AL_INVALID_VALUE);
553 break;
555 case AL_CONE_INNER_ANGLE:
556 if ((lValue >= 0) && (lValue <= 360))
557 pSource->flInnerAngle = (float)lValue;
558 else
559 alSetError(AL_INVALID_VALUE);
560 break;
562 case AL_CONE_OUTER_ANGLE:
563 if ((lValue >= 0) && (lValue <= 360))
564 pSource->flOuterAngle = (float)lValue;
565 else
566 alSetError(AL_INVALID_VALUE);
567 break;
569 case AL_LOOPING:
570 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
571 pSource->bLooping = (ALboolean)lValue;
572 else
573 alSetError(AL_INVALID_VALUE);
574 break;
576 case AL_BUFFER:
577 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
579 if (alIsBuffer(lValue))
581 // Remove all elements in the queue
582 while (pSource->queue != NULL)
584 pALBufferListItem = pSource->queue;
585 pSource->queue = pALBufferListItem->next;
586 // Decrement reference counter for buffer
587 if (pALBufferListItem->buffer)
588 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
589 // Record size of buffer
590 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
591 DataSize += BufferSize;
592 // Increment the number of buffers removed from queue
593 Counter++;
594 // Release memory for buffer list item
595 free(pALBufferListItem);
596 // Decrement the number of buffers in the queue
597 pSource->BuffersInQueue--;
600 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
601 if (lValue != 0)
603 // Source is now in STATIC mode
604 pSource->lSourceType = AL_STATIC;
606 // Add the selected buffer to the queue
607 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
608 pALBufferListItem->buffer = lValue;
609 pALBufferListItem->bufferstate = PENDING;
610 pALBufferListItem->flag = 0;
611 pALBufferListItem->next = NULL;
613 pSource->queue = pALBufferListItem;
614 pSource->BuffersInQueue = 1;
616 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
618 // Increment reference counter for buffer
619 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
621 else
623 // Source is now in UNDETERMINED mode
624 pSource->lSourceType = AL_UNDETERMINED;
627 // Set Buffers Processed
628 pSource->BuffersProcessed = 0;
630 // Update AL_BUFFER parameter
631 pSource->ulBufferID = lValue;
633 else
634 alSetError(AL_INVALID_VALUE);
636 else
637 alSetError(AL_INVALID_OPERATION);
638 break;
640 case AL_SOURCE_STATE:
641 // Query only
642 alSetError(AL_INVALID_OPERATION);
643 break;
645 case AL_SEC_OFFSET:
646 case AL_SAMPLE_OFFSET:
647 case AL_BYTE_OFFSET:
648 if (lValue >= 0)
650 pSource->lOffsetType = eParam;
652 // Store Offset (convert Seconds into Milliseconds)
653 if (eParam == AL_SEC_OFFSET)
654 pSource->lOffset = lValue * 1000;
655 else
656 pSource->lOffset = lValue;
658 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
659 ApplyOffset(pSource, AL_TRUE);
661 else
662 alSetError(AL_INVALID_VALUE);
663 break;
665 case AL_DIRECT_FILTER:
666 if(alIsFilter(lValue))
668 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
669 if(!filter)
671 pSource->DirectFilter.type = AL_FILTER_NULL;
672 pSource->DirectFilter.filter = 0;
674 else
675 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
677 else
678 alSetError(AL_INVALID_VALUE);
679 break;
681 case AL_DIRECT_FILTER_GAINHF_AUTO:
682 if(lValue == AL_TRUE || lValue == AL_FALSE)
683 pSource->DryGainHFAuto = lValue;
684 else
685 alSetError(AL_INVALID_VALUE);
686 break;
688 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
689 if(lValue == AL_TRUE || lValue == AL_FALSE)
690 pSource->WetGainAuto = lValue;
691 else
692 alSetError(AL_INVALID_VALUE);
693 break;
695 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
696 if(lValue == AL_TRUE || lValue == AL_FALSE)
697 pSource->WetGainHFAuto = lValue;
698 else
699 alSetError(AL_INVALID_VALUE);
700 break;
702 default:
703 alSetError(AL_INVALID_ENUM);
704 break;
707 else
708 alSetError(AL_INVALID_NAME);
710 ProcessContext(pContext);
712 else
713 alSetError(AL_INVALID_OPERATION);
715 return;
719 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
721 ALCcontext *pContext;
723 pContext = alcGetCurrentContext();
724 if (pContext)
726 SuspendContext(pContext);
728 if (alIsSource(source))
730 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
732 switch (eParam)
734 case AL_POSITION:
735 case AL_VELOCITY:
736 case AL_DIRECTION:
737 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
738 break;
740 case AL_AUXILIARY_SEND_FILTER:
741 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
742 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
743 alIsFilter(lValue3))
745 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
746 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
748 /* Release refcount on the previous slot, and add one for
749 * the new slot */
750 if(pSource->Send[lValue2].Slot)
751 pSource->Send[lValue2].Slot->refcount--;
752 pSource->Send[lValue2].Slot = ALEffectSlot;
753 if(pSource->Send[lValue2].Slot)
754 pSource->Send[lValue2].Slot->refcount++;
756 if(!ALFilter)
758 /* Disable filter */
759 pSource->Send[lValue2].WetFilter.type = 0;
760 pSource->Send[lValue2].WetFilter.filter = 0;
762 else
763 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
765 else
766 alSetError(AL_INVALID_VALUE);
767 break;
769 default:
770 alSetError(AL_INVALID_ENUM);
771 break;
774 else
775 alSetError(AL_INVALID_NAME);
777 ProcessContext(pContext);
779 else
780 alSetError(AL_INVALID_OPERATION);
782 return;
786 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
788 ALCcontext *pContext;
790 pContext = alcGetCurrentContext();
791 if (pContext)
793 SuspendContext(pContext);
795 if (plValues)
797 if (alIsSource(source))
799 switch (eParam)
801 case AL_SOURCE_RELATIVE:
802 case AL_CONE_INNER_ANGLE:
803 case AL_CONE_OUTER_ANGLE:
804 case AL_LOOPING:
805 case AL_BUFFER:
806 case AL_SOURCE_STATE:
807 case AL_SEC_OFFSET:
808 case AL_SAMPLE_OFFSET:
809 case AL_BYTE_OFFSET:
810 case AL_MAX_DISTANCE:
811 case AL_ROLLOFF_FACTOR:
812 case AL_REFERENCE_DISTANCE:
813 case AL_DIRECT_FILTER:
814 case AL_DIRECT_FILTER_GAINHF_AUTO:
815 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
816 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
817 alSourcei(source, eParam, plValues[0]);
818 break;
820 case AL_POSITION:
821 case AL_VELOCITY:
822 case AL_DIRECTION:
823 case AL_AUXILIARY_SEND_FILTER:
824 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
825 break;
827 default:
828 alSetError(AL_INVALID_ENUM);
829 break;
832 else
833 alSetError(AL_INVALID_NAME);
835 else
836 alSetError(AL_INVALID_VALUE);
838 ProcessContext(pContext);
840 else
841 alSetError(AL_INVALID_OPERATION);
843 return;
847 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
849 ALCcontext *pContext;
850 ALsource *pSource;
851 ALfloat flOffset;
853 pContext = alcGetCurrentContext();
854 if (pContext)
856 SuspendContext(pContext);
858 if (pflValue)
860 if (alIsSource(source))
862 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
864 switch(eParam)
866 case AL_PITCH:
867 *pflValue = pSource->flPitch;
868 break;
870 case AL_GAIN:
871 *pflValue = pSource->flGain;
872 break;
874 case AL_MIN_GAIN:
875 *pflValue = pSource->flMinGain;
876 break;
878 case AL_MAX_GAIN:
879 *pflValue = pSource->flMaxGain;
880 break;
882 case AL_MAX_DISTANCE:
883 *pflValue = pSource->flMaxDistance;
884 break;
886 case AL_ROLLOFF_FACTOR:
887 *pflValue = pSource->flRollOffFactor;
888 break;
890 case AL_CONE_OUTER_GAIN:
891 *pflValue = pSource->flOuterGain;
892 break;
894 case AL_CONE_OUTER_GAINHF:
895 *pflValue = pSource->OuterGainHF;
896 break;
898 case AL_SEC_OFFSET:
899 case AL_SAMPLE_OFFSET:
900 case AL_BYTE_OFFSET:
901 if (GetSourceOffset(pSource, eParam, &flOffset))
902 *pflValue = flOffset;
903 else
904 alSetError(AL_INVALID_OPERATION);
905 break;
907 case AL_CONE_INNER_ANGLE:
908 *pflValue = pSource->flInnerAngle;
909 break;
911 case AL_CONE_OUTER_ANGLE:
912 *pflValue = pSource->flOuterAngle;
913 break;
915 case AL_REFERENCE_DISTANCE:
916 *pflValue = pSource->flRefDistance;
917 break;
919 case AL_AIR_ABSORPTION_FACTOR:
920 *pflValue = pSource->AirAbsorptionFactor;
921 break;
923 case AL_ROOM_ROLLOFF_FACTOR:
924 *pflValue = pSource->RoomRolloffFactor;
925 break;
927 default:
928 alSetError(AL_INVALID_ENUM);
929 break;
932 else
933 alSetError(AL_INVALID_NAME);
935 else
936 alSetError(AL_INVALID_VALUE);
938 ProcessContext(pContext);
940 else
941 alSetError(AL_INVALID_OPERATION);
943 return;
947 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
949 ALCcontext *pContext;
950 ALsource *pSource;
952 pContext = alcGetCurrentContext();
953 if (pContext)
955 SuspendContext(pContext);
957 if ((pflValue1) && (pflValue2) && (pflValue3))
959 if (alIsSource(source))
961 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
963 switch(eParam)
965 case AL_POSITION:
966 *pflValue1 = pSource->vPosition[0];
967 *pflValue2 = pSource->vPosition[1];
968 *pflValue3 = pSource->vPosition[2];
969 break;
971 case AL_VELOCITY:
972 *pflValue1 = pSource->vVelocity[0];
973 *pflValue2 = pSource->vVelocity[1];
974 *pflValue3 = pSource->vVelocity[2];
975 break;
977 case AL_DIRECTION:
978 *pflValue1 = pSource->vOrientation[0];
979 *pflValue2 = pSource->vOrientation[1];
980 *pflValue3 = pSource->vOrientation[2];
981 break;
983 default:
984 alSetError(AL_INVALID_ENUM);
985 break;
988 else
989 alSetError(AL_INVALID_NAME);
991 else
992 alSetError(AL_INVALID_VALUE);
994 ProcessContext(pContext);
996 else
997 alSetError(AL_INVALID_OPERATION);
999 return;
1003 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1005 ALCcontext *pContext;
1006 ALsource *pSource;
1008 pContext = alcGetCurrentContext();
1009 if (pContext)
1011 SuspendContext(pContext);
1013 if (pflValues)
1015 if (alIsSource(source))
1017 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1019 switch(eParam)
1021 case AL_PITCH:
1022 case AL_GAIN:
1023 case AL_MIN_GAIN:
1024 case AL_MAX_GAIN:
1025 case AL_MAX_DISTANCE:
1026 case AL_ROLLOFF_FACTOR:
1027 case AL_CONE_OUTER_GAIN:
1028 case AL_SEC_OFFSET:
1029 case AL_SAMPLE_OFFSET:
1030 case AL_BYTE_OFFSET:
1031 case AL_CONE_INNER_ANGLE:
1032 case AL_CONE_OUTER_ANGLE:
1033 case AL_REFERENCE_DISTANCE:
1034 case AL_CONE_OUTER_GAINHF:
1035 case AL_AIR_ABSORPTION_FACTOR:
1036 case AL_ROOM_ROLLOFF_FACTOR:
1037 alGetSourcef(source, eParam, pflValues);
1038 break;
1040 case AL_POSITION:
1041 pflValues[0] = pSource->vPosition[0];
1042 pflValues[1] = pSource->vPosition[1];
1043 pflValues[2] = pSource->vPosition[2];
1044 break;
1046 case AL_VELOCITY:
1047 pflValues[0] = pSource->vVelocity[0];
1048 pflValues[1] = pSource->vVelocity[1];
1049 pflValues[2] = pSource->vVelocity[2];
1050 break;
1052 case AL_DIRECTION:
1053 pflValues[0] = pSource->vOrientation[0];
1054 pflValues[1] = pSource->vOrientation[1];
1055 pflValues[2] = pSource->vOrientation[2];
1056 break;
1058 default:
1059 alSetError(AL_INVALID_ENUM);
1060 break;
1063 else
1064 alSetError(AL_INVALID_NAME);
1066 else
1067 alSetError(AL_INVALID_VALUE);
1069 ProcessContext(pContext);
1071 else
1072 alSetError(AL_INVALID_OPERATION);
1074 return;
1078 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1080 ALCcontext *pContext;
1081 ALsource *pSource;
1082 ALfloat flOffset;
1084 pContext = alcGetCurrentContext();
1085 if (pContext)
1087 SuspendContext(pContext);
1089 if (plValue)
1091 if (alIsSource(source))
1093 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1095 switch(eParam)
1097 case AL_MAX_DISTANCE:
1098 *plValue = (ALint)pSource->flMaxDistance;
1099 break;
1101 case AL_ROLLOFF_FACTOR:
1102 *plValue = (ALint)pSource->flRollOffFactor;
1103 break;
1105 case AL_REFERENCE_DISTANCE:
1106 *plValue = (ALint)pSource->flRefDistance;
1107 break;
1109 case AL_SOURCE_RELATIVE:
1110 *plValue = pSource->bHeadRelative;
1111 break;
1113 case AL_CONE_INNER_ANGLE:
1114 *plValue = (ALint)pSource->flInnerAngle;
1115 break;
1117 case AL_CONE_OUTER_ANGLE:
1118 *plValue = (ALint)pSource->flOuterAngle;
1119 break;
1121 case AL_LOOPING:
1122 *plValue = pSource->bLooping;
1123 break;
1125 case AL_BUFFER:
1126 *plValue = pSource->ulBufferID;
1127 break;
1129 case AL_SOURCE_STATE:
1130 *plValue = pSource->state;
1131 break;
1133 case AL_BUFFERS_QUEUED:
1134 *plValue = pSource->BuffersInQueue;
1135 break;
1137 case AL_BUFFERS_PROCESSED:
1138 if(pSource->bLooping)
1140 /* Buffers on a looping source are in a perpetual state
1141 * of PENDING, so don't report any as PROCESSED */
1142 *plValue = 0;
1144 else
1145 *plValue = pSource->BuffersProcessed;
1146 break;
1148 case AL_SOURCE_TYPE:
1149 *plValue = pSource->lSourceType;
1150 break;
1152 case AL_SEC_OFFSET:
1153 case AL_SAMPLE_OFFSET:
1154 case AL_BYTE_OFFSET:
1155 if (GetSourceOffset(pSource, eParam, &flOffset))
1156 *plValue = (ALint)flOffset;
1157 else
1158 alSetError(AL_INVALID_OPERATION);
1159 break;
1161 case AL_DIRECT_FILTER:
1162 *plValue = pSource->DirectFilter.filter;
1163 break;
1165 case AL_DIRECT_FILTER_GAINHF_AUTO:
1166 *plValue = pSource->DryGainHFAuto;
1167 break;
1169 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1170 *plValue = pSource->WetGainAuto;
1171 break;
1173 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1174 *plValue = pSource->WetGainHFAuto;
1175 break;
1177 default:
1178 alSetError(AL_INVALID_ENUM);
1179 break;
1182 else
1183 alSetError(AL_INVALID_NAME);
1185 else
1186 alSetError(AL_INVALID_VALUE);
1188 ProcessContext(pContext);
1190 else
1191 alSetError(AL_INVALID_OPERATION);
1193 return;
1197 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1199 ALCcontext *pContext;
1200 ALsource *pSource;
1202 pContext = alcGetCurrentContext();
1203 if (pContext)
1205 SuspendContext(pContext);
1207 if ((plValue1) && (plValue2) && (plValue3))
1209 if (alIsSource(source))
1211 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1213 switch(eParam)
1215 case AL_POSITION:
1216 *plValue1 = (ALint)pSource->vPosition[0];
1217 *plValue2 = (ALint)pSource->vPosition[1];
1218 *plValue3 = (ALint)pSource->vPosition[2];
1219 break;
1221 case AL_VELOCITY:
1222 *plValue1 = (ALint)pSource->vVelocity[0];
1223 *plValue2 = (ALint)pSource->vVelocity[1];
1224 *plValue3 = (ALint)pSource->vVelocity[2];
1225 break;
1227 case AL_DIRECTION:
1228 *plValue1 = (ALint)pSource->vOrientation[0];
1229 *plValue2 = (ALint)pSource->vOrientation[1];
1230 *plValue3 = (ALint)pSource->vOrientation[2];
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 alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1255 ALCcontext *pContext;
1256 ALsource *pSource;
1258 pContext = alcGetCurrentContext();
1259 if (pContext)
1261 SuspendContext(pContext);
1263 if (plValues)
1265 if (alIsSource(source))
1267 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1269 switch (eParam)
1271 case AL_SOURCE_RELATIVE:
1272 case AL_CONE_INNER_ANGLE:
1273 case AL_CONE_OUTER_ANGLE:
1274 case AL_LOOPING:
1275 case AL_BUFFER:
1276 case AL_SOURCE_STATE:
1277 case AL_BUFFERS_QUEUED:
1278 case AL_BUFFERS_PROCESSED:
1279 case AL_SEC_OFFSET:
1280 case AL_SAMPLE_OFFSET:
1281 case AL_BYTE_OFFSET:
1282 case AL_MAX_DISTANCE:
1283 case AL_ROLLOFF_FACTOR:
1284 case AL_REFERENCE_DISTANCE:
1285 case AL_SOURCE_TYPE:
1286 case AL_DIRECT_FILTER:
1287 case AL_DIRECT_FILTER_GAINHF_AUTO:
1288 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1289 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1290 alGetSourcei(source, eParam, plValues);
1291 break;
1293 case AL_POSITION:
1294 plValues[0] = (ALint)pSource->vPosition[0];
1295 plValues[1] = (ALint)pSource->vPosition[1];
1296 plValues[2] = (ALint)pSource->vPosition[2];
1297 break;
1299 case AL_VELOCITY:
1300 plValues[0] = (ALint)pSource->vVelocity[0];
1301 plValues[1] = (ALint)pSource->vVelocity[1];
1302 plValues[2] = (ALint)pSource->vVelocity[2];
1303 break;
1305 case AL_DIRECTION:
1306 plValues[0] = (ALint)pSource->vOrientation[0];
1307 plValues[1] = (ALint)pSource->vOrientation[1];
1308 plValues[2] = (ALint)pSource->vOrientation[2];
1309 break;
1311 default:
1312 alSetError(AL_INVALID_ENUM);
1313 break;
1316 else
1317 alSetError(AL_INVALID_NAME);
1319 else
1320 alSetError(AL_INVALID_VALUE);
1322 ProcessContext(pContext);
1324 else
1325 alSetError(AL_INVALID_OPERATION);
1327 return;
1331 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1333 alSourcePlayv(1, &source);
1334 return;
1337 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1339 ALCcontext *pContext;
1340 ALsource *pSource;
1341 ALbufferlistitem *ALBufferList;
1342 ALboolean bSourcesValid = AL_TRUE;
1343 ALboolean bPlay;
1344 ALsizei i;
1346 pContext = alcGetCurrentContext();
1347 if (pContext)
1349 SuspendContext(pContext);
1351 if (pSourceList)
1353 // Check that all the Sources are valid
1354 for (i = 0; i < n; i++)
1356 if (!alIsSource(pSourceList[i]))
1358 alSetError(AL_INVALID_NAME);
1359 bSourcesValid = AL_FALSE;
1360 break;
1364 if (bSourcesValid)
1366 for (i = 0; i < n; i++)
1368 // Assume Source won't need to play
1369 bPlay = AL_FALSE;
1371 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1373 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1374 ALBufferList = pSource->queue;
1375 while (ALBufferList)
1377 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1379 bPlay = AL_TRUE;
1380 break;
1382 ALBufferList = ALBufferList->next;
1385 if (bPlay)
1387 if (pSource->state != AL_PAUSED)
1389 pSource->state = AL_PLAYING;
1390 pSource->inuse = AL_TRUE;
1391 pSource->play = AL_TRUE;
1392 pSource->position = 0;
1393 pSource->position_fraction = 0;
1394 pSource->BuffersProcessed = 0;
1395 pSource->BuffersPlayed = 0;
1396 pSource->BufferPosition = 0;
1397 pSource->lBytesPlayed = 0;
1399 pSource->ulBufferID = pSource->queue->buffer;
1401 // Make sure all the Buffers in the queue are marked as PENDING
1402 ALBufferList = pSource->queue;
1403 while (ALBufferList)
1405 ALBufferList->bufferstate = PENDING;
1406 ALBufferList = ALBufferList->next;
1409 else
1411 pSource->state = AL_PLAYING;
1412 pSource->inuse = AL_TRUE;
1413 pSource->play = AL_TRUE;
1416 // Check if an Offset has been set
1417 if (pSource->lOffset)
1418 ApplyOffset(pSource, AL_FALSE);
1420 else
1422 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1423 ALBufferList = pSource->queue;
1424 while (ALBufferList)
1426 ALBufferList->bufferstate = PROCESSED;
1427 ALBufferList = ALBufferList->next;
1430 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1435 else
1437 // sources is a NULL pointer
1438 alSetError(AL_INVALID_VALUE);
1441 ProcessContext(pContext);
1443 else
1445 // Invalid Context
1446 alSetError(AL_INVALID_OPERATION);
1449 return;
1452 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1454 alSourcePausev(1, &source);
1455 return;
1458 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1460 ALCcontext *Context;
1461 ALsource *Source;
1462 ALsizei i;
1463 ALboolean bSourcesValid = AL_TRUE;
1465 Context=alcGetCurrentContext();
1466 if (Context)
1468 SuspendContext(Context);
1470 if (sources)
1472 // Check all the Sources are valid
1473 for (i=0;i<n;i++)
1475 if (!alIsSource(sources[i]))
1477 alSetError(AL_INVALID_NAME);
1478 bSourcesValid = AL_FALSE;
1479 break;
1483 if (bSourcesValid)
1485 for (i=0;i<n;i++)
1487 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1488 if (Source->state==AL_PLAYING)
1490 Source->state=AL_PAUSED;
1491 Source->inuse=AL_FALSE;
1496 else
1498 // sources is a NULL pointer
1499 alSetError(AL_INVALID_VALUE);
1502 ProcessContext(Context);
1504 else
1506 // Invalid Context
1507 alSetError(AL_INVALID_OPERATION);
1510 return;
1513 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1515 alSourceStopv(1, &source);
1516 return;
1519 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1521 ALCcontext *Context;
1522 ALsource *Source;
1523 ALsizei i;
1524 ALbufferlistitem *ALBufferListItem;
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_INITIAL)
1552 Source->state=AL_STOPPED;
1553 Source->inuse=AL_FALSE;
1554 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1555 ALBufferListItem= Source->queue;
1556 while (ALBufferListItem != NULL)
1558 ALBufferListItem->bufferstate = PROCESSED;
1559 ALBufferListItem = ALBufferListItem->next;
1562 Source->lOffset = 0;
1566 else
1568 // sources is a NULL pointer
1569 alSetError(AL_INVALID_VALUE);
1572 ProcessContext(Context);
1574 else
1576 // Invalid Context
1577 alSetError(AL_INVALID_OPERATION);
1580 return;
1583 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1585 alSourceRewindv(1, &source);
1586 return;
1589 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1591 ALCcontext *Context;
1592 ALsource *Source;
1593 ALsizei i;
1594 ALbufferlistitem *ALBufferListItem;
1595 ALboolean bSourcesValid = AL_TRUE;
1597 Context=alcGetCurrentContext();
1598 if (Context)
1600 SuspendContext(Context);
1602 if (sources)
1604 // Check all the Sources are valid
1605 for (i=0;i<n;i++)
1607 if (!alIsSource(sources[i]))
1609 alSetError(AL_INVALID_NAME);
1610 bSourcesValid = AL_FALSE;
1611 break;
1615 if (bSourcesValid)
1617 for (i=0;i<n;i++)
1619 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1620 if (Source->state!=AL_INITIAL)
1622 Source->state=AL_INITIAL;
1623 Source->inuse=AL_FALSE;
1624 Source->position=0;
1625 Source->position_fraction=0;
1626 Source->BuffersProcessed = 0;
1627 ALBufferListItem= Source->queue;
1628 while (ALBufferListItem != NULL)
1630 ALBufferListItem->bufferstate = PENDING;
1631 ALBufferListItem = ALBufferListItem->next;
1633 if (Source->queue)
1634 Source->ulBufferID = Source->queue->buffer;
1636 Source->lOffset = 0;
1640 else
1642 // sources is a NULL pointer
1643 alSetError(AL_INVALID_VALUE);
1646 ProcessContext(Context);
1648 else
1650 // Invalid Context
1651 alSetError(AL_INVALID_OPERATION);
1654 return;
1658 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1660 ALCcontext *Context;
1661 ALsource *ALSource;
1662 ALsizei i;
1663 ALbufferlistitem *ALBufferList;
1664 ALbufferlistitem *ALBufferListStart;
1665 ALuint DataSize;
1666 ALuint BufferSize;
1667 ALint iFrequency;
1668 ALint iFormat;
1669 ALboolean bBuffersValid = AL_TRUE;
1671 if (n == 0)
1672 return;
1674 Context=alcGetCurrentContext();
1675 if (Context)
1677 SuspendContext(Context);
1679 DataSize = 0;
1680 BufferSize = 0;
1682 // Check that all buffers are valid or zero and that the source is valid
1684 // Check that this is a valid source
1685 if (alIsSource(source))
1687 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1689 // Check that this is not a STATIC Source
1690 if (ALSource->lSourceType != AL_STATIC)
1692 iFrequency = -1;
1693 iFormat = -1;
1695 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1696 ALBufferList = ALSource->queue;
1697 while (ALBufferList)
1699 if (ALBufferList->buffer)
1701 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1702 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1703 break;
1705 ALBufferList = ALBufferList->next;
1708 for (i = 0; i < n; i++)
1710 if (alIsBuffer(buffers[i]))
1712 if (buffers[i])
1714 if ((iFrequency == -1) && (iFormat == -1))
1716 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1717 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1719 else
1721 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1722 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1724 alSetError(AL_INVALID_OPERATION);
1725 bBuffersValid = AL_FALSE;
1726 break;
1731 else
1733 alSetError(AL_INVALID_NAME);
1734 bBuffersValid = AL_FALSE;
1735 break;
1739 if (bBuffersValid)
1741 // Change Source Type
1742 ALSource->lSourceType = AL_STREAMING;
1744 // All buffers are valid - so add them to the list
1745 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1746 ALBufferListStart->buffer = buffers[0];
1747 ALBufferListStart->bufferstate = PENDING;
1748 ALBufferListStart->flag = 0;
1749 ALBufferListStart->next = NULL;
1751 if (buffers[0])
1752 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1753 else
1754 BufferSize = 0;
1756 DataSize += BufferSize;
1758 // Increment reference counter for buffer
1759 if (buffers[0])
1760 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1762 ALBufferList = ALBufferListStart;
1764 for (i = 1; i < n; i++)
1766 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1767 ALBufferList->next->buffer = buffers[i];
1768 ALBufferList->next->bufferstate = PENDING;
1769 ALBufferList->next->flag = 0;
1770 ALBufferList->next->next = NULL;
1772 if (buffers[i])
1773 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1774 else
1775 BufferSize = 0;
1777 DataSize += BufferSize;
1779 // Increment reference counter for buffer
1780 if (buffers[i])
1781 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1783 ALBufferList = ALBufferList->next;
1786 if (ALSource->queue == NULL)
1788 ALSource->queue = ALBufferListStart;
1789 // Update Current Buffer
1790 ALSource->ulBufferID = ALBufferListStart->buffer;
1792 else
1794 // Find end of queue
1795 ALBufferList = ALSource->queue;
1796 while (ALBufferList->next != NULL)
1798 ALBufferList = ALBufferList->next;
1801 ALBufferList->next = ALBufferListStart;
1804 // Update number of buffers in queue
1805 ALSource->BuffersInQueue += n;
1808 else
1810 // Invalid Source Type (can't queue on a Static Source)
1811 alSetError(AL_INVALID_OPERATION);
1814 else
1816 // Invalid Source Name
1817 alSetError(AL_INVALID_NAME);
1820 ProcessContext(Context);
1822 else
1824 // Invalid Context
1825 alSetError(AL_INVALID_OPERATION);
1828 return;
1832 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1833 // an array of buffer IDs that are to be filled with the names of the buffers removed
1834 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1836 ALCcontext *Context;
1837 ALsource *ALSource;
1838 ALsizei i;
1839 ALbufferlistitem *ALBufferList;
1840 ALuint DataSize;
1841 ALuint BufferSize;
1842 ALuint BufferID;
1843 ALboolean bBuffersProcessed;
1845 if (n == 0)
1846 return;
1848 DataSize = 0;
1849 BufferSize = 0;
1850 bBuffersProcessed = AL_TRUE;
1852 Context=alcGetCurrentContext();
1853 if (Context)
1855 SuspendContext(Context);
1857 if (alIsSource(source))
1859 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1861 // Check that all 'n' buffers have been processed
1862 ALBufferList = ALSource->queue;
1863 for (i = 0; i < n; i++)
1865 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1867 ALBufferList = ALBufferList->next;
1869 else
1871 bBuffersProcessed = AL_FALSE;
1872 break;
1876 // If all 'n' buffers have been processed, remove them from the queue
1877 if (bBuffersProcessed)
1879 for (i = 0; i < n; i++)
1881 ALBufferList = ALSource->queue;
1883 ALSource->queue = ALBufferList->next;
1884 // Record name of buffer
1885 buffers[i] = ALBufferList->buffer;
1886 // Decrement buffer reference counter
1887 if (ALBufferList->buffer)
1888 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1889 // Record size of buffer
1890 if (ALBufferList->buffer)
1891 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1892 else
1893 BufferSize = 0;
1895 DataSize += BufferSize;
1896 // Release memory for buffer list item
1897 free(ALBufferList);
1898 ALSource->BuffersInQueue--;
1899 ALSource->BuffersProcessed--;
1902 if (ALSource->state != AL_PLAYING)
1904 if (ALSource->queue)
1905 BufferID = ALSource->queue->buffer;
1906 else
1907 BufferID = 0;
1909 ALSource->ulBufferID = BufferID;
1912 if((ALuint)n > ALSource->BuffersPlayed)
1914 ALSource->BuffersPlayed = 0;
1915 ALSource->BufferPosition = 0;
1917 else
1918 ALSource->BuffersPlayed -= n;
1920 else
1922 // Some buffers can't be unqueue because they have not been processed
1923 alSetError(AL_INVALID_VALUE);
1926 else
1928 // Invalid Source Name
1929 alSetError(AL_INVALID_NAME);
1932 ProcessContext(Context);
1934 else
1936 // Invalid Context
1937 alSetError(AL_INVALID_OPERATION);
1940 return;
1944 static ALvoid InitSourceParams(ALsource *pSource)
1946 pSource->flInnerAngle = 360.0f;
1947 pSource->flOuterAngle = 360.0f;
1948 pSource->flPitch = 1.0f;
1949 pSource->vPosition[0] = 0.0f;
1950 pSource->vPosition[1] = 0.0f;
1951 pSource->vPosition[2] = 0.0f;
1952 pSource->vOrientation[0] = 0.0f;
1953 pSource->vOrientation[1] = 0.0f;
1954 pSource->vOrientation[2] = 0.0f;
1955 pSource->vVelocity[0] = 0.0f;
1956 pSource->vVelocity[1] = 0.0f;
1957 pSource->vVelocity[2] = 0.0f;
1958 pSource->flRefDistance = 1.0f;
1959 pSource->flMaxDistance = FLT_MAX;
1960 pSource->flRollOffFactor = 1.0f;
1961 pSource->bLooping = AL_FALSE;
1962 pSource->flGain = 1.0f;
1963 pSource->flMinGain = 0.0f;
1964 pSource->flMaxGain = 1.0f;
1965 pSource->flOuterGain = 0.0f;
1966 pSource->OuterGainHF = 1.0f;
1968 pSource->DryGainHFAuto = AL_TRUE;
1969 pSource->WetGainAuto = AL_TRUE;
1970 pSource->WetGainHFAuto = AL_TRUE;
1971 pSource->AirAbsorptionFactor = 0.0f;
1972 pSource->RoomRolloffFactor = 0.0f;
1974 pSource->state = AL_INITIAL;
1975 pSource->lSourceType = AL_UNDETERMINED;
1977 pSource->ulBufferID= 0;
1982 GetSourceOffset
1984 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1985 The offset is relative to the start of the queue (not the start of the current buffer)
1987 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1989 ALbufferlistitem *pBufferList;
1990 ALbuffer *pBuffer;
1991 ALfloat flBufferFreq;
1992 ALint lBytesPlayed, lChannels;
1993 ALenum eOriginalFormat;
1994 ALboolean bReturn = AL_TRUE;
1995 ALint lTotalBufferDataSize;
1997 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1999 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2000 // Get Current Buffer Size and frequency (in milliseconds)
2001 flBufferFreq = (ALfloat)pBuffer->frequency;
2002 eOriginalFormat = pBuffer->eOriginalFormat;
2003 lChannels = aluChannelsFromFormat(pBuffer->format);
2005 // Get Current BytesPlayed
2006 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2007 // Add byte length of any processed buffers in the queue
2008 pBufferList = pSource->queue;
2009 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2011 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2012 pBufferList = pBufferList->next;
2015 lTotalBufferDataSize = 0;
2016 pBufferList = pSource->queue;
2017 while (pBufferList)
2019 if (pBufferList->buffer)
2020 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2021 pBufferList = pBufferList->next;
2024 if (pSource->bLooping)
2026 if (lBytesPlayed < 0)
2027 lBytesPlayed = 0;
2028 else
2029 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2031 else
2033 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2034 if(lBytesPlayed < 0)
2035 lBytesPlayed = 0;
2036 if(lBytesPlayed > lTotalBufferDataSize)
2037 lBytesPlayed = lTotalBufferDataSize;
2040 switch (eName)
2042 case AL_SEC_OFFSET:
2043 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2044 break;
2045 case AL_SAMPLE_OFFSET:
2046 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2047 break;
2048 case AL_BYTE_OFFSET:
2049 // Take into account the original format of the Buffer
2050 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2051 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2053 // Compression rate of the ADPCM supported is 3.6111 to 1
2054 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2055 // Round down to nearest ADPCM block
2056 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2058 else if (eOriginalFormat == AL_FORMAT_REAR8)
2060 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2062 else if (eOriginalFormat == AL_FORMAT_REAR16)
2064 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2066 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2068 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2070 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2072 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2074 else
2076 *pflOffset = (ALfloat)lBytesPlayed;
2078 break;
2081 else
2083 *pflOffset = 0.0f;
2086 return bReturn;
2091 ApplyOffset
2093 Apply a playback offset to the Source. This function will update the queue (to correctly
2094 mark buffers as 'pending' or 'processed' depending upon the new offset.
2096 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2098 ALbufferlistitem *pBufferList;
2099 ALbuffer *pBuffer;
2100 ALint lBufferSize, lTotalBufferSize;
2101 ALint lByteOffset;
2103 // Get true byte offset
2104 lByteOffset = GetByteOffset(pSource);
2106 // If this is a valid offset apply it
2107 if (lByteOffset != -1)
2109 // Sort out the queue (pending and processed states)
2110 pBufferList = pSource->queue;
2111 lTotalBufferSize = 0;
2112 pSource->BuffersPlayed = 0;
2113 pSource->BuffersProcessed = 0;
2114 while (pBufferList)
2116 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2117 lBufferSize = pBuffer ? pBuffer->size : 0;
2119 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2121 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2122 // update the state to PROCESSED
2123 pSource->BuffersPlayed++;
2125 if (!pSource->bLooping)
2127 pBufferList->bufferstate = PROCESSED;
2128 pSource->BuffersProcessed++;
2131 else if (lTotalBufferSize <= lByteOffset)
2133 // Offset is within this buffer
2134 pBufferList->bufferstate = PENDING;
2136 // Set Current Buffer ID
2137 pSource->ulBufferID = pBufferList->buffer;
2139 // Set current position in this buffer
2140 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2142 // Set Total Bytes Played to Offset
2143 pSource->lBytesPlayed = lByteOffset;
2145 // SW Mixer Positions are in Samples
2146 pSource->position = pSource->BufferPosition /
2147 aluBytesFromFormat(pBuffer->format) /
2148 aluChannelsFromFormat(pBuffer->format);
2150 else
2152 // Offset is before this buffer, so mark as pending
2153 pBufferList->bufferstate = PENDING;
2156 // Increment the TotalBufferSize
2157 lTotalBufferSize += lBufferSize;
2159 // Move on to next buffer in the Queue
2160 pBufferList = pBufferList->next;
2163 else
2165 if (bUpdateContext)
2166 alSetError(AL_INVALID_VALUE);
2169 // Clear Offset
2170 pSource->lOffset = 0;
2175 GetByteOffset
2177 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2178 offset supplied by the application). This takes into account the fact that the buffer format
2179 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2181 static ALint GetByteOffset(ALsource *pSource)
2183 ALbuffer *pBuffer = NULL;
2184 ALbufferlistitem *pBufferList;
2185 ALfloat flBufferFreq;
2186 ALint lChannels;
2187 ALint lByteOffset = -1;
2188 ALint lTotalBufferDataSize;
2190 // Find the first non-NULL Buffer in the Queue
2191 pBufferList = pSource->queue;
2192 while (pBufferList)
2194 if (pBufferList->buffer)
2196 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2197 break;
2199 pBufferList = pBufferList->next;
2202 if (pBuffer)
2204 flBufferFreq = ((ALfloat)pBuffer->frequency);
2205 lChannels = aluChannelsFromFormat(pBuffer->format);
2207 // Determine the ByteOffset (and ensure it is block aligned)
2208 switch (pSource->lOffsetType)
2210 case AL_BYTE_OFFSET:
2211 // Take into consideration the original format
2212 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2213 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2215 // Round down to nearest ADPCM block
2216 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2217 // Multiply by compression rate
2218 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2219 lByteOffset -= (lByteOffset % (lChannels * 2));
2221 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2223 lByteOffset = pSource->lOffset * 4;
2224 lByteOffset -= (lByteOffset % (lChannels * 2));
2226 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2228 lByteOffset = pSource->lOffset * 2;
2229 lByteOffset -= (lByteOffset % (lChannels * 2));
2231 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2233 lByteOffset = pSource->lOffset * 2;
2234 lByteOffset -= (lByteOffset % (lChannels * 2));
2236 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2238 lByteOffset = pSource->lOffset / 2;
2239 lByteOffset -= (lByteOffset % (lChannels * 2));
2241 else
2243 lByteOffset = pSource->lOffset;
2244 lByteOffset -= (lByteOffset % (lChannels * 2));
2246 break;
2248 case AL_SAMPLE_OFFSET:
2249 lByteOffset = pSource->lOffset * lChannels * 2;
2250 break;
2252 case AL_SEC_OFFSET:
2253 // Note - lOffset is internally stored as Milliseconds
2254 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2255 lByteOffset -= (lByteOffset % (lChannels * 2));
2256 break;
2259 lTotalBufferDataSize = 0;
2260 pBufferList = pSource->queue;
2261 while (pBufferList)
2263 if (pBufferList->buffer)
2264 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2265 pBufferList = pBufferList->next;
2268 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2269 if (lByteOffset >= lTotalBufferDataSize)
2270 lByteOffset = -1;
2273 return lByteOffset;
2277 ALvoid ReleaseALSources(ALCcontext *Context)
2279 #ifdef _DEBUG
2280 if(Context->SourceCount > 0)
2281 AL_PRINT("exit() %d Source(s) NOT deleted\n", Context->SourceCount);
2282 #endif
2284 while(Context->Source)
2286 ALsource *temp = Context->Source;
2287 Context->Source = Context->Source->next;
2289 // Release source structure
2290 memset(temp, 0, sizeof(ALsource));
2291 free(temp);
2293 Context->SourceCount = 0;