Replace the sinc4 resampler with cubic
[openal-soft.git] / OpenAL32 / alState.c
blobc8c8106535790a689e6e8ff762805fa5f9086803
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2000 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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "version.h"
25 #include <stdlib.h>
26 #include "alMain.h"
27 #include "AL/alc.h"
28 #include "AL/al.h"
29 #include "AL/alext.h"
30 #include "alError.h"
31 #include "alListener.h"
32 #include "alSource.h"
33 #include "alAuxEffectSlot.h"
35 #include "backends/base.h"
38 static const ALchar alVendor[] = "OpenAL Community";
39 static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
40 static const ALchar alRenderer[] = "OpenAL Soft";
42 // Error Messages
43 static const ALchar alNoError[] = "No Error";
44 static const ALchar alErrInvalidName[] = "Invalid Name";
45 static const ALchar alErrInvalidEnum[] = "Invalid Enum";
46 static const ALchar alErrInvalidValue[] = "Invalid Value";
47 static const ALchar alErrInvalidOp[] = "Invalid Operation";
48 static const ALchar alErrOutOfMemory[] = "Out of Memory";
50 /* Resampler strings */
51 static const ALchar alPointResampler[] = "Nearest";
52 static const ALchar alLinearResampler[] = "Linear";
53 static const ALchar alCubicResampler[] = "Cubic";
54 static const ALchar alBSinc12Resampler[] = "11th order Sinc";
55 static const ALchar alBSinc24Resampler[] = "23rd order Sinc";
57 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
58 * alcFunctions list.
60 AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
62 const char *spoof = getenv("ALSOFT_SPOOF_VERSION");
63 if(spoof && spoof[0] != '\0') return spoof;
64 return ALSOFT_VERSION;
67 #define DO_UPDATEPROPS() do { \
68 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
69 UpdateContextProps(context); \
70 else \
71 ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); \
72 } while(0)
75 AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
77 ALCcontext *context;
79 context = GetContextRef();
80 if(!context) return;
82 WriteLock(&context->PropLock);
83 switch(capability)
85 case AL_SOURCE_DISTANCE_MODEL:
86 context->SourceDistanceModel = AL_TRUE;
87 DO_UPDATEPROPS();
88 break;
90 default:
91 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
94 done:
95 WriteUnlock(&context->PropLock);
96 ALCcontext_DecRef(context);
99 AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
101 ALCcontext *context;
103 context = GetContextRef();
104 if(!context) return;
106 WriteLock(&context->PropLock);
107 switch(capability)
109 case AL_SOURCE_DISTANCE_MODEL:
110 context->SourceDistanceModel = AL_FALSE;
111 DO_UPDATEPROPS();
112 break;
114 default:
115 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
118 done:
119 WriteUnlock(&context->PropLock);
120 ALCcontext_DecRef(context);
123 AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
125 ALCcontext *context;
126 ALboolean value=AL_FALSE;
128 context = GetContextRef();
129 if(!context) return AL_FALSE;
131 switch(capability)
133 case AL_SOURCE_DISTANCE_MODEL:
134 value = context->SourceDistanceModel;
135 break;
137 default:
138 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
141 done:
142 ALCcontext_DecRef(context);
144 return value;
147 AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
149 ALCcontext *context;
150 ALboolean value=AL_FALSE;
152 context = GetContextRef();
153 if(!context) return AL_FALSE;
155 switch(pname)
157 case AL_DOPPLER_FACTOR:
158 if(context->DopplerFactor != 0.0f)
159 value = AL_TRUE;
160 break;
162 case AL_DOPPLER_VELOCITY:
163 if(context->DopplerVelocity != 0.0f)
164 value = AL_TRUE;
165 break;
167 case AL_DISTANCE_MODEL:
168 if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
169 value = AL_TRUE;
170 break;
172 case AL_SPEED_OF_SOUND:
173 if(context->SpeedOfSound != 0.0f)
174 value = AL_TRUE;
175 break;
177 case AL_DEFERRED_UPDATES_SOFT:
178 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
179 value = AL_TRUE;
180 break;
182 case AL_GAIN_LIMIT_SOFT:
183 if(GAIN_MIX_MAX/context->GainBoost != 0.0f)
184 value = AL_TRUE;
185 break;
187 case AL_NUM_RESAMPLERS_SOFT:
188 /* Always non-0. */
189 value = AL_TRUE;
190 break;
192 case AL_DEFAULT_RESAMPLER_SOFT:
193 value = ResamplerDefault ? AL_TRUE : AL_FALSE;
194 break;
196 default:
197 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
200 done:
201 ALCcontext_DecRef(context);
203 return value;
206 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
208 ALCcontext *context;
209 ALdouble value = 0.0;
211 context = GetContextRef();
212 if(!context) return 0.0;
214 switch(pname)
216 case AL_DOPPLER_FACTOR:
217 value = (ALdouble)context->DopplerFactor;
218 break;
220 case AL_DOPPLER_VELOCITY:
221 value = (ALdouble)context->DopplerVelocity;
222 break;
224 case AL_DISTANCE_MODEL:
225 value = (ALdouble)context->DistanceModel;
226 break;
228 case AL_SPEED_OF_SOUND:
229 value = (ALdouble)context->SpeedOfSound;
230 break;
232 case AL_DEFERRED_UPDATES_SOFT:
233 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
234 value = (ALdouble)AL_TRUE;
235 break;
237 case AL_GAIN_LIMIT_SOFT:
238 value = (ALdouble)GAIN_MIX_MAX/context->GainBoost;
239 break;
241 case AL_NUM_RESAMPLERS_SOFT:
242 value = (ALdouble)(ResamplerMax + 1);
243 break;
245 case AL_DEFAULT_RESAMPLER_SOFT:
246 value = (ALdouble)ResamplerDefault;
247 break;
249 default:
250 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
253 done:
254 ALCcontext_DecRef(context);
256 return value;
259 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
261 ALCcontext *context;
262 ALfloat value = 0.0f;
264 context = GetContextRef();
265 if(!context) return 0.0f;
267 switch(pname)
269 case AL_DOPPLER_FACTOR:
270 value = context->DopplerFactor;
271 break;
273 case AL_DOPPLER_VELOCITY:
274 value = context->DopplerVelocity;
275 break;
277 case AL_DISTANCE_MODEL:
278 value = (ALfloat)context->DistanceModel;
279 break;
281 case AL_SPEED_OF_SOUND:
282 value = context->SpeedOfSound;
283 break;
285 case AL_DEFERRED_UPDATES_SOFT:
286 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
287 value = (ALfloat)AL_TRUE;
288 break;
290 case AL_GAIN_LIMIT_SOFT:
291 value = GAIN_MIX_MAX/context->GainBoost;
292 break;
294 case AL_NUM_RESAMPLERS_SOFT:
295 value = (ALfloat)(ResamplerMax + 1);
296 break;
298 case AL_DEFAULT_RESAMPLER_SOFT:
299 value = (ALfloat)ResamplerDefault;
300 break;
302 default:
303 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
306 done:
307 ALCcontext_DecRef(context);
309 return value;
312 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
314 ALCcontext *context;
315 ALint value = 0;
317 context = GetContextRef();
318 if(!context) return 0;
320 switch(pname)
322 case AL_DOPPLER_FACTOR:
323 value = (ALint)context->DopplerFactor;
324 break;
326 case AL_DOPPLER_VELOCITY:
327 value = (ALint)context->DopplerVelocity;
328 break;
330 case AL_DISTANCE_MODEL:
331 value = (ALint)context->DistanceModel;
332 break;
334 case AL_SPEED_OF_SOUND:
335 value = (ALint)context->SpeedOfSound;
336 break;
338 case AL_DEFERRED_UPDATES_SOFT:
339 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
340 value = (ALint)AL_TRUE;
341 break;
343 case AL_GAIN_LIMIT_SOFT:
344 value = (ALint)(GAIN_MIX_MAX/context->GainBoost);
345 break;
347 case AL_NUM_RESAMPLERS_SOFT:
348 value = ResamplerMax + 1;
349 break;
351 case AL_DEFAULT_RESAMPLER_SOFT:
352 value = ResamplerDefault;
353 break;
355 default:
356 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
359 done:
360 ALCcontext_DecRef(context);
362 return value;
365 AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
367 ALCcontext *context;
368 ALint64SOFT value = 0;
370 context = GetContextRef();
371 if(!context) return 0;
373 switch(pname)
375 case AL_DOPPLER_FACTOR:
376 value = (ALint64SOFT)context->DopplerFactor;
377 break;
379 case AL_DOPPLER_VELOCITY:
380 value = (ALint64SOFT)context->DopplerVelocity;
381 break;
383 case AL_DISTANCE_MODEL:
384 value = (ALint64SOFT)context->DistanceModel;
385 break;
387 case AL_SPEED_OF_SOUND:
388 value = (ALint64SOFT)context->SpeedOfSound;
389 break;
391 case AL_DEFERRED_UPDATES_SOFT:
392 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
393 value = (ALint64SOFT)AL_TRUE;
394 break;
396 case AL_GAIN_LIMIT_SOFT:
397 value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
398 break;
400 case AL_NUM_RESAMPLERS_SOFT:
401 value = (ALint64SOFT)(ResamplerMax + 1);
402 break;
404 case AL_DEFAULT_RESAMPLER_SOFT:
405 value = (ALint64SOFT)ResamplerDefault;
406 break;
408 default:
409 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
412 done:
413 ALCcontext_DecRef(context);
415 return value;
418 AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
420 ALCcontext *context;
422 if(values)
424 switch(pname)
426 case AL_DOPPLER_FACTOR:
427 case AL_DOPPLER_VELOCITY:
428 case AL_DISTANCE_MODEL:
429 case AL_SPEED_OF_SOUND:
430 case AL_DEFERRED_UPDATES_SOFT:
431 case AL_GAIN_LIMIT_SOFT:
432 case AL_NUM_RESAMPLERS_SOFT:
433 case AL_DEFAULT_RESAMPLER_SOFT:
434 values[0] = alGetBoolean(pname);
435 return;
439 context = GetContextRef();
440 if(!context) return;
442 if(!(values))
443 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
444 switch(pname)
446 default:
447 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
450 done:
451 ALCcontext_DecRef(context);
454 AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
456 ALCcontext *context;
458 if(values)
460 switch(pname)
462 case AL_DOPPLER_FACTOR:
463 case AL_DOPPLER_VELOCITY:
464 case AL_DISTANCE_MODEL:
465 case AL_SPEED_OF_SOUND:
466 case AL_DEFERRED_UPDATES_SOFT:
467 case AL_GAIN_LIMIT_SOFT:
468 case AL_NUM_RESAMPLERS_SOFT:
469 case AL_DEFAULT_RESAMPLER_SOFT:
470 values[0] = alGetDouble(pname);
471 return;
475 context = GetContextRef();
476 if(!context) return;
478 if(!(values))
479 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
480 switch(pname)
482 default:
483 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
486 done:
487 ALCcontext_DecRef(context);
490 AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
492 ALCcontext *context;
494 if(values)
496 switch(pname)
498 case AL_DOPPLER_FACTOR:
499 case AL_DOPPLER_VELOCITY:
500 case AL_DISTANCE_MODEL:
501 case AL_SPEED_OF_SOUND:
502 case AL_DEFERRED_UPDATES_SOFT:
503 case AL_GAIN_LIMIT_SOFT:
504 case AL_NUM_RESAMPLERS_SOFT:
505 case AL_DEFAULT_RESAMPLER_SOFT:
506 values[0] = alGetFloat(pname);
507 return;
511 context = GetContextRef();
512 if(!context) return;
514 if(!(values))
515 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
516 switch(pname)
518 default:
519 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
522 done:
523 ALCcontext_DecRef(context);
526 AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
528 ALCcontext *context;
530 if(values)
532 switch(pname)
534 case AL_DOPPLER_FACTOR:
535 case AL_DOPPLER_VELOCITY:
536 case AL_DISTANCE_MODEL:
537 case AL_SPEED_OF_SOUND:
538 case AL_DEFERRED_UPDATES_SOFT:
539 case AL_GAIN_LIMIT_SOFT:
540 case AL_NUM_RESAMPLERS_SOFT:
541 case AL_DEFAULT_RESAMPLER_SOFT:
542 values[0] = alGetInteger(pname);
543 return;
547 context = GetContextRef();
548 if(!context) return;
550 switch(pname)
552 default:
553 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
556 done:
557 ALCcontext_DecRef(context);
560 AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
562 ALCcontext *context;
564 if(values)
566 switch(pname)
568 case AL_DOPPLER_FACTOR:
569 case AL_DOPPLER_VELOCITY:
570 case AL_DISTANCE_MODEL:
571 case AL_SPEED_OF_SOUND:
572 case AL_DEFERRED_UPDATES_SOFT:
573 case AL_GAIN_LIMIT_SOFT:
574 case AL_NUM_RESAMPLERS_SOFT:
575 case AL_DEFAULT_RESAMPLER_SOFT:
576 values[0] = alGetInteger64SOFT(pname);
577 return;
581 context = GetContextRef();
582 if(!context) return;
584 switch(pname)
586 default:
587 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
590 done:
591 ALCcontext_DecRef(context);
594 AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
596 const ALchar *value = NULL;
597 ALCcontext *context;
599 context = GetContextRef();
600 if(!context) return NULL;
602 switch(pname)
604 case AL_VENDOR:
605 value = alVendor;
606 break;
608 case AL_VERSION:
609 value = alVersion;
610 break;
612 case AL_RENDERER:
613 value = alRenderer;
614 break;
616 case AL_EXTENSIONS:
617 value = context->ExtensionList;
618 break;
620 case AL_NO_ERROR:
621 value = alNoError;
622 break;
624 case AL_INVALID_NAME:
625 value = alErrInvalidName;
626 break;
628 case AL_INVALID_ENUM:
629 value = alErrInvalidEnum;
630 break;
632 case AL_INVALID_VALUE:
633 value = alErrInvalidValue;
634 break;
636 case AL_INVALID_OPERATION:
637 value = alErrInvalidOp;
638 break;
640 case AL_OUT_OF_MEMORY:
641 value = alErrOutOfMemory;
642 break;
644 default:
645 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
648 done:
649 ALCcontext_DecRef(context);
651 return value;
654 AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
656 ALCcontext *context;
658 context = GetContextRef();
659 if(!context) return;
661 if(!(value >= 0.0f && isfinite(value)))
662 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
664 WriteLock(&context->PropLock);
665 context->DopplerFactor = value;
666 DO_UPDATEPROPS();
667 WriteUnlock(&context->PropLock);
669 done:
670 ALCcontext_DecRef(context);
673 AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
675 ALCcontext *context;
677 context = GetContextRef();
678 if(!context) return;
680 if(!(value >= 0.0f && isfinite(value)))
681 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
683 WriteLock(&context->PropLock);
684 context->DopplerVelocity = value;
685 DO_UPDATEPROPS();
686 WriteUnlock(&context->PropLock);
688 done:
689 ALCcontext_DecRef(context);
692 AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
694 ALCcontext *context;
696 context = GetContextRef();
697 if(!context) return;
699 if(!(value > 0.0f && isfinite(value)))
700 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
702 WriteLock(&context->PropLock);
703 context->SpeedOfSound = value;
704 DO_UPDATEPROPS();
705 WriteUnlock(&context->PropLock);
707 done:
708 ALCcontext_DecRef(context);
711 AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
713 ALCcontext *context;
715 context = GetContextRef();
716 if(!context) return;
718 if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED ||
719 value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
720 value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
721 value == AL_NONE))
722 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
724 WriteLock(&context->PropLock);
725 context->DistanceModel = value;
726 if(!context->SourceDistanceModel)
727 DO_UPDATEPROPS();
728 WriteUnlock(&context->PropLock);
730 done:
731 ALCcontext_DecRef(context);
735 AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
737 ALCcontext *context;
739 context = GetContextRef();
740 if(!context) return;
742 ALCcontext_DeferUpdates(context);
744 ALCcontext_DecRef(context);
747 AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
749 ALCcontext *context;
751 context = GetContextRef();
752 if(!context) return;
754 ALCcontext_ProcessUpdates(context);
756 ALCcontext_DecRef(context);
760 AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
762 const char *ResamplerNames[] = {
763 alPointResampler, alLinearResampler,
764 alCubicResampler, alBSinc12Resampler,
765 alBSinc24Resampler,
767 const ALchar *value = NULL;
768 ALCcontext *context;
770 static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
772 context = GetContextRef();
773 if(!context) return NULL;
775 switch(pname)
777 case AL_RESAMPLER_NAME_SOFT:
778 if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
779 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
780 value = ResamplerNames[index];
781 break;
783 default:
784 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
787 done:
788 ALCcontext_DecRef(context);
790 return value;
794 void UpdateContextProps(ALCcontext *context)
796 struct ALcontextProps *props;
798 /* Get an unused proprty container, or allocate a new one as needed. */
799 props = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire);
800 if(!props)
801 props = al_calloc(16, sizeof(*props));
802 else
804 struct ALcontextProps *next;
805 do {
806 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
807 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next,
808 almemory_order_seq_cst, almemory_order_acquire) == 0);
811 /* Copy in current property values. */
812 props->MetersPerUnit = context->MetersPerUnit;
814 props->DopplerFactor = context->DopplerFactor;
815 props->DopplerVelocity = context->DopplerVelocity;
816 props->SpeedOfSound = context->SpeedOfSound;
818 props->SourceDistanceModel = context->SourceDistanceModel;
819 props->DistanceModel = context->DistanceModel;
821 /* Set the new container for updating internal parameters. */
822 props = ATOMIC_EXCHANGE_PTR(&context->Update, props, almemory_order_acq_rel);
823 if(props)
825 /* If there was an unused update container, put it back in the
826 * freelist.
828 ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props);