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

765 lines
23 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 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 "effect.h"
  22. #include <algorithm>
  23. #include <cstdint>
  24. #include <cstring>
  25. #include <iterator>
  26. #include <memory>
  27. #include <mutex>
  28. #include <new>
  29. #include <numeric>
  30. #include <utility>
  31. #include "AL/al.h"
  32. #include "AL/alc.h"
  33. #include "AL/alext.h"
  34. #include "AL/efx-presets.h"
  35. #include "AL/efx.h"
  36. #include "albit.h"
  37. #include "alc/context.h"
  38. #include "alc/device.h"
  39. #include "alc/effects/base.h"
  40. #include "alc/inprogext.h"
  41. #include "almalloc.h"
  42. #include "alnumeric.h"
  43. #include "alstring.h"
  44. #include "core/except.h"
  45. #include "core/logging.h"
  46. #include "opthelpers.h"
  47. #include "vector.h"
  48. #ifdef ALSOFT_EAX
  49. #include <cassert>
  50. #include "eax/exception.h"
  51. #endif // ALSOFT_EAX
  52. const EffectList gEffectList[16]{
  53. { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
  54. { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
  55. { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
  56. { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
  57. { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
  58. { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
  59. { "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
  60. { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
  61. { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
  62. { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
  63. { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
  64. { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
  65. { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER },
  66. { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
  67. { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
  68. { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_REVERB_SOFT },
  69. };
  70. bool DisabledEffects[MAX_EFFECTS];
  71. effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
  72. {
  73. std::va_list args;
  74. va_start(args, msg);
  75. setMessage(msg, args);
  76. va_end(args);
  77. }
  78. namespace {
  79. struct EffectPropsItem {
  80. ALenum Type;
  81. const EffectProps &DefaultProps;
  82. const EffectVtable &Vtable;
  83. };
  84. constexpr EffectPropsItem EffectPropsList[] = {
  85. { AL_EFFECT_NULL, NullEffectProps, NullEffectVtable },
  86. { AL_EFFECT_EAXREVERB, ReverbEffectProps, ReverbEffectVtable },
  87. { AL_EFFECT_REVERB, StdReverbEffectProps, StdReverbEffectVtable },
  88. { AL_EFFECT_AUTOWAH, AutowahEffectProps, AutowahEffectVtable },
  89. { AL_EFFECT_CHORUS, ChorusEffectProps, ChorusEffectVtable },
  90. { AL_EFFECT_COMPRESSOR, CompressorEffectProps, CompressorEffectVtable },
  91. { AL_EFFECT_DISTORTION, DistortionEffectProps, DistortionEffectVtable },
  92. { AL_EFFECT_ECHO, EchoEffectProps, EchoEffectVtable },
  93. { AL_EFFECT_EQUALIZER, EqualizerEffectProps, EqualizerEffectVtable },
  94. { AL_EFFECT_FLANGER, FlangerEffectProps, FlangerEffectVtable },
  95. { AL_EFFECT_FREQUENCY_SHIFTER, FshifterEffectProps, FshifterEffectVtable },
  96. { AL_EFFECT_RING_MODULATOR, ModulatorEffectProps, ModulatorEffectVtable },
  97. { AL_EFFECT_PITCH_SHIFTER, PshifterEffectProps, PshifterEffectVtable },
  98. { AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable },
  99. { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable },
  100. { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable },
  101. { AL_EFFECT_CONVOLUTION_REVERB_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable },
  102. };
  103. void ALeffect_setParami(ALeffect *effect, ALenum param, int value)
  104. { effect->vtab->setParami(&effect->Props, param, value); }
  105. void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values)
  106. { effect->vtab->setParamiv(&effect->Props, param, values); }
  107. void ALeffect_setParamf(ALeffect *effect, ALenum param, float value)
  108. { effect->vtab->setParamf(&effect->Props, param, value); }
  109. void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values)
  110. { effect->vtab->setParamfv(&effect->Props, param, values); }
  111. void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value)
  112. { effect->vtab->getParami(&effect->Props, param, value); }
  113. void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values)
  114. { effect->vtab->getParamiv(&effect->Props, param, values); }
  115. void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value)
  116. { effect->vtab->getParamf(&effect->Props, param, value); }
  117. void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values)
  118. { effect->vtab->getParamfv(&effect->Props, param, values); }
  119. const EffectPropsItem *getEffectPropsItemByType(ALenum type)
  120. {
  121. auto iter = std::find_if(std::begin(EffectPropsList), std::end(EffectPropsList),
  122. [type](const EffectPropsItem &item) noexcept -> bool
  123. { return item.Type == type; });
  124. return (iter != std::end(EffectPropsList)) ? std::addressof(*iter) : nullptr;
  125. }
  126. void InitEffectParams(ALeffect *effect, ALenum type)
  127. {
  128. const EffectPropsItem *item{getEffectPropsItemByType(type)};
  129. if(item)
  130. {
  131. effect->Props = item->DefaultProps;
  132. effect->vtab = &item->Vtable;
  133. }
  134. else
  135. {
  136. effect->Props = EffectProps{};
  137. effect->vtab = &NullEffectVtable;
  138. }
  139. effect->type = type;
  140. }
  141. bool EnsureEffects(ALCdevice *device, size_t needed)
  142. {
  143. size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
  144. [](size_t cur, const EffectSubList &sublist) noexcept -> size_t
  145. { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
  146. while(needed > count)
  147. {
  148. if UNLIKELY(device->EffectList.size() >= 1<<25)
  149. return false;
  150. device->EffectList.emplace_back();
  151. auto sublist = device->EffectList.end() - 1;
  152. sublist->FreeMask = ~0_u64;
  153. sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
  154. if UNLIKELY(!sublist->Effects)
  155. {
  156. device->EffectList.pop_back();
  157. return false;
  158. }
  159. count += 64;
  160. }
  161. return true;
  162. }
  163. ALeffect *AllocEffect(ALCdevice *device)
  164. {
  165. auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
  166. [](const EffectSubList &entry) noexcept -> bool
  167. { return entry.FreeMask != 0; });
  168. auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
  169. auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
  170. ASSUME(slidx < 64);
  171. ALeffect *effect{al::construct_at(sublist->Effects + slidx)};
  172. InitEffectParams(effect, AL_EFFECT_NULL);
  173. /* Add 1 to avoid effect ID 0. */
  174. effect->id = ((lidx<<6) | slidx) + 1;
  175. sublist->FreeMask &= ~(1_u64 << slidx);
  176. return effect;
  177. }
  178. void FreeEffect(ALCdevice *device, ALeffect *effect)
  179. {
  180. const ALuint id{effect->id - 1};
  181. const size_t lidx{id >> 6};
  182. const ALuint slidx{id & 0x3f};
  183. al::destroy_at(effect);
  184. device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
  185. }
  186. inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
  187. {
  188. const size_t lidx{(id-1) >> 6};
  189. const ALuint slidx{(id-1) & 0x3f};
  190. if UNLIKELY(lidx >= device->EffectList.size())
  191. return nullptr;
  192. EffectSubList &sublist = device->EffectList[lidx];
  193. if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
  194. return nullptr;
  195. return sublist.Effects + slidx;
  196. }
  197. } // namespace
  198. AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
  199. START_API_FUNC
  200. {
  201. ContextRef context{GetContextRef()};
  202. if UNLIKELY(!context) return;
  203. if UNLIKELY(n < 0)
  204. context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
  205. if UNLIKELY(n <= 0) return;
  206. ALCdevice *device{context->mALDevice.get()};
  207. std::lock_guard<std::mutex> _{device->EffectLock};
  208. if(!EnsureEffects(device, static_cast<ALuint>(n)))
  209. {
  210. context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
  211. return;
  212. }
  213. if LIKELY(n == 1)
  214. {
  215. /* Special handling for the easy and normal case. */
  216. ALeffect *effect{AllocEffect(device)};
  217. effects[0] = effect->id;
  218. }
  219. else
  220. {
  221. /* Store the allocated buffer IDs in a separate local list, to avoid
  222. * modifying the user storage in case of failure.
  223. */
  224. al::vector<ALuint> ids;
  225. ids.reserve(static_cast<ALuint>(n));
  226. do {
  227. ALeffect *effect{AllocEffect(device)};
  228. ids.emplace_back(effect->id);
  229. } while(--n);
  230. std::copy(ids.cbegin(), ids.cend(), effects);
  231. }
  232. }
  233. END_API_FUNC
  234. AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
  235. START_API_FUNC
  236. {
  237. ContextRef context{GetContextRef()};
  238. if UNLIKELY(!context) return;
  239. if UNLIKELY(n < 0)
  240. context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
  241. if UNLIKELY(n <= 0) return;
  242. ALCdevice *device{context->mALDevice.get()};
  243. std::lock_guard<std::mutex> _{device->EffectLock};
  244. /* First try to find any effects that are invalid. */
  245. auto validate_effect = [device](const ALuint eid) -> bool
  246. { return !eid || LookupEffect(device, eid) != nullptr; };
  247. const ALuint *effects_end = effects + n;
  248. auto inveffect = std::find_if_not(effects, effects_end, validate_effect);
  249. if UNLIKELY(inveffect != effects_end)
  250. {
  251. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
  252. return;
  253. }
  254. /* All good. Delete non-0 effect IDs. */
  255. auto delete_effect = [device](ALuint eid) -> void
  256. {
  257. ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
  258. if(effect) FreeEffect(device, effect);
  259. };
  260. std::for_each(effects, effects_end, delete_effect);
  261. }
  262. END_API_FUNC
  263. AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
  264. START_API_FUNC
  265. {
  266. ContextRef context{GetContextRef()};
  267. if LIKELY(context)
  268. {
  269. ALCdevice *device{context->mALDevice.get()};
  270. std::lock_guard<std::mutex> _{device->EffectLock};
  271. if(!effect || LookupEffect(device, effect))
  272. return AL_TRUE;
  273. }
  274. return AL_FALSE;
  275. }
  276. END_API_FUNC
  277. AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
  278. START_API_FUNC
  279. {
  280. ContextRef context{GetContextRef()};
  281. if UNLIKELY(!context) return;
  282. ALCdevice *device{context->mALDevice.get()};
  283. std::lock_guard<std::mutex> _{device->EffectLock};
  284. ALeffect *aleffect{LookupEffect(device, effect)};
  285. if UNLIKELY(!aleffect)
  286. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  287. else if(param == AL_EFFECT_TYPE)
  288. {
  289. bool isOk{value == AL_EFFECT_NULL};
  290. if(!isOk)
  291. {
  292. for(const EffectList &effectitem : gEffectList)
  293. {
  294. if(value == effectitem.val && !DisabledEffects[effectitem.type])
  295. {
  296. isOk = true;
  297. break;
  298. }
  299. }
  300. }
  301. if(isOk)
  302. InitEffectParams(aleffect, value);
  303. else
  304. context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
  305. }
  306. else try
  307. {
  308. /* Call the appropriate handler */
  309. ALeffect_setParami(aleffect, param, value);
  310. }
  311. catch(effect_exception &e) {
  312. context->setError(e.errorCode(), "%s", e.what());
  313. }
  314. }
  315. END_API_FUNC
  316. AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
  317. START_API_FUNC
  318. {
  319. switch(param)
  320. {
  321. case AL_EFFECT_TYPE:
  322. alEffecti(effect, param, values[0]);
  323. return;
  324. }
  325. ContextRef context{GetContextRef()};
  326. if UNLIKELY(!context) return;
  327. ALCdevice *device{context->mALDevice.get()};
  328. std::lock_guard<std::mutex> _{device->EffectLock};
  329. ALeffect *aleffect{LookupEffect(device, effect)};
  330. if UNLIKELY(!aleffect)
  331. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  332. else try
  333. {
  334. /* Call the appropriate handler */
  335. ALeffect_setParamiv(aleffect, param, values);
  336. }
  337. catch(effect_exception &e) {
  338. context->setError(e.errorCode(), "%s", e.what());
  339. }
  340. }
  341. END_API_FUNC
  342. AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
  343. START_API_FUNC
  344. {
  345. ContextRef context{GetContextRef()};
  346. if UNLIKELY(!context) return;
  347. ALCdevice *device{context->mALDevice.get()};
  348. std::lock_guard<std::mutex> _{device->EffectLock};
  349. ALeffect *aleffect{LookupEffect(device, effect)};
  350. if UNLIKELY(!aleffect)
  351. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  352. else try
  353. {
  354. /* Call the appropriate handler */
  355. ALeffect_setParamf(aleffect, param, value);
  356. }
  357. catch(effect_exception &e) {
  358. context->setError(e.errorCode(), "%s", e.what());
  359. }
  360. }
  361. END_API_FUNC
  362. AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
  363. START_API_FUNC
  364. {
  365. ContextRef context{GetContextRef()};
  366. if UNLIKELY(!context) return;
  367. ALCdevice *device{context->mALDevice.get()};
  368. std::lock_guard<std::mutex> _{device->EffectLock};
  369. ALeffect *aleffect{LookupEffect(device, effect)};
  370. if UNLIKELY(!aleffect)
  371. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  372. else try
  373. {
  374. /* Call the appropriate handler */
  375. ALeffect_setParamfv(aleffect, param, values);
  376. }
  377. catch(effect_exception &e) {
  378. context->setError(e.errorCode(), "%s", e.what());
  379. }
  380. }
  381. END_API_FUNC
  382. AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
  383. START_API_FUNC
  384. {
  385. ContextRef context{GetContextRef()};
  386. if UNLIKELY(!context) return;
  387. ALCdevice *device{context->mALDevice.get()};
  388. std::lock_guard<std::mutex> _{device->EffectLock};
  389. const ALeffect *aleffect{LookupEffect(device, effect)};
  390. if UNLIKELY(!aleffect)
  391. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  392. else if(param == AL_EFFECT_TYPE)
  393. *value = aleffect->type;
  394. else try
  395. {
  396. /* Call the appropriate handler */
  397. ALeffect_getParami(aleffect, param, value);
  398. }
  399. catch(effect_exception &e) {
  400. context->setError(e.errorCode(), "%s", e.what());
  401. }
  402. }
  403. END_API_FUNC
  404. AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
  405. START_API_FUNC
  406. {
  407. switch(param)
  408. {
  409. case AL_EFFECT_TYPE:
  410. alGetEffecti(effect, param, values);
  411. return;
  412. }
  413. ContextRef context{GetContextRef()};
  414. if UNLIKELY(!context) return;
  415. ALCdevice *device{context->mALDevice.get()};
  416. std::lock_guard<std::mutex> _{device->EffectLock};
  417. const ALeffect *aleffect{LookupEffect(device, effect)};
  418. if UNLIKELY(!aleffect)
  419. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  420. else try
  421. {
  422. /* Call the appropriate handler */
  423. ALeffect_getParamiv(aleffect, param, values);
  424. }
  425. catch(effect_exception &e) {
  426. context->setError(e.errorCode(), "%s", e.what());
  427. }
  428. }
  429. END_API_FUNC
  430. AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
  431. START_API_FUNC
  432. {
  433. ContextRef context{GetContextRef()};
  434. if UNLIKELY(!context) return;
  435. ALCdevice *device{context->mALDevice.get()};
  436. std::lock_guard<std::mutex> _{device->EffectLock};
  437. const ALeffect *aleffect{LookupEffect(device, effect)};
  438. if UNLIKELY(!aleffect)
  439. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  440. else try
  441. {
  442. /* Call the appropriate handler */
  443. ALeffect_getParamf(aleffect, param, value);
  444. }
  445. catch(effect_exception &e) {
  446. context->setError(e.errorCode(), "%s", e.what());
  447. }
  448. }
  449. END_API_FUNC
  450. AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
  451. START_API_FUNC
  452. {
  453. ContextRef context{GetContextRef()};
  454. if UNLIKELY(!context) return;
  455. ALCdevice *device{context->mALDevice.get()};
  456. std::lock_guard<std::mutex> _{device->EffectLock};
  457. const ALeffect *aleffect{LookupEffect(device, effect)};
  458. if UNLIKELY(!aleffect)
  459. context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
  460. else try
  461. {
  462. /* Call the appropriate handler */
  463. ALeffect_getParamfv(aleffect, param, values);
  464. }
  465. catch(effect_exception &e) {
  466. context->setError(e.errorCode(), "%s", e.what());
  467. }
  468. }
  469. END_API_FUNC
  470. void InitEffect(ALeffect *effect)
  471. {
  472. InitEffectParams(effect, AL_EFFECT_NULL);
  473. }
  474. EffectSubList::~EffectSubList()
  475. {
  476. uint64_t usemask{~FreeMask};
  477. while(usemask)
  478. {
  479. const int idx{al::countr_zero(usemask)};
  480. al::destroy_at(Effects+idx);
  481. usemask &= ~(1_u64 << idx);
  482. }
  483. FreeMask = ~usemask;
  484. al_free(Effects);
  485. Effects = nullptr;
  486. }
  487. #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
  488. static const struct {
  489. const char name[32];
  490. EFXEAXREVERBPROPERTIES props;
  491. } reverblist[] = {
  492. DECL(GENERIC),
  493. DECL(PADDEDCELL),
  494. DECL(ROOM),
  495. DECL(BATHROOM),
  496. DECL(LIVINGROOM),
  497. DECL(STONEROOM),
  498. DECL(AUDITORIUM),
  499. DECL(CONCERTHALL),
  500. DECL(CAVE),
  501. DECL(ARENA),
  502. DECL(HANGAR),
  503. DECL(CARPETEDHALLWAY),
  504. DECL(HALLWAY),
  505. DECL(STONECORRIDOR),
  506. DECL(ALLEY),
  507. DECL(FOREST),
  508. DECL(CITY),
  509. DECL(MOUNTAINS),
  510. DECL(QUARRY),
  511. DECL(PLAIN),
  512. DECL(PARKINGLOT),
  513. DECL(SEWERPIPE),
  514. DECL(UNDERWATER),
  515. DECL(DRUGGED),
  516. DECL(DIZZY),
  517. DECL(PSYCHOTIC),
  518. DECL(CASTLE_SMALLROOM),
  519. DECL(CASTLE_SHORTPASSAGE),
  520. DECL(CASTLE_MEDIUMROOM),
  521. DECL(CASTLE_LARGEROOM),
  522. DECL(CASTLE_LONGPASSAGE),
  523. DECL(CASTLE_HALL),
  524. DECL(CASTLE_CUPBOARD),
  525. DECL(CASTLE_COURTYARD),
  526. DECL(CASTLE_ALCOVE),
  527. DECL(FACTORY_SMALLROOM),
  528. DECL(FACTORY_SHORTPASSAGE),
  529. DECL(FACTORY_MEDIUMROOM),
  530. DECL(FACTORY_LARGEROOM),
  531. DECL(FACTORY_LONGPASSAGE),
  532. DECL(FACTORY_HALL),
  533. DECL(FACTORY_CUPBOARD),
  534. DECL(FACTORY_COURTYARD),
  535. DECL(FACTORY_ALCOVE),
  536. DECL(ICEPALACE_SMALLROOM),
  537. DECL(ICEPALACE_SHORTPASSAGE),
  538. DECL(ICEPALACE_MEDIUMROOM),
  539. DECL(ICEPALACE_LARGEROOM),
  540. DECL(ICEPALACE_LONGPASSAGE),
  541. DECL(ICEPALACE_HALL),
  542. DECL(ICEPALACE_CUPBOARD),
  543. DECL(ICEPALACE_COURTYARD),
  544. DECL(ICEPALACE_ALCOVE),
  545. DECL(SPACESTATION_SMALLROOM),
  546. DECL(SPACESTATION_SHORTPASSAGE),
  547. DECL(SPACESTATION_MEDIUMROOM),
  548. DECL(SPACESTATION_LARGEROOM),
  549. DECL(SPACESTATION_LONGPASSAGE),
  550. DECL(SPACESTATION_HALL),
  551. DECL(SPACESTATION_CUPBOARD),
  552. DECL(SPACESTATION_ALCOVE),
  553. DECL(WOODEN_SMALLROOM),
  554. DECL(WOODEN_SHORTPASSAGE),
  555. DECL(WOODEN_MEDIUMROOM),
  556. DECL(WOODEN_LARGEROOM),
  557. DECL(WOODEN_LONGPASSAGE),
  558. DECL(WOODEN_HALL),
  559. DECL(WOODEN_CUPBOARD),
  560. DECL(WOODEN_COURTYARD),
  561. DECL(WOODEN_ALCOVE),
  562. DECL(SPORT_EMPTYSTADIUM),
  563. DECL(SPORT_SQUASHCOURT),
  564. DECL(SPORT_SMALLSWIMMINGPOOL),
  565. DECL(SPORT_LARGESWIMMINGPOOL),
  566. DECL(SPORT_GYMNASIUM),
  567. DECL(SPORT_FULLSTADIUM),
  568. DECL(SPORT_STADIUMTANNOY),
  569. DECL(PREFAB_WORKSHOP),
  570. DECL(PREFAB_SCHOOLROOM),
  571. DECL(PREFAB_PRACTISEROOM),
  572. DECL(PREFAB_OUTHOUSE),
  573. DECL(PREFAB_CARAVAN),
  574. DECL(DOME_TOMB),
  575. DECL(PIPE_SMALL),
  576. DECL(DOME_SAINTPAULS),
  577. DECL(PIPE_LONGTHIN),
  578. DECL(PIPE_LARGE),
  579. DECL(PIPE_RESONANT),
  580. DECL(OUTDOORS_BACKYARD),
  581. DECL(OUTDOORS_ROLLINGPLAINS),
  582. DECL(OUTDOORS_DEEPCANYON),
  583. DECL(OUTDOORS_CREEK),
  584. DECL(OUTDOORS_VALLEY),
  585. DECL(MOOD_HEAVEN),
  586. DECL(MOOD_HELL),
  587. DECL(MOOD_MEMORY),
  588. DECL(DRIVING_COMMENTATOR),
  589. DECL(DRIVING_PITGARAGE),
  590. DECL(DRIVING_INCAR_RACER),
  591. DECL(DRIVING_INCAR_SPORTS),
  592. DECL(DRIVING_INCAR_LUXURY),
  593. DECL(DRIVING_FULLGRANDSTAND),
  594. DECL(DRIVING_EMPTYGRANDSTAND),
  595. DECL(DRIVING_TUNNEL),
  596. DECL(CITY_STREETS),
  597. DECL(CITY_SUBWAY),
  598. DECL(CITY_MUSEUM),
  599. DECL(CITY_LIBRARY),
  600. DECL(CITY_UNDERPASS),
  601. DECL(CITY_ABANDONED),
  602. DECL(DUSTYROOM),
  603. DECL(CHAPEL),
  604. DECL(SMALLWATERROOM),
  605. };
  606. #undef DECL
  607. void LoadReverbPreset(const char *name, ALeffect *effect)
  608. {
  609. if(al::strcasecmp(name, "NONE") == 0)
  610. {
  611. InitEffectParams(effect, AL_EFFECT_NULL);
  612. TRACE("Loading reverb '%s'\n", "NONE");
  613. return;
  614. }
  615. if(!DisabledEffects[EAXREVERB_EFFECT])
  616. InitEffectParams(effect, AL_EFFECT_EAXREVERB);
  617. else if(!DisabledEffects[REVERB_EFFECT])
  618. InitEffectParams(effect, AL_EFFECT_REVERB);
  619. else
  620. InitEffectParams(effect, AL_EFFECT_NULL);
  621. for(const auto &reverbitem : reverblist)
  622. {
  623. const EFXEAXREVERBPROPERTIES *props;
  624. if(al::strcasecmp(name, reverbitem.name) != 0)
  625. continue;
  626. TRACE("Loading reverb '%s'\n", reverbitem.name);
  627. props = &reverbitem.props;
  628. effect->Props.Reverb.Density = props->flDensity;
  629. effect->Props.Reverb.Diffusion = props->flDiffusion;
  630. effect->Props.Reverb.Gain = props->flGain;
  631. effect->Props.Reverb.GainHF = props->flGainHF;
  632. effect->Props.Reverb.GainLF = props->flGainLF;
  633. effect->Props.Reverb.DecayTime = props->flDecayTime;
  634. effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
  635. effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
  636. effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
  637. effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
  638. effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
  639. effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
  640. effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
  641. effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
  642. effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
  643. effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
  644. effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
  645. effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
  646. effect->Props.Reverb.EchoTime = props->flEchoTime;
  647. effect->Props.Reverb.EchoDepth = props->flEchoDepth;
  648. effect->Props.Reverb.ModulationTime = props->flModulationTime;
  649. effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
  650. effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
  651. effect->Props.Reverb.HFReference = props->flHFReference;
  652. effect->Props.Reverb.LFReference = props->flLFReference;
  653. effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
  654. effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
  655. return;
  656. }
  657. WARN("Reverb preset '%s' not found\n", name);
  658. }
  659. bool IsValidEffectType(ALenum type) noexcept
  660. {
  661. if(type == AL_EFFECT_NULL)
  662. return true;
  663. for(const auto &effect_item : gEffectList)
  664. {
  665. if(type == effect_item.val && !DisabledEffects[effect_item.type])
  666. return true;
  667. }
  668. return false;
  669. }