Store a reference to the effect slot in a source's send, not a copy
[openal-soft.git] / OpenAL32 / alSource.c
blob69da0df42ecc33be834a3241aa07cd62482d9d3c
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 pSource->Send[lValue2].Slot = ALEffectSlot;
750 if(!ALFilter)
752 /* Disable filter */
753 pSource->Send[lValue2].WetFilter.type = 0;
754 pSource->Send[lValue2].WetFilter.filter = 0;
756 else
757 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
759 else
760 alSetError(AL_INVALID_VALUE);
761 break;
763 default:
764 alSetError(AL_INVALID_ENUM);
765 break;
768 else
769 alSetError(AL_INVALID_NAME);
771 ProcessContext(pContext);
773 else
774 alSetError(AL_INVALID_OPERATION);
776 return;
780 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
782 ALCcontext *pContext;
784 pContext = alcGetCurrentContext();
785 if (pContext)
787 SuspendContext(pContext);
789 if (plValues)
791 if (alIsSource(source))
793 switch (eParam)
795 case AL_SOURCE_RELATIVE:
796 case AL_CONE_INNER_ANGLE:
797 case AL_CONE_OUTER_ANGLE:
798 case AL_LOOPING:
799 case AL_BUFFER:
800 case AL_SOURCE_STATE:
801 case AL_SEC_OFFSET:
802 case AL_SAMPLE_OFFSET:
803 case AL_BYTE_OFFSET:
804 case AL_MAX_DISTANCE:
805 case AL_ROLLOFF_FACTOR:
806 case AL_REFERENCE_DISTANCE:
807 case AL_DIRECT_FILTER:
808 case AL_DIRECT_FILTER_GAINHF_AUTO:
809 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
810 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
811 alSourcei(source, eParam, plValues[0]);
812 break;
814 case AL_POSITION:
815 case AL_VELOCITY:
816 case AL_DIRECTION:
817 case AL_AUXILIARY_SEND_FILTER:
818 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
819 break;
821 default:
822 alSetError(AL_INVALID_ENUM);
823 break;
826 else
827 alSetError(AL_INVALID_NAME);
829 else
830 alSetError(AL_INVALID_VALUE);
832 ProcessContext(pContext);
834 else
835 alSetError(AL_INVALID_OPERATION);
837 return;
841 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
843 ALCcontext *pContext;
844 ALsource *pSource;
845 ALfloat flOffset;
847 pContext = alcGetCurrentContext();
848 if (pContext)
850 SuspendContext(pContext);
852 if (pflValue)
854 if (alIsSource(source))
856 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
858 switch(eParam)
860 case AL_PITCH:
861 *pflValue = pSource->flPitch;
862 break;
864 case AL_GAIN:
865 *pflValue = pSource->flGain;
866 break;
868 case AL_MIN_GAIN:
869 *pflValue = pSource->flMinGain;
870 break;
872 case AL_MAX_GAIN:
873 *pflValue = pSource->flMaxGain;
874 break;
876 case AL_MAX_DISTANCE:
877 *pflValue = pSource->flMaxDistance;
878 break;
880 case AL_ROLLOFF_FACTOR:
881 *pflValue = pSource->flRollOffFactor;
882 break;
884 case AL_CONE_OUTER_GAIN:
885 *pflValue = pSource->flOuterGain;
886 break;
888 case AL_CONE_OUTER_GAINHF:
889 *pflValue = pSource->OuterGainHF;
890 break;
892 case AL_SEC_OFFSET:
893 case AL_SAMPLE_OFFSET:
894 case AL_BYTE_OFFSET:
895 if (GetSourceOffset(pSource, eParam, &flOffset))
896 *pflValue = flOffset;
897 else
898 alSetError(AL_INVALID_OPERATION);
899 break;
901 case AL_CONE_INNER_ANGLE:
902 *pflValue = pSource->flInnerAngle;
903 break;
905 case AL_CONE_OUTER_ANGLE:
906 *pflValue = pSource->flOuterAngle;
907 break;
909 case AL_REFERENCE_DISTANCE:
910 *pflValue = pSource->flRefDistance;
911 break;
913 case AL_AIR_ABSORPTION_FACTOR:
914 *pflValue = pSource->AirAbsorptionFactor;
915 break;
917 case AL_ROOM_ROLLOFF_FACTOR:
918 *pflValue = pSource->RoomRolloffFactor;
919 break;
921 default:
922 alSetError(AL_INVALID_ENUM);
923 break;
926 else
927 alSetError(AL_INVALID_NAME);
929 else
930 alSetError(AL_INVALID_VALUE);
932 ProcessContext(pContext);
934 else
935 alSetError(AL_INVALID_OPERATION);
937 return;
941 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
943 ALCcontext *pContext;
944 ALsource *pSource;
946 pContext = alcGetCurrentContext();
947 if (pContext)
949 SuspendContext(pContext);
951 if ((pflValue1) && (pflValue2) && (pflValue3))
953 if (alIsSource(source))
955 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
957 switch(eParam)
959 case AL_POSITION:
960 *pflValue1 = pSource->vPosition[0];
961 *pflValue2 = pSource->vPosition[1];
962 *pflValue3 = pSource->vPosition[2];
963 break;
965 case AL_VELOCITY:
966 *pflValue1 = pSource->vVelocity[0];
967 *pflValue2 = pSource->vVelocity[1];
968 *pflValue3 = pSource->vVelocity[2];
969 break;
971 case AL_DIRECTION:
972 *pflValue1 = pSource->vOrientation[0];
973 *pflValue2 = pSource->vOrientation[1];
974 *pflValue3 = pSource->vOrientation[2];
975 break;
977 default:
978 alSetError(AL_INVALID_ENUM);
979 break;
982 else
983 alSetError(AL_INVALID_NAME);
985 else
986 alSetError(AL_INVALID_VALUE);
988 ProcessContext(pContext);
990 else
991 alSetError(AL_INVALID_OPERATION);
993 return;
997 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
999 ALCcontext *pContext;
1000 ALsource *pSource;
1002 pContext = alcGetCurrentContext();
1003 if (pContext)
1005 SuspendContext(pContext);
1007 if (pflValues)
1009 if (alIsSource(source))
1011 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1013 switch(eParam)
1015 case AL_PITCH:
1016 case AL_GAIN:
1017 case AL_MIN_GAIN:
1018 case AL_MAX_GAIN:
1019 case AL_MAX_DISTANCE:
1020 case AL_ROLLOFF_FACTOR:
1021 case AL_CONE_OUTER_GAIN:
1022 case AL_SEC_OFFSET:
1023 case AL_SAMPLE_OFFSET:
1024 case AL_BYTE_OFFSET:
1025 case AL_CONE_INNER_ANGLE:
1026 case AL_CONE_OUTER_ANGLE:
1027 case AL_REFERENCE_DISTANCE:
1028 case AL_CONE_OUTER_GAINHF:
1029 case AL_AIR_ABSORPTION_FACTOR:
1030 case AL_ROOM_ROLLOFF_FACTOR:
1031 alGetSourcef(source, eParam, pflValues);
1032 break;
1034 case AL_POSITION:
1035 pflValues[0] = pSource->vPosition[0];
1036 pflValues[1] = pSource->vPosition[1];
1037 pflValues[2] = pSource->vPosition[2];
1038 break;
1040 case AL_VELOCITY:
1041 pflValues[0] = pSource->vVelocity[0];
1042 pflValues[1] = pSource->vVelocity[1];
1043 pflValues[2] = pSource->vVelocity[2];
1044 break;
1046 case AL_DIRECTION:
1047 pflValues[0] = pSource->vOrientation[0];
1048 pflValues[1] = pSource->vOrientation[1];
1049 pflValues[2] = pSource->vOrientation[2];
1050 break;
1052 default:
1053 alSetError(AL_INVALID_ENUM);
1054 break;
1057 else
1058 alSetError(AL_INVALID_NAME);
1060 else
1061 alSetError(AL_INVALID_VALUE);
1063 ProcessContext(pContext);
1065 else
1066 alSetError(AL_INVALID_OPERATION);
1068 return;
1072 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1074 ALCcontext *pContext;
1075 ALsource *pSource;
1076 ALfloat flOffset;
1078 pContext = alcGetCurrentContext();
1079 if (pContext)
1081 SuspendContext(pContext);
1083 if (plValue)
1085 if (alIsSource(source))
1087 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1089 switch(eParam)
1091 case AL_MAX_DISTANCE:
1092 *plValue = (ALint)pSource->flMaxDistance;
1093 break;
1095 case AL_ROLLOFF_FACTOR:
1096 *plValue = (ALint)pSource->flRollOffFactor;
1097 break;
1099 case AL_REFERENCE_DISTANCE:
1100 *plValue = (ALint)pSource->flRefDistance;
1101 break;
1103 case AL_SOURCE_RELATIVE:
1104 *plValue = pSource->bHeadRelative;
1105 break;
1107 case AL_CONE_INNER_ANGLE:
1108 *plValue = (ALint)pSource->flInnerAngle;
1109 break;
1111 case AL_CONE_OUTER_ANGLE:
1112 *plValue = (ALint)pSource->flOuterAngle;
1113 break;
1115 case AL_LOOPING:
1116 *plValue = pSource->bLooping;
1117 break;
1119 case AL_BUFFER:
1120 *plValue = pSource->ulBufferID;
1121 break;
1123 case AL_SOURCE_STATE:
1124 *plValue = pSource->state;
1125 break;
1127 case AL_BUFFERS_QUEUED:
1128 *plValue = pSource->BuffersInQueue;
1129 break;
1131 case AL_BUFFERS_PROCESSED:
1132 if(pSource->bLooping)
1134 /* Buffers on a looping source are in a perpetual state
1135 * of PENDING, so don't report any as PROCESSED */
1136 *plValue = 0;
1138 else
1139 *plValue = pSource->BuffersProcessed;
1140 break;
1142 case AL_SOURCE_TYPE:
1143 *plValue = pSource->lSourceType;
1144 break;
1146 case AL_SEC_OFFSET:
1147 case AL_SAMPLE_OFFSET:
1148 case AL_BYTE_OFFSET:
1149 if (GetSourceOffset(pSource, eParam, &flOffset))
1150 *plValue = (ALint)flOffset;
1151 else
1152 alSetError(AL_INVALID_OPERATION);
1153 break;
1155 case AL_DIRECT_FILTER:
1156 *plValue = pSource->DirectFilter.filter;
1157 break;
1159 case AL_DIRECT_FILTER_GAINHF_AUTO:
1160 *plValue = pSource->DryGainHFAuto;
1161 break;
1163 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1164 *plValue = pSource->WetGainAuto;
1165 break;
1167 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1168 *plValue = pSource->WetGainHFAuto;
1169 break;
1171 default:
1172 alSetError(AL_INVALID_ENUM);
1173 break;
1176 else
1177 alSetError(AL_INVALID_NAME);
1179 else
1180 alSetError(AL_INVALID_VALUE);
1182 ProcessContext(pContext);
1184 else
1185 alSetError(AL_INVALID_OPERATION);
1187 return;
1191 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1193 ALCcontext *pContext;
1194 ALsource *pSource;
1196 pContext = alcGetCurrentContext();
1197 if (pContext)
1199 SuspendContext(pContext);
1201 if ((plValue1) && (plValue2) && (plValue3))
1203 if (alIsSource(source))
1205 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1207 switch(eParam)
1209 case AL_POSITION:
1210 *plValue1 = (ALint)pSource->vPosition[0];
1211 *plValue2 = (ALint)pSource->vPosition[1];
1212 *plValue3 = (ALint)pSource->vPosition[2];
1213 break;
1215 case AL_VELOCITY:
1216 *plValue1 = (ALint)pSource->vVelocity[0];
1217 *plValue2 = (ALint)pSource->vVelocity[1];
1218 *plValue3 = (ALint)pSource->vVelocity[2];
1219 break;
1221 case AL_DIRECTION:
1222 *plValue1 = (ALint)pSource->vOrientation[0];
1223 *plValue2 = (ALint)pSource->vOrientation[1];
1224 *plValue3 = (ALint)pSource->vOrientation[2];
1225 break;
1227 default:
1228 alSetError(AL_INVALID_ENUM);
1229 break;
1232 else
1233 alSetError(AL_INVALID_NAME);
1235 else
1236 alSetError(AL_INVALID_VALUE);
1238 ProcessContext(pContext);
1240 else
1241 alSetError(AL_INVALID_OPERATION);
1243 return;
1247 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1249 ALCcontext *pContext;
1250 ALsource *pSource;
1252 pContext = alcGetCurrentContext();
1253 if (pContext)
1255 SuspendContext(pContext);
1257 if (plValues)
1259 if (alIsSource(source))
1261 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1263 switch (eParam)
1265 case AL_SOURCE_RELATIVE:
1266 case AL_CONE_INNER_ANGLE:
1267 case AL_CONE_OUTER_ANGLE:
1268 case AL_LOOPING:
1269 case AL_BUFFER:
1270 case AL_SOURCE_STATE:
1271 case AL_BUFFERS_QUEUED:
1272 case AL_BUFFERS_PROCESSED:
1273 case AL_SEC_OFFSET:
1274 case AL_SAMPLE_OFFSET:
1275 case AL_BYTE_OFFSET:
1276 case AL_MAX_DISTANCE:
1277 case AL_ROLLOFF_FACTOR:
1278 case AL_REFERENCE_DISTANCE:
1279 case AL_SOURCE_TYPE:
1280 case AL_DIRECT_FILTER:
1281 case AL_DIRECT_FILTER_GAINHF_AUTO:
1282 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1283 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1284 alGetSourcei(source, eParam, plValues);
1285 break;
1287 case AL_POSITION:
1288 plValues[0] = (ALint)pSource->vPosition[0];
1289 plValues[1] = (ALint)pSource->vPosition[1];
1290 plValues[2] = (ALint)pSource->vPosition[2];
1291 break;
1293 case AL_VELOCITY:
1294 plValues[0] = (ALint)pSource->vVelocity[0];
1295 plValues[1] = (ALint)pSource->vVelocity[1];
1296 plValues[2] = (ALint)pSource->vVelocity[2];
1297 break;
1299 case AL_DIRECTION:
1300 plValues[0] = (ALint)pSource->vOrientation[0];
1301 plValues[1] = (ALint)pSource->vOrientation[1];
1302 plValues[2] = (ALint)pSource->vOrientation[2];
1303 break;
1305 default:
1306 alSetError(AL_INVALID_ENUM);
1307 break;
1310 else
1311 alSetError(AL_INVALID_NAME);
1313 else
1314 alSetError(AL_INVALID_VALUE);
1316 ProcessContext(pContext);
1318 else
1319 alSetError(AL_INVALID_OPERATION);
1321 return;
1325 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1327 alSourcePlayv(1, &source);
1328 return;
1331 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1333 ALCcontext *pContext;
1334 ALsource *pSource;
1335 ALbufferlistitem *ALBufferList;
1336 ALboolean bSourcesValid = AL_TRUE;
1337 ALboolean bPlay;
1338 ALsizei i;
1340 pContext = alcGetCurrentContext();
1341 if (pContext)
1343 SuspendContext(pContext);
1345 if (pSourceList)
1347 // Check that all the Sources are valid
1348 for (i = 0; i < n; i++)
1350 if (!alIsSource(pSourceList[i]))
1352 alSetError(AL_INVALID_NAME);
1353 bSourcesValid = AL_FALSE;
1354 break;
1358 if (bSourcesValid)
1360 for (i = 0; i < n; i++)
1362 // Assume Source won't need to play
1363 bPlay = AL_FALSE;
1365 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1367 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1368 ALBufferList = pSource->queue;
1369 while (ALBufferList)
1371 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1373 bPlay = AL_TRUE;
1374 break;
1376 ALBufferList = ALBufferList->next;
1379 if (bPlay)
1381 if (pSource->state != AL_PAUSED)
1383 pSource->state = AL_PLAYING;
1384 pSource->inuse = AL_TRUE;
1385 pSource->play = AL_TRUE;
1386 pSource->position = 0;
1387 pSource->position_fraction = 0;
1388 pSource->BuffersProcessed = 0;
1389 pSource->BuffersPlayed = 0;
1390 pSource->BufferPosition = 0;
1391 pSource->lBytesPlayed = 0;
1393 pSource->ulBufferID = pSource->queue->buffer;
1395 // Make sure all the Buffers in the queue are marked as PENDING
1396 ALBufferList = pSource->queue;
1397 while (ALBufferList)
1399 ALBufferList->bufferstate = PENDING;
1400 ALBufferList = ALBufferList->next;
1403 else
1405 pSource->state = AL_PLAYING;
1406 pSource->inuse = AL_TRUE;
1407 pSource->play = AL_TRUE;
1410 // Check if an Offset has been set
1411 if (pSource->lOffset)
1412 ApplyOffset(pSource, AL_FALSE);
1414 else
1416 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1417 ALBufferList = pSource->queue;
1418 while (ALBufferList)
1420 ALBufferList->bufferstate = PROCESSED;
1421 ALBufferList = ALBufferList->next;
1424 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1429 else
1431 // sources is a NULL pointer
1432 alSetError(AL_INVALID_VALUE);
1435 ProcessContext(pContext);
1437 else
1439 // Invalid Context
1440 alSetError(AL_INVALID_OPERATION);
1443 return;
1446 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1448 alSourcePausev(1, &source);
1449 return;
1452 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1454 ALCcontext *Context;
1455 ALsource *Source;
1456 ALsizei i;
1457 ALboolean bSourcesValid = AL_TRUE;
1459 Context=alcGetCurrentContext();
1460 if (Context)
1462 SuspendContext(Context);
1464 if (sources)
1466 // Check all the Sources are valid
1467 for (i=0;i<n;i++)
1469 if (!alIsSource(sources[i]))
1471 alSetError(AL_INVALID_NAME);
1472 bSourcesValid = AL_FALSE;
1473 break;
1477 if (bSourcesValid)
1479 for (i=0;i<n;i++)
1481 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1482 if (Source->state==AL_PLAYING)
1484 Source->state=AL_PAUSED;
1485 Source->inuse=AL_FALSE;
1490 else
1492 // sources is a NULL pointer
1493 alSetError(AL_INVALID_VALUE);
1496 ProcessContext(Context);
1498 else
1500 // Invalid Context
1501 alSetError(AL_INVALID_OPERATION);
1504 return;
1507 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1509 alSourceStopv(1, &source);
1510 return;
1513 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1515 ALCcontext *Context;
1516 ALsource *Source;
1517 ALsizei i;
1518 ALbufferlistitem *ALBufferListItem;
1519 ALboolean bSourcesValid = AL_TRUE;
1521 Context=alcGetCurrentContext();
1522 if (Context)
1524 SuspendContext(Context);
1526 if (sources)
1528 // Check all the Sources are valid
1529 for (i=0;i<n;i++)
1531 if (!alIsSource(sources[i]))
1533 alSetError(AL_INVALID_NAME);
1534 bSourcesValid = AL_FALSE;
1535 break;
1539 if (bSourcesValid)
1541 for (i=0;i<n;i++)
1543 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1544 if (Source->state!=AL_INITIAL)
1546 Source->state=AL_STOPPED;
1547 Source->inuse=AL_FALSE;
1548 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1549 ALBufferListItem= Source->queue;
1550 while (ALBufferListItem != NULL)
1552 ALBufferListItem->bufferstate = PROCESSED;
1553 ALBufferListItem = ALBufferListItem->next;
1556 Source->lOffset = 0;
1560 else
1562 // sources is a NULL pointer
1563 alSetError(AL_INVALID_VALUE);
1566 ProcessContext(Context);
1568 else
1570 // Invalid Context
1571 alSetError(AL_INVALID_OPERATION);
1574 return;
1577 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1579 alSourceRewindv(1, &source);
1580 return;
1583 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1585 ALCcontext *Context;
1586 ALsource *Source;
1587 ALsizei i;
1588 ALbufferlistitem *ALBufferListItem;
1589 ALboolean bSourcesValid = AL_TRUE;
1591 Context=alcGetCurrentContext();
1592 if (Context)
1594 SuspendContext(Context);
1596 if (sources)
1598 // Check all the Sources are valid
1599 for (i=0;i<n;i++)
1601 if (!alIsSource(sources[i]))
1603 alSetError(AL_INVALID_NAME);
1604 bSourcesValid = AL_FALSE;
1605 break;
1609 if (bSourcesValid)
1611 for (i=0;i<n;i++)
1613 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1614 if (Source->state!=AL_INITIAL)
1616 Source->state=AL_INITIAL;
1617 Source->inuse=AL_FALSE;
1618 Source->position=0;
1619 Source->position_fraction=0;
1620 Source->BuffersProcessed = 0;
1621 ALBufferListItem= Source->queue;
1622 while (ALBufferListItem != NULL)
1624 ALBufferListItem->bufferstate = PENDING;
1625 ALBufferListItem = ALBufferListItem->next;
1627 if (Source->queue)
1628 Source->ulBufferID = Source->queue->buffer;
1630 Source->lOffset = 0;
1634 else
1636 // sources is a NULL pointer
1637 alSetError(AL_INVALID_VALUE);
1640 ProcessContext(Context);
1642 else
1644 // Invalid Context
1645 alSetError(AL_INVALID_OPERATION);
1648 return;
1652 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1654 ALCcontext *Context;
1655 ALsource *ALSource;
1656 ALsizei i;
1657 ALbufferlistitem *ALBufferList;
1658 ALbufferlistitem *ALBufferListStart;
1659 ALuint DataSize;
1660 ALuint BufferSize;
1661 ALint iFrequency;
1662 ALint iFormat;
1663 ALboolean bBuffersValid = AL_TRUE;
1665 if (n == 0)
1666 return;
1668 Context=alcGetCurrentContext();
1669 if (Context)
1671 SuspendContext(Context);
1673 DataSize = 0;
1674 BufferSize = 0;
1676 // Check that all buffers are valid or zero and that the source is valid
1678 // Check that this is a valid source
1679 if (alIsSource(source))
1681 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1683 // Check that this is not a STATIC Source
1684 if (ALSource->lSourceType != AL_STATIC)
1686 iFrequency = -1;
1687 iFormat = -1;
1689 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1690 ALBufferList = ALSource->queue;
1691 while (ALBufferList)
1693 if (ALBufferList->buffer)
1695 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1696 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1697 break;
1699 ALBufferList = ALBufferList->next;
1702 for (i = 0; i < n; i++)
1704 if (alIsBuffer(buffers[i]))
1706 if (buffers[i])
1708 if ((iFrequency == -1) && (iFormat == -1))
1710 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1711 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1713 else
1715 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1716 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1718 alSetError(AL_INVALID_OPERATION);
1719 bBuffersValid = AL_FALSE;
1720 break;
1725 else
1727 alSetError(AL_INVALID_NAME);
1728 bBuffersValid = AL_FALSE;
1729 break;
1733 if (bBuffersValid)
1735 // Change Source Type
1736 ALSource->lSourceType = AL_STREAMING;
1738 // All buffers are valid - so add them to the list
1739 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1740 ALBufferListStart->buffer = buffers[0];
1741 ALBufferListStart->bufferstate = PENDING;
1742 ALBufferListStart->flag = 0;
1743 ALBufferListStart->next = NULL;
1745 if (buffers[0])
1746 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1747 else
1748 BufferSize = 0;
1750 DataSize += BufferSize;
1752 // Increment reference counter for buffer
1753 if (buffers[0])
1754 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1756 ALBufferList = ALBufferListStart;
1758 for (i = 1; i < n; i++)
1760 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1761 ALBufferList->next->buffer = buffers[i];
1762 ALBufferList->next->bufferstate = PENDING;
1763 ALBufferList->next->flag = 0;
1764 ALBufferList->next->next = NULL;
1766 if (buffers[i])
1767 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1768 else
1769 BufferSize = 0;
1771 DataSize += BufferSize;
1773 // Increment reference counter for buffer
1774 if (buffers[i])
1775 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1777 ALBufferList = ALBufferList->next;
1780 if (ALSource->queue == NULL)
1782 ALSource->queue = ALBufferListStart;
1783 // Update Current Buffer
1784 ALSource->ulBufferID = ALBufferListStart->buffer;
1786 else
1788 // Find end of queue
1789 ALBufferList = ALSource->queue;
1790 while (ALBufferList->next != NULL)
1792 ALBufferList = ALBufferList->next;
1795 ALBufferList->next = ALBufferListStart;
1798 // Update number of buffers in queue
1799 ALSource->BuffersInQueue += n;
1802 else
1804 // Invalid Source Type (can't queue on a Static Source)
1805 alSetError(AL_INVALID_OPERATION);
1808 else
1810 // Invalid Source Name
1811 alSetError(AL_INVALID_NAME);
1814 ProcessContext(Context);
1816 else
1818 // Invalid Context
1819 alSetError(AL_INVALID_OPERATION);
1822 return;
1826 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1827 // an array of buffer IDs that are to be filled with the names of the buffers removed
1828 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1830 ALCcontext *Context;
1831 ALsource *ALSource;
1832 ALsizei i;
1833 ALbufferlistitem *ALBufferList;
1834 ALuint DataSize;
1835 ALuint BufferSize;
1836 ALuint BufferID;
1837 ALboolean bBuffersProcessed;
1839 if (n == 0)
1840 return;
1842 DataSize = 0;
1843 BufferSize = 0;
1844 bBuffersProcessed = AL_TRUE;
1846 Context=alcGetCurrentContext();
1847 if (Context)
1849 SuspendContext(Context);
1851 if (alIsSource(source))
1853 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1855 // Check that all 'n' buffers have been processed
1856 ALBufferList = ALSource->queue;
1857 for (i = 0; i < n; i++)
1859 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1861 ALBufferList = ALBufferList->next;
1863 else
1865 bBuffersProcessed = AL_FALSE;
1866 break;
1870 // If all 'n' buffers have been processed, remove them from the queue
1871 if (bBuffersProcessed)
1873 for (i = 0; i < n; i++)
1875 ALBufferList = ALSource->queue;
1877 ALSource->queue = ALBufferList->next;
1878 // Record name of buffer
1879 buffers[i] = ALBufferList->buffer;
1880 // Decrement buffer reference counter
1881 if (ALBufferList->buffer)
1882 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1883 // Record size of buffer
1884 if (ALBufferList->buffer)
1885 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1886 else
1887 BufferSize = 0;
1889 DataSize += BufferSize;
1890 // Release memory for buffer list item
1891 free(ALBufferList);
1892 ALSource->BuffersInQueue--;
1893 ALSource->BuffersProcessed--;
1896 if (ALSource->state != AL_PLAYING)
1898 if (ALSource->queue)
1899 BufferID = ALSource->queue->buffer;
1900 else
1901 BufferID = 0;
1903 ALSource->ulBufferID = BufferID;
1906 if((ALuint)n > ALSource->BuffersPlayed)
1908 ALSource->BuffersPlayed = 0;
1909 ALSource->BufferPosition = 0;
1911 else
1912 ALSource->BuffersPlayed -= n;
1914 else
1916 // Some buffers can't be unqueue because they have not been processed
1917 alSetError(AL_INVALID_VALUE);
1920 else
1922 // Invalid Source Name
1923 alSetError(AL_INVALID_NAME);
1926 ProcessContext(Context);
1928 else
1930 // Invalid Context
1931 alSetError(AL_INVALID_OPERATION);
1934 return;
1938 static ALvoid InitSourceParams(ALsource *pSource)
1940 pSource->flInnerAngle = 360.0f;
1941 pSource->flOuterAngle = 360.0f;
1942 pSource->flPitch = 1.0f;
1943 pSource->vPosition[0] = 0.0f;
1944 pSource->vPosition[1] = 0.0f;
1945 pSource->vPosition[2] = 0.0f;
1946 pSource->vOrientation[0] = 0.0f;
1947 pSource->vOrientation[1] = 0.0f;
1948 pSource->vOrientation[2] = 0.0f;
1949 pSource->vVelocity[0] = 0.0f;
1950 pSource->vVelocity[1] = 0.0f;
1951 pSource->vVelocity[2] = 0.0f;
1952 pSource->flRefDistance = 1.0f;
1953 pSource->flMaxDistance = FLT_MAX;
1954 pSource->flRollOffFactor = 1.0f;
1955 pSource->bLooping = AL_FALSE;
1956 pSource->flGain = 1.0f;
1957 pSource->flMinGain = 0.0f;
1958 pSource->flMaxGain = 1.0f;
1959 pSource->flOuterGain = 0.0f;
1960 pSource->OuterGainHF = 1.0f;
1962 pSource->DryGainHFAuto = AL_TRUE;
1963 pSource->WetGainAuto = AL_TRUE;
1964 pSource->WetGainHFAuto = AL_TRUE;
1965 pSource->AirAbsorptionFactor = 0.0f;
1966 pSource->RoomRolloffFactor = 0.0f;
1968 pSource->state = AL_INITIAL;
1969 pSource->lSourceType = AL_UNDETERMINED;
1971 pSource->ulBufferID= 0;
1976 GetSourceOffset
1978 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1979 The offset is relative to the start of the queue (not the start of the current buffer)
1981 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1983 ALbufferlistitem *pBufferList;
1984 ALbuffer *pBuffer;
1985 ALfloat flBufferFreq;
1986 ALint lBytesPlayed, lChannels;
1987 ALenum eOriginalFormat;
1988 ALboolean bReturn = AL_TRUE;
1989 ALint lTotalBufferDataSize;
1991 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1993 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
1994 // Get Current Buffer Size and frequency (in milliseconds)
1995 flBufferFreq = (ALfloat)pBuffer->frequency;
1996 eOriginalFormat = pBuffer->eOriginalFormat;
1997 lChannels = aluChannelsFromFormat(pBuffer->format);
1999 // Get Current BytesPlayed
2000 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2001 // Add byte length of any processed buffers in the queue
2002 pBufferList = pSource->queue;
2003 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2005 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2006 pBufferList = pBufferList->next;
2009 lTotalBufferDataSize = 0;
2010 pBufferList = pSource->queue;
2011 while (pBufferList)
2013 if (pBufferList->buffer)
2014 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2015 pBufferList = pBufferList->next;
2018 if (pSource->bLooping)
2020 if (lBytesPlayed < 0)
2021 lBytesPlayed = 0;
2022 else
2023 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2025 else
2027 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2028 if(lBytesPlayed < 0)
2029 lBytesPlayed = 0;
2030 if(lBytesPlayed > lTotalBufferDataSize)
2031 lBytesPlayed = lTotalBufferDataSize;
2034 switch (eName)
2036 case AL_SEC_OFFSET:
2037 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2038 break;
2039 case AL_SAMPLE_OFFSET:
2040 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2041 break;
2042 case AL_BYTE_OFFSET:
2043 // Take into account the original format of the Buffer
2044 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2045 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2047 // Compression rate of the ADPCM supported is 3.6111 to 1
2048 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2049 // Round down to nearest ADPCM block
2050 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2052 else if (eOriginalFormat == AL_FORMAT_REAR8)
2054 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2056 else if (eOriginalFormat == AL_FORMAT_REAR16)
2058 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2060 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2062 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2064 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2066 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2068 else
2070 *pflOffset = (ALfloat)lBytesPlayed;
2072 break;
2075 else
2077 *pflOffset = 0.0f;
2080 return bReturn;
2085 ApplyOffset
2087 Apply a playback offset to the Source. This function will update the queue (to correctly
2088 mark buffers as 'pending' or 'processed' depending upon the new offset.
2090 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2092 ALbufferlistitem *pBufferList;
2093 ALbuffer *pBuffer;
2094 ALint lBufferSize, lTotalBufferSize;
2095 ALint lByteOffset;
2097 // Get true byte offset
2098 lByteOffset = GetByteOffset(pSource);
2100 // If this is a valid offset apply it
2101 if (lByteOffset != -1)
2103 // Sort out the queue (pending and processed states)
2104 pBufferList = pSource->queue;
2105 lTotalBufferSize = 0;
2106 pSource->BuffersPlayed = 0;
2107 pSource->BuffersProcessed = 0;
2108 while (pBufferList)
2110 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2111 lBufferSize = pBuffer ? pBuffer->size : 0;
2113 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2115 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2116 // update the state to PROCESSED
2117 pSource->BuffersPlayed++;
2119 if (!pSource->bLooping)
2121 pBufferList->bufferstate = PROCESSED;
2122 pSource->BuffersProcessed++;
2125 else if (lTotalBufferSize <= lByteOffset)
2127 // Offset is within this buffer
2128 pBufferList->bufferstate = PENDING;
2130 // Set Current Buffer ID
2131 pSource->ulBufferID = pBufferList->buffer;
2133 // Set current position in this buffer
2134 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2136 // Set Total Bytes Played to Offset
2137 pSource->lBytesPlayed = lByteOffset;
2139 // SW Mixer Positions are in Samples
2140 pSource->position = pSource->BufferPosition /
2141 aluBytesFromFormat(pBuffer->format) /
2142 aluChannelsFromFormat(pBuffer->format);
2144 else
2146 // Offset is before this buffer, so mark as pending
2147 pBufferList->bufferstate = PENDING;
2150 // Increment the TotalBufferSize
2151 lTotalBufferSize += lBufferSize;
2153 // Move on to next buffer in the Queue
2154 pBufferList = pBufferList->next;
2157 else
2159 if (bUpdateContext)
2160 alSetError(AL_INVALID_VALUE);
2163 // Clear Offset
2164 pSource->lOffset = 0;
2169 GetByteOffset
2171 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2172 offset supplied by the application). This takes into account the fact that the buffer format
2173 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2175 static ALint GetByteOffset(ALsource *pSource)
2177 ALbuffer *pBuffer = NULL;
2178 ALbufferlistitem *pBufferList;
2179 ALfloat flBufferFreq;
2180 ALint lChannels;
2181 ALint lByteOffset = -1;
2182 ALint lTotalBufferDataSize;
2184 // Find the first non-NULL Buffer in the Queue
2185 pBufferList = pSource->queue;
2186 while (pBufferList)
2188 if (pBufferList->buffer)
2190 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2191 break;
2193 pBufferList = pBufferList->next;
2196 if (pBuffer)
2198 flBufferFreq = ((ALfloat)pBuffer->frequency);
2199 lChannels = aluChannelsFromFormat(pBuffer->format);
2201 // Determine the ByteOffset (and ensure it is block aligned)
2202 switch (pSource->lOffsetType)
2204 case AL_BYTE_OFFSET:
2205 // Take into consideration the original format
2206 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2207 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2209 // Round down to nearest ADPCM block
2210 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2211 // Multiply by compression rate
2212 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2213 lByteOffset -= (lByteOffset % (lChannels * 2));
2215 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2217 lByteOffset = pSource->lOffset * 4;
2218 lByteOffset -= (lByteOffset % (lChannels * 2));
2220 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2222 lByteOffset = pSource->lOffset * 2;
2223 lByteOffset -= (lByteOffset % (lChannels * 2));
2225 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2227 lByteOffset = pSource->lOffset * 2;
2228 lByteOffset -= (lByteOffset % (lChannels * 2));
2230 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2232 lByteOffset = pSource->lOffset / 2;
2233 lByteOffset -= (lByteOffset % (lChannels * 2));
2235 else
2237 lByteOffset = pSource->lOffset;
2238 lByteOffset -= (lByteOffset % (lChannels * 2));
2240 break;
2242 case AL_SAMPLE_OFFSET:
2243 lByteOffset = pSource->lOffset * lChannels * 2;
2244 break;
2246 case AL_SEC_OFFSET:
2247 // Note - lOffset is internally stored as Milliseconds
2248 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2249 lByteOffset -= (lByteOffset % (lChannels * 2));
2250 break;
2253 lTotalBufferDataSize = 0;
2254 pBufferList = pSource->queue;
2255 while (pBufferList)
2257 if (pBufferList->buffer)
2258 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2259 pBufferList = pBufferList->next;
2262 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2263 if (lByteOffset >= lTotalBufferDataSize)
2264 lByteOffset = -1;
2267 return lByteOffset;