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
39 #include "AL/efx-presets.h"
43 #include "alc/context.h"
44 #include "alc/device.h"
45 #include "alc/effects/base.h"
46 #include "alc/inprogext.h"
48 #include "alnumeric.h"
50 #include "core/except.h"
51 #include "core/logging.h"
52 #include "direct_defs.h"
53 #include "opthelpers.h"
58 #include "eax/exception.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
},
81 effect_exception::effect_exception(ALenum code
, const char *msg
, ...) : mErrorCode
{code
}
83 /* NOLINTBEGIN(*-array-to-pointer-decay) */
86 setMessage(msg
, args
);
88 /* NOLINTEND(*-array-to-pointer-decay) */
90 effect_exception::~effect_exception() = default;
94 using SubListAllocator
= typename
al::allocator
<std::array
<ALeffect
,64>>;
96 auto GetDefaultProps(ALenum type
) -> const EffectProps
&
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
);
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
)); })};
134 while(needed
> count
)
136 if(device
->EffectList
.size() >= 1<<25) UNLIKELY
139 EffectSubList sublist
{};
140 sublist
.FreeMask
= ~0_u64
;
141 sublist
.Effects
= SubListAllocator
{}.allocate(1);
142 device
->EffectList
.emplace_back(std::move(sublist
));
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
));
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
);
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
192 EffectSubList
&sublist
= device
->EffectList
[lidx
];
193 if(sublist
.FreeMask
& (1_u64
<< slidx
)) UNLIKELY
195 return al::to_address(sublist
.Effects
->begin() + slidx
);
200 AL_API
DECL_FUNC2(void, alGenEffects
, ALsizei
, ALuint
*)
201 FORCE_ALIGN
void AL_APIENTRY
alGenEffectsDirect(ALCcontext
*context
, ALsizei n
, ALuint
*effects
) noexcept
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");
217 /* Special handling for the easy and normal case. */
218 *effects
= AllocEffect(device
)->id
;
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
));
228 ALeffect
*effect
{AllocEffect(device
)};
229 ids
.emplace_back(effect
->id
);
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
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
);
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
))
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
};
293 for(const EffectList
&effectitem
: gEffectList
)
295 if(value
== effectitem
.val
&& !DisabledEffects
.test(effectitem
.type
))
304 InitEffectParams(aleffect
, value
);
306 context
->setError(AL_INVALID_VALUE
, "Effect type 0x%04x not supported", value
);
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
);
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
334 alEffectiDirect(context
, effect
, param
, values
[0]);
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
);
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
);
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
);
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
);
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
);
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
);
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
;
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
);
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
459 alGetEffectiDirect(context
, effect
, param
, values
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
559 return context
->setError(AL_INVALID_NAME
, "Invalid effect ID %u", id
);
561 device
->mEffectNames
.insert_or_assign(id
, name
);
565 EffectSubList::~EffectSubList()
570 uint64_t usemask
{~FreeMask
};
573 const int idx
{al::countr_zero(usemask
)};
574 std::destroy_at(al::to_address(Effects
->begin()+idx
));
575 usemask
&= ~(1_u64
<< idx
);
578 SubListAllocator
{}.deallocate(Effects
, 1);
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
{
600 DECL(CARPETEDHALLWAY
),
616 DECL(CASTLE_SMALLROOM
),
617 DECL(CASTLE_SHORTPASSAGE
),
618 DECL(CASTLE_MEDIUMROOM
),
619 DECL(CASTLE_LARGEROOM
),
620 DECL(CASTLE_LONGPASSAGE
),
622 DECL(CASTLE_CUPBOARD
),
623 DECL(CASTLE_COURTYARD
),
626 DECL(FACTORY_SMALLROOM
),
627 DECL(FACTORY_SHORTPASSAGE
),
628 DECL(FACTORY_MEDIUMROOM
),
629 DECL(FACTORY_LARGEROOM
),
630 DECL(FACTORY_LONGPASSAGE
),
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
),
661 DECL(WOODEN_CUPBOARD
),
662 DECL(WOODEN_COURTYARD
),
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
),
681 DECL(DOME_SAINTPAULS
),
686 DECL(OUTDOORS_BACKYARD
),
687 DECL(OUTDOORS_ROLLINGPLAINS
),
688 DECL(OUTDOORS_DEEPCANYON
),
689 DECL(OUTDOORS_CREEK
),
690 DECL(OUTDOORS_VALLEY
),
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
),
709 DECL(CITY_UNDERPASS
),
710 DECL(CITY_ABANDONED
),
714 DECL(SMALLWATERROOM
),
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");
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
);
734 InitEffectParams(effect
, AL_EFFECT_NULL
);
735 for(const auto &reverbitem
: reverblist
)
737 if(al::case_compare(name
, std::data(reverbitem
.name
)) != 0)
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
;
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
)
781 for(const auto &effect_item
: gEffectList
)
783 if(type
== effect_item
.val
&& !DisabledEffects
.test(effect_item
.type
))