state.cpp 24 KB

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