Add try/catch-like macros to handle errors, and convert alSource.c to use them
[openal-soft.git] / OpenAL32 / alSource.c
blobbaa0fc2c0283d8d2db044b171f4a61da936c5ee1
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].WetGain = 1.0f;
690 Source->Send[value2].WetGainHF = 1.0f;
692 else
694 Source->Send[value2].WetGain = filter->Gain;
695 Source->Send[value2].WetGainHF = filter->GainHF;
697 Source->NeedsUpdate = AL_TRUE;
698 UnlockContext(Context);
699 break;
701 default:
702 alSetError(Context, AL_INVALID_ENUM);
703 break;
706 al_endtry;
708 ALCcontext_DecRef(Context);
712 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
714 ALCcontext *Context;
716 if(values)
718 switch(param)
720 case AL_SOURCE_RELATIVE:
721 case AL_CONE_INNER_ANGLE:
722 case AL_CONE_OUTER_ANGLE:
723 case AL_LOOPING:
724 case AL_BUFFER:
725 case AL_SOURCE_STATE:
726 case AL_SEC_OFFSET:
727 case AL_SAMPLE_OFFSET:
728 case AL_BYTE_OFFSET:
729 case AL_MAX_DISTANCE:
730 case AL_ROLLOFF_FACTOR:
731 case AL_REFERENCE_DISTANCE:
732 case AL_DIRECT_FILTER:
733 case AL_DIRECT_FILTER_GAINHF_AUTO:
734 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
735 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
736 case AL_DISTANCE_MODEL:
737 case AL_DIRECT_CHANNELS_SOFT:
738 alSourcei(source, param, values[0]);
739 return;
741 case AL_POSITION:
742 case AL_VELOCITY:
743 case AL_DIRECTION:
744 case AL_AUXILIARY_SEND_FILTER:
745 alSource3i(source, param, values[0], values[1], values[2]);
746 return;
750 Context = GetContextRef();
751 if(!Context) return;
753 al_try
755 if(LookupSource(Context, source) == NULL)
756 al_throwerr(Context, AL_INVALID_NAME);
757 CHECK_VALUE(Context, values);
758 switch(param)
760 default:
761 al_throwerr(Context, AL_INVALID_ENUM);
764 al_endtry;
766 ALCcontext_DecRef(Context);
770 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
772 ALCcontext *Context;
773 ALsource *Source;
774 ALdouble offsets[2];
775 ALdouble updateLen;
777 Context = GetContextRef();
778 if(!Context) return;
780 al_try
782 if((Source=LookupSource(Context, source)) == NULL)
783 al_throwerr(Context, AL_INVALID_NAME);
784 CHECK_VALUE(Context, value);
785 switch(param)
787 case AL_PITCH:
788 *value = Source->Pitch;
789 break;
791 case AL_GAIN:
792 *value = Source->Gain;
793 break;
795 case AL_MIN_GAIN:
796 *value = Source->MinGain;
797 break;
799 case AL_MAX_GAIN:
800 *value = Source->MaxGain;
801 break;
803 case AL_MAX_DISTANCE:
804 *value = Source->MaxDistance;
805 break;
807 case AL_ROLLOFF_FACTOR:
808 *value = Source->RollOffFactor;
809 break;
811 case AL_CONE_OUTER_GAIN:
812 *value = Source->OuterGain;
813 break;
815 case AL_CONE_OUTER_GAINHF:
816 *value = Source->OuterGainHF;
817 break;
819 case AL_SEC_OFFSET:
820 case AL_SAMPLE_OFFSET:
821 case AL_BYTE_OFFSET:
822 LockContext(Context);
823 updateLen = (ALdouble)Context->Device->UpdateSize /
824 Context->Device->Frequency;
825 GetSourceOffsets(Source, param, offsets, updateLen);
826 UnlockContext(Context);
827 *value = (ALfloat)offsets[0];
828 break;
830 case AL_CONE_INNER_ANGLE:
831 *value = Source->InnerAngle;
832 break;
834 case AL_CONE_OUTER_ANGLE:
835 *value = Source->OuterAngle;
836 break;
838 case AL_REFERENCE_DISTANCE:
839 *value = Source->RefDistance;
840 break;
842 case AL_AIR_ABSORPTION_FACTOR:
843 *value = Source->AirAbsorptionFactor;
844 break;
846 case AL_ROOM_ROLLOFF_FACTOR:
847 *value = Source->RoomRolloffFactor;
848 break;
850 case AL_DOPPLER_FACTOR:
851 *value = Source->DopplerFactor;
852 break;
854 default:
855 al_throwerr(Context, AL_INVALID_ENUM);
858 al_endtry;
860 ALCcontext_DecRef(Context);
864 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
866 ALCcontext *Context;
867 ALsource *Source;
869 Context = GetContextRef();
870 if(!Context) return;
872 al_try
874 if((Source=LookupSource(Context, source)) == NULL)
875 al_throwerr(Context, AL_INVALID_NAME);
876 CHECK_VALUE(Context, value1 && value2 && value3);
877 switch(param)
879 case AL_POSITION:
880 LockContext(Context);
881 *value1 = Source->Position[0];
882 *value2 = Source->Position[1];
883 *value3 = Source->Position[2];
884 UnlockContext(Context);
885 break;
887 case AL_VELOCITY:
888 LockContext(Context);
889 *value1 = Source->Velocity[0];
890 *value2 = Source->Velocity[1];
891 *value3 = Source->Velocity[2];
892 UnlockContext(Context);
893 break;
895 case AL_DIRECTION:
896 LockContext(Context);
897 *value1 = Source->Orientation[0];
898 *value2 = Source->Orientation[1];
899 *value3 = Source->Orientation[2];
900 UnlockContext(Context);
901 break;
903 default:
904 al_throwerr(Context, AL_INVALID_ENUM);
907 al_endtry;
909 ALCcontext_DecRef(Context);
913 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
915 ALCcontext *Context;
916 ALsource *Source;
917 ALdouble offsets[2];
918 ALdouble updateLen;
920 switch(param)
922 case AL_PITCH:
923 case AL_GAIN:
924 case AL_MIN_GAIN:
925 case AL_MAX_GAIN:
926 case AL_MAX_DISTANCE:
927 case AL_ROLLOFF_FACTOR:
928 case AL_DOPPLER_FACTOR:
929 case AL_CONE_OUTER_GAIN:
930 case AL_SEC_OFFSET:
931 case AL_SAMPLE_OFFSET:
932 case AL_BYTE_OFFSET:
933 case AL_CONE_INNER_ANGLE:
934 case AL_CONE_OUTER_ANGLE:
935 case AL_REFERENCE_DISTANCE:
936 case AL_CONE_OUTER_GAINHF:
937 case AL_AIR_ABSORPTION_FACTOR:
938 case AL_ROOM_ROLLOFF_FACTOR:
939 alGetSourcef(source, param, values);
940 return;
942 case AL_POSITION:
943 case AL_VELOCITY:
944 case AL_DIRECTION:
945 alGetSource3f(source, param, values+0, values+1, values+2);
946 return;
949 Context = GetContextRef();
950 if(!Context) return;
952 al_try
954 if((Source=LookupSource(Context, source)) == NULL)
955 al_throwerr(Context, AL_INVALID_NAME);
956 CHECK_VALUE(Context, values);
957 switch(param)
959 case AL_SAMPLE_RW_OFFSETS_SOFT:
960 case AL_BYTE_RW_OFFSETS_SOFT:
961 LockContext(Context);
962 updateLen = (ALdouble)Context->Device->UpdateSize /
963 Context->Device->Frequency;
964 GetSourceOffsets(Source, param, offsets, updateLen);
965 UnlockContext(Context);
966 values[0] = (ALfloat)offsets[0];
967 values[1] = (ALfloat)offsets[1];
968 break;
970 default:
971 al_throwerr(Context, AL_INVALID_ENUM);
974 al_endtry;
976 ALCcontext_DecRef(Context);
980 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
982 ALbufferlistitem *BufferList;
983 ALCcontext *Context;
984 ALsource *Source;
985 ALdouble offsets[2];
986 ALdouble updateLen;
988 Context = GetContextRef();
989 if(!Context) return;
991 al_try
993 if((Source=LookupSource(Context, source)) == NULL)
994 al_throwerr(Context, AL_INVALID_NAME);
995 CHECK_VALUE(Context, value);
996 switch(param)
998 case AL_MAX_DISTANCE:
999 *value = (ALint)Source->MaxDistance;
1000 break;
1002 case AL_ROLLOFF_FACTOR:
1003 *value = (ALint)Source->RollOffFactor;
1004 break;
1006 case AL_REFERENCE_DISTANCE:
1007 *value = (ALint)Source->RefDistance;
1008 break;
1010 case AL_SOURCE_RELATIVE:
1011 *value = Source->HeadRelative;
1012 break;
1014 case AL_CONE_INNER_ANGLE:
1015 *value = (ALint)Source->InnerAngle;
1016 break;
1018 case AL_CONE_OUTER_ANGLE:
1019 *value = (ALint)Source->OuterAngle;
1020 break;
1022 case AL_LOOPING:
1023 *value = Source->Looping;
1024 break;
1026 case AL_BUFFER:
1027 LockContext(Context);
1028 BufferList = Source->queue;
1029 if(Source->SourceType != AL_STATIC)
1031 ALuint i = Source->BuffersPlayed;
1032 while(i > 0)
1034 BufferList = BufferList->next;
1035 i--;
1038 *value = ((BufferList && BufferList->buffer) ?
1039 BufferList->buffer->id : 0);
1040 UnlockContext(Context);
1041 break;
1043 case AL_SOURCE_STATE:
1044 *value = Source->state;
1045 break;
1047 case AL_BUFFERS_QUEUED:
1048 *value = Source->BuffersInQueue;
1049 break;
1051 case AL_BUFFERS_PROCESSED:
1052 LockContext(Context);
1053 if(Source->Looping || Source->SourceType != AL_STREAMING)
1055 /* Buffers on a looping source are in a perpetual state of
1056 * PENDING, so don't report any as PROCESSED */
1057 *value = 0;
1059 else
1060 *value = Source->BuffersPlayed;
1061 UnlockContext(Context);
1062 break;
1064 case AL_SOURCE_TYPE:
1065 *value = Source->SourceType;
1066 break;
1068 case AL_SEC_OFFSET:
1069 case AL_SAMPLE_OFFSET:
1070 case AL_BYTE_OFFSET:
1071 LockContext(Context);
1072 updateLen = (ALdouble)Context->Device->UpdateSize /
1073 Context->Device->Frequency;
1074 GetSourceOffsets(Source, param, offsets, updateLen);
1075 UnlockContext(Context);
1076 *value = (ALint)offsets[0];
1077 break;
1079 case AL_DIRECT_FILTER_GAINHF_AUTO:
1080 *value = Source->DryGainHFAuto;
1081 break;
1083 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1084 *value = Source->WetGainAuto;
1085 break;
1087 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1088 *value = Source->WetGainHFAuto;
1089 break;
1091 case AL_DOPPLER_FACTOR:
1092 *value = (ALint)Source->DopplerFactor;
1093 break;
1095 case AL_DIRECT_CHANNELS_SOFT:
1096 *value = Source->DirectChannels;
1097 break;
1099 case AL_DISTANCE_MODEL:
1100 *value = Source->DistanceModel;
1101 break;
1103 default:
1104 al_throwerr(Context, AL_INVALID_ENUM);
1107 al_endtry;
1109 ALCcontext_DecRef(Context);
1113 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1115 ALCcontext *Context;
1116 ALsource *Source;
1118 Context = GetContextRef();
1119 if(!Context) return;
1121 al_try
1123 if((Source=LookupSource(Context, source)) == NULL)
1124 al_throwerr(Context, AL_INVALID_NAME);
1125 CHECK_VALUE(Context, value1 && value2 && value3);
1126 switch(param)
1128 case AL_POSITION:
1129 LockContext(Context);
1130 *value1 = (ALint)Source->Position[0];
1131 *value2 = (ALint)Source->Position[1];
1132 *value3 = (ALint)Source->Position[2];
1133 UnlockContext(Context);
1134 break;
1136 case AL_VELOCITY:
1137 LockContext(Context);
1138 *value1 = (ALint)Source->Velocity[0];
1139 *value2 = (ALint)Source->Velocity[1];
1140 *value3 = (ALint)Source->Velocity[2];
1141 UnlockContext(Context);
1142 break;
1144 case AL_DIRECTION:
1145 LockContext(Context);
1146 *value1 = (ALint)Source->Orientation[0];
1147 *value2 = (ALint)Source->Orientation[1];
1148 *value3 = (ALint)Source->Orientation[2];
1149 UnlockContext(Context);
1150 break;
1152 default:
1153 al_throwerr(Context, AL_INVALID_ENUM);
1156 al_endtry;
1158 ALCcontext_DecRef(Context);
1162 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1164 ALCcontext *Context;
1165 ALsource *Source;
1166 ALdouble offsets[2];
1167 ALdouble updateLen;
1169 switch(param)
1171 case AL_SOURCE_RELATIVE:
1172 case AL_CONE_INNER_ANGLE:
1173 case AL_CONE_OUTER_ANGLE:
1174 case AL_LOOPING:
1175 case AL_BUFFER:
1176 case AL_SOURCE_STATE:
1177 case AL_BUFFERS_QUEUED:
1178 case AL_BUFFERS_PROCESSED:
1179 case AL_SEC_OFFSET:
1180 case AL_SAMPLE_OFFSET:
1181 case AL_BYTE_OFFSET:
1182 case AL_MAX_DISTANCE:
1183 case AL_ROLLOFF_FACTOR:
1184 case AL_DOPPLER_FACTOR:
1185 case AL_REFERENCE_DISTANCE:
1186 case AL_SOURCE_TYPE:
1187 case AL_DIRECT_FILTER:
1188 case AL_DIRECT_FILTER_GAINHF_AUTO:
1189 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1190 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1191 case AL_DISTANCE_MODEL:
1192 case AL_DIRECT_CHANNELS_SOFT:
1193 alGetSourcei(source, param, values);
1194 return;
1196 case AL_POSITION:
1197 case AL_VELOCITY:
1198 case AL_DIRECTION:
1199 alGetSource3i(source, param, values+0, values+1, values+2);
1200 return;
1203 Context = GetContextRef();
1204 if(!Context) return;
1206 al_try
1208 if((Source=LookupSource(Context, source)) == NULL)
1209 al_throwerr(Context, AL_INVALID_NAME);
1210 CHECK_VALUE(Context, values);
1211 switch(param)
1213 case AL_SAMPLE_RW_OFFSETS_SOFT:
1214 case AL_BYTE_RW_OFFSETS_SOFT:
1215 LockContext(Context);
1216 updateLen = (ALdouble)Context->Device->UpdateSize /
1217 Context->Device->Frequency;
1218 GetSourceOffsets(Source, param, offsets, updateLen);
1219 UnlockContext(Context);
1220 values[0] = (ALint)offsets[0];
1221 values[1] = (ALint)offsets[1];
1222 break;
1224 default:
1225 al_throwerr(Context, AL_INVALID_ENUM);
1228 al_endtry;
1230 ALCcontext_DecRef(Context);
1234 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1236 alSourcePlayv(1, &source);
1238 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1240 ALCcontext *Context;
1241 ALsource *Source;
1242 ALsizei i;
1244 Context = GetContextRef();
1245 if(!Context) return;
1247 al_try
1249 CHECK_VALUE(Context, n >= 0);
1250 for(i = 0;i < n;i++)
1252 if(!LookupSource(Context, sources[i]))
1253 al_throwerr(Context, AL_INVALID_NAME);
1256 LockContext(Context);
1257 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1259 void *temp = NULL;
1260 ALsizei newcount;
1262 newcount = Context->MaxActiveSources << 1;
1263 if(newcount > 0)
1264 temp = realloc(Context->ActiveSources,
1265 sizeof(*Context->ActiveSources) * newcount);
1266 if(!temp)
1268 UnlockContext(Context);
1269 al_throwerr(Context, AL_OUT_OF_MEMORY);
1272 Context->ActiveSources = temp;
1273 Context->MaxActiveSources = newcount;
1276 for(i = 0;i < n;i++)
1278 Source = LookupSource(Context, sources[i]);
1279 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1280 else SetSourceState(Source, Context, AL_PLAYING);
1282 UnlockContext(Context);
1284 al_endtry;
1286 ALCcontext_DecRef(Context);
1289 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1291 alSourcePausev(1, &source);
1293 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1295 ALCcontext *Context;
1296 ALsource *Source;
1297 ALsizei i;
1299 Context = GetContextRef();
1300 if(!Context) return;
1302 al_try
1304 CHECK_VALUE(Context, n >= 0);
1305 for(i = 0;i < n;i++)
1307 if(!LookupSource(Context, sources[i]))
1308 al_throwerr(Context, AL_INVALID_NAME);
1311 LockContext(Context);
1312 for(i = 0;i < n;i++)
1314 Source = LookupSource(Context, sources[i]);
1315 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1316 else SetSourceState(Source, Context, AL_PAUSED);
1318 UnlockContext(Context);
1320 al_endtry;
1322 ALCcontext_DecRef(Context);
1325 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1327 alSourceStopv(1, &source);
1329 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1331 ALCcontext *Context;
1332 ALsource *Source;
1333 ALsizei i;
1335 Context = GetContextRef();
1336 if(!Context) return;
1338 al_try
1340 CHECK_VALUE(Context, n >= 0);
1341 for(i = 0;i < n;i++)
1343 if(!LookupSource(Context, sources[i]))
1344 al_throwerr(Context, AL_INVALID_NAME);
1347 LockContext(Context);
1348 for(i = 0;i < n;i++)
1350 Source = LookupSource(Context, sources[i]);
1351 Source->new_state = AL_NONE;
1352 SetSourceState(Source, Context, AL_STOPPED);
1354 UnlockContext(Context);
1356 al_endtry;
1358 ALCcontext_DecRef(Context);
1361 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1363 alSourceRewindv(1, &source);
1365 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1367 ALCcontext *Context;
1368 ALsource *Source;
1369 ALsizei i;
1371 Context = GetContextRef();
1372 if(!Context) return;
1374 al_try
1376 CHECK_VALUE(Context, n >= 0);
1377 for(i = 0;i < n;i++)
1379 if(!LookupSource(Context, sources[i]))
1380 al_throwerr(Context, AL_INVALID_NAME);
1383 LockContext(Context);
1384 for(i = 0;i < n;i++)
1386 Source = LookupSource(Context, sources[i]);
1387 Source->new_state = AL_NONE;
1388 SetSourceState(Source, Context, AL_INITIAL);
1390 UnlockContext(Context);
1392 al_endtry;
1394 ALCcontext_DecRef(Context);
1398 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
1400 ALCcontext *Context;
1401 ALsource *Source;
1402 ALsizei i;
1403 ALbufferlistitem *BufferListStart = NULL;
1404 ALbufferlistitem *BufferList;
1405 ALbuffer *BufferFmt;
1407 if(nb == 0)
1408 return;
1410 Context = GetContextRef();
1411 if(!Context) return;
1413 al_try
1415 ALCdevice *device = Context->Device;
1417 CHECK_VALUE(Context, nb >= 0);
1419 if((Source=LookupSource(Context, source)) == NULL)
1420 al_throwerr(Context, AL_INVALID_NAME);
1422 LockContext(Context);
1423 if(Source->SourceType == AL_STATIC)
1425 UnlockContext(Context);
1426 /* Can't queue on a Static Source */
1427 al_throwerr(Context, AL_INVALID_OPERATION);
1430 BufferFmt = NULL;
1432 /* Check for a valid Buffer, for its frequency and format */
1433 BufferList = Source->queue;
1434 while(BufferList)
1436 if(BufferList->buffer)
1438 BufferFmt = BufferList->buffer;
1439 break;
1441 BufferList = BufferList->next;
1444 for(i = 0;i < nb;i++)
1446 ALbuffer *buffer = NULL;
1447 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1449 UnlockContext(Context);
1450 al_throwerr(Context, AL_INVALID_NAME);
1453 if(!BufferListStart)
1455 BufferListStart = malloc(sizeof(ALbufferlistitem));
1456 BufferListStart->buffer = buffer;
1457 BufferListStart->next = NULL;
1458 BufferListStart->prev = NULL;
1459 BufferList = BufferListStart;
1461 else
1463 BufferList->next = malloc(sizeof(ALbufferlistitem));
1464 BufferList->next->buffer = buffer;
1465 BufferList->next->next = NULL;
1466 BufferList->next->prev = BufferList;
1467 BufferList = BufferList->next;
1469 if(!buffer) continue;
1470 IncrementRef(&buffer->ref);
1472 ReadLock(&buffer->lock);
1473 if(BufferFmt == NULL)
1475 BufferFmt = buffer;
1477 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1478 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1479 if(buffer->FmtChannels == FmtMono)
1480 Source->Update = CalcSourceParams;
1481 else
1482 Source->Update = CalcNonAttnSourceParams;
1484 Source->NeedsUpdate = AL_TRUE;
1486 else if(BufferFmt->Frequency != buffer->Frequency ||
1487 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1488 BufferFmt->OriginalType != buffer->OriginalType)
1490 ReadUnlock(&buffer->lock);
1491 UnlockContext(Context);
1492 al_throwerr(Context, AL_INVALID_OPERATION);
1494 ReadUnlock(&buffer->lock);
1497 /* Source is now streaming */
1498 Source->SourceType = AL_STREAMING;
1500 if(Source->queue == NULL)
1501 Source->queue = BufferListStart;
1502 else
1504 /* Append to the end of the queue */
1505 BufferList = Source->queue;
1506 while(BufferList->next != NULL)
1507 BufferList = BufferList->next;
1509 BufferListStart->prev = BufferList;
1510 BufferList->next = BufferListStart;
1513 Source->BuffersInQueue += nb;
1515 UnlockContext(Context);
1517 al_catchany()
1519 while(BufferListStart)
1521 BufferList = BufferListStart;
1522 BufferListStart = BufferList->next;
1524 if(BufferList->buffer)
1525 DecrementRef(&BufferList->buffer->ref);
1526 free(BufferList);
1529 al_endtry;
1531 ALCcontext_DecRef(Context);
1534 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
1536 ALCcontext *Context;
1537 ALsource *Source;
1538 ALsizei i;
1539 ALbufferlistitem *BufferList;
1541 if(nb == 0)
1542 return;
1544 Context = GetContextRef();
1545 if(!Context) return;
1547 al_try
1549 CHECK_VALUE(Context, nb >= 0);
1551 if((Source=LookupSource(Context, source)) == NULL)
1552 al_throwerr(Context, AL_INVALID_NAME);
1554 LockContext(Context);
1555 if(Source->Looping || Source->SourceType != AL_STREAMING ||
1556 (ALuint)nb > Source->BuffersPlayed)
1558 UnlockContext(Context);
1559 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1560 al_throwerr(Context, AL_INVALID_VALUE);
1563 for(i = 0;i < nb;i++)
1565 BufferList = Source->queue;
1566 Source->queue = BufferList->next;
1567 Source->BuffersInQueue--;
1568 Source->BuffersPlayed--;
1570 if(BufferList->buffer)
1572 buffers[i] = BufferList->buffer->id;
1573 DecrementRef(&BufferList->buffer->ref);
1575 else
1576 buffers[i] = 0;
1578 free(BufferList);
1580 if(Source->queue)
1581 Source->queue->prev = NULL;
1582 UnlockContext(Context);
1584 al_endtry;
1586 ALCcontext_DecRef(Context);
1590 static ALvoid InitSourceParams(ALsource *Source)
1592 ALuint i;
1594 Source->InnerAngle = 360.0f;
1595 Source->OuterAngle = 360.0f;
1596 Source->Pitch = 1.0f;
1597 Source->Position[0] = 0.0f;
1598 Source->Position[1] = 0.0f;
1599 Source->Position[2] = 0.0f;
1600 Source->Orientation[0] = 0.0f;
1601 Source->Orientation[1] = 0.0f;
1602 Source->Orientation[2] = 0.0f;
1603 Source->Velocity[0] = 0.0f;
1604 Source->Velocity[1] = 0.0f;
1605 Source->Velocity[2] = 0.0f;
1606 Source->RefDistance = 1.0f;
1607 Source->MaxDistance = FLT_MAX;
1608 Source->RollOffFactor = 1.0f;
1609 Source->Looping = AL_FALSE;
1610 Source->Gain = 1.0f;
1611 Source->MinGain = 0.0f;
1612 Source->MaxGain = 1.0f;
1613 Source->OuterGain = 0.0f;
1614 Source->OuterGainHF = 1.0f;
1616 Source->DryGainHFAuto = AL_TRUE;
1617 Source->WetGainAuto = AL_TRUE;
1618 Source->WetGainHFAuto = AL_TRUE;
1619 Source->AirAbsorptionFactor = 0.0f;
1620 Source->RoomRolloffFactor = 0.0f;
1621 Source->DopplerFactor = 1.0f;
1622 Source->DirectChannels = AL_FALSE;
1624 Source->DistanceModel = DefaultDistanceModel;
1626 Source->Resampler = DefaultResampler;
1628 Source->state = AL_INITIAL;
1629 Source->new_state = AL_NONE;
1630 Source->SourceType = AL_UNDETERMINED;
1631 Source->Offset = -1.0;
1633 Source->DirectGain = 1.0f;
1634 Source->DirectGainHF = 1.0f;
1635 for(i = 0;i < MAX_SENDS;i++)
1637 Source->Send[i].WetGain = 1.0f;
1638 Source->Send[i].WetGainHF = 1.0f;
1641 Source->NeedsUpdate = AL_TRUE;
1643 Source->HrtfMoving = AL_FALSE;
1644 Source->HrtfCounter = 0;
1648 /* SetSourceState
1650 * Sets the source's new play state given its current state.
1652 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1654 if(state == AL_PLAYING)
1656 ALbufferlistitem *BufferList;
1657 ALsizei j, k;
1659 /* Check that there is a queue containing at least one valid, non zero
1660 * length Buffer. */
1661 BufferList = Source->queue;
1662 while(BufferList)
1664 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1665 break;
1666 BufferList = BufferList->next;
1669 if(Source->state != AL_PLAYING)
1671 for(j = 0;j < MAXCHANNELS;j++)
1673 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1674 Source->HrtfHistory[j][k] = 0.0f;
1675 for(k = 0;k < HRIR_LENGTH;k++)
1677 Source->HrtfValues[j][k][0] = 0.0f;
1678 Source->HrtfValues[j][k][1] = 0.0f;
1683 if(Source->state != AL_PAUSED)
1685 Source->state = AL_PLAYING;
1686 Source->position = 0;
1687 Source->position_fraction = 0;
1688 Source->BuffersPlayed = 0;
1690 else
1691 Source->state = AL_PLAYING;
1693 // Check if an Offset has been set
1694 if(Source->Offset >= 0.0)
1695 ApplyOffset(Source);
1697 /* If there's nothing to play, or device is disconnected, go right to
1698 * stopped */
1699 if(!BufferList || !Context->Device->Connected)
1701 SetSourceState(Source, Context, AL_STOPPED);
1702 return;
1705 for(j = 0;j < Context->ActiveSourceCount;j++)
1707 if(Context->ActiveSources[j] == Source)
1708 break;
1710 if(j == Context->ActiveSourceCount)
1711 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1713 else if(state == AL_PAUSED)
1715 if(Source->state == AL_PLAYING)
1717 Source->state = AL_PAUSED;
1718 Source->HrtfMoving = AL_FALSE;
1719 Source->HrtfCounter = 0;
1722 else if(state == AL_STOPPED)
1724 if(Source->state != AL_INITIAL)
1726 Source->state = AL_STOPPED;
1727 Source->BuffersPlayed = Source->BuffersInQueue;
1728 Source->HrtfMoving = AL_FALSE;
1729 Source->HrtfCounter = 0;
1731 Source->Offset = -1.0;
1733 else if(state == AL_INITIAL)
1735 if(Source->state != AL_INITIAL)
1737 Source->state = AL_INITIAL;
1738 Source->position = 0;
1739 Source->position_fraction = 0;
1740 Source->BuffersPlayed = 0;
1741 Source->HrtfMoving = AL_FALSE;
1742 Source->HrtfCounter = 0;
1744 Source->Offset = -1.0;
1748 /* GetSourceOffsets
1750 * Gets the current read and write offsets for the given Source, in the
1751 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
1752 * the start of the queue (not the start of the current buffer).
1754 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1756 const ALbufferlistitem *BufferList;
1757 const ALbuffer *Buffer = NULL;
1758 ALuint readPos, writePos;
1759 ALuint totalBufferLen;
1760 ALuint i;
1762 // Find the first valid Buffer in the Queue
1763 BufferList = Source->queue;
1764 while(BufferList)
1766 if(BufferList->buffer)
1768 Buffer = BufferList->buffer;
1769 break;
1771 BufferList = BufferList->next;
1774 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1776 offset[0] = 0.0;
1777 offset[1] = 0.0;
1778 return;
1781 if(updateLen > 0.0 && updateLen < 0.015)
1782 updateLen = 0.015;
1784 /* NOTE: This is the offset into the *current* buffer, so add the length of
1785 * any played buffers */
1786 readPos = Source->position;
1787 totalBufferLen = 0;
1788 BufferList = Source->queue;
1789 for(i = 0;BufferList;i++)
1791 if(BufferList->buffer)
1793 if(i < Source->BuffersPlayed)
1794 readPos += BufferList->buffer->SampleLen;
1795 totalBufferLen += BufferList->buffer->SampleLen;
1797 BufferList = BufferList->next;
1799 if(Source->state == AL_PLAYING)
1800 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
1801 else
1802 writePos = readPos;
1804 if(Source->Looping)
1806 readPos %= totalBufferLen;
1807 writePos %= totalBufferLen;
1809 else
1811 /* Wrap positions back to 0 */
1812 if(readPos >= totalBufferLen)
1813 readPos = 0;
1814 if(writePos >= totalBufferLen)
1815 writePos = 0;
1818 switch(name)
1820 case AL_SEC_OFFSET:
1821 offset[0] = (ALdouble)readPos / Buffer->Frequency;
1822 offset[1] = (ALdouble)writePos / Buffer->Frequency;
1823 break;
1825 case AL_SAMPLE_OFFSET:
1826 case AL_SAMPLE_RW_OFFSETS_SOFT:
1827 offset[0] = (ALdouble)readPos;
1828 offset[1] = (ALdouble)writePos;
1829 break;
1831 case AL_BYTE_OFFSET:
1832 case AL_BYTE_RW_OFFSETS_SOFT:
1833 if(Buffer->OriginalType == UserFmtIMA4)
1835 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
1836 ALuint FrameBlockSize = 65;
1838 /* Round down to nearest ADPCM block */
1839 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1840 if(Source->state != AL_PLAYING)
1841 offset[1] = offset[0];
1842 else
1844 /* Round up to nearest ADPCM block */
1845 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1846 FrameBlockSize * BlockSize);
1849 else
1851 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
1852 offset[0] = (ALdouble)(readPos * FrameSize);
1853 offset[1] = (ALdouble)(writePos * FrameSize);
1855 break;
1860 /* ApplyOffset
1862 * Apply the stored playback offset to the Source. This function will update
1863 * the number of buffers "played" given the stored offset.
1865 ALboolean ApplyOffset(ALsource *Source)
1867 const ALbufferlistitem *BufferList;
1868 const ALbuffer *Buffer;
1869 ALint bufferLen, totalBufferLen;
1870 ALint buffersPlayed;
1871 ALint offset;
1873 /* Get sample frame offset */
1874 offset = GetSampleOffset(Source);
1875 if(offset == -1)
1876 return AL_FALSE;
1878 buffersPlayed = 0;
1879 totalBufferLen = 0;
1881 BufferList = Source->queue;
1882 while(BufferList)
1884 Buffer = BufferList->buffer;
1885 bufferLen = Buffer ? Buffer->SampleLen : 0;
1887 if(bufferLen <= offset-totalBufferLen)
1889 /* Offset is past this buffer so increment to the next buffer */
1890 buffersPlayed++;
1892 else if(totalBufferLen <= offset)
1894 /* Offset is in this buffer */
1895 Source->BuffersPlayed = buffersPlayed;
1897 Source->position = offset - totalBufferLen;
1898 Source->position_fraction = 0;
1899 return AL_TRUE;
1902 totalBufferLen += bufferLen;
1904 BufferList = BufferList->next;
1907 /* Offset is out of range of the queue */
1908 return AL_FALSE;
1912 /* GetSampleOffset
1914 * Returns the sample offset into the Source's queue (from the Sample, Byte or
1915 * Second offset supplied by the application). This takes into account the fact
1916 * that the buffer format may have been modifed since.
1918 static ALint GetSampleOffset(ALsource *Source)
1920 const ALbuffer *Buffer = NULL;
1921 const ALbufferlistitem *BufferList;
1922 ALint Offset = -1;
1924 /* Find the first valid Buffer in the Queue */
1925 BufferList = Source->queue;
1926 while(BufferList)
1928 if(BufferList->buffer)
1930 Buffer = BufferList->buffer;
1931 break;
1933 BufferList = BufferList->next;
1936 if(!Buffer)
1938 Source->Offset = -1.0;
1939 return -1;
1942 switch(Source->OffsetType)
1944 case AL_BYTE_OFFSET:
1945 /* Determine the ByteOffset (and ensure it is block aligned) */
1946 Offset = (ALint)Source->Offset;
1947 if(Buffer->OriginalType == UserFmtIMA4)
1949 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
1950 Offset *= 65;
1952 else
1953 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
1954 break;
1956 case AL_SAMPLE_OFFSET:
1957 Offset = (ALint)Source->Offset;
1958 break;
1960 case AL_SEC_OFFSET:
1961 Offset = (ALint)(Source->Offset * Buffer->Frequency);
1962 break;
1964 Source->Offset = -1.0;
1966 return Offset;
1970 /* ReleaseALSources
1972 * Destroys all sources in the source map.
1974 ALvoid ReleaseALSources(ALCcontext *Context)
1976 ALsizei pos;
1977 ALuint j;
1978 for(pos = 0;pos < Context->SourceMap.size;pos++)
1980 ALsource *temp = Context->SourceMap.array[pos].value;
1981 Context->SourceMap.array[pos].value = NULL;
1983 while(temp->queue != NULL)
1985 ALbufferlistitem *BufferList = temp->queue;
1986 temp->queue = BufferList->next;
1988 if(BufferList->buffer != NULL)
1989 DecrementRef(&BufferList->buffer->ref);
1990 free(BufferList);
1993 for(j = 0;j < MAX_SENDS;++j)
1995 if(temp->Send[j].Slot)
1996 DecrementRef(&temp->Send[j].Slot->ref);
1997 temp->Send[j].Slot = NULL;
2000 FreeThunkEntry(temp->id);
2001 memset(temp, 0, sizeof(*temp));
2002 free(temp);