diff options
-rw-r--r-- | al/auxeffectslot.h | 4 | ||||
-rw-r--r-- | al/eax/effect.h | 137 | ||||
-rw-r--r-- | al/effects/modulator.cpp | 248 | ||||
-rw-r--r-- | al/effects/pshifter.cpp | 190 | ||||
-rw-r--r-- | al/effects/vmorpher.cpp | 480 |
5 files changed, 410 insertions, 649 deletions
diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 999ea102..3e9a2a4e 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -139,11 +139,11 @@ private: guidLoadEffect != EAX_DISTORTION_EFFECT && guidLoadEffect != EAX_ECHO_EFFECT && guidLoadEffect != EAX_EQUALIZER_EFFECT && - guidLoadEffect != EAX_FLANGER_EFFECT /*&& + guidLoadEffect != EAX_FLANGER_EFFECT && guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT && guidLoadEffect != EAX_VOCALMORPHER_EFFECT && guidLoadEffect != EAX_PITCHSHIFTER_EFFECT && - guidLoadEffect != EAX_RINGMODULATOR_EFFECT*/) + guidLoadEffect != EAX_RINGMODULATOR_EFFECT) { eax_fail_unknown_effect_id(); } diff --git a/al/eax/effect.h b/al/eax/effect.h index 6e5a0553..2de768b7 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -189,6 +189,15 @@ struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> { struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> { using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter; }; +struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> { + using EaxCommitter<EaxModulatorCommitter>::EaxCommitter; +}; +struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> { + using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter; +}; +struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> { + using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter; +}; struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> { using EaxCommitter<EaxNullCommitter>::EaxCommitter; }; @@ -197,7 +206,7 @@ struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> { class EaxEffect { public: EaxEffect() noexcept = default; - virtual ~EaxEffect() = default; + ~EaxEffect() = default; ALenum al_effect_type_{AL_EFFECT_NULL}; EffectProps al_effect_props_{}; @@ -236,10 +245,6 @@ public: State4 state4_{}; State4 state5_{}; - [[deprecated]] virtual void dispatch(const EaxCall& /*call*/) { } - - // Returns "true" if any immediated property was changed. - /*[[nodiscard]]*/ [[deprecated]] virtual bool commit() { return false; } template<typename T, typename ...Args> void call_set_defaults(Args&& ...args) @@ -265,6 +270,12 @@ public: return call_set_defaults<EaxFlangerCommitter>(props); if(altype == AL_EFFECT_FREQUENCY_SHIFTER) return call_set_defaults<EaxFrequencyShifterCommitter>(props); + if(altype == AL_EFFECT_RING_MODULATOR) + return call_set_defaults<EaxModulatorCommitter>(props); + if(altype == AL_EFFECT_PITCH_SHIFTER) + return call_set_defaults<EaxPitchShifterCommitter>(props); + if(altype == AL_EFFECT_VOCAL_MORPHER) + return call_set_defaults<EaxVocalMorpherCommitter>(props); return call_set_defaults<EaxNullCommitter>(props); } @@ -316,6 +327,12 @@ public: return Callable<EaxFlangerCommitter>(__VA_ARGS__); \ if(T == EaxEffectType::FrequencyShifter) \ return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \ + if(T == EaxEffectType::Modulator) \ + return Callable<EaxModulatorCommitter>(__VA_ARGS__); \ + if(T == EaxEffectType::PitchShifter) \ + return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \ + if(T == EaxEffectType::VocalMorpher) \ + return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \ return Callable<EaxNullCommitter>(__VA_ARGS__) template<typename T, typename ...Args> @@ -404,116 +421,6 @@ public: #undef EAXCALL }; // EaxEffect -// Base class for EAX4+ effects. -template<typename TException> -class EaxEffect4 : public EaxEffect -{ -public: - EaxEffect4(ALenum, int) { } - - void initialize() - { - set_defaults(); - set_efx_defaults(); - } - - void dispatch(const EaxCall& call) override - { call.is_get() ? get(call) : set(call); } - - bool commit() final - { - switch (version_) - { - case 4: return commit_state(state4_); - case 5: return commit_state(state5_); - default: fail_unknown_version(); - } - } - -protected: - using Exception = TException; - - template<typename TValidator, typename TProperty> - static void defer(const EaxCall& call, TProperty& property) - { - const auto& value = call.get_value<Exception, const TProperty>(); - TValidator{}(value); - property = value; - } - - virtual void set_defaults(Props4& props) = 0; - virtual void set_efx_defaults() = 0; - - virtual void get(const EaxCall& call, const Props4& props) = 0; - virtual void set(const EaxCall& call, Props4& props) = 0; - - virtual bool commit_props(const Props4& props) = 0; - - [[noreturn]] static void fail(const char* message) - { - throw Exception{message}; - } - - [[noreturn]] static void fail_unknown_property_id() - { - fail(EaxEffectErrorMessages::unknown_property_id()); - } - - [[noreturn]] static void fail_unknown_version() - { - fail(EaxEffectErrorMessages::unknown_version()); - } - -private: - void set_defaults() - { - set_defaults(props_); - state4_.i = props_; - state4_.d = props_; - state5_.i = props_; - state5_.d = props_; - } - - void get(const EaxCall& call) - { - switch (call.get_version()) - { - case 4: get(call, state4_.i); break; - case 5: get(call, state5_.i); break; - default: fail_unknown_version(); - } - } - - void set(const EaxCall& call) - { - const auto version = call.get_version(); - switch (version) - { - case 4: set(call, state4_.d); break; - case 5: set(call, state5_.d); break; - default: fail_unknown_version(); - } - version_ = version; - } - - bool commit_state(State4& state) - { - const auto props = props_; - state.i = state.d; - props_ = state.d; - return commit_props(props); - } -}; // EaxEffect4 - using EaxEffectUPtr = std::unique_ptr<EaxEffect>; -// Creates EAX4+ effect. -template<typename TEffect> -EaxEffectUPtr eax_create_eax4_effect(int eax_version) -{ - auto effect = std::make_unique<TEffect>(eax_version); - effect->initialize(); - return effect; -} - #endif // !EAX_EFFECT_INCLUDED diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp index f1d01ddc..f3e43c52 100644 --- a/al/effects/modulator.cpp +++ b/al/effects/modulator.cpp @@ -145,176 +145,128 @@ const EffectProps ModulatorEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -class EaxRingModulatorEffectException : public EaxException -{ -public: - explicit EaxRingModulatorEffectException(const char* message) - : EaxException{"EAX_RING_MODULATOR_EFFECT", message} - {} -}; // EaxRingModulatorEffectException +using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>; -class EaxRingModulatorEffect final : public EaxEffect4<EaxRingModulatorEffectException> -{ -public: - EaxRingModulatorEffect(int eax_version); - -private: - struct FrequencyValidator { - void operator()(float flFrequency) const - { - eax_validate_range<EaxRingModulatorEffectException>( - "Frequency", - flFrequency, - EAXRINGMODULATOR_MINFREQUENCY, - EAXRINGMODULATOR_MAXFREQUENCY); - } - }; // FrequencyValidator - - struct HighPassCutOffValidator { - void operator()(float flHighPassCutOff) const - { - eax_validate_range<EaxRingModulatorEffectException>( - "High-Pass Cutoff", - flHighPassCutOff, - EAXRINGMODULATOR_MINHIGHPASSCUTOFF, - EAXRINGMODULATOR_MAXHIGHPASSCUTOFF); - } - }; // HighPassCutOffValidator - - struct WaveformValidator { - void operator()(unsigned long ulWaveform) const - { - eax_validate_range<EaxRingModulatorEffectException>( - "Waveform", - ulWaveform, - EAXRINGMODULATOR_MINWAVEFORM, - EAXRINGMODULATOR_MAXWAVEFORM); - } - }; // WaveformValidator - - struct AllValidator { - void operator()(const EAXRINGMODULATORPROPERTIES& all) const - { - FrequencyValidator{}(all.flFrequency); - HighPassCutOffValidator{}(all.flHighPassCutOff); - WaveformValidator{}(all.ulWaveform); - } - }; // AllValidator - - void set_defaults(Props4& props) override; - - void set_efx_frequency() noexcept; - void set_efx_high_pass_cutoff() noexcept; - void set_efx_waveform(); - void set_efx_defaults() override; - - void get(const EaxCall& call, const Props4& props) override; - void set(const EaxCall& call, Props4& props) override; - bool commit_props(const Props4& props) override; -}; // EaxRingModulatorEffect - -EaxRingModulatorEffect::EaxRingModulatorEffect(int eax_version) - : EaxEffect4{AL_EFFECT_RING_MODULATOR, eax_version} -{} - -void EaxRingModulatorEffect::set_defaults(Props4& props) -{ - props.mType = EaxEffectType::Modulator; - props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; - props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; - props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; -} +struct FrequencyValidator { + void operator()(float flFrequency) const + { + eax_validate_range<ModulatorCommitter::Exception>( + "Frequency", + flFrequency, + EAXRINGMODULATOR_MINFREQUENCY, + EAXRINGMODULATOR_MAXFREQUENCY); + } +}; // FrequencyValidator -void EaxRingModulatorEffect::set_efx_frequency() noexcept -{ - al_effect_props_.Modulator.Frequency = clamp( - props_.mModulator.flFrequency, - AL_RING_MODULATOR_MIN_FREQUENCY, - AL_RING_MODULATOR_MAX_FREQUENCY); -} +struct HighPassCutOffValidator { + void operator()(float flHighPassCutOff) const + { + eax_validate_range<ModulatorCommitter::Exception>( + "High-Pass Cutoff", + flHighPassCutOff, + EAXRINGMODULATOR_MINHIGHPASSCUTOFF, + EAXRINGMODULATOR_MAXHIGHPASSCUTOFF); + } +}; // HighPassCutOffValidator + +struct WaveformValidator { + void operator()(unsigned long ulWaveform) const + { + eax_validate_range<ModulatorCommitter::Exception>( + "Waveform", + ulWaveform, + EAXRINGMODULATOR_MINWAVEFORM, + EAXRINGMODULATOR_MAXWAVEFORM); + } +}; // WaveformValidator + +struct AllValidator { + void operator()(const EAXRINGMODULATORPROPERTIES& all) const + { + FrequencyValidator{}(all.flFrequency); + HighPassCutOffValidator{}(all.flHighPassCutOff); + WaveformValidator{}(all.ulWaveform); + } +}; // AllValidator + +} // namespace + +template<> +struct ModulatorCommitter::Exception : public EaxException { + explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message} + { } +}; -void EaxRingModulatorEffect::set_efx_high_pass_cutoff() noexcept +template<> +[[noreturn]] void ModulatorCommitter::fail(const char *message) { - al_effect_props_.Modulator.HighPassCutoff = clamp( - props_.mModulator.flHighPassCutOff, - AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF, - AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF); + throw Exception{message}; } -void EaxRingModulatorEffect::set_efx_waveform() +template<> +bool ModulatorCommitter::commit(const EaxEffectProps &props) { - const auto waveform = clamp( - static_cast<ALint>(props_.mModulator.ulWaveform), - AL_RING_MODULATOR_MIN_WAVEFORM, - AL_RING_MODULATOR_MAX_WAVEFORM); - const auto efx_waveform = WaveformFromEmum(waveform); - assert(efx_waveform.has_value()); - al_effect_props_.Modulator.Waveform = *efx_waveform; + const auto orig = props_; + props_ = props; + + if(orig.mType == props_.mType && props_.mModulator.flFrequency == props.mModulator.flFrequency + && props_.mModulator.flHighPassCutOff == props.mModulator.flHighPassCutOff + && props_.mModulator.ulWaveform == props.mModulator.ulWaveform) + return false; + + auto get_waveform = [](unsigned long form) + { + if(form == EAX_RINGMODULATOR_SINUSOID) + return ModulatorWaveform::Sinusoid; + if(form == EAX_RINGMODULATOR_SAWTOOTH) + return ModulatorWaveform::Sawtooth; + if(form == EAX_RINGMODULATOR_SQUARE) + return ModulatorWaveform::Square; + return ModulatorWaveform::Sinusoid; + }; + + al_effect_props_.Modulator.Frequency = props_.mModulator.flFrequency; + al_effect_props_.Modulator.HighPassCutoff = props_.mModulator.flHighPassCutOff; + al_effect_props_.Modulator.Waveform = get_waveform(props_.mModulator.ulWaveform); + + return true; } -void EaxRingModulatorEffect::set_efx_defaults() +template<> +void ModulatorCommitter::SetDefaults(EaxEffectProps &props) { - set_efx_frequency(); - set_efx_high_pass_cutoff(); - set_efx_waveform(); + props.mType = EaxEffectType::Modulator; + props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; + props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; + props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; } -void EaxRingModulatorEffect::get(const EaxCall& call, const Props4& props) +template<> +void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { switch(call.get_property_id()) { - case EAXRINGMODULATOR_NONE: break; - case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props.mModulator); break; - case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.mModulator.flFrequency); break; - case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.mModulator.flHighPassCutOff); break; - case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.mModulator.ulWaveform); break; - default: fail_unknown_property_id(); + case EAXRINGMODULATOR_NONE: break; + case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props.mModulator); break; + case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.mModulator.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.mModulator.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.mModulator.ulWaveform); break; + default: fail_unknown_property_id(); } } -void EaxRingModulatorEffect::set(const EaxCall& call, Props4& props) +template<> +void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props) { switch (call.get_property_id()) { - case EAXRINGMODULATOR_NONE: break; - case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props.mModulator); break; - case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.mModulator.flFrequency); break; - case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.mModulator.flHighPassCutOff); break; - case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.mModulator.ulWaveform); break; - default: fail_unknown_property_id(); - } -} - -bool EaxRingModulatorEffect::commit_props(const Props4& props) -{ - auto is_dirty = false; - - if (props_.mModulator.flFrequency != props.mModulator.flFrequency) - { - is_dirty = true; - set_efx_frequency(); + case EAXRINGMODULATOR_NONE: break; + case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props.mModulator); break; + case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.mModulator.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.mModulator.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.mModulator.ulWaveform); break; + default: fail_unknown_property_id(); } - - if (props_.mModulator.flHighPassCutOff != props.mModulator.flHighPassCutOff) - { - is_dirty = true; - set_efx_high_pass_cutoff(); - } - - if (props_.mModulator.ulWaveform != props.mModulator.ulWaveform) - { - is_dirty = true; - set_efx_waveform(); - } - - return is_dirty; -} - -} // namespace - -EaxEffectUPtr eax_create_eax_ring_modulator_effect(int eax_version) -{ - return eax_create_eax4_effect<EaxRingModulatorEffect>(eax_version); } #endif // ALSOFT_EAX diff --git a/al/effects/pshifter.cpp b/al/effects/pshifter.cpp index 524585a2..53115edb 100644 --- a/al/effects/pshifter.cpp +++ b/al/effects/pshifter.cpp @@ -92,141 +92,101 @@ const EffectProps PshifterEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -class EaxPitchShifterEffectException : public EaxException -{ -public: - explicit EaxPitchShifterEffectException(const char* message) - : EaxException{"EAX_PITCH_SHIFTER_EFFECT", message} - {} -}; // EaxPitchShifterEffectException - -class EaxPitchShifterEffect final : public EaxEffect4<EaxPitchShifterEffectException> { -public: - EaxPitchShifterEffect(int eax_version); - -private: - struct CoarseTuneValidator { - void operator()(long lCoarseTune) const - { - eax_validate_range<Exception>( - "Coarse Tune", - lCoarseTune, - EAXPITCHSHIFTER_MINCOARSETUNE, - EAXPITCHSHIFTER_MAXCOARSETUNE); - } - }; // CoarseTuneValidator - - struct FineTuneValidator { - void operator()(long lFineTune) const - { - eax_validate_range<Exception>( - "Fine Tune", - lFineTune, - EAXPITCHSHIFTER_MINFINETUNE, - EAXPITCHSHIFTER_MAXFINETUNE); - } - }; // FineTuneValidator - - struct AllValidator { - void operator()(const EAXPITCHSHIFTERPROPERTIES& all) const - { - CoarseTuneValidator{}(all.lCoarseTune); - FineTuneValidator{}(all.lFineTune); - } - }; // AllValidator - - void set_defaults(Props4& props) override; - - void set_efx_coarse_tune() noexcept; - void set_efx_fine_tune() noexcept; - void set_efx_defaults() override; - - void get(const EaxCall& call, const Props4& props) override; - void set(const EaxCall& call, Props4& props) override; - bool commit_props(const Props4& old_i) override; -}; // EaxPitchShifterEffect - -EaxPitchShifterEffect::EaxPitchShifterEffect(int eax_version) - : EaxEffect4{AL_EFFECT_PITCH_SHIFTER, eax_version} -{} - -void EaxPitchShifterEffect::set_defaults(Props4& props) -{ - props.mType = EaxEffectType::PitchShifter; - props.mPitchShifter.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE; - props.mPitchShifter.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE; -} +using PitchShifterCommitter = EaxCommitter<EaxPitchShifterCommitter>; -void EaxPitchShifterEffect::set_efx_coarse_tune() noexcept -{ - al_effect_props_.Pshifter.CoarseTune = clamp( - static_cast<ALint>(props_.mPitchShifter.lCoarseTune), - AL_PITCH_SHIFTER_MIN_COARSE_TUNE, - AL_PITCH_SHIFTER_MAX_COARSE_TUNE); -} +struct CoarseTuneValidator { + void operator()(long lCoarseTune) const + { + eax_validate_range<PitchShifterCommitter::Exception>( + "Coarse Tune", + lCoarseTune, + EAXPITCHSHIFTER_MINCOARSETUNE, + EAXPITCHSHIFTER_MAXCOARSETUNE); + } +}; // CoarseTuneValidator -void EaxPitchShifterEffect::set_efx_fine_tune() noexcept +struct FineTuneValidator { + void operator()(long lFineTune) const + { + eax_validate_range<PitchShifterCommitter::Exception>( + "Fine Tune", + lFineTune, + EAXPITCHSHIFTER_MINFINETUNE, + EAXPITCHSHIFTER_MAXFINETUNE); + } +}; // FineTuneValidator + +struct AllValidator { + void operator()(const EAXPITCHSHIFTERPROPERTIES& all) const + { + CoarseTuneValidator{}(all.lCoarseTune); + FineTuneValidator{}(all.lFineTune); + } +}; // AllValidator + +} // namespace + +template<> +struct PitchShifterCommitter::Exception : public EaxException { + explicit Exception(const char *message) : EaxException{"EAX_PITCH_SHIFTER_EFFECT", message} + { } +}; + +template<> +[[noreturn]] void PitchShifterCommitter::fail(const char *message) { - al_effect_props_.Pshifter.FineTune = clamp( - static_cast<ALint>(props_.mPitchShifter.lFineTune), - AL_PITCH_SHIFTER_MIN_FINE_TUNE, - AL_PITCH_SHIFTER_MAX_FINE_TUNE); + throw Exception{message}; } -void EaxPitchShifterEffect::set_efx_defaults() +template<> +bool PitchShifterCommitter::commit(const EaxEffectProps &props) { - set_efx_coarse_tune(); - set_efx_fine_tune(); + const auto orig = props_; + props_ = props; + + if(orig.mType == props_.mType + && props_.mPitchShifter.lCoarseTune == props.mPitchShifter.lCoarseTune + && props_.mPitchShifter.lFineTune == props.mPitchShifter.lFineTune) + return false; + + al_effect_props_.Pshifter.CoarseTune = static_cast<ALint>(props_.mPitchShifter.lCoarseTune); + al_effect_props_.Pshifter.FineTune = static_cast<ALint>(props_.mPitchShifter.lFineTune); + + return true; } -void EaxPitchShifterEffect::get(const EaxCall& call, const Props4& props) +template<> +void PitchShifterCommitter::SetDefaults(EaxEffectProps &props) { - switch(call.get_property_id()) - { - case EAXPITCHSHIFTER_NONE: break; - case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mPitchShifter); break; - case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.mPitchShifter.lCoarseTune); break; - case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.mPitchShifter.lFineTune); break; - default: fail_unknown_property_id(); - } + props.mType = EaxEffectType::PitchShifter; + props.mPitchShifter.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE; + props.mPitchShifter.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE; } -void EaxPitchShifterEffect::set(const EaxCall& call, Props4& props) +template<> +void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { switch(call.get_property_id()) { - case EAXPITCHSHIFTER_NONE: break; - case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mPitchShifter); break; - case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.mPitchShifter.lCoarseTune); break; - case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.mPitchShifter.lFineTune); break; - default: fail_unknown_property_id(); + case EAXPITCHSHIFTER_NONE: break; + case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mPitchShifter); break; + case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.mPitchShifter.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.mPitchShifter.lFineTune); break; + default: fail_unknown_property_id(); } } -bool EaxPitchShifterEffect::commit_props(const Props4& props) +template<> +void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props) { - auto is_dirty = false; - - if (props_.mPitchShifter.lCoarseTune != props.mPitchShifter.lCoarseTune) - { - is_dirty = true; - set_efx_coarse_tune(); - } - - if (props_.mPitchShifter.lFineTune != props.mPitchShifter.lFineTune) + switch(call.get_property_id()) { - is_dirty = true; - set_efx_fine_tune(); + case EAXPITCHSHIFTER_NONE: break; + case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mPitchShifter); break; + case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.mPitchShifter.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.mPitchShifter.lFineTune); break; + default: fail_unknown_property_id(); } - - return is_dirty; -} - -} // namespace - -EaxEffectUPtr eax_create_eax_pitch_shifter_effect(int eax_version) -{ - return eax_create_eax4_effect<EaxPitchShifterEffect>(eax_version); } #endif // ALSOFT_EAX diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp index d8d74b94..f8be5856 100644 --- a/al/effects/vmorpher.cpp +++ b/al/effects/vmorpher.cpp @@ -258,116 +258,174 @@ const EffectProps VmorpherEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -class EaxVocalMorpherEffectException : public EaxException { -public: - explicit EaxVocalMorpherEffectException(const char* message) - : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message} - {} -}; // EaxVocalMorpherEffectException - -class EaxVocalMorpherEffect final : public EaxEffect4<EaxVocalMorpherEffectException> { -public: - EaxVocalMorpherEffect(int eax_version); - -private: - struct PhonemeAValidator { - void operator()(unsigned long ulPhonemeA) const - { - eax_validate_range<Exception>( - "Phoneme A", - ulPhonemeA, - EAXVOCALMORPHER_MINPHONEMEA, - EAXVOCALMORPHER_MAXPHONEMEA); - } - }; // PhonemeAValidator +using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>; - struct PhonemeACoarseTuningValidator { - void operator()(long lPhonemeACoarseTuning) const - { - eax_validate_range<Exception>( - "Phoneme A Coarse Tuning", - lPhonemeACoarseTuning, - EAXVOCALMORPHER_MINPHONEMEACOARSETUNING, - EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING); - } - }; // PhonemeACoarseTuningValidator +struct PhonemeAValidator { + void operator()(unsigned long ulPhonemeA) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Phoneme A", + ulPhonemeA, + EAXVOCALMORPHER_MINPHONEMEA, + EAXVOCALMORPHER_MAXPHONEMEA); + } +}; // PhonemeAValidator - struct PhonemeBValidator { - void operator()(unsigned long ulPhonemeB) const - { - eax_validate_range<Exception>( - "Phoneme B", - ulPhonemeB, - EAXVOCALMORPHER_MINPHONEMEB, - EAXVOCALMORPHER_MAXPHONEMEB); - } - }; // PhonemeBValidator +struct PhonemeACoarseTuningValidator { + void operator()(long lPhonemeACoarseTuning) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Phoneme A Coarse Tuning", + lPhonemeACoarseTuning, + EAXVOCALMORPHER_MINPHONEMEACOARSETUNING, + EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING); + } +}; // PhonemeACoarseTuningValidator - struct PhonemeBCoarseTuningValidator { - void operator()(long lPhonemeBCoarseTuning) const - { - eax_validate_range<Exception>( - "Phoneme B Coarse Tuning", - lPhonemeBCoarseTuning, - EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING, - EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING); - } - }; // PhonemeBCoarseTuningValidator +struct PhonemeBValidator { + void operator()(unsigned long ulPhonemeB) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Phoneme B", + ulPhonemeB, + EAXVOCALMORPHER_MINPHONEMEB, + EAXVOCALMORPHER_MAXPHONEMEB); + } +}; // PhonemeBValidator - struct WaveformValidator { - void operator()(unsigned long ulWaveform) const - { - eax_validate_range<Exception>( - "Waveform", - ulWaveform, - EAXVOCALMORPHER_MINWAVEFORM, - EAXVOCALMORPHER_MAXWAVEFORM); - } - }; // WaveformValidator +struct PhonemeBCoarseTuningValidator { + void operator()(long lPhonemeBCoarseTuning) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Phoneme B Coarse Tuning", + lPhonemeBCoarseTuning, + EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING, + EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING); + } +}; // PhonemeBCoarseTuningValidator - struct RateValidator { - void operator()(float flRate) const - { - eax_validate_range<Exception>( - "Rate", - flRate, - EAXVOCALMORPHER_MINRATE, - EAXVOCALMORPHER_MAXRATE); - } - }; // RateValidator +struct WaveformValidator { + void operator()(unsigned long ulWaveform) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Waveform", + ulWaveform, + EAXVOCALMORPHER_MINWAVEFORM, + EAXVOCALMORPHER_MAXWAVEFORM); + } +}; // WaveformValidator - struct AllValidator { - void operator()(const EAXVOCALMORPHERPROPERTIES& all) const - { - PhonemeAValidator{}(all.ulPhonemeA); - PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning); - PhonemeBValidator{}(all.ulPhonemeB); - PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning); - WaveformValidator{}(all.ulWaveform); - RateValidator{}(all.flRate); - } - }; // AllValidator +struct RateValidator { + void operator()(float flRate) const + { + eax_validate_range<VocalMorpherCommitter::Exception>( + "Rate", + flRate, + EAXVOCALMORPHER_MINRATE, + EAXVOCALMORPHER_MAXRATE); + } +}; // RateValidator - void set_defaults(Props4& props) override; +struct AllValidator { + void operator()(const EAXVOCALMORPHERPROPERTIES& all) const + { + PhonemeAValidator{}(all.ulPhonemeA); + PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning); + PhonemeBValidator{}(all.ulPhonemeB); + PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning); + WaveformValidator{}(all.ulWaveform); + RateValidator{}(all.flRate); + } +}; // AllValidator - void set_efx_phoneme_a(); - void set_efx_phoneme_a_coarse_tuning() noexcept; - void set_efx_phoneme_b(); - void set_efx_phoneme_b_coarse_tuning() noexcept; - void set_efx_waveform(); - void set_efx_rate() noexcept; - void set_efx_defaults() override; +} // namespace - void get(const EaxCall& call, const Props4& props) override; - void set(const EaxCall& call, Props4& props) override; - bool commit_props(const Props4& props) override; -}; // EaxVocalMorpherEffect +template<> +struct VocalMorpherCommitter::Exception : public EaxException { + explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message} + { } +}; -EaxVocalMorpherEffect::EaxVocalMorpherEffect(int eax_version) - : EaxEffect4{AL_EFFECT_VOCAL_MORPHER, eax_version} -{} +template<> +[[noreturn]] void VocalMorpherCommitter::fail(const char *message) +{ + throw Exception{message}; +} -void EaxVocalMorpherEffect::set_defaults(Props4& props) +template<> +bool VocalMorpherCommitter::commit(const EaxEffectProps &props) +{ + const auto orig = props_; + props_ = props; + + if(orig.mType == props_.mType + && props_.mVocalMorpher.ulPhonemeA == props.mVocalMorpher.ulPhonemeA + && props_.mVocalMorpher.lPhonemeACoarseTuning == props.mVocalMorpher.lPhonemeACoarseTuning + && props_.mVocalMorpher.ulPhonemeB == props.mVocalMorpher.ulPhonemeB + && props_.mVocalMorpher.lPhonemeBCoarseTuning == props.mVocalMorpher.lPhonemeBCoarseTuning + && props_.mVocalMorpher.ulWaveform == props.mVocalMorpher.ulWaveform + && props_.mVocalMorpher.flRate == props.mVocalMorpher.flRate) + return false; + + auto get_phoneme = [](unsigned long phoneme) noexcept + { +#define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x + switch(phoneme) + { + HANDLE_PHENOME(A); + HANDLE_PHENOME(E); + HANDLE_PHENOME(I); + HANDLE_PHENOME(O); + HANDLE_PHENOME(U); + HANDLE_PHENOME(AA); + HANDLE_PHENOME(AE); + HANDLE_PHENOME(AH); + HANDLE_PHENOME(AO); + HANDLE_PHENOME(EH); + HANDLE_PHENOME(ER); + HANDLE_PHENOME(IH); + HANDLE_PHENOME(IY); + HANDLE_PHENOME(UH); + HANDLE_PHENOME(UW); + HANDLE_PHENOME(B); + HANDLE_PHENOME(D); + HANDLE_PHENOME(F); + HANDLE_PHENOME(G); + HANDLE_PHENOME(J); + HANDLE_PHENOME(K); + HANDLE_PHENOME(L); + HANDLE_PHENOME(M); + HANDLE_PHENOME(N); + HANDLE_PHENOME(P); + HANDLE_PHENOME(R); + HANDLE_PHENOME(S); + HANDLE_PHENOME(T); + HANDLE_PHENOME(V); + HANDLE_PHENOME(Z); + } + return VMorpherPhenome::A; +#undef HANDLE_PHENOME + }; + auto get_waveform = [](unsigned long form) noexcept + { + if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid; + if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle; + if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth; + return VMorpherWaveform::Sinusoid; + }; + + al_effect_props_.Vmorpher.PhonemeA = get_phoneme(props_.mVocalMorpher.ulPhonemeA); + al_effect_props_.Vmorpher.PhonemeACoarseTuning = static_cast<ALint>(props_.mVocalMorpher.lPhonemeACoarseTuning); + al_effect_props_.Vmorpher.PhonemeB = get_phoneme(props_.mVocalMorpher.ulPhonemeB); + al_effect_props_.Vmorpher.PhonemeBCoarseTuning = static_cast<ALint>(props_.mVocalMorpher.lPhonemeBCoarseTuning); + al_effect_props_.Vmorpher.Waveform = get_waveform(props_.mVocalMorpher.ulWaveform); + al_effect_props_.Vmorpher.Rate = props_.mVocalMorpher.flRate; + + return true; +} + +template<> +void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props) { props.mType = EaxEffectType::VocalMorpher; props.mVocalMorpher.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA; @@ -378,202 +436,86 @@ void EaxVocalMorpherEffect::set_defaults(Props4& props) props.mVocalMorpher.flRate = EAXVOCALMORPHER_DEFAULTRATE; } -void EaxVocalMorpherEffect::set_efx_phoneme_a() -{ - const auto phoneme_a = clamp( - static_cast<ALint>(props_.mVocalMorpher.ulPhonemeA), - AL_VOCAL_MORPHER_MIN_PHONEMEA, - AL_VOCAL_MORPHER_MAX_PHONEMEA); - const auto efx_phoneme_a = PhenomeFromEnum(phoneme_a); - assert(efx_phoneme_a.has_value()); - al_effect_props_.Vmorpher.PhonemeA = *efx_phoneme_a; -} - -void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning() noexcept -{ - const auto phoneme_a_coarse_tuning = clamp( - static_cast<ALint>(props_.mVocalMorpher.lPhonemeACoarseTuning), - AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING, - AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING); - al_effect_props_.Vmorpher.PhonemeACoarseTuning = phoneme_a_coarse_tuning; -} - -void EaxVocalMorpherEffect::set_efx_phoneme_b() -{ - const auto phoneme_b = clamp( - static_cast<ALint>(props_.mVocalMorpher.ulPhonemeB), - AL_VOCAL_MORPHER_MIN_PHONEMEB, - AL_VOCAL_MORPHER_MAX_PHONEMEB); - const auto efx_phoneme_b = PhenomeFromEnum(phoneme_b); - assert(efx_phoneme_b.has_value()); - al_effect_props_.Vmorpher.PhonemeB = *efx_phoneme_b; -} - -void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning() noexcept -{ - al_effect_props_.Vmorpher.PhonemeBCoarseTuning = clamp( - static_cast<ALint>(props_.mVocalMorpher.lPhonemeBCoarseTuning), - AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING, - AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING); -} - -void EaxVocalMorpherEffect::set_efx_waveform() -{ - const auto waveform = clamp( - static_cast<ALint>(props_.mVocalMorpher.ulWaveform), - AL_VOCAL_MORPHER_MIN_WAVEFORM, - AL_VOCAL_MORPHER_MAX_WAVEFORM); - const auto wfx_waveform = WaveformFromEmum(waveform); - assert(wfx_waveform.has_value()); - al_effect_props_.Vmorpher.Waveform = *wfx_waveform; -} - -void EaxVocalMorpherEffect::set_efx_rate() noexcept -{ - al_effect_props_.Vmorpher.Rate = clamp( - props_.mVocalMorpher.flRate, - AL_VOCAL_MORPHER_MIN_RATE, - AL_VOCAL_MORPHER_MAX_RATE); -} - -void EaxVocalMorpherEffect::set_efx_defaults() -{ - set_efx_phoneme_a(); - set_efx_phoneme_a_coarse_tuning(); - set_efx_phoneme_b(); - set_efx_phoneme_b_coarse_tuning(); - set_efx_waveform(); - set_efx_rate(); -} - -void EaxVocalMorpherEffect::get(const EaxCall& call, const Props4& props) +template<> +void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { switch(call.get_property_id()) { - case EAXVOCALMORPHER_NONE: - break; + case EAXVOCALMORPHER_NONE: + break; - case EAXVOCALMORPHER_ALLPARAMETERS: - call.set_value<Exception>(props.mVocalMorpher); - break; + case EAXVOCALMORPHER_ALLPARAMETERS: + call.set_value<Exception>(props.mVocalMorpher); + break; - case EAXVOCALMORPHER_PHONEMEA: - call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA); - break; + case EAXVOCALMORPHER_PHONEMEA: + call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA); + break; - case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning); - break; + case EAXVOCALMORPHER_PHONEMEACOARSETUNING: + call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning); + break; - case EAXVOCALMORPHER_PHONEMEB: - call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB); - break; + case EAXVOCALMORPHER_PHONEMEB: + call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB); + break; - case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning); - break; + case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: + call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning); + break; - case EAXVOCALMORPHER_WAVEFORM: - call.set_value<Exception>(props.mVocalMorpher.ulWaveform); - break; + case EAXVOCALMORPHER_WAVEFORM: + call.set_value<Exception>(props.mVocalMorpher.ulWaveform); + break; - case EAXVOCALMORPHER_RATE: - call.set_value<Exception>(props.mVocalMorpher.flRate); - break; + case EAXVOCALMORPHER_RATE: + call.set_value<Exception>(props.mVocalMorpher.flRate); + break; - default: - fail_unknown_property_id(); + default: + fail_unknown_property_id(); } } -void EaxVocalMorpherEffect::set(const EaxCall& call, Props4& props) +template<> +void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props) { switch(call.get_property_id()) { - case EAXVOCALMORPHER_NONE: - break; - - case EAXVOCALMORPHER_ALLPARAMETERS: - defer<AllValidator>(call, props.mVocalMorpher); - break; - - case EAXVOCALMORPHER_PHONEMEA: - defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA); - break; - - case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning); - break; - - case EAXVOCALMORPHER_PHONEMEB: - defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB); - break; - - case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning); - break; - - case EAXVOCALMORPHER_WAVEFORM: - defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform); - break; - - case EAXVOCALMORPHER_RATE: - defer<RateValidator>(call, props.mVocalMorpher.flRate); - break; + case EAXVOCALMORPHER_NONE: + break; - default: - fail_unknown_property_id(); - } -} + case EAXVOCALMORPHER_ALLPARAMETERS: + defer<AllValidator>(call, props.mVocalMorpher); + break; -bool EaxVocalMorpherEffect::commit_props(const Props4& props) -{ - auto is_dirty = false; + case EAXVOCALMORPHER_PHONEMEA: + defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA); + break; - if (props_.mVocalMorpher.ulPhonemeA != props.mVocalMorpher.ulPhonemeA) - { - is_dirty = true; - set_efx_phoneme_a(); - } + case EAXVOCALMORPHER_PHONEMEACOARSETUNING: + defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning); + break; - if (props_.mVocalMorpher.lPhonemeACoarseTuning != props.mVocalMorpher.lPhonemeACoarseTuning) - { - is_dirty = true; - set_efx_phoneme_a_coarse_tuning(); - } + case EAXVOCALMORPHER_PHONEMEB: + defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB); + break; - if (props_.mVocalMorpher.ulPhonemeB != props.mVocalMorpher.ulPhonemeB) - { - is_dirty = true; - set_efx_phoneme_b(); - } + case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: + defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning); + break; - if (props_.mVocalMorpher.lPhonemeBCoarseTuning != props.mVocalMorpher.lPhonemeBCoarseTuning) - { - is_dirty = true; - set_efx_phoneme_b_coarse_tuning(); - } + case EAXVOCALMORPHER_WAVEFORM: + defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform); + break; - if (props_.mVocalMorpher.ulWaveform != props.mVocalMorpher.ulWaveform) - { - is_dirty = true; - set_efx_waveform(); - } + case EAXVOCALMORPHER_RATE: + defer<RateValidator>(call, props.mVocalMorpher.flRate); + break; - if (props_.mVocalMorpher.flRate != props.mVocalMorpher.flRate) - { - is_dirty = true; - set_efx_rate(); + default: + fail_unknown_property_id(); } - - return is_dirty; -} - -} // namespace - -EaxEffectUPtr eax_create_eax_vocal_morpher_effect(int eax_version) -{ - return eax_create_eax4_effect<EaxVocalMorpherEffect>(eax_version); } #endif // ALSOFT_EAX |