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
33 #include <type_traits>
34 #include <unordered_map>
42 #include "AL/efx-presets.h"
45 #include "al/effects/effects.h"
47 #include "alc/context.h"
48 #include "alc/device.h"
49 #include "alc/inprogext.h"
51 #include "alnumeric.h"
54 #include "core/logging.h"
55 #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
},
83 using SubListAllocator
= al::allocator
<std::array
<ALeffect
,64>>;
85 constexpr auto GetDefaultProps(ALenum type
) noexcept
-> const EffectProps
&
89 case AL_EFFECT_NULL
: return NullEffectProps
;
90 case AL_EFFECT_EAXREVERB
: return ReverbEffectProps
;
91 case AL_EFFECT_REVERB
: return StdReverbEffectProps
;
92 case AL_EFFECT_AUTOWAH
: return AutowahEffectProps
;
93 case AL_EFFECT_CHORUS
: return ChorusEffectProps
;
94 case AL_EFFECT_COMPRESSOR
: return CompressorEffectProps
;
95 case AL_EFFECT_DISTORTION
: return DistortionEffectProps
;
96 case AL_EFFECT_ECHO
: return EchoEffectProps
;
97 case AL_EFFECT_EQUALIZER
: return EqualizerEffectProps
;
98 case AL_EFFECT_FLANGER
: return FlangerEffectProps
;
99 case AL_EFFECT_FREQUENCY_SHIFTER
: return FshifterEffectProps
;
100 case AL_EFFECT_RING_MODULATOR
: return ModulatorEffectProps
;
101 case AL_EFFECT_PITCH_SHIFTER
: return PshifterEffectProps
;
102 case AL_EFFECT_VOCAL_MORPHER
: return VmorpherEffectProps
;
103 case AL_EFFECT_DEDICATED_DIALOGUE
: return DedicatedDialogEffectProps
;
104 case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
: return DedicatedLfeEffectProps
;
105 case AL_EFFECT_CONVOLUTION_SOFT
: return ConvolutionEffectProps
;
107 return NullEffectProps
;
110 void InitEffectParams(ALeffect
*effect
, ALenum type
) noexcept
114 case AL_EFFECT_NULL
: effect
->PropsVariant
.emplace
<NullEffectHandler
>(); break;
115 case AL_EFFECT_EAXREVERB
: effect
->PropsVariant
.emplace
<ReverbEffectHandler
>(); break;
116 case AL_EFFECT_REVERB
: effect
->PropsVariant
.emplace
<StdReverbEffectHandler
>(); break;
117 case AL_EFFECT_AUTOWAH
: effect
->PropsVariant
.emplace
<AutowahEffectHandler
>(); break;
118 case AL_EFFECT_CHORUS
: effect
->PropsVariant
.emplace
<ChorusEffectHandler
>(); break;
119 case AL_EFFECT_COMPRESSOR
: effect
->PropsVariant
.emplace
<CompressorEffectHandler
>(); break;
120 case AL_EFFECT_DISTORTION
: effect
->PropsVariant
.emplace
<DistortionEffectHandler
>(); break;
121 case AL_EFFECT_ECHO
: effect
->PropsVariant
.emplace
<EchoEffectHandler
>(); break;
122 case AL_EFFECT_EQUALIZER
: effect
->PropsVariant
.emplace
<EqualizerEffectHandler
>(); break;
123 case AL_EFFECT_FLANGER
: effect
->PropsVariant
.emplace
<ChorusEffectHandler
>(); break;
124 case AL_EFFECT_FREQUENCY_SHIFTER
: effect
->PropsVariant
.emplace
<FshifterEffectHandler
>(); break;
125 case AL_EFFECT_RING_MODULATOR
: effect
->PropsVariant
.emplace
<ModulatorEffectHandler
>(); break;
126 case AL_EFFECT_PITCH_SHIFTER
: effect
->PropsVariant
.emplace
<PshifterEffectHandler
>(); break;
127 case AL_EFFECT_VOCAL_MORPHER
: effect
->PropsVariant
.emplace
<VmorpherEffectHandler
>(); break;
128 case AL_EFFECT_DEDICATED_DIALOGUE
:
129 effect
->PropsVariant
.emplace
<DedicatedDialogEffectHandler
>();
131 case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
:
132 effect
->PropsVariant
.emplace
<DedicatedLfeEffectHandler
>();
134 case AL_EFFECT_CONVOLUTION_SOFT
:
135 effect
->PropsVariant
.emplace
<ConvolutionEffectHandler
>();
138 effect
->Props
= GetDefaultProps(type
);
142 auto EnsureEffects(ALCdevice
*device
, size_t needed
) noexcept
-> bool
144 size_t count
{std::accumulate(device
->EffectList
.cbegin(), device
->EffectList
.cend(), 0_uz
,
145 [](size_t cur
, const EffectSubList
&sublist
) noexcept
-> size_t
146 { return cur
+ static_cast<ALuint
>(al::popcount(sublist
.FreeMask
)); })};
148 while(needed
> count
)
150 if(device
->EffectList
.size() >= 1<<25) UNLIKELY
153 EffectSubList sublist
{};
154 sublist
.FreeMask
= ~0_u64
;
155 sublist
.Effects
= SubListAllocator
{}.allocate(1);
156 device
->EffectList
.emplace_back(std::move(sublist
));
157 count
+= std::tuple_size_v
<SubListAllocator::value_type
>;
165 ALeffect
*AllocEffect(ALCdevice
*device
) noexcept
167 auto sublist
= std::find_if(device
->EffectList
.begin(), device
->EffectList
.end(),
168 [](const EffectSubList
&entry
) noexcept
-> bool
169 { return entry
.FreeMask
!= 0; });
170 auto lidx
= static_cast<ALuint
>(std::distance(device
->EffectList
.begin(), sublist
));
171 auto slidx
= static_cast<ALuint
>(al::countr_zero(sublist
->FreeMask
));
174 ALeffect
*effect
{al::construct_at(al::to_address(sublist
->Effects
->begin() + slidx
))};
175 InitEffectParams(effect
, AL_EFFECT_NULL
);
177 /* Add 1 to avoid effect ID 0. */
178 effect
->id
= ((lidx
<<6) | slidx
) + 1;
180 sublist
->FreeMask
&= ~(1_u64
<< slidx
);
185 void FreeEffect(ALCdevice
*device
, ALeffect
*effect
)
187 device
->mEffectNames
.erase(effect
->id
);
189 const ALuint id
{effect
->id
- 1};
190 const size_t lidx
{id
>> 6};
191 const ALuint slidx
{id
& 0x3f};
193 std::destroy_at(effect
);
195 device
->EffectList
[lidx
].FreeMask
|= 1_u64
<< slidx
;
198 inline auto LookupEffect(ALCdevice
*device
, ALuint id
) noexcept
-> ALeffect
*
200 const size_t lidx
{(id
-1) >> 6};
201 const ALuint slidx
{(id
-1) & 0x3f};
203 if(lidx
>= device
->EffectList
.size()) UNLIKELY
205 EffectSubList
&sublist
= device
->EffectList
[lidx
];
206 if(sublist
.FreeMask
& (1_u64
<< slidx
)) UNLIKELY
208 return al::to_address(sublist
.Effects
->begin() + slidx
);
213 AL_API
DECL_FUNC2(void, alGenEffects
, ALsizei
,n
, ALuint
*,effects
)
214 FORCE_ALIGN
void AL_APIENTRY
alGenEffectsDirect(ALCcontext
*context
, ALsizei n
, ALuint
*effects
) noexcept
217 throw al::context_error
{AL_INVALID_VALUE
, "Generating %d effects", n
};
218 if(n
<= 0) UNLIKELY
return;
220 ALCdevice
*device
{context
->mALDevice
.get()};
221 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
223 const al::span eids
{effects
, static_cast<ALuint
>(n
)};
224 if(!EnsureEffects(device
, eids
.size()))
225 throw al::context_error
{AL_OUT_OF_MEMORY
, "Failed to allocate %d effect%s", n
,
226 (n
== 1) ? "" : "s"};
228 std::generate(eids
.begin(), eids
.end(), [device
]{ return AllocEffect(device
)->id
; });
230 catch(al::context_error
& e
) {
231 context
->setError(e
.errorCode(), "%s", e
.what());
234 AL_API
DECL_FUNC2(void, alDeleteEffects
, ALsizei
,n
, const ALuint
*,effects
)
235 FORCE_ALIGN
void AL_APIENTRY
alDeleteEffectsDirect(ALCcontext
*context
, ALsizei n
,
236 const ALuint
*effects
) noexcept
239 throw al::context_error
{AL_INVALID_VALUE
, "Deleting %d effects", n
};
240 if(n
<= 0) UNLIKELY
return;
242 ALCdevice
*device
{context
->mALDevice
.get()};
243 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
245 /* First try to find any effects that are invalid. */
246 auto validate_effect
= [device
](const ALuint eid
) -> bool
247 { return !eid
|| LookupEffect(device
, eid
) != nullptr; };
249 const al::span eids
{effects
, static_cast<ALuint
>(n
)};
250 auto inveffect
= std::find_if_not(eids
.begin(), eids
.end(), validate_effect
);
251 if(inveffect
!= eids
.end())
252 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", *inveffect
};
254 /* All good. Delete non-0 effect IDs. */
255 auto delete_effect
= [device
](ALuint eid
) -> void
257 if(ALeffect
*effect
{eid
? LookupEffect(device
, eid
) : nullptr})
258 FreeEffect(device
, effect
);
260 std::for_each(eids
.begin(), eids
.end(), delete_effect
);
262 catch(al::context_error
& e
) {
263 context
->setError(e
.errorCode(), "%s", e
.what());
266 AL_API
DECL_FUNC1(ALboolean
, alIsEffect
, ALuint
,effect
)
267 FORCE_ALIGN ALboolean AL_APIENTRY
alIsEffectDirect(ALCcontext
*context
, ALuint effect
) noexcept
269 ALCdevice
*device
{context
->mALDevice
.get()};
270 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
271 if(!effect
|| LookupEffect(device
, effect
))
276 AL_API
DECL_FUNC3(void, alEffecti
, ALuint
,effect
, ALenum
,param
, ALint
,value
)
277 FORCE_ALIGN
void AL_APIENTRY
alEffectiDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
278 ALint value
) noexcept
280 ALCdevice
*device
{context
->mALDevice
.get()};
281 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
283 ALeffect
*aleffect
{LookupEffect(device
, effect
)};
285 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
290 if(value
!= AL_EFFECT_NULL
)
292 auto check_effect
= [value
](const EffectList
&item
) -> bool
293 { return value
== item
.val
&& !DisabledEffects
.test(item
.type
); };
294 if(!std::any_of(gEffectList
.cbegin(), gEffectList
.cend(), check_effect
))
295 throw al::context_error
{AL_INVALID_VALUE
, "Effect type 0x%04x not supported",
299 InitEffectParams(aleffect
, value
);
303 /* Call the appropriate handler */
304 std::visit([aleffect
,param
,value
](auto &arg
)
306 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
307 using PropType
= typename
Type::prop_type
;
308 return arg
.SetParami(std::get
<PropType
>(aleffect
->Props
), param
, value
);
309 }, aleffect
->PropsVariant
);
311 catch(al::context_error
& e
) {
312 context
->setError(e
.errorCode(), "%s", e
.what());
315 AL_API
DECL_FUNC3(void, alEffectiv
, ALuint
,effect
, ALenum
,param
, const ALint
*,values
)
316 FORCE_ALIGN
void AL_APIENTRY
alEffectivDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
317 const ALint
*values
) noexcept
322 alEffectiDirect(context
, effect
, param
, *values
);
326 ALCdevice
*device
{context
->mALDevice
.get()};
327 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
329 ALeffect
*aleffect
{LookupEffect(device
, effect
)};
331 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
333 /* Call the appropriate handler */
334 std::visit([aleffect
,param
,values
](auto &arg
)
336 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
337 using PropType
= typename
Type::prop_type
;
338 return arg
.SetParamiv(std::get
<PropType
>(aleffect
->Props
), param
, values
);
339 }, aleffect
->PropsVariant
);
341 catch(al::context_error
& e
) {
342 context
->setError(e
.errorCode(), "%s", e
.what());
345 AL_API
DECL_FUNC3(void, alEffectf
, ALuint
,effect
, ALenum
,param
, ALfloat
,value
)
346 FORCE_ALIGN
void AL_APIENTRY
alEffectfDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
347 ALfloat value
) noexcept
349 ALCdevice
*device
{context
->mALDevice
.get()};
350 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
352 ALeffect
*aleffect
{LookupEffect(device
, effect
)};
353 if(!aleffect
) UNLIKELY
354 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
356 /* Call the appropriate handler */
357 std::visit([aleffect
,param
,value
](auto &arg
)
359 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
360 using PropType
= typename
Type::prop_type
;
361 return arg
.SetParamf(std::get
<PropType
>(aleffect
->Props
), param
, value
);
362 }, aleffect
->PropsVariant
);
364 catch(al::context_error
& e
) {
365 context
->setError(e
.errorCode(), "%s", e
.what());
368 AL_API
DECL_FUNC3(void, alEffectfv
, ALuint
,effect
, ALenum
,param
, const ALfloat
*,values
)
369 FORCE_ALIGN
void AL_APIENTRY
alEffectfvDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
370 const ALfloat
*values
) noexcept
372 ALCdevice
*device
{context
->mALDevice
.get()};
373 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
375 ALeffect
*aleffect
{LookupEffect(device
, effect
)};
377 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
379 /* Call the appropriate handler */
380 std::visit([aleffect
,param
,values
](auto &arg
)
382 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
383 using PropType
= typename
Type::prop_type
;
384 return arg
.SetParamfv(std::get
<PropType
>(aleffect
->Props
), param
, values
);
385 }, aleffect
->PropsVariant
);
387 catch(al::context_error
& e
) {
388 context
->setError(e
.errorCode(), "%s", e
.what());
391 AL_API
DECL_FUNC3(void, alGetEffecti
, ALuint
,effect
, ALenum
,param
, ALint
*,value
)
392 FORCE_ALIGN
void AL_APIENTRY
alGetEffectiDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
393 ALint
*value
) noexcept
395 ALCdevice
*device
{context
->mALDevice
.get()};
396 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
398 const ALeffect
*aleffect
{LookupEffect(device
, effect
)};
400 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
405 *value
= aleffect
->type
;
409 /* Call the appropriate handler */
410 std::visit([aleffect
,param
,value
](auto &arg
)
412 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
413 using PropType
= typename
Type::prop_type
;
414 return arg
.GetParami(std::get
<PropType
>(aleffect
->Props
), param
, value
);
415 }, aleffect
->PropsVariant
);
417 catch(al::context_error
& e
) {
418 context
->setError(e
.errorCode(), "%s", e
.what());
421 AL_API
DECL_FUNC3(void, alGetEffectiv
, ALuint
,effect
, ALenum
,param
, ALint
*,values
)
422 FORCE_ALIGN
void AL_APIENTRY
alGetEffectivDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
423 ALint
*values
) noexcept
428 alGetEffectiDirect(context
, effect
, param
, values
);
432 ALCdevice
*device
{context
->mALDevice
.get()};
433 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
435 const ALeffect
*aleffect
{LookupEffect(device
, effect
)};
437 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
439 /* Call the appropriate handler */
440 std::visit([aleffect
,param
,values
](auto &arg
)
442 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
443 using PropType
= typename
Type::prop_type
;
444 return arg
.GetParamiv(std::get
<PropType
>(aleffect
->Props
), param
, values
);
445 }, aleffect
->PropsVariant
);
447 catch(al::context_error
& e
) {
448 context
->setError(e
.errorCode(), "%s", e
.what());
451 AL_API
DECL_FUNC3(void, alGetEffectf
, ALuint
,effect
, ALenum
,param
, ALfloat
*,value
)
452 FORCE_ALIGN
void AL_APIENTRY
alGetEffectfDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
453 ALfloat
*value
) noexcept
455 ALCdevice
*device
{context
->mALDevice
.get()};
456 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
458 const ALeffect
*aleffect
{LookupEffect(device
, effect
)};
460 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
462 /* Call the appropriate handler */
463 std::visit([aleffect
,param
,value
](auto &arg
)
465 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
466 using PropType
= typename
Type::prop_type
;
467 return arg
.GetParamf(std::get
<PropType
>(aleffect
->Props
), param
, value
);
468 }, aleffect
->PropsVariant
);
470 catch(al::context_error
& e
) {
471 context
->setError(e
.errorCode(), "%s", e
.what());
474 AL_API
DECL_FUNC3(void, alGetEffectfv
, ALuint
,effect
, ALenum
,param
, ALfloat
*,values
)
475 FORCE_ALIGN
void AL_APIENTRY
alGetEffectfvDirect(ALCcontext
*context
, ALuint effect
, ALenum param
,
476 ALfloat
*values
) noexcept
478 ALCdevice
*device
{context
->mALDevice
.get()};
479 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
481 const ALeffect
*aleffect
{LookupEffect(device
, effect
)};
483 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", effect
};
485 /* Call the appropriate handler */
486 std::visit([aleffect
,param
,values
](auto &arg
)
488 using Type
= std::remove_cv_t
<std::remove_reference_t
<decltype(arg
)>>;
489 using PropType
= typename
Type::prop_type
;
490 return arg
.GetParamfv(std::get
<PropType
>(aleffect
->Props
), param
, values
);
491 }, aleffect
->PropsVariant
);
493 catch(al::context_error
& e
) {
494 context
->setError(e
.errorCode(), "%s", e
.what());
498 void InitEffect(ALeffect
*effect
)
500 InitEffectParams(effect
, AL_EFFECT_NULL
);
503 void ALeffect::SetName(ALCcontext
* context
, ALuint id
, std::string_view name
)
505 ALCdevice
*device
{context
->mALDevice
.get()};
506 std::lock_guard
<std::mutex
> effectlock
{device
->EffectLock
};
508 auto effect
= LookupEffect(device
, id
);
510 throw al::context_error
{AL_INVALID_NAME
, "Invalid effect ID %u", id
};
512 device
->mEffectNames
.insert_or_assign(id
, name
);
516 EffectSubList::~EffectSubList()
521 uint64_t usemask
{~FreeMask
};
524 const int idx
{al::countr_zero(usemask
)};
525 std::destroy_at(al::to_address(Effects
->begin()+idx
));
526 usemask
&= ~(1_u64
<< idx
);
529 SubListAllocator
{}.deallocate(Effects
, 1);
534 struct EffectPreset
{
535 const char name
[32]; /* NOLINT(*-avoid-c-arrays) */
536 EFXEAXREVERBPROPERTIES props
;
538 #define DECL(x) EffectPreset{#x, EFX_REVERB_PRESET_##x}
539 static constexpr std::array reverblist
{
551 DECL(CARPETEDHALLWAY
),
567 DECL(CASTLE_SMALLROOM
),
568 DECL(CASTLE_SHORTPASSAGE
),
569 DECL(CASTLE_MEDIUMROOM
),
570 DECL(CASTLE_LARGEROOM
),
571 DECL(CASTLE_LONGPASSAGE
),
573 DECL(CASTLE_CUPBOARD
),
574 DECL(CASTLE_COURTYARD
),
577 DECL(FACTORY_SMALLROOM
),
578 DECL(FACTORY_SHORTPASSAGE
),
579 DECL(FACTORY_MEDIUMROOM
),
580 DECL(FACTORY_LARGEROOM
),
581 DECL(FACTORY_LONGPASSAGE
),
583 DECL(FACTORY_CUPBOARD
),
584 DECL(FACTORY_COURTYARD
),
585 DECL(FACTORY_ALCOVE
),
587 DECL(ICEPALACE_SMALLROOM
),
588 DECL(ICEPALACE_SHORTPASSAGE
),
589 DECL(ICEPALACE_MEDIUMROOM
),
590 DECL(ICEPALACE_LARGEROOM
),
591 DECL(ICEPALACE_LONGPASSAGE
),
592 DECL(ICEPALACE_HALL
),
593 DECL(ICEPALACE_CUPBOARD
),
594 DECL(ICEPALACE_COURTYARD
),
595 DECL(ICEPALACE_ALCOVE
),
597 DECL(SPACESTATION_SMALLROOM
),
598 DECL(SPACESTATION_SHORTPASSAGE
),
599 DECL(SPACESTATION_MEDIUMROOM
),
600 DECL(SPACESTATION_LARGEROOM
),
601 DECL(SPACESTATION_LONGPASSAGE
),
602 DECL(SPACESTATION_HALL
),
603 DECL(SPACESTATION_CUPBOARD
),
604 DECL(SPACESTATION_ALCOVE
),
606 DECL(WOODEN_SMALLROOM
),
607 DECL(WOODEN_SHORTPASSAGE
),
608 DECL(WOODEN_MEDIUMROOM
),
609 DECL(WOODEN_LARGEROOM
),
610 DECL(WOODEN_LONGPASSAGE
),
612 DECL(WOODEN_CUPBOARD
),
613 DECL(WOODEN_COURTYARD
),
616 DECL(SPORT_EMPTYSTADIUM
),
617 DECL(SPORT_SQUASHCOURT
),
618 DECL(SPORT_SMALLSWIMMINGPOOL
),
619 DECL(SPORT_LARGESWIMMINGPOOL
),
620 DECL(SPORT_GYMNASIUM
),
621 DECL(SPORT_FULLSTADIUM
),
622 DECL(SPORT_STADIUMTANNOY
),
624 DECL(PREFAB_WORKSHOP
),
625 DECL(PREFAB_SCHOOLROOM
),
626 DECL(PREFAB_PRACTISEROOM
),
627 DECL(PREFAB_OUTHOUSE
),
628 DECL(PREFAB_CARAVAN
),
632 DECL(DOME_SAINTPAULS
),
637 DECL(OUTDOORS_BACKYARD
),
638 DECL(OUTDOORS_ROLLINGPLAINS
),
639 DECL(OUTDOORS_DEEPCANYON
),
640 DECL(OUTDOORS_CREEK
),
641 DECL(OUTDOORS_VALLEY
),
647 DECL(DRIVING_COMMENTATOR
),
648 DECL(DRIVING_PITGARAGE
),
649 DECL(DRIVING_INCAR_RACER
),
650 DECL(DRIVING_INCAR_SPORTS
),
651 DECL(DRIVING_INCAR_LUXURY
),
652 DECL(DRIVING_FULLGRANDSTAND
),
653 DECL(DRIVING_EMPTYGRANDSTAND
),
654 DECL(DRIVING_TUNNEL
),
660 DECL(CITY_UNDERPASS
),
661 DECL(CITY_ABANDONED
),
665 DECL(SMALLWATERROOM
),
669 void LoadReverbPreset(const std::string_view name
, ALeffect
*effect
)
671 using namespace std::string_view_literals
;
673 if(al::case_compare(name
, "NONE"sv
) == 0)
675 InitEffectParams(effect
, AL_EFFECT_NULL
);
676 TRACE("Loading reverb '%s'\n", "NONE");
680 if(!DisabledEffects
.test(EAXREVERB_EFFECT
))
681 InitEffectParams(effect
, AL_EFFECT_EAXREVERB
);
682 else if(!DisabledEffects
.test(REVERB_EFFECT
))
683 InitEffectParams(effect
, AL_EFFECT_REVERB
);
685 InitEffectParams(effect
, AL_EFFECT_NULL
);
686 for(const auto &reverbitem
: reverblist
)
688 if(al::case_compare(name
, std::data(reverbitem
.name
)) != 0)
691 TRACE("Loading reverb '%s'\n", std::data(reverbitem
.name
));
692 const auto &props
= reverbitem
.props
;
693 auto &dst
= std::get
<ReverbProps
>(effect
->Props
);
694 dst
.Density
= props
.flDensity
;
695 dst
.Diffusion
= props
.flDiffusion
;
696 dst
.Gain
= props
.flGain
;
697 dst
.GainHF
= props
.flGainHF
;
698 dst
.GainLF
= props
.flGainLF
;
699 dst
.DecayTime
= props
.flDecayTime
;
700 dst
.DecayHFRatio
= props
.flDecayHFRatio
;
701 dst
.DecayLFRatio
= props
.flDecayLFRatio
;
702 dst
.ReflectionsGain
= props
.flReflectionsGain
;
703 dst
.ReflectionsDelay
= props
.flReflectionsDelay
;
704 dst
.ReflectionsPan
[0] = props
.flReflectionsPan
[0];
705 dst
.ReflectionsPan
[1] = props
.flReflectionsPan
[1];
706 dst
.ReflectionsPan
[2] = props
.flReflectionsPan
[2];
707 dst
.LateReverbGain
= props
.flLateReverbGain
;
708 dst
.LateReverbDelay
= props
.flLateReverbDelay
;
709 dst
.LateReverbPan
[0] = props
.flLateReverbPan
[0];
710 dst
.LateReverbPan
[1] = props
.flLateReverbPan
[1];
711 dst
.LateReverbPan
[2] = props
.flLateReverbPan
[2];
712 dst
.EchoTime
= props
.flEchoTime
;
713 dst
.EchoDepth
= props
.flEchoDepth
;
714 dst
.ModulationTime
= props
.flModulationTime
;
715 dst
.ModulationDepth
= props
.flModulationDepth
;
716 dst
.AirAbsorptionGainHF
= props
.flAirAbsorptionGainHF
;
717 dst
.HFReference
= props
.flHFReference
;
718 dst
.LFReference
= props
.flLFReference
;
719 dst
.RoomRolloffFactor
= props
.flRoomRolloffFactor
;
720 dst
.DecayHFLimit
= props
.iDecayHFLimit
? AL_TRUE
: AL_FALSE
;
724 WARN("Reverb preset '%.*s' not found\n", al::sizei(name
), name
.data());
727 bool IsValidEffectType(ALenum type
) noexcept
729 if(type
== AL_EFFECT_NULL
)
732 auto check_effect
= [type
](const EffectList
&item
) noexcept
-> bool
733 { return type
== item
.val
&& !DisabledEffects
.test(item
.type
); };
734 return std::any_of(gEffectList
.cbegin(), gEffectList
.cend(), check_effect
);