Avoid implicit array-to-pointer decay
[openal-soft.git] / al / effect.cpp
blobe8217e40cea94de47c8f1e32846fe707865f3299
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 <cstdint>
27 #include <cstring>
28 #include <iterator>
29 #include <memory>
30 #include <mutex>
31 #include <new>
32 #include <numeric>
33 #include <utility>
34 #include <vector>
36 #include "AL/al.h"
37 #include "AL/alc.h"
38 #include "AL/alext.h"
39 #include "AL/efx-presets.h"
40 #include "AL/efx.h"
42 #include "albit.h"
43 #include "alc/context.h"
44 #include "alc/device.h"
45 #include "alc/effects/base.h"
46 #include "alc/inprogext.h"
47 #include "almalloc.h"
48 #include "alnumeric.h"
49 #include "alstring.h"
50 #include "core/except.h"
51 #include "core/logging.h"
52 #include "direct_defs.h"
53 #include "opthelpers.h"
55 #ifdef ALSOFT_EAX
56 #include <cassert>
58 #include "eax/exception.h"
59 #endif // ALSOFT_EAX
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 = typename al::allocator<std::array<ALeffect,64>>;
96 auto GetDefaultProps(ALenum type) -> 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)
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 += 64;
146 catch(...) {
147 return false;
149 return true;
152 ALeffect *AllocEffect(ALCdevice *device)
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, ALuint*)
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 if(n == 1) LIKELY
217 /* Special handling for the easy and normal case. */
218 *effects = AllocEffect(device)->id;
220 else
222 /* Store the allocated buffer IDs in a separate local list, to avoid
223 * modifying the user storage in case of failure.
225 std::vector<ALuint> ids;
226 ids.reserve(static_cast<ALuint>(n));
227 do {
228 ALeffect *effect{AllocEffect(device)};
229 ids.emplace_back(effect->id);
230 } while(--n);
231 const al::span eids{effects, static_cast<ALuint>(n)};
232 std::copy(ids.cbegin(), ids.cend(), eids.begin());
236 AL_API DECL_FUNC2(void, alDeleteEffects, ALsizei, const ALuint*)
237 FORCE_ALIGN void AL_APIENTRY alDeleteEffectsDirect(ALCcontext *context, ALsizei n,
238 const ALuint *effects) noexcept
240 if(n < 0) UNLIKELY
241 context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
242 if(n <= 0) UNLIKELY return;
244 ALCdevice *device{context->mALDevice.get()};
245 std::lock_guard<std::mutex> effectlock{device->EffectLock};
247 /* First try to find any effects that are invalid. */
248 auto validate_effect = [device](const ALuint eid) -> bool
249 { return !eid || LookupEffect(device, eid) != nullptr; };
251 const al::span eids{effects, static_cast<ALuint>(n)};
252 auto inveffect = std::find_if_not(eids.begin(), eids.end(), validate_effect);
253 if(inveffect != eids.end()) UNLIKELY
255 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
256 return;
259 /* All good. Delete non-0 effect IDs. */
260 auto delete_effect = [device](ALuint eid) -> void
262 ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
263 if(effect) FreeEffect(device, effect);
265 std::for_each(eids.begin(), eids.end(), delete_effect);
268 AL_API DECL_FUNC1(ALboolean, alIsEffect, ALuint)
269 FORCE_ALIGN ALboolean AL_APIENTRY alIsEffectDirect(ALCcontext *context, ALuint effect) noexcept
271 ALCdevice *device{context->mALDevice.get()};
272 std::lock_guard<std::mutex> effectlock{device->EffectLock};
273 if(!effect || LookupEffect(device, effect))
274 return AL_TRUE;
275 return AL_FALSE;
278 AL_API DECL_FUNC3(void, alEffecti, ALuint, ALenum, ALint)
279 FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
280 ALint value) noexcept
282 ALCdevice *device{context->mALDevice.get()};
283 std::lock_guard<std::mutex> effectlock{device->EffectLock};
285 ALeffect *aleffect{LookupEffect(device, effect)};
286 if(!aleffect) UNLIKELY
287 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
288 else if(param == AL_EFFECT_TYPE)
290 bool isOk{value == AL_EFFECT_NULL};
291 if(!isOk)
293 for(const EffectList &effectitem : gEffectList)
295 if(value == effectitem.val && !DisabledEffects.test(effectitem.type))
297 isOk = true;
298 break;
303 if(isOk)
304 InitEffectParams(aleffect, value);
305 else
306 context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
308 else try
310 /* Call the appropriate handler */
311 std::visit([aleffect,param,value](auto &arg)
313 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
314 if constexpr(std::is_same_v<Type,ReverbProps>)
316 if(aleffect->type == AL_EFFECT_REVERB)
317 return EffectHandler::StdReverbSetParami(arg, param, value);
319 return EffectHandler::SetParami(arg, param, value);
320 }, aleffect->Props);
322 catch(effect_exception &e) {
323 context->setError(e.errorCode(), "%s", e.what());
327 AL_API DECL_FUNC3(void, alEffectiv, ALuint, ALenum, const ALint*)
328 FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
329 const ALint *values) noexcept
331 switch(param)
333 case AL_EFFECT_TYPE:
334 alEffectiDirect(context, effect, param, values[0]);
335 return;
338 ALCdevice *device{context->mALDevice.get()};
339 std::lock_guard<std::mutex> effectlock{device->EffectLock};
341 ALeffect *aleffect{LookupEffect(device, effect)};
342 if(!aleffect) UNLIKELY
343 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
344 else try
346 /* Call the appropriate handler */
347 std::visit([aleffect,param,values](auto &arg)
349 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
350 if constexpr(std::is_same_v<Type,ReverbProps>)
352 if(aleffect->type == AL_EFFECT_REVERB)
353 return EffectHandler::StdReverbSetParamiv(arg, param, values);
355 return EffectHandler::SetParamiv(arg, param, values);
356 }, aleffect->Props);
358 catch(effect_exception &e) {
359 context->setError(e.errorCode(), "%s", e.what());
363 AL_API DECL_FUNC3(void, alEffectf, ALuint, ALenum, ALfloat)
364 FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
365 ALfloat value) noexcept
367 ALCdevice *device{context->mALDevice.get()};
368 std::lock_guard<std::mutex> effectlock{device->EffectLock};
370 ALeffect *aleffect{LookupEffect(device, effect)};
371 if(!aleffect) UNLIKELY
372 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
373 else try
375 /* Call the appropriate handler */
376 std::visit([aleffect,param,value](auto &arg)
378 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
379 if constexpr(std::is_same_v<Type,ReverbProps>)
381 if(aleffect->type == AL_EFFECT_REVERB)
382 return EffectHandler::StdReverbSetParamf(arg, param, value);
384 return EffectHandler::SetParamf(arg, param, value);
385 }, aleffect->Props);
387 catch(effect_exception &e) {
388 context->setError(e.errorCode(), "%s", e.what());
392 AL_API DECL_FUNC3(void, alEffectfv, ALuint, ALenum, const ALfloat*)
393 FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
394 const ALfloat *values) noexcept
396 ALCdevice *device{context->mALDevice.get()};
397 std::lock_guard<std::mutex> effectlock{device->EffectLock};
399 ALeffect *aleffect{LookupEffect(device, effect)};
400 if(!aleffect) UNLIKELY
401 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
402 else try
404 /* Call the appropriate handler */
405 std::visit([aleffect,param,values](auto &arg)
407 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
408 if constexpr(std::is_same_v<Type,ReverbProps>)
410 if(aleffect->type == AL_EFFECT_REVERB)
411 return EffectHandler::StdReverbSetParamfv(arg, param, values);
413 return EffectHandler::SetParamfv(arg, param, values);
414 }, aleffect->Props);
416 catch(effect_exception &e) {
417 context->setError(e.errorCode(), "%s", e.what());
421 AL_API DECL_FUNC3(void, alGetEffecti, ALuint, ALenum, ALint*)
422 FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
423 ALint *value) noexcept
425 ALCdevice *device{context->mALDevice.get()};
426 std::lock_guard<std::mutex> effectlock{device->EffectLock};
428 const ALeffect *aleffect{LookupEffect(device, effect)};
429 if(!aleffect) UNLIKELY
430 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
431 else if(param == AL_EFFECT_TYPE)
432 *value = aleffect->type;
433 else try
435 /* Call the appropriate handler */
436 std::visit([aleffect,param,value](auto &arg)
438 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
439 if constexpr(std::is_same_v<Type,ReverbProps>)
441 if(aleffect->type == AL_EFFECT_REVERB)
442 return EffectHandler::StdReverbGetParami(arg, param, value);
444 return EffectHandler::GetParami(arg, param, value);
445 }, aleffect->Props);
447 catch(effect_exception &e) {
448 context->setError(e.errorCode(), "%s", e.what());
452 AL_API DECL_FUNC3(void, alGetEffectiv, ALuint, ALenum, ALint*)
453 FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
454 ALint *values) noexcept
456 switch(param)
458 case AL_EFFECT_TYPE:
459 alGetEffectiDirect(context, effect, param, values);
460 return;
463 ALCdevice *device{context->mALDevice.get()};
464 std::lock_guard<std::mutex> effectlock{device->EffectLock};
466 const ALeffect *aleffect{LookupEffect(device, effect)};
467 if(!aleffect) UNLIKELY
468 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
469 else try
471 /* Call the appropriate handler */
472 std::visit([aleffect,param,values](auto &arg)
474 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
475 if constexpr(std::is_same_v<Type,ReverbProps>)
477 if(aleffect->type == AL_EFFECT_REVERB)
478 return EffectHandler::StdReverbGetParamiv(arg, param, values);
480 return EffectHandler::GetParamiv(arg, param, values);
481 }, aleffect->Props);
483 catch(effect_exception &e) {
484 context->setError(e.errorCode(), "%s", e.what());
488 AL_API DECL_FUNC3(void, alGetEffectf, ALuint, ALenum, ALfloat*)
489 FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
490 ALfloat *value) noexcept
492 ALCdevice *device{context->mALDevice.get()};
493 std::lock_guard<std::mutex> effectlock{device->EffectLock};
495 const ALeffect *aleffect{LookupEffect(device, effect)};
496 if(!aleffect) UNLIKELY
497 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
498 else try
500 /* Call the appropriate handler */
501 std::visit([aleffect,param,value](auto &arg)
503 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
504 if constexpr(std::is_same_v<Type,ReverbProps>)
506 if(aleffect->type == AL_EFFECT_REVERB)
507 return EffectHandler::StdReverbGetParamf(arg, param, value);
509 return EffectHandler::GetParamf(arg, param, value);
510 }, aleffect->Props);
512 catch(effect_exception &e) {
513 context->setError(e.errorCode(), "%s", e.what());
517 AL_API DECL_FUNC3(void, alGetEffectfv, ALuint, ALenum, ALfloat*)
518 FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
519 ALfloat *values) noexcept
521 ALCdevice *device{context->mALDevice.get()};
522 std::lock_guard<std::mutex> effectlock{device->EffectLock};
524 const ALeffect *aleffect{LookupEffect(device, effect)};
525 if(!aleffect) UNLIKELY
526 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
527 else try
529 /* Call the appropriate handler */
530 std::visit([aleffect,param,values](auto &arg)
532 using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
533 if constexpr(std::is_same_v<Type,ReverbProps>)
535 if(aleffect->type == AL_EFFECT_REVERB)
536 return EffectHandler::StdReverbGetParamfv(arg, param, values);
538 return EffectHandler::GetParamfv(arg, param, values);
539 }, aleffect->Props);
541 catch(effect_exception &e) {
542 context->setError(e.errorCode(), "%s", e.what());
547 void InitEffect(ALeffect *effect)
549 InitEffectParams(effect, AL_EFFECT_NULL);
552 void ALeffect::SetName(ALCcontext* context, ALuint id, std::string_view name)
554 ALCdevice *device{context->mALDevice.get()};
555 std::lock_guard<std::mutex> effectlock{device->EffectLock};
557 auto effect = LookupEffect(device, id);
558 if(!effect) UNLIKELY
559 return context->setError(AL_INVALID_NAME, "Invalid effect ID %u", id);
561 device->mEffectNames.insert_or_assign(id, name);
565 EffectSubList::~EffectSubList()
567 if(!Effects)
568 return;
570 uint64_t usemask{~FreeMask};
571 while(usemask)
573 const int idx{al::countr_zero(usemask)};
574 std::destroy_at(al::to_address(Effects->begin()+idx));
575 usemask &= ~(1_u64 << idx);
577 FreeMask = ~usemask;
578 SubListAllocator{}.deallocate(Effects, 1);
579 Effects = nullptr;
583 struct EffectPreset {
584 const char name[32]; /* NOLINT(*-avoid-c-arrays) */
585 EFXEAXREVERBPROPERTIES props;
587 #define DECL(x) EffectPreset{#x, EFX_REVERB_PRESET_##x}
588 static constexpr std::array reverblist{
589 DECL(GENERIC),
590 DECL(PADDEDCELL),
591 DECL(ROOM),
592 DECL(BATHROOM),
593 DECL(LIVINGROOM),
594 DECL(STONEROOM),
595 DECL(AUDITORIUM),
596 DECL(CONCERTHALL),
597 DECL(CAVE),
598 DECL(ARENA),
599 DECL(HANGAR),
600 DECL(CARPETEDHALLWAY),
601 DECL(HALLWAY),
602 DECL(STONECORRIDOR),
603 DECL(ALLEY),
604 DECL(FOREST),
605 DECL(CITY),
606 DECL(MOUNTAINS),
607 DECL(QUARRY),
608 DECL(PLAIN),
609 DECL(PARKINGLOT),
610 DECL(SEWERPIPE),
611 DECL(UNDERWATER),
612 DECL(DRUGGED),
613 DECL(DIZZY),
614 DECL(PSYCHOTIC),
616 DECL(CASTLE_SMALLROOM),
617 DECL(CASTLE_SHORTPASSAGE),
618 DECL(CASTLE_MEDIUMROOM),
619 DECL(CASTLE_LARGEROOM),
620 DECL(CASTLE_LONGPASSAGE),
621 DECL(CASTLE_HALL),
622 DECL(CASTLE_CUPBOARD),
623 DECL(CASTLE_COURTYARD),
624 DECL(CASTLE_ALCOVE),
626 DECL(FACTORY_SMALLROOM),
627 DECL(FACTORY_SHORTPASSAGE),
628 DECL(FACTORY_MEDIUMROOM),
629 DECL(FACTORY_LARGEROOM),
630 DECL(FACTORY_LONGPASSAGE),
631 DECL(FACTORY_HALL),
632 DECL(FACTORY_CUPBOARD),
633 DECL(FACTORY_COURTYARD),
634 DECL(FACTORY_ALCOVE),
636 DECL(ICEPALACE_SMALLROOM),
637 DECL(ICEPALACE_SHORTPASSAGE),
638 DECL(ICEPALACE_MEDIUMROOM),
639 DECL(ICEPALACE_LARGEROOM),
640 DECL(ICEPALACE_LONGPASSAGE),
641 DECL(ICEPALACE_HALL),
642 DECL(ICEPALACE_CUPBOARD),
643 DECL(ICEPALACE_COURTYARD),
644 DECL(ICEPALACE_ALCOVE),
646 DECL(SPACESTATION_SMALLROOM),
647 DECL(SPACESTATION_SHORTPASSAGE),
648 DECL(SPACESTATION_MEDIUMROOM),
649 DECL(SPACESTATION_LARGEROOM),
650 DECL(SPACESTATION_LONGPASSAGE),
651 DECL(SPACESTATION_HALL),
652 DECL(SPACESTATION_CUPBOARD),
653 DECL(SPACESTATION_ALCOVE),
655 DECL(WOODEN_SMALLROOM),
656 DECL(WOODEN_SHORTPASSAGE),
657 DECL(WOODEN_MEDIUMROOM),
658 DECL(WOODEN_LARGEROOM),
659 DECL(WOODEN_LONGPASSAGE),
660 DECL(WOODEN_HALL),
661 DECL(WOODEN_CUPBOARD),
662 DECL(WOODEN_COURTYARD),
663 DECL(WOODEN_ALCOVE),
665 DECL(SPORT_EMPTYSTADIUM),
666 DECL(SPORT_SQUASHCOURT),
667 DECL(SPORT_SMALLSWIMMINGPOOL),
668 DECL(SPORT_LARGESWIMMINGPOOL),
669 DECL(SPORT_GYMNASIUM),
670 DECL(SPORT_FULLSTADIUM),
671 DECL(SPORT_STADIUMTANNOY),
673 DECL(PREFAB_WORKSHOP),
674 DECL(PREFAB_SCHOOLROOM),
675 DECL(PREFAB_PRACTISEROOM),
676 DECL(PREFAB_OUTHOUSE),
677 DECL(PREFAB_CARAVAN),
679 DECL(DOME_TOMB),
680 DECL(PIPE_SMALL),
681 DECL(DOME_SAINTPAULS),
682 DECL(PIPE_LONGTHIN),
683 DECL(PIPE_LARGE),
684 DECL(PIPE_RESONANT),
686 DECL(OUTDOORS_BACKYARD),
687 DECL(OUTDOORS_ROLLINGPLAINS),
688 DECL(OUTDOORS_DEEPCANYON),
689 DECL(OUTDOORS_CREEK),
690 DECL(OUTDOORS_VALLEY),
692 DECL(MOOD_HEAVEN),
693 DECL(MOOD_HELL),
694 DECL(MOOD_MEMORY),
696 DECL(DRIVING_COMMENTATOR),
697 DECL(DRIVING_PITGARAGE),
698 DECL(DRIVING_INCAR_RACER),
699 DECL(DRIVING_INCAR_SPORTS),
700 DECL(DRIVING_INCAR_LUXURY),
701 DECL(DRIVING_FULLGRANDSTAND),
702 DECL(DRIVING_EMPTYGRANDSTAND),
703 DECL(DRIVING_TUNNEL),
705 DECL(CITY_STREETS),
706 DECL(CITY_SUBWAY),
707 DECL(CITY_MUSEUM),
708 DECL(CITY_LIBRARY),
709 DECL(CITY_UNDERPASS),
710 DECL(CITY_ABANDONED),
712 DECL(DUSTYROOM),
713 DECL(CHAPEL),
714 DECL(SMALLWATERROOM),
716 #undef DECL
718 void LoadReverbPreset(const std::string_view name, ALeffect *effect)
720 using namespace std::string_view_literals;
722 if(al::case_compare(name, "NONE"sv) == 0)
724 InitEffectParams(effect, AL_EFFECT_NULL);
725 TRACE("Loading reverb '%s'\n", "NONE");
726 return;
729 if(!DisabledEffects.test(EAXREVERB_EFFECT))
730 InitEffectParams(effect, AL_EFFECT_EAXREVERB);
731 else if(!DisabledEffects.test(REVERB_EFFECT))
732 InitEffectParams(effect, AL_EFFECT_REVERB);
733 else
734 InitEffectParams(effect, AL_EFFECT_NULL);
735 for(const auto &reverbitem : reverblist)
737 if(al::case_compare(name, std::data(reverbitem.name)) != 0)
738 continue;
740 TRACE("Loading reverb '%s'\n", std::data(reverbitem.name));
741 const auto &props = reverbitem.props;
742 auto &dst = std::get<ReverbProps>(effect->Props);
743 dst.Density = props.flDensity;
744 dst.Diffusion = props.flDiffusion;
745 dst.Gain = props.flGain;
746 dst.GainHF = props.flGainHF;
747 dst.GainLF = props.flGainLF;
748 dst.DecayTime = props.flDecayTime;
749 dst.DecayHFRatio = props.flDecayHFRatio;
750 dst.DecayLFRatio = props.flDecayLFRatio;
751 dst.ReflectionsGain = props.flReflectionsGain;
752 dst.ReflectionsDelay = props.flReflectionsDelay;
753 dst.ReflectionsPan[0] = props.flReflectionsPan[0];
754 dst.ReflectionsPan[1] = props.flReflectionsPan[1];
755 dst.ReflectionsPan[2] = props.flReflectionsPan[2];
756 dst.LateReverbGain = props.flLateReverbGain;
757 dst.LateReverbDelay = props.flLateReverbDelay;
758 dst.LateReverbPan[0] = props.flLateReverbPan[0];
759 dst.LateReverbPan[1] = props.flLateReverbPan[1];
760 dst.LateReverbPan[2] = props.flLateReverbPan[2];
761 dst.EchoTime = props.flEchoTime;
762 dst.EchoDepth = props.flEchoDepth;
763 dst.ModulationTime = props.flModulationTime;
764 dst.ModulationDepth = props.flModulationDepth;
765 dst.AirAbsorptionGainHF = props.flAirAbsorptionGainHF;
766 dst.HFReference = props.flHFReference;
767 dst.LFReference = props.flLFReference;
768 dst.RoomRolloffFactor = props.flRoomRolloffFactor;
769 dst.DecayHFLimit = props.iDecayHFLimit ? AL_TRUE : AL_FALSE;
770 return;
773 WARN("Reverb preset '%.*s' not found\n", std::abs(static_cast<int>(name.size())), name.data());
776 bool IsValidEffectType(ALenum type) noexcept
778 if(type == AL_EFFECT_NULL)
779 return true;
781 for(const auto &effect_item : gEffectList)
783 if(type == effect_item.val && !DisabledEffects.test(effect_item.type))
784 return true;
786 return false;