Add a macro to help make a 64-bit value
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob0192b5efb4f0329a268be17042bd1c4c029d8072
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 ALint64 GetSourceOffset(ALsource *Source);
51 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
52 static ALint GetSampleOffset(ALsource *Source);
55 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
57 ALCcontext *Context;
58 ALsizei cur = 0;
60 Context = GetContextRef();
61 if(!Context) return;
63 al_try
65 ALenum err;
67 CHECK_VALUE(Context, n >= 0);
68 for(cur = 0;cur < n;cur++)
70 ALsource *source = al_calloc(16, sizeof(ALsource));
71 if(!source)
72 al_throwerr(Context, AL_OUT_OF_MEMORY);
73 InitSourceParams(source);
75 err = NewThunkEntry(&source->id);
76 if(err == AL_NO_ERROR)
77 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
78 if(err != AL_NO_ERROR)
80 FreeThunkEntry(source->id);
81 memset(source, 0, sizeof(ALsource));
82 al_free(source);
84 al_throwerr(Context, err);
87 sources[cur] = source->id;
90 al_catchany()
92 if(cur > 0)
93 alDeleteSources(cur, sources);
95 al_endtry;
97 ALCcontext_DecRef(Context);
101 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
103 ALCcontext *Context;
105 Context = GetContextRef();
106 if(!Context) return;
108 al_try
110 ALbufferlistitem *BufferList;
111 ALsource *Source;
112 ALsizei i, j;
114 CHECK_VALUE(Context, n >= 0);
116 /* Check that all Sources are valid */
117 for(i = 0;i < n;i++)
119 if(LookupSource(Context, sources[i]) == NULL)
120 al_throwerr(Context, AL_INVALID_NAME);
123 for(i = 0;i < n;i++)
125 ALsource **srclist, **srclistend;
127 if((Source=RemoveSource(Context, sources[i])) == NULL)
128 continue;
129 FreeThunkEntry(Source->id);
131 LockContext(Context);
132 srclist = Context->ActiveSources;
133 srclistend = srclist + Context->ActiveSourceCount;
134 while(srclist != srclistend)
136 if(*srclist == Source)
138 Context->ActiveSourceCount--;
139 *srclist = *(--srclistend);
140 break;
142 srclist++;
144 UnlockContext(Context);
146 while(Source->queue != NULL)
148 BufferList = Source->queue;
149 Source->queue = BufferList->next;
151 if(BufferList->buffer != NULL)
152 DecrementRef(&BufferList->buffer->ref);
153 free(BufferList);
156 for(j = 0;j < MAX_SENDS;++j)
158 if(Source->Send[j].Slot)
159 DecrementRef(&Source->Send[j].Slot->ref);
160 Source->Send[j].Slot = NULL;
163 memset(Source, 0, sizeof(*Source));
164 al_free(Source);
167 al_endtry;
169 ALCcontext_DecRef(Context);
173 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
175 ALCcontext *Context;
176 ALboolean result;
178 Context = GetContextRef();
179 if(!Context) return AL_FALSE;
181 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
183 ALCcontext_DecRef(Context);
185 return result;
189 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
191 ALCcontext *Context;
192 ALsource *Source;
194 Context = GetContextRef();
195 if(!Context) return;
197 al_try
199 if((Source=LookupSource(Context, source)) == NULL)
200 al_throwerr(Context, AL_INVALID_NAME);
201 switch(param)
203 case AL_PITCH:
204 CHECK_VALUE(Context, value >= 0.0f);
206 Source->Pitch = value;
207 Source->NeedsUpdate = AL_TRUE;
208 break;
210 case AL_CONE_INNER_ANGLE:
211 CHECK_VALUE(Context, value >= 0.0f && value <= 360.0f);
213 Source->InnerAngle = value;
214 Source->NeedsUpdate = AL_TRUE;
215 break;
217 case AL_CONE_OUTER_ANGLE:
218 CHECK_VALUE(Context, value >= 0.0f && value <= 360.0f);
220 Source->OuterAngle = value;
221 Source->NeedsUpdate = AL_TRUE;
222 break;
224 case AL_GAIN:
225 CHECK_VALUE(Context, value >= 0.0f);
227 Source->Gain = value;
228 Source->NeedsUpdate = AL_TRUE;
229 break;
231 case AL_MAX_DISTANCE:
232 CHECK_VALUE(Context, value >= 0.0f);
234 Source->MaxDistance = value;
235 Source->NeedsUpdate = AL_TRUE;
236 break;
238 case AL_ROLLOFF_FACTOR:
239 CHECK_VALUE(Context, value >= 0.0f);
241 Source->RollOffFactor = value;
242 Source->NeedsUpdate = AL_TRUE;
243 break;
245 case AL_REFERENCE_DISTANCE:
246 CHECK_VALUE(Context, value >= 0.0f);
248 Source->RefDistance = value;
249 Source->NeedsUpdate = AL_TRUE;
250 break;
252 case AL_MIN_GAIN:
253 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
255 Source->MinGain = value;
256 Source->NeedsUpdate = AL_TRUE;
257 break;
259 case AL_MAX_GAIN:
260 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
262 Source->MaxGain = value;
263 Source->NeedsUpdate = AL_TRUE;
264 break;
266 case AL_CONE_OUTER_GAIN:
267 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
269 Source->OuterGain = value;
270 Source->NeedsUpdate = AL_TRUE;
271 break;
273 case AL_CONE_OUTER_GAINHF:
274 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
276 Source->OuterGainHF = value;
277 Source->NeedsUpdate = AL_TRUE;
278 break;
280 case AL_AIR_ABSORPTION_FACTOR:
281 CHECK_VALUE(Context, value >= 0.0f && value <= 10.0f);
283 Source->AirAbsorptionFactor = value;
284 Source->NeedsUpdate = AL_TRUE;
285 break;
287 case AL_ROOM_ROLLOFF_FACTOR:
288 CHECK_VALUE(Context, value >= 0.0f && value <= 10.0f);
290 Source->RoomRolloffFactor = value;
291 Source->NeedsUpdate = AL_TRUE;
292 break;
294 case AL_DOPPLER_FACTOR:
295 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
297 Source->DopplerFactor = value;
298 Source->NeedsUpdate = AL_TRUE;
299 break;
301 case AL_SEC_OFFSET:
302 case AL_SAMPLE_OFFSET:
303 case AL_BYTE_OFFSET:
304 CHECK_VALUE(Context, value >= 0.0f);
306 LockContext(Context);
307 Source->OffsetType = param;
308 Source->Offset = value;
310 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
311 !Context->DeferUpdates)
313 if(ApplyOffset(Source) == AL_FALSE)
315 UnlockContext(Context);
316 al_throwerr(Context, AL_INVALID_VALUE);
319 UnlockContext(Context);
320 break;
322 default:
323 al_throwerr(Context, AL_INVALID_ENUM);
326 al_endtry;
328 ALCcontext_DecRef(Context);
332 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
334 ALCcontext *Context;
335 ALsource *Source;
337 Context = GetContextRef();
338 if(!Context) return;
340 al_try
342 if((Source=LookupSource(Context, source)) == NULL)
343 al_throwerr(Context, AL_INVALID_NAME);
344 switch(param)
346 case AL_POSITION:
347 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
349 LockContext(Context);
350 Source->Position[0] = value1;
351 Source->Position[1] = value2;
352 Source->Position[2] = value3;
353 UnlockContext(Context);
354 Source->NeedsUpdate = AL_TRUE;
355 break;
357 case AL_VELOCITY:
358 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
360 LockContext(Context);
361 Source->Velocity[0] = value1;
362 Source->Velocity[1] = value2;
363 Source->Velocity[2] = value3;
364 UnlockContext(Context);
365 Source->NeedsUpdate = AL_TRUE;
366 break;
368 case AL_DIRECTION:
369 CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
371 LockContext(Context);
372 Source->Orientation[0] = value1;
373 Source->Orientation[1] = value2;
374 Source->Orientation[2] = value3;
375 UnlockContext(Context);
376 Source->NeedsUpdate = AL_TRUE;
377 break;
379 default:
380 al_throwerr(Context, AL_INVALID_ENUM);
383 al_endtry;
385 ALCcontext_DecRef(Context);
389 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
391 ALCcontext *Context;
393 if(values)
395 switch(param)
397 case AL_PITCH:
398 case AL_CONE_INNER_ANGLE:
399 case AL_CONE_OUTER_ANGLE:
400 case AL_GAIN:
401 case AL_MAX_DISTANCE:
402 case AL_ROLLOFF_FACTOR:
403 case AL_REFERENCE_DISTANCE:
404 case AL_MIN_GAIN:
405 case AL_MAX_GAIN:
406 case AL_CONE_OUTER_GAIN:
407 case AL_CONE_OUTER_GAINHF:
408 case AL_SEC_OFFSET:
409 case AL_SAMPLE_OFFSET:
410 case AL_BYTE_OFFSET:
411 case AL_AIR_ABSORPTION_FACTOR:
412 case AL_ROOM_ROLLOFF_FACTOR:
413 alSourcef(source, param, values[0]);
414 return;
416 case AL_POSITION:
417 case AL_VELOCITY:
418 case AL_DIRECTION:
419 alSource3f(source, param, values[0], values[1], values[2]);
420 return;
424 Context = GetContextRef();
425 if(!Context) return;
427 al_try
429 if(LookupSource(Context, source) == NULL)
430 al_throwerr(Context, AL_INVALID_NAME);
431 CHECK_VALUE(Context, values);
433 switch(param)
435 default:
436 al_throwerr(Context, AL_INVALID_ENUM);
439 al_endtry;
441 ALCcontext_DecRef(Context);
445 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
447 ALCcontext *Context;
448 ALsource *Source;
450 switch(param)
452 case AL_MAX_DISTANCE:
453 case AL_ROLLOFF_FACTOR:
454 case AL_CONE_INNER_ANGLE:
455 case AL_CONE_OUTER_ANGLE:
456 case AL_REFERENCE_DISTANCE:
457 alSourcef(source, param, (ALfloat)value);
458 return;
461 Context = GetContextRef();
462 if(!Context) return;
464 al_try
466 ALCdevice *device = Context->Device;
467 ALbuffer *buffer = NULL;
468 ALfilter *filter = NULL;
469 ALbufferlistitem *oldlist;
471 if((Source=LookupSource(Context, source)) == NULL)
472 al_throwerr(Context, AL_INVALID_NAME);
473 switch(param)
475 case AL_SOURCE_RELATIVE:
476 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
478 Source->HeadRelative = (ALboolean)value;
479 Source->NeedsUpdate = AL_TRUE;
480 break;
482 case AL_LOOPING:
483 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
485 Source->Looping = (ALboolean)value;
486 break;
488 case AL_BUFFER:
489 CHECK_VALUE(Context, value == 0 ||
490 (buffer=LookupBuffer(device, value)) != NULL);
492 LockContext(Context);
493 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
495 UnlockContext(Context);
496 al_throwerr(Context, AL_INVALID_OPERATION);
499 Source->BuffersInQueue = 0;
500 Source->BuffersPlayed = 0;
502 if(buffer != NULL)
504 ALbufferlistitem *BufferListItem;
506 /* Source is now Static */
507 Source->SourceType = AL_STATIC;
509 /* Add the selected buffer to a one-item queue */
510 BufferListItem = malloc(sizeof(ALbufferlistitem));
511 BufferListItem->buffer = buffer;
512 BufferListItem->next = NULL;
513 BufferListItem->prev = NULL;
514 IncrementRef(&buffer->ref);
516 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
517 Source->BuffersInQueue = 1;
519 ReadLock(&buffer->lock);
520 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
521 Source->SampleSize = BytesFromFmt(buffer->FmtType);
522 ReadUnlock(&buffer->lock);
523 if(buffer->FmtChannels == FmtMono)
524 Source->Update = CalcSourceParams;
525 else
526 Source->Update = CalcNonAttnSourceParams;
527 Source->NeedsUpdate = AL_TRUE;
529 else
531 /* Source is now Undetermined */
532 Source->SourceType = AL_UNDETERMINED;
533 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
536 /* Delete all elements in the previous queue */
537 while(oldlist != NULL)
539 ALbufferlistitem *temp = oldlist;
540 oldlist = temp->next;
542 if(temp->buffer)
543 DecrementRef(&temp->buffer->ref);
544 free(temp);
546 UnlockContext(Context);
547 break;
549 case AL_SOURCE_STATE:
550 /* Query only */
551 al_throwerr(Context, AL_INVALID_OPERATION);
553 case AL_SEC_OFFSET:
554 case AL_SAMPLE_OFFSET:
555 case AL_BYTE_OFFSET:
556 CHECK_VALUE(Context, value >= 0);
558 LockContext(Context);
559 Source->OffsetType = param;
560 Source->Offset = value;
562 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
563 !Context->DeferUpdates)
565 if(ApplyOffset(Source) == AL_FALSE)
567 UnlockContext(Context);
568 al_throwerr(Context, AL_INVALID_VALUE);
571 UnlockContext(Context);
572 break;
574 case AL_DIRECT_FILTER:
575 CHECK_VALUE(Context, value == 0 ||
576 (filter=LookupFilter(device, value)) != NULL);
578 LockContext(Context);
579 if(!filter)
581 Source->DirectGain = 1.0f;
582 Source->DirectGainHF = 1.0f;
584 else
586 Source->DirectGain = filter->Gain;
587 Source->DirectGainHF = filter->GainHF;
589 UnlockContext(Context);
590 Source->NeedsUpdate = AL_TRUE;
591 break;
593 case AL_DIRECT_FILTER_GAINHF_AUTO:
594 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
596 Source->DryGainHFAuto = value;
597 Source->NeedsUpdate = AL_TRUE;
598 break;
600 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
601 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
603 Source->WetGainAuto = value;
604 Source->NeedsUpdate = AL_TRUE;
605 break;
607 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
608 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
610 Source->WetGainHFAuto = value;
611 Source->NeedsUpdate = AL_TRUE;
612 break;
614 case AL_DIRECT_CHANNELS_SOFT:
615 CHECK_VALUE(Context, value == AL_FALSE || value == AL_TRUE);
617 Source->DirectChannels = value;
618 Source->NeedsUpdate = AL_TRUE;
619 break;
621 case AL_DISTANCE_MODEL:
622 CHECK_VALUE(Context, value == AL_NONE ||
623 value == AL_INVERSE_DISTANCE ||
624 value == AL_INVERSE_DISTANCE_CLAMPED ||
625 value == AL_LINEAR_DISTANCE ||
626 value == AL_LINEAR_DISTANCE_CLAMPED ||
627 value == AL_EXPONENT_DISTANCE ||
628 value == AL_EXPONENT_DISTANCE_CLAMPED);
630 Source->DistanceModel = value;
631 if(Context->SourceDistanceModel)
632 Source->NeedsUpdate = AL_TRUE;
633 break;
635 default:
636 al_throwerr(Context, AL_INVALID_ENUM);
639 al_endtry;
641 ALCcontext_DecRef(Context);
645 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
647 ALCcontext *Context;
648 ALsource *Source;
650 switch(param)
652 case AL_POSITION:
653 case AL_VELOCITY:
654 case AL_DIRECTION:
655 alSource3f(source, param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
656 return;
659 Context = GetContextRef();
660 if(!Context) return;
662 al_try
664 ALCdevice *device = Context->Device;
665 ALeffectslot *slot = NULL;
666 ALfilter *filter = NULL;
668 if((Source=LookupSource(Context, source)) == NULL)
669 al_throwerr(Context, AL_INVALID_NAME);
670 switch(param)
672 case AL_AUXILIARY_SEND_FILTER:
673 LockContext(Context);
674 if(!((ALuint)value2 < device->NumAuxSends &&
675 (value1 == 0 || (slot=LookupEffectSlot(Context, value1)) != NULL) &&
676 (value3 == 0 || (filter=LookupFilter(device, value3)) != NULL)))
678 UnlockContext(Context);
679 al_throwerr(Context, AL_INVALID_VALUE);
682 /* Add refcount on the new slot, and release the previous slot */
683 if(slot) IncrementRef(&slot->ref);
684 slot = ExchangePtr((XchgPtr*)&Source->Send[value2].Slot, slot);
685 if(slot) DecrementRef(&slot->ref);
687 if(!filter)
689 /* Disable filter */
690 Source->Send[value2].Gain = 1.0f;
691 Source->Send[value2].GainHF = 1.0f;
693 else
695 Source->Send[value2].Gain = filter->Gain;
696 Source->Send[value2].GainHF = filter->GainHF;
698 Source->NeedsUpdate = AL_TRUE;
699 UnlockContext(Context);
700 break;
702 default:
703 al_throwerr(Context, AL_INVALID_ENUM);
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 void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64 *values)
1236 ALCcontext *Context;
1237 ALsource *Source;
1239 Context = GetContextRef();
1240 if(!Context) return;
1242 al_try
1244 if((Source=LookupSource(Context, source)) == NULL)
1245 al_throwerr(Context, AL_INVALID_NAME);
1246 CHECK_VALUE(Context, values);
1247 switch(param)
1249 default:
1250 al_throwerr(Context, AL_INVALID_ENUM);
1253 al_endtry;
1255 ALCcontext_DecRef(Context);
1258 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 *values)
1260 ALCcontext *Context;
1261 ALsource *Source;
1263 Context = GetContextRef();
1264 if(!Context) return;
1266 al_try
1268 if((Source=LookupSource(Context, source)) == NULL)
1269 al_throwerr(Context, AL_INVALID_NAME);
1270 CHECK_VALUE(Context, values);
1271 switch(param)
1273 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1274 LockContext(Context);
1275 values[0] = GetSourceOffset(Source);
1276 values[1] = ALCdevice_GetLatency(Context->Device);
1277 UnlockContext(Context);
1278 break;
1280 default:
1281 al_throwerr(Context, AL_INVALID_ENUM);
1284 al_endtry;
1286 ALCcontext_DecRef(Context);
1290 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1292 alSourcePlayv(1, &source);
1294 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1296 ALCcontext *Context;
1297 ALsource *Source;
1298 ALsizei i;
1300 Context = GetContextRef();
1301 if(!Context) return;
1303 al_try
1305 CHECK_VALUE(Context, n >= 0);
1306 for(i = 0;i < n;i++)
1308 if(!LookupSource(Context, sources[i]))
1309 al_throwerr(Context, AL_INVALID_NAME);
1312 LockContext(Context);
1313 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1315 void *temp = NULL;
1316 ALsizei newcount;
1318 newcount = Context->MaxActiveSources << 1;
1319 if(newcount > 0)
1320 temp = realloc(Context->ActiveSources,
1321 sizeof(*Context->ActiveSources) * newcount);
1322 if(!temp)
1324 UnlockContext(Context);
1325 al_throwerr(Context, AL_OUT_OF_MEMORY);
1328 Context->ActiveSources = temp;
1329 Context->MaxActiveSources = newcount;
1332 for(i = 0;i < n;i++)
1334 Source = LookupSource(Context, sources[i]);
1335 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1336 else SetSourceState(Source, Context, AL_PLAYING);
1338 UnlockContext(Context);
1340 al_endtry;
1342 ALCcontext_DecRef(Context);
1345 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1347 alSourcePausev(1, &source);
1349 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1351 ALCcontext *Context;
1352 ALsource *Source;
1353 ALsizei i;
1355 Context = GetContextRef();
1356 if(!Context) return;
1358 al_try
1360 CHECK_VALUE(Context, n >= 0);
1361 for(i = 0;i < n;i++)
1363 if(!LookupSource(Context, sources[i]))
1364 al_throwerr(Context, AL_INVALID_NAME);
1367 LockContext(Context);
1368 for(i = 0;i < n;i++)
1370 Source = LookupSource(Context, sources[i]);
1371 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1372 else SetSourceState(Source, Context, AL_PAUSED);
1374 UnlockContext(Context);
1376 al_endtry;
1378 ALCcontext_DecRef(Context);
1381 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1383 alSourceStopv(1, &source);
1385 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1387 ALCcontext *Context;
1388 ALsource *Source;
1389 ALsizei i;
1391 Context = GetContextRef();
1392 if(!Context) return;
1394 al_try
1396 CHECK_VALUE(Context, n >= 0);
1397 for(i = 0;i < n;i++)
1399 if(!LookupSource(Context, sources[i]))
1400 al_throwerr(Context, AL_INVALID_NAME);
1403 LockContext(Context);
1404 for(i = 0;i < n;i++)
1406 Source = LookupSource(Context, sources[i]);
1407 Source->new_state = AL_NONE;
1408 SetSourceState(Source, Context, AL_STOPPED);
1410 UnlockContext(Context);
1412 al_endtry;
1414 ALCcontext_DecRef(Context);
1417 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1419 alSourceRewindv(1, &source);
1421 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1423 ALCcontext *Context;
1424 ALsource *Source;
1425 ALsizei i;
1427 Context = GetContextRef();
1428 if(!Context) return;
1430 al_try
1432 CHECK_VALUE(Context, n >= 0);
1433 for(i = 0;i < n;i++)
1435 if(!LookupSource(Context, sources[i]))
1436 al_throwerr(Context, AL_INVALID_NAME);
1439 LockContext(Context);
1440 for(i = 0;i < n;i++)
1442 Source = LookupSource(Context, sources[i]);
1443 Source->new_state = AL_NONE;
1444 SetSourceState(Source, Context, AL_INITIAL);
1446 UnlockContext(Context);
1448 al_endtry;
1450 ALCcontext_DecRef(Context);
1454 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
1456 ALCcontext *Context;
1457 ALsource *Source;
1458 ALsizei i;
1459 ALbufferlistitem *BufferListStart = NULL;
1460 ALbufferlistitem *BufferList;
1461 ALbuffer *BufferFmt;
1463 if(nb == 0)
1464 return;
1466 Context = GetContextRef();
1467 if(!Context) return;
1469 al_try
1471 ALCdevice *device = Context->Device;
1473 CHECK_VALUE(Context, nb >= 0);
1475 if((Source=LookupSource(Context, source)) == NULL)
1476 al_throwerr(Context, AL_INVALID_NAME);
1478 LockContext(Context);
1479 if(Source->SourceType == AL_STATIC)
1481 UnlockContext(Context);
1482 /* Can't queue on a Static Source */
1483 al_throwerr(Context, AL_INVALID_OPERATION);
1486 BufferFmt = NULL;
1488 /* Check for a valid Buffer, for its frequency and format */
1489 BufferList = Source->queue;
1490 while(BufferList)
1492 if(BufferList->buffer)
1494 BufferFmt = BufferList->buffer;
1495 break;
1497 BufferList = BufferList->next;
1500 for(i = 0;i < nb;i++)
1502 ALbuffer *buffer = NULL;
1503 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1505 UnlockContext(Context);
1506 al_throwerr(Context, AL_INVALID_NAME);
1509 if(!BufferListStart)
1511 BufferListStart = malloc(sizeof(ALbufferlistitem));
1512 BufferListStart->buffer = buffer;
1513 BufferListStart->next = NULL;
1514 BufferListStart->prev = NULL;
1515 BufferList = BufferListStart;
1517 else
1519 BufferList->next = malloc(sizeof(ALbufferlistitem));
1520 BufferList->next->buffer = buffer;
1521 BufferList->next->next = NULL;
1522 BufferList->next->prev = BufferList;
1523 BufferList = BufferList->next;
1525 if(!buffer) continue;
1526 IncrementRef(&buffer->ref);
1528 ReadLock(&buffer->lock);
1529 if(BufferFmt == NULL)
1531 BufferFmt = buffer;
1533 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1534 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1535 if(buffer->FmtChannels == FmtMono)
1536 Source->Update = CalcSourceParams;
1537 else
1538 Source->Update = CalcNonAttnSourceParams;
1540 Source->NeedsUpdate = AL_TRUE;
1542 else if(BufferFmt->Frequency != buffer->Frequency ||
1543 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1544 BufferFmt->OriginalType != buffer->OriginalType)
1546 ReadUnlock(&buffer->lock);
1547 UnlockContext(Context);
1548 al_throwerr(Context, AL_INVALID_OPERATION);
1550 ReadUnlock(&buffer->lock);
1553 /* Source is now streaming */
1554 Source->SourceType = AL_STREAMING;
1556 if(Source->queue == NULL)
1557 Source->queue = BufferListStart;
1558 else
1560 /* Append to the end of the queue */
1561 BufferList = Source->queue;
1562 while(BufferList->next != NULL)
1563 BufferList = BufferList->next;
1565 BufferListStart->prev = BufferList;
1566 BufferList->next = BufferListStart;
1569 Source->BuffersInQueue += nb;
1571 UnlockContext(Context);
1573 al_catchany()
1575 while(BufferListStart)
1577 BufferList = BufferListStart;
1578 BufferListStart = BufferList->next;
1580 if(BufferList->buffer)
1581 DecrementRef(&BufferList->buffer->ref);
1582 free(BufferList);
1585 al_endtry;
1587 ALCcontext_DecRef(Context);
1590 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
1592 ALCcontext *Context;
1593 ALsource *Source;
1594 ALsizei i;
1595 ALbufferlistitem *BufferList;
1597 if(nb == 0)
1598 return;
1600 Context = GetContextRef();
1601 if(!Context) return;
1603 al_try
1605 CHECK_VALUE(Context, nb >= 0);
1607 if((Source=LookupSource(Context, source)) == NULL)
1608 al_throwerr(Context, AL_INVALID_NAME);
1610 LockContext(Context);
1611 if(Source->Looping || Source->SourceType != AL_STREAMING ||
1612 (ALuint)nb > Source->BuffersPlayed)
1614 UnlockContext(Context);
1615 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1616 al_throwerr(Context, AL_INVALID_VALUE);
1619 for(i = 0;i < nb;i++)
1621 BufferList = Source->queue;
1622 Source->queue = BufferList->next;
1623 Source->BuffersInQueue--;
1624 Source->BuffersPlayed--;
1626 if(BufferList->buffer)
1628 buffers[i] = BufferList->buffer->id;
1629 DecrementRef(&BufferList->buffer->ref);
1631 else
1632 buffers[i] = 0;
1634 free(BufferList);
1636 if(Source->queue)
1637 Source->queue->prev = NULL;
1638 UnlockContext(Context);
1640 al_endtry;
1642 ALCcontext_DecRef(Context);
1646 static ALvoid InitSourceParams(ALsource *Source)
1648 ALuint i;
1650 Source->InnerAngle = 360.0f;
1651 Source->OuterAngle = 360.0f;
1652 Source->Pitch = 1.0f;
1653 Source->Position[0] = 0.0f;
1654 Source->Position[1] = 0.0f;
1655 Source->Position[2] = 0.0f;
1656 Source->Orientation[0] = 0.0f;
1657 Source->Orientation[1] = 0.0f;
1658 Source->Orientation[2] = 0.0f;
1659 Source->Velocity[0] = 0.0f;
1660 Source->Velocity[1] = 0.0f;
1661 Source->Velocity[2] = 0.0f;
1662 Source->RefDistance = 1.0f;
1663 Source->MaxDistance = FLT_MAX;
1664 Source->RollOffFactor = 1.0f;
1665 Source->Looping = AL_FALSE;
1666 Source->Gain = 1.0f;
1667 Source->MinGain = 0.0f;
1668 Source->MaxGain = 1.0f;
1669 Source->OuterGain = 0.0f;
1670 Source->OuterGainHF = 1.0f;
1672 Source->DryGainHFAuto = AL_TRUE;
1673 Source->WetGainAuto = AL_TRUE;
1674 Source->WetGainHFAuto = AL_TRUE;
1675 Source->AirAbsorptionFactor = 0.0f;
1676 Source->RoomRolloffFactor = 0.0f;
1677 Source->DopplerFactor = 1.0f;
1678 Source->DirectChannels = AL_FALSE;
1680 Source->DistanceModel = DefaultDistanceModel;
1682 Source->Resampler = DefaultResampler;
1684 Source->state = AL_INITIAL;
1685 Source->new_state = AL_NONE;
1686 Source->SourceType = AL_UNDETERMINED;
1687 Source->Offset = -1.0;
1689 Source->DirectGain = 1.0f;
1690 Source->DirectGainHF = 1.0f;
1691 for(i = 0;i < MAX_SENDS;i++)
1693 Source->Send[i].Gain = 1.0f;
1694 Source->Send[i].GainHF = 1.0f;
1697 Source->NeedsUpdate = AL_TRUE;
1699 Source->Hrtf.Moving = AL_FALSE;
1700 Source->Hrtf.Counter = 0;
1704 /* SetSourceState
1706 * Sets the source's new play state given its current state.
1708 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1710 if(state == AL_PLAYING)
1712 ALbufferlistitem *BufferList;
1713 ALsizei j, k;
1715 /* Check that there is a queue containing at least one valid, non zero
1716 * length Buffer. */
1717 BufferList = Source->queue;
1718 while(BufferList)
1720 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
1721 break;
1722 BufferList = BufferList->next;
1725 if(Source->state != AL_PLAYING)
1727 for(j = 0;j < MaxChannels;j++)
1729 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1730 Source->Hrtf.History[j][k] = 0.0f;
1731 for(k = 0;k < HRIR_LENGTH;k++)
1733 Source->Hrtf.Values[j][k][0] = 0.0f;
1734 Source->Hrtf.Values[j][k][1] = 0.0f;
1739 if(Source->state != AL_PAUSED)
1741 Source->state = AL_PLAYING;
1742 Source->position = 0;
1743 Source->position_fraction = 0;
1744 Source->BuffersPlayed = 0;
1746 else
1747 Source->state = AL_PLAYING;
1749 // Check if an Offset has been set
1750 if(Source->Offset >= 0.0)
1751 ApplyOffset(Source);
1753 /* If there's nothing to play, or device is disconnected, go right to
1754 * stopped */
1755 if(!BufferList || !Context->Device->Connected)
1757 SetSourceState(Source, Context, AL_STOPPED);
1758 return;
1761 for(j = 0;j < Context->ActiveSourceCount;j++)
1763 if(Context->ActiveSources[j] == Source)
1764 break;
1766 if(j == Context->ActiveSourceCount)
1767 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1769 else if(state == AL_PAUSED)
1771 if(Source->state == AL_PLAYING)
1773 Source->state = AL_PAUSED;
1774 Source->Hrtf.Moving = AL_FALSE;
1775 Source->Hrtf.Counter = 0;
1778 else if(state == AL_STOPPED)
1780 if(Source->state != AL_INITIAL)
1782 Source->state = AL_STOPPED;
1783 Source->BuffersPlayed = Source->BuffersInQueue;
1784 Source->Hrtf.Moving = AL_FALSE;
1785 Source->Hrtf.Counter = 0;
1787 Source->Offset = -1.0;
1789 else if(state == AL_INITIAL)
1791 if(Source->state != AL_INITIAL)
1793 Source->state = AL_INITIAL;
1794 Source->position = 0;
1795 Source->position_fraction = 0;
1796 Source->BuffersPlayed = 0;
1797 Source->Hrtf.Moving = AL_FALSE;
1798 Source->Hrtf.Counter = 0;
1800 Source->Offset = -1.0;
1804 /* GetSourceOffset
1806 * Gets the current read offset for the given Source, in 32.32 fixed-point
1807 * samples. The offset is relative to the start of the queue (not the start of
1808 * the current buffer).
1810 static ALint64 GetSourceOffset(ALsource *Source)
1812 const ALbufferlistitem *BufferList;
1813 ALuint64 readPos;
1814 ALuint i;
1816 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
1817 return 0;
1819 /* NOTE: This is the offset into the *current* buffer, so add the length of
1820 * any played buffers */
1821 readPos = (ALuint64)Source->position << 32;
1822 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
1823 BufferList = Source->queue;
1824 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
1826 if(BufferList->buffer)
1827 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
1828 BufferList = BufferList->next;
1831 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
1834 /* GetSourceOffsets
1836 * Gets the current read and write offsets for the given Source, in the
1837 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
1838 * the start of the queue (not the start of the current buffer).
1840 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1842 const ALbufferlistitem *BufferList;
1843 const ALbuffer *Buffer = NULL;
1844 ALuint readPos, writePos;
1845 ALuint totalBufferLen;
1846 ALuint i;
1848 // Find the first valid Buffer in the Queue
1849 BufferList = Source->queue;
1850 while(BufferList)
1852 if(BufferList->buffer)
1854 Buffer = BufferList->buffer;
1855 break;
1857 BufferList = BufferList->next;
1860 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1862 offset[0] = 0.0;
1863 offset[1] = 0.0;
1864 return;
1867 if(updateLen > 0.0 && updateLen < 0.015)
1868 updateLen = 0.015;
1870 /* NOTE: This is the offset into the *current* buffer, so add the length of
1871 * any played buffers */
1872 readPos = Source->position;
1873 totalBufferLen = 0;
1874 BufferList = Source->queue;
1875 for(i = 0;BufferList;i++)
1877 if(BufferList->buffer)
1879 if(i < Source->BuffersPlayed)
1880 readPos += BufferList->buffer->SampleLen;
1881 totalBufferLen += BufferList->buffer->SampleLen;
1883 BufferList = BufferList->next;
1885 if(Source->state == AL_PLAYING)
1886 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
1887 else
1888 writePos = readPos;
1890 if(Source->Looping)
1892 readPos %= totalBufferLen;
1893 writePos %= totalBufferLen;
1895 else
1897 /* Wrap positions back to 0 */
1898 if(readPos >= totalBufferLen)
1899 readPos = 0;
1900 if(writePos >= totalBufferLen)
1901 writePos = 0;
1904 switch(name)
1906 case AL_SEC_OFFSET:
1907 offset[0] = (ALdouble)readPos / Buffer->Frequency;
1908 offset[1] = (ALdouble)writePos / Buffer->Frequency;
1909 break;
1911 case AL_SAMPLE_OFFSET:
1912 case AL_SAMPLE_RW_OFFSETS_SOFT:
1913 offset[0] = (ALdouble)readPos;
1914 offset[1] = (ALdouble)writePos;
1915 break;
1917 case AL_BYTE_OFFSET:
1918 case AL_BYTE_RW_OFFSETS_SOFT:
1919 if(Buffer->OriginalType == UserFmtIMA4)
1921 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
1922 ALuint FrameBlockSize = 65;
1924 /* Round down to nearest ADPCM block */
1925 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1926 if(Source->state != AL_PLAYING)
1927 offset[1] = offset[0];
1928 else
1930 /* Round up to nearest ADPCM block */
1931 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
1932 FrameBlockSize * BlockSize);
1935 else
1937 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
1938 offset[0] = (ALdouble)(readPos * FrameSize);
1939 offset[1] = (ALdouble)(writePos * FrameSize);
1941 break;
1946 /* ApplyOffset
1948 * Apply the stored playback offset to the Source. This function will update
1949 * the number of buffers "played" given the stored offset.
1951 ALboolean ApplyOffset(ALsource *Source)
1953 const ALbufferlistitem *BufferList;
1954 const ALbuffer *Buffer;
1955 ALint bufferLen, totalBufferLen;
1956 ALint buffersPlayed;
1957 ALint offset;
1959 /* Get sample frame offset */
1960 offset = GetSampleOffset(Source);
1961 if(offset == -1)
1962 return AL_FALSE;
1964 buffersPlayed = 0;
1965 totalBufferLen = 0;
1967 BufferList = Source->queue;
1968 while(BufferList)
1970 Buffer = BufferList->buffer;
1971 bufferLen = Buffer ? Buffer->SampleLen : 0;
1973 if(bufferLen <= offset-totalBufferLen)
1975 /* Offset is past this buffer so increment to the next buffer */
1976 buffersPlayed++;
1978 else if(totalBufferLen <= offset)
1980 /* Offset is in this buffer */
1981 Source->BuffersPlayed = buffersPlayed;
1983 Source->position = offset - totalBufferLen;
1984 Source->position_fraction = 0;
1985 return AL_TRUE;
1988 totalBufferLen += bufferLen;
1990 BufferList = BufferList->next;
1993 /* Offset is out of range of the queue */
1994 return AL_FALSE;
1998 /* GetSampleOffset
2000 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2001 * Second offset supplied by the application). This takes into account the fact
2002 * that the buffer format may have been modifed since.
2004 static ALint GetSampleOffset(ALsource *Source)
2006 const ALbuffer *Buffer = NULL;
2007 const ALbufferlistitem *BufferList;
2008 ALint Offset = -1;
2010 /* Find the first valid Buffer in the Queue */
2011 BufferList = Source->queue;
2012 while(BufferList)
2014 if(BufferList->buffer)
2016 Buffer = BufferList->buffer;
2017 break;
2019 BufferList = BufferList->next;
2022 if(!Buffer)
2024 Source->Offset = -1.0;
2025 return -1;
2028 switch(Source->OffsetType)
2030 case AL_BYTE_OFFSET:
2031 /* Determine the ByteOffset (and ensure it is block aligned) */
2032 Offset = (ALint)Source->Offset;
2033 if(Buffer->OriginalType == UserFmtIMA4)
2035 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2036 Offset *= 65;
2038 else
2039 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2040 break;
2042 case AL_SAMPLE_OFFSET:
2043 Offset = (ALint)Source->Offset;
2044 break;
2046 case AL_SEC_OFFSET:
2047 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2048 break;
2050 Source->Offset = -1.0;
2052 return Offset;
2056 /* ReleaseALSources
2058 * Destroys all sources in the source map.
2060 ALvoid ReleaseALSources(ALCcontext *Context)
2062 ALsizei pos;
2063 ALuint j;
2064 for(pos = 0;pos < Context->SourceMap.size;pos++)
2066 ALsource *temp = Context->SourceMap.array[pos].value;
2067 Context->SourceMap.array[pos].value = NULL;
2069 while(temp->queue != NULL)
2071 ALbufferlistitem *BufferList = temp->queue;
2072 temp->queue = BufferList->next;
2074 if(BufferList->buffer != NULL)
2075 DecrementRef(&BufferList->buffer->ref);
2076 free(BufferList);
2079 for(j = 0;j < MAX_SENDS;++j)
2081 if(temp->Send[j].Slot)
2082 DecrementRef(&temp->Send[j].Slot->ref);
2083 temp->Send[j].Slot = NULL;
2086 FreeThunkEntry(temp->id);
2087 memset(temp, 0, sizeof(*temp));
2088 al_free(temp);