🛠️🐜 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.

849 lines
22 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 <stdlib.h>
  23. #include <cmath>
  24. #include "alMain.h"
  25. #include "alcontext.h"
  26. #include "alu.h"
  27. #include "alError.h"
  28. #include "alexcpt.h"
  29. #include "backends/base.h"
  30. namespace {
  31. constexpr ALchar alVendor[] = "OpenAL Community";
  32. constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
  33. constexpr ALchar alRenderer[] = "OpenAL Soft";
  34. // Error Messages
  35. constexpr ALchar alNoError[] = "No Error";
  36. constexpr ALchar alErrInvalidName[] = "Invalid Name";
  37. constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
  38. constexpr ALchar alErrInvalidValue[] = "Invalid Value";
  39. constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
  40. constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
  41. /* Resampler strings */
  42. constexpr ALchar alPointResampler[] = "Nearest";
  43. constexpr ALchar alLinearResampler[] = "Linear";
  44. constexpr ALchar alCubicResampler[] = "Cubic";
  45. constexpr ALchar alBSinc12Resampler[] = "11th order Sinc";
  46. constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc";
  47. } // namespace
  48. /* WARNING: Non-standard export! Not part of any extension, or exposed in the
  49. * alcFunctions list.
  50. */
  51. extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
  52. START_API_FUNC
  53. {
  54. const char *spoof{getenv("ALSOFT_SPOOF_VERSION")};
  55. if(spoof && spoof[0] != '\0') return spoof;
  56. return ALSOFT_VERSION;
  57. }
  58. END_API_FUNC
  59. #define DO_UPDATEPROPS() do { \
  60. if(!context->DeferUpdates.load(std::memory_order_acquire)) \
  61. UpdateContextProps(context.get()); \
  62. else \
  63. context->PropsClean.clear(std::memory_order_release); \
  64. } while(0)
  65. AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
  66. START_API_FUNC
  67. {
  68. ContextRef context{GetContextRef()};
  69. if(UNLIKELY(!context)) return;
  70. std::lock_guard<std::mutex> _{context->PropLock};
  71. switch(capability)
  72. {
  73. case AL_SOURCE_DISTANCE_MODEL:
  74. context->SourceDistanceModel = AL_TRUE;
  75. DO_UPDATEPROPS();
  76. break;
  77. default:
  78. alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
  79. }
  80. }
  81. END_API_FUNC
  82. AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
  83. START_API_FUNC
  84. {
  85. ContextRef context{GetContextRef()};
  86. if(UNLIKELY(!context)) return;
  87. std::lock_guard<std::mutex> _{context->PropLock};
  88. switch(capability)
  89. {
  90. case AL_SOURCE_DISTANCE_MODEL:
  91. context->SourceDistanceModel = AL_FALSE;
  92. DO_UPDATEPROPS();
  93. break;
  94. default:
  95. alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
  96. }
  97. }
  98. END_API_FUNC
  99. AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
  100. START_API_FUNC
  101. {
  102. ContextRef context{GetContextRef()};
  103. if(UNLIKELY(!context)) return AL_FALSE;
  104. std::lock_guard<std::mutex> _{context->PropLock};
  105. ALboolean value{AL_FALSE};
  106. switch(capability)
  107. {
  108. case AL_SOURCE_DISTANCE_MODEL:
  109. value = context->SourceDistanceModel;
  110. break;
  111. default:
  112. alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
  113. }
  114. return value;
  115. }
  116. END_API_FUNC
  117. AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
  118. START_API_FUNC
  119. {
  120. ContextRef context{GetContextRef()};
  121. if(UNLIKELY(!context)) return AL_FALSE;
  122. std::lock_guard<std::mutex> _{context->PropLock};
  123. ALboolean value{AL_FALSE};
  124. switch(pname)
  125. {
  126. case AL_DOPPLER_FACTOR:
  127. if(context->DopplerFactor != 0.0f)
  128. value = AL_TRUE;
  129. break;
  130. case AL_DOPPLER_VELOCITY:
  131. if(context->DopplerVelocity != 0.0f)
  132. value = AL_TRUE;
  133. break;
  134. case AL_DISTANCE_MODEL:
  135. if(context->mDistanceModel == DistanceModel::Default)
  136. value = AL_TRUE;
  137. break;
  138. case AL_SPEED_OF_SOUND:
  139. if(context->SpeedOfSound != 0.0f)
  140. value = AL_TRUE;
  141. break;
  142. case AL_DEFERRED_UPDATES_SOFT:
  143. if(context->DeferUpdates.load(std::memory_order_acquire))
  144. value = AL_TRUE;
  145. break;
  146. case AL_GAIN_LIMIT_SOFT:
  147. if(GAIN_MIX_MAX/context->GainBoost != 0.0f)
  148. value = AL_TRUE;
  149. break;
  150. case AL_NUM_RESAMPLERS_SOFT:
  151. /* Always non-0. */
  152. value = AL_TRUE;
  153. break;
  154. case AL_DEFAULT_RESAMPLER_SOFT:
  155. value = ResamplerDefault ? AL_TRUE : AL_FALSE;
  156. break;
  157. default:
  158. alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
  159. }
  160. return value;
  161. }
  162. END_API_FUNC
  163. AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
  164. START_API_FUNC
  165. {
  166. ContextRef context{GetContextRef()};
  167. if(UNLIKELY(!context)) return 0.0;
  168. std::lock_guard<std::mutex> _{context->PropLock};
  169. ALdouble value{0.0};
  170. switch(pname)
  171. {
  172. case AL_DOPPLER_FACTOR:
  173. value = static_cast<ALdouble>(context->DopplerFactor);
  174. break;
  175. case AL_DOPPLER_VELOCITY:
  176. value = static_cast<ALdouble>(context->DopplerVelocity);
  177. break;
  178. case AL_DISTANCE_MODEL:
  179. value = static_cast<ALdouble>(context->mDistanceModel);
  180. break;
  181. case AL_SPEED_OF_SOUND:
  182. value = static_cast<ALdouble>(context->SpeedOfSound);
  183. break;
  184. case AL_DEFERRED_UPDATES_SOFT:
  185. if(context->DeferUpdates.load(std::memory_order_acquire))
  186. value = static_cast<ALdouble>(AL_TRUE);
  187. break;
  188. case AL_GAIN_LIMIT_SOFT:
  189. value = static_cast<ALdouble>GAIN_MIX_MAX/context->GainBoost;
  190. break;
  191. case AL_NUM_RESAMPLERS_SOFT:
  192. value = static_cast<ALdouble>(ResamplerMax + 1);
  193. break;
  194. case AL_DEFAULT_RESAMPLER_SOFT:
  195. value = static_cast<ALdouble>(ResamplerDefault);
  196. break;
  197. default:
  198. alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
  199. }
  200. return value;
  201. }
  202. END_API_FUNC
  203. AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
  204. START_API_FUNC
  205. {
  206. ContextRef context{GetContextRef()};
  207. if(UNLIKELY(!context)) return 0.0f;
  208. std::lock_guard<std::mutex> _{context->PropLock};
  209. ALfloat value{0.0f};
  210. switch(pname)
  211. {
  212. case AL_DOPPLER_FACTOR:
  213. value = context->DopplerFactor;
  214. break;
  215. case AL_DOPPLER_VELOCITY:
  216. value = context->DopplerVelocity;
  217. break;
  218. case AL_DISTANCE_MODEL:
  219. value = static_cast<ALfloat>(context->mDistanceModel);
  220. break;
  221. case AL_SPEED_OF_SOUND:
  222. value = context->SpeedOfSound;
  223. break;
  224. case AL_DEFERRED_UPDATES_SOFT:
  225. if(context->DeferUpdates.load(std::memory_order_acquire))
  226. value = static_cast<ALfloat>(AL_TRUE);
  227. break;
  228. case AL_GAIN_LIMIT_SOFT:
  229. value = GAIN_MIX_MAX/context->GainBoost;
  230. break;
  231. case AL_NUM_RESAMPLERS_SOFT:
  232. value = static_cast<ALfloat>(ResamplerMax + 1);
  233. break;
  234. case AL_DEFAULT_RESAMPLER_SOFT:
  235. value = static_cast<ALfloat>(ResamplerDefault);
  236. break;
  237. default:
  238. alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
  239. }
  240. return value;
  241. }
  242. END_API_FUNC
  243. AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
  244. START_API_FUNC
  245. {
  246. ContextRef context{GetContextRef()};
  247. if(UNLIKELY(!context)) return 0;
  248. std::lock_guard<std::mutex> _{context->PropLock};
  249. ALint value{0};
  250. switch(pname)
  251. {
  252. case AL_DOPPLER_FACTOR:
  253. value = static_cast<ALint>(context->DopplerFactor);
  254. break;
  255. case AL_DOPPLER_VELOCITY:
  256. value = static_cast<ALint>(context->DopplerVelocity);
  257. break;
  258. case AL_DISTANCE_MODEL:
  259. value = static_cast<ALint>(context->mDistanceModel);
  260. break;
  261. case AL_SPEED_OF_SOUND:
  262. value = static_cast<ALint>(context->SpeedOfSound);
  263. break;
  264. case AL_DEFERRED_UPDATES_SOFT:
  265. if(context->DeferUpdates.load(std::memory_order_acquire))
  266. value = static_cast<ALint>(AL_TRUE);
  267. break;
  268. case AL_GAIN_LIMIT_SOFT:
  269. value = static_cast<ALint>(GAIN_MIX_MAX/context->GainBoost);
  270. break;
  271. case AL_NUM_RESAMPLERS_SOFT:
  272. value = ResamplerMax + 1;
  273. break;
  274. case AL_DEFAULT_RESAMPLER_SOFT:
  275. value = ResamplerDefault;
  276. break;
  277. default:
  278. alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
  279. }
  280. return value;
  281. }
  282. END_API_FUNC
  283. extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
  284. START_API_FUNC
  285. {
  286. ContextRef context{GetContextRef()};
  287. if(UNLIKELY(!context)) return 0;
  288. std::lock_guard<std::mutex> _{context->PropLock};
  289. ALint64SOFT value{0};
  290. switch(pname)
  291. {
  292. case AL_DOPPLER_FACTOR:
  293. value = (ALint64SOFT)context->DopplerFactor;
  294. break;
  295. case AL_DOPPLER_VELOCITY:
  296. value = (ALint64SOFT)context->DopplerVelocity;
  297. break;
  298. case AL_DISTANCE_MODEL:
  299. value = (ALint64SOFT)context->mDistanceModel;
  300. break;
  301. case AL_SPEED_OF_SOUND:
  302. value = (ALint64SOFT)context->SpeedOfSound;
  303. break;
  304. case AL_DEFERRED_UPDATES_SOFT:
  305. if(context->DeferUpdates.load(std::memory_order_acquire))
  306. value = (ALint64SOFT)AL_TRUE;
  307. break;
  308. case AL_GAIN_LIMIT_SOFT:
  309. value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
  310. break;
  311. case AL_NUM_RESAMPLERS_SOFT:
  312. value = (ALint64SOFT)(ResamplerMax + 1);
  313. break;
  314. case AL_DEFAULT_RESAMPLER_SOFT:
  315. value = (ALint64SOFT)ResamplerDefault;
  316. break;
  317. default:
  318. alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
  319. }
  320. return value;
  321. }
  322. END_API_FUNC
  323. AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname)
  324. START_API_FUNC
  325. {
  326. ContextRef context{GetContextRef()};
  327. if(UNLIKELY(!context)) return nullptr;
  328. std::lock_guard<std::mutex> _{context->PropLock};
  329. void *value{nullptr};
  330. switch(pname)
  331. {
  332. case AL_EVENT_CALLBACK_FUNCTION_SOFT:
  333. value = reinterpret_cast<void*>(context->EventCb);
  334. break;
  335. case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
  336. value = context->EventParam;
  337. break;
  338. default:
  339. alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
  340. }
  341. return value;
  342. }
  343. END_API_FUNC
  344. AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
  345. START_API_FUNC
  346. {
  347. if(values)
  348. {
  349. switch(pname)
  350. {
  351. case AL_DOPPLER_FACTOR:
  352. case AL_DOPPLER_VELOCITY:
  353. case AL_DISTANCE_MODEL:
  354. case AL_SPEED_OF_SOUND:
  355. case AL_DEFERRED_UPDATES_SOFT:
  356. case AL_GAIN_LIMIT_SOFT:
  357. case AL_NUM_RESAMPLERS_SOFT:
  358. case AL_DEFAULT_RESAMPLER_SOFT:
  359. values[0] = alGetBoolean(pname);
  360. return;
  361. }
  362. }
  363. ContextRef context{GetContextRef()};
  364. if(UNLIKELY(!context)) return;
  365. if(!values)
  366. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  367. else switch(pname)
  368. {
  369. default:
  370. alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
  371. }
  372. }
  373. END_API_FUNC
  374. AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
  375. START_API_FUNC
  376. {
  377. if(values)
  378. {
  379. switch(pname)
  380. {
  381. case AL_DOPPLER_FACTOR:
  382. case AL_DOPPLER_VELOCITY:
  383. case AL_DISTANCE_MODEL:
  384. case AL_SPEED_OF_SOUND:
  385. case AL_DEFERRED_UPDATES_SOFT:
  386. case AL_GAIN_LIMIT_SOFT:
  387. case AL_NUM_RESAMPLERS_SOFT:
  388. case AL_DEFAULT_RESAMPLER_SOFT:
  389. values[0] = alGetDouble(pname);
  390. return;
  391. }
  392. }
  393. ContextRef context{GetContextRef()};
  394. if(UNLIKELY(!context)) return;
  395. if(!values)
  396. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  397. else switch(pname)
  398. {
  399. default:
  400. alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
  401. }
  402. }
  403. END_API_FUNC
  404. AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
  405. START_API_FUNC
  406. {
  407. if(values)
  408. {
  409. switch(pname)
  410. {
  411. case AL_DOPPLER_FACTOR:
  412. case AL_DOPPLER_VELOCITY:
  413. case AL_DISTANCE_MODEL:
  414. case AL_SPEED_OF_SOUND:
  415. case AL_DEFERRED_UPDATES_SOFT:
  416. case AL_GAIN_LIMIT_SOFT:
  417. case AL_NUM_RESAMPLERS_SOFT:
  418. case AL_DEFAULT_RESAMPLER_SOFT:
  419. values[0] = alGetFloat(pname);
  420. return;
  421. }
  422. }
  423. ContextRef context{GetContextRef()};
  424. if(UNLIKELY(!context)) return;
  425. if(!values)
  426. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  427. else switch(pname)
  428. {
  429. default:
  430. alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
  431. }
  432. }
  433. END_API_FUNC
  434. AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
  435. START_API_FUNC
  436. {
  437. if(values)
  438. {
  439. switch(pname)
  440. {
  441. case AL_DOPPLER_FACTOR:
  442. case AL_DOPPLER_VELOCITY:
  443. case AL_DISTANCE_MODEL:
  444. case AL_SPEED_OF_SOUND:
  445. case AL_DEFERRED_UPDATES_SOFT:
  446. case AL_GAIN_LIMIT_SOFT:
  447. case AL_NUM_RESAMPLERS_SOFT:
  448. case AL_DEFAULT_RESAMPLER_SOFT:
  449. values[0] = alGetInteger(pname);
  450. return;
  451. }
  452. }
  453. ContextRef context{GetContextRef()};
  454. if(UNLIKELY(!context)) return;
  455. if(!values)
  456. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  457. else switch(pname)
  458. {
  459. default:
  460. alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
  461. }
  462. }
  463. END_API_FUNC
  464. extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
  465. START_API_FUNC
  466. {
  467. if(values)
  468. {
  469. switch(pname)
  470. {
  471. case AL_DOPPLER_FACTOR:
  472. case AL_DOPPLER_VELOCITY:
  473. case AL_DISTANCE_MODEL:
  474. case AL_SPEED_OF_SOUND:
  475. case AL_DEFERRED_UPDATES_SOFT:
  476. case AL_GAIN_LIMIT_SOFT:
  477. case AL_NUM_RESAMPLERS_SOFT:
  478. case AL_DEFAULT_RESAMPLER_SOFT:
  479. values[0] = alGetInteger64SOFT(pname);
  480. return;
  481. }
  482. }
  483. ContextRef context{GetContextRef()};
  484. if(UNLIKELY(!context)) return;
  485. if(!values)
  486. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  487. else switch(pname)
  488. {
  489. default:
  490. alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
  491. }
  492. }
  493. END_API_FUNC
  494. AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values)
  495. START_API_FUNC
  496. {
  497. if(values)
  498. {
  499. switch(pname)
  500. {
  501. case AL_EVENT_CALLBACK_FUNCTION_SOFT:
  502. case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
  503. values[0] = alGetPointerSOFT(pname);
  504. return;
  505. }
  506. }
  507. ContextRef context{GetContextRef()};
  508. if(UNLIKELY(!context)) return;
  509. if(!values)
  510. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  511. else switch(pname)
  512. {
  513. default:
  514. alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
  515. }
  516. }
  517. END_API_FUNC
  518. AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
  519. START_API_FUNC
  520. {
  521. ContextRef context{GetContextRef()};
  522. if(UNLIKELY(!context)) return nullptr;
  523. const ALchar *value{nullptr};
  524. switch(pname)
  525. {
  526. case AL_VENDOR:
  527. value = alVendor;
  528. break;
  529. case AL_VERSION:
  530. value = alVersion;
  531. break;
  532. case AL_RENDERER:
  533. value = alRenderer;
  534. break;
  535. case AL_EXTENSIONS:
  536. value = context->ExtensionList;
  537. break;
  538. case AL_NO_ERROR:
  539. value = alNoError;
  540. break;
  541. case AL_INVALID_NAME:
  542. value = alErrInvalidName;
  543. break;
  544. case AL_INVALID_ENUM:
  545. value = alErrInvalidEnum;
  546. break;
  547. case AL_INVALID_VALUE:
  548. value = alErrInvalidValue;
  549. break;
  550. case AL_INVALID_OPERATION:
  551. value = alErrInvalidOp;
  552. break;
  553. case AL_OUT_OF_MEMORY:
  554. value = alErrOutOfMemory;
  555. break;
  556. default:
  557. alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
  558. }
  559. return value;
  560. }
  561. END_API_FUNC
  562. AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
  563. START_API_FUNC
  564. {
  565. ContextRef context{GetContextRef()};
  566. if(UNLIKELY(!context)) return;
  567. if(!(value >= 0.0f && std::isfinite(value)))
  568. alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value);
  569. else
  570. {
  571. std::lock_guard<std::mutex> _{context->PropLock};
  572. context->DopplerFactor = value;
  573. DO_UPDATEPROPS();
  574. }
  575. }
  576. END_API_FUNC
  577. AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
  578. START_API_FUNC
  579. {
  580. ContextRef context{GetContextRef()};
  581. if(UNLIKELY(!context)) return;
  582. if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated))
  583. {
  584. static constexpr ALCchar msg[] =
  585. "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound";
  586. const ALsizei msglen = static_cast<ALsizei>(strlen(msg));
  587. std::lock_guard<std::mutex> _{context->EventCbLock};
  588. ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)};
  589. if((enabledevts&EventType_Deprecated) && context->EventCb)
  590. (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg,
  591. context->EventParam);
  592. }
  593. if(!(value >= 0.0f && std::isfinite(value)))
  594. alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
  595. else
  596. {
  597. std::lock_guard<std::mutex> _{context->PropLock};
  598. context->DopplerVelocity = value;
  599. DO_UPDATEPROPS();
  600. }
  601. }
  602. END_API_FUNC
  603. AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
  604. START_API_FUNC
  605. {
  606. ContextRef context{GetContextRef()};
  607. if(UNLIKELY(!context)) return;
  608. if(!(value > 0.0f && std::isfinite(value)))
  609. alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value);
  610. else
  611. {
  612. std::lock_guard<std::mutex> _{context->PropLock};
  613. context->SpeedOfSound = value;
  614. DO_UPDATEPROPS();
  615. }
  616. }
  617. END_API_FUNC
  618. AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
  619. START_API_FUNC
  620. {
  621. ContextRef context{GetContextRef()};
  622. if(UNLIKELY(!context)) return;
  623. if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED ||
  624. value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
  625. value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
  626. value == AL_NONE))
  627. alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
  628. else
  629. {
  630. std::lock_guard<std::mutex> _{context->PropLock};
  631. context->mDistanceModel = static_cast<DistanceModel>(value);
  632. if(!context->SourceDistanceModel)
  633. DO_UPDATEPROPS();
  634. }
  635. }
  636. END_API_FUNC
  637. AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
  638. START_API_FUNC
  639. {
  640. ContextRef context{GetContextRef()};
  641. if(UNLIKELY(!context)) return;
  642. ALCcontext_DeferUpdates(context.get());
  643. }
  644. END_API_FUNC
  645. AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
  646. START_API_FUNC
  647. {
  648. ContextRef context{GetContextRef()};
  649. if(UNLIKELY(!context)) return;
  650. ALCcontext_ProcessUpdates(context.get());
  651. }
  652. END_API_FUNC
  653. AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
  654. START_API_FUNC
  655. {
  656. const char *ResamplerNames[] = {
  657. alPointResampler, alLinearResampler,
  658. alCubicResampler, alBSinc12Resampler,
  659. alBSinc24Resampler,
  660. };
  661. static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
  662. ContextRef context{GetContextRef()};
  663. if(UNLIKELY(!context)) return nullptr;
  664. const ALchar *value{nullptr};
  665. switch(pname)
  666. {
  667. case AL_RESAMPLER_NAME_SOFT:
  668. if(index < 0 || static_cast<size_t>(index) >= COUNTOF(ResamplerNames))
  669. alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range",
  670. index);
  671. else
  672. value = ResamplerNames[index];
  673. break;
  674. default:
  675. alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property");
  676. }
  677. return value;
  678. }
  679. END_API_FUNC
  680. void UpdateContextProps(ALCcontext *context)
  681. {
  682. /* Get an unused proprty container, or allocate a new one as needed. */
  683. ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)};
  684. if(!props)
  685. props = static_cast<ALcontextProps*>(al_calloc(16, sizeof(*props)));
  686. else
  687. {
  688. ALcontextProps *next;
  689. do {
  690. next = props->next.load(std::memory_order_relaxed);
  691. } while(context->FreeContextProps.compare_exchange_weak(props, next,
  692. std::memory_order_seq_cst, std::memory_order_acquire) == 0);
  693. }
  694. /* Copy in current property values. */
  695. props->MetersPerUnit = context->MetersPerUnit;
  696. props->DopplerFactor = context->DopplerFactor;
  697. props->DopplerVelocity = context->DopplerVelocity;
  698. props->SpeedOfSound = context->SpeedOfSound;
  699. props->SourceDistanceModel = context->SourceDistanceModel;
  700. props->mDistanceModel = context->mDistanceModel;
  701. /* Set the new container for updating internal parameters. */
  702. props = context->Update.exchange(props, std::memory_order_acq_rel);
  703. if(props)
  704. {
  705. /* If there was an unused update container, put it back in the
  706. * freelist.
  707. */
  708. AtomicReplaceHead(context->FreeContextProps, props);
  709. }
  710. }