Release 1.24.0
[openal-soft.git] / al / state.cpp
blob9bfaa8b3a722e563507d6a51876ebebdd903768c
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 <array>
26 #include <atomic>
27 #include <cmath>
28 #include <deque>
29 #include <mutex>
30 #include <optional>
31 #include <stdexcept>
32 #include <string>
33 #include <utility>
35 #include "AL/al.h"
36 #include "AL/alc.h"
37 #include "AL/alext.h"
39 #include "al/debug.h"
40 #include "al/listener.h"
41 #include "alc/alu.h"
42 #include "alc/context.h"
43 #include "alc/device.h"
44 #include "alc/inprogext.h"
45 #include "alnumeric.h"
46 #include "atomic.h"
47 #include "core/context.h"
48 #include "core/logging.h"
49 #include "core/mixer/defs.h"
50 #include "core/voice.h"
51 #include "direct_defs.h"
52 #include "intrusive_ptr.h"
53 #include "opthelpers.h"
54 #include "strutils.h"
56 #if ALSOFT_EAX
57 #include "eax/globals.h"
58 #include "eax/x_ram.h"
59 #endif // ALSOFT_EAX
62 namespace {
64 using ALvoidptr = ALvoid*;
66 [[nodiscard]] constexpr auto GetVendorString() noexcept { return "OpenAL Community"; }
67 [[nodiscard]] constexpr auto GetVersionString() noexcept { return "1.1 ALSOFT " ALSOFT_VERSION; }
68 [[nodiscard]] constexpr auto GetRendererString() noexcept { return "OpenAL Soft"; }
70 /* Error Messages */
71 [[nodiscard]] constexpr auto GetNoErrorString() noexcept { return "No Error"; }
72 [[nodiscard]] constexpr auto GetInvalidNameString() noexcept { return "Invalid Name"; }
73 [[nodiscard]] constexpr auto GetInvalidEnumString() noexcept { return "Invalid Enum"; }
74 [[nodiscard]] constexpr auto GetInvalidValueString() noexcept { return "Invalid Value"; }
75 [[nodiscard]] constexpr auto GetInvalidOperationString() noexcept { return "Invalid Operation"; }
76 [[nodiscard]] constexpr auto GetOutOfMemoryString() noexcept { return "Out of Memory"; }
77 [[nodiscard]] constexpr auto GetStackOverflowString() noexcept { return "Stack Overflow"; }
78 [[nodiscard]] constexpr auto GetStackUnderflowString() noexcept { return "Stack Underflow"; }
80 /* Resampler strings */
81 template<Resampler rtype> struct ResamplerName { };
82 template<> struct ResamplerName<Resampler::Point>
83 { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
84 template<> struct ResamplerName<Resampler::Linear>
85 { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
86 template<> struct ResamplerName<Resampler::Spline>
87 { static constexpr const ALchar *Get() noexcept { return "Cubic Spline"; } };
88 template<> struct ResamplerName<Resampler::Gaussian>
89 { static constexpr const ALchar *Get() noexcept { return "4-point Gaussian"; } };
90 template<> struct ResamplerName<Resampler::FastBSinc12>
91 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
92 template<> struct ResamplerName<Resampler::BSinc12>
93 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
94 template<> struct ResamplerName<Resampler::FastBSinc24>
95 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
96 template<> struct ResamplerName<Resampler::BSinc24>
97 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
99 const ALchar *GetResamplerName(const Resampler rtype)
101 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
102 switch(rtype)
104 HANDLE_RESAMPLER(Resampler::Point);
105 HANDLE_RESAMPLER(Resampler::Linear);
106 HANDLE_RESAMPLER(Resampler::Spline);
107 HANDLE_RESAMPLER(Resampler::Gaussian);
108 HANDLE_RESAMPLER(Resampler::FastBSinc12);
109 HANDLE_RESAMPLER(Resampler::BSinc12);
110 HANDLE_RESAMPLER(Resampler::FastBSinc24);
111 HANDLE_RESAMPLER(Resampler::BSinc24);
113 #undef HANDLE_RESAMPLER
114 /* Should never get here. */
115 throw std::runtime_error{"Unexpected resampler index"};
118 constexpr auto DistanceModelFromALenum(ALenum model) noexcept -> std::optional<DistanceModel>
120 switch(model)
122 case AL_NONE: return DistanceModel::Disable;
123 case AL_INVERSE_DISTANCE: return DistanceModel::Inverse;
124 case AL_INVERSE_DISTANCE_CLAMPED: return DistanceModel::InverseClamped;
125 case AL_LINEAR_DISTANCE: return DistanceModel::Linear;
126 case AL_LINEAR_DISTANCE_CLAMPED: return DistanceModel::LinearClamped;
127 case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent;
128 case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped;
130 return std::nullopt;
132 constexpr auto ALenumFromDistanceModel(DistanceModel model) -> ALenum
134 switch(model)
136 case DistanceModel::Disable: return AL_NONE;
137 case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
138 case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
139 case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
140 case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
141 case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
142 case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
144 throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
147 enum PropertyValue : ALenum {
148 DopplerFactorProp = AL_DOPPLER_FACTOR,
149 DopplerVelocityProp = AL_DOPPLER_VELOCITY,
150 DistanceModelProp = AL_DISTANCE_MODEL,
151 SpeedOfSoundProp = AL_SPEED_OF_SOUND,
152 DeferredUpdatesProp = AL_DEFERRED_UPDATES_SOFT,
153 GainLimitProp = AL_GAIN_LIMIT_SOFT,
154 NumResamplersProp = AL_NUM_RESAMPLERS_SOFT,
155 DefaultResamplerProp = AL_DEFAULT_RESAMPLER_SOFT,
156 DebugLoggedMessagesProp = AL_DEBUG_LOGGED_MESSAGES_EXT,
157 DebugNextLoggedMessageLengthProp = AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT,
158 MaxDebugMessageLengthProp = AL_MAX_DEBUG_MESSAGE_LENGTH_EXT,
159 MaxDebugLoggedMessagesProp = AL_MAX_DEBUG_LOGGED_MESSAGES_EXT,
160 MaxDebugGroupDepthProp = AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT,
161 MaxLabelLengthProp = AL_MAX_LABEL_LENGTH_EXT,
162 ContextFlagsProp = AL_CONTEXT_FLAGS_EXT,
163 #if ALSOFT_EAX
164 EaxRamSizeProp = AL_EAX_RAM_SIZE,
165 EaxRamFreeProp = AL_EAX_RAM_FREE,
166 #endif
169 template<typename T>
170 struct PropertyCastType {
171 template<typename U>
172 constexpr auto operator()(U&& value) const noexcept
173 { return static_cast<T>(std::forward<U>(value)); }
175 /* Special-case ALboolean to be an actual bool instead of a char type. */
176 template<>
177 struct PropertyCastType<ALboolean> {
178 template<typename U>
179 constexpr ALboolean operator()(U&& value) const noexcept
180 { return static_cast<bool>(std::forward<U>(value)) ? AL_TRUE : AL_FALSE; }
184 template<typename T>
185 void GetValue(ALCcontext *context, ALenum pname, T *values)
187 auto cast_value = PropertyCastType<T>{};
189 switch(static_cast<PropertyValue>(pname))
191 case AL_DOPPLER_FACTOR:
192 *values = cast_value(context->mDopplerFactor);
193 return;
195 case AL_DOPPLER_VELOCITY:
196 if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY
197 context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0,
198 DebugSeverity::Medium,
199 "AL_DOPPLER_VELOCITY is deprecated in AL 1.1, use AL_SPEED_OF_SOUND; "
200 "AL_DOPPLER_VELOCITY -> AL_SPEED_OF_SOUND / 343.3f");
201 *values = cast_value(context->mDopplerVelocity);
202 return;
204 case AL_SPEED_OF_SOUND:
205 *values = cast_value(context->mSpeedOfSound);
206 return;
208 case AL_GAIN_LIMIT_SOFT:
209 *values = cast_value(GainMixMax / context->mGainBoost);
210 return;
212 case AL_DEFERRED_UPDATES_SOFT:
213 *values = cast_value(context->mDeferUpdates ? AL_TRUE : AL_FALSE);
214 return;
216 case AL_DISTANCE_MODEL:
217 *values = cast_value(ALenumFromDistanceModel(context->mDistanceModel));
218 return;
220 case AL_NUM_RESAMPLERS_SOFT:
221 *values = cast_value(al::to_underlying(Resampler::Max) + 1);
222 return;
224 case AL_DEFAULT_RESAMPLER_SOFT:
225 *values = cast_value(al::to_underlying(ResamplerDefault));
226 return;
228 case AL_DEBUG_LOGGED_MESSAGES_EXT:
230 std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
231 *values = cast_value(context->mDebugLog.size());
232 return;
235 case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT:
237 std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
238 *values = cast_value(context->mDebugLog.empty() ? 0_uz
239 : (context->mDebugLog.front().mMessage.size()+1));
240 return;
243 case AL_MAX_DEBUG_MESSAGE_LENGTH_EXT:
244 *values = cast_value(MaxDebugMessageLength);
245 return;
247 case AL_MAX_DEBUG_LOGGED_MESSAGES_EXT:
248 *values = cast_value(MaxDebugLoggedMessages);
249 return;
251 case AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT:
252 *values = cast_value(MaxDebugGroupDepth);
253 return;
255 case AL_MAX_LABEL_LENGTH_EXT:
256 *values = cast_value(MaxObjectLabelLength);
257 return;
259 case AL_CONTEXT_FLAGS_EXT:
260 *values = cast_value(context->mContextFlags.to_ulong());
261 return;
263 #if ALSOFT_EAX
264 #define EAX_ERROR "[alGetInteger] EAX not enabled"
266 case AL_EAX_RAM_SIZE:
267 if(eax_g_is_enabled)
269 *values = cast_value(eax_x_ram_max_size);
270 return;
272 ERR(EAX_ERROR "\n");
273 break;
275 case AL_EAX_RAM_FREE:
276 if(eax_g_is_enabled)
278 auto device = context->mALDevice.get();
279 std::lock_guard<std::mutex> device_lock{device->BufferLock};
280 *values = cast_value(device->eax_x_ram_free_size);
281 return;
283 ERR(EAX_ERROR "\n");
284 break;
286 #undef EAX_ERROR
287 #endif // ALSOFT_EAX
289 context->setError(AL_INVALID_ENUM, "Invalid context property 0x%04x", pname);
293 inline void UpdateProps(ALCcontext *context)
295 if(!context->mDeferUpdates)
296 UpdateContextProps(context);
297 else
298 context->mPropsDirty = true;
301 } // namespace
303 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
304 * alcFunctions list.
306 AL_API auto AL_APIENTRY alsoft_get_version() noexcept -> const ALchar*
308 static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
309 if(spoof) return spoof->c_str();
310 return ALSOFT_VERSION;
314 AL_API DECL_FUNC1(void, alEnable, ALenum,capability)
315 FORCE_ALIGN void AL_APIENTRY alEnableDirect(ALCcontext *context, ALenum capability) noexcept
317 switch(capability)
319 case AL_SOURCE_DISTANCE_MODEL:
321 std::lock_guard<std::mutex> proplock{context->mPropLock};
322 context->mSourceDistanceModel = true;
323 UpdateProps(context);
325 return;
327 case AL_DEBUG_OUTPUT_EXT:
328 context->mDebugEnabled.store(true);
329 return;
331 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
332 context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
333 return;
335 context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
338 AL_API DECL_FUNC1(void, alDisable, ALenum,capability)
339 FORCE_ALIGN void AL_APIENTRY alDisableDirect(ALCcontext *context, ALenum capability) noexcept
341 switch(capability)
343 case AL_SOURCE_DISTANCE_MODEL:
345 std::lock_guard<std::mutex> proplock{context->mPropLock};
346 context->mSourceDistanceModel = false;
347 UpdateProps(context);
349 return;
351 case AL_DEBUG_OUTPUT_EXT:
352 context->mDebugEnabled.store(false);
353 return;
355 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
356 context->mStopVoicesOnDisconnect.store(false);
357 return;
359 context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
362 AL_API DECL_FUNC1(ALboolean, alIsEnabled, ALenum,capability)
363 FORCE_ALIGN ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum capability) noexcept
365 std::lock_guard<std::mutex> proplock{context->mPropLock};
366 switch(capability)
368 case AL_SOURCE_DISTANCE_MODEL: return context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
369 case AL_DEBUG_OUTPUT_EXT: return context->mDebugEnabled ? AL_TRUE : AL_FALSE;
370 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
371 return context->mStopVoicesOnDisconnect.load() ? AL_TRUE : AL_FALSE;
373 context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
374 return AL_FALSE;
377 #define DECL_GETFUNC(R, Name, Ext) \
378 auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \
380 auto value = R{}; \
381 auto context = GetContextRef(); \
382 if(!context) UNLIKELY return value; \
383 Name##vDirect##Ext(GetContextRef().get(), pname, &value); \
384 return value; \
386 FORCE_ALIGN auto AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept -> R \
388 auto value = R{}; \
389 Name##vDirect##Ext(context, pname, &value); \
390 return value; \
393 AL_API DECL_GETFUNC(ALboolean, alGetBoolean,)
394 AL_API DECL_GETFUNC(ALdouble, alGetDouble,)
395 AL_API DECL_GETFUNC(ALfloat, alGetFloat,)
396 AL_API DECL_GETFUNC(ALint, alGetInteger,)
398 DECL_GETFUNC(ALvoidptr, alGetPointer,EXT)
399 AL_API DECL_GETFUNC(ALint64SOFT, alGetInteger64,SOFT)
400 AL_API DECL_GETFUNC(ALvoidptr, alGetPointer,SOFT)
402 #undef DECL_GETFUNC
405 AL_API DECL_FUNC2(void, alGetBooleanv, ALenum,pname, ALboolean*,values)
406 FORCE_ALIGN void AL_APIENTRY alGetBooleanvDirect(ALCcontext *context, ALenum pname, ALboolean *values) noexcept
408 if(!values) UNLIKELY
409 return context->setError(AL_INVALID_VALUE, "NULL pointer");
410 GetValue(context, pname, values);
413 AL_API DECL_FUNC2(void, alGetDoublev, ALenum,pname, ALdouble*,values)
414 FORCE_ALIGN void AL_APIENTRY alGetDoublevDirect(ALCcontext *context, ALenum pname, ALdouble *values) noexcept
416 if(!values) UNLIKELY
417 return context->setError(AL_INVALID_VALUE, "NULL pointer");
418 GetValue(context, pname, values);
421 AL_API DECL_FUNC2(void, alGetFloatv, ALenum,pname, ALfloat*,values)
422 FORCE_ALIGN void AL_APIENTRY alGetFloatvDirect(ALCcontext *context, ALenum pname, ALfloat *values) noexcept
424 if(!values) UNLIKELY
425 return context->setError(AL_INVALID_VALUE, "NULL pointer");
426 GetValue(context, pname, values);
429 AL_API DECL_FUNC2(void, alGetIntegerv, ALenum,pname, ALint*,values)
430 FORCE_ALIGN void AL_APIENTRY alGetIntegervDirect(ALCcontext *context, ALenum pname, ALint *values) noexcept
432 if(!values) UNLIKELY
433 return context->setError(AL_INVALID_VALUE, "NULL pointer");
434 GetValue(context, pname, values);
437 AL_API DECL_FUNCEXT2(void, alGetInteger64v,SOFT, ALenum,pname, ALint64SOFT*,values)
438 FORCE_ALIGN void AL_APIENTRY alGetInteger64vDirectSOFT(ALCcontext *context, ALenum pname, ALint64SOFT *values) noexcept
440 if(!values) UNLIKELY
441 return context->setError(AL_INVALID_VALUE, "NULL pointer");
442 GetValue(context, pname, values);
445 AL_API DECL_FUNCEXT2(void, alGetPointerv,SOFT, ALenum,pname, ALvoid**,values)
446 FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum pname, ALvoid **values) noexcept
447 { return alGetPointervDirectEXT(context, pname, values); }
449 FORCE_ALIGN DECL_FUNCEXT2(void, alGetPointerv,EXT, ALenum,pname, ALvoid**,values)
450 FORCE_ALIGN void AL_APIENTRY alGetPointervDirectEXT(ALCcontext *context, ALenum pname, ALvoid **values) noexcept
452 if(!values) UNLIKELY
453 return context->setError(AL_INVALID_VALUE, "NULL pointer");
455 switch(pname)
457 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
458 *values = reinterpret_cast<void*>(context->mEventCb);
459 return;
461 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
462 *values = context->mEventParam;
463 return;
465 case AL_DEBUG_CALLBACK_FUNCTION_EXT:
466 *values = reinterpret_cast<void*>(context->mDebugCb);
467 return;
469 case AL_DEBUG_CALLBACK_USER_PARAM_EXT:
470 *values = context->mDebugParam;
471 return;
473 context->setError(AL_INVALID_ENUM, "Invalid context pointer property 0x%04x", pname);
476 AL_API DECL_FUNC1(const ALchar*, alGetString, ALenum,pname)
477 FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringDirect(ALCcontext *context, ALenum pname) noexcept
479 switch(pname)
481 case AL_VENDOR:
482 if(auto device = context->mALDevice.get(); !device->mVendorOverride.empty())
483 return device->mVendorOverride.c_str();
484 return GetVendorString();
485 case AL_VERSION:
486 if(auto device = context->mALDevice.get(); !device->mVersionOverride.empty())
487 return device->mVersionOverride.c_str();
488 return GetVersionString();
489 case AL_RENDERER:
490 if(auto device = context->mALDevice.get(); !device->mRendererOverride.empty())
491 return device->mRendererOverride.c_str();
492 return GetRendererString();
493 case AL_EXTENSIONS: return context->mExtensionsString.c_str();
494 case AL_NO_ERROR: return GetNoErrorString();
495 case AL_INVALID_NAME: return GetInvalidNameString();
496 case AL_INVALID_ENUM: return GetInvalidEnumString();
497 case AL_INVALID_VALUE: return GetInvalidValueString();
498 case AL_INVALID_OPERATION: return GetInvalidOperationString();
499 case AL_OUT_OF_MEMORY: return GetOutOfMemoryString();
500 case AL_STACK_OVERFLOW_EXT: return GetStackOverflowString();
501 case AL_STACK_UNDERFLOW_EXT: return GetStackUnderflowString();
503 context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
504 return nullptr;
507 AL_API DECL_FUNC1(void, alDopplerFactor, ALfloat,value)
508 FORCE_ALIGN void AL_APIENTRY alDopplerFactorDirect(ALCcontext *context, ALfloat value) noexcept
510 if(!(value >= 0.0f && std::isfinite(value)))
511 context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
512 else
514 std::lock_guard<std::mutex> proplock{context->mPropLock};
515 context->mDopplerFactor = value;
516 UpdateProps(context);
520 AL_API DECL_FUNC1(void, alSpeedOfSound, ALfloat,value)
521 FORCE_ALIGN void AL_APIENTRY alSpeedOfSoundDirect(ALCcontext *context, ALfloat value) noexcept
523 if(!(value > 0.0f && std::isfinite(value)))
524 context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
525 else
527 std::lock_guard<std::mutex> proplock{context->mPropLock};
528 context->mSpeedOfSound = value;
529 UpdateProps(context);
533 AL_API DECL_FUNC1(void, alDistanceModel, ALenum,value)
534 FORCE_ALIGN void AL_APIENTRY alDistanceModelDirect(ALCcontext *context, ALenum value) noexcept
536 if(auto model = DistanceModelFromALenum(value))
538 std::lock_guard<std::mutex> proplock{context->mPropLock};
539 context->mDistanceModel = *model;
540 if(!context->mSourceDistanceModel)
541 UpdateProps(context);
543 else
544 context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
548 AL_API DECL_FUNCEXT(void, alDeferUpdates,SOFT)
549 FORCE_ALIGN void AL_APIENTRY alDeferUpdatesDirectSOFT(ALCcontext *context) noexcept
551 std::lock_guard<std::mutex> proplock{context->mPropLock};
552 context->deferUpdates();
555 AL_API DECL_FUNCEXT(void, alProcessUpdates,SOFT)
556 FORCE_ALIGN void AL_APIENTRY alProcessUpdatesDirectSOFT(ALCcontext *context) noexcept
558 std::lock_guard<std::mutex> proplock{context->mPropLock};
559 context->processUpdates();
563 AL_API DECL_FUNCEXT2(const ALchar*, alGetStringi,SOFT, ALenum,pname, ALsizei,index)
564 FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringiDirectSOFT(ALCcontext *context, ALenum pname, ALsizei index) noexcept
566 switch(pname)
568 case AL_RESAMPLER_NAME_SOFT:
569 if(index >= 0 && index <= static_cast<ALint>(Resampler::Max))
570 return GetResamplerName(static_cast<Resampler>(index));
571 context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
572 return nullptr;
574 context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
575 return nullptr;
579 AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept
581 ContextRef context{GetContextRef()};
582 if(!context) UNLIKELY return;
584 if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY
585 context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 1,
586 DebugSeverity::Medium,
587 "alDopplerVelocity is deprecated in AL 1.1, use alSpeedOfSound; "
588 "alDopplerVelocity(x) -> alSpeedOfSound(343.3f * x)");
590 if(!(value >= 0.0f && std::isfinite(value)))
591 context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
592 else
594 std::lock_guard<std::mutex> proplock{context->mPropLock};
595 context->mDopplerVelocity = value;
596 UpdateProps(context.get());
601 void UpdateContextProps(ALCcontext *context)
603 /* Get an unused property container, or allocate a new one as needed. */
604 ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
605 if(!props)
607 context->allocContextProps();
608 props = context->mFreeContextProps.load(std::memory_order_acquire);
610 ContextProps *next;
611 do {
612 next = props->next.load(std::memory_order_relaxed);
613 } while(context->mFreeContextProps.compare_exchange_weak(props, next,
614 std::memory_order_acq_rel, std::memory_order_acquire) == false);
616 /* Copy in current property values. */
617 const auto &listener = context->mListener;
618 props->Position = listener.Position;
619 props->Velocity = listener.Velocity;
620 props->OrientAt = listener.OrientAt;
621 props->OrientUp = listener.OrientUp;
622 props->Gain = listener.Gain;
623 props->MetersPerUnit = listener.mMetersPerUnit;
625 props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
626 props->DopplerFactor = context->mDopplerFactor;
627 props->DopplerVelocity = context->mDopplerVelocity;
628 props->SpeedOfSound = context->mSpeedOfSound;
629 #if ALSOFT_EAX
630 props->DistanceFactor = context->eaxGetDistanceFactor();
631 #endif
633 props->SourceDistanceModel = context->mSourceDistanceModel;
634 props->mDistanceModel = context->mDistanceModel;
636 /* Set the new container for updating internal parameters. */
637 props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
638 if(props)
640 /* If there was an unused update container, put it back in the
641 * freelist.
643 AtomicReplaceHead(context->mFreeContextProps, props);