Don't update context and listener props unnecessarily
[openal-soft.git] / OpenAL32 / alState.c
blob14646043a621d41aa0588fa24b904e6b75e3e333
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 alSinc4Resampler[] = "3rd order Sinc";
54 static const ALchar alBSinc12Resampler[] = "11th order Sinc";
55 static const ALchar alBSinc24Resampler[] = "23rd order Sinc";
57 #define DO_UPDATEPROPS() do { \
58 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
59 UpdateContextProps(context); \
60 else \
61 ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); \
62 } while(0)
65 AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
67 ALCcontext *context;
69 context = GetContextRef();
70 if(!context) return;
72 WriteLock(&context->PropLock);
73 switch(capability)
75 case AL_SOURCE_DISTANCE_MODEL:
76 context->SourceDistanceModel = AL_TRUE;
77 DO_UPDATEPROPS();
78 break;
80 default:
81 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
84 done:
85 WriteUnlock(&context->PropLock);
86 ALCcontext_DecRef(context);
89 AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
91 ALCcontext *context;
93 context = GetContextRef();
94 if(!context) return;
96 WriteLock(&context->PropLock);
97 switch(capability)
99 case AL_SOURCE_DISTANCE_MODEL:
100 context->SourceDistanceModel = AL_FALSE;
101 DO_UPDATEPROPS();
102 break;
104 default:
105 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
108 done:
109 WriteUnlock(&context->PropLock);
110 ALCcontext_DecRef(context);
113 AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
115 ALCcontext *context;
116 ALboolean value=AL_FALSE;
118 context = GetContextRef();
119 if(!context) return AL_FALSE;
121 switch(capability)
123 case AL_SOURCE_DISTANCE_MODEL:
124 value = context->SourceDistanceModel;
125 break;
127 default:
128 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
131 done:
132 ALCcontext_DecRef(context);
134 return value;
137 AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
139 ALCcontext *context;
140 ALboolean value=AL_FALSE;
142 context = GetContextRef();
143 if(!context) return AL_FALSE;
145 switch(pname)
147 case AL_DOPPLER_FACTOR:
148 if(context->DopplerFactor != 0.0f)
149 value = AL_TRUE;
150 break;
152 case AL_DOPPLER_VELOCITY:
153 if(context->DopplerVelocity != 0.0f)
154 value = AL_TRUE;
155 break;
157 case AL_DISTANCE_MODEL:
158 if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
159 value = AL_TRUE;
160 break;
162 case AL_SPEED_OF_SOUND:
163 if(context->SpeedOfSound != 0.0f)
164 value = AL_TRUE;
165 break;
167 case AL_DEFERRED_UPDATES_SOFT:
168 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
169 value = AL_TRUE;
170 break;
172 case AL_GAIN_LIMIT_SOFT:
173 if(GAIN_MIX_MAX/context->GainBoost != 0.0f)
174 value = AL_TRUE;
175 break;
177 case AL_NUM_RESAMPLERS_SOFT:
178 /* Always non-0. */
179 value = AL_TRUE;
180 break;
182 case AL_DEFAULT_RESAMPLER_SOFT:
183 value = ResamplerDefault ? AL_TRUE : AL_FALSE;
184 break;
186 default:
187 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
190 done:
191 ALCcontext_DecRef(context);
193 return value;
196 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
198 ALCcontext *context;
199 ALdouble value = 0.0;
201 context = GetContextRef();
202 if(!context) return 0.0;
204 switch(pname)
206 case AL_DOPPLER_FACTOR:
207 value = (ALdouble)context->DopplerFactor;
208 break;
210 case AL_DOPPLER_VELOCITY:
211 value = (ALdouble)context->DopplerVelocity;
212 break;
214 case AL_DISTANCE_MODEL:
215 value = (ALdouble)context->DistanceModel;
216 break;
218 case AL_SPEED_OF_SOUND:
219 value = (ALdouble)context->SpeedOfSound;
220 break;
222 case AL_DEFERRED_UPDATES_SOFT:
223 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
224 value = (ALdouble)AL_TRUE;
225 break;
227 case AL_GAIN_LIMIT_SOFT:
228 value = (ALdouble)GAIN_MIX_MAX/context->GainBoost;
229 break;
231 case AL_NUM_RESAMPLERS_SOFT:
232 value = (ALdouble)(ResamplerMax + 1);
233 break;
235 case AL_DEFAULT_RESAMPLER_SOFT:
236 value = (ALdouble)ResamplerDefault;
237 break;
239 default:
240 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
243 done:
244 ALCcontext_DecRef(context);
246 return value;
249 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
251 ALCcontext *context;
252 ALfloat value = 0.0f;
254 context = GetContextRef();
255 if(!context) return 0.0f;
257 switch(pname)
259 case AL_DOPPLER_FACTOR:
260 value = context->DopplerFactor;
261 break;
263 case AL_DOPPLER_VELOCITY:
264 value = context->DopplerVelocity;
265 break;
267 case AL_DISTANCE_MODEL:
268 value = (ALfloat)context->DistanceModel;
269 break;
271 case AL_SPEED_OF_SOUND:
272 value = context->SpeedOfSound;
273 break;
275 case AL_DEFERRED_UPDATES_SOFT:
276 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
277 value = (ALfloat)AL_TRUE;
278 break;
280 case AL_GAIN_LIMIT_SOFT:
281 value = GAIN_MIX_MAX/context->GainBoost;
282 break;
284 case AL_NUM_RESAMPLERS_SOFT:
285 value = (ALfloat)(ResamplerMax + 1);
286 break;
288 case AL_DEFAULT_RESAMPLER_SOFT:
289 value = (ALfloat)ResamplerDefault;
290 break;
292 default:
293 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
296 done:
297 ALCcontext_DecRef(context);
299 return value;
302 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
304 ALCcontext *context;
305 ALint value = 0;
307 context = GetContextRef();
308 if(!context) return 0;
310 switch(pname)
312 case AL_DOPPLER_FACTOR:
313 value = (ALint)context->DopplerFactor;
314 break;
316 case AL_DOPPLER_VELOCITY:
317 value = (ALint)context->DopplerVelocity;
318 break;
320 case AL_DISTANCE_MODEL:
321 value = (ALint)context->DistanceModel;
322 break;
324 case AL_SPEED_OF_SOUND:
325 value = (ALint)context->SpeedOfSound;
326 break;
328 case AL_DEFERRED_UPDATES_SOFT:
329 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
330 value = (ALint)AL_TRUE;
331 break;
333 case AL_GAIN_LIMIT_SOFT:
334 value = (ALint)(GAIN_MIX_MAX/context->GainBoost);
335 break;
337 case AL_NUM_RESAMPLERS_SOFT:
338 value = ResamplerMax + 1;
339 break;
341 case AL_DEFAULT_RESAMPLER_SOFT:
342 value = ResamplerDefault;
343 break;
345 default:
346 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
349 done:
350 ALCcontext_DecRef(context);
352 return value;
355 AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
357 ALCcontext *context;
358 ALint64SOFT value = 0;
360 context = GetContextRef();
361 if(!context) return 0;
363 switch(pname)
365 case AL_DOPPLER_FACTOR:
366 value = (ALint64SOFT)context->DopplerFactor;
367 break;
369 case AL_DOPPLER_VELOCITY:
370 value = (ALint64SOFT)context->DopplerVelocity;
371 break;
373 case AL_DISTANCE_MODEL:
374 value = (ALint64SOFT)context->DistanceModel;
375 break;
377 case AL_SPEED_OF_SOUND:
378 value = (ALint64SOFT)context->SpeedOfSound;
379 break;
381 case AL_DEFERRED_UPDATES_SOFT:
382 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
383 value = (ALint64SOFT)AL_TRUE;
384 break;
386 case AL_GAIN_LIMIT_SOFT:
387 value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
388 break;
390 case AL_NUM_RESAMPLERS_SOFT:
391 value = (ALint64SOFT)(ResamplerMax + 1);
392 break;
394 case AL_DEFAULT_RESAMPLER_SOFT:
395 value = (ALint64SOFT)ResamplerDefault;
396 break;
398 default:
399 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
402 done:
403 ALCcontext_DecRef(context);
405 return value;
408 AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
410 ALCcontext *context;
412 if(values)
414 switch(pname)
416 case AL_DOPPLER_FACTOR:
417 case AL_DOPPLER_VELOCITY:
418 case AL_DISTANCE_MODEL:
419 case AL_SPEED_OF_SOUND:
420 case AL_DEFERRED_UPDATES_SOFT:
421 case AL_GAIN_LIMIT_SOFT:
422 case AL_NUM_RESAMPLERS_SOFT:
423 case AL_DEFAULT_RESAMPLER_SOFT:
424 values[0] = alGetBoolean(pname);
425 return;
429 context = GetContextRef();
430 if(!context) return;
432 if(!(values))
433 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
434 switch(pname)
436 default:
437 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
440 done:
441 ALCcontext_DecRef(context);
444 AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
446 ALCcontext *context;
448 if(values)
450 switch(pname)
452 case AL_DOPPLER_FACTOR:
453 case AL_DOPPLER_VELOCITY:
454 case AL_DISTANCE_MODEL:
455 case AL_SPEED_OF_SOUND:
456 case AL_DEFERRED_UPDATES_SOFT:
457 case AL_GAIN_LIMIT_SOFT:
458 case AL_NUM_RESAMPLERS_SOFT:
459 case AL_DEFAULT_RESAMPLER_SOFT:
460 values[0] = alGetDouble(pname);
461 return;
465 context = GetContextRef();
466 if(!context) return;
468 if(!(values))
469 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
470 switch(pname)
472 default:
473 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
476 done:
477 ALCcontext_DecRef(context);
480 AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
482 ALCcontext *context;
484 if(values)
486 switch(pname)
488 case AL_DOPPLER_FACTOR:
489 case AL_DOPPLER_VELOCITY:
490 case AL_DISTANCE_MODEL:
491 case AL_SPEED_OF_SOUND:
492 case AL_DEFERRED_UPDATES_SOFT:
493 case AL_GAIN_LIMIT_SOFT:
494 case AL_NUM_RESAMPLERS_SOFT:
495 case AL_DEFAULT_RESAMPLER_SOFT:
496 values[0] = alGetFloat(pname);
497 return;
501 context = GetContextRef();
502 if(!context) return;
504 if(!(values))
505 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
506 switch(pname)
508 default:
509 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
512 done:
513 ALCcontext_DecRef(context);
516 AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
518 ALCcontext *context;
520 if(values)
522 switch(pname)
524 case AL_DOPPLER_FACTOR:
525 case AL_DOPPLER_VELOCITY:
526 case AL_DISTANCE_MODEL:
527 case AL_SPEED_OF_SOUND:
528 case AL_DEFERRED_UPDATES_SOFT:
529 case AL_GAIN_LIMIT_SOFT:
530 case AL_NUM_RESAMPLERS_SOFT:
531 case AL_DEFAULT_RESAMPLER_SOFT:
532 values[0] = alGetInteger(pname);
533 return;
537 context = GetContextRef();
538 if(!context) return;
540 switch(pname)
542 default:
543 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
546 done:
547 ALCcontext_DecRef(context);
550 AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
552 ALCcontext *context;
554 if(values)
556 switch(pname)
558 case AL_DOPPLER_FACTOR:
559 case AL_DOPPLER_VELOCITY:
560 case AL_DISTANCE_MODEL:
561 case AL_SPEED_OF_SOUND:
562 case AL_DEFERRED_UPDATES_SOFT:
563 case AL_GAIN_LIMIT_SOFT:
564 case AL_NUM_RESAMPLERS_SOFT:
565 case AL_DEFAULT_RESAMPLER_SOFT:
566 values[0] = alGetInteger64SOFT(pname);
567 return;
571 context = GetContextRef();
572 if(!context) return;
574 switch(pname)
576 default:
577 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
580 done:
581 ALCcontext_DecRef(context);
584 AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
586 const ALchar *value = NULL;
587 ALCcontext *context;
589 context = GetContextRef();
590 if(!context) return NULL;
592 switch(pname)
594 case AL_VENDOR:
595 value = alVendor;
596 break;
598 case AL_VERSION:
599 value = alVersion;
600 break;
602 case AL_RENDERER:
603 value = alRenderer;
604 break;
606 case AL_EXTENSIONS:
607 value = context->ExtensionList;
608 break;
610 case AL_NO_ERROR:
611 value = alNoError;
612 break;
614 case AL_INVALID_NAME:
615 value = alErrInvalidName;
616 break;
618 case AL_INVALID_ENUM:
619 value = alErrInvalidEnum;
620 break;
622 case AL_INVALID_VALUE:
623 value = alErrInvalidValue;
624 break;
626 case AL_INVALID_OPERATION:
627 value = alErrInvalidOp;
628 break;
630 case AL_OUT_OF_MEMORY:
631 value = alErrOutOfMemory;
632 break;
634 default:
635 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
638 done:
639 ALCcontext_DecRef(context);
641 return value;
644 AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
646 ALCcontext *context;
648 context = GetContextRef();
649 if(!context) return;
651 if(!(value >= 0.0f && isfinite(value)))
652 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
654 WriteLock(&context->PropLock);
655 context->DopplerFactor = value;
656 DO_UPDATEPROPS();
657 WriteUnlock(&context->PropLock);
659 done:
660 ALCcontext_DecRef(context);
663 AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
665 ALCcontext *context;
667 context = GetContextRef();
668 if(!context) return;
670 if(!(value >= 0.0f && isfinite(value)))
671 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
673 WriteLock(&context->PropLock);
674 context->DopplerVelocity = value;
675 DO_UPDATEPROPS();
676 WriteUnlock(&context->PropLock);
678 done:
679 ALCcontext_DecRef(context);
682 AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
684 ALCcontext *context;
686 context = GetContextRef();
687 if(!context) return;
689 if(!(value > 0.0f && isfinite(value)))
690 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
692 WriteLock(&context->PropLock);
693 context->SpeedOfSound = value;
694 DO_UPDATEPROPS();
695 WriteUnlock(&context->PropLock);
697 done:
698 ALCcontext_DecRef(context);
701 AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
703 ALCcontext *context;
705 context = GetContextRef();
706 if(!context) return;
708 if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED ||
709 value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
710 value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
711 value == AL_NONE))
712 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
714 WriteLock(&context->PropLock);
715 context->DistanceModel = value;
716 if(!context->SourceDistanceModel)
717 DO_UPDATEPROPS();
718 WriteUnlock(&context->PropLock);
720 done:
721 ALCcontext_DecRef(context);
725 AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
727 ALCcontext *context;
729 context = GetContextRef();
730 if(!context) return;
732 ALCcontext_DeferUpdates(context);
734 ALCcontext_DecRef(context);
737 AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
739 ALCcontext *context;
741 context = GetContextRef();
742 if(!context) return;
744 ALCcontext_ProcessUpdates(context);
746 ALCcontext_DecRef(context);
750 AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
752 const char *ResamplerNames[] = {
753 alPointResampler, alLinearResampler,
754 alSinc4Resampler, alBSinc12Resampler,
755 alBSinc24Resampler,
757 const ALchar *value = NULL;
758 ALCcontext *context;
760 static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
762 context = GetContextRef();
763 if(!context) return NULL;
765 switch(pname)
767 case AL_RESAMPLER_NAME_SOFT:
768 if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
769 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
770 value = ResamplerNames[index];
771 break;
773 default:
774 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
777 done:
778 ALCcontext_DecRef(context);
780 return value;
784 void UpdateContextProps(ALCcontext *context)
786 struct ALcontextProps *props;
788 /* Get an unused proprty container, or allocate a new one as needed. */
789 props = ATOMIC_LOAD(&context->FreeList, almemory_order_acquire);
790 if(!props)
791 props = al_calloc(16, sizeof(*props));
792 else
794 struct ALcontextProps *next;
795 do {
796 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
797 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeList, &props, next,
798 almemory_order_seq_cst, almemory_order_acquire) == 0);
801 /* Copy in current property values. */
802 props->MetersPerUnit = context->MetersPerUnit;
804 props->DopplerFactor = context->DopplerFactor;
805 props->DopplerVelocity = context->DopplerVelocity;
806 props->SpeedOfSound = context->SpeedOfSound;
808 props->SourceDistanceModel = context->SourceDistanceModel;
809 props->DistanceModel = context->DistanceModel;
811 /* Set the new container for updating internal parameters. */
812 props = ATOMIC_EXCHANGE_PTR(&context->Update, props, almemory_order_acq_rel);
813 if(props)
815 /* If there was an unused update container, put it back in the
816 * freelist.
818 ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeList, props);