state.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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.
  8. *
  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.
  13. *
  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
  19. */
  20. #include "config.h"
  21. #include "version.h"
  22. #include <array>
  23. #include <atomic>
  24. #include <cmath>
  25. #include <deque>
  26. #include <mutex>
  27. #include <optional>
  28. #include <stdexcept>
  29. #include <string>
  30. #include <utility>
  31. #include "AL/al.h"
  32. #include "AL/alc.h"
  33. #include "AL/alext.h"
  34. #include "al/debug.h"
  35. #include "al/listener.h"
  36. #include "alc/alu.h"
  37. #include "alc/context.h"
  38. #include "alc/inprogext.h"
  39. #include "alnumeric.h"
  40. #include "atomic.h"
  41. #include "core/context.h"
  42. #include "core/logging.h"
  43. #include "core/mixer/defs.h"
  44. #include "core/voice.h"
  45. #include "direct_defs.h"
  46. #include "intrusive_ptr.h"
  47. #include "opthelpers.h"
  48. #include "strutils.h"
  49. #ifdef ALSOFT_EAX
  50. #include "alc/device.h"
  51. #include "eax/globals.h"
  52. #include "eax/x_ram.h"
  53. #endif // ALSOFT_EAX
  54. namespace {
  55. [[nodiscard]] constexpr auto GetVendorString() noexcept { return "OpenAL Community"; }
  56. [[nodiscard]] constexpr auto GetVersionString() noexcept { return "1.1 ALSOFT " ALSOFT_VERSION; }
  57. [[nodiscard]] constexpr auto GetRendererString() noexcept { return "OpenAL Soft"; }
  58. /* Error Messages */
  59. [[nodiscard]] constexpr auto GetNoErrorString() noexcept { return "No Error"; }
  60. [[nodiscard]] constexpr auto GetInvalidNameString() noexcept { return "Invalid Name"; }
  61. [[nodiscard]] constexpr auto GetInvalidEnumString() noexcept { return "Invalid Enum"; }
  62. [[nodiscard]] constexpr auto GetInvalidValueString() noexcept { return "Invalid Value"; }
  63. [[nodiscard]] constexpr auto GetInvalidOperationString() noexcept { return "Invalid Operation"; }
  64. [[nodiscard]] constexpr auto GetOutOfMemoryString() noexcept { return "Out of Memory"; }
  65. [[nodiscard]] constexpr auto GetStackOverflowString() noexcept { return "Stack Overflow"; }
  66. [[nodiscard]] constexpr auto GetStackUnderflowString() noexcept { return "Stack Underflow"; }
  67. /* Resampler strings */
  68. template<Resampler rtype> struct ResamplerName { };
  69. template<> struct ResamplerName<Resampler::Point>
  70. { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
  71. template<> struct ResamplerName<Resampler::Linear>
  72. { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
  73. template<> struct ResamplerName<Resampler::Spline>
  74. { static constexpr const ALchar *Get() noexcept { return "Cubic Spline"; } };
  75. template<> struct ResamplerName<Resampler::Gaussian>
  76. { static constexpr const ALchar *Get() noexcept { return "4-point Gaussian"; } };
  77. template<> struct ResamplerName<Resampler::FastBSinc12>
  78. { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
  79. template<> struct ResamplerName<Resampler::BSinc12>
  80. { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
  81. template<> struct ResamplerName<Resampler::FastBSinc24>
  82. { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
  83. template<> struct ResamplerName<Resampler::BSinc24>
  84. { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
  85. const ALchar *GetResamplerName(const Resampler rtype)
  86. {
  87. #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
  88. switch(rtype)
  89. {
  90. HANDLE_RESAMPLER(Resampler::Point);
  91. HANDLE_RESAMPLER(Resampler::Linear);
  92. HANDLE_RESAMPLER(Resampler::Spline);
  93. HANDLE_RESAMPLER(Resampler::Gaussian);
  94. HANDLE_RESAMPLER(Resampler::FastBSinc12);
  95. HANDLE_RESAMPLER(Resampler::BSinc12);
  96. HANDLE_RESAMPLER(Resampler::FastBSinc24);
  97. HANDLE_RESAMPLER(Resampler::BSinc24);
  98. }
  99. #undef HANDLE_RESAMPLER
  100. /* Should never get here. */
  101. throw std::runtime_error{"Unexpected resampler index"};
  102. }
  103. constexpr auto DistanceModelFromALenum(ALenum model) noexcept -> std::optional<DistanceModel>
  104. {
  105. switch(model)
  106. {
  107. case AL_NONE: return DistanceModel::Disable;
  108. case AL_INVERSE_DISTANCE: return DistanceModel::Inverse;
  109. case AL_INVERSE_DISTANCE_CLAMPED: return DistanceModel::InverseClamped;
  110. case AL_LINEAR_DISTANCE: return DistanceModel::Linear;
  111. case AL_LINEAR_DISTANCE_CLAMPED: return DistanceModel::LinearClamped;
  112. case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent;
  113. case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped;
  114. }
  115. return std::nullopt;
  116. }
  117. constexpr auto ALenumFromDistanceModel(DistanceModel model) -> ALenum
  118. {
  119. switch(model)
  120. {
  121. case DistanceModel::Disable: return AL_NONE;
  122. case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
  123. case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
  124. case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
  125. case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
  126. case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
  127. case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
  128. }
  129. throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
  130. }
  131. enum PropertyValue : ALenum {
  132. DopplerFactor = AL_DOPPLER_FACTOR,
  133. DopplerVelocity = AL_DOPPLER_VELOCITY,
  134. DistanceModel = AL_DISTANCE_MODEL,
  135. SpeedOfSound = AL_SPEED_OF_SOUND,
  136. DeferredUpdates = AL_DEFERRED_UPDATES_SOFT,
  137. GainLimit = AL_GAIN_LIMIT_SOFT,
  138. NumResamplers = AL_NUM_RESAMPLERS_SOFT,
  139. DefaultResampler = AL_DEFAULT_RESAMPLER_SOFT,
  140. DebugLoggedMessages = AL_DEBUG_LOGGED_MESSAGES_EXT,
  141. DebugNextLoggedMessageLength = AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT,
  142. MaxDebugMessageLength = AL_MAX_DEBUG_MESSAGE_LENGTH_EXT,
  143. MaxDebugLoggedMessages = AL_MAX_DEBUG_LOGGED_MESSAGES_EXT,
  144. MaxDebugGroupDepth = AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT,
  145. MaxLabelLength = AL_MAX_LABEL_LENGTH_EXT,
  146. ContextFlags = AL_CONTEXT_FLAGS_EXT,
  147. #ifdef ALSOFT_EAX
  148. EaxRamSize = AL_EAX_RAM_SIZE,
  149. EaxRamFree = AL_EAX_RAM_FREE,
  150. #endif
  151. };
  152. template<typename T>
  153. struct PropertyCastType {
  154. template<typename U>
  155. constexpr auto operator()(U&& value) const noexcept
  156. { return static_cast<T>(std::forward<U>(value)); }
  157. };
  158. /* Special-case ALboolean to be an actual bool instead of a char type. */
  159. template<>
  160. struct PropertyCastType<ALboolean> {
  161. template<typename U>
  162. constexpr ALboolean operator()(U&& value) const noexcept
  163. { return static_cast<bool>(std::forward<U>(value)) ? AL_TRUE : AL_FALSE; }
  164. };
  165. template<typename T>
  166. void GetValue(ALCcontext *context, ALenum pname, T *values)
  167. {
  168. auto cast_value = PropertyCastType<T>{};
  169. switch(static_cast<PropertyValue>(pname))
  170. {
  171. case AL_DOPPLER_FACTOR:
  172. *values = cast_value(context->mDopplerFactor);
  173. return;
  174. case AL_DOPPLER_VELOCITY:
  175. if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY
  176. context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0,
  177. DebugSeverity::Medium,
  178. "AL_DOPPLER_VELOCITY is deprecated in AL 1.1, use AL_SPEED_OF_SOUND; "
  179. "AL_DOPPLER_VELOCITY -> AL_SPEED_OF_SOUND / 343.3f");
  180. *values = cast_value(context->mDopplerVelocity);
  181. return;
  182. case AL_SPEED_OF_SOUND:
  183. *values = cast_value(context->mSpeedOfSound);
  184. return;
  185. case AL_GAIN_LIMIT_SOFT:
  186. *values = cast_value(GainMixMax / context->mGainBoost);
  187. return;
  188. case AL_DEFERRED_UPDATES_SOFT:
  189. *values = cast_value(context->mDeferUpdates ? AL_TRUE : AL_FALSE);
  190. return;
  191. case AL_DISTANCE_MODEL:
  192. *values = cast_value(ALenumFromDistanceModel(context->mDistanceModel));
  193. return;
  194. case AL_NUM_RESAMPLERS_SOFT:
  195. *values = cast_value(al::to_underlying(Resampler::Max) + 1);
  196. return;
  197. case AL_DEFAULT_RESAMPLER_SOFT:
  198. *values = cast_value(al::to_underlying(ResamplerDefault));
  199. return;
  200. case AL_DEBUG_LOGGED_MESSAGES_EXT:
  201. {
  202. std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
  203. *values = cast_value(context->mDebugLog.size());
  204. return;
  205. }
  206. case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT:
  207. {
  208. std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
  209. *values = cast_value(context->mDebugLog.empty() ? 0_uz
  210. : (context->mDebugLog.front().mMessage.size()+1));
  211. return;
  212. }
  213. case AL_MAX_DEBUG_MESSAGE_LENGTH_EXT:
  214. *values = cast_value(MaxDebugMessageLength);
  215. return;
  216. case AL_MAX_DEBUG_LOGGED_MESSAGES_EXT:
  217. *values = cast_value(MaxDebugLoggedMessages);
  218. return;
  219. case AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT:
  220. *values = cast_value(MaxDebugGroupDepth);
  221. return;
  222. case AL_MAX_LABEL_LENGTH_EXT:
  223. *values = cast_value(MaxObjectLabelLength);
  224. return;
  225. case AL_CONTEXT_FLAGS_EXT:
  226. *values = cast_value(context->mContextFlags.to_ulong());
  227. return;
  228. #ifdef ALSOFT_EAX
  229. #define EAX_ERROR "[alGetInteger] EAX not enabled"
  230. case AL_EAX_RAM_SIZE:
  231. if(eax_g_is_enabled)
  232. {
  233. *values = cast_value(eax_x_ram_max_size);
  234. return;
  235. }
  236. ERR(EAX_ERROR "\n");
  237. break;
  238. case AL_EAX_RAM_FREE:
  239. if(eax_g_is_enabled)
  240. {
  241. auto device = context->mALDevice.get();
  242. std::lock_guard<std::mutex> device_lock{device->BufferLock};
  243. *values = cast_value(device->eax_x_ram_free_size);
  244. return;
  245. }
  246. ERR(EAX_ERROR "\n");
  247. break;
  248. #undef EAX_ERROR
  249. #endif // ALSOFT_EAX
  250. }
  251. context->setError(AL_INVALID_ENUM, "Invalid context property 0x%04x", pname);
  252. }
  253. inline void UpdateProps(ALCcontext *context)
  254. {
  255. if(!context->mDeferUpdates)
  256. UpdateContextProps(context);
  257. else
  258. context->mPropsDirty = true;
  259. }
  260. } // namespace
  261. /* WARNING: Non-standard export! Not part of any extension, or exposed in the
  262. * alcFunctions list.
  263. */
  264. AL_API auto AL_APIENTRY alsoft_get_version() noexcept -> const ALchar*
  265. {
  266. static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
  267. if(spoof) return spoof->c_str();
  268. return ALSOFT_VERSION;
  269. }
  270. AL_API DECL_FUNC1(void, alEnable, ALenum,capability)
  271. FORCE_ALIGN void AL_APIENTRY alEnableDirect(ALCcontext *context, ALenum capability) noexcept
  272. {
  273. switch(capability)
  274. {
  275. case AL_SOURCE_DISTANCE_MODEL:
  276. {
  277. std::lock_guard<std::mutex> proplock{context->mPropLock};
  278. context->mSourceDistanceModel = true;
  279. UpdateProps(context);
  280. }
  281. return;
  282. case AL_DEBUG_OUTPUT_EXT:
  283. context->mDebugEnabled.store(true);
  284. return;
  285. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  286. context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
  287. return;
  288. }
  289. context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
  290. }
  291. AL_API DECL_FUNC1(void, alDisable, ALenum,capability)
  292. FORCE_ALIGN void AL_APIENTRY alDisableDirect(ALCcontext *context, ALenum capability) noexcept
  293. {
  294. switch(capability)
  295. {
  296. case AL_SOURCE_DISTANCE_MODEL:
  297. {
  298. std::lock_guard<std::mutex> proplock{context->mPropLock};
  299. context->mSourceDistanceModel = false;
  300. UpdateProps(context);
  301. }
  302. return;
  303. case AL_DEBUG_OUTPUT_EXT:
  304. context->mDebugEnabled.store(false);
  305. return;
  306. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  307. context->mStopVoicesOnDisconnect.store(false);
  308. return;
  309. }
  310. context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
  311. }
  312. AL_API DECL_FUNC1(ALboolean, alIsEnabled, ALenum,capability)
  313. FORCE_ALIGN ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum capability) noexcept
  314. {
  315. std::lock_guard<std::mutex> proplock{context->mPropLock};
  316. switch(capability)
  317. {
  318. case AL_SOURCE_DISTANCE_MODEL: return context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
  319. case AL_DEBUG_OUTPUT_EXT: return context->mDebugEnabled ? AL_TRUE : AL_FALSE;
  320. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  321. return context->mStopVoicesOnDisconnect.load() ? AL_TRUE : AL_FALSE;
  322. }
  323. context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
  324. return AL_FALSE;
  325. }
  326. #define DECL_GETFUNC(R, Name, Ext) \
  327. AL_API auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \
  328. { \
  329. R value{}; \
  330. auto context = GetContextRef(); \
  331. if(!context) UNLIKELY return value; \
  332. Name##vDirect##Ext(GetContextRef().get(), pname, &value); \
  333. return value; \
  334. } \
  335. FORCE_ALIGN auto AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept -> R \
  336. { \
  337. R value{}; \
  338. Name##vDirect##Ext(context, pname, &value); \
  339. return value; \
  340. }
  341. DECL_GETFUNC(ALboolean, alGetBoolean,)
  342. DECL_GETFUNC(ALdouble, alGetDouble,)
  343. DECL_GETFUNC(ALfloat, alGetFloat,)
  344. DECL_GETFUNC(ALint, alGetInteger,)
  345. DECL_GETFUNC(ALint64SOFT, alGetInteger64,SOFT)
  346. DECL_GETFUNC(ALvoid*, alGetPointer,SOFT)
  347. #undef DECL_GETFUNC
  348. AL_API DECL_FUNC2(void, alGetBooleanv, ALenum,pname, ALboolean*,values)
  349. FORCE_ALIGN void AL_APIENTRY alGetBooleanvDirect(ALCcontext *context, ALenum pname, ALboolean *values) noexcept
  350. {
  351. if(!values) UNLIKELY
  352. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  353. GetValue(context, pname, values);
  354. }
  355. AL_API DECL_FUNC2(void, alGetDoublev, ALenum,pname, ALdouble*,values)
  356. FORCE_ALIGN void AL_APIENTRY alGetDoublevDirect(ALCcontext *context, ALenum pname, ALdouble *values) noexcept
  357. {
  358. if(!values) UNLIKELY
  359. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  360. GetValue(context, pname, values);
  361. }
  362. AL_API DECL_FUNC2(void, alGetFloatv, ALenum,pname, ALfloat*,values)
  363. FORCE_ALIGN void AL_APIENTRY alGetFloatvDirect(ALCcontext *context, ALenum pname, ALfloat *values) noexcept
  364. {
  365. if(!values) UNLIKELY
  366. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  367. GetValue(context, pname, values);
  368. }
  369. AL_API DECL_FUNC2(void, alGetIntegerv, ALenum,pname, ALint*,values)
  370. FORCE_ALIGN void AL_APIENTRY alGetIntegervDirect(ALCcontext *context, ALenum pname, ALint *values) noexcept
  371. {
  372. if(!values) UNLIKELY
  373. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  374. GetValue(context, pname, values);
  375. }
  376. AL_API DECL_FUNCEXT2(void, alGetInteger64v,SOFT, ALenum,pname, ALint64SOFT*,values)
  377. FORCE_ALIGN void AL_APIENTRY alGetInteger64vDirectSOFT(ALCcontext *context, ALenum pname, ALint64SOFT *values) noexcept
  378. {
  379. if(!values) UNLIKELY
  380. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  381. GetValue(context, pname, values);
  382. }
  383. AL_API DECL_FUNCEXT2(void, alGetPointerv,SOFT, ALenum,pname, ALvoid**,values)
  384. FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum pname, ALvoid **values) noexcept
  385. {
  386. if(!values) UNLIKELY
  387. return context->setError(AL_INVALID_VALUE, "NULL pointer");
  388. switch(pname)
  389. {
  390. case AL_EVENT_CALLBACK_FUNCTION_SOFT:
  391. *values = reinterpret_cast<void*>(context->mEventCb);
  392. return;
  393. case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
  394. *values = context->mEventParam;
  395. return;
  396. case AL_DEBUG_CALLBACK_FUNCTION_EXT:
  397. *values = reinterpret_cast<void*>(context->mDebugCb);
  398. return;
  399. case AL_DEBUG_CALLBACK_USER_PARAM_EXT:
  400. *values = context->mDebugParam;
  401. return;
  402. }
  403. context->setError(AL_INVALID_ENUM, "Invalid context pointer property 0x%04x", pname);
  404. }
  405. AL_API DECL_FUNC1(const ALchar*, alGetString, ALenum,pname)
  406. FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringDirect(ALCcontext *context, ALenum pname) noexcept
  407. {
  408. switch(pname)
  409. {
  410. case AL_VENDOR: return GetVendorString();
  411. case AL_VERSION: return GetVersionString();
  412. case AL_RENDERER: return GetRendererString();
  413. case AL_EXTENSIONS: return context->mExtensionsString.c_str();
  414. case AL_NO_ERROR: return GetNoErrorString();
  415. case AL_INVALID_NAME: return GetInvalidNameString();
  416. case AL_INVALID_ENUM: return GetInvalidEnumString();
  417. case AL_INVALID_VALUE: return GetInvalidValueString();
  418. case AL_INVALID_OPERATION: return GetInvalidOperationString();
  419. case AL_OUT_OF_MEMORY: return GetOutOfMemoryString();
  420. case AL_STACK_OVERFLOW_EXT: return GetStackOverflowString();
  421. case AL_STACK_UNDERFLOW_EXT: return GetStackUnderflowString();
  422. }
  423. context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
  424. return nullptr;
  425. }
  426. AL_API DECL_FUNC1(void, alDopplerFactor, ALfloat,value)
  427. FORCE_ALIGN void AL_APIENTRY alDopplerFactorDirect(ALCcontext *context, ALfloat value) noexcept
  428. {
  429. if(!(value >= 0.0f && std::isfinite(value)))
  430. context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
  431. else
  432. {
  433. std::lock_guard<std::mutex> proplock{context->mPropLock};
  434. context->mDopplerFactor = value;
  435. UpdateProps(context);
  436. }
  437. }
  438. AL_API DECL_FUNC1(void, alSpeedOfSound, ALfloat,value)
  439. FORCE_ALIGN void AL_APIENTRY alSpeedOfSoundDirect(ALCcontext *context, ALfloat value) noexcept
  440. {
  441. if(!(value > 0.0f && std::isfinite(value)))
  442. context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
  443. else
  444. {
  445. std::lock_guard<std::mutex> proplock{context->mPropLock};
  446. context->mSpeedOfSound = value;
  447. UpdateProps(context);
  448. }
  449. }
  450. AL_API DECL_FUNC1(void, alDistanceModel, ALenum,value)
  451. FORCE_ALIGN void AL_APIENTRY alDistanceModelDirect(ALCcontext *context, ALenum value) noexcept
  452. {
  453. if(auto model = DistanceModelFromALenum(value))
  454. {
  455. std::lock_guard<std::mutex> proplock{context->mPropLock};
  456. context->mDistanceModel = *model;
  457. if(!context->mSourceDistanceModel)
  458. UpdateProps(context);
  459. }
  460. else
  461. context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
  462. }
  463. AL_API DECL_FUNCEXT(void, alDeferUpdates,SOFT)
  464. FORCE_ALIGN void AL_APIENTRY alDeferUpdatesDirectSOFT(ALCcontext *context) noexcept
  465. {
  466. std::lock_guard<std::mutex> proplock{context->mPropLock};
  467. context->deferUpdates();
  468. }
  469. AL_API DECL_FUNCEXT(void, alProcessUpdates,SOFT)
  470. FORCE_ALIGN void AL_APIENTRY alProcessUpdatesDirectSOFT(ALCcontext *context) noexcept
  471. {
  472. std::lock_guard<std::mutex> proplock{context->mPropLock};
  473. context->processUpdates();
  474. }
  475. AL_API DECL_FUNCEXT2(const ALchar*, alGetStringi,SOFT, ALenum,pname, ALsizei,index)
  476. FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringiDirectSOFT(ALCcontext *context, ALenum pname, ALsizei index) noexcept
  477. {
  478. switch(pname)
  479. {
  480. case AL_RESAMPLER_NAME_SOFT:
  481. if(index >= 0 && index <= static_cast<ALint>(Resampler::Max))
  482. return GetResamplerName(static_cast<Resampler>(index));
  483. context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
  484. return nullptr;
  485. }
  486. context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
  487. return nullptr;
  488. }
  489. AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept
  490. {
  491. ContextRef context{GetContextRef()};
  492. if(!context) UNLIKELY return;
  493. if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY
  494. context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0,
  495. DebugSeverity::Medium,
  496. "alDopplerVelocity is deprecated in AL 1.1, use alSpeedOfSound; "
  497. "alDopplerVelocity(x) -> alSpeedOfSound(343.3f * x)");
  498. if(!(value >= 0.0f && std::isfinite(value)))
  499. context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
  500. else
  501. {
  502. std::lock_guard<std::mutex> proplock{context->mPropLock};
  503. context->mDopplerVelocity = value;
  504. UpdateProps(context.get());
  505. }
  506. }
  507. void UpdateContextProps(ALCcontext *context)
  508. {
  509. /* Get an unused property container, or allocate a new one as needed. */
  510. ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
  511. if(!props)
  512. {
  513. context->allocContextProps();
  514. props = context->mFreeContextProps.load(std::memory_order_acquire);
  515. }
  516. ContextProps *next;
  517. do {
  518. next = props->next.load(std::memory_order_relaxed);
  519. } while(context->mFreeContextProps.compare_exchange_weak(props, next,
  520. std::memory_order_acq_rel, std::memory_order_acquire) == false);
  521. /* Copy in current property values. */
  522. const auto &listener = context->mListener;
  523. props->Position = listener.Position;
  524. props->Velocity = listener.Velocity;
  525. props->OrientAt = listener.OrientAt;
  526. props->OrientUp = listener.OrientUp;
  527. props->Gain = listener.Gain;
  528. props->MetersPerUnit = listener.mMetersPerUnit;
  529. props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
  530. props->DopplerFactor = context->mDopplerFactor;
  531. props->DopplerVelocity = context->mDopplerVelocity;
  532. props->SpeedOfSound = context->mSpeedOfSound;
  533. props->SourceDistanceModel = context->mSourceDistanceModel;
  534. props->mDistanceModel = context->mDistanceModel;
  535. /* Set the new container for updating internal parameters. */
  536. props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
  537. if(props)
  538. {
  539. /* If there was an unused update container, put it back in the
  540. * freelist.
  541. */
  542. AtomicReplaceHead(context->mFreeContextProps, props);
  543. }
  544. }