#pragma once #include #include #include "amuse/Common.hpp" #include "amuse/EffectBase.hpp" namespace amuse { /** Parameters needed to create EffectReverbStd */ struct EffectReverbStdInfo { float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */ float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */ float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */ float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */ EffectReverbStdInfo() = default; EffectReverbStdInfo(float coloration, float mix, float time, float damping, float preDelay) : coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay) {} }; /** Parameters needed to create EffectReverbHi */ struct EffectReverbHiInfo { float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */ float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */ float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */ float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */ float crosstalk = 0.f; /**< [0.0, 1.0] factor defining how much reflections are allowed to bleed to other channels */ EffectReverbHiInfo() = default; EffectReverbHiInfo(float coloration, float mix, float time, float damping, float preDelay, float crosstalk) : coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay), crosstalk(crosstalk) {} }; /** Delay state for one 'tap' of the reverb effect */ struct ReverbDelayLine { int32_t x0_inPoint = 0; int32_t x4_outPoint = 0; int32_t x8_length = 0; std::unique_ptr xc_inputs; float x10_lastInput = 0.f; void allocate(int32_t delay); void setdelay(int32_t delay); }; template class EffectReverbStdImp; template class EffectReverbHiImp; /** Reverb effect with configurable reflection filtering */ class EffectReverbStd { protected: float x140_x1c8_coloration; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */ float x144_x1cc_mix; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */ float x148_x1d0_time; /**< [0.01, 10.0] time in seconds for reflection decay */ float x14c_x1d4_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float x150_x1d8_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */ bool m_dirty = true; /**< needs update of internal parameter data */ template friend class EffectReverbStdImp; template friend class EffectReverbHiImp; EffectReverbStd(float coloration, float mix, float time, float damping, float preDelay); public: template using ImpType = EffectReverbStdImp; void setColoration(float coloration) { x140_x1c8_coloration = std::clamp(0.f, coloration, 1.f); m_dirty = true; } float getColoration() const { return x140_x1c8_coloration; } void setMix(float mix) { x144_x1cc_mix = std::clamp(0.f, mix, 1.f); m_dirty = true; } float getMix() const { return x144_x1cc_mix; } void setTime(float time) { x148_x1d0_time = std::clamp(0.01f, time, 10.f); m_dirty = true; } float getTime() const { return x148_x1d0_time; } void setDamping(float damping) { x14c_x1d4_damping = std::clamp(0.f, damping, 1.f); m_dirty = true; } float getDamping() const { return x14c_x1d4_damping; } void setPreDelay(float preDelay) { x150_x1d8_preDelay = std::clamp(0.f, preDelay, 0.1f); m_dirty = true; } float getPreDelay() const { return x150_x1d8_preDelay; } void setParams(const EffectReverbStdInfo& info) { setColoration(info.coloration); setMix(info.mix); setTime(info.time); setDamping(info.damping); setPreDelay(info.preDelay); } }; /** Reverb effect with configurable reflection filtering, adds per-channel low-pass and crosstalk */ class EffectReverbHi : public EffectReverbStd { float x1dc_crosstalk; /**< [0.0, 1.0] factor defining how much reflections are allowed to bleed to other channels */ template friend class EffectReverbHiImp; EffectReverbHi(float coloration, float mix, float time, float damping, float preDelay, float crosstalk); public: template using ImpType = EffectReverbHiImp; void setCrosstalk(float crosstalk) { x1dc_crosstalk = std::clamp(0.f, crosstalk, 1.f); m_dirty = true; } float getCrosstalk() const { return x1dc_crosstalk; } void setParams(const EffectReverbHiInfo& info) { setColoration(info.coloration); setMix(info.mix); setTime(info.time); setDamping(info.damping); setPreDelay(info.preDelay); setCrosstalk(info.crosstalk); } }; /** Standard-quality 2-stage reverb */ template class EffectReverbStdImp : public EffectBase, public EffectReverbStd { ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */ ReverbDelayLine x78_C[8][2] = {}; /**< Comb delay lines */ float xf0_allPassCoef = 0.f; /**< All-pass mix coefficient */ float xf4_combCoef[8][2] = {}; /**< Comb mix coefficients */ float x10c_lpLastout[8] = {}; /**< Last low-pass results */ float x118_level = 0.f; /**< Internal wet/dry mix factor */ float x11c_damping = 0.f; /**< Low-pass damping */ int32_t x120_preDelayTime = 0; /**< Sample count of pre-delay */ std::unique_ptr x124_preDelayLine[8]; /**< Dedicated pre-delay buffers */ float* x130_preDelayPtr[8] = {}; /**< Current pre-delay pointers */ double m_sampleRate; /**< copy of sample rate */ void _setup(double sampleRate); void _update(); public: EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate); EffectReverbStdImp(const EffectReverbStdInfo& info, double sampleRate) : EffectReverbStdImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, sampleRate) {} void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override; void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); } EffectType Isa() const override { return EffectType::ReverbStd; } }; /** High-quality 3-stage reverb with per-channel low-pass and crosstalk */ template class EffectReverbHiImp : public EffectBase, public EffectReverbHi { ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */ ReverbDelayLine x78_LP[8] = {}; /**< Per-channel low-pass delay-lines */ ReverbDelayLine xb4_C[8][3] = {}; /**< Comb delay lines */ float x168_allPassCoef = 0.f; /**< All-pass mix coefficient */ float x16c_combCoef[8][3] = {}; /**< Comb mix coefficients */ float x190_lpLastout[8] = {}; /**< Last low-pass results */ float x19c_level = 0.f; /**< Internal wet/dry mix factor */ float x1a0_damping = 0.f; /**< Low-pass damping */ int32_t x1a4_preDelayTime = 0; /**< Sample count of pre-delay */ std::unique_ptr x1ac_preDelayLine[8]; /**< Dedicated pre-delay buffers */ float* x1b8_preDelayPtr[8] = {}; /**< Current pre-delay pointers */ float x1a8_internalCrosstalk = 0.f; double m_sampleRate; /**< copy of sample rate */ void _setup(double sampleRate); void _update(); void _handleReverb(T* audio, int chanIdx, int chanCount, int sampleCount); void _doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount); public: EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk, double sampleRate); EffectReverbHiImp(const EffectReverbHiInfo& info, double sampleRate) : EffectReverbHiImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, info.crosstalk, sampleRate) {} void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override; void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); } EffectType Isa() const override { return EffectType::ReverbHi; } }; } // namespace amuse