|
|
-
- #include "config.h"
-
- #include <cmath>
- #include <cstdlib>
-
- #include <algorithm>
-
- #include "AL/efx.h"
-
- #include "alc/effects/base.h"
- #include "effects.h"
-
- #ifdef ALSOFT_EAX
- #include "alnumeric.h"
-
- #include "al/eax_exception.h"
- #include "al/eax_utils.h"
- #endif // ALSOFT_EAX
-
-
- namespace {
-
- void Autowah_setParamf(EffectProps *props, ALenum param, float val)
- {
- switch(param)
- {
- case AL_AUTOWAH_ATTACK_TIME:
- if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
- throw effect_exception{AL_INVALID_VALUE, "Autowah attack time out of range"};
- props->Autowah.AttackTime = val;
- break;
-
- case AL_AUTOWAH_RELEASE_TIME:
- if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
- throw effect_exception{AL_INVALID_VALUE, "Autowah release time out of range"};
- props->Autowah.ReleaseTime = val;
- break;
-
- case AL_AUTOWAH_RESONANCE:
- if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
- throw effect_exception{AL_INVALID_VALUE, "Autowah resonance out of range"};
- props->Autowah.Resonance = val;
- break;
-
- case AL_AUTOWAH_PEAK_GAIN:
- if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
- throw effect_exception{AL_INVALID_VALUE, "Autowah peak gain out of range"};
- props->Autowah.PeakGain = val;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
- }
- }
- void Autowah_setParamfv(EffectProps *props, ALenum param, const float *vals)
- { Autowah_setParamf(props, param, vals[0]); }
-
- void Autowah_setParami(EffectProps*, ALenum param, int)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
- void Autowah_setParamiv(EffectProps*, ALenum param, const int*)
- {
- throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
- param};
- }
-
- void Autowah_getParamf(const EffectProps *props, ALenum param, float *val)
- {
- switch(param)
- {
- case AL_AUTOWAH_ATTACK_TIME:
- *val = props->Autowah.AttackTime;
- break;
-
- case AL_AUTOWAH_RELEASE_TIME:
- *val = props->Autowah.ReleaseTime;
- break;
-
- case AL_AUTOWAH_RESONANCE:
- *val = props->Autowah.Resonance;
- break;
-
- case AL_AUTOWAH_PEAK_GAIN:
- *val = props->Autowah.PeakGain;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
- }
-
- }
- void Autowah_getParamfv(const EffectProps *props, ALenum param, float *vals)
- { Autowah_getParamf(props, param, vals); }
-
- void Autowah_getParami(const EffectProps*, ALenum param, int*)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
- void Autowah_getParamiv(const EffectProps*, ALenum param, int*)
- {
- throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
- param};
- }
-
- EffectProps genDefaultProps() noexcept
- {
- EffectProps props{};
- props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
- props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
- props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
- props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
- return props;
- }
-
- } // namespace
-
- DEFINE_ALEFFECT_VTABLE(Autowah);
-
- const EffectProps AutowahEffectProps{genDefaultProps()};
-
- #ifdef ALSOFT_EAX
- namespace {
-
- using EaxAutoWahEffectDirtyFlagsValue = std::uint_least8_t;
-
- struct EaxAutoWahEffectDirtyFlags
- {
- using EaxIsBitFieldStruct = bool;
-
- EaxAutoWahEffectDirtyFlagsValue flAttackTime : 1;
- EaxAutoWahEffectDirtyFlagsValue flReleaseTime : 1;
- EaxAutoWahEffectDirtyFlagsValue lResonance : 1;
- EaxAutoWahEffectDirtyFlagsValue lPeakLevel : 1;
- }; // EaxAutoWahEffectDirtyFlags
-
-
- class EaxAutoWahEffect final :
- public EaxEffect
- {
- public:
- EaxAutoWahEffect();
-
-
- void dispatch(const EaxEaxCall& eax_call) override;
-
- // [[nodiscard]]
- bool apply_deferred() override;
-
- private:
- EAXAUTOWAHPROPERTIES eax_{};
- EAXAUTOWAHPROPERTIES eax_d_{};
- EaxAutoWahEffectDirtyFlags eax_dirty_flags_{};
-
-
- void set_eax_defaults();
-
-
- void set_efx_attack_time();
-
- void set_efx_release_time();
-
- void set_efx_resonance();
-
- void set_efx_peak_gain();
-
- void set_efx_defaults();
-
-
- void get(const EaxEaxCall& eax_call);
-
-
- void validate_attack_time(
- float flAttackTime);
-
- void validate_release_time(
- float flReleaseTime);
-
- void validate_resonance(
- long lResonance);
-
- void validate_peak_level(
- long lPeakLevel);
-
- void validate_all(
- const EAXAUTOWAHPROPERTIES& eax_all);
-
-
- void defer_attack_time(
- float flAttackTime);
-
- void defer_release_time(
- float flReleaseTime);
-
- void defer_resonance(
- long lResonance);
-
- void defer_peak_level(
- long lPeakLevel);
-
- void defer_all(
- const EAXAUTOWAHPROPERTIES& eax_all);
-
-
- void defer_attack_time(
- const EaxEaxCall& eax_call);
-
- void defer_release_time(
- const EaxEaxCall& eax_call);
-
- void defer_resonance(
- const EaxEaxCall& eax_call);
-
- void defer_peak_level(
- const EaxEaxCall& eax_call);
-
- void defer_all(
- const EaxEaxCall& eax_call);
-
- void set(const EaxEaxCall& eax_call);
- }; // EaxAutoWahEffect
-
-
- class EaxAutoWahEffectException :
- public EaxException
- {
- public:
- explicit EaxAutoWahEffectException(
- const char* message)
- :
- EaxException{"EAX_AUTO_WAH_EFFECT", message}
- {
- }
- }; // EaxAutoWahEffectException
-
-
- EaxAutoWahEffect::EaxAutoWahEffect()
- : EaxEffect{AL_EFFECT_AUTOWAH}
- {
- set_eax_defaults();
- set_efx_defaults();
- }
-
- void EaxAutoWahEffect::dispatch(const EaxEaxCall& eax_call)
- {
- eax_call.is_get() ? get(eax_call) : set(eax_call);
- }
-
- void EaxAutoWahEffect::set_eax_defaults()
- {
- eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
- eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
- eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
- eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
-
- eax_d_ = eax_;
- }
-
- void EaxAutoWahEffect::set_efx_attack_time()
- {
- const auto attack_time = clamp(
- eax_.flAttackTime,
- AL_AUTOWAH_MIN_ATTACK_TIME,
- AL_AUTOWAH_MAX_ATTACK_TIME);
-
- al_effect_props_.Autowah.AttackTime = attack_time;
- }
-
- void EaxAutoWahEffect::set_efx_release_time()
- {
- const auto release_time = clamp(
- eax_.flReleaseTime,
- AL_AUTOWAH_MIN_RELEASE_TIME,
- AL_AUTOWAH_MAX_RELEASE_TIME);
-
- al_effect_props_.Autowah.ReleaseTime = release_time;
- }
-
- void EaxAutoWahEffect::set_efx_resonance()
- {
- const auto resonance = clamp(
- level_mb_to_gain(static_cast<float>(eax_.lResonance)),
- AL_AUTOWAH_MIN_RESONANCE,
- AL_AUTOWAH_MAX_RESONANCE);
-
- al_effect_props_.Autowah.Resonance = resonance;
- }
-
- void EaxAutoWahEffect::set_efx_peak_gain()
- {
- const auto peak_gain = clamp(
- level_mb_to_gain(static_cast<float>(eax_.lPeakLevel)),
- AL_AUTOWAH_MIN_PEAK_GAIN,
- AL_AUTOWAH_MAX_PEAK_GAIN);
-
- al_effect_props_.Autowah.PeakGain = peak_gain;
- }
-
- void EaxAutoWahEffect::set_efx_defaults()
- {
- set_efx_attack_time();
- set_efx_release_time();
- set_efx_resonance();
- set_efx_peak_gain();
- }
-
- void EaxAutoWahEffect::get(const EaxEaxCall& eax_call)
- {
- switch (eax_call.get_property_id())
- {
- case EAXAUTOWAH_NONE:
- break;
-
- case EAXAUTOWAH_ALLPARAMETERS:
- eax_call.set_value<EaxAutoWahEffectException>(eax_);
- break;
-
- case EAXAUTOWAH_ATTACKTIME:
- eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
- break;
-
- case EAXAUTOWAH_RELEASETIME:
- eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
- break;
-
- case EAXAUTOWAH_RESONANCE:
- eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
- break;
-
- case EAXAUTOWAH_PEAKLEVEL:
- eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
- break;
-
- default:
- throw EaxAutoWahEffectException{"Unsupported property id."};
- }
- }
-
- void EaxAutoWahEffect::validate_attack_time(
- float flAttackTime)
- {
- eax_validate_range<EaxAutoWahEffectException>(
- "Attack Time",
- flAttackTime,
- EAXAUTOWAH_MINATTACKTIME,
- EAXAUTOWAH_MAXATTACKTIME);
- }
-
- void EaxAutoWahEffect::validate_release_time(
- float flReleaseTime)
- {
- eax_validate_range<EaxAutoWahEffectException>(
- "Release Time",
- flReleaseTime,
- EAXAUTOWAH_MINRELEASETIME,
- EAXAUTOWAH_MAXRELEASETIME);
- }
-
- void EaxAutoWahEffect::validate_resonance(
- long lResonance)
- {
- eax_validate_range<EaxAutoWahEffectException>(
- "Resonance",
- lResonance,
- EAXAUTOWAH_MINRESONANCE,
- EAXAUTOWAH_MAXRESONANCE);
- }
-
- void EaxAutoWahEffect::validate_peak_level(
- long lPeakLevel)
- {
- eax_validate_range<EaxAutoWahEffectException>(
- "Peak Level",
- lPeakLevel,
- EAXAUTOWAH_MINPEAKLEVEL,
- EAXAUTOWAH_MAXPEAKLEVEL);
- }
-
- void EaxAutoWahEffect::validate_all(
- const EAXAUTOWAHPROPERTIES& eax_all)
- {
- validate_attack_time(eax_all.flAttackTime);
- validate_release_time(eax_all.flReleaseTime);
- validate_resonance(eax_all.lResonance);
- validate_peak_level(eax_all.lPeakLevel);
- }
-
- void EaxAutoWahEffect::defer_attack_time(
- float flAttackTime)
- {
- eax_d_.flAttackTime = flAttackTime;
- eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime);
- }
-
- void EaxAutoWahEffect::defer_release_time(
- float flReleaseTime)
- {
- eax_d_.flReleaseTime = flReleaseTime;
- eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime);
- }
-
- void EaxAutoWahEffect::defer_resonance(
- long lResonance)
- {
- eax_d_.lResonance = lResonance;
- eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance);
- }
-
- void EaxAutoWahEffect::defer_peak_level(
- long lPeakLevel)
- {
- eax_d_.lPeakLevel = lPeakLevel;
- eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel);
- }
-
- void EaxAutoWahEffect::defer_all(
- const EAXAUTOWAHPROPERTIES& eax_all)
- {
- validate_all(eax_all);
-
- defer_attack_time(eax_all.flAttackTime);
- defer_release_time(eax_all.flReleaseTime);
- defer_resonance(eax_all.lResonance);
- defer_peak_level(eax_all.lPeakLevel);
- }
-
- void EaxAutoWahEffect::defer_attack_time(
- const EaxEaxCall& eax_call)
- {
- const auto& attack_time =
- eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
-
- validate_attack_time(attack_time);
- defer_attack_time(attack_time);
- }
-
- void EaxAutoWahEffect::defer_release_time(
- const EaxEaxCall& eax_call)
- {
- const auto& release_time =
- eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
-
- validate_release_time(release_time);
- defer_release_time(release_time);
- }
-
- void EaxAutoWahEffect::defer_resonance(
- const EaxEaxCall& eax_call)
- {
- const auto& resonance =
- eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
-
- validate_resonance(resonance);
- defer_resonance(resonance);
- }
-
- void EaxAutoWahEffect::defer_peak_level(
- const EaxEaxCall& eax_call)
- {
- const auto& peak_level =
- eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
-
- validate_peak_level(peak_level);
- defer_peak_level(peak_level);
- }
-
- void EaxAutoWahEffect::defer_all(
- const EaxEaxCall& eax_call)
- {
- const auto& all =
- eax_call.get_value<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
-
- validate_all(all);
- defer_all(all);
- }
-
- // [[nodiscard]]
- bool EaxAutoWahEffect::apply_deferred()
- {
- if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{})
- {
- return false;
- }
-
- eax_ = eax_d_;
-
- if (eax_dirty_flags_.flAttackTime)
- {
- set_efx_attack_time();
- }
-
- if (eax_dirty_flags_.flReleaseTime)
- {
- set_efx_release_time();
- }
-
- if (eax_dirty_flags_.lResonance)
- {
- set_efx_resonance();
- }
-
- if (eax_dirty_flags_.lPeakLevel)
- {
- set_efx_peak_gain();
- }
-
- eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{};
-
- return true;
- }
-
- void EaxAutoWahEffect::set(const EaxEaxCall& eax_call)
- {
- switch (eax_call.get_property_id())
- {
- case EAXAUTOWAH_NONE:
- break;
-
- case EAXAUTOWAH_ALLPARAMETERS:
- defer_all(eax_call);
- break;
-
- case EAXAUTOWAH_ATTACKTIME:
- defer_attack_time(eax_call);
- break;
-
- case EAXAUTOWAH_RELEASETIME:
- defer_release_time(eax_call);
- break;
-
- case EAXAUTOWAH_RESONANCE:
- defer_resonance(eax_call);
- break;
-
- case EAXAUTOWAH_PEAKLEVEL:
- defer_peak_level(eax_call);
- break;
-
- default:
- throw EaxAutoWahEffectException{"Unsupported property id."};
- }
- }
-
- } // namespace
-
- EaxEffectUPtr eax_create_eax_auto_wah_effect()
- {
- return std::make_unique<::EaxAutoWahEffect>();
- }
-
- #endif // ALSOFT_EAX
|