Use a double to store the source offset and don't use milliseconds for seconds
[openal-soft.git] / OpenAL32 / alSource.c
blob2c0bc4273501ce101c22e98ae5370a6d74f82a21
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 // Store Offset
356 Source->OffsetType = eParam;
357 Source->Offset = flValue;
359 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
360 !pContext->DeferUpdates)
362 if(ApplyOffset(Source) == AL_FALSE)
363 alSetError(pContext, AL_INVALID_VALUE);
365 UnlockContext(pContext);
367 else
368 alSetError(pContext, AL_INVALID_VALUE);
369 break;
371 default:
372 alSetError(pContext, AL_INVALID_ENUM);
373 break;
376 else
378 // Invalid Source Name
379 alSetError(pContext, AL_INVALID_NAME);
382 ALCcontext_DecRef(pContext);
386 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
388 ALCcontext *pContext;
389 ALsource *Source;
391 pContext = GetContextRef();
392 if(!pContext) return;
394 if((Source=LookupSource(pContext, source)) != NULL)
396 switch(eParam)
398 case AL_POSITION:
399 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
401 LockContext(pContext);
402 Source->vPosition[0] = flValue1;
403 Source->vPosition[1] = flValue2;
404 Source->vPosition[2] = flValue3;
405 UnlockContext(pContext);
406 Source->NeedsUpdate = AL_TRUE;
408 else
409 alSetError(pContext, AL_INVALID_VALUE);
410 break;
412 case AL_VELOCITY:
413 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
415 LockContext(pContext);
416 Source->vVelocity[0] = flValue1;
417 Source->vVelocity[1] = flValue2;
418 Source->vVelocity[2] = flValue3;
419 UnlockContext(pContext);
420 Source->NeedsUpdate = AL_TRUE;
422 else
423 alSetError(pContext, AL_INVALID_VALUE);
424 break;
426 case AL_DIRECTION:
427 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
429 LockContext(pContext);
430 Source->vOrientation[0] = flValue1;
431 Source->vOrientation[1] = flValue2;
432 Source->vOrientation[2] = flValue3;
433 UnlockContext(pContext);
434 Source->NeedsUpdate = AL_TRUE;
436 else
437 alSetError(pContext, AL_INVALID_VALUE);
438 break;
440 default:
441 alSetError(pContext, AL_INVALID_ENUM);
442 break;
445 else
446 alSetError(pContext, AL_INVALID_NAME);
448 ALCcontext_DecRef(pContext);
452 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
454 ALCcontext *pContext;
456 if(pflValues)
458 switch(eParam)
460 case AL_PITCH:
461 case AL_CONE_INNER_ANGLE:
462 case AL_CONE_OUTER_ANGLE:
463 case AL_GAIN:
464 case AL_MAX_DISTANCE:
465 case AL_ROLLOFF_FACTOR:
466 case AL_REFERENCE_DISTANCE:
467 case AL_MIN_GAIN:
468 case AL_MAX_GAIN:
469 case AL_CONE_OUTER_GAIN:
470 case AL_CONE_OUTER_GAINHF:
471 case AL_SEC_OFFSET:
472 case AL_SAMPLE_OFFSET:
473 case AL_BYTE_OFFSET:
474 case AL_AIR_ABSORPTION_FACTOR:
475 case AL_ROOM_ROLLOFF_FACTOR:
476 alSourcef(source, eParam, pflValues[0]);
477 return;
479 case AL_POSITION:
480 case AL_VELOCITY:
481 case AL_DIRECTION:
482 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
483 return;
487 pContext = GetContextRef();
488 if(!pContext) return;
490 if(pflValues)
492 if(LookupSource(pContext, source) != NULL)
494 switch(eParam)
496 default:
497 alSetError(pContext, AL_INVALID_ENUM);
498 break;
501 else
502 alSetError(pContext, AL_INVALID_NAME);
504 else
505 alSetError(pContext, AL_INVALID_VALUE);
507 ALCcontext_DecRef(pContext);
511 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
513 ALCcontext *pContext;
514 ALsource *Source;
515 ALbufferlistitem *BufferListItem;
517 switch(eParam)
519 case AL_MAX_DISTANCE:
520 case AL_ROLLOFF_FACTOR:
521 case AL_CONE_INNER_ANGLE:
522 case AL_CONE_OUTER_ANGLE:
523 case AL_REFERENCE_DISTANCE:
524 alSourcef(source, eParam, (ALfloat)lValue);
525 return;
528 pContext = GetContextRef();
529 if(!pContext) return;
531 if((Source=LookupSource(pContext, source)) != NULL)
533 ALCdevice *device = pContext->Device;
535 switch(eParam)
537 case AL_SOURCE_RELATIVE:
538 if(lValue == AL_FALSE || lValue == AL_TRUE)
540 Source->bHeadRelative = (ALboolean)lValue;
541 Source->NeedsUpdate = AL_TRUE;
543 else
544 alSetError(pContext, AL_INVALID_VALUE);
545 break;
547 case AL_LOOPING:
548 if(lValue == AL_FALSE || lValue == AL_TRUE)
549 Source->bLooping = (ALboolean)lValue;
550 else
551 alSetError(pContext, AL_INVALID_VALUE);
552 break;
554 case AL_BUFFER:
555 LockContext(pContext);
556 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
558 ALbufferlistitem *oldlist;
559 ALbuffer *buffer = NULL;
561 if(lValue == 0 || (buffer=LookupBuffer(device, lValue)) != NULL)
563 Source->BuffersInQueue = 0;
564 Source->BuffersPlayed = 0;
566 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
567 if(buffer != NULL)
569 // Source is now in STATIC mode
570 Source->lSourceType = AL_STATIC;
572 // Add the selected buffer to the queue
573 BufferListItem = malloc(sizeof(ALbufferlistitem));
574 BufferListItem->buffer = buffer;
575 BufferListItem->next = NULL;
576 BufferListItem->prev = NULL;
577 // Increment reference counter for buffer
578 IncrementRef(&buffer->ref);
580 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
581 Source->BuffersInQueue = 1;
583 ReadLock(&buffer->lock);
584 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
585 Source->SampleSize = BytesFromFmt(buffer->FmtType);
586 ReadUnlock(&buffer->lock);
587 if(buffer->FmtChannels == FmtMono)
588 Source->Update = CalcSourceParams;
589 else
590 Source->Update = CalcNonAttnSourceParams;
591 Source->NeedsUpdate = AL_TRUE;
593 else
595 // Source is now in UNDETERMINED mode
596 Source->lSourceType = AL_UNDETERMINED;
597 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
600 // Delete all previous elements in the queue
601 while(oldlist != NULL)
603 BufferListItem = oldlist;
604 oldlist = BufferListItem->next;
606 if(BufferListItem->buffer)
607 DecrementRef(&BufferListItem->buffer->ref);
608 free(BufferListItem);
611 else
612 alSetError(pContext, AL_INVALID_VALUE);
614 else
615 alSetError(pContext, AL_INVALID_OPERATION);
616 UnlockContext(pContext);
617 break;
619 case AL_SOURCE_STATE:
620 // Query only
621 alSetError(pContext, AL_INVALID_OPERATION);
622 break;
624 case AL_SEC_OFFSET:
625 case AL_SAMPLE_OFFSET:
626 case AL_BYTE_OFFSET:
627 if(lValue >= 0)
629 LockContext(pContext);
630 // Store Offset
631 Source->OffsetType = eParam;
632 Source->Offset = lValue;
634 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
635 !pContext->DeferUpdates)
637 if(ApplyOffset(Source) == AL_FALSE)
638 alSetError(pContext, AL_INVALID_VALUE);
640 UnlockContext(pContext);
642 else
643 alSetError(pContext, AL_INVALID_VALUE);
644 break;
646 case AL_DIRECT_FILTER: {
647 ALfilter *filter = NULL;
649 if(lValue == 0 || (filter=LookupFilter(pContext->Device, lValue)) != NULL)
651 LockContext(pContext);
652 if(!filter)
654 Source->DirectGain = 1.0f;
655 Source->DirectGainHF = 1.0f;
657 else
659 Source->DirectGain = filter->Gain;
660 Source->DirectGainHF = filter->GainHF;
662 UnlockContext(pContext);
663 Source->NeedsUpdate = AL_TRUE;
665 else
666 alSetError(pContext, AL_INVALID_VALUE);
667 } break;
669 case AL_DIRECT_FILTER_GAINHF_AUTO:
670 if(lValue == AL_TRUE || lValue == AL_FALSE)
672 Source->DryGainHFAuto = lValue;
673 Source->NeedsUpdate = AL_TRUE;
675 else
676 alSetError(pContext, AL_INVALID_VALUE);
677 break;
679 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
680 if(lValue == AL_TRUE || lValue == AL_FALSE)
682 Source->WetGainAuto = lValue;
683 Source->NeedsUpdate = AL_TRUE;
685 else
686 alSetError(pContext, AL_INVALID_VALUE);
687 break;
689 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
690 if(lValue == AL_TRUE || lValue == AL_FALSE)
692 Source->WetGainHFAuto = lValue;
693 Source->NeedsUpdate = AL_TRUE;
695 else
696 alSetError(pContext, AL_INVALID_VALUE);
697 break;
699 case AL_DIRECT_CHANNELS_SOFT:
700 if(lValue == AL_TRUE || lValue == AL_FALSE)
702 Source->DirectChannels = lValue;
703 Source->NeedsUpdate = AL_TRUE;
705 else
706 alSetError(pContext, AL_INVALID_VALUE);
707 break;
709 case AL_DISTANCE_MODEL:
710 if(lValue == AL_NONE ||
711 lValue == AL_INVERSE_DISTANCE ||
712 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
713 lValue == AL_LINEAR_DISTANCE ||
714 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
715 lValue == AL_EXPONENT_DISTANCE ||
716 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
718 Source->DistanceModel = lValue;
719 if(pContext->SourceDistanceModel)
720 Source->NeedsUpdate = AL_TRUE;
722 else
723 alSetError(pContext, AL_INVALID_VALUE);
724 break;
726 default:
727 alSetError(pContext, AL_INVALID_ENUM);
728 break;
731 else
732 alSetError(pContext, AL_INVALID_NAME);
734 ALCcontext_DecRef(pContext);
738 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
740 ALCcontext *pContext;
741 ALsource *Source;
743 switch(eParam)
745 case AL_POSITION:
746 case AL_VELOCITY:
747 case AL_DIRECTION:
748 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
749 return;
752 pContext = GetContextRef();
753 if(!pContext) return;
755 if((Source=LookupSource(pContext, source)) != NULL)
757 ALCdevice *device = pContext->Device;
759 switch(eParam)
761 case AL_AUXILIARY_SEND_FILTER: {
762 ALeffectslot *ALEffectSlot = NULL;
763 ALfilter *ALFilter = NULL;
765 LockContext(pContext);
766 if((ALuint)lValue2 < device->NumAuxSends &&
767 (lValue1 == 0 || (ALEffectSlot=LookupEffectSlot(pContext, lValue1)) != NULL) &&
768 (lValue3 == 0 || (ALFilter=LookupFilter(device, lValue3)) != NULL))
770 /* Release refcount on the previous slot, and add one for
771 * the new slot */
772 if(ALEffectSlot) IncrementRef(&ALEffectSlot->ref);
773 ALEffectSlot = ExchangePtr((XchgPtr*)&Source->Send[lValue2].Slot, ALEffectSlot);
774 if(ALEffectSlot) DecrementRef(&ALEffectSlot->ref);
776 if(!ALFilter)
778 /* Disable filter */
779 Source->Send[lValue2].WetGain = 1.0f;
780 Source->Send[lValue2].WetGainHF = 1.0f;
782 else
784 Source->Send[lValue2].WetGain = ALFilter->Gain;
785 Source->Send[lValue2].WetGainHF = ALFilter->GainHF;
787 Source->NeedsUpdate = AL_TRUE;
789 else
790 alSetError(pContext, AL_INVALID_VALUE);
791 UnlockContext(pContext);
792 } break;
794 default:
795 alSetError(pContext, AL_INVALID_ENUM);
796 break;
799 else
800 alSetError(pContext, AL_INVALID_NAME);
802 ALCcontext_DecRef(pContext);
806 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
808 ALCcontext *pContext;
810 if(plValues)
812 switch(eParam)
814 case AL_SOURCE_RELATIVE:
815 case AL_CONE_INNER_ANGLE:
816 case AL_CONE_OUTER_ANGLE:
817 case AL_LOOPING:
818 case AL_BUFFER:
819 case AL_SOURCE_STATE:
820 case AL_SEC_OFFSET:
821 case AL_SAMPLE_OFFSET:
822 case AL_BYTE_OFFSET:
823 case AL_MAX_DISTANCE:
824 case AL_ROLLOFF_FACTOR:
825 case AL_REFERENCE_DISTANCE:
826 case AL_DIRECT_FILTER:
827 case AL_DIRECT_FILTER_GAINHF_AUTO:
828 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
829 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
830 case AL_DISTANCE_MODEL:
831 case AL_DIRECT_CHANNELS_SOFT:
832 alSourcei(source, eParam, plValues[0]);
833 return;
835 case AL_POSITION:
836 case AL_VELOCITY:
837 case AL_DIRECTION:
838 case AL_AUXILIARY_SEND_FILTER:
839 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
840 return;
844 pContext = GetContextRef();
845 if(!pContext) return;
847 if(plValues)
849 if(LookupSource(pContext, source) != NULL)
851 switch(eParam)
853 default:
854 alSetError(pContext, AL_INVALID_ENUM);
855 break;
858 else
859 alSetError(pContext, AL_INVALID_NAME);
861 else
862 alSetError(pContext, AL_INVALID_VALUE);
864 ALCcontext_DecRef(pContext);
868 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
870 ALCcontext *pContext;
871 ALsource *Source;
872 ALdouble Offsets[2];
873 ALdouble updateLen;
875 pContext = GetContextRef();
876 if(!pContext) return;
878 if(pflValue)
880 if((Source=LookupSource(pContext, source)) != NULL)
882 switch(eParam)
884 case AL_PITCH:
885 *pflValue = Source->flPitch;
886 break;
888 case AL_GAIN:
889 *pflValue = Source->flGain;
890 break;
892 case AL_MIN_GAIN:
893 *pflValue = Source->flMinGain;
894 break;
896 case AL_MAX_GAIN:
897 *pflValue = Source->flMaxGain;
898 break;
900 case AL_MAX_DISTANCE:
901 *pflValue = Source->flMaxDistance;
902 break;
904 case AL_ROLLOFF_FACTOR:
905 *pflValue = Source->flRollOffFactor;
906 break;
908 case AL_CONE_OUTER_GAIN:
909 *pflValue = Source->flOuterGain;
910 break;
912 case AL_CONE_OUTER_GAINHF:
913 *pflValue = Source->OuterGainHF;
914 break;
916 case AL_SEC_OFFSET:
917 case AL_SAMPLE_OFFSET:
918 case AL_BYTE_OFFSET:
919 LockContext(pContext);
920 updateLen = (ALdouble)pContext->Device->UpdateSize /
921 pContext->Device->Frequency;
922 GetSourceOffset(Source, eParam, Offsets, updateLen);
923 UnlockContext(pContext);
924 *pflValue = (ALfloat)Offsets[0];
925 break;
927 case AL_CONE_INNER_ANGLE:
928 *pflValue = Source->flInnerAngle;
929 break;
931 case AL_CONE_OUTER_ANGLE:
932 *pflValue = Source->flOuterAngle;
933 break;
935 case AL_REFERENCE_DISTANCE:
936 *pflValue = Source->flRefDistance;
937 break;
939 case AL_AIR_ABSORPTION_FACTOR:
940 *pflValue = Source->AirAbsorptionFactor;
941 break;
943 case AL_ROOM_ROLLOFF_FACTOR:
944 *pflValue = Source->RoomRolloffFactor;
945 break;
947 case AL_DOPPLER_FACTOR:
948 *pflValue = Source->DopplerFactor;
949 break;
951 default:
952 alSetError(pContext, AL_INVALID_ENUM);
953 break;
956 else
957 alSetError(pContext, AL_INVALID_NAME);
959 else
960 alSetError(pContext, AL_INVALID_VALUE);
962 ALCcontext_DecRef(pContext);
966 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
968 ALCcontext *pContext;
969 ALsource *Source;
971 pContext = GetContextRef();
972 if(!pContext) return;
974 if(pflValue1 && pflValue2 && pflValue3)
976 if((Source=LookupSource(pContext, source)) != NULL)
978 switch(eParam)
980 case AL_POSITION:
981 LockContext(pContext);
982 *pflValue1 = Source->vPosition[0];
983 *pflValue2 = Source->vPosition[1];
984 *pflValue3 = Source->vPosition[2];
985 UnlockContext(pContext);
986 break;
988 case AL_VELOCITY:
989 LockContext(pContext);
990 *pflValue1 = Source->vVelocity[0];
991 *pflValue2 = Source->vVelocity[1];
992 *pflValue3 = Source->vVelocity[2];
993 UnlockContext(pContext);
994 break;
996 case AL_DIRECTION:
997 LockContext(pContext);
998 *pflValue1 = Source->vOrientation[0];
999 *pflValue2 = Source->vOrientation[1];
1000 *pflValue3 = Source->vOrientation[2];
1001 UnlockContext(pContext);
1002 break;
1004 default:
1005 alSetError(pContext, AL_INVALID_ENUM);
1006 break;
1009 else
1010 alSetError(pContext, AL_INVALID_NAME);
1012 else
1013 alSetError(pContext, AL_INVALID_VALUE);
1015 ALCcontext_DecRef(pContext);
1019 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1021 ALCcontext *pContext;
1022 ALsource *Source;
1023 ALdouble Offsets[2];
1024 ALdouble updateLen;
1026 switch(eParam)
1028 case AL_PITCH:
1029 case AL_GAIN:
1030 case AL_MIN_GAIN:
1031 case AL_MAX_GAIN:
1032 case AL_MAX_DISTANCE:
1033 case AL_ROLLOFF_FACTOR:
1034 case AL_DOPPLER_FACTOR:
1035 case AL_CONE_OUTER_GAIN:
1036 case AL_SEC_OFFSET:
1037 case AL_SAMPLE_OFFSET:
1038 case AL_BYTE_OFFSET:
1039 case AL_CONE_INNER_ANGLE:
1040 case AL_CONE_OUTER_ANGLE:
1041 case AL_REFERENCE_DISTANCE:
1042 case AL_CONE_OUTER_GAINHF:
1043 case AL_AIR_ABSORPTION_FACTOR:
1044 case AL_ROOM_ROLLOFF_FACTOR:
1045 alGetSourcef(source, eParam, pflValues);
1046 return;
1048 case AL_POSITION:
1049 case AL_VELOCITY:
1050 case AL_DIRECTION:
1051 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1052 return;
1055 pContext = GetContextRef();
1056 if(!pContext) return;
1058 if(pflValues)
1060 if((Source=LookupSource(pContext, source)) != NULL)
1062 switch(eParam)
1064 case AL_SAMPLE_RW_OFFSETS_SOFT:
1065 case AL_BYTE_RW_OFFSETS_SOFT:
1066 LockContext(pContext);
1067 updateLen = (ALdouble)pContext->Device->UpdateSize /
1068 pContext->Device->Frequency;
1069 GetSourceOffset(Source, eParam, Offsets, updateLen);
1070 UnlockContext(pContext);
1071 pflValues[0] = (ALfloat)Offsets[0];
1072 pflValues[1] = (ALfloat)Offsets[1];
1073 break;
1075 default:
1076 alSetError(pContext, AL_INVALID_ENUM);
1077 break;
1080 else
1081 alSetError(pContext, AL_INVALID_NAME);
1083 else
1084 alSetError(pContext, AL_INVALID_VALUE);
1086 ALCcontext_DecRef(pContext);
1090 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1092 ALbufferlistitem *BufferList;
1093 ALCcontext *pContext;
1094 ALsource *Source;
1095 ALdouble Offsets[2];
1096 ALdouble updateLen;
1098 pContext = GetContextRef();
1099 if(!pContext) return;
1101 if(plValue)
1103 if((Source=LookupSource(pContext, source)) != NULL)
1105 switch(eParam)
1107 case AL_MAX_DISTANCE:
1108 *plValue = (ALint)Source->flMaxDistance;
1109 break;
1111 case AL_ROLLOFF_FACTOR:
1112 *plValue = (ALint)Source->flRollOffFactor;
1113 break;
1115 case AL_REFERENCE_DISTANCE:
1116 *plValue = (ALint)Source->flRefDistance;
1117 break;
1119 case AL_SOURCE_RELATIVE:
1120 *plValue = Source->bHeadRelative;
1121 break;
1123 case AL_CONE_INNER_ANGLE:
1124 *plValue = (ALint)Source->flInnerAngle;
1125 break;
1127 case AL_CONE_OUTER_ANGLE:
1128 *plValue = (ALint)Source->flOuterAngle;
1129 break;
1131 case AL_LOOPING:
1132 *plValue = Source->bLooping;
1133 break;
1135 case AL_BUFFER:
1136 LockContext(pContext);
1137 BufferList = Source->queue;
1138 if(Source->lSourceType != AL_STATIC)
1140 ALuint i = Source->BuffersPlayed;
1141 while(i > 0)
1143 BufferList = BufferList->next;
1144 i--;
1147 *plValue = ((BufferList && BufferList->buffer) ?
1148 BufferList->buffer->buffer : 0);
1149 UnlockContext(pContext);
1150 break;
1152 case AL_SOURCE_STATE:
1153 *plValue = Source->state;
1154 break;
1156 case AL_BUFFERS_QUEUED:
1157 *plValue = Source->BuffersInQueue;
1158 break;
1160 case AL_BUFFERS_PROCESSED:
1161 LockContext(pContext);
1162 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1164 /* Buffers on a looping source are in a perpetual state
1165 * of PENDING, so don't report any as PROCESSED */
1166 *plValue = 0;
1168 else
1169 *plValue = Source->BuffersPlayed;
1170 UnlockContext(pContext);
1171 break;
1173 case AL_SOURCE_TYPE:
1174 *plValue = Source->lSourceType;
1175 break;
1177 case AL_SEC_OFFSET:
1178 case AL_SAMPLE_OFFSET:
1179 case AL_BYTE_OFFSET:
1180 LockContext(pContext);
1181 updateLen = (ALdouble)pContext->Device->UpdateSize /
1182 pContext->Device->Frequency;
1183 GetSourceOffset(Source, eParam, Offsets, updateLen);
1184 UnlockContext(pContext);
1185 *plValue = (ALint)Offsets[0];
1186 break;
1188 case AL_DIRECT_FILTER_GAINHF_AUTO:
1189 *plValue = Source->DryGainHFAuto;
1190 break;
1192 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1193 *plValue = Source->WetGainAuto;
1194 break;
1196 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1197 *plValue = Source->WetGainHFAuto;
1198 break;
1200 case AL_DOPPLER_FACTOR:
1201 *plValue = (ALint)Source->DopplerFactor;
1202 break;
1204 case AL_DIRECT_CHANNELS_SOFT:
1205 *plValue = Source->DirectChannels;
1206 break;
1208 case AL_DISTANCE_MODEL:
1209 *plValue = Source->DistanceModel;
1210 break;
1212 default:
1213 alSetError(pContext, AL_INVALID_ENUM);
1214 break;
1217 else
1218 alSetError(pContext, AL_INVALID_NAME);
1220 else
1221 alSetError(pContext, AL_INVALID_VALUE);
1223 ALCcontext_DecRef(pContext);
1227 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1229 ALCcontext *pContext;
1230 ALsource *Source;
1232 pContext = GetContextRef();
1233 if(!pContext) return;
1235 if(plValue1 && plValue2 && plValue3)
1237 if((Source=LookupSource(pContext, source)) != NULL)
1239 switch(eParam)
1241 case AL_POSITION:
1242 LockContext(pContext);
1243 *plValue1 = (ALint)Source->vPosition[0];
1244 *plValue2 = (ALint)Source->vPosition[1];
1245 *plValue3 = (ALint)Source->vPosition[2];
1246 UnlockContext(pContext);
1247 break;
1249 case AL_VELOCITY:
1250 LockContext(pContext);
1251 *plValue1 = (ALint)Source->vVelocity[0];
1252 *plValue2 = (ALint)Source->vVelocity[1];
1253 *plValue3 = (ALint)Source->vVelocity[2];
1254 UnlockContext(pContext);
1255 break;
1257 case AL_DIRECTION:
1258 LockContext(pContext);
1259 *plValue1 = (ALint)Source->vOrientation[0];
1260 *plValue2 = (ALint)Source->vOrientation[1];
1261 *plValue3 = (ALint)Source->vOrientation[2];
1262 UnlockContext(pContext);
1263 break;
1265 default:
1266 alSetError(pContext, AL_INVALID_ENUM);
1267 break;
1270 else
1271 alSetError(pContext, AL_INVALID_NAME);
1273 else
1274 alSetError(pContext, AL_INVALID_VALUE);
1276 ALCcontext_DecRef(pContext);
1280 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1282 ALCcontext *pContext;
1283 ALsource *Source;
1284 ALdouble Offsets[2];
1285 ALdouble updateLen;
1287 switch(eParam)
1289 case AL_SOURCE_RELATIVE:
1290 case AL_CONE_INNER_ANGLE:
1291 case AL_CONE_OUTER_ANGLE:
1292 case AL_LOOPING:
1293 case AL_BUFFER:
1294 case AL_SOURCE_STATE:
1295 case AL_BUFFERS_QUEUED:
1296 case AL_BUFFERS_PROCESSED:
1297 case AL_SEC_OFFSET:
1298 case AL_SAMPLE_OFFSET:
1299 case AL_BYTE_OFFSET:
1300 case AL_MAX_DISTANCE:
1301 case AL_ROLLOFF_FACTOR:
1302 case AL_DOPPLER_FACTOR:
1303 case AL_REFERENCE_DISTANCE:
1304 case AL_SOURCE_TYPE:
1305 case AL_DIRECT_FILTER:
1306 case AL_DIRECT_FILTER_GAINHF_AUTO:
1307 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1308 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1309 case AL_DISTANCE_MODEL:
1310 case AL_DIRECT_CHANNELS_SOFT:
1311 alGetSourcei(source, eParam, plValues);
1312 return;
1314 case AL_POSITION:
1315 case AL_VELOCITY:
1316 case AL_DIRECTION:
1317 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1318 return;
1321 pContext = GetContextRef();
1322 if(!pContext) return;
1324 if(plValues)
1326 if((Source=LookupSource(pContext, source)) != NULL)
1328 switch(eParam)
1330 case AL_SAMPLE_RW_OFFSETS_SOFT:
1331 case AL_BYTE_RW_OFFSETS_SOFT:
1332 LockContext(pContext);
1333 updateLen = (ALdouble)pContext->Device->UpdateSize /
1334 pContext->Device->Frequency;
1335 GetSourceOffset(Source, eParam, Offsets, updateLen);
1336 UnlockContext(pContext);
1337 plValues[0] = (ALint)Offsets[0];
1338 plValues[1] = (ALint)Offsets[1];
1339 break;
1341 default:
1342 alSetError(pContext, AL_INVALID_ENUM);
1343 break;
1346 else
1347 alSetError(pContext, AL_INVALID_NAME);
1349 else
1350 alSetError(pContext, AL_INVALID_VALUE);
1352 ALCcontext_DecRef(pContext);
1356 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1358 alSourcePlayv(1, &source);
1361 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1363 ALCcontext *Context;
1364 ALsource *Source;
1365 ALsizei i;
1367 Context = GetContextRef();
1368 if(!Context) return;
1370 if(n < 0)
1372 alSetError(Context, AL_INVALID_VALUE);
1373 goto done;
1375 if(n > 0 && !sources)
1377 alSetError(Context, AL_INVALID_VALUE);
1378 goto done;
1381 // Check that all the Sources are valid
1382 for(i = 0;i < n;i++)
1384 if(!LookupSource(Context, sources[i]))
1386 alSetError(Context, AL_INVALID_NAME);
1387 goto done;
1391 LockContext(Context);
1392 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1394 void *temp = NULL;
1395 ALsizei newcount;
1397 newcount = Context->MaxActiveSources << 1;
1398 if(newcount > 0)
1399 temp = realloc(Context->ActiveSources,
1400 sizeof(*Context->ActiveSources) * newcount);
1401 if(!temp)
1403 UnlockContext(Context);
1404 alSetError(Context, AL_OUT_OF_MEMORY);
1405 goto done;
1408 Context->ActiveSources = temp;
1409 Context->MaxActiveSources = newcount;
1412 for(i = 0;i < n;i++)
1414 Source = LookupSource(Context, sources[i]);
1415 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1416 else SetSourceState(Source, Context, AL_PLAYING);
1418 UnlockContext(Context);
1420 done:
1421 ALCcontext_DecRef(Context);
1424 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1426 alSourcePausev(1, &source);
1429 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1431 ALCcontext *Context;
1432 ALsource *Source;
1433 ALsizei i;
1435 Context = GetContextRef();
1436 if(!Context) return;
1438 if(n < 0)
1440 alSetError(Context, AL_INVALID_VALUE);
1441 goto done;
1443 if(n > 0 && !sources)
1445 alSetError(Context, AL_INVALID_VALUE);
1446 goto done;
1449 // Check all the Sources are valid
1450 for(i = 0;i < n;i++)
1452 if(!LookupSource(Context, sources[i]))
1454 alSetError(Context, AL_INVALID_NAME);
1455 goto done;
1459 LockContext(Context);
1460 for(i = 0;i < n;i++)
1462 Source = LookupSource(Context, sources[i]);
1463 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1464 else SetSourceState(Source, Context, AL_PAUSED);
1466 UnlockContext(Context);
1468 done:
1469 ALCcontext_DecRef(Context);
1472 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1474 alSourceStopv(1, &source);
1477 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1479 ALCcontext *Context;
1480 ALsource *Source;
1481 ALsizei i;
1483 Context = GetContextRef();
1484 if(!Context) return;
1486 if(n < 0)
1488 alSetError(Context, AL_INVALID_VALUE);
1489 goto done;
1491 if(n > 0 && !sources)
1493 alSetError(Context, AL_INVALID_VALUE);
1494 goto done;
1497 // Check all the Sources are valid
1498 for(i = 0;i < n;i++)
1500 if(!LookupSource(Context, sources[i]))
1502 alSetError(Context, AL_INVALID_NAME);
1503 goto done;
1507 LockContext(Context);
1508 for(i = 0;i < n;i++)
1510 Source = LookupSource(Context, sources[i]);
1511 Source->new_state = AL_NONE;
1512 SetSourceState(Source, Context, AL_STOPPED);
1514 UnlockContext(Context);
1516 done:
1517 ALCcontext_DecRef(Context);
1520 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1522 alSourceRewindv(1, &source);
1525 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1527 ALCcontext *Context;
1528 ALsource *Source;
1529 ALsizei i;
1531 Context = GetContextRef();
1532 if(!Context) return;
1534 if(n < 0)
1536 alSetError(Context, AL_INVALID_VALUE);
1537 goto done;
1539 if(n > 0 && !sources)
1541 alSetError(Context, AL_INVALID_VALUE);
1542 goto done;
1545 // Check all the Sources are valid
1546 for(i = 0;i < n;i++)
1548 if(!LookupSource(Context, sources[i]))
1550 alSetError(Context, AL_INVALID_NAME);
1551 goto done;
1555 LockContext(Context);
1556 for(i = 0;i < n;i++)
1558 Source = LookupSource(Context, sources[i]);
1559 Source->new_state = AL_NONE;
1560 SetSourceState(Source, Context, AL_INITIAL);
1562 UnlockContext(Context);
1564 done:
1565 ALCcontext_DecRef(Context);
1569 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1571 ALCcontext *Context;
1572 ALCdevice *device;
1573 ALsource *Source;
1574 ALsizei i;
1575 ALbufferlistitem *BufferListStart = NULL;
1576 ALbufferlistitem *BufferList;
1577 ALbuffer *BufferFmt;
1579 if(n == 0)
1580 return;
1582 Context = GetContextRef();
1583 if(!Context) return;
1585 if(n < 0)
1587 alSetError(Context, AL_INVALID_VALUE);
1588 goto error;
1591 // Check that all buffers are valid or zero and that the source is valid
1593 // Check that this is a valid source
1594 if((Source=LookupSource(Context, source)) == NULL)
1596 alSetError(Context, AL_INVALID_NAME);
1597 goto error;
1600 LockContext(Context);
1601 // Check that this is not a STATIC Source
1602 if(Source->lSourceType == AL_STATIC)
1604 UnlockContext(Context);
1605 // Invalid Source Type (can't queue on a Static Source)
1606 alSetError(Context, AL_INVALID_OPERATION);
1607 goto error;
1610 device = Context->Device;
1612 BufferFmt = NULL;
1614 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1615 BufferList = Source->queue;
1616 while(BufferList)
1618 if(BufferList->buffer)
1620 BufferFmt = BufferList->buffer;
1621 break;
1623 BufferList = BufferList->next;
1626 for(i = 0;i < n;i++)
1628 ALbuffer *buffer = NULL;
1629 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1631 UnlockContext(Context);
1632 alSetError(Context, AL_INVALID_NAME);
1633 goto error;
1636 if(!BufferListStart)
1638 BufferListStart = malloc(sizeof(ALbufferlistitem));
1639 BufferListStart->buffer = buffer;
1640 BufferListStart->next = NULL;
1641 BufferListStart->prev = NULL;
1642 BufferList = BufferListStart;
1644 else
1646 BufferList->next = malloc(sizeof(ALbufferlistitem));
1647 BufferList->next->buffer = buffer;
1648 BufferList->next->next = NULL;
1649 BufferList->next->prev = BufferList;
1650 BufferList = BufferList->next;
1652 if(!buffer) continue;
1654 // Increment reference counter for buffer
1655 IncrementRef(&buffer->ref);
1656 ReadLock(&buffer->lock);
1657 if(BufferFmt == NULL)
1659 BufferFmt = buffer;
1661 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1662 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1663 if(buffer->FmtChannels == FmtMono)
1664 Source->Update = CalcSourceParams;
1665 else
1666 Source->Update = CalcNonAttnSourceParams;
1668 Source->NeedsUpdate = AL_TRUE;
1670 else if(BufferFmt->Frequency != buffer->Frequency ||
1671 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1672 BufferFmt->OriginalType != buffer->OriginalType)
1674 ReadUnlock(&buffer->lock);
1675 UnlockContext(Context);
1676 alSetError(Context, AL_INVALID_OPERATION);
1677 goto error;
1679 ReadUnlock(&buffer->lock);
1682 // Change Source Type
1683 Source->lSourceType = AL_STREAMING;
1685 if(Source->queue == NULL)
1686 Source->queue = BufferListStart;
1687 else
1689 // Find end of queue
1690 BufferList = Source->queue;
1691 while(BufferList->next != NULL)
1692 BufferList = BufferList->next;
1694 BufferListStart->prev = BufferList;
1695 BufferList->next = BufferListStart;
1698 // Update number of buffers in queue
1699 Source->BuffersInQueue += n;
1701 UnlockContext(Context);
1702 ALCcontext_DecRef(Context);
1703 return;
1705 error:
1706 while(BufferListStart)
1708 BufferList = BufferListStart;
1709 BufferListStart = BufferList->next;
1711 if(BufferList->buffer)
1712 DecrementRef(&BufferList->buffer->ref);
1713 free(BufferList);
1715 ALCcontext_DecRef(Context);
1719 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1720 // an array of buffer IDs that are to be filled with the names of the buffers removed
1721 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1723 ALCcontext *Context;
1724 ALsource *Source;
1725 ALsizei i;
1726 ALbufferlistitem *BufferList;
1728 if(n == 0)
1729 return;
1731 Context = GetContextRef();
1732 if(!Context) return;
1734 if(n < 0)
1736 alSetError(Context, AL_INVALID_VALUE);
1737 goto done;
1740 if((Source=LookupSource(Context, source)) == NULL)
1742 alSetError(Context, AL_INVALID_NAME);
1743 goto done;
1746 LockContext(Context);
1747 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1748 (ALuint)n > Source->BuffersPlayed)
1750 UnlockContext(Context);
1751 // Some buffers can't be unqueue because they have not been processed
1752 alSetError(Context, AL_INVALID_VALUE);
1753 goto done;
1756 for(i = 0;i < n;i++)
1758 BufferList = Source->queue;
1759 Source->queue = BufferList->next;
1760 Source->BuffersInQueue--;
1761 Source->BuffersPlayed--;
1763 if(BufferList->buffer)
1765 // Record name of buffer
1766 buffers[i] = BufferList->buffer->buffer;
1767 // Decrement buffer reference counter
1768 DecrementRef(&BufferList->buffer->ref);
1770 else
1771 buffers[i] = 0;
1773 // Release memory for buffer list item
1774 free(BufferList);
1776 if(Source->queue)
1777 Source->queue->prev = NULL;
1778 UnlockContext(Context);
1780 done:
1781 ALCcontext_DecRef(Context);
1785 static ALvoid InitSourceParams(ALsource *Source)
1787 ALuint i;
1789 Source->flInnerAngle = 360.0f;
1790 Source->flOuterAngle = 360.0f;
1791 Source->flPitch = 1.0f;
1792 Source->vPosition[0] = 0.0f;
1793 Source->vPosition[1] = 0.0f;
1794 Source->vPosition[2] = 0.0f;
1795 Source->vOrientation[0] = 0.0f;
1796 Source->vOrientation[1] = 0.0f;
1797 Source->vOrientation[2] = 0.0f;
1798 Source->vVelocity[0] = 0.0f;
1799 Source->vVelocity[1] = 0.0f;
1800 Source->vVelocity[2] = 0.0f;
1801 Source->flRefDistance = 1.0f;
1802 Source->flMaxDistance = FLT_MAX;
1803 Source->flRollOffFactor = 1.0f;
1804 Source->bLooping = AL_FALSE;
1805 Source->flGain = 1.0f;
1806 Source->flMinGain = 0.0f;
1807 Source->flMaxGain = 1.0f;
1808 Source->flOuterGain = 0.0f;
1809 Source->OuterGainHF = 1.0f;
1811 Source->DryGainHFAuto = AL_TRUE;
1812 Source->WetGainAuto = AL_TRUE;
1813 Source->WetGainHFAuto = AL_TRUE;
1814 Source->AirAbsorptionFactor = 0.0f;
1815 Source->RoomRolloffFactor = 0.0f;
1816 Source->DopplerFactor = 1.0f;
1817 Source->DirectChannels = AL_FALSE;
1819 Source->DistanceModel = DefaultDistanceModel;
1821 Source->Resampler = DefaultResampler;
1823 Source->state = AL_INITIAL;
1824 Source->new_state = AL_NONE;
1825 Source->lSourceType = AL_UNDETERMINED;
1826 Source->Offset = -1.0;
1828 Source->DirectGain = 1.0f;
1829 Source->DirectGainHF = 1.0f;
1830 for(i = 0;i < MAX_SENDS;i++)
1832 Source->Send[i].WetGain = 1.0f;
1833 Source->Send[i].WetGainHF = 1.0f;
1836 Source->NeedsUpdate = AL_TRUE;
1838 Source->HrtfMoving = AL_FALSE;
1839 Source->HrtfCounter = 0;
1844 * SetSourceState
1846 * Sets the source's new play state given its current state
1848 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1850 if(state == AL_PLAYING)
1852 ALbufferlistitem *BufferList;
1853 ALsizei j, k;
1855 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
1856 BufferList = Source->queue;
1857 while(BufferList)
1859 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1860 break;
1861 BufferList = BufferList->next;
1864 if(Source->state != AL_PLAYING)
1866 for(j = 0;j < MAXCHANNELS;j++)
1868 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1869 Source->HrtfHistory[j][k] = 0.0f;
1870 for(k = 0;k < HRIR_LENGTH;k++)
1872 Source->HrtfValues[j][k][0] = 0.0f;
1873 Source->HrtfValues[j][k][1] = 0.0f;
1878 if(Source->state != AL_PAUSED)
1880 Source->state = AL_PLAYING;
1881 Source->position = 0;
1882 Source->position_fraction = 0;
1883 Source->BuffersPlayed = 0;
1885 else
1886 Source->state = AL_PLAYING;
1888 // Check if an Offset has been set
1889 if(Source->Offset >= 0.0)
1890 ApplyOffset(Source);
1892 /* If there's nothing to play, or device is disconnected, go right to
1893 * stopped */
1894 if(!BufferList || !Context->Device->Connected)
1896 SetSourceState(Source, Context, AL_STOPPED);
1897 return;
1900 for(j = 0;j < Context->ActiveSourceCount;j++)
1902 if(Context->ActiveSources[j] == Source)
1903 break;
1905 if(j == Context->ActiveSourceCount)
1906 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1908 else if(state == AL_PAUSED)
1910 if(Source->state == AL_PLAYING)
1912 Source->state = AL_PAUSED;
1913 Source->HrtfMoving = AL_FALSE;
1914 Source->HrtfCounter = 0;
1917 else if(state == AL_STOPPED)
1919 if(Source->state != AL_INITIAL)
1921 Source->state = AL_STOPPED;
1922 Source->BuffersPlayed = Source->BuffersInQueue;
1923 Source->HrtfMoving = AL_FALSE;
1924 Source->HrtfCounter = 0;
1926 Source->Offset = -1.0;
1928 else if(state == AL_INITIAL)
1930 if(Source->state != AL_INITIAL)
1932 Source->state = AL_INITIAL;
1933 Source->position = 0;
1934 Source->position_fraction = 0;
1935 Source->BuffersPlayed = 0;
1936 Source->HrtfMoving = AL_FALSE;
1937 Source->HrtfCounter = 0;
1939 Source->Offset = -1.0;
1944 GetSourceOffset
1946 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1947 The offset is relative to the start of the queue (not the start of the current buffer)
1949 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1951 const ALbufferlistitem *BufferList;
1952 const ALbuffer *Buffer = NULL;
1953 ALuint BufferFreq = 0;
1954 ALuint readPos, writePos;
1955 ALuint totalBufferLen;
1956 ALuint i;
1958 // Find the first non-NULL Buffer in the Queue
1959 BufferList = Source->queue;
1960 while(BufferList)
1962 if(BufferList->buffer)
1964 Buffer = BufferList->buffer;
1965 BufferFreq = Buffer->Frequency;
1966 break;
1968 BufferList = BufferList->next;
1971 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1973 offset[0] = 0.0;
1974 offset[1] = 0.0;
1975 return;
1978 if(updateLen > 0.0 && updateLen < 0.015)
1979 updateLen = 0.015;
1981 // Get Current SamplesPlayed (NOTE : This is the offset into the *current* buffer)
1982 readPos = Source->position;
1983 // Add length of any processed buffers in the queue
1984 totalBufferLen = 0;
1985 BufferList = Source->queue;
1986 for(i = 0;BufferList;i++)
1988 if(BufferList->buffer)
1990 if(i < Source->BuffersPlayed)
1991 readPos += BufferList->buffer->SampleLen;
1992 totalBufferLen += BufferList->buffer->SampleLen;
1994 BufferList = BufferList->next;
1996 if(Source->state == AL_PLAYING)
1997 writePos = readPos + (ALuint)(updateLen*BufferFreq);
1998 else
1999 writePos = readPos;
2001 if(Source->bLooping)
2003 readPos %= totalBufferLen;
2004 writePos %= totalBufferLen;
2006 else
2008 // Wrap positions back to 0
2009 if(readPos >= totalBufferLen)
2010 readPos = 0;
2011 if(writePos >= totalBufferLen)
2012 writePos = 0;
2015 switch(name)
2017 case AL_SEC_OFFSET:
2018 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2019 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2020 break;
2021 case AL_SAMPLE_OFFSET:
2022 case AL_SAMPLE_RW_OFFSETS_SOFT:
2023 offset[0] = (ALdouble)readPos;
2024 offset[1] = (ALdouble)writePos;
2025 break;
2026 case AL_BYTE_OFFSET:
2027 case AL_BYTE_RW_OFFSETS_SOFT:
2028 // Take into account the original format of the Buffer
2029 if(Buffer->OriginalType == UserFmtIMA4)
2031 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2032 ALuint FrameBlockSize = 65;
2034 // Round down to nearest ADPCM block
2035 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2036 if(Source->state != AL_PLAYING)
2037 offset[1] = offset[0];
2038 else
2040 // Round up to nearest ADPCM block
2041 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2042 FrameBlockSize * BlockSize);
2045 else
2047 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2048 offset[0] = (ALdouble)(readPos * FrameSize);
2049 offset[1] = (ALdouble)(writePos * FrameSize);
2051 break;
2057 ApplyOffset
2059 Apply a playback offset to the Source. This function will update the queue (to correctly
2060 mark buffers as 'pending' or 'processed' depending upon the new offset.
2062 ALboolean ApplyOffset(ALsource *Source)
2064 const ALbufferlistitem *BufferList;
2065 const ALbuffer *Buffer;
2066 ALint bufferLen, totalBufferLen;
2067 ALint buffersPlayed;
2068 ALint offset;
2070 // Get true byte offset
2071 offset = GetSampleOffset(Source);
2073 // If the offset is invalid, don't apply it
2074 if(offset == -1)
2075 return AL_FALSE;
2077 // Sort out the queue (pending and processed states)
2078 BufferList = Source->queue;
2079 totalBufferLen = 0;
2080 buffersPlayed = 0;
2082 while(BufferList)
2084 Buffer = BufferList->buffer;
2085 bufferLen = Buffer ? Buffer->SampleLen : 0;
2087 if(bufferLen <= offset-totalBufferLen)
2089 // Offset is past this buffer so increment BuffersPlayed
2090 buffersPlayed++;
2092 else if(totalBufferLen <= offset)
2094 // Offset is within this buffer
2095 Source->BuffersPlayed = buffersPlayed;
2097 // SW Mixer Positions are in Samples
2098 Source->position = offset - totalBufferLen;
2099 return AL_TRUE;
2102 // Increment the TotalBufferSize
2103 totalBufferLen += bufferLen;
2105 // Move on to next buffer in the Queue
2106 BufferList = BufferList->next;
2108 // Offset is out of range of the buffer queue
2109 return AL_FALSE;
2114 GetSampleOffset
2116 Returns the sample offset into the Source's queue (from the Sample, Byte or Millisecond offset
2117 supplied by the application). This takes into account the fact that the buffer format may have
2118 been modifed by AL
2120 static ALint GetSampleOffset(ALsource *Source)
2122 const ALbuffer *Buffer = NULL;
2123 const ALbufferlistitem *BufferList;
2124 ALint Offset = -1;
2126 // Find the first non-NULL Buffer in the Queue
2127 BufferList = Source->queue;
2128 while(BufferList)
2130 if(BufferList->buffer)
2132 Buffer = BufferList->buffer;
2133 break;
2135 BufferList = BufferList->next;
2138 if(!Buffer)
2140 Source->Offset = -1.0;
2141 return -1;
2144 // Determine the ByteOffset (and ensure it is block aligned)
2145 switch(Source->OffsetType)
2147 case AL_BYTE_OFFSET:
2148 // Take into consideration the original format
2149 Offset = (ALint)Source->Offset;
2150 if(Buffer->OriginalType == UserFmtIMA4)
2152 // Round down to nearest ADPCM block
2153 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2154 // Multiply by compression rate (65 sample frames per block)
2155 Offset *= 65;
2157 else
2158 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2159 break;
2161 case AL_SAMPLE_OFFSET:
2162 Offset = (ALint)Source->Offset;
2163 break;
2165 case AL_SEC_OFFSET:
2166 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2167 break;
2169 // Clear Offset
2170 Source->Offset = -1.0;
2172 return Offset;
2176 ALvoid ReleaseALSources(ALCcontext *Context)
2178 ALsizei pos;
2179 ALuint j;
2180 for(pos = 0;pos < Context->SourceMap.size;pos++)
2182 ALsource *temp = Context->SourceMap.array[pos].value;
2183 Context->SourceMap.array[pos].value = NULL;
2185 // For each buffer in the source's queue, decrement its reference counter and remove it
2186 while(temp->queue != NULL)
2188 ALbufferlistitem *BufferList = temp->queue;
2189 temp->queue = BufferList->next;
2191 if(BufferList->buffer != NULL)
2192 DecrementRef(&BufferList->buffer->ref);
2193 free(BufferList);
2196 for(j = 0;j < MAX_SENDS;++j)
2198 if(temp->Send[j].Slot)
2199 DecrementRef(&temp->Send[j].Slot->ref);
2200 temp->Send[j].Slot = NULL;
2203 // Release source structure
2204 FreeThunkEntry(temp->source);
2205 memset(temp, 0, sizeof(ALsource));
2206 free(temp);