Release effect slots when deleting sources
[openal-soft.git] / OpenAL32 / alSource.c
blobf48ef304b5827c83806404b5d489359ae115161a
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);
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 if ((ALuint)n <= Context->SourceCount)
142 // Check that all Sources are valid (and can therefore be deleted)
143 for (i = 0; i < n; i++)
145 if (!alIsSource(sources[i]))
147 alSetError(AL_INVALID_NAME);
148 bSourcesValid = AL_FALSE;
149 break;
153 if (bSourcesValid)
155 // All Sources are valid, and can be deleted
156 for (i = 0; i < n; i++)
158 // Recheck that the Source is valid, because there could be duplicated Source names
159 if (alIsSource(sources[i]))
161 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
162 alSourceStop((ALuint)ALSource->source);
164 // For each buffer in the source's queue, decrement its reference counter and remove it
165 while (ALSource->queue != NULL)
167 ALBufferList = ALSource->queue;
168 // Decrement buffer's reference counter
169 if (ALBufferList->buffer != 0)
170 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
171 // Update queue to point to next element in list
172 ALSource->queue = ALBufferList->next;
173 // Release memory allocated for buffer list item
174 free(ALBufferList);
177 for(j = 0;j < MAX_SENDS;++j)
179 if(ALSource->Send[j].Slot)
180 ALSource->Send[j].Slot->refcount--;
181 ALSource->Send[j].Slot = NULL;
184 // Decrement Source count
185 Context->SourceCount--;
187 // Remove Source from list of Sources
188 list = &Context->Source;
189 while(*list && *list != ALSource)
190 list = &(*list)->next;
192 if(*list)
193 *list = (*list)->next;
194 ALTHUNK_REMOVEENTRY(ALSource->source);
196 memset(ALSource,0,sizeof(ALsource));
197 free(ALSource);
203 else
205 // Trying to delete more Sources than have been generated
206 alSetError(AL_INVALID_NAME);
209 else
211 // No Device created, or attached to Context
212 alSetError(AL_INVALID_OPERATION);
215 else
216 alSetError(AL_INVALID_VALUE);
218 ProcessContext(Context);
220 else
222 // Invalid Context
223 alSetError(AL_INVALID_OPERATION);
226 return;
230 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
232 ALboolean result=AL_FALSE;
233 ALCcontext *Context;
234 ALsource *Source;
236 Context=alcGetCurrentContext();
237 if (Context)
239 SuspendContext(Context);
241 // To determine if this is a valid Source name, look through the list of generated Sources
242 Source = Context->Source;
243 while(Source)
245 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
247 result = AL_TRUE;
248 break;
251 Source = Source->next;
254 ProcessContext(Context);
256 else
258 // Invalid Context
259 alSetError(AL_INVALID_OPERATION);
262 return result;
266 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
268 ALCcontext *pContext;
269 ALsource *pSource;
271 pContext = alcGetCurrentContext();
272 if (pContext)
274 SuspendContext(pContext);
276 if (alIsSource(source))
278 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
280 switch (eParam)
282 case AL_PITCH:
283 if (flValue >= 0.0f)
285 pSource->flPitch = flValue;
286 if(pSource->flPitch < 0.001f)
287 pSource->flPitch = 0.001f;
289 else
290 alSetError(AL_INVALID_VALUE);
291 break;
293 case AL_CONE_INNER_ANGLE:
294 if ((flValue >= 0.0f) && (flValue <= 360.0f))
295 pSource->flInnerAngle = flValue;
296 else
297 alSetError(AL_INVALID_VALUE);
298 break;
300 case AL_CONE_OUTER_ANGLE:
301 if ((flValue >= 0.0f) && (flValue <= 360.0f))
302 pSource->flOuterAngle = flValue;
303 else
304 alSetError(AL_INVALID_VALUE);
305 break;
307 case AL_GAIN:
308 if (flValue >= 0.0f)
309 pSource->flGain = flValue;
310 else
311 alSetError(AL_INVALID_VALUE);
312 break;
314 case AL_MAX_DISTANCE:
315 if (flValue >= 0.0f)
316 pSource->flMaxDistance = flValue;
317 else
318 alSetError(AL_INVALID_VALUE);
319 break;
321 case AL_ROLLOFF_FACTOR:
322 if (flValue >= 0.0f)
323 pSource->flRollOffFactor = flValue;
324 else
325 alSetError(AL_INVALID_VALUE);
326 break;
328 case AL_REFERENCE_DISTANCE:
329 if (flValue >= 0.0f)
330 pSource->flRefDistance = flValue;
331 else
332 alSetError(AL_INVALID_VALUE);
333 break;
335 case AL_MIN_GAIN:
336 if ((flValue >= 0.0f) && (flValue <= 1.0f))
337 pSource->flMinGain = flValue;
338 else
339 alSetError(AL_INVALID_VALUE);
340 break;
342 case AL_MAX_GAIN:
343 if ((flValue >= 0.0f) && (flValue <= 1.0f))
344 pSource->flMaxGain = flValue;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 case AL_CONE_OUTER_GAIN:
350 if ((flValue >= 0.0f) && (flValue <= 1.0f))
351 pSource->flOuterGain = flValue;
352 else
353 alSetError(AL_INVALID_VALUE);
354 break;
356 case AL_CONE_OUTER_GAINHF:
357 if ((flValue >= 0.0f) && (flValue <= 1.0f))
358 pSource->OuterGainHF = flValue;
359 else
360 alSetError(AL_INVALID_VALUE);
361 break;
363 case AL_AIR_ABSORPTION_FACTOR:
364 if (flValue >= 0.0f && flValue <= 10.0f)
365 pSource->AirAbsorptionFactor = flValue;
366 else
367 alSetError(AL_INVALID_VALUE);
368 break;
370 case AL_ROOM_ROLLOFF_FACTOR:
371 if (flValue >= 0.0f && flValue <= 1.0f)
372 pSource->RoomRolloffFactor = flValue;
373 else
374 alSetError(AL_INVALID_VALUE);
375 break;
377 case AL_SEC_OFFSET:
378 case AL_SAMPLE_OFFSET:
379 case AL_BYTE_OFFSET:
380 if (flValue >= 0.0f)
382 pSource->lOffsetType = eParam;
384 // Store Offset (convert Seconds into Milliseconds)
385 if (eParam == AL_SEC_OFFSET)
386 pSource->lOffset = (ALint)(flValue * 1000.0f);
387 else
388 pSource->lOffset = (ALint)flValue;
390 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
391 ApplyOffset(pSource, AL_TRUE);
393 else
394 alSetError(AL_INVALID_VALUE);
395 break;
397 default:
398 alSetError(AL_INVALID_ENUM);
399 break;
402 else
404 // Invalid Source Name
405 alSetError(AL_INVALID_NAME);
408 ProcessContext(pContext);
410 else
412 // Invalid context
413 alSetError(AL_INVALID_OPERATION);
416 return;
420 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
422 ALCcontext *pContext;
423 ALsource *pSource;
425 pContext = alcGetCurrentContext();
426 if (pContext)
428 SuspendContext(pContext);
430 if (alIsSource(source))
432 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
433 switch(eParam)
435 case AL_POSITION:
436 pSource->vPosition[0] = flValue1;
437 pSource->vPosition[1] = flValue2;
438 pSource->vPosition[2] = flValue3;
439 break;
441 case AL_VELOCITY:
442 pSource->vVelocity[0] = flValue1;
443 pSource->vVelocity[1] = flValue2;
444 pSource->vVelocity[2] = flValue3;
445 break;
447 case AL_DIRECTION:
448 pSource->vOrientation[0] = flValue1;
449 pSource->vOrientation[1] = flValue2;
450 pSource->vOrientation[2] = flValue3;
451 break;
453 default:
454 alSetError(AL_INVALID_ENUM);
455 break;
458 else
459 alSetError(AL_INVALID_NAME);
461 ProcessContext(pContext);
463 else
465 alSetError(AL_INVALID_OPERATION);
468 return;
472 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
474 ALCcontext *pContext;
476 pContext = alcGetCurrentContext();
477 if (pContext)
479 SuspendContext(pContext);
481 if (pflValues)
483 if (alIsSource(source))
485 switch (eParam)
487 case AL_PITCH:
488 case AL_CONE_INNER_ANGLE:
489 case AL_CONE_OUTER_ANGLE:
490 case AL_GAIN:
491 case AL_MAX_DISTANCE:
492 case AL_ROLLOFF_FACTOR:
493 case AL_REFERENCE_DISTANCE:
494 case AL_MIN_GAIN:
495 case AL_MAX_GAIN:
496 case AL_CONE_OUTER_GAIN:
497 case AL_CONE_OUTER_GAINHF:
498 case AL_SEC_OFFSET:
499 case AL_SAMPLE_OFFSET:
500 case AL_BYTE_OFFSET:
501 case AL_AIR_ABSORPTION_FACTOR:
502 case AL_ROOM_ROLLOFF_FACTOR:
503 alSourcef(source, eParam, pflValues[0]);
504 break;
506 case AL_POSITION:
507 case AL_VELOCITY:
508 case AL_DIRECTION:
509 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
510 break;
512 default:
513 alSetError(AL_INVALID_ENUM);
514 break;
517 else
518 alSetError(AL_INVALID_NAME);
520 else
521 alSetError(AL_INVALID_VALUE);
523 ProcessContext(pContext);
525 else
526 alSetError(AL_INVALID_OPERATION);
528 return;
532 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
534 ALCcontext *pContext;
535 ALsource *pSource;
536 ALbufferlistitem *pALBufferListItem;
537 ALint Counter = 0;
538 ALint DataSize = 0;
539 ALint BufferSize;
541 pContext = alcGetCurrentContext();
542 if (pContext)
544 SuspendContext(pContext);
546 if (alIsSource(source))
548 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
550 switch(eParam)
552 case AL_MAX_DISTANCE:
553 case AL_ROLLOFF_FACTOR:
554 case AL_REFERENCE_DISTANCE:
555 alSourcef(source, eParam, (ALfloat)lValue);
556 break;
558 case AL_SOURCE_RELATIVE:
559 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
560 pSource->bHeadRelative = (ALboolean)lValue;
561 else
562 alSetError(AL_INVALID_VALUE);
563 break;
565 case AL_CONE_INNER_ANGLE:
566 if ((lValue >= 0) && (lValue <= 360))
567 pSource->flInnerAngle = (float)lValue;
568 else
569 alSetError(AL_INVALID_VALUE);
570 break;
572 case AL_CONE_OUTER_ANGLE:
573 if ((lValue >= 0) && (lValue <= 360))
574 pSource->flOuterAngle = (float)lValue;
575 else
576 alSetError(AL_INVALID_VALUE);
577 break;
579 case AL_LOOPING:
580 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
581 pSource->bLooping = (ALboolean)lValue;
582 else
583 alSetError(AL_INVALID_VALUE);
584 break;
586 case AL_BUFFER:
587 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
589 if (alIsBuffer(lValue))
591 // Remove all elements in the queue
592 while (pSource->queue != NULL)
594 pALBufferListItem = pSource->queue;
595 pSource->queue = pALBufferListItem->next;
596 // Decrement reference counter for buffer
597 if (pALBufferListItem->buffer)
598 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
599 // Record size of buffer
600 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
601 DataSize += BufferSize;
602 // Increment the number of buffers removed from queue
603 Counter++;
604 // Release memory for buffer list item
605 free(pALBufferListItem);
606 // Decrement the number of buffers in the queue
607 pSource->BuffersInQueue--;
610 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
611 if (lValue != 0)
613 // Source is now in STATIC mode
614 pSource->lSourceType = AL_STATIC;
616 // Add the selected buffer to the queue
617 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
618 pALBufferListItem->buffer = lValue;
619 pALBufferListItem->bufferstate = PENDING;
620 pALBufferListItem->flag = 0;
621 pALBufferListItem->next = NULL;
623 pSource->queue = pALBufferListItem;
624 pSource->BuffersInQueue = 1;
626 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
628 // Increment reference counter for buffer
629 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
631 else
633 // Source is now in UNDETERMINED mode
634 pSource->lSourceType = AL_UNDETERMINED;
637 // Set Buffers Processed
638 pSource->BuffersProcessed = 0;
640 // Update AL_BUFFER parameter
641 pSource->ulBufferID = lValue;
643 else
644 alSetError(AL_INVALID_VALUE);
646 else
647 alSetError(AL_INVALID_OPERATION);
648 break;
650 case AL_SOURCE_STATE:
651 // Query only
652 alSetError(AL_INVALID_OPERATION);
653 break;
655 case AL_SEC_OFFSET:
656 case AL_SAMPLE_OFFSET:
657 case AL_BYTE_OFFSET:
658 if (lValue >= 0)
660 pSource->lOffsetType = eParam;
662 // Store Offset (convert Seconds into Milliseconds)
663 if (eParam == AL_SEC_OFFSET)
664 pSource->lOffset = lValue * 1000;
665 else
666 pSource->lOffset = lValue;
668 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
669 ApplyOffset(pSource, AL_TRUE);
671 else
672 alSetError(AL_INVALID_VALUE);
673 break;
675 case AL_DIRECT_FILTER:
676 if(alIsFilter(lValue))
678 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
679 if(!filter)
681 pSource->DirectFilter.type = AL_FILTER_NULL;
682 pSource->DirectFilter.filter = 0;
684 else
685 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
687 else
688 alSetError(AL_INVALID_VALUE);
689 break;
691 case AL_DIRECT_FILTER_GAINHF_AUTO:
692 if(lValue == AL_TRUE || lValue == AL_FALSE)
693 pSource->DryGainHFAuto = lValue;
694 else
695 alSetError(AL_INVALID_VALUE);
696 break;
698 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
699 if(lValue == AL_TRUE || lValue == AL_FALSE)
700 pSource->WetGainAuto = lValue;
701 else
702 alSetError(AL_INVALID_VALUE);
703 break;
705 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
706 if(lValue == AL_TRUE || lValue == AL_FALSE)
707 pSource->WetGainHFAuto = lValue;
708 else
709 alSetError(AL_INVALID_VALUE);
710 break;
712 default:
713 alSetError(AL_INVALID_ENUM);
714 break;
717 else
718 alSetError(AL_INVALID_NAME);
720 ProcessContext(pContext);
722 else
723 alSetError(AL_INVALID_OPERATION);
725 return;
729 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
731 ALCcontext *pContext;
733 pContext = alcGetCurrentContext();
734 if (pContext)
736 SuspendContext(pContext);
738 if (alIsSource(source))
740 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
742 switch (eParam)
744 case AL_POSITION:
745 case AL_VELOCITY:
746 case AL_DIRECTION:
747 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
748 break;
750 case AL_AUXILIARY_SEND_FILTER:
751 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
752 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
753 alIsFilter(lValue3))
755 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
756 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
758 /* Release refcount on the previous slot, and add one for
759 * the new slot */
760 if(pSource->Send[lValue2].Slot)
761 pSource->Send[lValue2].Slot->refcount--;
762 pSource->Send[lValue2].Slot = ALEffectSlot;
763 if(pSource->Send[lValue2].Slot)
764 pSource->Send[lValue2].Slot->refcount++;
766 if(!ALFilter)
768 /* Disable filter */
769 pSource->Send[lValue2].WetFilter.type = 0;
770 pSource->Send[lValue2].WetFilter.filter = 0;
772 else
773 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
775 else
776 alSetError(AL_INVALID_VALUE);
777 break;
779 default:
780 alSetError(AL_INVALID_ENUM);
781 break;
784 else
785 alSetError(AL_INVALID_NAME);
787 ProcessContext(pContext);
789 else
790 alSetError(AL_INVALID_OPERATION);
792 return;
796 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
798 ALCcontext *pContext;
800 pContext = alcGetCurrentContext();
801 if (pContext)
803 SuspendContext(pContext);
805 if (plValues)
807 if (alIsSource(source))
809 switch (eParam)
811 case AL_SOURCE_RELATIVE:
812 case AL_CONE_INNER_ANGLE:
813 case AL_CONE_OUTER_ANGLE:
814 case AL_LOOPING:
815 case AL_BUFFER:
816 case AL_SOURCE_STATE:
817 case AL_SEC_OFFSET:
818 case AL_SAMPLE_OFFSET:
819 case AL_BYTE_OFFSET:
820 case AL_MAX_DISTANCE:
821 case AL_ROLLOFF_FACTOR:
822 case AL_REFERENCE_DISTANCE:
823 case AL_DIRECT_FILTER:
824 case AL_DIRECT_FILTER_GAINHF_AUTO:
825 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
826 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
827 alSourcei(source, eParam, plValues[0]);
828 break;
830 case AL_POSITION:
831 case AL_VELOCITY:
832 case AL_DIRECTION:
833 case AL_AUXILIARY_SEND_FILTER:
834 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
835 break;
837 default:
838 alSetError(AL_INVALID_ENUM);
839 break;
842 else
843 alSetError(AL_INVALID_NAME);
845 else
846 alSetError(AL_INVALID_VALUE);
848 ProcessContext(pContext);
850 else
851 alSetError(AL_INVALID_OPERATION);
853 return;
857 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
859 ALCcontext *pContext;
860 ALsource *pSource;
861 ALfloat flOffset;
863 pContext = alcGetCurrentContext();
864 if (pContext)
866 SuspendContext(pContext);
868 if (pflValue)
870 if (alIsSource(source))
872 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
874 switch(eParam)
876 case AL_PITCH:
877 *pflValue = pSource->flPitch;
878 break;
880 case AL_GAIN:
881 *pflValue = pSource->flGain;
882 break;
884 case AL_MIN_GAIN:
885 *pflValue = pSource->flMinGain;
886 break;
888 case AL_MAX_GAIN:
889 *pflValue = pSource->flMaxGain;
890 break;
892 case AL_MAX_DISTANCE:
893 *pflValue = pSource->flMaxDistance;
894 break;
896 case AL_ROLLOFF_FACTOR:
897 *pflValue = pSource->flRollOffFactor;
898 break;
900 case AL_CONE_OUTER_GAIN:
901 *pflValue = pSource->flOuterGain;
902 break;
904 case AL_CONE_OUTER_GAINHF:
905 *pflValue = pSource->OuterGainHF;
906 break;
908 case AL_SEC_OFFSET:
909 case AL_SAMPLE_OFFSET:
910 case AL_BYTE_OFFSET:
911 if (GetSourceOffset(pSource, eParam, &flOffset))
912 *pflValue = flOffset;
913 else
914 alSetError(AL_INVALID_OPERATION);
915 break;
917 case AL_CONE_INNER_ANGLE:
918 *pflValue = pSource->flInnerAngle;
919 break;
921 case AL_CONE_OUTER_ANGLE:
922 *pflValue = pSource->flOuterAngle;
923 break;
925 case AL_REFERENCE_DISTANCE:
926 *pflValue = pSource->flRefDistance;
927 break;
929 case AL_AIR_ABSORPTION_FACTOR:
930 *pflValue = pSource->AirAbsorptionFactor;
931 break;
933 case AL_ROOM_ROLLOFF_FACTOR:
934 *pflValue = pSource->RoomRolloffFactor;
935 break;
937 default:
938 alSetError(AL_INVALID_ENUM);
939 break;
942 else
943 alSetError(AL_INVALID_NAME);
945 else
946 alSetError(AL_INVALID_VALUE);
948 ProcessContext(pContext);
950 else
951 alSetError(AL_INVALID_OPERATION);
953 return;
957 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
959 ALCcontext *pContext;
960 ALsource *pSource;
962 pContext = alcGetCurrentContext();
963 if (pContext)
965 SuspendContext(pContext);
967 if ((pflValue1) && (pflValue2) && (pflValue3))
969 if (alIsSource(source))
971 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
973 switch(eParam)
975 case AL_POSITION:
976 *pflValue1 = pSource->vPosition[0];
977 *pflValue2 = pSource->vPosition[1];
978 *pflValue3 = pSource->vPosition[2];
979 break;
981 case AL_VELOCITY:
982 *pflValue1 = pSource->vVelocity[0];
983 *pflValue2 = pSource->vVelocity[1];
984 *pflValue3 = pSource->vVelocity[2];
985 break;
987 case AL_DIRECTION:
988 *pflValue1 = pSource->vOrientation[0];
989 *pflValue2 = pSource->vOrientation[1];
990 *pflValue3 = pSource->vOrientation[2];
991 break;
993 default:
994 alSetError(AL_INVALID_ENUM);
995 break;
998 else
999 alSetError(AL_INVALID_NAME);
1001 else
1002 alSetError(AL_INVALID_VALUE);
1004 ProcessContext(pContext);
1006 else
1007 alSetError(AL_INVALID_OPERATION);
1009 return;
1013 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1015 ALCcontext *pContext;
1016 ALsource *pSource;
1018 pContext = alcGetCurrentContext();
1019 if (pContext)
1021 SuspendContext(pContext);
1023 if (pflValues)
1025 if (alIsSource(source))
1027 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1029 switch(eParam)
1031 case AL_PITCH:
1032 case AL_GAIN:
1033 case AL_MIN_GAIN:
1034 case AL_MAX_GAIN:
1035 case AL_MAX_DISTANCE:
1036 case AL_ROLLOFF_FACTOR:
1037 case AL_CONE_OUTER_GAIN:
1038 case AL_SEC_OFFSET:
1039 case AL_SAMPLE_OFFSET:
1040 case AL_BYTE_OFFSET:
1041 case AL_CONE_INNER_ANGLE:
1042 case AL_CONE_OUTER_ANGLE:
1043 case AL_REFERENCE_DISTANCE:
1044 case AL_CONE_OUTER_GAINHF:
1045 case AL_AIR_ABSORPTION_FACTOR:
1046 case AL_ROOM_ROLLOFF_FACTOR:
1047 alGetSourcef(source, eParam, pflValues);
1048 break;
1050 case AL_POSITION:
1051 pflValues[0] = pSource->vPosition[0];
1052 pflValues[1] = pSource->vPosition[1];
1053 pflValues[2] = pSource->vPosition[2];
1054 break;
1056 case AL_VELOCITY:
1057 pflValues[0] = pSource->vVelocity[0];
1058 pflValues[1] = pSource->vVelocity[1];
1059 pflValues[2] = pSource->vVelocity[2];
1060 break;
1062 case AL_DIRECTION:
1063 pflValues[0] = pSource->vOrientation[0];
1064 pflValues[1] = pSource->vOrientation[1];
1065 pflValues[2] = pSource->vOrientation[2];
1066 break;
1068 default:
1069 alSetError(AL_INVALID_ENUM);
1070 break;
1073 else
1074 alSetError(AL_INVALID_NAME);
1076 else
1077 alSetError(AL_INVALID_VALUE);
1079 ProcessContext(pContext);
1081 else
1082 alSetError(AL_INVALID_OPERATION);
1084 return;
1088 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1090 ALCcontext *pContext;
1091 ALsource *pSource;
1092 ALfloat flOffset;
1094 pContext = alcGetCurrentContext();
1095 if (pContext)
1097 SuspendContext(pContext);
1099 if (plValue)
1101 if (alIsSource(source))
1103 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1105 switch(eParam)
1107 case AL_MAX_DISTANCE:
1108 *plValue = (ALint)pSource->flMaxDistance;
1109 break;
1111 case AL_ROLLOFF_FACTOR:
1112 *plValue = (ALint)pSource->flRollOffFactor;
1113 break;
1115 case AL_REFERENCE_DISTANCE:
1116 *plValue = (ALint)pSource->flRefDistance;
1117 break;
1119 case AL_SOURCE_RELATIVE:
1120 *plValue = pSource->bHeadRelative;
1121 break;
1123 case AL_CONE_INNER_ANGLE:
1124 *plValue = (ALint)pSource->flInnerAngle;
1125 break;
1127 case AL_CONE_OUTER_ANGLE:
1128 *plValue = (ALint)pSource->flOuterAngle;
1129 break;
1131 case AL_LOOPING:
1132 *plValue = pSource->bLooping;
1133 break;
1135 case AL_BUFFER:
1136 *plValue = pSource->ulBufferID;
1137 break;
1139 case AL_SOURCE_STATE:
1140 *plValue = pSource->state;
1141 break;
1143 case AL_BUFFERS_QUEUED:
1144 *plValue = pSource->BuffersInQueue;
1145 break;
1147 case AL_BUFFERS_PROCESSED:
1148 if(pSource->bLooping)
1150 /* Buffers on a looping source are in a perpetual state
1151 * of PENDING, so don't report any as PROCESSED */
1152 *plValue = 0;
1154 else
1155 *plValue = pSource->BuffersProcessed;
1156 break;
1158 case AL_SOURCE_TYPE:
1159 *plValue = pSource->lSourceType;
1160 break;
1162 case AL_SEC_OFFSET:
1163 case AL_SAMPLE_OFFSET:
1164 case AL_BYTE_OFFSET:
1165 if (GetSourceOffset(pSource, eParam, &flOffset))
1166 *plValue = (ALint)flOffset;
1167 else
1168 alSetError(AL_INVALID_OPERATION);
1169 break;
1171 case AL_DIRECT_FILTER:
1172 *plValue = pSource->DirectFilter.filter;
1173 break;
1175 case AL_DIRECT_FILTER_GAINHF_AUTO:
1176 *plValue = pSource->DryGainHFAuto;
1177 break;
1179 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1180 *plValue = pSource->WetGainAuto;
1181 break;
1183 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1184 *plValue = pSource->WetGainHFAuto;
1185 break;
1187 default:
1188 alSetError(AL_INVALID_ENUM);
1189 break;
1192 else
1193 alSetError(AL_INVALID_NAME);
1195 else
1196 alSetError(AL_INVALID_VALUE);
1198 ProcessContext(pContext);
1200 else
1201 alSetError(AL_INVALID_OPERATION);
1203 return;
1207 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1209 ALCcontext *pContext;
1210 ALsource *pSource;
1212 pContext = alcGetCurrentContext();
1213 if (pContext)
1215 SuspendContext(pContext);
1217 if ((plValue1) && (plValue2) && (plValue3))
1219 if (alIsSource(source))
1221 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1223 switch(eParam)
1225 case AL_POSITION:
1226 *plValue1 = (ALint)pSource->vPosition[0];
1227 *plValue2 = (ALint)pSource->vPosition[1];
1228 *plValue3 = (ALint)pSource->vPosition[2];
1229 break;
1231 case AL_VELOCITY:
1232 *plValue1 = (ALint)pSource->vVelocity[0];
1233 *plValue2 = (ALint)pSource->vVelocity[1];
1234 *plValue3 = (ALint)pSource->vVelocity[2];
1235 break;
1237 case AL_DIRECTION:
1238 *plValue1 = (ALint)pSource->vOrientation[0];
1239 *plValue2 = (ALint)pSource->vOrientation[1];
1240 *plValue3 = (ALint)pSource->vOrientation[2];
1241 break;
1243 default:
1244 alSetError(AL_INVALID_ENUM);
1245 break;
1248 else
1249 alSetError(AL_INVALID_NAME);
1251 else
1252 alSetError(AL_INVALID_VALUE);
1254 ProcessContext(pContext);
1256 else
1257 alSetError(AL_INVALID_OPERATION);
1259 return;
1263 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1265 ALCcontext *pContext;
1266 ALsource *pSource;
1268 pContext = alcGetCurrentContext();
1269 if (pContext)
1271 SuspendContext(pContext);
1273 if (plValues)
1275 if (alIsSource(source))
1277 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1279 switch (eParam)
1281 case AL_SOURCE_RELATIVE:
1282 case AL_CONE_INNER_ANGLE:
1283 case AL_CONE_OUTER_ANGLE:
1284 case AL_LOOPING:
1285 case AL_BUFFER:
1286 case AL_SOURCE_STATE:
1287 case AL_BUFFERS_QUEUED:
1288 case AL_BUFFERS_PROCESSED:
1289 case AL_SEC_OFFSET:
1290 case AL_SAMPLE_OFFSET:
1291 case AL_BYTE_OFFSET:
1292 case AL_MAX_DISTANCE:
1293 case AL_ROLLOFF_FACTOR:
1294 case AL_REFERENCE_DISTANCE:
1295 case AL_SOURCE_TYPE:
1296 case AL_DIRECT_FILTER:
1297 case AL_DIRECT_FILTER_GAINHF_AUTO:
1298 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1299 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1300 alGetSourcei(source, eParam, plValues);
1301 break;
1303 case AL_POSITION:
1304 plValues[0] = (ALint)pSource->vPosition[0];
1305 plValues[1] = (ALint)pSource->vPosition[1];
1306 plValues[2] = (ALint)pSource->vPosition[2];
1307 break;
1309 case AL_VELOCITY:
1310 plValues[0] = (ALint)pSource->vVelocity[0];
1311 plValues[1] = (ALint)pSource->vVelocity[1];
1312 plValues[2] = (ALint)pSource->vVelocity[2];
1313 break;
1315 case AL_DIRECTION:
1316 plValues[0] = (ALint)pSource->vOrientation[0];
1317 plValues[1] = (ALint)pSource->vOrientation[1];
1318 plValues[2] = (ALint)pSource->vOrientation[2];
1319 break;
1321 default:
1322 alSetError(AL_INVALID_ENUM);
1323 break;
1326 else
1327 alSetError(AL_INVALID_NAME);
1329 else
1330 alSetError(AL_INVALID_VALUE);
1332 ProcessContext(pContext);
1334 else
1335 alSetError(AL_INVALID_OPERATION);
1337 return;
1341 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1343 alSourcePlayv(1, &source);
1344 return;
1347 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1349 ALCcontext *pContext;
1350 ALsource *pSource;
1351 ALbufferlistitem *ALBufferList;
1352 ALboolean bSourcesValid = AL_TRUE;
1353 ALboolean bPlay;
1354 ALsizei i;
1356 pContext = alcGetCurrentContext();
1357 if (pContext)
1359 SuspendContext(pContext);
1361 if (pSourceList)
1363 // Check that all the Sources are valid
1364 for (i = 0; i < n; i++)
1366 if (!alIsSource(pSourceList[i]))
1368 alSetError(AL_INVALID_NAME);
1369 bSourcesValid = AL_FALSE;
1370 break;
1374 if (bSourcesValid)
1376 for (i = 0; i < n; i++)
1378 // Assume Source won't need to play
1379 bPlay = AL_FALSE;
1381 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1383 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1384 ALBufferList = pSource->queue;
1385 while (ALBufferList)
1387 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1389 bPlay = AL_TRUE;
1390 break;
1392 ALBufferList = ALBufferList->next;
1395 if (bPlay)
1397 if (pSource->state != AL_PAUSED)
1399 pSource->state = AL_PLAYING;
1400 pSource->inuse = AL_TRUE;
1401 pSource->play = AL_TRUE;
1402 pSource->position = 0;
1403 pSource->position_fraction = 0;
1404 pSource->BuffersProcessed = 0;
1405 pSource->BuffersPlayed = 0;
1406 pSource->BufferPosition = 0;
1407 pSource->lBytesPlayed = 0;
1409 pSource->ulBufferID = pSource->queue->buffer;
1411 // Make sure all the Buffers in the queue are marked as PENDING
1412 ALBufferList = pSource->queue;
1413 while (ALBufferList)
1415 ALBufferList->bufferstate = PENDING;
1416 ALBufferList = ALBufferList->next;
1419 else
1421 pSource->state = AL_PLAYING;
1422 pSource->inuse = AL_TRUE;
1423 pSource->play = AL_TRUE;
1426 // Check if an Offset has been set
1427 if (pSource->lOffset)
1428 ApplyOffset(pSource, AL_FALSE);
1430 else
1432 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1433 ALBufferList = pSource->queue;
1434 while (ALBufferList)
1436 ALBufferList->bufferstate = PROCESSED;
1437 ALBufferList = ALBufferList->next;
1440 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1445 else
1447 // sources is a NULL pointer
1448 alSetError(AL_INVALID_VALUE);
1451 ProcessContext(pContext);
1453 else
1455 // Invalid Context
1456 alSetError(AL_INVALID_OPERATION);
1459 return;
1462 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1464 alSourcePausev(1, &source);
1465 return;
1468 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1470 ALCcontext *Context;
1471 ALsource *Source;
1472 ALsizei i;
1473 ALboolean bSourcesValid = AL_TRUE;
1475 Context=alcGetCurrentContext();
1476 if (Context)
1478 SuspendContext(Context);
1480 if (sources)
1482 // Check all the Sources are valid
1483 for (i=0;i<n;i++)
1485 if (!alIsSource(sources[i]))
1487 alSetError(AL_INVALID_NAME);
1488 bSourcesValid = AL_FALSE;
1489 break;
1493 if (bSourcesValid)
1495 for (i=0;i<n;i++)
1497 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1498 if (Source->state==AL_PLAYING)
1500 Source->state=AL_PAUSED;
1501 Source->inuse=AL_FALSE;
1506 else
1508 // sources is a NULL pointer
1509 alSetError(AL_INVALID_VALUE);
1512 ProcessContext(Context);
1514 else
1516 // Invalid Context
1517 alSetError(AL_INVALID_OPERATION);
1520 return;
1523 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1525 alSourceStopv(1, &source);
1526 return;
1529 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1531 ALCcontext *Context;
1532 ALsource *Source;
1533 ALsizei i;
1534 ALbufferlistitem *ALBufferListItem;
1535 ALboolean bSourcesValid = AL_TRUE;
1537 Context=alcGetCurrentContext();
1538 if (Context)
1540 SuspendContext(Context);
1542 if (sources)
1544 // Check all the Sources are valid
1545 for (i=0;i<n;i++)
1547 if (!alIsSource(sources[i]))
1549 alSetError(AL_INVALID_NAME);
1550 bSourcesValid = AL_FALSE;
1551 break;
1555 if (bSourcesValid)
1557 for (i=0;i<n;i++)
1559 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1560 if (Source->state!=AL_INITIAL)
1562 Source->state=AL_STOPPED;
1563 Source->inuse=AL_FALSE;
1564 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1565 ALBufferListItem= Source->queue;
1566 while (ALBufferListItem != NULL)
1568 ALBufferListItem->bufferstate = PROCESSED;
1569 ALBufferListItem = ALBufferListItem->next;
1572 Source->lOffset = 0;
1576 else
1578 // sources is a NULL pointer
1579 alSetError(AL_INVALID_VALUE);
1582 ProcessContext(Context);
1584 else
1586 // Invalid Context
1587 alSetError(AL_INVALID_OPERATION);
1590 return;
1593 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1595 alSourceRewindv(1, &source);
1596 return;
1599 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1601 ALCcontext *Context;
1602 ALsource *Source;
1603 ALsizei i;
1604 ALbufferlistitem *ALBufferListItem;
1605 ALboolean bSourcesValid = AL_TRUE;
1607 Context=alcGetCurrentContext();
1608 if (Context)
1610 SuspendContext(Context);
1612 if (sources)
1614 // Check all the Sources are valid
1615 for (i=0;i<n;i++)
1617 if (!alIsSource(sources[i]))
1619 alSetError(AL_INVALID_NAME);
1620 bSourcesValid = AL_FALSE;
1621 break;
1625 if (bSourcesValid)
1627 for (i=0;i<n;i++)
1629 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1630 if (Source->state!=AL_INITIAL)
1632 Source->state=AL_INITIAL;
1633 Source->inuse=AL_FALSE;
1634 Source->position=0;
1635 Source->position_fraction=0;
1636 Source->BuffersProcessed = 0;
1637 ALBufferListItem= Source->queue;
1638 while (ALBufferListItem != NULL)
1640 ALBufferListItem->bufferstate = PENDING;
1641 ALBufferListItem = ALBufferListItem->next;
1643 if (Source->queue)
1644 Source->ulBufferID = Source->queue->buffer;
1646 Source->lOffset = 0;
1650 else
1652 // sources is a NULL pointer
1653 alSetError(AL_INVALID_VALUE);
1656 ProcessContext(Context);
1658 else
1660 // Invalid Context
1661 alSetError(AL_INVALID_OPERATION);
1664 return;
1668 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1670 ALCcontext *Context;
1671 ALsource *ALSource;
1672 ALsizei i;
1673 ALbufferlistitem *ALBufferList;
1674 ALbufferlistitem *ALBufferListStart;
1675 ALuint DataSize;
1676 ALuint BufferSize;
1677 ALint iFrequency;
1678 ALint iFormat;
1679 ALboolean bBuffersValid = AL_TRUE;
1681 if (n == 0)
1682 return;
1684 Context=alcGetCurrentContext();
1685 if (Context)
1687 SuspendContext(Context);
1689 DataSize = 0;
1690 BufferSize = 0;
1692 // Check that all buffers are valid or zero and that the source is valid
1694 // Check that this is a valid source
1695 if (alIsSource(source))
1697 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1699 // Check that this is not a STATIC Source
1700 if (ALSource->lSourceType != AL_STATIC)
1702 iFrequency = -1;
1703 iFormat = -1;
1705 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1706 ALBufferList = ALSource->queue;
1707 while (ALBufferList)
1709 if (ALBufferList->buffer)
1711 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1712 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1713 break;
1715 ALBufferList = ALBufferList->next;
1718 for (i = 0; i < n; i++)
1720 if (alIsBuffer(buffers[i]))
1722 if (buffers[i])
1724 if ((iFrequency == -1) && (iFormat == -1))
1726 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1727 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1729 else
1731 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1732 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1734 alSetError(AL_INVALID_OPERATION);
1735 bBuffersValid = AL_FALSE;
1736 break;
1741 else
1743 alSetError(AL_INVALID_NAME);
1744 bBuffersValid = AL_FALSE;
1745 break;
1749 if (bBuffersValid)
1751 // Change Source Type
1752 ALSource->lSourceType = AL_STREAMING;
1754 // All buffers are valid - so add them to the list
1755 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1756 ALBufferListStart->buffer = buffers[0];
1757 ALBufferListStart->bufferstate = PENDING;
1758 ALBufferListStart->flag = 0;
1759 ALBufferListStart->next = NULL;
1761 if (buffers[0])
1762 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1763 else
1764 BufferSize = 0;
1766 DataSize += BufferSize;
1768 // Increment reference counter for buffer
1769 if (buffers[0])
1770 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1772 ALBufferList = ALBufferListStart;
1774 for (i = 1; i < n; i++)
1776 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1777 ALBufferList->next->buffer = buffers[i];
1778 ALBufferList->next->bufferstate = PENDING;
1779 ALBufferList->next->flag = 0;
1780 ALBufferList->next->next = NULL;
1782 if (buffers[i])
1783 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1784 else
1785 BufferSize = 0;
1787 DataSize += BufferSize;
1789 // Increment reference counter for buffer
1790 if (buffers[i])
1791 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1793 ALBufferList = ALBufferList->next;
1796 if (ALSource->queue == NULL)
1798 ALSource->queue = ALBufferListStart;
1799 // Update Current Buffer
1800 ALSource->ulBufferID = ALBufferListStart->buffer;
1802 else
1804 // Find end of queue
1805 ALBufferList = ALSource->queue;
1806 while (ALBufferList->next != NULL)
1808 ALBufferList = ALBufferList->next;
1811 ALBufferList->next = ALBufferListStart;
1814 // Update number of buffers in queue
1815 ALSource->BuffersInQueue += n;
1818 else
1820 // Invalid Source Type (can't queue on a Static Source)
1821 alSetError(AL_INVALID_OPERATION);
1824 else
1826 // Invalid Source Name
1827 alSetError(AL_INVALID_NAME);
1830 ProcessContext(Context);
1832 else
1834 // Invalid Context
1835 alSetError(AL_INVALID_OPERATION);
1838 return;
1842 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1843 // an array of buffer IDs that are to be filled with the names of the buffers removed
1844 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1846 ALCcontext *Context;
1847 ALsource *ALSource;
1848 ALsizei i;
1849 ALbufferlistitem *ALBufferList;
1850 ALuint DataSize;
1851 ALuint BufferSize;
1852 ALuint BufferID;
1853 ALboolean bBuffersProcessed;
1855 if (n == 0)
1856 return;
1858 DataSize = 0;
1859 BufferSize = 0;
1860 bBuffersProcessed = AL_TRUE;
1862 Context=alcGetCurrentContext();
1863 if (Context)
1865 SuspendContext(Context);
1867 if (alIsSource(source))
1869 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1871 // Check that all 'n' buffers have been processed
1872 ALBufferList = ALSource->queue;
1873 for (i = 0; i < n; i++)
1875 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1877 ALBufferList = ALBufferList->next;
1879 else
1881 bBuffersProcessed = AL_FALSE;
1882 break;
1886 // If all 'n' buffers have been processed, remove them from the queue
1887 if (bBuffersProcessed)
1889 for (i = 0; i < n; i++)
1891 ALBufferList = ALSource->queue;
1893 ALSource->queue = ALBufferList->next;
1894 // Record name of buffer
1895 buffers[i] = ALBufferList->buffer;
1896 // Decrement buffer reference counter
1897 if (ALBufferList->buffer)
1898 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1899 // Record size of buffer
1900 if (ALBufferList->buffer)
1901 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1902 else
1903 BufferSize = 0;
1905 DataSize += BufferSize;
1906 // Release memory for buffer list item
1907 free(ALBufferList);
1908 ALSource->BuffersInQueue--;
1909 ALSource->BuffersProcessed--;
1912 if (ALSource->state != AL_PLAYING)
1914 if (ALSource->queue)
1915 BufferID = ALSource->queue->buffer;
1916 else
1917 BufferID = 0;
1919 ALSource->ulBufferID = BufferID;
1922 if((ALuint)n > ALSource->BuffersPlayed)
1924 ALSource->BuffersPlayed = 0;
1925 ALSource->BufferPosition = 0;
1927 else
1928 ALSource->BuffersPlayed -= n;
1930 else
1932 // Some buffers can't be unqueue because they have not been processed
1933 alSetError(AL_INVALID_VALUE);
1936 else
1938 // Invalid Source Name
1939 alSetError(AL_INVALID_NAME);
1942 ProcessContext(Context);
1944 else
1946 // Invalid Context
1947 alSetError(AL_INVALID_OPERATION);
1950 return;
1954 static ALvoid InitSourceParams(ALsource *pSource)
1956 pSource->flInnerAngle = 360.0f;
1957 pSource->flOuterAngle = 360.0f;
1958 pSource->flPitch = 1.0f;
1959 pSource->vPosition[0] = 0.0f;
1960 pSource->vPosition[1] = 0.0f;
1961 pSource->vPosition[2] = 0.0f;
1962 pSource->vOrientation[0] = 0.0f;
1963 pSource->vOrientation[1] = 0.0f;
1964 pSource->vOrientation[2] = 0.0f;
1965 pSource->vVelocity[0] = 0.0f;
1966 pSource->vVelocity[1] = 0.0f;
1967 pSource->vVelocity[2] = 0.0f;
1968 pSource->flRefDistance = 1.0f;
1969 pSource->flMaxDistance = FLT_MAX;
1970 pSource->flRollOffFactor = 1.0f;
1971 pSource->bLooping = AL_FALSE;
1972 pSource->flGain = 1.0f;
1973 pSource->flMinGain = 0.0f;
1974 pSource->flMaxGain = 1.0f;
1975 pSource->flOuterGain = 0.0f;
1976 pSource->OuterGainHF = 1.0f;
1978 pSource->DryGainHFAuto = AL_TRUE;
1979 pSource->WetGainAuto = AL_TRUE;
1980 pSource->WetGainHFAuto = AL_TRUE;
1981 pSource->AirAbsorptionFactor = 0.0f;
1982 pSource->RoomRolloffFactor = 0.0f;
1984 pSource->state = AL_INITIAL;
1985 pSource->lSourceType = AL_UNDETERMINED;
1987 pSource->ulBufferID= 0;
1992 GetSourceOffset
1994 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1995 The offset is relative to the start of the queue (not the start of the current buffer)
1997 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1999 ALbufferlistitem *pBufferList;
2000 ALbuffer *pBuffer;
2001 ALfloat flBufferFreq;
2002 ALint lBytesPlayed, lChannels;
2003 ALenum eOriginalFormat;
2004 ALboolean bReturn = AL_TRUE;
2005 ALint lTotalBufferDataSize;
2007 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2009 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2010 // Get Current Buffer Size and frequency (in milliseconds)
2011 flBufferFreq = (ALfloat)pBuffer->frequency;
2012 eOriginalFormat = pBuffer->eOriginalFormat;
2013 lChannels = aluChannelsFromFormat(pBuffer->format);
2015 // Get Current BytesPlayed
2016 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2017 // Add byte length of any processed buffers in the queue
2018 pBufferList = pSource->queue;
2019 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2021 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2022 pBufferList = pBufferList->next;
2025 lTotalBufferDataSize = 0;
2026 pBufferList = pSource->queue;
2027 while (pBufferList)
2029 if (pBufferList->buffer)
2030 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2031 pBufferList = pBufferList->next;
2034 if (pSource->bLooping)
2036 if (lBytesPlayed < 0)
2037 lBytesPlayed = 0;
2038 else
2039 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2041 else
2043 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2044 if(lBytesPlayed < 0)
2045 lBytesPlayed = 0;
2046 if(lBytesPlayed > lTotalBufferDataSize)
2047 lBytesPlayed = lTotalBufferDataSize;
2050 switch (eName)
2052 case AL_SEC_OFFSET:
2053 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2054 break;
2055 case AL_SAMPLE_OFFSET:
2056 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2057 break;
2058 case AL_BYTE_OFFSET:
2059 // Take into account the original format of the Buffer
2060 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2061 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2063 // Compression rate of the ADPCM supported is 3.6111 to 1
2064 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2065 // Round down to nearest ADPCM block
2066 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2068 else if (eOriginalFormat == AL_FORMAT_REAR8)
2070 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2072 else if (eOriginalFormat == AL_FORMAT_REAR16)
2074 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2076 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2078 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2080 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2082 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2084 else
2086 *pflOffset = (ALfloat)lBytesPlayed;
2088 break;
2091 else
2093 *pflOffset = 0.0f;
2096 return bReturn;
2101 ApplyOffset
2103 Apply a playback offset to the Source. This function will update the queue (to correctly
2104 mark buffers as 'pending' or 'processed' depending upon the new offset.
2106 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2108 ALbufferlistitem *pBufferList;
2109 ALbuffer *pBuffer;
2110 ALint lBufferSize, lTotalBufferSize;
2111 ALint lByteOffset;
2113 // Get true byte offset
2114 lByteOffset = GetByteOffset(pSource);
2116 // If this is a valid offset apply it
2117 if (lByteOffset != -1)
2119 // Sort out the queue (pending and processed states)
2120 pBufferList = pSource->queue;
2121 lTotalBufferSize = 0;
2122 pSource->BuffersPlayed = 0;
2123 pSource->BuffersProcessed = 0;
2124 while (pBufferList)
2126 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2127 lBufferSize = pBuffer ? pBuffer->size : 0;
2129 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2131 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2132 // update the state to PROCESSED
2133 pSource->BuffersPlayed++;
2135 if (!pSource->bLooping)
2137 pBufferList->bufferstate = PROCESSED;
2138 pSource->BuffersProcessed++;
2141 else if (lTotalBufferSize <= lByteOffset)
2143 // Offset is within this buffer
2144 pBufferList->bufferstate = PENDING;
2146 // Set Current Buffer ID
2147 pSource->ulBufferID = pBufferList->buffer;
2149 // Set current position in this buffer
2150 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2152 // Set Total Bytes Played to Offset
2153 pSource->lBytesPlayed = lByteOffset;
2155 // SW Mixer Positions are in Samples
2156 pSource->position = pSource->BufferPosition /
2157 aluBytesFromFormat(pBuffer->format) /
2158 aluChannelsFromFormat(pBuffer->format);
2160 else
2162 // Offset is before this buffer, so mark as pending
2163 pBufferList->bufferstate = PENDING;
2166 // Increment the TotalBufferSize
2167 lTotalBufferSize += lBufferSize;
2169 // Move on to next buffer in the Queue
2170 pBufferList = pBufferList->next;
2173 else
2175 if (bUpdateContext)
2176 alSetError(AL_INVALID_VALUE);
2179 // Clear Offset
2180 pSource->lOffset = 0;
2185 GetByteOffset
2187 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2188 offset supplied by the application). This takes into account the fact that the buffer format
2189 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2191 static ALint GetByteOffset(ALsource *pSource)
2193 ALbuffer *pBuffer = NULL;
2194 ALbufferlistitem *pBufferList;
2195 ALfloat flBufferFreq;
2196 ALint lChannels;
2197 ALint lByteOffset = -1;
2198 ALint lTotalBufferDataSize;
2200 // Find the first non-NULL Buffer in the Queue
2201 pBufferList = pSource->queue;
2202 while (pBufferList)
2204 if (pBufferList->buffer)
2206 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2207 break;
2209 pBufferList = pBufferList->next;
2212 if (pBuffer)
2214 flBufferFreq = ((ALfloat)pBuffer->frequency);
2215 lChannels = aluChannelsFromFormat(pBuffer->format);
2217 // Determine the ByteOffset (and ensure it is block aligned)
2218 switch (pSource->lOffsetType)
2220 case AL_BYTE_OFFSET:
2221 // Take into consideration the original format
2222 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2223 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2225 // Round down to nearest ADPCM block
2226 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2227 // Multiply by compression rate
2228 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2229 lByteOffset -= (lByteOffset % (lChannels * 2));
2231 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2233 lByteOffset = pSource->lOffset * 4;
2234 lByteOffset -= (lByteOffset % (lChannels * 2));
2236 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2238 lByteOffset = pSource->lOffset * 2;
2239 lByteOffset -= (lByteOffset % (lChannels * 2));
2241 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2243 lByteOffset = pSource->lOffset * 2;
2244 lByteOffset -= (lByteOffset % (lChannels * 2));
2246 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2248 lByteOffset = pSource->lOffset / 2;
2249 lByteOffset -= (lByteOffset % (lChannels * 2));
2251 else
2253 lByteOffset = pSource->lOffset;
2254 lByteOffset -= (lByteOffset % (lChannels * 2));
2256 break;
2258 case AL_SAMPLE_OFFSET:
2259 lByteOffset = pSource->lOffset * lChannels * 2;
2260 break;
2262 case AL_SEC_OFFSET:
2263 // Note - lOffset is internally stored as Milliseconds
2264 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2265 lByteOffset -= (lByteOffset % (lChannels * 2));
2266 break;
2269 lTotalBufferDataSize = 0;
2270 pBufferList = pSource->queue;
2271 while (pBufferList)
2273 if (pBufferList->buffer)
2274 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2275 pBufferList = pBufferList->next;
2278 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2279 if (lByteOffset >= lTotalBufferDataSize)
2280 lByteOffset = -1;
2283 return lByteOffset;
2287 ALvoid ReleaseALSources(ALCcontext *Context)
2289 #ifdef _DEBUG
2290 if(Context->SourceCount > 0)
2291 AL_PRINT("destroycontext: %d Source(s) NOT deleted\n", Context->SourceCount);
2292 #endif
2294 while(Context->Source)
2296 ALsource *temp = Context->Source;
2297 Context->Source = Context->Source->next;
2299 // Release source structure
2300 memset(temp, 0, sizeof(ALsource));
2301 free(temp);
2303 Context->SourceCount = 0;