Remove duplication of setting source angles
[openal-soft.git] / OpenAL32 / alSource.c
blobcf859e00e435de508738827107440adce1eef5d1
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, ALfloat updateLen);
37 static ALboolean ApplyOffset(ALsource *pSource);
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 = GetContextSuspended();
47 if(!Context) return;
49 if(n > 0)
51 Device = Context->Device;
53 // Check that enough memory has been allocted in the 'sources' array for n Sources
54 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
56 // Check that the requested number of sources can be generated
57 if((Context->SourceCount + n) <= Device->MaxNoOfSources)
59 ALsource **list = &Context->Source;
60 while(*list)
61 list = &(*list)->next;
63 // Add additional sources to the list (Source->next points to the location for the next Source structure)
64 while(i < n)
66 *list = calloc(1, sizeof(ALsource));
67 if(!(*list))
69 alDeleteSources(i, sources);
70 alSetError(AL_OUT_OF_MEMORY);
71 break;
74 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
75 (*list)->source = sources[i];
77 InitSourceParams(*list);
78 Context->SourceCount++;
79 i++;
81 list = &(*list)->next;
84 else
86 // Not enough resources to create the Sources
87 alSetError(AL_INVALID_VALUE);
90 else
92 // Bad pointer
93 alSetError(AL_INVALID_VALUE);
97 ProcessContext(Context);
101 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
103 ALCcontext *Context;
104 ALCdevice *Device;
105 ALsource *ALSource;
106 ALsource **list;
107 ALsizei i, j;
108 ALbufferlistitem *ALBufferList;
109 ALboolean bSourcesValid = AL_TRUE;
111 Context = GetContextSuspended();
112 if(!Context) return;
114 if(n >= 0)
116 Device = Context->Device;
118 // Check that all Sources are valid (and can therefore be deleted)
119 for (i = 0; i < n; i++)
121 if (!alIsSource(sources[i]))
123 alSetError(AL_INVALID_NAME);
124 bSourcesValid = AL_FALSE;
125 break;
129 if(bSourcesValid)
131 // All Sources are valid, and can be deleted
132 for(i = 0; i < n; i++)
134 // Recheck that the Source is valid, because there could be duplicated Source names
135 if(alIsSource(sources[i]))
137 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
138 alSourceStop((ALuint)ALSource->source);
140 // For each buffer in the source's queue, decrement its reference counter and remove it
141 while (ALSource->queue != NULL)
143 ALBufferList = ALSource->queue;
144 // Decrement buffer's reference counter
145 if(ALBufferList->buffer != NULL)
146 ALBufferList->buffer->refcount--;
147 // Update queue to point to next element in list
148 ALSource->queue = ALBufferList->next;
149 // Release memory allocated for buffer list item
150 free(ALBufferList);
153 for(j = 0;j < MAX_SENDS;++j)
155 if(ALSource->Send[j].Slot)
156 ALSource->Send[j].Slot->refcount--;
157 ALSource->Send[j].Slot = NULL;
160 // Decrement Source count
161 Context->SourceCount--;
163 // Remove Source from list of Sources
164 list = &Context->Source;
165 while(*list && *list != ALSource)
166 list = &(*list)->next;
168 if(*list)
169 *list = (*list)->next;
170 ALTHUNK_REMOVEENTRY(ALSource->source);
172 memset(ALSource,0,sizeof(ALsource));
173 free(ALSource);
178 else
179 alSetError(AL_INVALID_VALUE);
181 ProcessContext(Context);
185 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
187 ALboolean result=AL_FALSE;
188 ALCcontext *Context;
189 ALsource *Source;
191 Context = GetContextSuspended();
192 if(!Context) return AL_FALSE;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source = Context->Source;
196 while(Source)
198 if(Source->source == source)
200 result = AL_TRUE;
201 break;
204 Source = Source->next;
207 ProcessContext(Context);
209 return result;
213 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *pSource;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if(alIsSource(source))
223 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
225 switch(eParam)
227 case AL_PITCH:
228 if(flValue >= 0.0f)
230 pSource->flPitch = flValue;
231 if(pSource->flPitch < 0.001f)
232 pSource->flPitch = 0.001f;
233 pSource->NeedsUpdate = AL_TRUE;
235 else
236 alSetError(AL_INVALID_VALUE);
237 break;
239 case AL_CONE_INNER_ANGLE:
240 if(flValue >= 0.0f && flValue <= 360.0f)
242 pSource->flInnerAngle = flValue;
243 pSource->NeedsUpdate = AL_TRUE;
245 else
246 alSetError(AL_INVALID_VALUE);
247 break;
249 case AL_CONE_OUTER_ANGLE:
250 if(flValue >= 0.0f && flValue <= 360.0f)
252 pSource->flOuterAngle = flValue;
253 pSource->NeedsUpdate = AL_TRUE;
255 else
256 alSetError(AL_INVALID_VALUE);
257 break;
259 case AL_GAIN:
260 if(flValue >= 0.0f)
262 pSource->flGain = flValue;
263 pSource->NeedsUpdate = AL_TRUE;
265 else
266 alSetError(AL_INVALID_VALUE);
267 break;
269 case AL_MAX_DISTANCE:
270 if(flValue >= 0.0f)
272 pSource->flMaxDistance = flValue;
273 pSource->NeedsUpdate = AL_TRUE;
275 else
276 alSetError(AL_INVALID_VALUE);
277 break;
279 case AL_ROLLOFF_FACTOR:
280 if(flValue >= 0.0f)
282 pSource->flRollOffFactor = flValue;
283 pSource->NeedsUpdate = AL_TRUE;
285 else
286 alSetError(AL_INVALID_VALUE);
287 break;
289 case AL_REFERENCE_DISTANCE:
290 if(flValue >= 0.0f)
292 pSource->flRefDistance = flValue;
293 pSource->NeedsUpdate = AL_TRUE;
295 else
296 alSetError(AL_INVALID_VALUE);
297 break;
299 case AL_MIN_GAIN:
300 if(flValue >= 0.0f && flValue <= 1.0f)
302 pSource->flMinGain = flValue;
303 pSource->NeedsUpdate = AL_TRUE;
305 else
306 alSetError(AL_INVALID_VALUE);
307 break;
309 case AL_MAX_GAIN:
310 if(flValue >= 0.0f && flValue <= 1.0f)
312 pSource->flMaxGain = flValue;
313 pSource->NeedsUpdate = AL_TRUE;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_CONE_OUTER_GAIN:
320 if(flValue >= 0.0f && flValue <= 1.0f)
322 pSource->flOuterGain = flValue;
323 pSource->NeedsUpdate = AL_TRUE;
325 else
326 alSetError(AL_INVALID_VALUE);
327 break;
329 case AL_CONE_OUTER_GAINHF:
330 if(flValue >= 0.0f && flValue <= 1.0f)
332 pSource->OuterGainHF = flValue;
333 pSource->NeedsUpdate = AL_TRUE;
335 else
336 alSetError(AL_INVALID_VALUE);
337 break;
339 case AL_AIR_ABSORPTION_FACTOR:
340 if(flValue >= 0.0f && flValue <= 10.0f)
342 pSource->AirAbsorptionFactor = flValue;
343 pSource->NeedsUpdate = AL_TRUE;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 case AL_ROOM_ROLLOFF_FACTOR:
350 if(flValue >= 0.0f && flValue <= 10.0f)
352 pSource->RoomRolloffFactor = flValue;
353 pSource->NeedsUpdate = AL_TRUE;
355 else
356 alSetError(AL_INVALID_VALUE);
357 break;
359 case AL_DOPPLER_FACTOR:
360 if(flValue >= 0.0f && flValue <= 1.0f)
362 pSource->DopplerFactor = flValue;
363 pSource->NeedsUpdate = AL_TRUE;
365 else
366 alSetError(AL_INVALID_VALUE);
367 break;
369 case AL_SEC_OFFSET:
370 case AL_SAMPLE_OFFSET:
371 case AL_BYTE_OFFSET:
372 if(flValue >= 0.0f)
374 pSource->lOffsetType = eParam;
376 // Store Offset (convert Seconds into Milliseconds)
377 if(eParam == AL_SEC_OFFSET)
378 pSource->lOffset = (ALint)(flValue * 1000.0f);
379 else
380 pSource->lOffset = (ALint)flValue;
382 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
384 if(ApplyOffset(pSource) == AL_FALSE)
385 alSetError(AL_INVALID_VALUE);
388 else
389 alSetError(AL_INVALID_VALUE);
390 break;
392 default:
393 alSetError(AL_INVALID_ENUM);
394 break;
397 else
399 // Invalid Source Name
400 alSetError(AL_INVALID_NAME);
403 ProcessContext(pContext);
407 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
409 ALCcontext *pContext;
410 ALsource *pSource;
412 pContext = GetContextSuspended();
413 if(!pContext) return;
415 if(alIsSource(source))
417 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
418 switch(eParam)
420 case AL_POSITION:
421 pSource->vPosition[0] = flValue1;
422 pSource->vPosition[1] = flValue2;
423 pSource->vPosition[2] = flValue3;
424 pSource->NeedsUpdate = AL_TRUE;
425 break;
427 case AL_VELOCITY:
428 pSource->vVelocity[0] = flValue1;
429 pSource->vVelocity[1] = flValue2;
430 pSource->vVelocity[2] = flValue3;
431 pSource->NeedsUpdate = AL_TRUE;
432 break;
434 case AL_DIRECTION:
435 pSource->vOrientation[0] = flValue1;
436 pSource->vOrientation[1] = flValue2;
437 pSource->vOrientation[2] = flValue3;
438 pSource->NeedsUpdate = AL_TRUE;
439 break;
441 default:
442 alSetError(AL_INVALID_ENUM);
443 break;
446 else
447 alSetError(AL_INVALID_NAME);
449 ProcessContext(pContext);
453 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
455 ALCcontext *pContext;
457 pContext = GetContextSuspended();
458 if(!pContext) return;
460 if(pflValues)
462 if(alIsSource(source))
464 switch(eParam)
466 case AL_PITCH:
467 case AL_CONE_INNER_ANGLE:
468 case AL_CONE_OUTER_ANGLE:
469 case AL_GAIN:
470 case AL_MAX_DISTANCE:
471 case AL_ROLLOFF_FACTOR:
472 case AL_REFERENCE_DISTANCE:
473 case AL_MIN_GAIN:
474 case AL_MAX_GAIN:
475 case AL_CONE_OUTER_GAIN:
476 case AL_CONE_OUTER_GAINHF:
477 case AL_SEC_OFFSET:
478 case AL_SAMPLE_OFFSET:
479 case AL_BYTE_OFFSET:
480 case AL_AIR_ABSORPTION_FACTOR:
481 case AL_ROOM_ROLLOFF_FACTOR:
482 alSourcef(source, eParam, pflValues[0]);
483 break;
485 case AL_POSITION:
486 case AL_VELOCITY:
487 case AL_DIRECTION:
488 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
489 break;
491 default:
492 alSetError(AL_INVALID_ENUM);
493 break;
496 else
497 alSetError(AL_INVALID_NAME);
499 else
500 alSetError(AL_INVALID_VALUE);
502 ProcessContext(pContext);
506 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
508 ALCcontext *pContext;
509 ALsource *pSource;
510 ALbufferlistitem *pALBufferListItem;
512 pContext = GetContextSuspended();
513 if(!pContext) return;
515 if(alIsSource(source))
517 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
519 switch(eParam)
521 case AL_MAX_DISTANCE:
522 case AL_ROLLOFF_FACTOR:
523 case AL_CONE_INNER_ANGLE:
524 case AL_CONE_OUTER_ANGLE:
525 case AL_REFERENCE_DISTANCE:
526 alSourcef(source, eParam, (ALfloat)lValue);
527 break;
529 case AL_SOURCE_RELATIVE:
530 if(lValue == AL_FALSE || lValue == AL_TRUE)
532 pSource->bHeadRelative = (ALboolean)lValue;
533 pSource->NeedsUpdate = AL_TRUE;
535 else
536 alSetError(AL_INVALID_VALUE);
537 break;
539 case AL_LOOPING:
540 if(lValue == AL_FALSE || lValue == AL_TRUE)
541 pSource->bLooping = (ALboolean)lValue;
542 else
543 alSetError(AL_INVALID_VALUE);
544 break;
546 case AL_BUFFER:
547 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
549 if(alIsBuffer(lValue))
551 ALbuffer *buffer = NULL;
553 // Remove all elements in the queue
554 while(pSource->queue != NULL)
556 pALBufferListItem = pSource->queue;
557 pSource->queue = pALBufferListItem->next;
558 // Decrement reference counter for buffer
559 if(pALBufferListItem->buffer)
560 pALBufferListItem->buffer->refcount--;
561 // Release memory for buffer list item
562 free(pALBufferListItem);
563 // Decrement the number of buffers in the queue
564 pSource->BuffersInQueue--;
567 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
568 if(lValue != 0)
570 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue);
572 // Source is now in STATIC mode
573 pSource->lSourceType = AL_STATIC;
575 // Add the selected buffer to the queue
576 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
577 pALBufferListItem->buffer = buffer;
578 pALBufferListItem->next = NULL;
580 pSource->queue = pALBufferListItem;
581 pSource->BuffersInQueue = 1;
583 // Increment reference counter for buffer
584 buffer->refcount++;
586 else
588 // Source is now in UNDETERMINED mode
589 pSource->lSourceType = AL_UNDETERMINED;
590 pSource->BuffersPlayed = 0;
593 // Update AL_BUFFER parameter
594 pSource->Buffer = buffer;
595 pSource->NeedsUpdate = AL_TRUE;
597 else
598 alSetError(AL_INVALID_VALUE);
600 else
601 alSetError(AL_INVALID_OPERATION);
602 break;
604 case AL_SOURCE_STATE:
605 // Query only
606 alSetError(AL_INVALID_OPERATION);
607 break;
609 case AL_SEC_OFFSET:
610 case AL_SAMPLE_OFFSET:
611 case AL_BYTE_OFFSET:
612 if(lValue >= 0)
614 pSource->lOffsetType = eParam;
616 // Store Offset (convert Seconds into Milliseconds)
617 if(eParam == AL_SEC_OFFSET)
618 pSource->lOffset = lValue * 1000;
619 else
620 pSource->lOffset = lValue;
622 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
624 if(ApplyOffset(pSource) == AL_FALSE)
625 alSetError(AL_INVALID_VALUE);
628 else
629 alSetError(AL_INVALID_VALUE);
630 break;
632 case AL_DIRECT_FILTER:
633 if(alIsFilter(lValue))
635 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
636 if(!filter)
638 pSource->DirectFilter.type = AL_FILTER_NULL;
639 pSource->DirectFilter.filter = 0;
641 else
642 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
643 pSource->NeedsUpdate = AL_TRUE;
645 else
646 alSetError(AL_INVALID_VALUE);
647 break;
649 case AL_DIRECT_FILTER_GAINHF_AUTO:
650 if(lValue == AL_TRUE || lValue == AL_FALSE)
652 pSource->DryGainHFAuto = lValue;
653 pSource->NeedsUpdate = AL_TRUE;
655 else
656 alSetError(AL_INVALID_VALUE);
657 break;
659 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
660 if(lValue == AL_TRUE || lValue == AL_FALSE)
662 pSource->WetGainAuto = lValue;
663 pSource->NeedsUpdate = AL_TRUE;
665 else
666 alSetError(AL_INVALID_VALUE);
667 break;
669 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
670 if(lValue == AL_TRUE || lValue == AL_FALSE)
672 pSource->WetGainHFAuto = lValue;
673 pSource->NeedsUpdate = AL_TRUE;
675 else
676 alSetError(AL_INVALID_VALUE);
677 break;
679 case AL_DISTANCE_MODEL:
680 if(lValue == AL_NONE ||
681 lValue == AL_INVERSE_DISTANCE ||
682 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
683 lValue == AL_LINEAR_DISTANCE ||
684 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
685 lValue == AL_EXPONENT_DISTANCE ||
686 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
688 pSource->DistanceModel = lValue;
689 if(pContext->SourceDistanceModel)
690 pSource->NeedsUpdate = AL_TRUE;
692 else
693 alSetError(AL_INVALID_VALUE);
694 break;
696 default:
697 alSetError(AL_INVALID_ENUM);
698 break;
701 else
702 alSetError(AL_INVALID_NAME);
704 ProcessContext(pContext);
708 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
710 ALCcontext *pContext;
712 pContext = GetContextSuspended();
713 if(!pContext) return;
715 if(alIsSource(source))
717 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
718 ALCdevice *Device = pContext->Device;
720 switch (eParam)
722 case AL_POSITION:
723 case AL_VELOCITY:
724 case AL_DIRECTION:
725 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
726 break;
728 case AL_AUXILIARY_SEND_FILTER:
729 if((ALuint)lValue2 < Device->NumAuxSends &&
730 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
731 alIsFilter(lValue3))
733 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
734 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
736 /* Release refcount on the previous slot, and add one for
737 * the new slot */
738 if(pSource->Send[lValue2].Slot)
739 pSource->Send[lValue2].Slot->refcount--;
740 pSource->Send[lValue2].Slot = ALEffectSlot;
741 if(pSource->Send[lValue2].Slot)
742 pSource->Send[lValue2].Slot->refcount++;
744 if(!ALFilter)
746 /* Disable filter */
747 pSource->Send[lValue2].WetFilter.type = 0;
748 pSource->Send[lValue2].WetFilter.filter = 0;
750 else
751 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
752 pSource->NeedsUpdate = AL_TRUE;
754 else
755 alSetError(AL_INVALID_VALUE);
756 break;
758 default:
759 alSetError(AL_INVALID_ENUM);
760 break;
763 else
764 alSetError(AL_INVALID_NAME);
766 ProcessContext(pContext);
770 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
772 ALCcontext *pContext;
774 pContext = GetContextSuspended();
775 if(!pContext) return;
777 if(plValues)
779 if(alIsSource(source))
781 switch(eParam)
783 case AL_SOURCE_RELATIVE:
784 case AL_CONE_INNER_ANGLE:
785 case AL_CONE_OUTER_ANGLE:
786 case AL_LOOPING:
787 case AL_BUFFER:
788 case AL_SOURCE_STATE:
789 case AL_SEC_OFFSET:
790 case AL_SAMPLE_OFFSET:
791 case AL_BYTE_OFFSET:
792 case AL_MAX_DISTANCE:
793 case AL_ROLLOFF_FACTOR:
794 case AL_REFERENCE_DISTANCE:
795 case AL_DIRECT_FILTER:
796 case AL_DIRECT_FILTER_GAINHF_AUTO:
797 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
798 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
799 case AL_DISTANCE_MODEL:
800 alSourcei(source, eParam, plValues[0]);
801 break;
803 case AL_POSITION:
804 case AL_VELOCITY:
805 case AL_DIRECTION:
806 case AL_AUXILIARY_SEND_FILTER:
807 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
808 break;
810 default:
811 alSetError(AL_INVALID_ENUM);
812 break;
815 else
816 alSetError(AL_INVALID_NAME);
818 else
819 alSetError(AL_INVALID_VALUE);
821 ProcessContext(pContext);
825 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
827 ALCcontext *pContext;
828 ALsource *pSource;
829 ALfloat flOffset[2];
830 ALfloat updateLen;
832 pContext = GetContextSuspended();
833 if(!pContext) return;
835 if(pflValue)
837 if(alIsSource(source))
839 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
841 switch(eParam)
843 case AL_PITCH:
844 *pflValue = pSource->flPitch;
845 break;
847 case AL_GAIN:
848 *pflValue = pSource->flGain;
849 break;
851 case AL_MIN_GAIN:
852 *pflValue = pSource->flMinGain;
853 break;
855 case AL_MAX_GAIN:
856 *pflValue = pSource->flMaxGain;
857 break;
859 case AL_MAX_DISTANCE:
860 *pflValue = pSource->flMaxDistance;
861 break;
863 case AL_ROLLOFF_FACTOR:
864 *pflValue = pSource->flRollOffFactor;
865 break;
867 case AL_CONE_OUTER_GAIN:
868 *pflValue = pSource->flOuterGain;
869 break;
871 case AL_CONE_OUTER_GAINHF:
872 *pflValue = pSource->OuterGainHF;
873 break;
875 case AL_SEC_OFFSET:
876 case AL_SAMPLE_OFFSET:
877 case AL_BYTE_OFFSET:
878 updateLen = (ALfloat)pContext->Device->UpdateSize /
879 pContext->Device->Frequency;
880 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
881 *pflValue = flOffset[0];
882 else
883 alSetError(AL_INVALID_OPERATION);
884 break;
886 case AL_CONE_INNER_ANGLE:
887 *pflValue = pSource->flInnerAngle;
888 break;
890 case AL_CONE_OUTER_ANGLE:
891 *pflValue = pSource->flOuterAngle;
892 break;
894 case AL_REFERENCE_DISTANCE:
895 *pflValue = pSource->flRefDistance;
896 break;
898 case AL_AIR_ABSORPTION_FACTOR:
899 *pflValue = pSource->AirAbsorptionFactor;
900 break;
902 case AL_ROOM_ROLLOFF_FACTOR:
903 *pflValue = pSource->RoomRolloffFactor;
904 break;
906 case AL_DOPPLER_FACTOR:
907 *pflValue = pSource->DopplerFactor;
908 break;
910 default:
911 alSetError(AL_INVALID_ENUM);
912 break;
915 else
916 alSetError(AL_INVALID_NAME);
918 else
919 alSetError(AL_INVALID_VALUE);
921 ProcessContext(pContext);
925 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
927 ALCcontext *pContext;
928 ALsource *pSource;
930 pContext = GetContextSuspended();
931 if(!pContext) return;
933 if(pflValue1 && pflValue2 && pflValue3)
935 if(alIsSource(source))
937 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
939 switch(eParam)
941 case AL_POSITION:
942 *pflValue1 = pSource->vPosition[0];
943 *pflValue2 = pSource->vPosition[1];
944 *pflValue3 = pSource->vPosition[2];
945 break;
947 case AL_VELOCITY:
948 *pflValue1 = pSource->vVelocity[0];
949 *pflValue2 = pSource->vVelocity[1];
950 *pflValue3 = pSource->vVelocity[2];
951 break;
953 case AL_DIRECTION:
954 *pflValue1 = pSource->vOrientation[0];
955 *pflValue2 = pSource->vOrientation[1];
956 *pflValue3 = pSource->vOrientation[2];
957 break;
959 default:
960 alSetError(AL_INVALID_ENUM);
961 break;
964 else
965 alSetError(AL_INVALID_NAME);
967 else
968 alSetError(AL_INVALID_VALUE);
970 ProcessContext(pContext);
974 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
976 ALCcontext *pContext;
977 ALsource *pSource;
978 ALfloat flOffset[2];
979 ALfloat updateLen;
981 pContext = GetContextSuspended();
982 if(!pContext) return;
984 if(pflValues)
986 if(alIsSource(source))
988 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
990 switch(eParam)
992 case AL_PITCH:
993 case AL_GAIN:
994 case AL_MIN_GAIN:
995 case AL_MAX_GAIN:
996 case AL_MAX_DISTANCE:
997 case AL_ROLLOFF_FACTOR:
998 case AL_DOPPLER_FACTOR:
999 case AL_CONE_OUTER_GAIN:
1000 case AL_SEC_OFFSET:
1001 case AL_SAMPLE_OFFSET:
1002 case AL_BYTE_OFFSET:
1003 case AL_CONE_INNER_ANGLE:
1004 case AL_CONE_OUTER_ANGLE:
1005 case AL_REFERENCE_DISTANCE:
1006 case AL_CONE_OUTER_GAINHF:
1007 case AL_AIR_ABSORPTION_FACTOR:
1008 case AL_ROOM_ROLLOFF_FACTOR:
1009 alGetSourcef(source, eParam, pflValues);
1010 break;
1012 case AL_SAMPLE_RW_OFFSETS_EXT:
1013 case AL_BYTE_RW_OFFSETS_EXT:
1014 updateLen = (ALfloat)pContext->Device->UpdateSize /
1015 pContext->Device->Frequency;
1016 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1018 pflValues[0] = flOffset[0];
1019 pflValues[1] = flOffset[1];
1021 else
1022 alSetError(AL_INVALID_OPERATION);
1023 break;
1025 case AL_POSITION:
1026 pflValues[0] = pSource->vPosition[0];
1027 pflValues[1] = pSource->vPosition[1];
1028 pflValues[2] = pSource->vPosition[2];
1029 break;
1031 case AL_VELOCITY:
1032 pflValues[0] = pSource->vVelocity[0];
1033 pflValues[1] = pSource->vVelocity[1];
1034 pflValues[2] = pSource->vVelocity[2];
1035 break;
1037 case AL_DIRECTION:
1038 pflValues[0] = pSource->vOrientation[0];
1039 pflValues[1] = pSource->vOrientation[1];
1040 pflValues[2] = pSource->vOrientation[2];
1041 break;
1043 default:
1044 alSetError(AL_INVALID_ENUM);
1045 break;
1048 else
1049 alSetError(AL_INVALID_NAME);
1051 else
1052 alSetError(AL_INVALID_VALUE);
1054 ProcessContext(pContext);
1058 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1060 ALCcontext *pContext;
1061 ALsource *pSource;
1062 ALfloat flOffset[2];
1063 ALfloat updateLen;
1065 pContext = GetContextSuspended();
1066 if(!pContext) return;
1068 if(plValue)
1070 if(alIsSource(source))
1072 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1074 switch(eParam)
1076 case AL_MAX_DISTANCE:
1077 *plValue = (ALint)pSource->flMaxDistance;
1078 break;
1080 case AL_ROLLOFF_FACTOR:
1081 *plValue = (ALint)pSource->flRollOffFactor;
1082 break;
1084 case AL_REFERENCE_DISTANCE:
1085 *plValue = (ALint)pSource->flRefDistance;
1086 break;
1088 case AL_SOURCE_RELATIVE:
1089 *plValue = pSource->bHeadRelative;
1090 break;
1092 case AL_CONE_INNER_ANGLE:
1093 *plValue = (ALint)pSource->flInnerAngle;
1094 break;
1096 case AL_CONE_OUTER_ANGLE:
1097 *plValue = (ALint)pSource->flOuterAngle;
1098 break;
1100 case AL_LOOPING:
1101 *plValue = pSource->bLooping;
1102 break;
1104 case AL_BUFFER:
1105 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1106 break;
1108 case AL_SOURCE_STATE:
1109 *plValue = pSource->state;
1110 break;
1112 case AL_BUFFERS_QUEUED:
1113 *plValue = pSource->BuffersInQueue;
1114 break;
1116 case AL_BUFFERS_PROCESSED:
1117 if(pSource->bLooping)
1119 /* Buffers on a looping source are in a perpetual state
1120 * of PENDING, so don't report any as PROCESSED */
1121 *plValue = 0;
1123 else
1124 *plValue = pSource->BuffersPlayed;
1125 break;
1127 case AL_SOURCE_TYPE:
1128 *plValue = pSource->lSourceType;
1129 break;
1131 case AL_SEC_OFFSET:
1132 case AL_SAMPLE_OFFSET:
1133 case AL_BYTE_OFFSET:
1134 updateLen = (ALfloat)pContext->Device->UpdateSize /
1135 pContext->Device->Frequency;
1136 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1137 *plValue = (ALint)flOffset[0];
1138 else
1139 alSetError(AL_INVALID_OPERATION);
1140 break;
1142 case AL_DIRECT_FILTER:
1143 *plValue = pSource->DirectFilter.filter;
1144 break;
1146 case AL_DIRECT_FILTER_GAINHF_AUTO:
1147 *plValue = pSource->DryGainHFAuto;
1148 break;
1150 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1151 *plValue = pSource->WetGainAuto;
1152 break;
1154 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1155 *plValue = pSource->WetGainHFAuto;
1156 break;
1158 case AL_DOPPLER_FACTOR:
1159 *plValue = (ALint)pSource->DopplerFactor;
1160 break;
1162 case AL_DISTANCE_MODEL:
1163 *plValue = pSource->DistanceModel;
1164 break;
1166 default:
1167 alSetError(AL_INVALID_ENUM);
1168 break;
1171 else
1172 alSetError(AL_INVALID_NAME);
1174 else
1175 alSetError(AL_INVALID_VALUE);
1177 ProcessContext(pContext);
1181 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1183 ALCcontext *pContext;
1184 ALsource *pSource;
1186 pContext = GetContextSuspended();
1187 if(!pContext) return;
1189 if(plValue1 && plValue2 && plValue3)
1191 if(alIsSource(source))
1193 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1195 switch(eParam)
1197 case AL_POSITION:
1198 *plValue1 = (ALint)pSource->vPosition[0];
1199 *plValue2 = (ALint)pSource->vPosition[1];
1200 *plValue3 = (ALint)pSource->vPosition[2];
1201 break;
1203 case AL_VELOCITY:
1204 *plValue1 = (ALint)pSource->vVelocity[0];
1205 *plValue2 = (ALint)pSource->vVelocity[1];
1206 *plValue3 = (ALint)pSource->vVelocity[2];
1207 break;
1209 case AL_DIRECTION:
1210 *plValue1 = (ALint)pSource->vOrientation[0];
1211 *plValue2 = (ALint)pSource->vOrientation[1];
1212 *plValue3 = (ALint)pSource->vOrientation[2];
1213 break;
1215 default:
1216 alSetError(AL_INVALID_ENUM);
1217 break;
1220 else
1221 alSetError(AL_INVALID_NAME);
1223 else
1224 alSetError(AL_INVALID_VALUE);
1226 ProcessContext(pContext);
1230 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1232 ALCcontext *pContext;
1233 ALsource *pSource;
1234 ALfloat flOffset[2];
1235 ALfloat updateLen;
1237 pContext = GetContextSuspended();
1238 if(!pContext) return;
1240 if(plValues)
1242 if(alIsSource(source))
1244 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1246 switch(eParam)
1248 case AL_SOURCE_RELATIVE:
1249 case AL_CONE_INNER_ANGLE:
1250 case AL_CONE_OUTER_ANGLE:
1251 case AL_LOOPING:
1252 case AL_BUFFER:
1253 case AL_SOURCE_STATE:
1254 case AL_BUFFERS_QUEUED:
1255 case AL_BUFFERS_PROCESSED:
1256 case AL_SEC_OFFSET:
1257 case AL_SAMPLE_OFFSET:
1258 case AL_BYTE_OFFSET:
1259 case AL_MAX_DISTANCE:
1260 case AL_ROLLOFF_FACTOR:
1261 case AL_DOPPLER_FACTOR:
1262 case AL_REFERENCE_DISTANCE:
1263 case AL_SOURCE_TYPE:
1264 case AL_DIRECT_FILTER:
1265 case AL_DIRECT_FILTER_GAINHF_AUTO:
1266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1268 case AL_DISTANCE_MODEL:
1269 alGetSourcei(source, eParam, plValues);
1270 break;
1272 case AL_SAMPLE_RW_OFFSETS_EXT:
1273 case AL_BYTE_RW_OFFSETS_EXT:
1274 updateLen = (ALfloat)pContext->Device->UpdateSize /
1275 pContext->Device->Frequency;
1276 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1278 plValues[0] = (ALint)flOffset[0];
1279 plValues[1] = (ALint)flOffset[1];
1281 else
1282 alSetError(AL_INVALID_OPERATION);
1283 break;
1285 case AL_POSITION:
1286 plValues[0] = (ALint)pSource->vPosition[0];
1287 plValues[1] = (ALint)pSource->vPosition[1];
1288 plValues[2] = (ALint)pSource->vPosition[2];
1289 break;
1291 case AL_VELOCITY:
1292 plValues[0] = (ALint)pSource->vVelocity[0];
1293 plValues[1] = (ALint)pSource->vVelocity[1];
1294 plValues[2] = (ALint)pSource->vVelocity[2];
1295 break;
1297 case AL_DIRECTION:
1298 plValues[0] = (ALint)pSource->vOrientation[0];
1299 plValues[1] = (ALint)pSource->vOrientation[1];
1300 plValues[2] = (ALint)pSource->vOrientation[2];
1301 break;
1303 default:
1304 alSetError(AL_INVALID_ENUM);
1305 break;
1308 else
1309 alSetError(AL_INVALID_NAME);
1311 else
1312 alSetError(AL_INVALID_VALUE);
1314 ProcessContext(pContext);
1318 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1320 alSourcePlayv(1, &source);
1323 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1325 ALCcontext *pContext;
1326 ALsource *pSource;
1327 ALbufferlistitem *ALBufferList;
1328 ALboolean bSourcesValid = AL_TRUE;
1329 ALboolean bPlay;
1330 ALsizei i, j;
1332 pContext = GetContextSuspended();
1333 if(!pContext) return;
1335 if(pSourceList)
1337 // Check that all the Sources are valid
1338 for(i = 0; i < n; i++)
1340 if(!alIsSource(pSourceList[i]))
1342 alSetError(AL_INVALID_NAME);
1343 bSourcesValid = AL_FALSE;
1344 break;
1348 if(bSourcesValid)
1350 for(i = 0; i < n; i++)
1352 // Assume Source won't need to play
1353 bPlay = AL_FALSE;
1355 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1357 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1358 ALBufferList = pSource->queue;
1359 while(ALBufferList)
1361 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1363 bPlay = AL_TRUE;
1364 break;
1366 ALBufferList = ALBufferList->next;
1369 if (bPlay)
1371 for(j = 0;j < OUTPUTCHANNELS;j++)
1372 pSource->DryGains[j] = 0.0f;
1373 for(j = 0;j < MAX_SENDS;j++)
1374 pSource->WetGains[j] = 0.0f;
1376 if(pSource->state != AL_PAUSED)
1378 pSource->state = AL_PLAYING;
1379 pSource->position = 0;
1380 pSource->position_fraction = 0;
1381 pSource->BuffersPlayed = 0;
1383 pSource->Buffer = pSource->queue->buffer;
1385 else
1386 pSource->state = AL_PLAYING;
1388 // Check if an Offset has been set
1389 if(pSource->lOffset)
1390 ApplyOffset(pSource);
1392 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1393 pSource->position_fraction == 0)
1394 pSource->FirstStart = AL_TRUE;
1395 else
1396 pSource->FirstStart = AL_FALSE;
1398 // If device is disconnected, go right to stopped
1399 if(!pContext->Device->Connected)
1401 pSource->state = AL_STOPPED;
1402 pSource->BuffersPlayed = pSource->BuffersInQueue;
1403 pSource->position = 0;
1404 pSource->position_fraction = 0;
1407 else
1408 pSource->BuffersPlayed = pSource->BuffersInQueue;
1412 else
1414 // sources is a NULL pointer
1415 alSetError(AL_INVALID_VALUE);
1418 ProcessContext(pContext);
1421 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1423 alSourcePausev(1, &source);
1426 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1428 ALCcontext *Context;
1429 ALsource *Source;
1430 ALsizei i;
1431 ALboolean bSourcesValid = AL_TRUE;
1433 Context = GetContextSuspended();
1434 if(!Context) return;
1436 if(sources)
1438 // Check all the Sources are valid
1439 for(i=0;i<n;i++)
1441 if(!alIsSource(sources[i]))
1443 alSetError(AL_INVALID_NAME);
1444 bSourcesValid = AL_FALSE;
1445 break;
1449 if(bSourcesValid)
1451 for(i = 0;i < n;i++)
1453 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1454 if(Source->state == AL_PLAYING)
1455 Source->state = AL_PAUSED;
1459 else
1461 // sources is a NULL pointer
1462 alSetError(AL_INVALID_VALUE);
1465 ProcessContext(Context);
1468 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1470 alSourceStopv(1, &source);
1473 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1475 ALCcontext *Context;
1476 ALsource *Source;
1477 ALsizei i;
1478 ALboolean bSourcesValid = AL_TRUE;
1480 Context = GetContextSuspended();
1481 if(!Context) return;
1483 if(sources)
1485 // Check all the Sources are valid
1486 for(i = 0;i < n;i++)
1488 if(!alIsSource(sources[i]))
1490 alSetError(AL_INVALID_NAME);
1491 bSourcesValid = AL_FALSE;
1492 break;
1496 if(bSourcesValid)
1498 for(i = 0;i < n;i++)
1500 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1501 if(Source->state != AL_INITIAL)
1503 Source->state = AL_STOPPED;
1504 Source->BuffersPlayed = Source->BuffersInQueue;
1506 Source->lOffset = 0;
1510 else
1512 // sources is a NULL pointer
1513 alSetError(AL_INVALID_VALUE);
1516 ProcessContext(Context);
1519 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1521 alSourceRewindv(1, &source);
1524 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1526 ALCcontext *Context;
1527 ALsource *Source;
1528 ALsizei i;
1529 ALboolean bSourcesValid = AL_TRUE;
1531 Context = GetContextSuspended();
1532 if(!Context) return;
1534 if(sources)
1536 // Check all the Sources are valid
1537 for(i = 0;i < n;i++)
1539 if(!alIsSource(sources[i]))
1541 alSetError(AL_INVALID_NAME);
1542 bSourcesValid = AL_FALSE;
1543 break;
1547 if(bSourcesValid)
1549 for(i = 0;i < n;i++)
1551 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1552 if(Source->state != AL_INITIAL)
1554 Source->state = AL_INITIAL;
1555 Source->position = 0;
1556 Source->position_fraction = 0;
1557 Source->BuffersPlayed = 0;
1558 if(Source->queue)
1559 Source->Buffer = Source->queue->buffer;
1561 Source->lOffset = 0;
1565 else
1567 // sources is a NULL pointer
1568 alSetError(AL_INVALID_VALUE);
1571 ProcessContext(Context);
1575 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1577 ALCcontext *Context;
1578 ALsource *ALSource;
1579 ALsizei i;
1580 ALbufferlistitem *ALBufferList;
1581 ALbufferlistitem *ALBufferListStart;
1582 ALint iFrequency;
1583 ALint iFormat;
1584 ALboolean bBuffersValid = AL_TRUE;
1585 ALboolean hadFormat = AL_FALSE;
1587 if (n == 0)
1588 return;
1590 Context = GetContextSuspended();
1591 if(!Context) return;
1593 // Check that all buffers are valid or zero and that the source is valid
1595 // Check that this is a valid source
1596 if(alIsSource(source))
1598 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1600 // Check that this is not a STATIC Source
1601 if(ALSource->lSourceType != AL_STATIC)
1603 iFrequency = -1;
1604 iFormat = -1;
1606 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1607 ALBufferList = ALSource->queue;
1608 while(ALBufferList)
1610 if (ALBufferList->buffer)
1612 iFrequency = ALBufferList->buffer->frequency;
1613 iFormat = ALBufferList->buffer->format;
1614 hadFormat = AL_TRUE;
1615 break;
1617 ALBufferList = ALBufferList->next;
1620 for(i = 0; i < n; i++)
1622 ALbuffer *buffer;
1624 if(!alIsBuffer(buffers[i]))
1626 alSetError(AL_INVALID_NAME);
1627 bBuffersValid = AL_FALSE;
1628 break;
1630 if(!buffers[i])
1631 continue;
1633 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1634 if(iFrequency == -1 && iFormat == -1)
1636 iFrequency = buffer->frequency;
1637 iFormat = buffer->format;
1639 else if(iFrequency != buffer->frequency ||
1640 iFormat != buffer->format)
1642 alSetError(AL_INVALID_OPERATION);
1643 bBuffersValid = AL_FALSE;
1644 break;
1648 if(bBuffersValid)
1650 ALbuffer *buffer = NULL;
1652 // Change Source Type
1653 ALSource->lSourceType = AL_STREAMING;
1655 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1657 // All buffers are valid - so add them to the list
1658 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1659 ALBufferListStart->buffer = buffer;
1660 ALBufferListStart->next = NULL;
1662 // Increment reference counter for buffer
1663 if(buffer) buffer->refcount++;
1665 ALBufferList = ALBufferListStart;
1667 for(i = 1; i < n; i++)
1669 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1671 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1672 ALBufferList->next->buffer = buffer;
1673 ALBufferList->next->next = NULL;
1675 // Increment reference counter for buffer
1676 if(buffer) buffer->refcount++;
1678 ALBufferList = ALBufferList->next;
1681 if(ALSource->queue == NULL)
1683 ALSource->queue = ALBufferListStart;
1684 // Update Current Buffer
1685 ALSource->Buffer = ALBufferListStart->buffer;
1687 else
1689 // Find end of queue
1690 ALBufferList = ALSource->queue;
1691 while(ALBufferList->next != NULL)
1692 ALBufferList = ALBufferList->next;
1694 ALBufferList->next = ALBufferListStart;
1697 // Update number of buffers in queue
1698 ALSource->BuffersInQueue += n;
1699 // If no previous format, mark the source dirty now that it may
1700 // have one
1701 if(!hadFormat)
1702 ALSource->NeedsUpdate = AL_TRUE;
1705 else
1707 // Invalid Source Type (can't queue on a Static Source)
1708 alSetError(AL_INVALID_OPERATION);
1711 else
1713 // Invalid Source Name
1714 alSetError(AL_INVALID_NAME);
1717 ProcessContext(Context);
1721 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1722 // an array of buffer IDs that are to be filled with the names of the buffers removed
1723 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1725 ALCcontext *Context;
1726 ALsource *ALSource;
1727 ALsizei i;
1728 ALbufferlistitem *ALBufferList;
1729 ALboolean bBuffersProcessed;
1731 if (n == 0)
1732 return;
1734 bBuffersProcessed = AL_TRUE;
1736 Context = GetContextSuspended();
1737 if(!Context) return;
1739 if(alIsSource(source))
1741 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1743 // If all 'n' buffers have been processed, remove them from the queue
1744 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1746 for(i = 0; i < n; i++)
1748 ALBufferList = ALSource->queue;
1750 ALSource->queue = ALBufferList->next;
1751 // Record name of buffer
1752 buffers[i] = ALBufferList->buffer->buffer;
1753 // Decrement buffer reference counter
1754 if(ALBufferList->buffer)
1755 ALBufferList->buffer->refcount--;
1757 // Release memory for buffer list item
1758 free(ALBufferList);
1759 ALSource->BuffersInQueue--;
1762 if(ALSource->state != AL_PLAYING)
1764 if(ALSource->queue)
1765 ALSource->Buffer = ALSource->queue->buffer;
1766 else
1767 ALSource->Buffer = NULL;
1770 ALSource->BuffersPlayed -= n;
1772 else
1774 // Some buffers can't be unqueue because they have not been processed
1775 alSetError(AL_INVALID_VALUE);
1778 else
1780 // Invalid Source Name
1781 alSetError(AL_INVALID_NAME);
1784 ProcessContext(Context);
1788 static ALvoid InitSourceParams(ALsource *pSource)
1790 pSource->flInnerAngle = 360.0f;
1791 pSource->flOuterAngle = 360.0f;
1792 pSource->flPitch = 1.0f;
1793 pSource->vPosition[0] = 0.0f;
1794 pSource->vPosition[1] = 0.0f;
1795 pSource->vPosition[2] = 0.0f;
1796 pSource->vOrientation[0] = 0.0f;
1797 pSource->vOrientation[1] = 0.0f;
1798 pSource->vOrientation[2] = 0.0f;
1799 pSource->vVelocity[0] = 0.0f;
1800 pSource->vVelocity[1] = 0.0f;
1801 pSource->vVelocity[2] = 0.0f;
1802 pSource->flRefDistance = 1.0f;
1803 pSource->flMaxDistance = FLT_MAX;
1804 pSource->flRollOffFactor = 1.0f;
1805 pSource->bLooping = AL_FALSE;
1806 pSource->flGain = 1.0f;
1807 pSource->flMinGain = 0.0f;
1808 pSource->flMaxGain = 1.0f;
1809 pSource->flOuterGain = 0.0f;
1810 pSource->OuterGainHF = 1.0f;
1812 pSource->DryGainHFAuto = AL_TRUE;
1813 pSource->WetGainAuto = AL_TRUE;
1814 pSource->WetGainHFAuto = AL_TRUE;
1815 pSource->AirAbsorptionFactor = 0.0f;
1816 pSource->RoomRolloffFactor = 0.0f;
1817 pSource->DopplerFactor = 1.0f;
1819 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1821 pSource->Resampler = DefaultResampler;
1823 pSource->state = AL_INITIAL;
1824 pSource->lSourceType = AL_UNDETERMINED;
1826 pSource->NeedsUpdate = AL_TRUE;
1828 pSource->Buffer = NULL;
1833 GetSourceOffset
1835 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1836 The offset is relative to the start of the queue (not the start of the current buffer)
1838 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen)
1840 ALbufferlistitem *pBufferList;
1841 ALbuffer *pBuffer;
1842 ALfloat flBufferFreq;
1843 ALint lChannels, lBytes;
1844 ALint readPos, writePos;
1845 ALenum eOriginalFormat;
1846 ALboolean bReturn = AL_TRUE;
1847 ALint lTotalBufferDataSize;
1848 ALuint i;
1850 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1852 pBuffer = pSource->Buffer;
1853 // Get Current Buffer Size and frequency (in milliseconds)
1854 flBufferFreq = (ALfloat)pBuffer->frequency;
1855 eOriginalFormat = pBuffer->eOriginalFormat;
1856 lChannels = aluChannelsFromFormat(pBuffer->format);
1857 lBytes = aluBytesFromFormat(pBuffer->format);
1859 // Get Current BytesPlayed
1860 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1861 // Add byte length of any processed buffers in the queue
1862 pBufferList = pSource->queue;
1863 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1865 readPos += pBufferList->buffer->size;
1866 pBufferList = pBufferList->next;
1869 if(pSource->state == AL_PLAYING)
1870 writePos = readPos + ((ALuint)(updateLen*flBufferFreq) * lChannels * lBytes);
1871 else
1872 writePos = readPos;
1874 lTotalBufferDataSize = 0;
1875 pBufferList = pSource->queue;
1876 while (pBufferList)
1878 if (pBufferList->buffer)
1879 lTotalBufferDataSize += pBufferList->buffer->size;
1880 pBufferList = pBufferList->next;
1883 if (pSource->bLooping)
1885 if(readPos < 0)
1886 readPos = 0;
1887 else
1888 readPos %= lTotalBufferDataSize;
1889 if(writePos < 0)
1890 writePos = 0;
1891 else
1892 writePos %= lTotalBufferDataSize;
1894 else
1896 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1897 if(readPos < 0)
1898 readPos = 0;
1899 else if(readPos > lTotalBufferDataSize)
1900 readPos = lTotalBufferDataSize;
1901 if(writePos < 0)
1902 writePos = 0;
1903 else if(writePos > lTotalBufferDataSize)
1904 writePos = lTotalBufferDataSize;
1907 switch (eName)
1909 case AL_SEC_OFFSET:
1910 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1911 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1912 break;
1913 case AL_SAMPLE_OFFSET:
1914 case AL_SAMPLE_RW_OFFSETS_EXT:
1915 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1916 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1917 break;
1918 case AL_BYTE_OFFSET:
1919 case AL_BYTE_RW_OFFSETS_EXT:
1920 // Take into account the original format of the Buffer
1921 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1922 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1924 // Round down to nearest ADPCM block
1925 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1926 if(pSource->state == AL_PLAYING)
1928 // Round up to nearest ADPCM block
1929 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1931 else
1932 pflOffset[1] = pflOffset[0];
1934 else if (eOriginalFormat == AL_FORMAT_REAR8)
1936 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1937 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1939 else if (eOriginalFormat == AL_FORMAT_REAR16)
1941 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1942 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1944 else if (eOriginalFormat == AL_FORMAT_REAR32)
1946 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1947 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1949 else
1951 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1952 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1953 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1955 break;
1958 else
1960 pflOffset[0] = 0.0f;
1961 pflOffset[1] = 0.0f;
1964 return bReturn;
1969 ApplyOffset
1971 Apply a playback offset to the Source. This function will update the queue (to correctly
1972 mark buffers as 'pending' or 'processed' depending upon the new offset.
1974 static ALboolean ApplyOffset(ALsource *pSource)
1976 ALbufferlistitem *pBufferList;
1977 ALbuffer *pBuffer;
1978 ALint lBufferSize, lTotalBufferSize;
1979 ALint lByteOffset;
1981 // Get true byte offset
1982 lByteOffset = GetByteOffset(pSource);
1984 // If the offset is invalid, don't apply it
1985 if(lByteOffset == -1)
1986 return AL_FALSE;
1988 // Sort out the queue (pending and processed states)
1989 pBufferList = pSource->queue;
1990 lTotalBufferSize = 0;
1991 pSource->BuffersPlayed = 0;
1993 while(pBufferList)
1995 pBuffer = pBufferList->buffer;
1996 lBufferSize = pBuffer ? pBuffer->size : 0;
1998 if(lTotalBufferSize+lBufferSize <= lByteOffset)
2000 // Offset is past this buffer so increment BuffersPlayed
2001 pSource->BuffersPlayed++;
2003 else if(lTotalBufferSize <= lByteOffset)
2005 // Offset is within this buffer
2006 // Set Current Buffer
2007 pSource->Buffer = pBufferList->buffer;
2009 // SW Mixer Positions are in Samples
2010 pSource->position = (lByteOffset - lTotalBufferSize) /
2011 aluBytesFromFormat(pBuffer->format) /
2012 aluChannelsFromFormat(pBuffer->format);
2013 break;
2016 // Increment the TotalBufferSize
2017 lTotalBufferSize += lBufferSize;
2019 // Move on to next buffer in the Queue
2020 pBufferList = pBufferList->next;
2023 return AL_TRUE;
2028 GetByteOffset
2030 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2031 offset supplied by the application). This takes into account the fact that the buffer format
2032 may have been modifed by AL (e.g 8bit samples are converted to float)
2034 static ALint GetByteOffset(ALsource *pSource)
2036 ALbuffer *pBuffer = NULL;
2037 ALbufferlistitem *pBufferList;
2038 ALfloat flBufferFreq;
2039 ALint lChannels, lBytes;
2040 ALint lByteOffset = -1;
2041 ALint lTotalBufferDataSize;
2042 ALenum OriginalFormat;
2044 // Find the first non-NULL Buffer in the Queue
2045 pBufferList = pSource->queue;
2046 while (pBufferList)
2048 if (pBufferList->buffer)
2050 pBuffer = pBufferList->buffer;
2051 break;
2053 pBufferList = pBufferList->next;
2056 if (pBuffer)
2058 flBufferFreq = ((ALfloat)pBuffer->frequency);
2059 lChannels = aluChannelsFromFormat(pBuffer->format);
2060 lBytes = aluBytesFromFormat(pBuffer->format);
2061 OriginalFormat = pBuffer->eOriginalFormat;
2063 // Determine the ByteOffset (and ensure it is block aligned)
2064 switch (pSource->lOffsetType)
2066 case AL_BYTE_OFFSET:
2067 // Take into consideration the original format
2068 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2069 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2071 // Round down to nearest ADPCM block
2072 lByteOffset = pSource->lOffset / (36 * lChannels);
2073 // Multiply by compression rate
2074 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2075 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2077 else if(OriginalFormat == AL_FORMAT_REAR8)
2079 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2080 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2082 else if(OriginalFormat == AL_FORMAT_REAR16)
2084 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2085 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2087 else if(OriginalFormat == AL_FORMAT_REAR32)
2089 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2090 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2092 else
2094 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2095 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2096 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2098 break;
2100 case AL_SAMPLE_OFFSET:
2101 lByteOffset = pSource->lOffset * lChannels * lBytes;
2102 break;
2104 case AL_SEC_OFFSET:
2105 // Note - lOffset is internally stored as Milliseconds
2106 lByteOffset = (ALint)(pSource->lOffset / 1000.0f * flBufferFreq);
2107 lByteOffset *= lChannels * lBytes;
2108 break;
2111 lTotalBufferDataSize = 0;
2112 pBufferList = pSource->queue;
2113 while (pBufferList)
2115 if (pBufferList->buffer)
2116 lTotalBufferDataSize += pBufferList->buffer->size;
2117 pBufferList = pBufferList->next;
2120 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2121 if (lByteOffset >= lTotalBufferDataSize)
2122 lByteOffset = -1;
2125 // Clear Offset
2126 pSource->lOffset = 0;
2128 return lByteOffset;
2132 ALvoid ReleaseALSources(ALCcontext *Context)
2134 ALuint j;
2136 while(Context->Source)
2138 ALsource *temp = Context->Source;
2139 Context->Source = temp->next;
2141 // For each buffer in the source's queue, decrement its reference counter and remove it
2142 while(temp->queue != NULL)
2144 ALbufferlistitem *ALBufferList = temp->queue;
2145 // Decrement buffer's reference counter
2146 if(ALBufferList->buffer != NULL)
2147 ALBufferList->buffer->refcount--;
2148 // Update queue to point to next element in list
2149 temp->queue = ALBufferList->next;
2150 // Release memory allocated for buffer list item
2151 free(ALBufferList);
2154 for(j = 0;j < MAX_SENDS;++j)
2156 if(temp->Send[j].Slot)
2157 temp->Send[j].Slot->refcount--;
2160 // Release source structure
2161 ALTHUNK_REMOVEENTRY(temp->source);
2162 memset(temp, 0, sizeof(ALsource));
2163 free(temp);
2165 Context->SourceCount = 0;