Avoid using preexisting enum values
[openal-soft.git] / al / effect.cpp
blob29c563973b5652403feb81f6c6b806d059d8f94f
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.
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.
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
21 #include "config.h"
23 #include "effect.h"
25 #include <algorithm>
26 #include <cstdarg>
27 #include <cstdint>
28 #include <cstring>
29 #include <iterator>
30 #include <memory>
31 #include <mutex>
32 #include <numeric>
33 #include <string>
34 #include <type_traits>
35 #include <unordered_map>
36 #include <utility>
37 #include <variant>
38 #include <vector>
40 #include "AL/al.h"
41 #include "AL/alc.h"
42 #include "AL/alext.h"
43 #include "AL/efx-presets.h"
44 #include "AL/efx.h"
46 #include "al/effects/effects.h"
47 #include "albit.h"
48 #include "alc/context.h"
49 #include "alc/device.h"
50 #include "alc/inprogext.h"
51 #include "almalloc.h"
52 #include "alnumeric.h"
53 #include "alspan.h"
54 #include "alstring.h"
55 #include "core/logging.h"
56 #include "direct_defs.h"
57 #include "intrusive_ptr.h"
58 #include "opthelpers.h"
61 const std::array<EffectList,16> gEffectList{{
62 { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
63 { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
64 { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
65 { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
66 { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
67 { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
68 { "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
69 { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
70 { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
71 { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
72 { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
73 { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
74 { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER },
75 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
76 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
77 { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_SOFT },
78 }};
81 effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
83 /* NOLINTBEGIN(*-array-to-pointer-decay) */
84 std::va_list args;
85 va_start(args, msg);
86 setMessage(msg, args);
87 va_end(args);
88 /* NOLINTEND(*-array-to-pointer-decay) */
90 effect_exception::~effect_exception() = default;
92 namespace {
94 using SubListAllocator = al::allocator<std::array<ALeffect,64>>;
96 auto GetDefaultProps(ALenum type) noexcept -> const EffectProps&
98 switch(type)
100 case AL_EFFECT_NULL: return NullEffectProps;
101 case AL_EFFECT_EAXREVERB: return ReverbEffectProps;
102 case AL_EFFECT_REVERB: return StdReverbEffectProps;
103 case AL_EFFECT_AUTOWAH: return AutowahEffectProps;
104 case AL_EFFECT_CHORUS: return ChorusEffectProps;
105 case AL_EFFECT_COMPRESSOR: return CompressorEffectProps;
106 case AL_EFFECT_DISTORTION: return DistortionEffectProps;
107 case AL_EFFECT_ECHO: return EchoEffectProps;
108 case AL_EFFECT_EQUALIZER: return EqualizerEffectProps;
109 case AL_EFFECT_FLANGER: return FlangerEffectProps;
110 case AL_EFFECT_FREQUENCY_SHIFTER: return FshifterEffectProps;
111 case AL_EFFECT_RING_MODULATOR: return ModulatorEffectProps;
112 case AL_EFFECT_PITCH_SHIFTER: return PshifterEffectProps;
113 case AL_EFFECT_VOCAL_MORPHER: return VmorpherEffectProps;
114 case AL_EFFECT_DEDICATED_DIALOGUE: return DedicatedDialogEffectProps;
115 case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: return DedicatedLfeEffectProps;
116 case AL_EFFECT_CONVOLUTION_SOFT: return ConvolutionEffectProps;
118 return NullEffectProps;
121 void InitEffectParams(ALeffect *effect, ALenum type) noexcept
123 effect->Props = GetDefaultProps(type);
124 effect->type = type;
127 bool EnsureEffects(ALCdevice *device, size_t needed)
129 size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), 0_uz,
130 [](size_t cur, const EffectSubList &sublist) noexcept -> size_t
131 { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
133 try {
134 while(needed > count)
136 if(device->EffectList.size() >= 1<<25) UNLIKELY
137 return false;
139 EffectSubList sublist{};
140 sublist.FreeMask = ~0_u64;
141 sublist.Effects = SubListAllocator{}.allocate(1);
142 device->EffectList.emplace_back(std::move(sublist));
143 count += std::tuple_size_v<SubListAllocator::value_type>;
146 catch(...) {
147 return false;
149 return true;
152 ALeffect *AllocEffect(ALCdevice *device) noexcept
154 auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
155 [](const EffectSubList &entry) noexcept -> bool
156 { return entry.FreeMask != 0; });
157 auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
158 auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
159 ASSUME(slidx < 64);
161 ALeffect *effect{al::construct_at(al::to_address(sublist->Effects->begin() + slidx))};
162 InitEffectParams(effect, AL_EFFECT_NULL);
164 /* Add 1 to avoid effect ID 0. */
165 effect->id = ((lidx<<6) | slidx) + 1;
167 sublist->FreeMask &= ~(1_u64 << slidx);
169 return effect;
172 void FreeEffect(ALCdevice *device, ALeffect *effect)
174 device->mEffectNames.erase(effect->id);
176 const ALuint id{effect->id - 1};
177 const size_t lidx{id >> 6};
178 const ALuint slidx{id & 0x3f};
180 std::destroy_at(effect);
182 device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
185 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
187 const size_t lidx{(id-1) >> 6};
188 const ALuint slidx{(id-1) & 0x3f};
190 if(lidx >= device->EffectList.size()) UNLIKELY
191 return nullptr;
192 EffectSubList &sublist = device->EffectList[lidx];
193 if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
194 return nullptr;
195 return al::to_address(sublist.Effects->begin() + slidx);
198 } // namespace
200 AL_API DECL_FUNC2(void, alGenEffects, ALsizei,n, ALuint*,effects)
201 FORCE_ALIGN void AL_APIENTRY alGenEffectsDirect(ALCcontext *context, ALsizei n, ALuint *effects) noexcept
203 if(n < 0) UNLIKELY
204 context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
205 if(n <= 0) UNLIKELY return;
207 ALCdevice *device{context->mALDevice.get()};
208 std::lock_guard<std::mutex> effectlock{device->EffectLock};
209 if(!EnsureEffects(device, static_cast<ALuint>(n)))
211 context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
212 return;
215 const al::span eids{effects, static_cast<ALuint>(n)};
216 std::generate(eids.begin(), eids.end(), [device]{ return AllocEffect(device)->id; });
219 AL_API DECL_FUNC2(void, alDeleteEffects, ALsizei,n, const ALuint*,effects)
220 FORCE_ALIGN void AL_APIENTRY alDeleteEffectsDirect(ALCcontext *context, ALsizei n,
221 const ALuint *effects) noexcept
223 if(n < 0) UNLIKELY
224 context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
225 if(n <= 0) UNLIKELY return;
227 ALCdevice *device{context->mALDevice.get()};
228 std::lock_guard<std::mutex> effectlock{device->EffectLock};
230 /* First try to find any effects that are invalid. */
231 auto validate_effect = [device](const ALuint eid) -> bool
232 { return !eid || LookupEffect(device, eid) != nullptr; };
234 const al::span eids{effects, static_cast<ALuint>(n)};
235 auto inveffect = std::find_if_not(eids.begin(), eids.end(), validate_effect);
236 if(inveffect != eids.end()) UNLIKELY
238 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
239 return;
242 /* All good. Delete non-0 effect IDs. */
243 auto delete_effect = [device](ALuint eid) -> void
245 if(ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr})
246 FreeEffect(device, effect);
248 std::for_each(eids.begin(), eids.end(), delete_effect);
251 AL_API DECL_FUNC1(ALboolean, alIsEffect, ALuint,effect)
252 FORCE_ALIGN ALboolean AL_APIENTRY alIsEffectDirect(ALCcontext *context, ALuint effect) noexcept
254 ALCdevice *device{context->mALDevice.get()};
255 std::lock_guard<std::mutex> effectlock{device->EffectLock};
256 if(!effect || LookupEffect(device, effect))
257 return AL_TRUE;
258 return AL_FALSE;
261 AL_API DECL_FUNC3(void, alEffecti, ALuint,effect, ALenum,param, ALint,value)
262 FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
263 ALint value) noexcept
265 ALCdevice *device{context->mALDevice.get()};
266 std::lock_guard<std::mutex> effectlock{device->EffectLock};
268 ALeffect *aleffect{LookupEffect(device, effect)};
269 if(!aleffect) UNLIKELY
270 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
271 else if(param == AL_EFFECT_TYPE)
273 bool isOk{value == AL_EFFECT_NULL};
274 if(!isOk)
276 auto check_effect = [value](const EffectList &item) -> bool
277 { return value == item.val && !DisabledEffects.test(item.type); };
278 isOk = std::any_of(gEffectList.cbegin(), gEffectList.cend(), check_effect);
281 if(isOk)
282 InitEffectParams(aleffect, value);
283 else
284 context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
286 else try
288 /* Call the appropriate handler */
289 std::visit([aleffect,param,value](auto &arg)
291 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
292 if constexpr(std::is_same_v<Type,ReverbProps>)
294 if(aleffect->type == AL_EFFECT_REVERB)
295 return EffectHandler::StdReverbSetParami(arg, param, value);
297 return EffectHandler::SetParami(arg, param, value);
298 }, aleffect->Props);
300 catch(effect_exception &e) {
301 context->setError(e.errorCode(), "%s", e.what());
305 AL_API DECL_FUNC3(void, alEffectiv, ALuint,effect, ALenum,param, const ALint*,values)
306 FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
307 const ALint *values) noexcept
309 switch(param)
311 case AL_EFFECT_TYPE:
312 alEffectiDirect(context, effect, param, *values);
313 return;
316 ALCdevice *device{context->mALDevice.get()};
317 std::lock_guard<std::mutex> effectlock{device->EffectLock};
319 ALeffect *aleffect{LookupEffect(device, effect)};
320 if(!aleffect) UNLIKELY
321 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
322 else try
324 /* Call the appropriate handler */
325 std::visit([aleffect,param,values](auto &arg)
327 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
328 if constexpr(std::is_same_v<Type,ReverbProps>)
330 if(aleffect->type == AL_EFFECT_REVERB)
331 return EffectHandler::StdReverbSetParamiv(arg, param, values);
333 return EffectHandler::SetParamiv(arg, param, values);
334 }, aleffect->Props);
336 catch(effect_exception &e) {
337 context->setError(e.errorCode(), "%s", e.what());
341 AL_API DECL_FUNC3(void, alEffectf, ALuint,effect, ALenum,param, ALfloat,value)
342 FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
343 ALfloat value) noexcept
345 ALCdevice *device{context->mALDevice.get()};
346 std::lock_guard<std::mutex> effectlock{device->EffectLock};
348 ALeffect *aleffect{LookupEffect(device, effect)};
349 if(!aleffect) UNLIKELY
350 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
351 else try
353 /* Call the appropriate handler */
354 std::visit([aleffect,param,value](auto &arg)
356 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
357 if constexpr(std::is_same_v<Type,ReverbProps>)
359 if(aleffect->type == AL_EFFECT_REVERB)
360 return EffectHandler::StdReverbSetParamf(arg, param, value);
362 return EffectHandler::SetParamf(arg, param, value);
363 }, aleffect->Props);
365 catch(effect_exception &e) {
366 context->setError(e.errorCode(), "%s", e.what());
370 AL_API DECL_FUNC3(void, alEffectfv, ALuint,effect, ALenum,param, const ALfloat*,values)
371 FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
372 const ALfloat *values) noexcept
374 ALCdevice *device{context->mALDevice.get()};
375 std::lock_guard<std::mutex> effectlock{device->EffectLock};
377 ALeffect *aleffect{LookupEffect(device, effect)};
378 if(!aleffect) UNLIKELY
379 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
380 else try
382 /* Call the appropriate handler */
383 std::visit([aleffect,param,values](auto &arg)
385 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
386 if constexpr(std::is_same_v<Type,ReverbProps>)
388 if(aleffect->type == AL_EFFECT_REVERB)
389 return EffectHandler::StdReverbSetParamfv(arg, param, values);
391 return EffectHandler::SetParamfv(arg, param, values);
392 }, aleffect->Props);
394 catch(effect_exception &e) {
395 context->setError(e.errorCode(), "%s", e.what());
399 AL_API DECL_FUNC3(void, alGetEffecti, ALuint,effect, ALenum,param, ALint*,value)
400 FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
401 ALint *value) noexcept
403 ALCdevice *device{context->mALDevice.get()};
404 std::lock_guard<std::mutex> effectlock{device->EffectLock};
406 const ALeffect *aleffect{LookupEffect(device, effect)};
407 if(!aleffect) UNLIKELY
408 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
409 else if(param == AL_EFFECT_TYPE)
410 *value = aleffect->type;
411 else try
413 /* Call the appropriate handler */
414 std::visit([aleffect,param,value](auto &arg)
416 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
417 if constexpr(std::is_same_v<Type,ReverbProps>)
419 if(aleffect->type == AL_EFFECT_REVERB)
420 return EffectHandler::StdReverbGetParami(arg, param, value);
422 return EffectHandler::GetParami(arg, param, value);
423 }, aleffect->Props);
425 catch(effect_exception &e) {
426 context->setError(e.errorCode(), "%s", e.what());
430 AL_API DECL_FUNC3(void, alGetEffectiv, ALuint,effect, ALenum,param, ALint*,values)
431 FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
432 ALint *values) noexcept
434 switch(param)
436 case AL_EFFECT_TYPE:
437 alGetEffectiDirect(context, effect, param, values);
438 return;
441 ALCdevice *device{context->mALDevice.get()};
442 std::lock_guard<std::mutex> effectlock{device->EffectLock};
444 const ALeffect *aleffect{LookupEffect(device, effect)};
445 if(!aleffect) UNLIKELY
446 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
447 else try
449 /* Call the appropriate handler */
450 std::visit([aleffect,param,values](auto &arg)
452 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
453 if constexpr(std::is_same_v<Type,ReverbProps>)
455 if(aleffect->type == AL_EFFECT_REVERB)
456 return EffectHandler::StdReverbGetParamiv(arg, param, values);
458 return EffectHandler::GetParamiv(arg, param, values);
459 }, aleffect->Props);
461 catch(effect_exception &e) {
462 context->setError(e.errorCode(), "%s", e.what());
466 AL_API DECL_FUNC3(void, alGetEffectf, ALuint,effect, ALenum,param, ALfloat*,value)
467 FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
468 ALfloat *value) noexcept
470 ALCdevice *device{context->mALDevice.get()};
471 std::lock_guard<std::mutex> effectlock{device->EffectLock};
473 const ALeffect *aleffect{LookupEffect(device, effect)};
474 if(!aleffect) UNLIKELY
475 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
476 else try
478 /* Call the appropriate handler */
479 std::visit([aleffect,param,value](auto &arg)
481 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
482 if constexpr(std::is_same_v<Type,ReverbProps>)
484 if(aleffect->type == AL_EFFECT_REVERB)
485 return EffectHandler::StdReverbGetParamf(arg, param, value);
487 return EffectHandler::GetParamf(arg, param, value);
488 }, aleffect->Props);
490 catch(effect_exception &e) {
491 context->setError(e.errorCode(), "%s", e.what());
495 AL_API DECL_FUNC3(void, alGetEffectfv, ALuint,effect, ALenum,param, ALfloat*,values)
496 FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
497 ALfloat *values) noexcept
499 ALCdevice *device{context->mALDevice.get()};
500 std::lock_guard<std::mutex> effectlock{device->EffectLock};
502 const ALeffect *aleffect{LookupEffect(device, effect)};
503 if(!aleffect) UNLIKELY
504 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
505 else try
507 /* Call the appropriate handler */
508 std::visit([aleffect,param,values](auto &arg)
510 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
511 if constexpr(std::is_same_v<Type,ReverbProps>)
513 if(aleffect->type == AL_EFFECT_REVERB)
514 return EffectHandler::StdReverbGetParamfv(arg, param, values);
516 return EffectHandler::GetParamfv(arg, param, values);
517 }, aleffect->Props);
519 catch(effect_exception &e) {
520 context->setError(e.errorCode(), "%s", e.what());
525 void InitEffect(ALeffect *effect)
527 InitEffectParams(effect, AL_EFFECT_NULL);
530 void ALeffect::SetName(ALCcontext* context, ALuint id, std::string_view name)
532 ALCdevice *device{context->mALDevice.get()};
533 std::lock_guard<std::mutex> effectlock{device->EffectLock};
535 auto effect = LookupEffect(device, id);
536 if(!effect) UNLIKELY
537 return context->setError(AL_INVALID_NAME, "Invalid effect ID %u", id);
539 device->mEffectNames.insert_or_assign(id, name);
543 EffectSubList::~EffectSubList()
545 if(!Effects)
546 return;
548 uint64_t usemask{~FreeMask};
549 while(usemask)
551 const int idx{al::countr_zero(usemask)};
552 std::destroy_at(al::to_address(Effects->begin()+idx));
553 usemask &= ~(1_u64 << idx);
555 FreeMask = ~usemask;
556 SubListAllocator{}.deallocate(Effects, 1);
557 Effects = nullptr;
561 struct EffectPreset {
562 const char name[32]; /* NOLINT(*-avoid-c-arrays) */
563 EFXEAXREVERBPROPERTIES props;
565 #define DECL(x) EffectPreset{#x, EFX_REVERB_PRESET_##x}
566 static constexpr std::array reverblist{
567 DECL(GENERIC),
568 DECL(PADDEDCELL),
569 DECL(ROOM),
570 DECL(BATHROOM),
571 DECL(LIVINGROOM),
572 DECL(STONEROOM),
573 DECL(AUDITORIUM),
574 DECL(CONCERTHALL),
575 DECL(CAVE),
576 DECL(ARENA),
577 DECL(HANGAR),
578 DECL(CARPETEDHALLWAY),
579 DECL(HALLWAY),
580 DECL(STONECORRIDOR),
581 DECL(ALLEY),
582 DECL(FOREST),
583 DECL(CITY),
584 DECL(MOUNTAINS),
585 DECL(QUARRY),
586 DECL(PLAIN),
587 DECL(PARKINGLOT),
588 DECL(SEWERPIPE),
589 DECL(UNDERWATER),
590 DECL(DRUGGED),
591 DECL(DIZZY),
592 DECL(PSYCHOTIC),
594 DECL(CASTLE_SMALLROOM),
595 DECL(CASTLE_SHORTPASSAGE),
596 DECL(CASTLE_MEDIUMROOM),
597 DECL(CASTLE_LARGEROOM),
598 DECL(CASTLE_LONGPASSAGE),
599 DECL(CASTLE_HALL),
600 DECL(CASTLE_CUPBOARD),
601 DECL(CASTLE_COURTYARD),
602 DECL(CASTLE_ALCOVE),
604 DECL(FACTORY_SMALLROOM),
605 DECL(FACTORY_SHORTPASSAGE),
606 DECL(FACTORY_MEDIUMROOM),
607 DECL(FACTORY_LARGEROOM),
608 DECL(FACTORY_LONGPASSAGE),
609 DECL(FACTORY_HALL),
610 DECL(FACTORY_CUPBOARD),
611 DECL(FACTORY_COURTYARD),
612 DECL(FACTORY_ALCOVE),
614 DECL(ICEPALACE_SMALLROOM),
615 DECL(ICEPALACE_SHORTPASSAGE),
616 DECL(ICEPALACE_MEDIUMROOM),
617 DECL(ICEPALACE_LARGEROOM),
618 DECL(ICEPALACE_LONGPASSAGE),
619 DECL(ICEPALACE_HALL),
620 DECL(ICEPALACE_CUPBOARD),
621 DECL(ICEPALACE_COURTYARD),
622 DECL(ICEPALACE_ALCOVE),
624 DECL(SPACESTATION_SMALLROOM),
625 DECL(SPACESTATION_SHORTPASSAGE),
626 DECL(SPACESTATION_MEDIUMROOM),
627 DECL(SPACESTATION_LARGEROOM),
628 DECL(SPACESTATION_LONGPASSAGE),
629 DECL(SPACESTATION_HALL),
630 DECL(SPACESTATION_CUPBOARD),
631 DECL(SPACESTATION_ALCOVE),
633 DECL(WOODEN_SMALLROOM),
634 DECL(WOODEN_SHORTPASSAGE),
635 DECL(WOODEN_MEDIUMROOM),
636 DECL(WOODEN_LARGEROOM),
637 DECL(WOODEN_LONGPASSAGE),
638 DECL(WOODEN_HALL),
639 DECL(WOODEN_CUPBOARD),
640 DECL(WOODEN_COURTYARD),
641 DECL(WOODEN_ALCOVE),
643 DECL(SPORT_EMPTYSTADIUM),
644 DECL(SPORT_SQUASHCOURT),
645 DECL(SPORT_SMALLSWIMMINGPOOL),
646 DECL(SPORT_LARGESWIMMINGPOOL),
647 DECL(SPORT_GYMNASIUM),
648 DECL(SPORT_FULLSTADIUM),
649 DECL(SPORT_STADIUMTANNOY),
651 DECL(PREFAB_WORKSHOP),
652 DECL(PREFAB_SCHOOLROOM),
653 DECL(PREFAB_PRACTISEROOM),
654 DECL(PREFAB_OUTHOUSE),
655 DECL(PREFAB_CARAVAN),
657 DECL(DOME_TOMB),
658 DECL(PIPE_SMALL),
659 DECL(DOME_SAINTPAULS),
660 DECL(PIPE_LONGTHIN),
661 DECL(PIPE_LARGE),
662 DECL(PIPE_RESONANT),
664 DECL(OUTDOORS_BACKYARD),
665 DECL(OUTDOORS_ROLLINGPLAINS),
666 DECL(OUTDOORS_DEEPCANYON),
667 DECL(OUTDOORS_CREEK),
668 DECL(OUTDOORS_VALLEY),
670 DECL(MOOD_HEAVEN),
671 DECL(MOOD_HELL),
672 DECL(MOOD_MEMORY),
674 DECL(DRIVING_COMMENTATOR),
675 DECL(DRIVING_PITGARAGE),
676 DECL(DRIVING_INCAR_RACER),
677 DECL(DRIVING_INCAR_SPORTS),
678 DECL(DRIVING_INCAR_LUXURY),
679 DECL(DRIVING_FULLGRANDSTAND),
680 DECL(DRIVING_EMPTYGRANDSTAND),
681 DECL(DRIVING_TUNNEL),
683 DECL(CITY_STREETS),
684 DECL(CITY_SUBWAY),
685 DECL(CITY_MUSEUM),
686 DECL(CITY_LIBRARY),
687 DECL(CITY_UNDERPASS),
688 DECL(CITY_ABANDONED),
690 DECL(DUSTYROOM),
691 DECL(CHAPEL),
692 DECL(SMALLWATERROOM),
694 #undef DECL
696 void LoadReverbPreset(const std::string_view name, ALeffect *effect)
698 using namespace std::string_view_literals;
700 if(al::case_compare(name, "NONE"sv) == 0)
702 InitEffectParams(effect, AL_EFFECT_NULL);
703 TRACE("Loading reverb '%s'\n", "NONE");
704 return;
707 if(!DisabledEffects.test(EAXREVERB_EFFECT))
708 InitEffectParams(effect, AL_EFFECT_EAXREVERB);
709 else if(!DisabledEffects.test(REVERB_EFFECT))
710 InitEffectParams(effect, AL_EFFECT_REVERB);
711 else
712 InitEffectParams(effect, AL_EFFECT_NULL);
713 for(const auto &reverbitem : reverblist)
715 if(al::case_compare(name, std::data(reverbitem.name)) != 0)
716 continue;
718 TRACE("Loading reverb '%s'\n", std::data(reverbitem.name));
719 const auto &props = reverbitem.props;
720 auto &dst = std::get<ReverbProps>(effect->Props);
721 dst.Density = props.flDensity;
722 dst.Diffusion = props.flDiffusion;
723 dst.Gain = props.flGain;
724 dst.GainHF = props.flGainHF;
725 dst.GainLF = props.flGainLF;
726 dst.DecayTime = props.flDecayTime;
727 dst.DecayHFRatio = props.flDecayHFRatio;
728 dst.DecayLFRatio = props.flDecayLFRatio;
729 dst.ReflectionsGain = props.flReflectionsGain;
730 dst.ReflectionsDelay = props.flReflectionsDelay;
731 dst.ReflectionsPan[0] = props.flReflectionsPan[0];
732 dst.ReflectionsPan[1] = props.flReflectionsPan[1];
733 dst.ReflectionsPan[2] = props.flReflectionsPan[2];
734 dst.LateReverbGain = props.flLateReverbGain;
735 dst.LateReverbDelay = props.flLateReverbDelay;
736 dst.LateReverbPan[0] = props.flLateReverbPan[0];
737 dst.LateReverbPan[1] = props.flLateReverbPan[1];
738 dst.LateReverbPan[2] = props.flLateReverbPan[2];
739 dst.EchoTime = props.flEchoTime;
740 dst.EchoDepth = props.flEchoDepth;
741 dst.ModulationTime = props.flModulationTime;
742 dst.ModulationDepth = props.flModulationDepth;
743 dst.AirAbsorptionGainHF = props.flAirAbsorptionGainHF;
744 dst.HFReference = props.flHFReference;
745 dst.LFReference = props.flLFReference;
746 dst.RoomRolloffFactor = props.flRoomRolloffFactor;
747 dst.DecayHFLimit = props.iDecayHFLimit ? AL_TRUE : AL_FALSE;
748 return;
751 WARN("Reverb preset '%.*s' not found\n", al::sizei(name), name.data());
754 bool IsValidEffectType(ALenum type) noexcept
756 if(type == AL_EFFECT_NULL)
757 return true;
759 auto check_effect = [type](const EffectList &item) noexcept -> bool
760 { return type == item.val && !DisabledEffects.test(item.type); };
761 return std::any_of(gEffectList.cbegin(), gEffectList.cend(), check_effect);