Avoid dereferencing a NULL buffer when unqueueing buffer 0
[openal-soft.git] / OpenAL32 / alSource.c
blobe7c51a6620cb25ac18e43a145076b4316f92b9db
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 if(ALBufferList->buffer)
1753 // Record name of buffer
1754 buffers[i] = ALBufferList->buffer->buffer;
1755 // Decrement buffer reference counter
1756 ALBufferList->buffer->refcount--;
1758 else
1759 buffers[i] = 0;
1761 // Release memory for buffer list item
1762 free(ALBufferList);
1763 ALSource->BuffersInQueue--;
1766 if(ALSource->state != AL_PLAYING)
1768 if(ALSource->queue)
1769 ALSource->Buffer = ALSource->queue->buffer;
1770 else
1771 ALSource->Buffer = NULL;
1774 ALSource->BuffersPlayed -= n;
1776 else
1778 // Some buffers can't be unqueue because they have not been processed
1779 alSetError(AL_INVALID_VALUE);
1782 else
1784 // Invalid Source Name
1785 alSetError(AL_INVALID_NAME);
1788 ProcessContext(Context);
1792 static ALvoid InitSourceParams(ALsource *pSource)
1794 pSource->flInnerAngle = 360.0f;
1795 pSource->flOuterAngle = 360.0f;
1796 pSource->flPitch = 1.0f;
1797 pSource->vPosition[0] = 0.0f;
1798 pSource->vPosition[1] = 0.0f;
1799 pSource->vPosition[2] = 0.0f;
1800 pSource->vOrientation[0] = 0.0f;
1801 pSource->vOrientation[1] = 0.0f;
1802 pSource->vOrientation[2] = 0.0f;
1803 pSource->vVelocity[0] = 0.0f;
1804 pSource->vVelocity[1] = 0.0f;
1805 pSource->vVelocity[2] = 0.0f;
1806 pSource->flRefDistance = 1.0f;
1807 pSource->flMaxDistance = FLT_MAX;
1808 pSource->flRollOffFactor = 1.0f;
1809 pSource->bLooping = AL_FALSE;
1810 pSource->flGain = 1.0f;
1811 pSource->flMinGain = 0.0f;
1812 pSource->flMaxGain = 1.0f;
1813 pSource->flOuterGain = 0.0f;
1814 pSource->OuterGainHF = 1.0f;
1816 pSource->DryGainHFAuto = AL_TRUE;
1817 pSource->WetGainAuto = AL_TRUE;
1818 pSource->WetGainHFAuto = AL_TRUE;
1819 pSource->AirAbsorptionFactor = 0.0f;
1820 pSource->RoomRolloffFactor = 0.0f;
1821 pSource->DopplerFactor = 1.0f;
1823 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1825 pSource->Resampler = DefaultResampler;
1827 pSource->state = AL_INITIAL;
1828 pSource->lSourceType = AL_UNDETERMINED;
1830 pSource->NeedsUpdate = AL_TRUE;
1832 pSource->Buffer = NULL;
1837 GetSourceOffset
1839 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1840 The offset is relative to the start of the queue (not the start of the current buffer)
1842 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen)
1844 ALbufferlistitem *pBufferList;
1845 ALbuffer *pBuffer;
1846 ALfloat flBufferFreq;
1847 ALint lChannels, lBytes;
1848 ALint readPos, writePos;
1849 ALenum eOriginalFormat;
1850 ALboolean bReturn = AL_TRUE;
1851 ALint lTotalBufferDataSize;
1852 ALuint i;
1854 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1856 pBuffer = pSource->Buffer;
1857 // Get Current Buffer Size and frequency (in milliseconds)
1858 flBufferFreq = (ALfloat)pBuffer->frequency;
1859 eOriginalFormat = pBuffer->eOriginalFormat;
1860 lChannels = aluChannelsFromFormat(pBuffer->format);
1861 lBytes = aluBytesFromFormat(pBuffer->format);
1863 // Get Current BytesPlayed
1864 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1865 // Add byte length of any processed buffers in the queue
1866 pBufferList = pSource->queue;
1867 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1869 readPos += pBufferList->buffer->size;
1870 pBufferList = pBufferList->next;
1873 if(pSource->state == AL_PLAYING)
1874 writePos = readPos + ((ALuint)(updateLen*flBufferFreq) * lChannels * lBytes);
1875 else
1876 writePos = readPos;
1878 lTotalBufferDataSize = 0;
1879 pBufferList = pSource->queue;
1880 while (pBufferList)
1882 if (pBufferList->buffer)
1883 lTotalBufferDataSize += pBufferList->buffer->size;
1884 pBufferList = pBufferList->next;
1887 if (pSource->bLooping)
1889 if(readPos < 0)
1890 readPos = 0;
1891 else
1892 readPos %= lTotalBufferDataSize;
1893 if(writePos < 0)
1894 writePos = 0;
1895 else
1896 writePos %= lTotalBufferDataSize;
1898 else
1900 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1901 if(readPos < 0)
1902 readPos = 0;
1903 else if(readPos > lTotalBufferDataSize)
1904 readPos = lTotalBufferDataSize;
1905 if(writePos < 0)
1906 writePos = 0;
1907 else if(writePos > lTotalBufferDataSize)
1908 writePos = lTotalBufferDataSize;
1911 switch (eName)
1913 case AL_SEC_OFFSET:
1914 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1915 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1916 break;
1917 case AL_SAMPLE_OFFSET:
1918 case AL_SAMPLE_RW_OFFSETS_EXT:
1919 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1920 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1921 break;
1922 case AL_BYTE_OFFSET:
1923 case AL_BYTE_RW_OFFSETS_EXT:
1924 // Take into account the original format of the Buffer
1925 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1926 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1928 // Round down to nearest ADPCM block
1929 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1930 if(pSource->state == AL_PLAYING)
1932 // Round up to nearest ADPCM block
1933 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1935 else
1936 pflOffset[1] = pflOffset[0];
1938 else if (eOriginalFormat == AL_FORMAT_REAR8)
1940 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1941 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1943 else if (eOriginalFormat == AL_FORMAT_REAR16)
1945 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1946 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1948 else if (eOriginalFormat == AL_FORMAT_REAR32)
1950 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1951 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1953 else
1955 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1956 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1957 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1959 break;
1962 else
1964 pflOffset[0] = 0.0f;
1965 pflOffset[1] = 0.0f;
1968 return bReturn;
1973 ApplyOffset
1975 Apply a playback offset to the Source. This function will update the queue (to correctly
1976 mark buffers as 'pending' or 'processed' depending upon the new offset.
1978 static ALboolean ApplyOffset(ALsource *pSource)
1980 ALbufferlistitem *pBufferList;
1981 ALbuffer *pBuffer;
1982 ALint lBufferSize, lTotalBufferSize;
1983 ALint lByteOffset;
1985 // Get true byte offset
1986 lByteOffset = GetByteOffset(pSource);
1988 // If the offset is invalid, don't apply it
1989 if(lByteOffset == -1)
1990 return AL_FALSE;
1992 // Sort out the queue (pending and processed states)
1993 pBufferList = pSource->queue;
1994 lTotalBufferSize = 0;
1995 pSource->BuffersPlayed = 0;
1997 while(pBufferList)
1999 pBuffer = pBufferList->buffer;
2000 lBufferSize = pBuffer ? pBuffer->size : 0;
2002 if(lTotalBufferSize+lBufferSize <= lByteOffset)
2004 // Offset is past this buffer so increment BuffersPlayed
2005 pSource->BuffersPlayed++;
2007 else if(lTotalBufferSize <= lByteOffset)
2009 // Offset is within this buffer
2010 // Set Current Buffer
2011 pSource->Buffer = pBufferList->buffer;
2013 // SW Mixer Positions are in Samples
2014 pSource->position = (lByteOffset - lTotalBufferSize) /
2015 aluBytesFromFormat(pBuffer->format) /
2016 aluChannelsFromFormat(pBuffer->format);
2017 break;
2020 // Increment the TotalBufferSize
2021 lTotalBufferSize += lBufferSize;
2023 // Move on to next buffer in the Queue
2024 pBufferList = pBufferList->next;
2027 return AL_TRUE;
2032 GetByteOffset
2034 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2035 offset supplied by the application). This takes into account the fact that the buffer format
2036 may have been modifed by AL (e.g 8bit samples are converted to float)
2038 static ALint GetByteOffset(ALsource *pSource)
2040 ALbuffer *pBuffer = NULL;
2041 ALbufferlistitem *pBufferList;
2042 ALfloat flBufferFreq;
2043 ALint lChannels, lBytes;
2044 ALint lByteOffset = -1;
2045 ALint lTotalBufferDataSize;
2046 ALenum OriginalFormat;
2048 // Find the first non-NULL Buffer in the Queue
2049 pBufferList = pSource->queue;
2050 while (pBufferList)
2052 if (pBufferList->buffer)
2054 pBuffer = pBufferList->buffer;
2055 break;
2057 pBufferList = pBufferList->next;
2060 if (pBuffer)
2062 flBufferFreq = ((ALfloat)pBuffer->frequency);
2063 lChannels = aluChannelsFromFormat(pBuffer->format);
2064 lBytes = aluBytesFromFormat(pBuffer->format);
2065 OriginalFormat = pBuffer->eOriginalFormat;
2067 // Determine the ByteOffset (and ensure it is block aligned)
2068 switch (pSource->lOffsetType)
2070 case AL_BYTE_OFFSET:
2071 // Take into consideration the original format
2072 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2073 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2075 // Round down to nearest ADPCM block
2076 lByteOffset = pSource->lOffset / (36 * lChannels);
2077 // Multiply by compression rate
2078 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2079 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2081 else if(OriginalFormat == AL_FORMAT_REAR8)
2083 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2084 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2086 else if(OriginalFormat == AL_FORMAT_REAR16)
2088 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2089 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2091 else if(OriginalFormat == AL_FORMAT_REAR32)
2093 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2094 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2096 else
2098 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2099 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2100 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2102 break;
2104 case AL_SAMPLE_OFFSET:
2105 lByteOffset = pSource->lOffset * lChannels * lBytes;
2106 break;
2108 case AL_SEC_OFFSET:
2109 // Note - lOffset is internally stored as Milliseconds
2110 lByteOffset = (ALint)(pSource->lOffset / 1000.0f * flBufferFreq);
2111 lByteOffset *= lChannels * lBytes;
2112 break;
2115 lTotalBufferDataSize = 0;
2116 pBufferList = pSource->queue;
2117 while (pBufferList)
2119 if (pBufferList->buffer)
2120 lTotalBufferDataSize += pBufferList->buffer->size;
2121 pBufferList = pBufferList->next;
2124 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2125 if (lByteOffset >= lTotalBufferDataSize)
2126 lByteOffset = -1;
2129 // Clear Offset
2130 pSource->lOffset = 0;
2132 return lByteOffset;
2136 ALvoid ReleaseALSources(ALCcontext *Context)
2138 ALuint j;
2140 while(Context->Source)
2142 ALsource *temp = Context->Source;
2143 Context->Source = temp->next;
2145 // For each buffer in the source's queue, decrement its reference counter and remove it
2146 while(temp->queue != NULL)
2148 ALbufferlistitem *ALBufferList = temp->queue;
2149 // Decrement buffer's reference counter
2150 if(ALBufferList->buffer != NULL)
2151 ALBufferList->buffer->refcount--;
2152 // Update queue to point to next element in list
2153 temp->queue = ALBufferList->next;
2154 // Release memory allocated for buffer list item
2155 free(ALBufferList);
2158 for(j = 0;j < MAX_SENDS;++j)
2160 if(temp->Send[j].Slot)
2161 temp->Send[j].Slot->refcount--;
2164 // Release source structure
2165 ALTHUNK_REMOVEENTRY(temp->source);
2166 memset(temp, 0, sizeof(ALsource));
2167 free(temp);
2169 Context->SourceCount = 0;