Minor corrections to the hrtf.txt
[openal-soft.git] / OpenAL32 / alSource.c
blobaf03985999958ef38afec1f232205f62a11b8135
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"
36 enum Resampler DefaultResampler = LinearResampler;
37 const ALsizei ResamplerPadding[ResamplerMax] = {
38 0, /* Point */
39 1, /* Linear */
40 2, /* Cubic */
42 const ALsizei ResamplerPrePadding[ResamplerMax] = {
43 0, /* Point */
44 0, /* Linear */
45 1, /* Cubic */
49 static ALvoid InitSourceParams(ALsource *Source);
50 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
51 static ALint GetSampleOffset(ALsource *Source);
54 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
56 ALCcontext *Context;
58 Context = GetContextRef();
59 if(!Context) return;
61 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
62 alSetError(Context, AL_INVALID_VALUE);
63 else
65 ALenum err;
66 ALsizei i;
68 // Add additional sources to the list
69 i = 0;
70 while(i < n)
72 ALsource *source = calloc(1, sizeof(ALsource));
73 if(!source)
75 alSetError(Context, AL_OUT_OF_MEMORY);
76 alDeleteSources(i, sources);
77 break;
79 InitSourceParams(source);
81 err = NewThunkEntry(&source->source);
82 if(err == AL_NO_ERROR)
83 err = InsertUIntMapEntry(&Context->SourceMap, source->source, source);
84 if(err != AL_NO_ERROR)
86 FreeThunkEntry(source->source);
87 memset(source, 0, sizeof(ALsource));
88 free(source);
90 alSetError(Context, err);
91 alDeleteSources(i, sources);
92 break;
95 sources[i++] = source->source;
99 ALCcontext_DecRef(Context);
103 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
105 ALCcontext *Context;
106 ALsource *Source;
107 ALsizei i, j;
108 ALbufferlistitem *BufferList;
110 Context = GetContextRef();
111 if(!Context) return;
113 if(n < 0)
114 alSetError(Context, AL_INVALID_VALUE);
115 else
117 // Check that all Sources are valid (and can therefore be deleted)
118 for(i = 0;i < n;i++)
120 if(LookupSource(Context, sources[i]) == NULL)
122 alSetError(Context, AL_INVALID_NAME);
123 n = 0;
124 break;
128 // All Sources are valid, and can be deleted
129 for(i = 0;i < n;i++)
131 ALsource **srclist, **srclistend;
133 // Remove Source from list of Sources
134 if((Source=RemoveSource(Context, sources[i])) == NULL)
135 continue;
137 FreeThunkEntry(Source->source);
139 LockContext(Context);
140 srclist = Context->ActiveSources;
141 srclistend = srclist + Context->ActiveSourceCount;
142 while(srclist != srclistend)
144 if(*srclist == Source)
146 Context->ActiveSourceCount--;
147 *srclist = *(--srclistend);
148 break;
150 srclist++;
152 UnlockContext(Context);
154 // For each buffer in the source's queue...
155 while(Source->queue != NULL)
157 BufferList = Source->queue;
158 Source->queue = BufferList->next;
160 if(BufferList->buffer != NULL)
161 DecrementRef(&BufferList->buffer->ref);
162 free(BufferList);
165 for(j = 0;j < MAX_SENDS;++j)
167 if(Source->Send[j].Slot)
168 DecrementRef(&Source->Send[j].Slot->ref);
169 Source->Send[j].Slot = NULL;
172 memset(Source,0,sizeof(ALsource));
173 free(Source);
177 ALCcontext_DecRef(Context);
181 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
183 ALCcontext *Context;
184 ALboolean result;
186 Context = GetContextRef();
187 if(!Context) return AL_FALSE;
189 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
191 ALCcontext_DecRef(Context);
193 return result;
197 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
199 ALCcontext *pContext;
200 ALsource *Source;
202 pContext = GetContextRef();
203 if(!pContext) return;
205 if((Source=LookupSource(pContext, source)) != NULL)
207 switch(eParam)
209 case AL_PITCH:
210 if(flValue >= 0.0f)
212 Source->flPitch = flValue;
213 Source->NeedsUpdate = AL_TRUE;
215 else
216 alSetError(pContext, AL_INVALID_VALUE);
217 break;
219 case AL_CONE_INNER_ANGLE:
220 if(flValue >= 0.0f && flValue <= 360.0f)
222 Source->flInnerAngle = flValue;
223 Source->NeedsUpdate = AL_TRUE;
225 else
226 alSetError(pContext, AL_INVALID_VALUE);
227 break;
229 case AL_CONE_OUTER_ANGLE:
230 if(flValue >= 0.0f && flValue <= 360.0f)
232 Source->flOuterAngle = flValue;
233 Source->NeedsUpdate = AL_TRUE;
235 else
236 alSetError(pContext, AL_INVALID_VALUE);
237 break;
239 case AL_GAIN:
240 if(flValue >= 0.0f)
242 Source->flGain = flValue;
243 Source->NeedsUpdate = AL_TRUE;
245 else
246 alSetError(pContext, AL_INVALID_VALUE);
247 break;
249 case AL_MAX_DISTANCE:
250 if(flValue >= 0.0f)
252 Source->flMaxDistance = flValue;
253 Source->NeedsUpdate = AL_TRUE;
255 else
256 alSetError(pContext, AL_INVALID_VALUE);
257 break;
259 case AL_ROLLOFF_FACTOR:
260 if(flValue >= 0.0f)
262 Source->flRollOffFactor = flValue;
263 Source->NeedsUpdate = AL_TRUE;
265 else
266 alSetError(pContext, AL_INVALID_VALUE);
267 break;
269 case AL_REFERENCE_DISTANCE:
270 if(flValue >= 0.0f)
272 Source->flRefDistance = flValue;
273 Source->NeedsUpdate = AL_TRUE;
275 else
276 alSetError(pContext, AL_INVALID_VALUE);
277 break;
279 case AL_MIN_GAIN:
280 if(flValue >= 0.0f && flValue <= 1.0f)
282 Source->flMinGain = flValue;
283 Source->NeedsUpdate = AL_TRUE;
285 else
286 alSetError(pContext, AL_INVALID_VALUE);
287 break;
289 case AL_MAX_GAIN:
290 if(flValue >= 0.0f && flValue <= 1.0f)
292 Source->flMaxGain = flValue;
293 Source->NeedsUpdate = AL_TRUE;
295 else
296 alSetError(pContext, AL_INVALID_VALUE);
297 break;
299 case AL_CONE_OUTER_GAIN:
300 if(flValue >= 0.0f && flValue <= 1.0f)
302 Source->flOuterGain = flValue;
303 Source->NeedsUpdate = AL_TRUE;
305 else
306 alSetError(pContext, AL_INVALID_VALUE);
307 break;
309 case AL_CONE_OUTER_GAINHF:
310 if(flValue >= 0.0f && flValue <= 1.0f)
312 Source->OuterGainHF = flValue;
313 Source->NeedsUpdate = AL_TRUE;
315 else
316 alSetError(pContext, AL_INVALID_VALUE);
317 break;
319 case AL_AIR_ABSORPTION_FACTOR:
320 if(flValue >= 0.0f && flValue <= 10.0f)
322 Source->AirAbsorptionFactor = flValue;
323 Source->NeedsUpdate = AL_TRUE;
325 else
326 alSetError(pContext, AL_INVALID_VALUE);
327 break;
329 case AL_ROOM_ROLLOFF_FACTOR:
330 if(flValue >= 0.0f && flValue <= 10.0f)
332 Source->RoomRolloffFactor = flValue;
333 Source->NeedsUpdate = AL_TRUE;
335 else
336 alSetError(pContext, AL_INVALID_VALUE);
337 break;
339 case AL_DOPPLER_FACTOR:
340 if(flValue >= 0.0f && flValue <= 1.0f)
342 Source->DopplerFactor = flValue;
343 Source->NeedsUpdate = AL_TRUE;
345 else
346 alSetError(pContext, AL_INVALID_VALUE);
347 break;
349 case AL_SEC_OFFSET:
350 case AL_SAMPLE_OFFSET:
351 case AL_BYTE_OFFSET:
352 if(flValue >= 0.0f)
354 LockContext(pContext);
355 Source->lOffsetType = eParam;
357 // Store Offset (convert Seconds into Milliseconds)
358 if(eParam == AL_SEC_OFFSET)
359 Source->lOffset = (ALint)(flValue * 1000.0f);
360 else
361 Source->lOffset = (ALint)flValue;
363 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
364 !pContext->DeferUpdates)
366 if(ApplyOffset(Source) == AL_FALSE)
367 alSetError(pContext, AL_INVALID_VALUE);
369 UnlockContext(pContext);
371 else
372 alSetError(pContext, AL_INVALID_VALUE);
373 break;
375 default:
376 alSetError(pContext, AL_INVALID_ENUM);
377 break;
380 else
382 // Invalid Source Name
383 alSetError(pContext, AL_INVALID_NAME);
386 ALCcontext_DecRef(pContext);
390 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
392 ALCcontext *pContext;
393 ALsource *Source;
395 pContext = GetContextRef();
396 if(!pContext) return;
398 if((Source=LookupSource(pContext, source)) != NULL)
400 switch(eParam)
402 case AL_POSITION:
403 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
405 LockContext(pContext);
406 Source->vPosition[0] = flValue1;
407 Source->vPosition[1] = flValue2;
408 Source->vPosition[2] = flValue3;
409 UnlockContext(pContext);
410 Source->NeedsUpdate = AL_TRUE;
412 else
413 alSetError(pContext, AL_INVALID_VALUE);
414 break;
416 case AL_VELOCITY:
417 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
419 LockContext(pContext);
420 Source->vVelocity[0] = flValue1;
421 Source->vVelocity[1] = flValue2;
422 Source->vVelocity[2] = flValue3;
423 UnlockContext(pContext);
424 Source->NeedsUpdate = AL_TRUE;
426 else
427 alSetError(pContext, AL_INVALID_VALUE);
428 break;
430 case AL_DIRECTION:
431 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
433 LockContext(pContext);
434 Source->vOrientation[0] = flValue1;
435 Source->vOrientation[1] = flValue2;
436 Source->vOrientation[2] = flValue3;
437 UnlockContext(pContext);
438 Source->NeedsUpdate = AL_TRUE;
440 else
441 alSetError(pContext, AL_INVALID_VALUE);
442 break;
444 default:
445 alSetError(pContext, AL_INVALID_ENUM);
446 break;
449 else
450 alSetError(pContext, AL_INVALID_NAME);
452 ALCcontext_DecRef(pContext);
456 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
458 ALCcontext *pContext;
460 if(pflValues)
462 switch(eParam)
464 case AL_PITCH:
465 case AL_CONE_INNER_ANGLE:
466 case AL_CONE_OUTER_ANGLE:
467 case AL_GAIN:
468 case AL_MAX_DISTANCE:
469 case AL_ROLLOFF_FACTOR:
470 case AL_REFERENCE_DISTANCE:
471 case AL_MIN_GAIN:
472 case AL_MAX_GAIN:
473 case AL_CONE_OUTER_GAIN:
474 case AL_CONE_OUTER_GAINHF:
475 case AL_SEC_OFFSET:
476 case AL_SAMPLE_OFFSET:
477 case AL_BYTE_OFFSET:
478 case AL_AIR_ABSORPTION_FACTOR:
479 case AL_ROOM_ROLLOFF_FACTOR:
480 alSourcef(source, eParam, pflValues[0]);
481 return;
483 case AL_POSITION:
484 case AL_VELOCITY:
485 case AL_DIRECTION:
486 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
487 return;
491 pContext = GetContextRef();
492 if(!pContext) return;
494 if(pflValues)
496 if(LookupSource(pContext, source) != NULL)
498 switch(eParam)
500 default:
501 alSetError(pContext, AL_INVALID_ENUM);
502 break;
505 else
506 alSetError(pContext, AL_INVALID_NAME);
508 else
509 alSetError(pContext, AL_INVALID_VALUE);
511 ALCcontext_DecRef(pContext);
515 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
517 ALCcontext *pContext;
518 ALsource *Source;
519 ALbufferlistitem *BufferListItem;
521 switch(eParam)
523 case AL_MAX_DISTANCE:
524 case AL_ROLLOFF_FACTOR:
525 case AL_CONE_INNER_ANGLE:
526 case AL_CONE_OUTER_ANGLE:
527 case AL_REFERENCE_DISTANCE:
528 alSourcef(source, eParam, (ALfloat)lValue);
529 return;
532 pContext = GetContextRef();
533 if(!pContext) return;
535 if((Source=LookupSource(pContext, source)) != NULL)
537 ALCdevice *device = pContext->Device;
539 switch(eParam)
541 case AL_SOURCE_RELATIVE:
542 if(lValue == AL_FALSE || lValue == AL_TRUE)
544 Source->bHeadRelative = (ALboolean)lValue;
545 Source->NeedsUpdate = AL_TRUE;
547 else
548 alSetError(pContext, AL_INVALID_VALUE);
549 break;
551 case AL_LOOPING:
552 if(lValue == AL_FALSE || lValue == AL_TRUE)
553 Source->bLooping = (ALboolean)lValue;
554 else
555 alSetError(pContext, AL_INVALID_VALUE);
556 break;
558 case AL_BUFFER:
559 LockContext(pContext);
560 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
562 ALbufferlistitem *oldlist;
563 ALbuffer *buffer = NULL;
565 if(lValue == 0 || (buffer=LookupBuffer(device, lValue)) != NULL)
567 Source->BuffersInQueue = 0;
568 Source->BuffersPlayed = 0;
570 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
571 if(buffer != NULL)
573 // Source is now in STATIC mode
574 Source->lSourceType = AL_STATIC;
576 // Add the selected buffer to the queue
577 BufferListItem = malloc(sizeof(ALbufferlistitem));
578 BufferListItem->buffer = buffer;
579 BufferListItem->next = NULL;
580 BufferListItem->prev = NULL;
581 // Increment reference counter for buffer
582 IncrementRef(&buffer->ref);
584 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
585 Source->BuffersInQueue = 1;
587 ReadLock(&buffer->lock);
588 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
589 Source->SampleSize = BytesFromFmt(buffer->FmtType);
590 ReadUnlock(&buffer->lock);
591 if(buffer->FmtChannels == FmtMono)
592 Source->Update = CalcSourceParams;
593 else
594 Source->Update = CalcNonAttnSourceParams;
595 Source->NeedsUpdate = AL_TRUE;
597 else
599 // Source is now in UNDETERMINED mode
600 Source->lSourceType = AL_UNDETERMINED;
601 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
604 // Delete all previous elements in the queue
605 while(oldlist != NULL)
607 BufferListItem = oldlist;
608 oldlist = BufferListItem->next;
610 if(BufferListItem->buffer)
611 DecrementRef(&BufferListItem->buffer->ref);
612 free(BufferListItem);
615 else
616 alSetError(pContext, AL_INVALID_VALUE);
618 else
619 alSetError(pContext, AL_INVALID_OPERATION);
620 UnlockContext(pContext);
621 break;
623 case AL_SOURCE_STATE:
624 // Query only
625 alSetError(pContext, AL_INVALID_OPERATION);
626 break;
628 case AL_SEC_OFFSET:
629 case AL_SAMPLE_OFFSET:
630 case AL_BYTE_OFFSET:
631 if(lValue >= 0)
633 LockContext(pContext);
634 Source->lOffsetType = eParam;
636 // Store Offset (convert Seconds into Milliseconds)
637 if(eParam == AL_SEC_OFFSET)
638 Source->lOffset = lValue * 1000;
639 else
640 Source->lOffset = lValue;
642 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
643 !pContext->DeferUpdates)
645 if(ApplyOffset(Source) == AL_FALSE)
646 alSetError(pContext, AL_INVALID_VALUE);
648 UnlockContext(pContext);
650 else
651 alSetError(pContext, AL_INVALID_VALUE);
652 break;
654 case AL_DIRECT_FILTER: {
655 ALfilter *filter = NULL;
657 if(lValue == 0 || (filter=LookupFilter(pContext->Device, lValue)) != NULL)
659 LockContext(pContext);
660 if(!filter)
662 Source->DirectGain = 1.0f;
663 Source->DirectGainHF = 1.0f;
665 else
667 Source->DirectGain = filter->Gain;
668 Source->DirectGainHF = filter->GainHF;
670 UnlockContext(pContext);
671 Source->NeedsUpdate = AL_TRUE;
673 else
674 alSetError(pContext, AL_INVALID_VALUE);
675 } break;
677 case AL_DIRECT_FILTER_GAINHF_AUTO:
678 if(lValue == AL_TRUE || lValue == AL_FALSE)
680 Source->DryGainHFAuto = lValue;
681 Source->NeedsUpdate = AL_TRUE;
683 else
684 alSetError(pContext, AL_INVALID_VALUE);
685 break;
687 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
688 if(lValue == AL_TRUE || lValue == AL_FALSE)
690 Source->WetGainAuto = lValue;
691 Source->NeedsUpdate = AL_TRUE;
693 else
694 alSetError(pContext, AL_INVALID_VALUE);
695 break;
697 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
698 if(lValue == AL_TRUE || lValue == AL_FALSE)
700 Source->WetGainHFAuto = lValue;
701 Source->NeedsUpdate = AL_TRUE;
703 else
704 alSetError(pContext, AL_INVALID_VALUE);
705 break;
707 case AL_DIRECT_CHANNELS_SOFT:
708 if(lValue == AL_TRUE || lValue == AL_FALSE)
710 Source->DirectChannels = lValue;
711 Source->NeedsUpdate = AL_TRUE;
713 else
714 alSetError(pContext, AL_INVALID_VALUE);
715 break;
717 case AL_DISTANCE_MODEL:
718 if(lValue == AL_NONE ||
719 lValue == AL_INVERSE_DISTANCE ||
720 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
721 lValue == AL_LINEAR_DISTANCE ||
722 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
723 lValue == AL_EXPONENT_DISTANCE ||
724 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
726 Source->DistanceModel = lValue;
727 if(pContext->SourceDistanceModel)
728 Source->NeedsUpdate = AL_TRUE;
730 else
731 alSetError(pContext, AL_INVALID_VALUE);
732 break;
734 default:
735 alSetError(pContext, AL_INVALID_ENUM);
736 break;
739 else
740 alSetError(pContext, AL_INVALID_NAME);
742 ALCcontext_DecRef(pContext);
746 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
748 ALCcontext *pContext;
749 ALsource *Source;
751 switch(eParam)
753 case AL_POSITION:
754 case AL_VELOCITY:
755 case AL_DIRECTION:
756 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
757 return;
760 pContext = GetContextRef();
761 if(!pContext) return;
763 if((Source=LookupSource(pContext, source)) != NULL)
765 ALCdevice *device = pContext->Device;
767 switch(eParam)
769 case AL_AUXILIARY_SEND_FILTER: {
770 ALeffectslot *ALEffectSlot = NULL;
771 ALfilter *ALFilter = NULL;
773 LockContext(pContext);
774 if((ALuint)lValue2 < device->NumAuxSends &&
775 (lValue1 == 0 || (ALEffectSlot=LookupEffectSlot(pContext, lValue1)) != NULL) &&
776 (lValue3 == 0 || (ALFilter=LookupFilter(device, lValue3)) != NULL))
778 /* Release refcount on the previous slot, and add one for
779 * the new slot */
780 if(ALEffectSlot) IncrementRef(&ALEffectSlot->ref);
781 ALEffectSlot = ExchangePtr((XchgPtr*)&Source->Send[lValue2].Slot, ALEffectSlot);
782 if(ALEffectSlot) DecrementRef(&ALEffectSlot->ref);
784 if(!ALFilter)
786 /* Disable filter */
787 Source->Send[lValue2].WetGain = 1.0f;
788 Source->Send[lValue2].WetGainHF = 1.0f;
790 else
792 Source->Send[lValue2].WetGain = ALFilter->Gain;
793 Source->Send[lValue2].WetGainHF = ALFilter->GainHF;
795 Source->NeedsUpdate = AL_TRUE;
797 else
798 alSetError(pContext, AL_INVALID_VALUE);
799 UnlockContext(pContext);
800 } break;
802 default:
803 alSetError(pContext, AL_INVALID_ENUM);
804 break;
807 else
808 alSetError(pContext, AL_INVALID_NAME);
810 ALCcontext_DecRef(pContext);
814 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
816 ALCcontext *pContext;
818 if(plValues)
820 switch(eParam)
822 case AL_SOURCE_RELATIVE:
823 case AL_CONE_INNER_ANGLE:
824 case AL_CONE_OUTER_ANGLE:
825 case AL_LOOPING:
826 case AL_BUFFER:
827 case AL_SOURCE_STATE:
828 case AL_SEC_OFFSET:
829 case AL_SAMPLE_OFFSET:
830 case AL_BYTE_OFFSET:
831 case AL_MAX_DISTANCE:
832 case AL_ROLLOFF_FACTOR:
833 case AL_REFERENCE_DISTANCE:
834 case AL_DIRECT_FILTER:
835 case AL_DIRECT_FILTER_GAINHF_AUTO:
836 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
837 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
838 case AL_DISTANCE_MODEL:
839 case AL_DIRECT_CHANNELS_SOFT:
840 alSourcei(source, eParam, plValues[0]);
841 return;
843 case AL_POSITION:
844 case AL_VELOCITY:
845 case AL_DIRECTION:
846 case AL_AUXILIARY_SEND_FILTER:
847 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
848 return;
852 pContext = GetContextRef();
853 if(!pContext) return;
855 if(plValues)
857 if(LookupSource(pContext, source) != NULL)
859 switch(eParam)
861 default:
862 alSetError(pContext, AL_INVALID_ENUM);
863 break;
866 else
867 alSetError(pContext, AL_INVALID_NAME);
869 else
870 alSetError(pContext, AL_INVALID_VALUE);
872 ALCcontext_DecRef(pContext);
876 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
878 ALCcontext *pContext;
879 ALsource *Source;
880 ALdouble Offsets[2];
881 ALdouble updateLen;
883 pContext = GetContextRef();
884 if(!pContext) return;
886 if(pflValue)
888 if((Source=LookupSource(pContext, source)) != NULL)
890 switch(eParam)
892 case AL_PITCH:
893 *pflValue = Source->flPitch;
894 break;
896 case AL_GAIN:
897 *pflValue = Source->flGain;
898 break;
900 case AL_MIN_GAIN:
901 *pflValue = Source->flMinGain;
902 break;
904 case AL_MAX_GAIN:
905 *pflValue = Source->flMaxGain;
906 break;
908 case AL_MAX_DISTANCE:
909 *pflValue = Source->flMaxDistance;
910 break;
912 case AL_ROLLOFF_FACTOR:
913 *pflValue = Source->flRollOffFactor;
914 break;
916 case AL_CONE_OUTER_GAIN:
917 *pflValue = Source->flOuterGain;
918 break;
920 case AL_CONE_OUTER_GAINHF:
921 *pflValue = Source->OuterGainHF;
922 break;
924 case AL_SEC_OFFSET:
925 case AL_SAMPLE_OFFSET:
926 case AL_BYTE_OFFSET:
927 LockContext(pContext);
928 updateLen = (ALdouble)pContext->Device->UpdateSize /
929 pContext->Device->Frequency;
930 GetSourceOffset(Source, eParam, Offsets, updateLen);
931 UnlockContext(pContext);
932 *pflValue = (ALfloat)Offsets[0];
933 break;
935 case AL_CONE_INNER_ANGLE:
936 *pflValue = Source->flInnerAngle;
937 break;
939 case AL_CONE_OUTER_ANGLE:
940 *pflValue = Source->flOuterAngle;
941 break;
943 case AL_REFERENCE_DISTANCE:
944 *pflValue = Source->flRefDistance;
945 break;
947 case AL_AIR_ABSORPTION_FACTOR:
948 *pflValue = Source->AirAbsorptionFactor;
949 break;
951 case AL_ROOM_ROLLOFF_FACTOR:
952 *pflValue = Source->RoomRolloffFactor;
953 break;
955 case AL_DOPPLER_FACTOR:
956 *pflValue = Source->DopplerFactor;
957 break;
959 default:
960 alSetError(pContext, AL_INVALID_ENUM);
961 break;
964 else
965 alSetError(pContext, AL_INVALID_NAME);
967 else
968 alSetError(pContext, AL_INVALID_VALUE);
970 ALCcontext_DecRef(pContext);
974 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
976 ALCcontext *pContext;
977 ALsource *Source;
979 pContext = GetContextRef();
980 if(!pContext) return;
982 if(pflValue1 && pflValue2 && pflValue3)
984 if((Source=LookupSource(pContext, source)) != NULL)
986 switch(eParam)
988 case AL_POSITION:
989 LockContext(pContext);
990 *pflValue1 = Source->vPosition[0];
991 *pflValue2 = Source->vPosition[1];
992 *pflValue3 = Source->vPosition[2];
993 UnlockContext(pContext);
994 break;
996 case AL_VELOCITY:
997 LockContext(pContext);
998 *pflValue1 = Source->vVelocity[0];
999 *pflValue2 = Source->vVelocity[1];
1000 *pflValue3 = Source->vVelocity[2];
1001 UnlockContext(pContext);
1002 break;
1004 case AL_DIRECTION:
1005 LockContext(pContext);
1006 *pflValue1 = Source->vOrientation[0];
1007 *pflValue2 = Source->vOrientation[1];
1008 *pflValue3 = Source->vOrientation[2];
1009 UnlockContext(pContext);
1010 break;
1012 default:
1013 alSetError(pContext, AL_INVALID_ENUM);
1014 break;
1017 else
1018 alSetError(pContext, AL_INVALID_NAME);
1020 else
1021 alSetError(pContext, AL_INVALID_VALUE);
1023 ALCcontext_DecRef(pContext);
1027 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1029 ALCcontext *pContext;
1030 ALsource *Source;
1031 ALdouble Offsets[2];
1032 ALdouble updateLen;
1034 switch(eParam)
1036 case AL_PITCH:
1037 case AL_GAIN:
1038 case AL_MIN_GAIN:
1039 case AL_MAX_GAIN:
1040 case AL_MAX_DISTANCE:
1041 case AL_ROLLOFF_FACTOR:
1042 case AL_DOPPLER_FACTOR:
1043 case AL_CONE_OUTER_GAIN:
1044 case AL_SEC_OFFSET:
1045 case AL_SAMPLE_OFFSET:
1046 case AL_BYTE_OFFSET:
1047 case AL_CONE_INNER_ANGLE:
1048 case AL_CONE_OUTER_ANGLE:
1049 case AL_REFERENCE_DISTANCE:
1050 case AL_CONE_OUTER_GAINHF:
1051 case AL_AIR_ABSORPTION_FACTOR:
1052 case AL_ROOM_ROLLOFF_FACTOR:
1053 alGetSourcef(source, eParam, pflValues);
1054 return;
1056 case AL_POSITION:
1057 case AL_VELOCITY:
1058 case AL_DIRECTION:
1059 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1060 return;
1063 pContext = GetContextRef();
1064 if(!pContext) return;
1066 if(pflValues)
1068 if((Source=LookupSource(pContext, source)) != NULL)
1070 switch(eParam)
1072 case AL_SAMPLE_RW_OFFSETS_SOFT:
1073 case AL_BYTE_RW_OFFSETS_SOFT:
1074 LockContext(pContext);
1075 updateLen = (ALdouble)pContext->Device->UpdateSize /
1076 pContext->Device->Frequency;
1077 GetSourceOffset(Source, eParam, Offsets, updateLen);
1078 UnlockContext(pContext);
1079 pflValues[0] = (ALfloat)Offsets[0];
1080 pflValues[1] = (ALfloat)Offsets[1];
1081 break;
1083 default:
1084 alSetError(pContext, AL_INVALID_ENUM);
1085 break;
1088 else
1089 alSetError(pContext, AL_INVALID_NAME);
1091 else
1092 alSetError(pContext, AL_INVALID_VALUE);
1094 ALCcontext_DecRef(pContext);
1098 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1100 ALbufferlistitem *BufferList;
1101 ALCcontext *pContext;
1102 ALsource *Source;
1103 ALdouble Offsets[2];
1104 ALdouble updateLen;
1106 pContext = GetContextRef();
1107 if(!pContext) return;
1109 if(plValue)
1111 if((Source=LookupSource(pContext, source)) != NULL)
1113 switch(eParam)
1115 case AL_MAX_DISTANCE:
1116 *plValue = (ALint)Source->flMaxDistance;
1117 break;
1119 case AL_ROLLOFF_FACTOR:
1120 *plValue = (ALint)Source->flRollOffFactor;
1121 break;
1123 case AL_REFERENCE_DISTANCE:
1124 *plValue = (ALint)Source->flRefDistance;
1125 break;
1127 case AL_SOURCE_RELATIVE:
1128 *plValue = Source->bHeadRelative;
1129 break;
1131 case AL_CONE_INNER_ANGLE:
1132 *plValue = (ALint)Source->flInnerAngle;
1133 break;
1135 case AL_CONE_OUTER_ANGLE:
1136 *plValue = (ALint)Source->flOuterAngle;
1137 break;
1139 case AL_LOOPING:
1140 *plValue = Source->bLooping;
1141 break;
1143 case AL_BUFFER:
1144 LockContext(pContext);
1145 BufferList = Source->queue;
1146 if(Source->lSourceType != AL_STATIC)
1148 ALuint i = Source->BuffersPlayed;
1149 while(i > 0)
1151 BufferList = BufferList->next;
1152 i--;
1155 *plValue = ((BufferList && BufferList->buffer) ?
1156 BufferList->buffer->buffer : 0);
1157 UnlockContext(pContext);
1158 break;
1160 case AL_SOURCE_STATE:
1161 *plValue = Source->state;
1162 break;
1164 case AL_BUFFERS_QUEUED:
1165 *plValue = Source->BuffersInQueue;
1166 break;
1168 case AL_BUFFERS_PROCESSED:
1169 LockContext(pContext);
1170 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1172 /* Buffers on a looping source are in a perpetual state
1173 * of PENDING, so don't report any as PROCESSED */
1174 *plValue = 0;
1176 else
1177 *plValue = Source->BuffersPlayed;
1178 UnlockContext(pContext);
1179 break;
1181 case AL_SOURCE_TYPE:
1182 *plValue = Source->lSourceType;
1183 break;
1185 case AL_SEC_OFFSET:
1186 case AL_SAMPLE_OFFSET:
1187 case AL_BYTE_OFFSET:
1188 LockContext(pContext);
1189 updateLen = (ALdouble)pContext->Device->UpdateSize /
1190 pContext->Device->Frequency;
1191 GetSourceOffset(Source, eParam, Offsets, updateLen);
1192 UnlockContext(pContext);
1193 *plValue = (ALint)Offsets[0];
1194 break;
1196 case AL_DIRECT_FILTER_GAINHF_AUTO:
1197 *plValue = Source->DryGainHFAuto;
1198 break;
1200 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1201 *plValue = Source->WetGainAuto;
1202 break;
1204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1205 *plValue = Source->WetGainHFAuto;
1206 break;
1208 case AL_DOPPLER_FACTOR:
1209 *plValue = (ALint)Source->DopplerFactor;
1210 break;
1212 case AL_DIRECT_CHANNELS_SOFT:
1213 *plValue = Source->DirectChannels;
1214 break;
1216 case AL_DISTANCE_MODEL:
1217 *plValue = Source->DistanceModel;
1218 break;
1220 default:
1221 alSetError(pContext, AL_INVALID_ENUM);
1222 break;
1225 else
1226 alSetError(pContext, AL_INVALID_NAME);
1228 else
1229 alSetError(pContext, AL_INVALID_VALUE);
1231 ALCcontext_DecRef(pContext);
1235 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1237 ALCcontext *pContext;
1238 ALsource *Source;
1240 pContext = GetContextRef();
1241 if(!pContext) return;
1243 if(plValue1 && plValue2 && plValue3)
1245 if((Source=LookupSource(pContext, source)) != NULL)
1247 switch(eParam)
1249 case AL_POSITION:
1250 LockContext(pContext);
1251 *plValue1 = (ALint)Source->vPosition[0];
1252 *plValue2 = (ALint)Source->vPosition[1];
1253 *plValue3 = (ALint)Source->vPosition[2];
1254 UnlockContext(pContext);
1255 break;
1257 case AL_VELOCITY:
1258 LockContext(pContext);
1259 *plValue1 = (ALint)Source->vVelocity[0];
1260 *plValue2 = (ALint)Source->vVelocity[1];
1261 *plValue3 = (ALint)Source->vVelocity[2];
1262 UnlockContext(pContext);
1263 break;
1265 case AL_DIRECTION:
1266 LockContext(pContext);
1267 *plValue1 = (ALint)Source->vOrientation[0];
1268 *plValue2 = (ALint)Source->vOrientation[1];
1269 *plValue3 = (ALint)Source->vOrientation[2];
1270 UnlockContext(pContext);
1271 break;
1273 default:
1274 alSetError(pContext, AL_INVALID_ENUM);
1275 break;
1278 else
1279 alSetError(pContext, AL_INVALID_NAME);
1281 else
1282 alSetError(pContext, AL_INVALID_VALUE);
1284 ALCcontext_DecRef(pContext);
1288 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1290 ALCcontext *pContext;
1291 ALsource *Source;
1292 ALdouble Offsets[2];
1293 ALdouble updateLen;
1295 switch(eParam)
1297 case AL_SOURCE_RELATIVE:
1298 case AL_CONE_INNER_ANGLE:
1299 case AL_CONE_OUTER_ANGLE:
1300 case AL_LOOPING:
1301 case AL_BUFFER:
1302 case AL_SOURCE_STATE:
1303 case AL_BUFFERS_QUEUED:
1304 case AL_BUFFERS_PROCESSED:
1305 case AL_SEC_OFFSET:
1306 case AL_SAMPLE_OFFSET:
1307 case AL_BYTE_OFFSET:
1308 case AL_MAX_DISTANCE:
1309 case AL_ROLLOFF_FACTOR:
1310 case AL_DOPPLER_FACTOR:
1311 case AL_REFERENCE_DISTANCE:
1312 case AL_SOURCE_TYPE:
1313 case AL_DIRECT_FILTER:
1314 case AL_DIRECT_FILTER_GAINHF_AUTO:
1315 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1316 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1317 case AL_DISTANCE_MODEL:
1318 case AL_DIRECT_CHANNELS_SOFT:
1319 alGetSourcei(source, eParam, plValues);
1320 return;
1322 case AL_POSITION:
1323 case AL_VELOCITY:
1324 case AL_DIRECTION:
1325 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1326 return;
1329 pContext = GetContextRef();
1330 if(!pContext) return;
1332 if(plValues)
1334 if((Source=LookupSource(pContext, source)) != NULL)
1336 switch(eParam)
1338 case AL_SAMPLE_RW_OFFSETS_SOFT:
1339 case AL_BYTE_RW_OFFSETS_SOFT:
1340 LockContext(pContext);
1341 updateLen = (ALdouble)pContext->Device->UpdateSize /
1342 pContext->Device->Frequency;
1343 GetSourceOffset(Source, eParam, Offsets, updateLen);
1344 UnlockContext(pContext);
1345 plValues[0] = (ALint)Offsets[0];
1346 plValues[1] = (ALint)Offsets[1];
1347 break;
1349 default:
1350 alSetError(pContext, AL_INVALID_ENUM);
1351 break;
1354 else
1355 alSetError(pContext, AL_INVALID_NAME);
1357 else
1358 alSetError(pContext, AL_INVALID_VALUE);
1360 ALCcontext_DecRef(pContext);
1364 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1366 alSourcePlayv(1, &source);
1369 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1371 ALCcontext *Context;
1372 ALsource *Source;
1373 ALsizei i;
1375 Context = GetContextRef();
1376 if(!Context) return;
1378 if(n < 0)
1380 alSetError(Context, AL_INVALID_VALUE);
1381 goto done;
1383 if(n > 0 && !sources)
1385 alSetError(Context, AL_INVALID_VALUE);
1386 goto done;
1389 // Check that all the Sources are valid
1390 for(i = 0;i < n;i++)
1392 if(!LookupSource(Context, sources[i]))
1394 alSetError(Context, AL_INVALID_NAME);
1395 goto done;
1399 LockContext(Context);
1400 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1402 void *temp = NULL;
1403 ALsizei newcount;
1405 newcount = Context->MaxActiveSources << 1;
1406 if(newcount > 0)
1407 temp = realloc(Context->ActiveSources,
1408 sizeof(*Context->ActiveSources) * newcount);
1409 if(!temp)
1411 UnlockContext(Context);
1412 alSetError(Context, AL_OUT_OF_MEMORY);
1413 goto done;
1416 Context->ActiveSources = temp;
1417 Context->MaxActiveSources = newcount;
1420 for(i = 0;i < n;i++)
1422 Source = LookupSource(Context, sources[i]);
1423 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1424 else SetSourceState(Source, Context, AL_PLAYING);
1426 UnlockContext(Context);
1428 done:
1429 ALCcontext_DecRef(Context);
1432 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1434 alSourcePausev(1, &source);
1437 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1439 ALCcontext *Context;
1440 ALsource *Source;
1441 ALsizei i;
1443 Context = GetContextRef();
1444 if(!Context) return;
1446 if(n < 0)
1448 alSetError(Context, AL_INVALID_VALUE);
1449 goto done;
1451 if(n > 0 && !sources)
1453 alSetError(Context, AL_INVALID_VALUE);
1454 goto done;
1457 // Check all the Sources are valid
1458 for(i = 0;i < n;i++)
1460 if(!LookupSource(Context, sources[i]))
1462 alSetError(Context, AL_INVALID_NAME);
1463 goto done;
1467 LockContext(Context);
1468 for(i = 0;i < n;i++)
1470 Source = LookupSource(Context, sources[i]);
1471 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1472 else SetSourceState(Source, Context, AL_PAUSED);
1474 UnlockContext(Context);
1476 done:
1477 ALCcontext_DecRef(Context);
1480 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1482 alSourceStopv(1, &source);
1485 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1487 ALCcontext *Context;
1488 ALsource *Source;
1489 ALsizei i;
1491 Context = GetContextRef();
1492 if(!Context) return;
1494 if(n < 0)
1496 alSetError(Context, AL_INVALID_VALUE);
1497 goto done;
1499 if(n > 0 && !sources)
1501 alSetError(Context, AL_INVALID_VALUE);
1502 goto done;
1505 // Check all the Sources are valid
1506 for(i = 0;i < n;i++)
1508 if(!LookupSource(Context, sources[i]))
1510 alSetError(Context, AL_INVALID_NAME);
1511 goto done;
1515 LockContext(Context);
1516 for(i = 0;i < n;i++)
1518 Source = LookupSource(Context, sources[i]);
1519 Source->new_state = AL_NONE;
1520 SetSourceState(Source, Context, AL_STOPPED);
1522 UnlockContext(Context);
1524 done:
1525 ALCcontext_DecRef(Context);
1528 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1530 alSourceRewindv(1, &source);
1533 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1535 ALCcontext *Context;
1536 ALsource *Source;
1537 ALsizei i;
1539 Context = GetContextRef();
1540 if(!Context) return;
1542 if(n < 0)
1544 alSetError(Context, AL_INVALID_VALUE);
1545 goto done;
1547 if(n > 0 && !sources)
1549 alSetError(Context, AL_INVALID_VALUE);
1550 goto done;
1553 // Check all the Sources are valid
1554 for(i = 0;i < n;i++)
1556 if(!LookupSource(Context, sources[i]))
1558 alSetError(Context, AL_INVALID_NAME);
1559 goto done;
1563 LockContext(Context);
1564 for(i = 0;i < n;i++)
1566 Source = LookupSource(Context, sources[i]);
1567 Source->new_state = AL_NONE;
1568 SetSourceState(Source, Context, AL_INITIAL);
1570 UnlockContext(Context);
1572 done:
1573 ALCcontext_DecRef(Context);
1577 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1579 ALCcontext *Context;
1580 ALCdevice *device;
1581 ALsource *Source;
1582 ALsizei i;
1583 ALbufferlistitem *BufferListStart = NULL;
1584 ALbufferlistitem *BufferList;
1585 ALbuffer *BufferFmt;
1587 if(n == 0)
1588 return;
1590 Context = GetContextRef();
1591 if(!Context) return;
1593 if(n < 0)
1595 alSetError(Context, AL_INVALID_VALUE);
1596 goto error;
1599 // Check that all buffers are valid or zero and that the source is valid
1601 // Check that this is a valid source
1602 if((Source=LookupSource(Context, source)) == NULL)
1604 alSetError(Context, AL_INVALID_NAME);
1605 goto error;
1608 LockContext(Context);
1609 // Check that this is not a STATIC Source
1610 if(Source->lSourceType == AL_STATIC)
1612 UnlockContext(Context);
1613 // Invalid Source Type (can't queue on a Static Source)
1614 alSetError(Context, AL_INVALID_OPERATION);
1615 goto error;
1618 device = Context->Device;
1620 BufferFmt = NULL;
1622 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1623 BufferList = Source->queue;
1624 while(BufferList)
1626 if(BufferList->buffer)
1628 BufferFmt = BufferList->buffer;
1629 break;
1631 BufferList = BufferList->next;
1634 for(i = 0;i < n;i++)
1636 ALbuffer *buffer = NULL;
1637 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1639 UnlockContext(Context);
1640 alSetError(Context, AL_INVALID_NAME);
1641 goto error;
1644 if(!BufferListStart)
1646 BufferListStart = malloc(sizeof(ALbufferlistitem));
1647 BufferListStart->buffer = buffer;
1648 BufferListStart->next = NULL;
1649 BufferListStart->prev = NULL;
1650 BufferList = BufferListStart;
1652 else
1654 BufferList->next = malloc(sizeof(ALbufferlistitem));
1655 BufferList->next->buffer = buffer;
1656 BufferList->next->next = NULL;
1657 BufferList->next->prev = BufferList;
1658 BufferList = BufferList->next;
1660 if(!buffer) continue;
1662 // Increment reference counter for buffer
1663 IncrementRef(&buffer->ref);
1664 ReadLock(&buffer->lock);
1665 if(BufferFmt == NULL)
1667 BufferFmt = buffer;
1669 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1670 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1671 if(buffer->FmtChannels == FmtMono)
1672 Source->Update = CalcSourceParams;
1673 else
1674 Source->Update = CalcNonAttnSourceParams;
1676 Source->NeedsUpdate = AL_TRUE;
1678 else if(BufferFmt->Frequency != buffer->Frequency ||
1679 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1680 BufferFmt->OriginalType != buffer->OriginalType)
1682 ReadUnlock(&buffer->lock);
1683 UnlockContext(Context);
1684 alSetError(Context, AL_INVALID_OPERATION);
1685 goto error;
1687 ReadUnlock(&buffer->lock);
1690 // Change Source Type
1691 Source->lSourceType = AL_STREAMING;
1693 if(Source->queue == NULL)
1694 Source->queue = BufferListStart;
1695 else
1697 // Find end of queue
1698 BufferList = Source->queue;
1699 while(BufferList->next != NULL)
1700 BufferList = BufferList->next;
1702 BufferListStart->prev = BufferList;
1703 BufferList->next = BufferListStart;
1706 // Update number of buffers in queue
1707 Source->BuffersInQueue += n;
1709 UnlockContext(Context);
1710 ALCcontext_DecRef(Context);
1711 return;
1713 error:
1714 while(BufferListStart)
1716 BufferList = BufferListStart;
1717 BufferListStart = BufferList->next;
1719 if(BufferList->buffer)
1720 DecrementRef(&BufferList->buffer->ref);
1721 free(BufferList);
1723 ALCcontext_DecRef(Context);
1727 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1728 // an array of buffer IDs that are to be filled with the names of the buffers removed
1729 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1731 ALCcontext *Context;
1732 ALsource *Source;
1733 ALsizei i;
1734 ALbufferlistitem *BufferList;
1736 if(n == 0)
1737 return;
1739 Context = GetContextRef();
1740 if(!Context) return;
1742 if(n < 0)
1744 alSetError(Context, AL_INVALID_VALUE);
1745 goto done;
1748 if((Source=LookupSource(Context, source)) == NULL)
1750 alSetError(Context, AL_INVALID_NAME);
1751 goto done;
1754 LockContext(Context);
1755 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1756 (ALuint)n > Source->BuffersPlayed)
1758 UnlockContext(Context);
1759 // Some buffers can't be unqueue because they have not been processed
1760 alSetError(Context, AL_INVALID_VALUE);
1761 goto done;
1764 for(i = 0;i < n;i++)
1766 BufferList = Source->queue;
1767 Source->queue = BufferList->next;
1768 Source->BuffersInQueue--;
1769 Source->BuffersPlayed--;
1771 if(BufferList->buffer)
1773 // Record name of buffer
1774 buffers[i] = BufferList->buffer->buffer;
1775 // Decrement buffer reference counter
1776 DecrementRef(&BufferList->buffer->ref);
1778 else
1779 buffers[i] = 0;
1781 // Release memory for buffer list item
1782 free(BufferList);
1784 if(Source->queue)
1785 Source->queue->prev = NULL;
1786 UnlockContext(Context);
1788 done:
1789 ALCcontext_DecRef(Context);
1793 static ALvoid InitSourceParams(ALsource *Source)
1795 ALuint i;
1797 Source->flInnerAngle = 360.0f;
1798 Source->flOuterAngle = 360.0f;
1799 Source->flPitch = 1.0f;
1800 Source->vPosition[0] = 0.0f;
1801 Source->vPosition[1] = 0.0f;
1802 Source->vPosition[2] = 0.0f;
1803 Source->vOrientation[0] = 0.0f;
1804 Source->vOrientation[1] = 0.0f;
1805 Source->vOrientation[2] = 0.0f;
1806 Source->vVelocity[0] = 0.0f;
1807 Source->vVelocity[1] = 0.0f;
1808 Source->vVelocity[2] = 0.0f;
1809 Source->flRefDistance = 1.0f;
1810 Source->flMaxDistance = FLT_MAX;
1811 Source->flRollOffFactor = 1.0f;
1812 Source->bLooping = AL_FALSE;
1813 Source->flGain = 1.0f;
1814 Source->flMinGain = 0.0f;
1815 Source->flMaxGain = 1.0f;
1816 Source->flOuterGain = 0.0f;
1817 Source->OuterGainHF = 1.0f;
1819 Source->DryGainHFAuto = AL_TRUE;
1820 Source->WetGainAuto = AL_TRUE;
1821 Source->WetGainHFAuto = AL_TRUE;
1822 Source->AirAbsorptionFactor = 0.0f;
1823 Source->RoomRolloffFactor = 0.0f;
1824 Source->DopplerFactor = 1.0f;
1825 Source->DirectChannels = AL_FALSE;
1827 Source->DistanceModel = DefaultDistanceModel;
1829 Source->Resampler = DefaultResampler;
1831 Source->state = AL_INITIAL;
1832 Source->new_state = AL_NONE;
1833 Source->lSourceType = AL_UNDETERMINED;
1834 Source->lOffset = -1;
1836 Source->DirectGain = 1.0f;
1837 Source->DirectGainHF = 1.0f;
1838 for(i = 0;i < MAX_SENDS;i++)
1840 Source->Send[i].WetGain = 1.0f;
1841 Source->Send[i].WetGainHF = 1.0f;
1844 Source->NeedsUpdate = AL_TRUE;
1846 Source->HrtfMoving = AL_FALSE;
1847 Source->HrtfCounter = 0;
1852 * SetSourceState
1854 * Sets the source's new play state given its current state
1856 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1858 if(state == AL_PLAYING)
1860 ALbufferlistitem *BufferList;
1861 ALsizei j, k;
1863 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
1864 BufferList = Source->queue;
1865 while(BufferList)
1867 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1868 break;
1869 BufferList = BufferList->next;
1872 if(Source->state != AL_PLAYING)
1874 for(j = 0;j < MAXCHANNELS;j++)
1876 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1877 Source->HrtfHistory[j][k] = 0.0f;
1878 for(k = 0;k < HRIR_LENGTH;k++)
1880 Source->HrtfValues[j][k][0] = 0.0f;
1881 Source->HrtfValues[j][k][1] = 0.0f;
1886 if(Source->state != AL_PAUSED)
1888 Source->state = AL_PLAYING;
1889 Source->position = 0;
1890 Source->position_fraction = 0;
1891 Source->BuffersPlayed = 0;
1893 else
1894 Source->state = AL_PLAYING;
1896 // Check if an Offset has been set
1897 if(Source->lOffset != -1)
1898 ApplyOffset(Source);
1900 /* If there's nothing to play, or device is disconnected, go right to
1901 * stopped */
1902 if(!BufferList || !Context->Device->Connected)
1904 SetSourceState(Source, Context, AL_STOPPED);
1905 return;
1908 for(j = 0;j < Context->ActiveSourceCount;j++)
1910 if(Context->ActiveSources[j] == Source)
1911 break;
1913 if(j == Context->ActiveSourceCount)
1914 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1916 else if(state == AL_PAUSED)
1918 if(Source->state == AL_PLAYING)
1920 Source->state = AL_PAUSED;
1921 Source->HrtfMoving = AL_FALSE;
1922 Source->HrtfCounter = 0;
1925 else if(state == AL_STOPPED)
1927 if(Source->state != AL_INITIAL)
1929 Source->state = AL_STOPPED;
1930 Source->BuffersPlayed = Source->BuffersInQueue;
1931 Source->HrtfMoving = AL_FALSE;
1932 Source->HrtfCounter = 0;
1934 Source->lOffset = -1;
1936 else if(state == AL_INITIAL)
1938 if(Source->state != AL_INITIAL)
1940 Source->state = AL_INITIAL;
1941 Source->position = 0;
1942 Source->position_fraction = 0;
1943 Source->BuffersPlayed = 0;
1944 Source->HrtfMoving = AL_FALSE;
1945 Source->HrtfCounter = 0;
1947 Source->lOffset = -1;
1952 GetSourceOffset
1954 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1955 The offset is relative to the start of the queue (not the start of the current buffer)
1957 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1959 const ALbufferlistitem *BufferList;
1960 const ALbuffer *Buffer = NULL;
1961 ALuint BufferFreq = 0;
1962 ALuint readPos, writePos;
1963 ALuint totalBufferLen;
1964 ALuint i;
1966 // Find the first non-NULL Buffer in the Queue
1967 BufferList = Source->queue;
1968 while(BufferList)
1970 if(BufferList->buffer)
1972 Buffer = BufferList->buffer;
1973 BufferFreq = Buffer->Frequency;
1974 break;
1976 BufferList = BufferList->next;
1979 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1981 offset[0] = 0.0;
1982 offset[1] = 0.0;
1983 return;
1986 if(updateLen > 0.0 && updateLen < 0.015)
1987 updateLen = 0.015;
1989 // Get Current SamplesPlayed (NOTE : This is the offset into the *current* buffer)
1990 readPos = Source->position;
1991 // Add length of any processed buffers in the queue
1992 totalBufferLen = 0;
1993 BufferList = Source->queue;
1994 for(i = 0;BufferList;i++)
1996 if(BufferList->buffer)
1998 if(i < Source->BuffersPlayed)
1999 readPos += BufferList->buffer->SampleLen;
2000 totalBufferLen += BufferList->buffer->SampleLen;
2002 BufferList = BufferList->next;
2004 if(Source->state == AL_PLAYING)
2005 writePos = readPos + (ALuint)(updateLen*BufferFreq);
2006 else
2007 writePos = readPos;
2009 if(Source->bLooping)
2011 readPos %= totalBufferLen;
2012 writePos %= totalBufferLen;
2014 else
2016 // Wrap positions back to 0
2017 if(readPos >= totalBufferLen)
2018 readPos = 0;
2019 if(writePos >= totalBufferLen)
2020 writePos = 0;
2023 switch(name)
2025 case AL_SEC_OFFSET:
2026 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2027 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2028 break;
2029 case AL_SAMPLE_OFFSET:
2030 case AL_SAMPLE_RW_OFFSETS_SOFT:
2031 offset[0] = (ALdouble)readPos;
2032 offset[1] = (ALdouble)writePos;
2033 break;
2034 case AL_BYTE_OFFSET:
2035 case AL_BYTE_RW_OFFSETS_SOFT:
2036 // Take into account the original format of the Buffer
2037 if(Buffer->OriginalType == UserFmtIMA4)
2039 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2040 ALuint FrameBlockSize = 65;
2042 // Round down to nearest ADPCM block
2043 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2044 if(Source->state != AL_PLAYING)
2045 offset[1] = offset[0];
2046 else
2048 // Round up to nearest ADPCM block
2049 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2050 FrameBlockSize * BlockSize);
2053 else
2055 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2056 offset[0] = (ALdouble)(readPos * FrameSize);
2057 offset[1] = (ALdouble)(writePos * FrameSize);
2059 break;
2065 ApplyOffset
2067 Apply a playback offset to the Source. This function will update the queue (to correctly
2068 mark buffers as 'pending' or 'processed' depending upon the new offset.
2070 ALboolean ApplyOffset(ALsource *Source)
2072 const ALbufferlistitem *BufferList;
2073 const ALbuffer *Buffer;
2074 ALint bufferLen, totalBufferLen;
2075 ALint buffersPlayed;
2076 ALint offset;
2078 // Get true byte offset
2079 offset = GetSampleOffset(Source);
2081 // If the offset is invalid, don't apply it
2082 if(offset == -1)
2083 return AL_FALSE;
2085 // Sort out the queue (pending and processed states)
2086 BufferList = Source->queue;
2087 totalBufferLen = 0;
2088 buffersPlayed = 0;
2090 while(BufferList)
2092 Buffer = BufferList->buffer;
2093 bufferLen = Buffer ? Buffer->SampleLen : 0;
2095 if(bufferLen <= offset-totalBufferLen)
2097 // Offset is past this buffer so increment BuffersPlayed
2098 buffersPlayed++;
2100 else if(totalBufferLen <= offset)
2102 // Offset is within this buffer
2103 Source->BuffersPlayed = buffersPlayed;
2105 // SW Mixer Positions are in Samples
2106 Source->position = offset - totalBufferLen;
2107 return AL_TRUE;
2110 // Increment the TotalBufferSize
2111 totalBufferLen += bufferLen;
2113 // Move on to next buffer in the Queue
2114 BufferList = BufferList->next;
2116 // Offset is out of range of the buffer queue
2117 return AL_FALSE;
2122 GetSampleOffset
2124 Returns the sample offset into the Source's queue (from the Sample, Byte or Millisecond offset
2125 supplied by the application). This takes into account the fact that the buffer format may have
2126 been modifed by AL
2128 static ALint GetSampleOffset(ALsource *Source)
2130 const ALbuffer *Buffer = NULL;
2131 const ALbufferlistitem *BufferList;
2132 ALint Offset = -1;
2134 // Find the first non-NULL Buffer in the Queue
2135 BufferList = Source->queue;
2136 while(BufferList)
2138 if(BufferList->buffer)
2140 Buffer = BufferList->buffer;
2141 break;
2143 BufferList = BufferList->next;
2146 if(!Buffer)
2148 Source->lOffset = -1;
2149 return -1;
2152 // Determine the ByteOffset (and ensure it is block aligned)
2153 switch(Source->lOffsetType)
2155 case AL_BYTE_OFFSET:
2156 // Take into consideration the original format
2157 Offset = Source->lOffset;
2158 if(Buffer->OriginalType == UserFmtIMA4)
2160 // Round down to nearest ADPCM block
2161 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2162 // Multiply by compression rate (65 sample frames per block)
2163 Offset *= 65;
2165 else
2166 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2167 break;
2169 case AL_SAMPLE_OFFSET:
2170 Offset = Source->lOffset;
2171 break;
2173 case AL_SEC_OFFSET:
2174 // Note - lOffset is internally stored as Milliseconds
2175 Offset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2176 break;
2178 // Clear Offset
2179 Source->lOffset = -1;
2181 return Offset;
2185 ALvoid ReleaseALSources(ALCcontext *Context)
2187 ALsizei pos;
2188 ALuint j;
2189 for(pos = 0;pos < Context->SourceMap.size;pos++)
2191 ALsource *temp = Context->SourceMap.array[pos].value;
2192 Context->SourceMap.array[pos].value = NULL;
2194 // For each buffer in the source's queue, decrement its reference counter and remove it
2195 while(temp->queue != NULL)
2197 ALbufferlistitem *BufferList = temp->queue;
2198 temp->queue = BufferList->next;
2200 if(BufferList->buffer != NULL)
2201 DecrementRef(&BufferList->buffer->ref);
2202 free(BufferList);
2205 for(j = 0;j < MAX_SENDS;++j)
2207 if(temp->Send[j].Slot)
2208 DecrementRef(&temp->Send[j].Slot->ref);
2209 temp->Send[j].Slot = NULL;
2212 // Release source structure
2213 FreeThunkEntry(temp->source);
2214 memset(temp, 0, sizeof(ALsource));
2215 free(temp);