Don't apply distance attenuation when the slot's AuxSendAuto is off
[openal-soft.git] / al / state.cpp
blob7daf3be1736107c323095ad6da930724f7ff4e30
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 #ifdef ALSOFT_EAX
57 #include "alc/device.h"
59 #include "eax/globals.h"
60 #include "eax/x_ram.h"
61 #endif // ALSOFT_EAX
64 namespace {
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 DopplerFactor = AL_DOPPLER_FACTOR,
149 DopplerVelocity = AL_DOPPLER_VELOCITY,
150 DistanceModel = AL_DISTANCE_MODEL,
151 SpeedOfSound = AL_SPEED_OF_SOUND,
152 DeferredUpdates = AL_DEFERRED_UPDATES_SOFT,
153 GainLimit = AL_GAIN_LIMIT_SOFT,
154 NumResamplers = AL_NUM_RESAMPLERS_SOFT,
155 DefaultResampler = AL_DEFAULT_RESAMPLER_SOFT,
156 DebugLoggedMessages = AL_DEBUG_LOGGED_MESSAGES_EXT,
157 DebugNextLoggedMessageLength = AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT,
158 MaxDebugMessageLength = AL_MAX_DEBUG_MESSAGE_LENGTH_EXT,
159 MaxDebugLoggedMessages = AL_MAX_DEBUG_LOGGED_MESSAGES_EXT,
160 MaxDebugGroupDepth = AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT,
161 MaxLabelLength = AL_MAX_LABEL_LENGTH_EXT,
162 ContextFlags = AL_CONTEXT_FLAGS_EXT,
163 #ifdef ALSOFT_EAX
164 EaxRamSize = AL_EAX_RAM_SIZE,
165 EaxRamFree = 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 #ifdef 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 AL_API auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \
380 R value{}; \
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 R value{}; \
389 Name##vDirect##Ext(context, pname, &value); \
390 return value; \
393 DECL_GETFUNC(ALboolean, alGetBoolean,)
394 DECL_GETFUNC(ALdouble, alGetDouble,)
395 DECL_GETFUNC(ALfloat, alGetFloat,)
396 DECL_GETFUNC(ALint, alGetInteger,)
398 DECL_GETFUNC(ALint64SOFT, alGetInteger64,SOFT)
399 DECL_GETFUNC(ALvoid*, alGetPointer,SOFT)
401 #undef DECL_GETFUNC
404 AL_API DECL_FUNC2(void, alGetBooleanv, ALenum,pname, ALboolean*,values)
405 FORCE_ALIGN void AL_APIENTRY alGetBooleanvDirect(ALCcontext *context, ALenum pname, ALboolean *values) noexcept
407 if(!values) UNLIKELY
408 return context->setError(AL_INVALID_VALUE, "NULL pointer");
409 GetValue(context, pname, values);
412 AL_API DECL_FUNC2(void, alGetDoublev, ALenum,pname, ALdouble*,values)
413 FORCE_ALIGN void AL_APIENTRY alGetDoublevDirect(ALCcontext *context, ALenum pname, ALdouble *values) noexcept
415 if(!values) UNLIKELY
416 return context->setError(AL_INVALID_VALUE, "NULL pointer");
417 GetValue(context, pname, values);
420 AL_API DECL_FUNC2(void, alGetFloatv, ALenum,pname, ALfloat*,values)
421 FORCE_ALIGN void AL_APIENTRY alGetFloatvDirect(ALCcontext *context, ALenum pname, ALfloat *values) noexcept
423 if(!values) UNLIKELY
424 return context->setError(AL_INVALID_VALUE, "NULL pointer");
425 GetValue(context, pname, values);
428 AL_API DECL_FUNC2(void, alGetIntegerv, ALenum,pname, ALint*,values)
429 FORCE_ALIGN void AL_APIENTRY alGetIntegervDirect(ALCcontext *context, ALenum pname, ALint *values) noexcept
431 if(!values) UNLIKELY
432 return context->setError(AL_INVALID_VALUE, "NULL pointer");
433 GetValue(context, pname, values);
436 AL_API DECL_FUNCEXT2(void, alGetInteger64v,SOFT, ALenum,pname, ALint64SOFT*,values)
437 FORCE_ALIGN void AL_APIENTRY alGetInteger64vDirectSOFT(ALCcontext *context, ALenum pname, ALint64SOFT *values) noexcept
439 if(!values) UNLIKELY
440 return context->setError(AL_INVALID_VALUE, "NULL pointer");
441 GetValue(context, pname, values);
444 AL_API DECL_FUNCEXT2(void, alGetPointerv,SOFT, ALenum,pname, ALvoid**,values)
445 FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum pname, ALvoid **values) noexcept
447 if(!values) UNLIKELY
448 return context->setError(AL_INVALID_VALUE, "NULL pointer");
450 switch(pname)
452 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
453 *values = reinterpret_cast<void*>(context->mEventCb);
454 return;
456 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
457 *values = context->mEventParam;
458 return;
460 case AL_DEBUG_CALLBACK_FUNCTION_EXT:
461 *values = reinterpret_cast<void*>(context->mDebugCb);
462 return;
464 case AL_DEBUG_CALLBACK_USER_PARAM_EXT:
465 *values = context->mDebugParam;
466 return;
468 context->setError(AL_INVALID_ENUM, "Invalid context pointer property 0x%04x", pname);
471 AL_API DECL_FUNC1(const ALchar*, alGetString, ALenum,pname)
472 FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringDirect(ALCcontext *context, ALenum pname) noexcept
474 switch(pname)
476 case AL_VENDOR:
477 if(auto device = context->mALDevice.get(); !device->mVendorOverride.empty())
478 return device->mVendorOverride.c_str();
479 return GetVendorString();
480 case AL_VERSION:
481 if(auto device = context->mALDevice.get(); !device->mVersionOverride.empty())
482 return device->mVersionOverride.c_str();
483 return GetVersionString();
484 case AL_RENDERER:
485 if(auto device = context->mALDevice.get(); !device->mRendererOverride.empty())
486 return device->mRendererOverride.c_str();
487 return GetRendererString();
488 case AL_EXTENSIONS: return context->mExtensionsString.c_str();
489 case AL_NO_ERROR: return GetNoErrorString();
490 case AL_INVALID_NAME: return GetInvalidNameString();
491 case AL_INVALID_ENUM: return GetInvalidEnumString();
492 case AL_INVALID_VALUE: return GetInvalidValueString();
493 case AL_INVALID_OPERATION: return GetInvalidOperationString();
494 case AL_OUT_OF_MEMORY: return GetOutOfMemoryString();
495 case AL_STACK_OVERFLOW_EXT: return GetStackOverflowString();
496 case AL_STACK_UNDERFLOW_EXT: return GetStackUnderflowString();
498 context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
499 return nullptr;
502 AL_API DECL_FUNC1(void, alDopplerFactor, ALfloat,value)
503 FORCE_ALIGN void AL_APIENTRY alDopplerFactorDirect(ALCcontext *context, ALfloat value) noexcept
505 if(!(value >= 0.0f && std::isfinite(value)))
506 context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
507 else
509 std::lock_guard<std::mutex> proplock{context->mPropLock};
510 context->mDopplerFactor = value;
511 UpdateProps(context);
515 AL_API DECL_FUNC1(void, alSpeedOfSound, ALfloat,value)
516 FORCE_ALIGN void AL_APIENTRY alSpeedOfSoundDirect(ALCcontext *context, ALfloat value) noexcept
518 if(!(value > 0.0f && std::isfinite(value)))
519 context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
520 else
522 std::lock_guard<std::mutex> proplock{context->mPropLock};
523 context->mSpeedOfSound = value;
524 UpdateProps(context);
528 AL_API DECL_FUNC1(void, alDistanceModel, ALenum,value)
529 FORCE_ALIGN void AL_APIENTRY alDistanceModelDirect(ALCcontext *context, ALenum value) noexcept
531 if(auto model = DistanceModelFromALenum(value))
533 std::lock_guard<std::mutex> proplock{context->mPropLock};
534 context->mDistanceModel = *model;
535 if(!context->mSourceDistanceModel)
536 UpdateProps(context);
538 else
539 context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
543 AL_API DECL_FUNCEXT(void, alDeferUpdates,SOFT)
544 FORCE_ALIGN void AL_APIENTRY alDeferUpdatesDirectSOFT(ALCcontext *context) noexcept
546 std::lock_guard<std::mutex> proplock{context->mPropLock};
547 context->deferUpdates();
550 AL_API DECL_FUNCEXT(void, alProcessUpdates,SOFT)
551 FORCE_ALIGN void AL_APIENTRY alProcessUpdatesDirectSOFT(ALCcontext *context) noexcept
553 std::lock_guard<std::mutex> proplock{context->mPropLock};
554 context->processUpdates();
558 AL_API DECL_FUNCEXT2(const ALchar*, alGetStringi,SOFT, ALenum,pname, ALsizei,index)
559 FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringiDirectSOFT(ALCcontext *context, ALenum pname, ALsizei index) noexcept
561 switch(pname)
563 case AL_RESAMPLER_NAME_SOFT:
564 if(index >= 0 && index <= static_cast<ALint>(Resampler::Max))
565 return GetResamplerName(static_cast<Resampler>(index));
566 context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
567 return nullptr;
569 context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
570 return nullptr;
574 AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept
576 ContextRef context{GetContextRef()};
577 if(!context) UNLIKELY return;
579 if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY
580 context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0,
581 DebugSeverity::Medium,
582 "alDopplerVelocity is deprecated in AL 1.1, use alSpeedOfSound; "
583 "alDopplerVelocity(x) -> alSpeedOfSound(343.3f * x)");
585 if(!(value >= 0.0f && std::isfinite(value)))
586 context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
587 else
589 std::lock_guard<std::mutex> proplock{context->mPropLock};
590 context->mDopplerVelocity = value;
591 UpdateProps(context.get());
596 void UpdateContextProps(ALCcontext *context)
598 /* Get an unused property container, or allocate a new one as needed. */
599 ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
600 if(!props)
602 context->allocContextProps();
603 props = context->mFreeContextProps.load(std::memory_order_acquire);
605 ContextProps *next;
606 do {
607 next = props->next.load(std::memory_order_relaxed);
608 } while(context->mFreeContextProps.compare_exchange_weak(props, next,
609 std::memory_order_acq_rel, std::memory_order_acquire) == false);
611 /* Copy in current property values. */
612 const auto &listener = context->mListener;
613 props->Position = listener.Position;
614 props->Velocity = listener.Velocity;
615 props->OrientAt = listener.OrientAt;
616 props->OrientUp = listener.OrientUp;
617 props->Gain = listener.Gain;
618 props->MetersPerUnit = listener.mMetersPerUnit;
620 props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
621 props->DopplerFactor = context->mDopplerFactor;
622 props->DopplerVelocity = context->mDopplerVelocity;
623 props->SpeedOfSound = context->mSpeedOfSound;
624 #ifdef ALSOFT_EAX
625 props->DistanceFactor = context->eaxGetDistanceFactor();
626 #endif
628 props->SourceDistanceModel = context->mSourceDistanceModel;
629 props->mDistanceModel = context->mDistanceModel;
631 /* Set the new container for updating internal parameters. */
632 props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
633 if(props)
635 /* If there was an unused update container, put it back in the
636 * freelist.
638 AtomicReplaceHead(context->mFreeContextProps, props);