Handle the scalar values a bit better
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob7b4742df38a1e1e2d0d69dee18528b1f8541b0ba
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 GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
51 static ALint GetSampleOffset(ALsource *Source);
54 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
56 ALCcontext *Context;
57 ALsizei cur = 0;
59 Context = GetContextRef();
60 if(!Context) return;
62 al_try
64 ALenum err;
66 CHECK_VALUE(Context, n >= 0);
67 for(cur = 0;cur < n;cur++)
69 ALsource *source = calloc(1, sizeof(ALsource));
70 if(!source)
71 al_throwerr(Context, AL_OUT_OF_MEMORY);
72 InitSourceParams(source);
74 err = NewThunkEntry(&source->id);
75 if(err == AL_NO_ERROR)
76 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
77 if(err != AL_NO_ERROR)
79 FreeThunkEntry(source->id);
80 memset(source, 0, sizeof(ALsource));
81 free(source);
83 al_throwerr(Context, err);
86 sources[cur] = source->id;
89 al_catchany()
91 if(cur > 0)
92 alDeleteSources(cur, sources);
94 al_endtry;
96 ALCcontext_DecRef(Context);
100 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
102 ALCcontext *Context;
104 Context = GetContextRef();
105 if(!Context) return;
107 al_try
109 ALbufferlistitem *BufferList;
110 ALsource *Source;
111 ALsizei i, j;
113 CHECK_VALUE(Context, n >= 0);
115 /* Check that all Sources are valid */
116 for(i = 0;i < n;i++)
118 if(LookupSource(Context, sources[i]) == NULL)
119 al_throwerr(Context, AL_INVALID_NAME);
122 for(i = 0;i < n;i++)
124 ALsource **srclist, **srclistend;
126 if((Source=RemoveSource(Context, sources[i])) == NULL)
127 continue;
128 FreeThunkEntry(Source->id);
130 LockContext(Context);
131 srclist = Context->ActiveSources;
132 srclistend = srclist + Context->ActiveSourceCount;
133 while(srclist != srclistend)
135 if(*srclist == Source)
137 Context->ActiveSourceCount--;
138 *srclist = *(--srclistend);
139 break;
141 srclist++;
143 UnlockContext(Context);
145 while(Source->queue != NULL)
147 BufferList = Source->queue;
148 Source->queue = BufferList->next;
150 if(BufferList->buffer != NULL)
151 DecrementRef(&BufferList->buffer->ref);
152 free(BufferList);
155 for(j = 0;j < MAX_SENDS;++j)
157 if(Source->Send[j].Slot)
158 DecrementRef(&Source->Send[j].Slot->ref);
159 Source->Send[j].Slot = NULL;
162 memset(Source, 0, sizeof(*Source));
163 free(Source);
166 al_endtry;
168 ALCcontext_DecRef(Context);
172 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
174 ALCcontext *Context;
175 ALboolean result;
177 Context = GetContextRef();
178 if(!Context) return AL_FALSE;
180 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
182 ALCcontext_DecRef(Context);
184 return result;
188 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
190 ALCcontext *Context;
191 ALsource *Source;
193 Context = GetContextRef();
194 if(!Context) return;
196 al_try
198 if((Source=LookupSource(Context, source)) == NULL)
199 al_throwerr(Context, AL_INVALID_NAME);
200 switch(param)
202 case AL_PITCH:
203 CHECK_VALUE(Context, value >= 0.0f);
205 Source->Pitch = value;
206 Source->NeedsUpdate = AL_TRUE;
207 break;
209 case AL_CONE_INNER_ANGLE:
210 CHECK_VALUE(Context, value >= 0.0f && value <= 360.0f);
212 Source->InnerAngle = value;
213 Source->NeedsUpdate = AL_TRUE;
214 break;
216 case AL_CONE_OUTER_ANGLE:
217 CHECK_VALUE(Context, value >= 0.0f && value <= 360.0f);
219 Source->OuterAngle = value;
220 Source->NeedsUpdate = AL_TRUE;
221 break;
223 case AL_GAIN:
224 CHECK_VALUE(Context, value >= 0.0f);
226 Source->Gain = value;
227 Source->NeedsUpdate = AL_TRUE;
228 break;
230 case AL_MAX_DISTANCE:
231 CHECK_VALUE(Context, value >= 0.0f);
233 Source->MaxDistance = value;
234 Source->NeedsUpdate = AL_TRUE;
235 break;
237 case AL_ROLLOFF_FACTOR:
238 CHECK_VALUE(Context, value >= 0.0f);
240 Source->RollOffFactor = value;
241 Source->NeedsUpdate = AL_TRUE;
242 break;
244 case AL_REFERENCE_DISTANCE:
245 CHECK_VALUE(Context, value >= 0.0f);
247 Source->RefDistance = value;
248 Source->NeedsUpdate = AL_TRUE;
249 break;
251 case AL_MIN_GAIN:
252 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
254 Source->MinGain = value;
255 Source->NeedsUpdate = AL_TRUE;
256 break;
258 case AL_MAX_GAIN:
259 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
261 Source->MaxGain = value;
262 Source->NeedsUpdate = AL_TRUE;
263 break;
265 case AL_CONE_OUTER_GAIN:
266 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
268 Source->OuterGain = value;
269 Source->NeedsUpdate = AL_TRUE;
270 break;
272 case AL_CONE_OUTER_GAINHF:
273 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
275 Source->OuterGainHF = value;
276 Source->NeedsUpdate = AL_TRUE;
277 break;
279 case AL_AIR_ABSORPTION_FACTOR:
280 CHECK_VALUE(Context, value >= 0.0f && value <= 10.0f);
282 Source->AirAbsorptionFactor = value;
283 Source->NeedsUpdate = AL_TRUE;
284 break;
286 case AL_ROOM_ROLLOFF_FACTOR:
287 CHECK_VALUE(Context, value >= 0.0f && value <= 10.0f);
289 Source->RoomRolloffFactor = value;
290 Source->NeedsUpdate = AL_TRUE;
291 break;
293 case AL_DOPPLER_FACTOR:
294 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
296 Source->DopplerFactor = value;
297 Source->NeedsUpdate = AL_TRUE;
298 break;
300 case AL_SEC_OFFSET:
301 case AL_SAMPLE_OFFSET:
302 case AL_BYTE_OFFSET:
303 CHECK_VALUE(Context, value >= 0.0f);
305 LockContext(Context);
306 Source->OffsetType = param;
307 Source->Offset = value;
309 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
310 !Context->DeferUpdates)
312 if(ApplyOffset(Source) == AL_FALSE)
314 UnlockContext(Context);
315 al_throwerr(Context, AL_INVALID_VALUE);
318 UnlockContext(Context);
319 break;
321 default:
322 al_throwerr(Context, AL_INVALID_ENUM);
325 al_endtry;
327 ALCcontext_DecRef(Context);
331 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
333 ALCcontext *Context;
334 ALsource *Source;
336 Context = GetContextRef();
337 if(!Context) return;
339 al_try
341 if((Source=LookupSource(Context, source)) == NULL)
342 al_throwerr(Context, AL_INVALID_NAME);
343 switch(param)
345 case AL_POSITION:
346 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
348 LockContext(Context);
349 Source->Position[0] = value1;
350 Source->Position[1] = value2;
351 Source->Position[2] = value3;
352 UnlockContext(Context);
353 Source->NeedsUpdate = AL_TRUE;
354 break;
356 case AL_VELOCITY:
357 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
359 LockContext(Context);
360 Source->Velocity[0] = value1;
361 Source->Velocity[1] = value2;
362 Source->Velocity[2] = value3;
363 UnlockContext(Context);
364 Source->NeedsUpdate = AL_TRUE;
365 break;
367 case AL_DIRECTION:
368 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
370 LockContext(Context);
371 Source->Orientation[0] = value1;
372 Source->Orientation[1] = value2;
373 Source->Orientation[2] = value3;
374 UnlockContext(Context);
375 Source->NeedsUpdate = AL_TRUE;
376 break;
378 default:
379 al_throwerr(Context, AL_INVALID_ENUM);
382 al_endtry;
384 ALCcontext_DecRef(Context);
388 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
390 ALCcontext *Context;
392 if(values)
394 switch(param)
396 case AL_PITCH:
397 case AL_CONE_INNER_ANGLE:
398 case AL_CONE_OUTER_ANGLE:
399 case AL_GAIN:
400 case AL_MAX_DISTANCE:
401 case AL_ROLLOFF_FACTOR:
402 case AL_REFERENCE_DISTANCE:
403 case AL_MIN_GAIN:
404 case AL_MAX_GAIN:
405 case AL_CONE_OUTER_GAIN:
406 case AL_CONE_OUTER_GAINHF:
407 case AL_SEC_OFFSET:
408 case AL_SAMPLE_OFFSET:
409 case AL_BYTE_OFFSET:
410 case AL_AIR_ABSORPTION_FACTOR:
411 case AL_ROOM_ROLLOFF_FACTOR:
412 alSourcef(source, param, values[0]);
413 return;
415 case AL_POSITION:
416 case AL_VELOCITY:
417 case AL_DIRECTION:
418 alSource3f(source, param, values[0], values[1], values[2]);
419 return;
423 Context = GetContextRef();
424 if(!Context) return;
426 al_try
428 if(LookupSource(Context, source) == NULL)
429 al_throwerr(Context, AL_INVALID_NAME);
430 CHECK_VALUE(Context, values);
432 switch(param)
434 default:
435 al_throwerr(Context, AL_INVALID_ENUM);
438 al_endtry;
440 ALCcontext_DecRef(Context);
444 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
446 ALCcontext *Context;
447 ALsource *Source;
449 switch(param)
451 case AL_MAX_DISTANCE:
452 case AL_ROLLOFF_FACTOR:
453 case AL_CONE_INNER_ANGLE:
454 case AL_CONE_OUTER_ANGLE:
455 case AL_REFERENCE_DISTANCE:
456 alSourcef(source, param, (ALfloat)value);
457 return;
460 Context = GetContextRef();
461 if(!Context) return;
463 al_try
465 ALCdevice *device = Context->Device;
466 ALbuffer *buffer = NULL;
467 ALfilter *filter = NULL;
468 ALbufferlistitem *oldlist;
470 if((Source=LookupSource(Context, source)) == NULL)
471 al_throwerr(Context, AL_INVALID_NAME);
472 switch(param)
474 case AL_SOURCE_RELATIVE:
475 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
477 Source->HeadRelative = (ALboolean)value;
478 Source->NeedsUpdate = AL_TRUE;
479 break;
481 case AL_LOOPING:
482 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
484 Source->Looping = (ALboolean)value;
485 break;
487 case AL_BUFFER:
488 CHECK_VALUE(Context, value == 0 ||
489 (buffer=LookupBuffer(device, value)) != NULL);
491 LockContext(Context);
492 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
494 UnlockContext(Context);
495 al_throwerr(Context, AL_INVALID_OPERATION);
498 Source->BuffersInQueue = 0;
499 Source->BuffersPlayed = 0;
501 if(buffer != NULL)
503 ALbufferlistitem *BufferListItem;
505 /* Source is now Static */
506 Source->SourceType = AL_STATIC;
508 /* Add the selected buffer to a one-item queue */
509 BufferListItem = malloc(sizeof(ALbufferlistitem));
510 BufferListItem->buffer = buffer;
511 BufferListItem->next = NULL;
512 BufferListItem->prev = NULL;
513 IncrementRef(&buffer->ref);
515 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
516 Source->BuffersInQueue = 1;
518 ReadLock(&buffer->lock);
519 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
520 Source->SampleSize = BytesFromFmt(buffer->FmtType);
521 ReadUnlock(&buffer->lock);
522 if(buffer->FmtChannels == FmtMono)
523 Source->Update = CalcSourceParams;
524 else
525 Source->Update = CalcNonAttnSourceParams;
526 Source->NeedsUpdate = AL_TRUE;
528 else
530 /* Source is now Undetermined */
531 Source->SourceType = AL_UNDETERMINED;
532 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
535 /* Delete all elements in the previous queue */
536 while(oldlist != NULL)
538 ALbufferlistitem *temp = oldlist;
539 oldlist = temp->next;
541 if(temp->buffer)
542 DecrementRef(&temp->buffer->ref);
543 free(temp);
545 UnlockContext(Context);
546 break;
548 case AL_SOURCE_STATE:
549 /* Query only */
550 al_throwerr(Context, AL_INVALID_OPERATION);
552 case AL_SEC_OFFSET:
553 case AL_SAMPLE_OFFSET:
554 case AL_BYTE_OFFSET:
555 CHECK_VALUE(Context, value >= 0);
557 LockContext(Context);
558 Source->OffsetType = param;
559 Source->Offset = value;
561 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
562 !Context->DeferUpdates)
564 if(ApplyOffset(Source) == AL_FALSE)
566 UnlockContext(Context);
567 al_throwerr(Context, AL_INVALID_VALUE);
570 UnlockContext(Context);
571 break;
573 case AL_DIRECT_FILTER:
574 CHECK_VALUE(Context, value == 0 ||
575 (filter=LookupFilter(device, value)) != NULL);
577 LockContext(Context);
578 if(!filter)
580 Source->DirectGain = 1.0f;
581 Source->DirectGainHF = 1.0f;
583 else
585 Source->DirectGain = filter->Gain;
586 Source->DirectGainHF = filter->GainHF;
588 UnlockContext(Context);
589 Source->NeedsUpdate = AL_TRUE;
590 break;
592 case AL_DIRECT_FILTER_GAINHF_AUTO:
593 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
595 Source->DryGainHFAuto = value;
596 Source->NeedsUpdate = AL_TRUE;
597 break;
599 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
600 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
602 Source->WetGainAuto = value;
603 Source->NeedsUpdate = AL_TRUE;
604 break;
606 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
607 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
609 Source->WetGainHFAuto = value;
610 Source->NeedsUpdate = AL_TRUE;
611 break;
613 case AL_DIRECT_CHANNELS_SOFT:
614 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
616 Source->DirectChannels = value;
617 Source->NeedsUpdate = AL_TRUE;
618 break;
620 case AL_DISTANCE_MODEL:
621 CHECK_VALUE(Context, value == AL_NONE ||
622 value == AL_INVERSE_DISTANCE ||
623 value == AL_INVERSE_DISTANCE_CLAMPED ||
624 value == AL_LINEAR_DISTANCE ||
625 value == AL_LINEAR_DISTANCE_CLAMPED ||
626 value == AL_EXPONENT_DISTANCE ||
627 value == AL_EXPONENT_DISTANCE_CLAMPED);
629 Source->DistanceModel = value;
630 if(Context->SourceDistanceModel)
631 Source->NeedsUpdate = AL_TRUE;
632 break;
634 default:
635 al_throwerr(Context, AL_INVALID_ENUM);
638 al_endtry;
640 ALCcontext_DecRef(Context);
644 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
646 ALCcontext *Context;
647 ALsource *Source;
649 switch(param)
651 case AL_POSITION:
652 case AL_VELOCITY:
653 case AL_DIRECTION:
654 alSource3f(source, param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
655 return;
658 Context = GetContextRef();
659 if(!Context) return;
661 al_try
663 ALCdevice *device = Context->Device;
664 ALeffectslot *slot = NULL;
665 ALfilter *filter = NULL;
667 if((Source=LookupSource(Context, source)) == NULL)
668 al_throwerr(Context, AL_INVALID_NAME);
669 switch(param)
671 case AL_AUXILIARY_SEND_FILTER:
672 LockContext(Context);
673 if(!((ALuint)value2 < device->NumAuxSends &&
674 (value1 == 0 || (slot=LookupEffectSlot(Context, value1)) != NULL) &&
675 (value3 == 0 || (filter=LookupFilter(device, value3)) != NULL)))
677 UnlockContext(Context);
678 al_throwerr(Context, AL_INVALID_VALUE);
681 /* Add refcount on the new slot, and release the previous slot */
682 if(slot) IncrementRef(&slot->ref);
683 slot = ExchangePtr((XchgPtr*)&Source->Send[value2].Slot, slot);
684 if(slot) DecrementRef(&slot->ref);
686 if(!filter)
688 /* Disable filter */
689 Source->Send[value2].Gain = 1.0f;
690 Source->Send[value2].GainHF = 1.0f;
692 else
694 Source->Send[value2].Gain = filter->Gain;
695 Source->Send[value2].GainHF = filter->GainHF;
697 Source->NeedsUpdate = AL_TRUE;
698 UnlockContext(Context);
699 break;
701 default:
702 al_throwerr(Context, AL_INVALID_ENUM);
705 al_endtry;
707 ALCcontext_DecRef(Context);
711 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
713 ALCcontext *Context;
715 if(values)
717 switch(param)
719 case AL_SOURCE_RELATIVE:
720 case AL_CONE_INNER_ANGLE:
721 case AL_CONE_OUTER_ANGLE:
722 case AL_LOOPING:
723 case AL_BUFFER:
724 case AL_SOURCE_STATE:
725 case AL_SEC_OFFSET:
726 case AL_SAMPLE_OFFSET:
727 case AL_BYTE_OFFSET:
728 case AL_MAX_DISTANCE:
729 case AL_ROLLOFF_FACTOR:
730 case AL_REFERENCE_DISTANCE:
731 case AL_DIRECT_FILTER:
732 case AL_DIRECT_FILTER_GAINHF_AUTO:
733 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
734 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
735 case AL_DISTANCE_MODEL:
736 case AL_DIRECT_CHANNELS_SOFT:
737 alSourcei(source, param, values[0]);
738 return;
740 case AL_POSITION:
741 case AL_VELOCITY:
742 case AL_DIRECTION:
743 case AL_AUXILIARY_SEND_FILTER:
744 alSource3i(source, param, values[0], values[1], values[2]);
745 return;
749 Context = GetContextRef();
750 if(!Context) return;
752 al_try
754 if(LookupSource(Context, source) == NULL)
755 al_throwerr(Context, AL_INVALID_NAME);
756 CHECK_VALUE(Context, values);
757 switch(param)
759 default:
760 al_throwerr(Context, AL_INVALID_ENUM);
763 al_endtry;
765 ALCcontext_DecRef(Context);
769 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
771 ALCcontext *Context;
772 ALsource *Source;
773 ALdouble offsets[2];
774 ALdouble updateLen;
776 Context = GetContextRef();
777 if(!Context) return;
779 al_try
781 if((Source=LookupSource(Context, source)) == NULL)
782 al_throwerr(Context, AL_INVALID_NAME);
783 CHECK_VALUE(Context, value);
784 switch(param)
786 case AL_PITCH:
787 *value = Source->Pitch;
788 break;
790 case AL_GAIN:
791 *value = Source->Gain;
792 break;
794 case AL_MIN_GAIN:
795 *value = Source->MinGain;
796 break;
798 case AL_MAX_GAIN:
799 *value = Source->MaxGain;
800 break;
802 case AL_MAX_DISTANCE:
803 *value = Source->MaxDistance;
804 break;
806 case AL_ROLLOFF_FACTOR:
807 *value = Source->RollOffFactor;
808 break;
810 case AL_CONE_OUTER_GAIN:
811 *value = Source->OuterGain;
812 break;
814 case AL_CONE_OUTER_GAINHF:
815 *value = Source->OuterGainHF;
816 break;
818 case AL_SEC_OFFSET:
819 case AL_SAMPLE_OFFSET:
820 case AL_BYTE_OFFSET:
821 LockContext(Context);
822 updateLen = (ALdouble)Context->Device->UpdateSize /
823 Context->Device->Frequency;
824 GetSourceOffsets(Source, param, offsets, updateLen);
825 UnlockContext(Context);
826 *value = (ALfloat)offsets[0];
827 break;
829 case AL_CONE_INNER_ANGLE:
830 *value = Source->InnerAngle;
831 break;
833 case AL_CONE_OUTER_ANGLE:
834 *value = Source->OuterAngle;
835 break;
837 case AL_REFERENCE_DISTANCE:
838 *value = Source->RefDistance;
839 break;
841 case AL_AIR_ABSORPTION_FACTOR:
842 *value = Source->AirAbsorptionFactor;
843 break;
845 case AL_ROOM_ROLLOFF_FACTOR:
846 *value = Source->RoomRolloffFactor;
847 break;
849 case AL_DOPPLER_FACTOR:
850 *value = Source->DopplerFactor;
851 break;
853 default:
854 al_throwerr(Context, AL_INVALID_ENUM);
857 al_endtry;
859 ALCcontext_DecRef(Context);
863 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
865 ALCcontext *Context;
866 ALsource *Source;
868 Context = GetContextRef();
869 if(!Context) return;
871 al_try
873 if((Source=LookupSource(Context, source)) == NULL)
874 al_throwerr(Context, AL_INVALID_NAME);
875 CHECK_VALUE(Context, value1 && value2 && value3);
876 switch(param)
878 case AL_POSITION:
879 LockContext(Context);
880 *value1 = Source->Position[0];
881 *value2 = Source->Position[1];
882 *value3 = Source->Position[2];
883 UnlockContext(Context);
884 break;
886 case AL_VELOCITY:
887 LockContext(Context);
888 *value1 = Source->Velocity[0];
889 *value2 = Source->Velocity[1];
890 *value3 = Source->Velocity[2];
891 UnlockContext(Context);
892 break;
894 case AL_DIRECTION:
895 LockContext(Context);
896 *value1 = Source->Orientation[0];
897 *value2 = Source->Orientation[1];
898 *value3 = Source->Orientation[2];
899 UnlockContext(Context);
900 break;
902 default:
903 al_throwerr(Context, AL_INVALID_ENUM);
906 al_endtry;
908 ALCcontext_DecRef(Context);
912 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
914 ALCcontext *Context;
915 ALsource *Source;
916 ALdouble offsets[2];
917 ALdouble updateLen;
919 switch(param)
921 case AL_PITCH:
922 case AL_GAIN:
923 case AL_MIN_GAIN:
924 case AL_MAX_GAIN:
925 case AL_MAX_DISTANCE:
926 case AL_ROLLOFF_FACTOR:
927 case AL_DOPPLER_FACTOR:
928 case AL_CONE_OUTER_GAIN:
929 case AL_SEC_OFFSET:
930 case AL_SAMPLE_OFFSET:
931 case AL_BYTE_OFFSET:
932 case AL_CONE_INNER_ANGLE:
933 case AL_CONE_OUTER_ANGLE:
934 case AL_REFERENCE_DISTANCE:
935 case AL_CONE_OUTER_GAINHF:
936 case AL_AIR_ABSORPTION_FACTOR:
937 case AL_ROOM_ROLLOFF_FACTOR:
938 alGetSourcef(source, param, values);
939 return;
941 case AL_POSITION:
942 case AL_VELOCITY:
943 case AL_DIRECTION:
944 alGetSource3f(source, param, values+0, values+1, values+2);
945 return;
948 Context = GetContextRef();
949 if(!Context) return;
951 al_try
953 if((Source=LookupSource(Context, source)) == NULL)
954 al_throwerr(Context, AL_INVALID_NAME);
955 CHECK_VALUE(Context, values);
956 switch(param)
958 case AL_SAMPLE_RW_OFFSETS_SOFT:
959 case AL_BYTE_RW_OFFSETS_SOFT:
960 LockContext(Context);
961 updateLen = (ALdouble)Context->Device->UpdateSize /
962 Context->Device->Frequency;
963 GetSourceOffsets(Source, param, offsets, updateLen);
964 UnlockContext(Context);
965 values[0] = (ALfloat)offsets[0];
966 values[1] = (ALfloat)offsets[1];
967 break;
969 default:
970 al_throwerr(Context, AL_INVALID_ENUM);
973 al_endtry;
975 ALCcontext_DecRef(Context);
979 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
981 ALbufferlistitem *BufferList;
982 ALCcontext *Context;
983 ALsource *Source;
984 ALdouble offsets[2];
985 ALdouble updateLen;
987 Context = GetContextRef();
988 if(!Context) return;
990 al_try
992 if((Source=LookupSource(Context, source)) == NULL)
993 al_throwerr(Context, AL_INVALID_NAME);
994 CHECK_VALUE(Context, value);
995 switch(param)
997 case AL_MAX_DISTANCE:
998 *value = (ALint)Source->MaxDistance;
999 break;
1001 case AL_ROLLOFF_FACTOR:
1002 *value = (ALint)Source->RollOffFactor;
1003 break;
1005 case AL_REFERENCE_DISTANCE:
1006 *value = (ALint)Source->RefDistance;
1007 break;
1009 case AL_SOURCE_RELATIVE:
1010 *value = Source->HeadRelative;
1011 break;
1013 case AL_CONE_INNER_ANGLE:
1014 *value = (ALint)Source->InnerAngle;
1015 break;
1017 case AL_CONE_OUTER_ANGLE:
1018 *value = (ALint)Source->OuterAngle;
1019 break;
1021 case AL_LOOPING:
1022 *value = Source->Looping;
1023 break;
1025 case AL_BUFFER:
1026 LockContext(Context);
1027 BufferList = Source->queue;
1028 if(Source->SourceType != AL_STATIC)
1030 ALuint i = Source->BuffersPlayed;
1031 while(i > 0)
1033 BufferList = BufferList->next;
1034 i--;
1037 *value = ((BufferList && BufferList->buffer) ?
1038 BufferList->buffer->id : 0);
1039 UnlockContext(Context);
1040 break;
1042 case AL_SOURCE_STATE:
1043 *value = Source->state;
1044 break;
1046 case AL_BUFFERS_QUEUED:
1047 *value = Source->BuffersInQueue;
1048 break;
1050 case AL_BUFFERS_PROCESSED:
1051 LockContext(Context);
1052 if(Source->Looping || Source->SourceType != AL_STREAMING)
1054 /* Buffers on a looping source are in a perpetual state of
1055 * PENDING, so don't report any as PROCESSED */
1056 *value = 0;
1058 else
1059 *value = Source->BuffersPlayed;
1060 UnlockContext(Context);
1061 break;
1063 case AL_SOURCE_TYPE:
1064 *value = Source->SourceType;
1065 break;
1067 case AL_SEC_OFFSET:
1068 case AL_SAMPLE_OFFSET:
1069 case AL_BYTE_OFFSET:
1070 LockContext(Context);
1071 updateLen = (ALdouble)Context->Device->UpdateSize /
1072 Context->Device->Frequency;
1073 GetSourceOffsets(Source, param, offsets, updateLen);
1074 UnlockContext(Context);
1075 *value = (ALint)offsets[0];
1076 break;
1078 case AL_DIRECT_FILTER_GAINHF_AUTO:
1079 *value = Source->DryGainHFAuto;
1080 break;
1082 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1083 *value = Source->WetGainAuto;
1084 break;
1086 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1087 *value = Source->WetGainHFAuto;
1088 break;
1090 case AL_DOPPLER_FACTOR:
1091 *value = (ALint)Source->DopplerFactor;
1092 break;
1094 case AL_DIRECT_CHANNELS_SOFT:
1095 *value = Source->DirectChannels;
1096 break;
1098 case AL_DISTANCE_MODEL:
1099 *value = Source->DistanceModel;
1100 break;
1102 default:
1103 al_throwerr(Context, AL_INVALID_ENUM);
1106 al_endtry;
1108 ALCcontext_DecRef(Context);
1112 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1114 ALCcontext *Context;
1115 ALsource *Source;
1117 Context = GetContextRef();
1118 if(!Context) return;
1120 al_try
1122 if((Source=LookupSource(Context, source)) == NULL)
1123 al_throwerr(Context, AL_INVALID_NAME);
1124 CHECK_VALUE(Context, value1 && value2 && value3);
1125 switch(param)
1127 case AL_POSITION:
1128 LockContext(Context);
1129 *value1 = (ALint)Source->Position[0];
1130 *value2 = (ALint)Source->Position[1];
1131 *value3 = (ALint)Source->Position[2];
1132 UnlockContext(Context);
1133 break;
1135 case AL_VELOCITY:
1136 LockContext(Context);
1137 *value1 = (ALint)Source->Velocity[0];
1138 *value2 = (ALint)Source->Velocity[1];
1139 *value3 = (ALint)Source->Velocity[2];
1140 UnlockContext(Context);
1141 break;
1143 case AL_DIRECTION:
1144 LockContext(Context);
1145 *value1 = (ALint)Source->Orientation[0];
1146 *value2 = (ALint)Source->Orientation[1];
1147 *value3 = (ALint)Source->Orientation[2];
1148 UnlockContext(Context);
1149 break;
1151 default:
1152 al_throwerr(Context, AL_INVALID_ENUM);
1155 al_endtry;
1157 ALCcontext_DecRef(Context);
1161 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1163 ALCcontext *Context;
1164 ALsource *Source;
1165 ALdouble offsets[2];
1166 ALdouble updateLen;
1168 switch(param)
1170 case AL_SOURCE_RELATIVE:
1171 case AL_CONE_INNER_ANGLE:
1172 case AL_CONE_OUTER_ANGLE:
1173 case AL_LOOPING:
1174 case AL_BUFFER:
1175 case AL_SOURCE_STATE:
1176 case AL_BUFFERS_QUEUED:
1177 case AL_BUFFERS_PROCESSED:
1178 case AL_SEC_OFFSET:
1179 case AL_SAMPLE_OFFSET:
1180 case AL_BYTE_OFFSET:
1181 case AL_MAX_DISTANCE:
1182 case AL_ROLLOFF_FACTOR:
1183 case AL_DOPPLER_FACTOR:
1184 case AL_REFERENCE_DISTANCE:
1185 case AL_SOURCE_TYPE:
1186 case AL_DIRECT_FILTER:
1187 case AL_DIRECT_FILTER_GAINHF_AUTO:
1188 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1189 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1190 case AL_DISTANCE_MODEL:
1191 case AL_DIRECT_CHANNELS_SOFT:
1192 alGetSourcei(source, param, values);
1193 return;
1195 case AL_POSITION:
1196 case AL_VELOCITY:
1197 case AL_DIRECTION:
1198 alGetSource3i(source, param, values+0, values+1, values+2);
1199 return;
1202 Context = GetContextRef();
1203 if(!Context) return;
1205 al_try
1207 if((Source=LookupSource(Context, source)) == NULL)
1208 al_throwerr(Context, AL_INVALID_NAME);
1209 CHECK_VALUE(Context, values);
1210 switch(param)
1212 case AL_SAMPLE_RW_OFFSETS_SOFT:
1213 case AL_BYTE_RW_OFFSETS_SOFT:
1214 LockContext(Context);
1215 updateLen = (ALdouble)Context->Device->UpdateSize /
1216 Context->Device->Frequency;
1217 GetSourceOffsets(Source, param, offsets, updateLen);
1218 UnlockContext(Context);
1219 values[0] = (ALint)offsets[0];
1220 values[1] = (ALint)offsets[1];
1221 break;
1223 default:
1224 al_throwerr(Context, AL_INVALID_ENUM);
1227 al_endtry;
1229 ALCcontext_DecRef(Context);
1233 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1235 alSourcePlayv(1, &source);
1237 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1239 ALCcontext *Context;
1240 ALsource *Source;
1241 ALsizei i;
1243 Context = GetContextRef();
1244 if(!Context) return;
1246 al_try
1248 CHECK_VALUE(Context, n >= 0);
1249 for(i = 0;i < n;i++)
1251 if(!LookupSource(Context, sources[i]))
1252 al_throwerr(Context, AL_INVALID_NAME);
1255 LockContext(Context);
1256 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1258 void *temp = NULL;
1259 ALsizei newcount;
1261 newcount = Context->MaxActiveSources << 1;
1262 if(newcount > 0)
1263 temp = realloc(Context->ActiveSources,
1264 sizeof(*Context->ActiveSources) * newcount);
1265 if(!temp)
1267 UnlockContext(Context);
1268 al_throwerr(Context, AL_OUT_OF_MEMORY);
1271 Context->ActiveSources = temp;
1272 Context->MaxActiveSources = newcount;
1275 for(i = 0;i < n;i++)
1277 Source = LookupSource(Context, sources[i]);
1278 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1279 else SetSourceState(Source, Context, AL_PLAYING);
1281 UnlockContext(Context);
1283 al_endtry;
1285 ALCcontext_DecRef(Context);
1288 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1290 alSourcePausev(1, &source);
1292 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1294 ALCcontext *Context;
1295 ALsource *Source;
1296 ALsizei i;
1298 Context = GetContextRef();
1299 if(!Context) return;
1301 al_try
1303 CHECK_VALUE(Context, n >= 0);
1304 for(i = 0;i < n;i++)
1306 if(!LookupSource(Context, sources[i]))
1307 al_throwerr(Context, AL_INVALID_NAME);
1310 LockContext(Context);
1311 for(i = 0;i < n;i++)
1313 Source = LookupSource(Context, sources[i]);
1314 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1315 else SetSourceState(Source, Context, AL_PAUSED);
1317 UnlockContext(Context);
1319 al_endtry;
1321 ALCcontext_DecRef(Context);
1324 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1326 alSourceStopv(1, &source);
1328 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1330 ALCcontext *Context;
1331 ALsource *Source;
1332 ALsizei i;
1334 Context = GetContextRef();
1335 if(!Context) return;
1337 al_try
1339 CHECK_VALUE(Context, n >= 0);
1340 for(i = 0;i < n;i++)
1342 if(!LookupSource(Context, sources[i]))
1343 al_throwerr(Context, AL_INVALID_NAME);
1346 LockContext(Context);
1347 for(i = 0;i < n;i++)
1349 Source = LookupSource(Context, sources[i]);
1350 Source->new_state = AL_NONE;
1351 SetSourceState(Source, Context, AL_STOPPED);
1353 UnlockContext(Context);
1355 al_endtry;
1357 ALCcontext_DecRef(Context);
1360 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1362 alSourceRewindv(1, &source);
1364 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1366 ALCcontext *Context;
1367 ALsource *Source;
1368 ALsizei i;
1370 Context = GetContextRef();
1371 if(!Context) return;
1373 al_try
1375 CHECK_VALUE(Context, n >= 0);
1376 for(i = 0;i < n;i++)
1378 if(!LookupSource(Context, sources[i]))
1379 al_throwerr(Context, AL_INVALID_NAME);
1382 LockContext(Context);
1383 for(i = 0;i < n;i++)
1385 Source = LookupSource(Context, sources[i]);
1386 Source->new_state = AL_NONE;
1387 SetSourceState(Source, Context, AL_INITIAL);
1389 UnlockContext(Context);
1391 al_endtry;
1393 ALCcontext_DecRef(Context);
1397 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
1399 ALCcontext *Context;
1400 ALsource *Source;
1401 ALsizei i;
1402 ALbufferlistitem *BufferListStart = NULL;
1403 ALbufferlistitem *BufferList;
1404 ALbuffer *BufferFmt;
1406 if(nb == 0)
1407 return;
1409 Context = GetContextRef();
1410 if(!Context) return;
1412 al_try
1414 ALCdevice *device = Context->Device;
1416 CHECK_VALUE(Context, nb >= 0);
1418 if((Source=LookupSource(Context, source)) == NULL)
1419 al_throwerr(Context, AL_INVALID_NAME);
1421 LockContext(Context);
1422 if(Source->SourceType == AL_STATIC)
1424 UnlockContext(Context);
1425 /* Can't queue on a Static Source */
1426 al_throwerr(Context, AL_INVALID_OPERATION);
1429 BufferFmt = NULL;
1431 /* Check for a valid Buffer, for its frequency and format */
1432 BufferList = Source->queue;
1433 while(BufferList)
1435 if(BufferList->buffer)
1437 BufferFmt = BufferList->buffer;
1438 break;
1440 BufferList = BufferList->next;
1443 for(i = 0;i < nb;i++)
1445 ALbuffer *buffer = NULL;
1446 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1448 UnlockContext(Context);
1449 al_throwerr(Context, AL_INVALID_NAME);
1452 if(!BufferListStart)
1454 BufferListStart = malloc(sizeof(ALbufferlistitem));
1455 BufferListStart->buffer = buffer;
1456 BufferListStart->next = NULL;
1457 BufferListStart->prev = NULL;
1458 BufferList = BufferListStart;
1460 else
1462 BufferList->next = malloc(sizeof(ALbufferlistitem));
1463 BufferList->next->buffer = buffer;
1464 BufferList->next->next = NULL;
1465 BufferList->next->prev = BufferList;
1466 BufferList = BufferList->next;
1468 if(!buffer) continue;
1469 IncrementRef(&buffer->ref);
1471 ReadLock(&buffer->lock);
1472 if(BufferFmt == NULL)
1474 BufferFmt = buffer;
1476 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1477 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1478 if(buffer->FmtChannels == FmtMono)
1479 Source->Update = CalcSourceParams;
1480 else
1481 Source->Update = CalcNonAttnSourceParams;
1483 Source->NeedsUpdate = AL_TRUE;
1485 else if(BufferFmt->Frequency != buffer->Frequency ||
1486 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1487 BufferFmt->OriginalType != buffer->OriginalType)
1489 ReadUnlock(&buffer->lock);
1490 UnlockContext(Context);
1491 al_throwerr(Context, AL_INVALID_OPERATION);
1493 ReadUnlock(&buffer->lock);
1496 /* Source is now streaming */
1497 Source->SourceType = AL_STREAMING;
1499 if(Source->queue == NULL)
1500 Source->queue = BufferListStart;
1501 else
1503 /* Append to the end of the queue */
1504 BufferList = Source->queue;
1505 while(BufferList->next != NULL)
1506 BufferList = BufferList->next;
1508 BufferListStart->prev = BufferList;
1509 BufferList->next = BufferListStart;
1512 Source->BuffersInQueue += nb;
1514 UnlockContext(Context);
1516 al_catchany()
1518 while(BufferListStart)
1520 BufferList = BufferListStart;
1521 BufferListStart = BufferList->next;
1523 if(BufferList->buffer)
1524 DecrementRef(&BufferList->buffer->ref);
1525 free(BufferList);
1528 al_endtry;
1530 ALCcontext_DecRef(Context);
1533 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
1535 ALCcontext *Context;
1536 ALsource *Source;
1537 ALsizei i;
1538 ALbufferlistitem *BufferList;
1540 if(nb == 0)
1541 return;
1543 Context = GetContextRef();
1544 if(!Context) return;
1546 al_try
1548 CHECK_VALUE(Context, nb >= 0);
1550 if((Source=LookupSource(Context, source)) == NULL)
1551 al_throwerr(Context, AL_INVALID_NAME);
1553 LockContext(Context);
1554 if(Source->Looping || Source->SourceType != AL_STREAMING ||
1555 (ALuint)nb > Source->BuffersPlayed)
1557 UnlockContext(Context);
1558 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1559 al_throwerr(Context, AL_INVALID_VALUE);
1562 for(i = 0;i < nb;i++)
1564 BufferList = Source->queue;
1565 Source->queue = BufferList->next;
1566 Source->BuffersInQueue--;
1567 Source->BuffersPlayed--;
1569 if(BufferList->buffer)
1571 buffers[i] = BufferList->buffer->id;
1572 DecrementRef(&BufferList->buffer->ref);
1574 else
1575 buffers[i] = 0;
1577 free(BufferList);
1579 if(Source->queue)
1580 Source->queue->prev = NULL;
1581 UnlockContext(Context);
1583 al_endtry;
1585 ALCcontext_DecRef(Context);
1589 static ALvoid InitSourceParams(ALsource *Source)
1591 ALuint i;
1593 Source->InnerAngle = 360.0f;
1594 Source->OuterAngle = 360.0f;
1595 Source->Pitch = 1.0f;
1596 Source->Position[0] = 0.0f;
1597 Source->Position[1] = 0.0f;
1598 Source->Position[2] = 0.0f;
1599 Source->Orientation[0] = 0.0f;
1600 Source->Orientation[1] = 0.0f;
1601 Source->Orientation[2] = 0.0f;
1602 Source->Velocity[0] = 0.0f;
1603 Source->Velocity[1] = 0.0f;
1604 Source->Velocity[2] = 0.0f;
1605 Source->RefDistance = 1.0f;
1606 Source->MaxDistance = FLT_MAX;
1607 Source->RollOffFactor = 1.0f;
1608 Source->Looping = AL_FALSE;
1609 Source->Gain = 1.0f;
1610 Source->MinGain = 0.0f;
1611 Source->MaxGain = 1.0f;
1612 Source->OuterGain = 0.0f;
1613 Source->OuterGainHF = 1.0f;
1615 Source->DryGainHFAuto = AL_TRUE;
1616 Source->WetGainAuto = AL_TRUE;
1617 Source->WetGainHFAuto = AL_TRUE;
1618 Source->AirAbsorptionFactor = 0.0f;
1619 Source->RoomRolloffFactor = 0.0f;
1620 Source->DopplerFactor = 1.0f;
1621 Source->DirectChannels = AL_FALSE;
1623 Source->DistanceModel = DefaultDistanceModel;
1625 Source->Resampler = DefaultResampler;
1627 Source->state = AL_INITIAL;
1628 Source->new_state = AL_NONE;
1629 Source->SourceType = AL_UNDETERMINED;
1630 Source->Offset = -1.0;
1632 Source->DirectGain = 1.0f;
1633 Source->DirectGainHF = 1.0f;
1634 for(i = 0;i < MAX_SENDS;i++)
1636 Source->Send[i].Gain = 1.0f;
1637 Source->Send[i].GainHF = 1.0f;
1640 Source->NeedsUpdate = AL_TRUE;
1642 Source->Hrtf.Moving = AL_FALSE;
1643 Source->Hrtf.Counter = 0;
1647 /* SetSourceState
1649 * Sets the source's new play state given its current state.
1651 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1653 if(state == AL_PLAYING)
1655 ALbufferlistitem *BufferList;
1656 ALsizei j, k;
1658 /* Check that there is a queue containing at least one valid, non zero
1659 * length Buffer. */
1660 BufferList = Source->queue;
1661 while(BufferList)
1663 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1664 break;
1665 BufferList = BufferList->next;
1668 if(Source->state != AL_PLAYING)
1670 for(j = 0;j < MaxChannels;j++)
1672 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1673 Source->Hrtf.History[j][k] = 0.0f;
1674 for(k = 0;k < HRIR_LENGTH;k++)
1676 Source->Hrtf.Values[j][k][0] = 0.0f;
1677 Source->Hrtf.Values[j][k][1] = 0.0f;
1682 if(Source->state != AL_PAUSED)
1684 Source->state = AL_PLAYING;
1685 Source->position = 0;
1686 Source->position_fraction = 0;
1687 Source->BuffersPlayed = 0;
1689 else
1690 Source->state = AL_PLAYING;
1692 // Check if an Offset has been set
1693 if(Source->Offset >= 0.0)
1694 ApplyOffset(Source);
1696 /* If there's nothing to play, or device is disconnected, go right to
1697 * stopped */
1698 if(!BufferList || !Context->Device->Connected)
1700 SetSourceState(Source, Context, AL_STOPPED);
1701 return;
1704 for(j = 0;j < Context->ActiveSourceCount;j++)
1706 if(Context->ActiveSources[j] == Source)
1707 break;
1709 if(j == Context->ActiveSourceCount)
1710 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1712 else if(state == AL_PAUSED)
1714 if(Source->state == AL_PLAYING)
1716 Source->state = AL_PAUSED;
1717 Source->Hrtf.Moving = AL_FALSE;
1718 Source->Hrtf.Counter = 0;
1721 else if(state == AL_STOPPED)
1723 if(Source->state != AL_INITIAL)
1725 Source->state = AL_STOPPED;
1726 Source->BuffersPlayed = Source->BuffersInQueue;
1727 Source->Hrtf.Moving = AL_FALSE;
1728 Source->Hrtf.Counter = 0;
1730 Source->Offset = -1.0;
1732 else if(state == AL_INITIAL)
1734 if(Source->state != AL_INITIAL)
1736 Source->state = AL_INITIAL;
1737 Source->position = 0;
1738 Source->position_fraction = 0;
1739 Source->BuffersPlayed = 0;
1740 Source->Hrtf.Moving = AL_FALSE;
1741 Source->Hrtf.Counter = 0;
1743 Source->Offset = -1.0;
1747 /* GetSourceOffsets
1749 * Gets the current read and write offsets for the given Source, in the
1750 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
1751 * the start of the queue (not the start of the current buffer).
1753 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1755 const ALbufferlistitem *BufferList;
1756 const ALbuffer *Buffer = NULL;
1757 ALuint readPos, writePos;
1758 ALuint totalBufferLen;
1759 ALuint i;
1761 // Find the first valid Buffer in the Queue
1762 BufferList = Source->queue;
1763 while(BufferList)
1765 if(BufferList->buffer)
1767 Buffer = BufferList->buffer;
1768 break;
1770 BufferList = BufferList->next;
1773 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1775 offset[0] = 0.0;
1776 offset[1] = 0.0;
1777 return;
1780 if(updateLen > 0.0 && updateLen < 0.015)
1781 updateLen = 0.015;
1783 /* NOTE: This is the offset into the *current* buffer, so add the length of
1784 * any played buffers */
1785 readPos = Source->position;
1786 totalBufferLen = 0;
1787 BufferList = Source->queue;
1788 for(i = 0;BufferList;i++)
1790 if(BufferList->buffer)
1792 if(i < Source->BuffersPlayed)
1793 readPos += BufferList->buffer->SampleLen;
1794 totalBufferLen += BufferList->buffer->SampleLen;
1796 BufferList = BufferList->next;
1798 if(Source->state == AL_PLAYING)
1799 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
1800 else
1801 writePos = readPos;
1803 if(Source->Looping)
1805 readPos %= totalBufferLen;
1806 writePos %= totalBufferLen;
1808 else
1810 /* Wrap positions back to 0 */
1811 if(readPos >= totalBufferLen)
1812 readPos = 0;
1813 if(writePos >= totalBufferLen)
1814 writePos = 0;
1817 switch(name)
1819 case AL_SEC_OFFSET:
1820 offset[0] = (ALdouble)readPos / Buffer->Frequency;
1821 offset[1] = (ALdouble)writePos / Buffer->Frequency;
1822 break;
1824 case AL_SAMPLE_OFFSET:
1825 case AL_SAMPLE_RW_OFFSETS_SOFT:
1826 offset[0] = (ALdouble)readPos;
1827 offset[1] = (ALdouble)writePos;
1828 break;
1830 case AL_BYTE_OFFSET:
1831 case AL_BYTE_RW_OFFSETS_SOFT:
1832 if(Buffer->OriginalType == UserFmtIMA4)
1834 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
1835 ALuint FrameBlockSize = 65;
1837 /* Round down to nearest ADPCM block */
1838 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1839 if(Source->state != AL_PLAYING)
1840 offset[1] = offset[0];
1841 else
1843 /* Round up to nearest ADPCM block */
1844 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1845 FrameBlockSize * BlockSize);
1848 else
1850 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
1851 offset[0] = (ALdouble)(readPos * FrameSize);
1852 offset[1] = (ALdouble)(writePos * FrameSize);
1854 break;
1859 /* ApplyOffset
1861 * Apply the stored playback offset to the Source. This function will update
1862 * the number of buffers "played" given the stored offset.
1864 ALboolean ApplyOffset(ALsource *Source)
1866 const ALbufferlistitem *BufferList;
1867 const ALbuffer *Buffer;
1868 ALint bufferLen, totalBufferLen;
1869 ALint buffersPlayed;
1870 ALint offset;
1872 /* Get sample frame offset */
1873 offset = GetSampleOffset(Source);
1874 if(offset == -1)
1875 return AL_FALSE;
1877 buffersPlayed = 0;
1878 totalBufferLen = 0;
1880 BufferList = Source->queue;
1881 while(BufferList)
1883 Buffer = BufferList->buffer;
1884 bufferLen = Buffer ? Buffer->SampleLen : 0;
1886 if(bufferLen <= offset-totalBufferLen)
1888 /* Offset is past this buffer so increment to the next buffer */
1889 buffersPlayed++;
1891 else if(totalBufferLen <= offset)
1893 /* Offset is in this buffer */
1894 Source->BuffersPlayed = buffersPlayed;
1896 Source->position = offset - totalBufferLen;
1897 Source->position_fraction = 0;
1898 return AL_TRUE;
1901 totalBufferLen += bufferLen;
1903 BufferList = BufferList->next;
1906 /* Offset is out of range of the queue */
1907 return AL_FALSE;
1911 /* GetSampleOffset
1913 * Returns the sample offset into the Source's queue (from the Sample, Byte or
1914 * Second offset supplied by the application). This takes into account the fact
1915 * that the buffer format may have been modifed since.
1917 static ALint GetSampleOffset(ALsource *Source)
1919 const ALbuffer *Buffer = NULL;
1920 const ALbufferlistitem *BufferList;
1921 ALint Offset = -1;
1923 /* Find the first valid Buffer in the Queue */
1924 BufferList = Source->queue;
1925 while(BufferList)
1927 if(BufferList->buffer)
1929 Buffer = BufferList->buffer;
1930 break;
1932 BufferList = BufferList->next;
1935 if(!Buffer)
1937 Source->Offset = -1.0;
1938 return -1;
1941 switch(Source->OffsetType)
1943 case AL_BYTE_OFFSET:
1944 /* Determine the ByteOffset (and ensure it is block aligned) */
1945 Offset = (ALint)Source->Offset;
1946 if(Buffer->OriginalType == UserFmtIMA4)
1948 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
1949 Offset *= 65;
1951 else
1952 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
1953 break;
1955 case AL_SAMPLE_OFFSET:
1956 Offset = (ALint)Source->Offset;
1957 break;
1959 case AL_SEC_OFFSET:
1960 Offset = (ALint)(Source->Offset * Buffer->Frequency);
1961 break;
1963 Source->Offset = -1.0;
1965 return Offset;
1969 /* ReleaseALSources
1971 * Destroys all sources in the source map.
1973 ALvoid ReleaseALSources(ALCcontext *Context)
1975 ALsizei pos;
1976 ALuint j;
1977 for(pos = 0;pos < Context->SourceMap.size;pos++)
1979 ALsource *temp = Context->SourceMap.array[pos].value;
1980 Context->SourceMap.array[pos].value = NULL;
1982 while(temp->queue != NULL)
1984 ALbufferlistitem *BufferList = temp->queue;
1985 temp->queue = BufferList->next;
1987 if(BufferList->buffer != NULL)
1988 DecrementRef(&BufferList->buffer->ref);
1989 free(BufferList);
1992 for(j = 0;j < MAX_SENDS;++j)
1994 if(temp->Send[j].Slot)
1995 DecrementRef(&temp->Send[j].Slot->ref);
1996 temp->Send[j].Slot = NULL;
1999 FreeThunkEntry(temp->id);
2000 memset(temp, 0, sizeof(*temp));
2001 free(temp);