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
40 #include "al/listener.h"
42 #include "alc/context.h"
43 #include "alc/device.h"
44 #include "alc/inprogext.h"
45 #include "alnumeric.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"
57 #include "eax/globals.h"
58 #include "eax/x_ram.h"
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"; }
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()
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
>
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
;
132 constexpr auto ALenumFromDistanceModel(DistanceModel model
) -> ALenum
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
,
164 EaxRamSizeProp
= AL_EAX_RAM_SIZE
,
165 EaxRamFreeProp
= AL_EAX_RAM_FREE
,
170 struct PropertyCastType
{
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. */
177 struct PropertyCastType
<ALboolean
> {
179 constexpr ALboolean
operator()(U
&& value
) const noexcept
180 { return static_cast<bool>(std::forward
<U
>(value
)) ? AL_TRUE
: AL_FALSE
; }
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
);
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
);
204 case AL_SPEED_OF_SOUND
:
205 *values
= cast_value(context
->mSpeedOfSound
);
208 case AL_GAIN_LIMIT_SOFT
:
209 *values
= cast_value(GainMixMax
/ context
->mGainBoost
);
212 case AL_DEFERRED_UPDATES_SOFT
:
213 *values
= cast_value(context
->mDeferUpdates
? AL_TRUE
: AL_FALSE
);
216 case AL_DISTANCE_MODEL
:
217 *values
= cast_value(ALenumFromDistanceModel(context
->mDistanceModel
));
220 case AL_NUM_RESAMPLERS_SOFT
:
221 *values
= cast_value(al::to_underlying(Resampler::Max
) + 1);
224 case AL_DEFAULT_RESAMPLER_SOFT
:
225 *values
= cast_value(al::to_underlying(ResamplerDefault
));
228 case AL_DEBUG_LOGGED_MESSAGES_EXT
:
230 std::lock_guard
<std::mutex
> debuglock
{context
->mDebugCbLock
};
231 *values
= cast_value(context
->mDebugLog
.size());
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));
243 case AL_MAX_DEBUG_MESSAGE_LENGTH_EXT
:
244 *values
= cast_value(MaxDebugMessageLength
);
247 case AL_MAX_DEBUG_LOGGED_MESSAGES_EXT
:
248 *values
= cast_value(MaxDebugLoggedMessages
);
251 case AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT
:
252 *values
= cast_value(MaxDebugGroupDepth
);
255 case AL_MAX_LABEL_LENGTH_EXT
:
256 *values
= cast_value(MaxObjectLabelLength
);
259 case AL_CONTEXT_FLAGS_EXT
:
260 *values
= cast_value(context
->mContextFlags
.to_ulong());
264 #define EAX_ERROR "[alGetInteger] EAX not enabled"
266 case AL_EAX_RAM_SIZE
:
269 *values
= cast_value(eax_x_ram_max_size
);
275 case AL_EAX_RAM_FREE
:
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
);
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
);
298 context
->mPropsDirty
= true;
303 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
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
319 case AL_SOURCE_DISTANCE_MODEL
:
321 std::lock_guard
<std::mutex
> proplock
{context
->mPropLock
};
322 context
->mSourceDistanceModel
= true;
323 UpdateProps(context
);
327 case AL_DEBUG_OUTPUT_EXT
:
328 context
->mDebugEnabled
.store(true);
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");
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
343 case AL_SOURCE_DISTANCE_MODEL
:
345 std::lock_guard
<std::mutex
> proplock
{context
->mPropLock
};
346 context
->mSourceDistanceModel
= false;
347 UpdateProps(context
);
351 case AL_DEBUG_OUTPUT_EXT
:
352 context
->mDebugEnabled
.store(false);
355 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT
:
356 context
->mStopVoicesOnDisconnect
.store(false);
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
};
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
);
377 #define DECL_GETFUNC(R, Name, Ext) \
378 auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \
381 auto context = GetContextRef(); \
382 if(!context) UNLIKELY return value; \
383 Name##vDirect##Ext(GetContextRef().get(), pname, &value); \
386 FORCE_ALIGN auto AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept -> R \
389 Name##vDirect##Ext(context, pname, &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
)
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
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
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
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
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
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
453 return context
->setError(AL_INVALID_VALUE
, "NULL pointer");
457 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
458 *values
= reinterpret_cast<void*>(context
->mEventCb
);
461 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
462 *values
= context
->mEventParam
;
465 case AL_DEBUG_CALLBACK_FUNCTION_EXT
:
466 *values
= reinterpret_cast<void*>(context
->mDebugCb
);
469 case AL_DEBUG_CALLBACK_USER_PARAM_EXT
:
470 *values
= context
->mDebugParam
;
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
482 if(auto device
= context
->mALDevice
.get(); !device
->mVendorOverride
.empty())
483 return device
->mVendorOverride
.c_str();
484 return GetVendorString();
486 if(auto device
= context
->mALDevice
.get(); !device
->mVersionOverride
.empty())
487 return device
->mVersionOverride
.c_str();
488 return GetVersionString();
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
);
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
);
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
);
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
);
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
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
);
574 context
->setError(AL_INVALID_VALUE
, "Invalid string indexed property");
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
);
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
)};
607 context
->allocContextProps();
608 props
= context
->mFreeContextProps
.load(std::memory_order_acquire
);
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
;
630 props
->DistanceFactor
= context
->eaxGetDistanceFactor();
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
);
640 /* If there was an unused update container, put it back in the
643 AtomicReplaceHead(context
->mFreeContextProps
, props
);