Allow using a negative offset with callback buffers
[openal-soft.git] / al / state.cpp
blob86d81b130a37308bcab85490f2d4c36cd0144447
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 <atomic>
26 #include <cmath>
27 #include <mutex>
28 #include <stdexcept>
29 #include <string>
31 #include "AL/al.h"
32 #include "AL/alc.h"
33 #include "AL/alext.h"
35 #include "alc/alu.h"
36 #include "alc/context.h"
37 #include "alc/inprogext.h"
38 #include "alnumeric.h"
39 #include "aloptional.h"
40 #include "atomic.h"
41 #include "core/context.h"
42 #include "core/except.h"
43 #include "core/mixer/defs.h"
44 #include "core/voice.h"
45 #include "intrusive_ptr.h"
46 #include "opthelpers.h"
47 #include "strutils.h"
49 #ifdef ALSOFT_EAX
50 #include "alc/device.h"
52 #include "eax/globals.h"
53 #include "eax/x_ram.h"
54 #endif // ALSOFT_EAX
57 namespace {
59 constexpr ALchar alVendor[] = "OpenAL Community";
60 constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
61 constexpr ALchar alRenderer[] = "OpenAL Soft";
63 // Error Messages
64 constexpr ALchar alNoError[] = "No Error";
65 constexpr ALchar alErrInvalidName[] = "Invalid Name";
66 constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
67 constexpr ALchar alErrInvalidValue[] = "Invalid Value";
68 constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
69 constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
71 /* Resampler strings */
72 template<Resampler rtype> struct ResamplerName { };
73 template<> struct ResamplerName<Resampler::Point>
74 { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
75 template<> struct ResamplerName<Resampler::Linear>
76 { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
77 template<> struct ResamplerName<Resampler::Cubic>
78 { static constexpr const ALchar *Get() noexcept { return "Cubic"; } };
79 template<> struct ResamplerName<Resampler::FastBSinc12>
80 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
81 template<> struct ResamplerName<Resampler::BSinc12>
82 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
83 template<> struct ResamplerName<Resampler::FastBSinc24>
84 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
85 template<> struct ResamplerName<Resampler::BSinc24>
86 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
88 const ALchar *GetResamplerName(const Resampler rtype)
90 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
91 switch(rtype)
93 HANDLE_RESAMPLER(Resampler::Point);
94 HANDLE_RESAMPLER(Resampler::Linear);
95 HANDLE_RESAMPLER(Resampler::Cubic);
96 HANDLE_RESAMPLER(Resampler::FastBSinc12);
97 HANDLE_RESAMPLER(Resampler::BSinc12);
98 HANDLE_RESAMPLER(Resampler::FastBSinc24);
99 HANDLE_RESAMPLER(Resampler::BSinc24);
101 #undef HANDLE_RESAMPLER
102 /* Should never get here. */
103 throw std::runtime_error{"Unexpected resampler index"};
106 al::optional<DistanceModel> DistanceModelFromALenum(ALenum model)
108 switch(model)
110 case AL_NONE: return DistanceModel::Disable;
111 case AL_INVERSE_DISTANCE: return DistanceModel::Inverse;
112 case AL_INVERSE_DISTANCE_CLAMPED: return DistanceModel::InverseClamped;
113 case AL_LINEAR_DISTANCE: return DistanceModel::Linear;
114 case AL_LINEAR_DISTANCE_CLAMPED: return DistanceModel::LinearClamped;
115 case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent;
116 case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped;
118 return al::nullopt;
120 ALenum ALenumFromDistanceModel(DistanceModel model)
122 switch(model)
124 case DistanceModel::Disable: return AL_NONE;
125 case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
126 case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
127 case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
128 case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
129 case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
130 case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
132 throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
135 } // namespace
137 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
138 * alcFunctions list.
140 AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
141 START_API_FUNC
143 static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
144 if(spoof) return spoof->c_str();
145 return ALSOFT_VERSION;
147 END_API_FUNC
149 #define DO_UPDATEPROPS() do { \
150 if(!context->mDeferUpdates) \
151 UpdateContextProps(context.get()); \
152 else \
153 context->mPropsDirty = true; \
154 } while(0)
157 AL_API void AL_APIENTRY alEnable(ALenum capability)
158 START_API_FUNC
160 ContextRef context{GetContextRef()};
161 if(!context) UNLIKELY return;
163 switch(capability)
165 case AL_SOURCE_DISTANCE_MODEL:
167 std::lock_guard<std::mutex> _{context->mPropLock};
168 context->mSourceDistanceModel = true;
169 DO_UPDATEPROPS();
171 break;
173 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
174 context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
175 break;
177 default:
178 context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
181 END_API_FUNC
183 AL_API void AL_APIENTRY alDisable(ALenum capability)
184 START_API_FUNC
186 ContextRef context{GetContextRef()};
187 if(!context) UNLIKELY return;
189 switch(capability)
191 case AL_SOURCE_DISTANCE_MODEL:
193 std::lock_guard<std::mutex> _{context->mPropLock};
194 context->mSourceDistanceModel = false;
195 DO_UPDATEPROPS();
197 break;
199 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
200 context->mStopVoicesOnDisconnect = false;
201 break;
203 default:
204 context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
207 END_API_FUNC
209 AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
210 START_API_FUNC
212 ContextRef context{GetContextRef()};
213 if(!context) UNLIKELY return AL_FALSE;
215 std::lock_guard<std::mutex> _{context->mPropLock};
216 ALboolean value{AL_FALSE};
217 switch(capability)
219 case AL_SOURCE_DISTANCE_MODEL:
220 value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
221 break;
223 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
224 value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE;
225 break;
227 default:
228 context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
231 return value;
233 END_API_FUNC
235 AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
236 START_API_FUNC
238 ContextRef context{GetContextRef()};
239 if(!context) UNLIKELY return AL_FALSE;
241 std::lock_guard<std::mutex> _{context->mPropLock};
242 ALboolean value{AL_FALSE};
243 switch(pname)
245 case AL_DOPPLER_FACTOR:
246 if(context->mDopplerFactor != 0.0f)
247 value = AL_TRUE;
248 break;
250 case AL_DOPPLER_VELOCITY:
251 if(context->mDopplerVelocity != 0.0f)
252 value = AL_TRUE;
253 break;
255 case AL_DISTANCE_MODEL:
256 if(context->mDistanceModel == DistanceModel::Default)
257 value = AL_TRUE;
258 break;
260 case AL_SPEED_OF_SOUND:
261 if(context->mSpeedOfSound != 0.0f)
262 value = AL_TRUE;
263 break;
265 case AL_DEFERRED_UPDATES_SOFT:
266 if(context->mDeferUpdates)
267 value = AL_TRUE;
268 break;
270 case AL_GAIN_LIMIT_SOFT:
271 if(GainMixMax/context->mGainBoost != 0.0f)
272 value = AL_TRUE;
273 break;
275 case AL_NUM_RESAMPLERS_SOFT:
276 /* Always non-0. */
277 value = AL_TRUE;
278 break;
280 case AL_DEFAULT_RESAMPLER_SOFT:
281 value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE;
282 break;
284 default:
285 context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
288 return value;
290 END_API_FUNC
292 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
293 START_API_FUNC
295 ContextRef context{GetContextRef()};
296 if(!context) UNLIKELY return 0.0;
298 std::lock_guard<std::mutex> _{context->mPropLock};
299 ALdouble value{0.0};
300 switch(pname)
302 case AL_DOPPLER_FACTOR:
303 value = context->mDopplerFactor;
304 break;
306 case AL_DOPPLER_VELOCITY:
307 value = context->mDopplerVelocity;
308 break;
310 case AL_DISTANCE_MODEL:
311 value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel));
312 break;
314 case AL_SPEED_OF_SOUND:
315 value = context->mSpeedOfSound;
316 break;
318 case AL_DEFERRED_UPDATES_SOFT:
319 if(context->mDeferUpdates)
320 value = static_cast<ALdouble>(AL_TRUE);
321 break;
323 case AL_GAIN_LIMIT_SOFT:
324 value = ALdouble{GainMixMax}/context->mGainBoost;
325 break;
327 case AL_NUM_RESAMPLERS_SOFT:
328 value = static_cast<ALdouble>(Resampler::Max) + 1.0;
329 break;
331 case AL_DEFAULT_RESAMPLER_SOFT:
332 value = static_cast<ALdouble>(ResamplerDefault);
333 break;
335 default:
336 context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
339 return value;
341 END_API_FUNC
343 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
344 START_API_FUNC
346 ContextRef context{GetContextRef()};
347 if(!context) UNLIKELY return 0.0f;
349 std::lock_guard<std::mutex> _{context->mPropLock};
350 ALfloat value{0.0f};
351 switch(pname)
353 case AL_DOPPLER_FACTOR:
354 value = context->mDopplerFactor;
355 break;
357 case AL_DOPPLER_VELOCITY:
358 value = context->mDopplerVelocity;
359 break;
361 case AL_DISTANCE_MODEL:
362 value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel));
363 break;
365 case AL_SPEED_OF_SOUND:
366 value = context->mSpeedOfSound;
367 break;
369 case AL_DEFERRED_UPDATES_SOFT:
370 if(context->mDeferUpdates)
371 value = static_cast<ALfloat>(AL_TRUE);
372 break;
374 case AL_GAIN_LIMIT_SOFT:
375 value = GainMixMax/context->mGainBoost;
376 break;
378 case AL_NUM_RESAMPLERS_SOFT:
379 value = static_cast<ALfloat>(Resampler::Max) + 1.0f;
380 break;
382 case AL_DEFAULT_RESAMPLER_SOFT:
383 value = static_cast<ALfloat>(ResamplerDefault);
384 break;
386 default:
387 context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
390 return value;
392 END_API_FUNC
394 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
395 START_API_FUNC
397 ContextRef context{GetContextRef()};
398 if(!context) UNLIKELY return 0;
400 std::lock_guard<std::mutex> _{context->mPropLock};
401 ALint value{0};
402 switch(pname)
404 case AL_DOPPLER_FACTOR:
405 value = static_cast<ALint>(context->mDopplerFactor);
406 break;
408 case AL_DOPPLER_VELOCITY:
409 value = static_cast<ALint>(context->mDopplerVelocity);
410 break;
412 case AL_DISTANCE_MODEL:
413 value = ALenumFromDistanceModel(context->mDistanceModel);
414 break;
416 case AL_SPEED_OF_SOUND:
417 value = static_cast<ALint>(context->mSpeedOfSound);
418 break;
420 case AL_DEFERRED_UPDATES_SOFT:
421 if(context->mDeferUpdates)
422 value = AL_TRUE;
423 break;
425 case AL_GAIN_LIMIT_SOFT:
426 value = static_cast<ALint>(GainMixMax/context->mGainBoost);
427 break;
429 case AL_NUM_RESAMPLERS_SOFT:
430 value = static_cast<int>(Resampler::Max) + 1;
431 break;
433 case AL_DEFAULT_RESAMPLER_SOFT:
434 value = static_cast<int>(ResamplerDefault);
435 break;
437 #ifdef ALSOFT_EAX
439 #define EAX_ERROR "[alGetInteger] EAX not enabled."
441 case AL_EAX_RAM_SIZE:
442 if (eax_g_is_enabled)
444 value = eax_x_ram_max_size;
446 else
448 context->setError(AL_INVALID_VALUE, EAX_ERROR);
451 break;
453 case AL_EAX_RAM_FREE:
454 if (eax_g_is_enabled)
456 auto device = context->mALDevice.get();
457 std::lock_guard<std::mutex> device_lock{device->BufferLock};
459 value = static_cast<ALint>(device->eax_x_ram_free_size);
461 else
463 context->setError(AL_INVALID_VALUE, EAX_ERROR);
466 break;
468 #undef EAX_ERROR
470 #endif // ALSOFT_EAX
472 default:
473 context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
476 return value;
478 END_API_FUNC
480 AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
481 START_API_FUNC
483 ContextRef context{GetContextRef()};
484 if(!context) UNLIKELY return 0_i64;
486 std::lock_guard<std::mutex> _{context->mPropLock};
487 ALint64SOFT value{0};
488 switch(pname)
490 case AL_DOPPLER_FACTOR:
491 value = static_cast<ALint64SOFT>(context->mDopplerFactor);
492 break;
494 case AL_DOPPLER_VELOCITY:
495 value = static_cast<ALint64SOFT>(context->mDopplerVelocity);
496 break;
498 case AL_DISTANCE_MODEL:
499 value = ALenumFromDistanceModel(context->mDistanceModel);
500 break;
502 case AL_SPEED_OF_SOUND:
503 value = static_cast<ALint64SOFT>(context->mSpeedOfSound);
504 break;
506 case AL_DEFERRED_UPDATES_SOFT:
507 if(context->mDeferUpdates)
508 value = AL_TRUE;
509 break;
511 case AL_GAIN_LIMIT_SOFT:
512 value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost);
513 break;
515 case AL_NUM_RESAMPLERS_SOFT:
516 value = static_cast<ALint64SOFT>(Resampler::Max) + 1;
517 break;
519 case AL_DEFAULT_RESAMPLER_SOFT:
520 value = static_cast<ALint64SOFT>(ResamplerDefault);
521 break;
523 default:
524 context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
527 return value;
529 END_API_FUNC
531 AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname)
532 START_API_FUNC
534 ContextRef context{GetContextRef()};
535 if(!context) UNLIKELY return nullptr;
537 std::lock_guard<std::mutex> _{context->mPropLock};
538 void *value{nullptr};
539 switch(pname)
541 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
542 value = reinterpret_cast<void*>(context->mEventCb);
543 break;
545 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
546 value = context->mEventParam;
547 break;
549 default:
550 context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
553 return value;
555 END_API_FUNC
557 AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
558 START_API_FUNC
560 if(values)
562 switch(pname)
564 case AL_DOPPLER_FACTOR:
565 case AL_DOPPLER_VELOCITY:
566 case AL_DISTANCE_MODEL:
567 case AL_SPEED_OF_SOUND:
568 case AL_DEFERRED_UPDATES_SOFT:
569 case AL_GAIN_LIMIT_SOFT:
570 case AL_NUM_RESAMPLERS_SOFT:
571 case AL_DEFAULT_RESAMPLER_SOFT:
572 values[0] = alGetBoolean(pname);
573 return;
577 ContextRef context{GetContextRef()};
578 if(!context) UNLIKELY return;
580 if(!values)
581 context->setError(AL_INVALID_VALUE, "NULL pointer");
582 else switch(pname)
584 default:
585 context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
588 END_API_FUNC
590 AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
591 START_API_FUNC
593 if(values)
595 switch(pname)
597 case AL_DOPPLER_FACTOR:
598 case AL_DOPPLER_VELOCITY:
599 case AL_DISTANCE_MODEL:
600 case AL_SPEED_OF_SOUND:
601 case AL_DEFERRED_UPDATES_SOFT:
602 case AL_GAIN_LIMIT_SOFT:
603 case AL_NUM_RESAMPLERS_SOFT:
604 case AL_DEFAULT_RESAMPLER_SOFT:
605 values[0] = alGetDouble(pname);
606 return;
610 ContextRef context{GetContextRef()};
611 if(!context) UNLIKELY return;
613 if(!values)
614 context->setError(AL_INVALID_VALUE, "NULL pointer");
615 else switch(pname)
617 default:
618 context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
621 END_API_FUNC
623 AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
624 START_API_FUNC
626 if(values)
628 switch(pname)
630 case AL_DOPPLER_FACTOR:
631 case AL_DOPPLER_VELOCITY:
632 case AL_DISTANCE_MODEL:
633 case AL_SPEED_OF_SOUND:
634 case AL_DEFERRED_UPDATES_SOFT:
635 case AL_GAIN_LIMIT_SOFT:
636 case AL_NUM_RESAMPLERS_SOFT:
637 case AL_DEFAULT_RESAMPLER_SOFT:
638 values[0] = alGetFloat(pname);
639 return;
643 ContextRef context{GetContextRef()};
644 if(!context) UNLIKELY return;
646 if(!values)
647 context->setError(AL_INVALID_VALUE, "NULL pointer");
648 else switch(pname)
650 default:
651 context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
654 END_API_FUNC
656 AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
657 START_API_FUNC
659 if(values)
661 switch(pname)
663 case AL_DOPPLER_FACTOR:
664 case AL_DOPPLER_VELOCITY:
665 case AL_DISTANCE_MODEL:
666 case AL_SPEED_OF_SOUND:
667 case AL_DEFERRED_UPDATES_SOFT:
668 case AL_GAIN_LIMIT_SOFT:
669 case AL_NUM_RESAMPLERS_SOFT:
670 case AL_DEFAULT_RESAMPLER_SOFT:
671 values[0] = alGetInteger(pname);
672 return;
676 ContextRef context{GetContextRef()};
677 if(!context) UNLIKELY return;
679 if(!values)
680 context->setError(AL_INVALID_VALUE, "NULL pointer");
681 else switch(pname)
683 default:
684 context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
687 END_API_FUNC
689 AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
690 START_API_FUNC
692 if(values)
694 switch(pname)
696 case AL_DOPPLER_FACTOR:
697 case AL_DOPPLER_VELOCITY:
698 case AL_DISTANCE_MODEL:
699 case AL_SPEED_OF_SOUND:
700 case AL_DEFERRED_UPDATES_SOFT:
701 case AL_GAIN_LIMIT_SOFT:
702 case AL_NUM_RESAMPLERS_SOFT:
703 case AL_DEFAULT_RESAMPLER_SOFT:
704 values[0] = alGetInteger64SOFT(pname);
705 return;
709 ContextRef context{GetContextRef()};
710 if(!context) UNLIKELY return;
712 if(!values)
713 context->setError(AL_INVALID_VALUE, "NULL pointer");
714 else switch(pname)
716 default:
717 context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
720 END_API_FUNC
722 AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values)
723 START_API_FUNC
725 if(values)
727 switch(pname)
729 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
730 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
731 values[0] = alGetPointerSOFT(pname);
732 return;
736 ContextRef context{GetContextRef()};
737 if(!context) UNLIKELY return;
739 if(!values)
740 context->setError(AL_INVALID_VALUE, "NULL pointer");
741 else switch(pname)
743 default:
744 context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
747 END_API_FUNC
749 AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
750 START_API_FUNC
752 ContextRef context{GetContextRef()};
753 if(!context) UNLIKELY return nullptr;
755 const ALchar *value{nullptr};
756 switch(pname)
758 case AL_VENDOR:
759 value = alVendor;
760 break;
762 case AL_VERSION:
763 value = alVersion;
764 break;
766 case AL_RENDERER:
767 value = alRenderer;
768 break;
770 case AL_EXTENSIONS:
771 value = context->mExtensionList;
772 break;
774 case AL_NO_ERROR:
775 value = alNoError;
776 break;
778 case AL_INVALID_NAME:
779 value = alErrInvalidName;
780 break;
782 case AL_INVALID_ENUM:
783 value = alErrInvalidEnum;
784 break;
786 case AL_INVALID_VALUE:
787 value = alErrInvalidValue;
788 break;
790 case AL_INVALID_OPERATION:
791 value = alErrInvalidOp;
792 break;
794 case AL_OUT_OF_MEMORY:
795 value = alErrOutOfMemory;
796 break;
798 default:
799 context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
801 return value;
803 END_API_FUNC
805 AL_API void AL_APIENTRY alDopplerFactor(ALfloat value)
806 START_API_FUNC
808 ContextRef context{GetContextRef()};
809 if(!context) UNLIKELY return;
811 if(!(value >= 0.0f && std::isfinite(value)))
812 context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
813 else
815 std::lock_guard<std::mutex> _{context->mPropLock};
816 context->mDopplerFactor = value;
817 DO_UPDATEPROPS();
820 END_API_FUNC
822 AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value)
823 START_API_FUNC
825 ContextRef context{GetContextRef()};
826 if(!context) UNLIKELY return;
828 if(!(value >= 0.0f && std::isfinite(value)))
829 context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
830 else
832 std::lock_guard<std::mutex> _{context->mPropLock};
833 context->mDopplerVelocity = value;
834 DO_UPDATEPROPS();
837 END_API_FUNC
839 AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value)
840 START_API_FUNC
842 ContextRef context{GetContextRef()};
843 if(!context) UNLIKELY return;
845 if(!(value > 0.0f && std::isfinite(value)))
846 context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
847 else
849 std::lock_guard<std::mutex> _{context->mPropLock};
850 context->mSpeedOfSound = value;
851 DO_UPDATEPROPS();
854 END_API_FUNC
856 AL_API void AL_APIENTRY alDistanceModel(ALenum value)
857 START_API_FUNC
859 ContextRef context{GetContextRef()};
860 if(!context) UNLIKELY return;
862 if(auto model = DistanceModelFromALenum(value))
864 std::lock_guard<std::mutex> _{context->mPropLock};
865 context->mDistanceModel = *model;
866 if(!context->mSourceDistanceModel)
867 DO_UPDATEPROPS();
869 else
870 context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
872 END_API_FUNC
875 AL_API void AL_APIENTRY alDeferUpdatesSOFT(void)
876 START_API_FUNC
878 ContextRef context{GetContextRef()};
879 if(!context) UNLIKELY return;
881 std::lock_guard<std::mutex> _{context->mPropLock};
882 context->deferUpdates();
884 END_API_FUNC
886 AL_API void AL_APIENTRY alProcessUpdatesSOFT(void)
887 START_API_FUNC
889 ContextRef context{GetContextRef()};
890 if(!context) UNLIKELY return;
892 std::lock_guard<std::mutex> _{context->mPropLock};
893 context->processUpdates();
895 END_API_FUNC
898 AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
899 START_API_FUNC
901 ContextRef context{GetContextRef()};
902 if(!context) UNLIKELY return nullptr;
904 const ALchar *value{nullptr};
905 switch(pname)
907 case AL_RESAMPLER_NAME_SOFT:
908 if(index < 0 || index > static_cast<ALint>(Resampler::Max))
909 context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
910 else
911 value = GetResamplerName(static_cast<Resampler>(index));
912 break;
914 default:
915 context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
917 return value;
919 END_API_FUNC
922 void UpdateContextProps(ALCcontext *context)
924 /* Get an unused proprty container, or allocate a new one as needed. */
925 ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
926 if(!props)
927 props = new ContextProps{};
928 else
930 ContextProps *next;
931 do {
932 next = props->next.load(std::memory_order_relaxed);
933 } while(context->mFreeContextProps.compare_exchange_weak(props, next,
934 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
937 /* Copy in current property values. */
938 ALlistener &listener = context->mListener;
939 props->Position = listener.Position;
940 props->Velocity = listener.Velocity;
941 props->OrientAt = listener.OrientAt;
942 props->OrientUp = listener.OrientUp;
943 props->Gain = listener.Gain;
944 props->MetersPerUnit = listener.mMetersPerUnit;
946 props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
947 props->DopplerFactor = context->mDopplerFactor;
948 props->DopplerVelocity = context->mDopplerVelocity;
949 props->SpeedOfSound = context->mSpeedOfSound;
951 props->SourceDistanceModel = context->mSourceDistanceModel;
952 props->mDistanceModel = context->mDistanceModel;
954 /* Set the new container for updating internal parameters. */
955 props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
956 if(props)
958 /* If there was an unused update container, put it back in the
959 * freelist.
961 AtomicReplaceHead(context->mFreeContextProps, props);