|
|
-
- #include "config.h"
-
- #include "AL/al.h"
- #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 Distortion_setParami(EffectProps*, ALenum param, int)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
- void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
- {
- throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
- param};
- }
- void Distortion_setParamf(EffectProps *props, ALenum param, float val)
- {
- switch(param)
- {
- case AL_DISTORTION_EDGE:
- if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
- throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
- props->Distortion.Edge = val;
- break;
-
- case AL_DISTORTION_GAIN:
- if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
- throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
- props->Distortion.Gain = val;
- break;
-
- case AL_DISTORTION_LOWPASS_CUTOFF:
- if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
- throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
- props->Distortion.LowpassCutoff = val;
- break;
-
- case AL_DISTORTION_EQCENTER:
- if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
- throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
- props->Distortion.EQCenter = val;
- break;
-
- case AL_DISTORTION_EQBANDWIDTH:
- if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
- throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
- props->Distortion.EQBandwidth = val;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
- }
- }
- void Distortion_setParamfv(EffectProps *props, ALenum param, const float *vals)
- { Distortion_setParamf(props, param, vals[0]); }
-
- void Distortion_getParami(const EffectProps*, ALenum param, int*)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
- void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
- {
- throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
- param};
- }
- void Distortion_getParamf(const EffectProps *props, ALenum param, float *val)
- {
- switch(param)
- {
- case AL_DISTORTION_EDGE:
- *val = props->Distortion.Edge;
- break;
-
- case AL_DISTORTION_GAIN:
- *val = props->Distortion.Gain;
- break;
-
- case AL_DISTORTION_LOWPASS_CUTOFF:
- *val = props->Distortion.LowpassCutoff;
- break;
-
- case AL_DISTORTION_EQCENTER:
- *val = props->Distortion.EQCenter;
- break;
-
- case AL_DISTORTION_EQBANDWIDTH:
- *val = props->Distortion.EQBandwidth;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
- }
- }
- void Distortion_getParamfv(const EffectProps *props, ALenum param, float *vals)
- { Distortion_getParamf(props, param, vals); }
-
- EffectProps genDefaultProps() noexcept
- {
- EffectProps props{};
- props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
- props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
- props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
- props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
- props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
- return props;
- }
-
- } // namespace
-
- DEFINE_ALEFFECT_VTABLE(Distortion);
-
- const EffectProps DistortionEffectProps{genDefaultProps()};
-
- #ifdef ALSOFT_EAX
- namespace {
-
- using EaxDistortionEffectDirtyFlagsValue = std::uint_least8_t;
-
- struct EaxDistortionEffectDirtyFlags
- {
- using EaxIsBitFieldStruct = bool;
-
- EaxDistortionEffectDirtyFlagsValue flEdge : 1;
- EaxDistortionEffectDirtyFlagsValue lGain : 1;
- EaxDistortionEffectDirtyFlagsValue flLowPassCutOff : 1;
- EaxDistortionEffectDirtyFlagsValue flEQCenter : 1;
- EaxDistortionEffectDirtyFlagsValue flEQBandwidth : 1;
- }; // EaxDistortionEffectDirtyFlags
-
-
- class EaxDistortionEffect final :
- public EaxEffect
- {
- public:
- EaxDistortionEffect();
-
- void dispatch(const EaxEaxCall& eax_call) override;
-
- // [[nodiscard]]
- bool apply_deferred() override;
-
- private:
- EAXDISTORTIONPROPERTIES eax_{};
- EAXDISTORTIONPROPERTIES eax_d_{};
- EaxDistortionEffectDirtyFlags eax_dirty_flags_{};
-
- void set_eax_defaults();
-
- void set_efx_edge();
- void set_efx_gain();
- void set_efx_lowpass_cutoff();
- void set_efx_eq_center();
- void set_efx_eq_bandwidth();
- void set_efx_defaults();
-
- void get(const EaxEaxCall& eax_call);
-
- void validate_edge(float flEdge);
- void validate_gain(long lGain);
- void validate_lowpass_cutoff(float flLowPassCutOff);
- void validate_eq_center(float flEQCenter);
- void validate_eq_bandwidth(float flEQBandwidth);
- void validate_all(const EAXDISTORTIONPROPERTIES& eax_all);
-
- void defer_edge(float flEdge);
- void defer_gain(long lGain);
- void defer_low_pass_cutoff(float flLowPassCutOff);
- void defer_eq_center(float flEQCenter);
- void defer_eq_bandwidth(float flEQBandwidth);
- void defer_all(const EAXDISTORTIONPROPERTIES& eax_all);
-
- void defer_edge(const EaxEaxCall& eax_call);
- void defer_gain(const EaxEaxCall& eax_call);
- void defer_low_pass_cutoff(const EaxEaxCall& eax_call);
- void defer_eq_center(const EaxEaxCall& eax_call);
- void defer_eq_bandwidth(const EaxEaxCall& eax_call);
- void defer_all(const EaxEaxCall& eax_call);
-
- void set(const EaxEaxCall& eax_call);
- }; // EaxDistortionEffect
-
-
- class EaxDistortionEffectException :
- public EaxException
- {
- public:
- explicit EaxDistortionEffectException(
- const char* message)
- :
- EaxException{"EAX_DISTORTION_EFFECT", message}
- {
- }
- }; // EaxDistortionEffectException
-
-
- EaxDistortionEffect::EaxDistortionEffect()
- : EaxEffect{AL_EFFECT_DISTORTION}
- {
- set_eax_defaults();
- set_efx_defaults();
- }
-
- void EaxDistortionEffect::dispatch(const EaxEaxCall& eax_call)
- {
- eax_call.is_get() ? get(eax_call) : set(eax_call);
- }
-
- void EaxDistortionEffect::set_eax_defaults()
- {
- eax_.flEdge = EAXDISTORTION_DEFAULTEDGE;
- eax_.lGain = EAXDISTORTION_DEFAULTGAIN;
- eax_.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
- eax_.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
- eax_.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
-
- eax_d_ = eax_;
- }
-
- void EaxDistortionEffect::set_efx_edge()
- {
- const auto edge = clamp(
- eax_.flEdge,
- AL_DISTORTION_MIN_EDGE,
- AL_DISTORTION_MAX_EDGE);
-
- al_effect_props_.Distortion.Edge = edge;
- }
-
- void EaxDistortionEffect::set_efx_gain()
- {
- const auto gain = clamp(
- level_mb_to_gain(static_cast<float>(eax_.lGain)),
- AL_DISTORTION_MIN_GAIN,
- AL_DISTORTION_MAX_GAIN);
-
- al_effect_props_.Distortion.Gain = gain;
- }
-
- void EaxDistortionEffect::set_efx_lowpass_cutoff()
- {
- const auto lowpass_cutoff = clamp(
- eax_.flLowPassCutOff,
- AL_DISTORTION_MIN_LOWPASS_CUTOFF,
- AL_DISTORTION_MAX_LOWPASS_CUTOFF);
-
- al_effect_props_.Distortion.LowpassCutoff = lowpass_cutoff;
- }
-
- void EaxDistortionEffect::set_efx_eq_center()
- {
- const auto eq_center = clamp(
- eax_.flEQCenter,
- AL_DISTORTION_MIN_EQCENTER,
- AL_DISTORTION_MAX_EQCENTER);
-
- al_effect_props_.Distortion.EQCenter = eq_center;
- }
-
- void EaxDistortionEffect::set_efx_eq_bandwidth()
- {
- const auto eq_bandwidth = clamp(
- eax_.flEdge,
- AL_DISTORTION_MIN_EQBANDWIDTH,
- AL_DISTORTION_MAX_EQBANDWIDTH);
-
- al_effect_props_.Distortion.EQBandwidth = eq_bandwidth;
- }
-
- void EaxDistortionEffect::set_efx_defaults()
- {
- set_efx_edge();
- set_efx_gain();
- set_efx_lowpass_cutoff();
- set_efx_eq_center();
- set_efx_eq_bandwidth();
- }
-
- void EaxDistortionEffect::get(const EaxEaxCall& eax_call)
- {
- switch(eax_call.get_property_id())
- {
- case EAXDISTORTION_NONE:
- break;
-
- case EAXDISTORTION_ALLPARAMETERS:
- eax_call.set_value<EaxDistortionEffectException>(eax_);
- break;
-
- case EAXDISTORTION_EDGE:
- eax_call.set_value<EaxDistortionEffectException>(eax_.flEdge);
- break;
-
- case EAXDISTORTION_GAIN:
- eax_call.set_value<EaxDistortionEffectException>(eax_.lGain);
- break;
-
- case EAXDISTORTION_LOWPASSCUTOFF:
- eax_call.set_value<EaxDistortionEffectException>(eax_.flLowPassCutOff);
- break;
-
- case EAXDISTORTION_EQCENTER:
- eax_call.set_value<EaxDistortionEffectException>(eax_.flEQCenter);
- break;
-
- case EAXDISTORTION_EQBANDWIDTH:
- eax_call.set_value<EaxDistortionEffectException>(eax_.flEQBandwidth);
- break;
-
- default:
- throw EaxDistortionEffectException{"Unsupported property id."};
- }
- }
-
- void EaxDistortionEffect::validate_edge(
- float flEdge)
- {
- eax_validate_range<EaxDistortionEffectException>(
- "Edge",
- flEdge,
- EAXDISTORTION_MINEDGE,
- EAXDISTORTION_MAXEDGE);
- }
-
- void EaxDistortionEffect::validate_gain(
- long lGain)
- {
- eax_validate_range<EaxDistortionEffectException>(
- "Gain",
- lGain,
- EAXDISTORTION_MINGAIN,
- EAXDISTORTION_MAXGAIN);
- }
-
- void EaxDistortionEffect::validate_lowpass_cutoff(
- float flLowPassCutOff)
- {
- eax_validate_range<EaxDistortionEffectException>(
- "Low-pass Cut-off",
- flLowPassCutOff,
- EAXDISTORTION_MINLOWPASSCUTOFF,
- EAXDISTORTION_MAXLOWPASSCUTOFF);
- }
-
- void EaxDistortionEffect::validate_eq_center(
- float flEQCenter)
- {
- eax_validate_range<EaxDistortionEffectException>(
- "EQ Center",
- flEQCenter,
- EAXDISTORTION_MINEQCENTER,
- EAXDISTORTION_MAXEQCENTER);
- }
-
- void EaxDistortionEffect::validate_eq_bandwidth(
- float flEQBandwidth)
- {
- eax_validate_range<EaxDistortionEffectException>(
- "EQ Bandwidth",
- flEQBandwidth,
- EAXDISTORTION_MINEQBANDWIDTH,
- EAXDISTORTION_MAXEQBANDWIDTH);
- }
-
- void EaxDistortionEffect::validate_all(
- const EAXDISTORTIONPROPERTIES& eax_all)
- {
- validate_edge(eax_all.flEdge);
- validate_gain(eax_all.lGain);
- validate_lowpass_cutoff(eax_all.flLowPassCutOff);
- validate_eq_center(eax_all.flEQCenter);
- validate_eq_bandwidth(eax_all.flEQBandwidth);
- }
-
- void EaxDistortionEffect::defer_edge(
- float flEdge)
- {
- eax_d_.flEdge = flEdge;
- eax_dirty_flags_.flEdge = (eax_.flEdge != eax_d_.flEdge);
- }
-
- void EaxDistortionEffect::defer_gain(
- long lGain)
- {
- eax_d_.lGain = lGain;
- eax_dirty_flags_.lGain = (eax_.lGain != eax_d_.lGain);
- }
-
- void EaxDistortionEffect::defer_low_pass_cutoff(
- float flLowPassCutOff)
- {
- eax_d_.flLowPassCutOff = flLowPassCutOff;
- eax_dirty_flags_.flLowPassCutOff = (eax_.flLowPassCutOff != eax_d_.flLowPassCutOff);
- }
-
- void EaxDistortionEffect::defer_eq_center(
- float flEQCenter)
- {
- eax_d_.flEQCenter = flEQCenter;
- eax_dirty_flags_.flEQCenter = (eax_.flEQCenter != eax_d_.flEQCenter);
- }
-
- void EaxDistortionEffect::defer_eq_bandwidth(
- float flEQBandwidth)
- {
- eax_d_.flEQBandwidth = flEQBandwidth;
- eax_dirty_flags_.flEQBandwidth = (eax_.flEQBandwidth != eax_d_.flEQBandwidth);
- }
-
- void EaxDistortionEffect::defer_all(
- const EAXDISTORTIONPROPERTIES& eax_all)
- {
- defer_edge(eax_all.flEdge);
- defer_gain(eax_all.lGain);
- defer_low_pass_cutoff(eax_all.flLowPassCutOff);
- defer_eq_center(eax_all.flEQCenter);
- defer_eq_bandwidth(eax_all.flEQBandwidth);
- }
-
- void EaxDistortionEffect::defer_edge(
- const EaxEaxCall& eax_call)
- {
- const auto& edge =
- eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEdge)>();
-
- validate_edge(edge);
- defer_edge(edge);
- }
-
- void EaxDistortionEffect::defer_gain(
- const EaxEaxCall& eax_call)
- {
- const auto& gain =
- eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::lGain)>();
-
- validate_gain(gain);
- defer_gain(gain);
- }
-
- void EaxDistortionEffect::defer_low_pass_cutoff(
- const EaxEaxCall& eax_call)
- {
- const auto& lowpass_cutoff =
- eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flLowPassCutOff)>();
-
- validate_lowpass_cutoff(lowpass_cutoff);
- defer_low_pass_cutoff(lowpass_cutoff);
- }
-
- void EaxDistortionEffect::defer_eq_center(
- const EaxEaxCall& eax_call)
- {
- const auto& eq_center =
- eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQCenter)>();
-
- validate_eq_center(eq_center);
- defer_eq_center(eq_center);
- }
-
- void EaxDistortionEffect::defer_eq_bandwidth(
- const EaxEaxCall& eax_call)
- {
- const auto& eq_bandwidth =
- eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQBandwidth)>();
-
- validate_eq_bandwidth(eq_bandwidth);
- defer_eq_bandwidth(eq_bandwidth);
- }
-
- void EaxDistortionEffect::defer_all(
- const EaxEaxCall& eax_call)
- {
- const auto& all =
- eax_call.get_value<EaxDistortionEffectException, const EAXDISTORTIONPROPERTIES>();
-
- validate_all(all);
- defer_all(all);
- }
-
- // [[nodiscard]]
- bool EaxDistortionEffect::apply_deferred()
- {
- if (eax_dirty_flags_ == EaxDistortionEffectDirtyFlags{})
- {
- return false;
- }
-
- eax_ = eax_d_;
-
- if (eax_dirty_flags_.flEdge)
- {
- set_efx_edge();
- }
-
- if (eax_dirty_flags_.lGain)
- {
- set_efx_gain();
- }
-
- if (eax_dirty_flags_.flLowPassCutOff)
- {
- set_efx_lowpass_cutoff();
- }
-
- if (eax_dirty_flags_.flEQCenter)
- {
- set_efx_eq_center();
- }
-
- if (eax_dirty_flags_.flEQBandwidth)
- {
- set_efx_eq_bandwidth();
- }
-
- eax_dirty_flags_ = EaxDistortionEffectDirtyFlags{};
-
- return true;
- }
-
- void EaxDistortionEffect::set(const EaxEaxCall& eax_call)
- {
- switch(eax_call.get_property_id())
- {
- case EAXDISTORTION_NONE:
- break;
-
- case EAXDISTORTION_ALLPARAMETERS:
- defer_all(eax_call);
- break;
-
- case EAXDISTORTION_EDGE:
- defer_edge(eax_call);
- break;
-
- case EAXDISTORTION_GAIN:
- defer_gain(eax_call);
- break;
-
- case EAXDISTORTION_LOWPASSCUTOFF:
- defer_low_pass_cutoff(eax_call);
- break;
-
- case EAXDISTORTION_EQCENTER:
- defer_eq_center(eax_call);
- break;
-
- case EAXDISTORTION_EQBANDWIDTH:
- defer_eq_bandwidth(eax_call);
- break;
-
- default:
- throw EaxDistortionEffectException{"Unsupported property id."};
- }
- }
-
- } // namespace
-
- EaxEffectUPtr eax_create_eax_distortion_effect()
- {
- return std::make_unique<EaxDistortionEffect>();
- }
-
- #endif // ALSOFT_EAX
|