🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

963 lines
25 KiB

  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 <atomic>
  23. #include <cmath>
  24. #include <mutex>
  25. #include <stdexcept>
  26. #include <string>
  27. #include "AL/al.h"
  28. #include "AL/alc.h"
  29. #include "AL/alext.h"
  30. #include "alc/alu.h"
  31. #include "alc/context.h"
  32. #include "alc/inprogext.h"
  33. #include "alnumeric.h"
  34. #include "aloptional.h"
  35. #include "atomic.h"
  36. #include "core/context.h"
  37. #include "core/except.h"
  38. #include "core/mixer/defs.h"
  39. #include "core/voice.h"
  40. #include "intrusive_ptr.h"
  41. #include "opthelpers.h"
  42. #include "strutils.h"
  43. #ifdef ALSOFT_EAX
  44. #include "alc/device.h"
  45. #include "eax/globals.h"
  46. #include "eax/x_ram.h"
  47. #endif // ALSOFT_EAX
  48. namespace {
  49. constexpr ALchar alVendor[] = "OpenAL Community";
  50. constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
  51. constexpr ALchar alRenderer[] = "OpenAL Soft";
  52. // Error Messages
  53. constexpr ALchar alNoError[] = "No Error";
  54. constexpr ALchar alErrInvalidName[] = "Invalid Name";
  55. constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
  56. constexpr ALchar alErrInvalidValue[] = "Invalid Value";
  57. constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
  58. constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
  59. /* Resampler strings */
  60. template<Resampler rtype> struct ResamplerName { };
  61. template<> struct ResamplerName<Resampler::Point>
  62. { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
  63. template<> struct ResamplerName<Resampler::Linear>
  64. { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
  65. template<> struct ResamplerName<Resampler::Cubic>
  66. { static constexpr const ALchar *Get() noexcept { return "Cubic"; } };
  67. template<> struct ResamplerName<Resampler::FastBSinc12>
  68. { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
  69. template<> struct ResamplerName<Resampler::BSinc12>
  70. { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
  71. template<> struct ResamplerName<Resampler::FastBSinc24>
  72. { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
  73. template<> struct ResamplerName<Resampler::BSinc24>
  74. { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
  75. const ALchar *GetResamplerName(const Resampler rtype)
  76. {
  77. #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
  78. switch(rtype)
  79. {
  80. HANDLE_RESAMPLER(Resampler::Point);
  81. HANDLE_RESAMPLER(Resampler::Linear);
  82. HANDLE_RESAMPLER(Resampler::Cubic);
  83. HANDLE_RESAMPLER(Resampler::FastBSinc12);
  84. HANDLE_RESAMPLER(Resampler::BSinc12);
  85. HANDLE_RESAMPLER(Resampler::FastBSinc24);
  86. HANDLE_RESAMPLER(Resampler::BSinc24);
  87. }
  88. #undef HANDLE_RESAMPLER
  89. /* Should never get here. */
  90. throw std::runtime_error{"Unexpected resampler index"};
  91. }
  92. al::optional<DistanceModel> DistanceModelFromALenum(ALenum model)
  93. {
  94. switch(model)
  95. {
  96. case AL_NONE: return al::make_optional(DistanceModel::Disable);
  97. case AL_INVERSE_DISTANCE: return al::make_optional(DistanceModel::Inverse);
  98. case AL_INVERSE_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::InverseClamped);
  99. case AL_LINEAR_DISTANCE: return al::make_optional(DistanceModel::Linear);
  100. case AL_LINEAR_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::LinearClamped);
  101. case AL_EXPONENT_DISTANCE: return al::make_optional(DistanceModel::Exponent);
  102. case AL_EXPONENT_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::ExponentClamped);
  103. }
  104. return al::nullopt;
  105. }
  106. ALenum ALenumFromDistanceModel(DistanceModel model)
  107. {
  108. switch(model)
  109. {
  110. case DistanceModel::Disable: return AL_NONE;
  111. case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
  112. case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
  113. case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
  114. case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
  115. case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
  116. case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
  117. }
  118. throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
  119. }
  120. } // namespace
  121. /* WARNING: Non-standard export! Not part of any extension, or exposed in the
  122. * alcFunctions list.
  123. */
  124. AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
  125. START_API_FUNC
  126. {
  127. static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
  128. if(spoof) return spoof->c_str();
  129. return ALSOFT_VERSION;
  130. }
  131. END_API_FUNC
  132. #define DO_UPDATEPROPS() do { \
  133. if(!context->mDeferUpdates) \
  134. UpdateContextProps(context.get()); \
  135. else \
  136. context->mPropsDirty = true; \
  137. } while(0)
  138. AL_API void AL_APIENTRY alEnable(ALenum capability)
  139. START_API_FUNC
  140. {
  141. ContextRef context{GetContextRef()};
  142. if UNLIKELY(!context) return;
  143. switch(capability)
  144. {
  145. case AL_SOURCE_DISTANCE_MODEL:
  146. {
  147. std::lock_guard<std::mutex> _{context->mPropLock};
  148. context->mSourceDistanceModel = true;
  149. DO_UPDATEPROPS();
  150. }
  151. break;
  152. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  153. context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
  154. break;
  155. default:
  156. context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
  157. }
  158. }
  159. END_API_FUNC
  160. AL_API void AL_APIENTRY alDisable(ALenum capability)
  161. START_API_FUNC
  162. {
  163. ContextRef context{GetContextRef()};
  164. if UNLIKELY(!context) return;
  165. switch(capability)
  166. {
  167. case AL_SOURCE_DISTANCE_MODEL:
  168. {
  169. std::lock_guard<std::mutex> _{context->mPropLock};
  170. context->mSourceDistanceModel = false;
  171. DO_UPDATEPROPS();
  172. }
  173. break;
  174. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  175. context->mStopVoicesOnDisconnect = false;
  176. break;
  177. default:
  178. context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
  179. }
  180. }
  181. END_API_FUNC
  182. AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
  183. START_API_FUNC
  184. {
  185. ContextRef context{GetContextRef()};
  186. if UNLIKELY(!context) return AL_FALSE;
  187. std::lock_guard<std::mutex> _{context->mPropLock};
  188. ALboolean value{AL_FALSE};
  189. switch(capability)
  190. {
  191. case AL_SOURCE_DISTANCE_MODEL:
  192. value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
  193. break;
  194. case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
  195. value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE;
  196. break;
  197. default:
  198. context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
  199. }
  200. return value;
  201. }
  202. END_API_FUNC
  203. AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
  204. START_API_FUNC
  205. {
  206. ContextRef context{GetContextRef()};
  207. if UNLIKELY(!context) return AL_FALSE;
  208. std::lock_guard<std::mutex> _{context->mPropLock};
  209. ALboolean value{AL_FALSE};
  210. switch(pname)
  211. {
  212. case AL_DOPPLER_FACTOR:
  213. if(context->mDopplerFactor != 0.0f)
  214. value = AL_TRUE;
  215. break;
  216. case AL_DOPPLER_VELOCITY:
  217. if(context->mDopplerVelocity != 0.0f)
  218. value = AL_TRUE;
  219. break;
  220. case AL_DISTANCE_MODEL:
  221. if(context->mDistanceModel == DistanceModel::Default)
  222. value = AL_TRUE;
  223. break;
  224. case AL_SPEED_OF_SOUND:
  225. if(context->mSpeedOfSound != 0.0f)
  226. value = AL_TRUE;
  227. break;
  228. case AL_DEFERRED_UPDATES_SOFT:
  229. if(context->mDeferUpdates)
  230. value = AL_TRUE;
  231. break;
  232. case AL_GAIN_LIMIT_SOFT:
  233. if(GainMixMax/context->mGainBoost != 0.0f)
  234. value = AL_TRUE;
  235. break;
  236. case AL_NUM_RESAMPLERS_SOFT:
  237. /* Always non-0. */
  238. value = AL_TRUE;
  239. break;
  240. case AL_DEFAULT_RESAMPLER_SOFT:
  241. value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE;
  242. break;
  243. default:
  244. context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
  245. }
  246. return value;
  247. }
  248. END_API_FUNC
  249. AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
  250. START_API_FUNC
  251. {
  252. ContextRef context{GetContextRef()};
  253. if UNLIKELY(!context) return 0.0;
  254. std::lock_guard<std::mutex> _{context->mPropLock};
  255. ALdouble value{0.0};
  256. switch(pname)
  257. {
  258. case AL_DOPPLER_FACTOR:
  259. value = context->mDopplerFactor;
  260. break;
  261. case AL_DOPPLER_VELOCITY:
  262. value = context->mDopplerVelocity;
  263. break;
  264. case AL_DISTANCE_MODEL:
  265. value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel));
  266. break;
  267. case AL_SPEED_OF_SOUND:
  268. value = context->mSpeedOfSound;
  269. break;
  270. case AL_DEFERRED_UPDATES_SOFT:
  271. if(context->mDeferUpdates)
  272. value = static_cast<ALdouble>(AL_TRUE);
  273. break;
  274. case AL_GAIN_LIMIT_SOFT:
  275. value = ALdouble{GainMixMax}/context->mGainBoost;
  276. break;
  277. case AL_NUM_RESAMPLERS_SOFT:
  278. value = static_cast<ALdouble>(Resampler::Max) + 1.0;
  279. break;
  280. case AL_DEFAULT_RESAMPLER_SOFT:
  281. value = static_cast<ALdouble>(ResamplerDefault);
  282. break;
  283. default:
  284. context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
  285. }
  286. return value;
  287. }
  288. END_API_FUNC
  289. AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
  290. START_API_FUNC
  291. {
  292. ContextRef context{GetContextRef()};
  293. if UNLIKELY(!context) return 0.0f;
  294. std::lock_guard<std::mutex> _{context->mPropLock};
  295. ALfloat value{0.0f};
  296. switch(pname)
  297. {
  298. case AL_DOPPLER_FACTOR:
  299. value = context->mDopplerFactor;
  300. break;
  301. case AL_DOPPLER_VELOCITY:
  302. value = context->mDopplerVelocity;
  303. break;
  304. case AL_DISTANCE_MODEL:
  305. value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel));
  306. break;
  307. case AL_SPEED_OF_SOUND:
  308. value = context->mSpeedOfSound;
  309. break;
  310. case AL_DEFERRED_UPDATES_SOFT:
  311. if(context->mDeferUpdates)
  312. value = static_cast<ALfloat>(AL_TRUE);
  313. break;
  314. case AL_GAIN_LIMIT_SOFT:
  315. value = GainMixMax/context->mGainBoost;
  316. break;
  317. case AL_NUM_RESAMPLERS_SOFT:
  318. value = static_cast<ALfloat>(Resampler::Max) + 1.0f;
  319. break;
  320. case AL_DEFAULT_RESAMPLER_SOFT:
  321. value = static_cast<ALfloat>(ResamplerDefault);
  322. break;
  323. default:
  324. context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
  325. }
  326. return value;
  327. }
  328. END_API_FUNC
  329. AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
  330. START_API_FUNC
  331. {
  332. ContextRef context{GetContextRef()};
  333. if UNLIKELY(!context) return 0;
  334. std::lock_guard<std::mutex> _{context->mPropLock};
  335. ALint value{0};
  336. switch(pname)
  337. {
  338. case AL_DOPPLER_FACTOR:
  339. value = static_cast<ALint>(context->mDopplerFactor);
  340. break;
  341. case AL_DOPPLER_VELOCITY:
  342. value = static_cast<ALint>(context->mDopplerVelocity);
  343. break;
  344. case AL_DISTANCE_MODEL:
  345. value = ALenumFromDistanceModel(context->mDistanceModel);
  346. break;
  347. case AL_SPEED_OF_SOUND:
  348. value = static_cast<ALint>(context->mSpeedOfSound);
  349. break;
  350. case AL_DEFERRED_UPDATES_SOFT:
  351. if(context->mDeferUpdates)
  352. value = AL_TRUE;
  353. break;
  354. case AL_GAIN_LIMIT_SOFT:
  355. value = static_cast<ALint>(GainMixMax/context->mGainBoost);
  356. break;
  357. case AL_NUM_RESAMPLERS_SOFT:
  358. value = static_cast<int>(Resampler::Max) + 1;
  359. break;
  360. case AL_DEFAULT_RESAMPLER_SOFT:
  361. value = static_cast<int>(ResamplerDefault);
  362. break;
  363. #ifdef ALSOFT_EAX
  364. #define EAX_ERROR "[alGetInteger] EAX not enabled."
  365. case AL_EAX_RAM_SIZE:
  366. if (eax_g_is_enabled)
  367. {
  368. value = eax_x_ram_max_size;
  369. }
  370. else
  371. {
  372. context->setError(AL_INVALID_VALUE, EAX_ERROR);
  373. }
  374. break;
  375. case AL_EAX_RAM_FREE:
  376. if (eax_g_is_enabled)
  377. {
  378. auto device = context->mALDevice.get();
  379. std::lock_guard<std::mutex> device_lock{device->BufferLock};
  380. value = static_cast<ALint>(device->eax_x_ram_free_size);
  381. }
  382. else
  383. {
  384. context->setError(AL_INVALID_VALUE, EAX_ERROR);
  385. }
  386. break;
  387. #undef EAX_ERROR
  388. #endif // ALSOFT_EAX
  389. default:
  390. context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
  391. }
  392. return value;
  393. }
  394. END_API_FUNC
  395. AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
  396. START_API_FUNC
  397. {
  398. ContextRef context{GetContextRef()};
  399. if UNLIKELY(!context) return 0_i64;
  400. std::lock_guard<std::mutex> _{context->mPropLock};
  401. ALint64SOFT value{0};
  402. switch(pname)
  403. {
  404. case AL_DOPPLER_FACTOR:
  405. value = static_cast<ALint64SOFT>(context->mDopplerFactor);
  406. break;
  407. case AL_DOPPLER_VELOCITY:
  408. value = static_cast<ALint64SOFT>(context->mDopplerVelocity);
  409. break;
  410. case AL_DISTANCE_MODEL:
  411. value = ALenumFromDistanceModel(context->mDistanceModel);
  412. break;
  413. case AL_SPEED_OF_SOUND:
  414. value = static_cast<ALint64SOFT>(context->mSpeedOfSound);
  415. break;
  416. case AL_DEFERRED_UPDATES_SOFT:
  417. if(context->mDeferUpdates)
  418. value = AL_TRUE;
  419. break;
  420. case AL_GAIN_LIMIT_SOFT:
  421. value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost);
  422. break;
  423. case AL_NUM_RESAMPLERS_SOFT:
  424. value = static_cast<ALint64SOFT>(Resampler::Max) + 1;
  425. break;
  426. case AL_DEFAULT_RESAMPLER_SOFT:
  427. value = static_cast<ALint64SOFT>(ResamplerDefault);
  428. break;
  429. default:
  430. context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
  431. }
  432. return value;
  433. }
  434. END_API_FUNC
  435. AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname)
  436. START_API_FUNC
  437. {
  438. ContextRef context{GetContextRef()};
  439. if UNLIKELY(!context) return nullptr;
  440. std::lock_guard<std::mutex> _{context->mPropLock};
  441. void *value{nullptr};
  442. switch(pname)
  443. {
  444. case AL_EVENT_CALLBACK_FUNCTION_SOFT:
  445. value = reinterpret_cast<void*>(context->mEventCb);
  446. break;
  447. case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
  448. value = context->mEventParam;
  449. break;
  450. default:
  451. context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
  452. }
  453. return value;
  454. }
  455. END_API_FUNC
  456. AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
  457. START_API_FUNC
  458. {
  459. if(values)
  460. {
  461. switch(pname)
  462. {
  463. case AL_DOPPLER_FACTOR:
  464. case AL_DOPPLER_VELOCITY:
  465. case AL_DISTANCE_MODEL:
  466. case AL_SPEED_OF_SOUND:
  467. case AL_DEFERRED_UPDATES_SOFT:
  468. case AL_GAIN_LIMIT_SOFT:
  469. case AL_NUM_RESAMPLERS_SOFT:
  470. case AL_DEFAULT_RESAMPLER_SOFT:
  471. values[0] = alGetBoolean(pname);
  472. return;
  473. }
  474. }
  475. ContextRef context{GetContextRef()};
  476. if UNLIKELY(!context) return;
  477. if(!values)
  478. context->setError(AL_INVALID_VALUE, "NULL pointer");
  479. else switch(pname)
  480. {
  481. default:
  482. context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
  483. }
  484. }
  485. END_API_FUNC
  486. AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
  487. START_API_FUNC
  488. {
  489. if(values)
  490. {
  491. switch(pname)
  492. {
  493. case AL_DOPPLER_FACTOR:
  494. case AL_DOPPLER_VELOCITY:
  495. case AL_DISTANCE_MODEL:
  496. case AL_SPEED_OF_SOUND:
  497. case AL_DEFERRED_UPDATES_SOFT:
  498. case AL_GAIN_LIMIT_SOFT:
  499. case AL_NUM_RESAMPLERS_SOFT:
  500. case AL_DEFAULT_RESAMPLER_SOFT:
  501. values[0] = alGetDouble(pname);
  502. return;
  503. }
  504. }
  505. ContextRef context{GetContextRef()};
  506. if UNLIKELY(!context) return;
  507. if(!values)
  508. context->setError(AL_INVALID_VALUE, "NULL pointer");
  509. else switch(pname)
  510. {
  511. default:
  512. context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
  513. }
  514. }
  515. END_API_FUNC
  516. AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
  517. START_API_FUNC
  518. {
  519. if(values)
  520. {
  521. switch(pname)
  522. {
  523. case AL_DOPPLER_FACTOR:
  524. case AL_DOPPLER_VELOCITY:
  525. case AL_DISTANCE_MODEL:
  526. case AL_SPEED_OF_SOUND:
  527. case AL_DEFERRED_UPDATES_SOFT:
  528. case AL_GAIN_LIMIT_SOFT:
  529. case AL_NUM_RESAMPLERS_SOFT:
  530. case AL_DEFAULT_RESAMPLER_SOFT:
  531. values[0] = alGetFloat(pname);
  532. return;
  533. }
  534. }
  535. ContextRef context{GetContextRef()};
  536. if UNLIKELY(!context) return;
  537. if(!values)
  538. context->setError(AL_INVALID_VALUE, "NULL pointer");
  539. else switch(pname)
  540. {
  541. default:
  542. context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
  543. }
  544. }
  545. END_API_FUNC
  546. AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
  547. START_API_FUNC
  548. {
  549. if(values)
  550. {
  551. switch(pname)
  552. {
  553. case AL_DOPPLER_FACTOR:
  554. case AL_DOPPLER_VELOCITY:
  555. case AL_DISTANCE_MODEL:
  556. case AL_SPEED_OF_SOUND:
  557. case AL_DEFERRED_UPDATES_SOFT:
  558. case AL_GAIN_LIMIT_SOFT:
  559. case AL_NUM_RESAMPLERS_SOFT:
  560. case AL_DEFAULT_RESAMPLER_SOFT:
  561. values[0] = alGetInteger(pname);
  562. return;
  563. }
  564. }
  565. ContextRef context{GetContextRef()};
  566. if UNLIKELY(!context) return;
  567. if(!values)
  568. context->setError(AL_INVALID_VALUE, "NULL pointer");
  569. else switch(pname)
  570. {
  571. default:
  572. context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
  573. }
  574. }
  575. END_API_FUNC
  576. AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
  577. START_API_FUNC
  578. {
  579. if(values)
  580. {
  581. switch(pname)
  582. {
  583. case AL_DOPPLER_FACTOR:
  584. case AL_DOPPLER_VELOCITY:
  585. case AL_DISTANCE_MODEL:
  586. case AL_SPEED_OF_SOUND:
  587. case AL_DEFERRED_UPDATES_SOFT:
  588. case AL_GAIN_LIMIT_SOFT:
  589. case AL_NUM_RESAMPLERS_SOFT:
  590. case AL_DEFAULT_RESAMPLER_SOFT:
  591. values[0] = alGetInteger64SOFT(pname);
  592. return;
  593. }
  594. }
  595. ContextRef context{GetContextRef()};
  596. if UNLIKELY(!context) return;
  597. if(!values)
  598. context->setError(AL_INVALID_VALUE, "NULL pointer");
  599. else switch(pname)
  600. {
  601. default:
  602. context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
  603. }
  604. }
  605. END_API_FUNC
  606. AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values)
  607. START_API_FUNC
  608. {
  609. if(values)
  610. {
  611. switch(pname)
  612. {
  613. case AL_EVENT_CALLBACK_FUNCTION_SOFT:
  614. case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
  615. values[0] = alGetPointerSOFT(pname);
  616. return;
  617. }
  618. }
  619. ContextRef context{GetContextRef()};
  620. if UNLIKELY(!context) return;
  621. if(!values)
  622. context->setError(AL_INVALID_VALUE, "NULL pointer");
  623. else switch(pname)
  624. {
  625. default:
  626. context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
  627. }
  628. }
  629. END_API_FUNC
  630. AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
  631. START_API_FUNC
  632. {
  633. ContextRef context{GetContextRef()};
  634. if UNLIKELY(!context) return nullptr;
  635. const ALchar *value{nullptr};
  636. switch(pname)
  637. {
  638. case AL_VENDOR:
  639. value = alVendor;
  640. break;
  641. case AL_VERSION:
  642. value = alVersion;
  643. break;
  644. case AL_RENDERER:
  645. value = alRenderer;
  646. break;
  647. case AL_EXTENSIONS:
  648. value = context->mExtensionList;
  649. break;
  650. case AL_NO_ERROR:
  651. value = alNoError;
  652. break;
  653. case AL_INVALID_NAME:
  654. value = alErrInvalidName;
  655. break;
  656. case AL_INVALID_ENUM:
  657. value = alErrInvalidEnum;
  658. break;
  659. case AL_INVALID_VALUE:
  660. value = alErrInvalidValue;
  661. break;
  662. case AL_INVALID_OPERATION:
  663. value = alErrInvalidOp;
  664. break;
  665. case AL_OUT_OF_MEMORY:
  666. value = alErrOutOfMemory;
  667. break;
  668. default:
  669. context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
  670. }
  671. return value;
  672. }
  673. END_API_FUNC
  674. AL_API void AL_APIENTRY alDopplerFactor(ALfloat value)
  675. START_API_FUNC
  676. {
  677. ContextRef context{GetContextRef()};
  678. if UNLIKELY(!context) return;
  679. if(!(value >= 0.0f && std::isfinite(value)))
  680. context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
  681. else
  682. {
  683. std::lock_guard<std::mutex> _{context->mPropLock};
  684. context->mDopplerFactor = value;
  685. DO_UPDATEPROPS();
  686. }
  687. }
  688. END_API_FUNC
  689. AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value)
  690. START_API_FUNC
  691. {
  692. ContextRef context{GetContextRef()};
  693. if UNLIKELY(!context) return;
  694. if(!(value >= 0.0f && std::isfinite(value)))
  695. context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
  696. else
  697. {
  698. std::lock_guard<std::mutex> _{context->mPropLock};
  699. context->mDopplerVelocity = value;
  700. DO_UPDATEPROPS();
  701. }
  702. }
  703. END_API_FUNC
  704. AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value)
  705. START_API_FUNC
  706. {
  707. ContextRef context{GetContextRef()};
  708. if UNLIKELY(!context) return;
  709. if(!(value > 0.0f && std::isfinite(value)))
  710. context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
  711. else
  712. {
  713. std::lock_guard<std::mutex> _{context->mPropLock};
  714. context->mSpeedOfSound = value;
  715. DO_UPDATEPROPS();
  716. }
  717. }
  718. END_API_FUNC
  719. AL_API void AL_APIENTRY alDistanceModel(ALenum value)
  720. START_API_FUNC
  721. {
  722. ContextRef context{GetContextRef()};
  723. if UNLIKELY(!context) return;
  724. if(auto model = DistanceModelFromALenum(value))
  725. {
  726. std::lock_guard<std::mutex> _{context->mPropLock};
  727. context->mDistanceModel = *model;
  728. if(!context->mSourceDistanceModel)
  729. DO_UPDATEPROPS();
  730. }
  731. else
  732. context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
  733. }
  734. END_API_FUNC
  735. AL_API void AL_APIENTRY alDeferUpdatesSOFT(void)
  736. START_API_FUNC
  737. {
  738. ContextRef context{GetContextRef()};
  739. if UNLIKELY(!context) return;
  740. std::lock_guard<std::mutex> _{context->mPropLock};
  741. context->deferUpdates();
  742. }
  743. END_API_FUNC
  744. AL_API void AL_APIENTRY alProcessUpdatesSOFT(void)
  745. START_API_FUNC
  746. {
  747. ContextRef context{GetContextRef()};
  748. if UNLIKELY(!context) return;
  749. std::lock_guard<std::mutex> _{context->mPropLock};
  750. context->processUpdates();
  751. }
  752. END_API_FUNC
  753. AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
  754. START_API_FUNC
  755. {
  756. ContextRef context{GetContextRef()};
  757. if UNLIKELY(!context) return nullptr;
  758. const ALchar *value{nullptr};
  759. switch(pname)
  760. {
  761. case AL_RESAMPLER_NAME_SOFT:
  762. if(index < 0 || index > static_cast<ALint>(Resampler::Max))
  763. context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
  764. else
  765. value = GetResamplerName(static_cast<Resampler>(index));
  766. break;
  767. default:
  768. context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
  769. }
  770. return value;
  771. }
  772. END_API_FUNC
  773. void UpdateContextProps(ALCcontext *context)
  774. {
  775. /* Get an unused proprty container, or allocate a new one as needed. */
  776. ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
  777. if(!props)
  778. props = new ContextProps{};
  779. else
  780. {
  781. ContextProps *next;
  782. do {
  783. next = props->next.load(std::memory_order_relaxed);
  784. } while(context->mFreeContextProps.compare_exchange_weak(props, next,
  785. std::memory_order_seq_cst, std::memory_order_acquire) == 0);
  786. }
  787. /* Copy in current property values. */
  788. ALlistener &listener = context->mListener;
  789. props->Position = listener.Position;
  790. props->Velocity = listener.Velocity;
  791. props->OrientAt = listener.OrientAt;
  792. props->OrientUp = listener.OrientUp;
  793. props->Gain = listener.Gain;
  794. props->MetersPerUnit = listener.mMetersPerUnit;
  795. props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
  796. props->DopplerFactor = context->mDopplerFactor;
  797. props->DopplerVelocity = context->mDopplerVelocity;
  798. props->SpeedOfSound = context->mSpeedOfSound;
  799. props->SourceDistanceModel = context->mSourceDistanceModel;
  800. props->mDistanceModel = context->mDistanceModel;
  801. /* Set the new container for updating internal parameters. */
  802. props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
  803. if(props)
  804. {
  805. /* If there was an unused update container, put it back in the
  806. * freelist.
  807. */
  808. AtomicReplaceHead(context->mFreeContextProps, props);
  809. }
  810. }