From fc6f7152f05c0e16503ed49c1a039282cf2ce686 Mon Sep 17 00:00:00 2001 From: jnonis Date: Tue, 9 Jul 2024 04:47:42 +0000 Subject: [PATCH] Adapted Plate Reverb as AudioEffect --- src/effect_base.h | 1 + src/effect_platervbstereo.cpp | 95 ++++++++++++++++++++++++++++++++--- src/effect_platervbstereo.h | 65 ++++++++++++++++++++++-- src/effects.h | 4 ++ src/minidexed.cpp | 2 +- src/uimenu.cpp | 53 +++++++++++++++++-- src/uimenu.h | 3 ++ 7 files changed, 206 insertions(+), 17 deletions(-) diff --git a/src/effect_base.h b/src/effect_base.h index 69a885b..f8efb0a 100644 --- a/src/effect_base.h +++ b/src/effect_base.h @@ -15,6 +15,7 @@ #define EFFECT_DS1 4 #define EFFECT_BIGMUFF 5 #define EFFECT_TALREVERB3 6 +#define EFFECT_REVERB 7 class AudioEffect { diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index ce2af1e..2c1161e 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -83,7 +83,7 @@ const int16_t AudioWaveformSine[257] = { -4808, -4011, -3212, -2410, -1608, -804, 0 }; -AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) +AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) : AudioEffect(samplerate) { input_attn = 0.5f; in_allp_k = INP_ALLP_COEFF; @@ -154,6 +154,87 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) lfo2_adder = (UINT32_MAX + 1)/(samplerate * LFO2_FREQ_HZ); reverb_level = 0.0f; + + this->setParameter(AudioEffectPlateReverb::Param::SIZE, 70); + this->setParameter(AudioEffectPlateReverb::Param::HIGH_DAMP, 50); + this->setParameter(AudioEffectPlateReverb::Param::LOW_DAMP, 50); + this->setParameter(AudioEffectPlateReverb::Param::LOW_PASS, 30); + this->setParameter(AudioEffectPlateReverb::Param::DIFFUSION, 65); + this->setParameter(AudioEffectPlateReverb::Param::MIX, 50); + this->setParameter(AudioEffectPlateReverb::Param::LEVEL, 99); +} + +void AudioEffectPlateReverb::initializeSendFX() +{ + this->setParameter(AudioEffectPlateReverb::Param::MIX, 100); +} + +void AudioEffectPlateReverb::setParameter(unsigned param, unsigned value) +{ + switch (param) + { + case AudioEffectPlateReverb::Param::BYPASS: + this->setBypass(value == 1); + break; + case AudioEffectPlateReverb::Param::SIZE: + this->sizeValue = value; + this->size((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::HIGH_DAMP: + this->hidampValue = value; + this->hidamp((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::LOW_DAMP: + this->lodampValue = value; + this->lodamp((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::LOW_PASS: + this->lowpassValue = value; + this->lowpass((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::DIFFUSION: + this->diffusionValue = value; + this->diffusion((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::MIX: + this->setMix((float32_t) value / 100.0f); + break; + case AudioEffectPlateReverb::Param::LEVEL: + this->level((float32_t) value / 100.0f); + break; + default: + break; + } +} + +unsigned AudioEffectPlateReverb::getParameter(unsigned param) +{ + switch (param) + { + case AudioEffectPlateReverb::Param::BYPASS: + return this->getBypass() ? 1 : 0; + case AudioEffectPlateReverb::Param::SIZE: + return this->sizeValue; + case AudioEffectPlateReverb::Param::HIGH_DAMP: + return this->hidampValue; + case AudioEffectPlateReverb::Param::LOW_DAMP: + return this->lodampValue; + case AudioEffectPlateReverb::Param::LOW_PASS: + return this->lowpassValue; + case AudioEffectPlateReverb::Param::DIFFUSION: + return this->diffusionValue; + case AudioEffectPlateReverb::Param::MIX: + return roundf(this->mix * 100); + case AudioEffectPlateReverb::Param::LEVEL: + return roundf(this->reverb_level * 100); + default: + return 0; + } +} + +void AudioEffectPlateReverb::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len) +{ + this->doReverb(inblockL, inblockR, outblockL, outblockR, len); } // #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift)) @@ -235,7 +316,7 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t y += (int64_t)y1 * idx; lfo2_out_cos = (int32_t) (y >> (32-8)); // 16bit output - input = inblockL[i] * input_attn; + input = inblockL[i] * input_attn; // chained input allpasses, channel L acc = in_allp1_bufL[in_allp1_idxL] + input * in_allp_k; @@ -405,10 +486,10 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_l; master_lowpass_l += temp1 * master_lowpass_f; - rvbblockL[i] = master_lowpass_l; + rvbblockL[i] = inblockL[i] * dryMix + master_lowpass_l * wetMix; // Channel R - #ifdef TAP1_MODULATED +#ifdef TAP1_MODULATED temp16 = (lp_dly1_idx + lp_dly1_offset_R + (lfo2_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); temp1 = lp_dly1_buf[temp16++]; // sample now if (temp16 >= sizeof(lp_dly1_buf)/sizeof(float32_t)) temp16 = 0; @@ -416,10 +497,10 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k acc = (temp1*(1.0f-input) + temp2*input)* 0.8f; - #else +#else temp16 = (lp_dly1_idx + lp_dly1_offset_R) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); acc = lp_dly1_buf[temp16] * 0.8f; - #endif +#endif #ifdef TAP2_MODULATED temp16 = (lp_dly2_idx + lp_dly2_offset_R + (lfo1_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); temp1 = lp_dly2_buf[temp16++]; @@ -449,6 +530,6 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_r; master_lowpass_r += temp1 * master_lowpass_f; - rvbblockR[i] = master_lowpass_r; + rvbblockR[i] = inblockR[i] * dryMix + master_lowpass_r * wetMix; } } diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 23538c4..489f9ad 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -47,6 +47,7 @@ #include #include #include "common.h" +#include "effect_base.h" /*** * Loop delay modulation: comment/uncomment to switch sin/cos @@ -56,10 +57,35 @@ //#define TAP1_MODULATED #define TAP2_MODULATED -class AudioEffectPlateReverb +class AudioEffectPlateReverb : public AudioEffect { public: + enum Param + { + BYPASS, + SIZE, + HIGH_DAMP, + LOW_DAMP, + LOW_PASS, + DIFFUSION, + MIX, + LEVEL, + UNKNOWN + }; + AudioEffectPlateReverb(float32_t samplerate); + //virtual ~AudioEffectPlateReverb(); + + virtual unsigned getId() + { + return EFFECT_REVERB; + } + + virtual void initializeSendFX(); + + virtual void setParameter(unsigned param, unsigned value); + virtual unsigned getParameter(unsigned param); + void doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR,uint16_t len); void size(float n) @@ -105,13 +131,42 @@ public: } float32_t get_size(void) {return rv_time_k;} - bool get_bypass(void) {return bypass;} - void set_bypass(bool state) {bypass = state;}; - void tgl_bypass(void) {bypass ^=1;} float32_t get_level(void) {return reverb_level;} + +protected: + virtual size_t getParametersSize() + { + return sizeof(AudioEffectPlateReverb::Param); + } + virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len); + private: - bool bypass = false; float32_t reverb_level; + + unsigned sizeValue; + unsigned hidampValue; + unsigned lodampValue; + unsigned lowpassValue; + unsigned diffusionValue; + float32_t mix; + float32_t dryMix; + float32_t wetMix; + + void setMix(float32_t mix) + { + this->mix = mix; + if (this->mix <= 0.5f) + { + this->dryMix = 1.0f; + this->wetMix = this->mix * 2; + } + else + { + this->dryMix = 1.0f - ((this->mix - 0.5f) * 2); + this->wetMix = 1.0f; + } + } + float32_t input_attn; float32_t in_allp_k; // input allpass coeff diff --git a/src/effects.h b/src/effects.h index b30f419..1c80e7b 100644 --- a/src/effects.h +++ b/src/effects.h @@ -13,6 +13,7 @@ #include "effect_ds1.h" #include "effect_bigmuff.h" #include "effect_talreverb3.h" +#include "effect_platervbstereo.h" inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate) { @@ -30,6 +31,8 @@ inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate) return new AudioEffectBigMuff(samplerate); case EFFECT_TALREVERB3: return new AudioEffectTalReverb3(samplerate); + case EFFECT_REVERB: + return new AudioEffectPlateReverb(samplerate); case EFFECT_NONE: default: return new AudioEffectNone(samplerate); @@ -46,6 +49,7 @@ inline std::string getFXTypeName(int nValue) case EFFECT_DS1: return "DS1"; case EFFECT_BIGMUFF: return "Big Muff"; case EFFECT_TALREVERB3: return "TalRvrb3"; + case EFFECT_REVERB: return "Reverb"; case EFFECT_NONE: default: return "None"; } diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 8308529..29da109 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -850,7 +850,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterReverbEnable: nValue=constrain((int)nValue,0,1); m_ReverbSpinLock.Acquire (); - reverb->set_bypass (!nValue); + reverb->setBypass (!nValue); m_ReverbSpinLock.Release (); break; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index c34a94a..02485e6 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -221,6 +221,19 @@ CUIMenu::TMenuItem CUIMenu::s_FXTalReverb3[] = {0} }; +CUIMenu::TMenuItem CUIMenu::s_FXReverb[] = +{ + {"Bypass", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::BYPASS}, + {"Size", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::SIZE}, + {"High damp", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::HIGH_DAMP}, + {"Low damp", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::LOW_DAMP}, + {"Low pass", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::LOW_PASS}, + {"Diffusion", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::DIFFUSION}, + {"Mix", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::MIX}, + {"Level", EditTGFXParameter, 0, AudioEffectPlateReverb::Param::LEVEL}, + {0} +}; + // inserting menu items before "OP1" affect OPShortcutHandler() const CUIMenu::TMenuItem CUIMenu::s_EditVoiceMenu[] = { @@ -292,7 +305,7 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = { {0, 1, 1, ToOnOff}, // ParameterCompessorEnable - {0, 6, 1, ToFXType}, // ParameterSendFXType + {0, 7, 1, ToFXType}, // ParameterSendFXType {0, 1, 1, ToOnOff}, // ParameterReverbEnable {0, 99, 1}, // ParameterReverbSize {0, 99, 1}, // ParameterReverbHighDamp @@ -313,7 +326,7 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] {0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram {0, 127, 8, ToVolume}, // TGParameterVolume {0, 127, 8, ToPan}, // TGParameterPan - {0, 6, 1, ToFXType}, // TGParameterInsertFXType + {0, 7, 1, ToFXType}, // TGParameterInsertFXType {-99, 99, 1}, // TGParameterMasterTune {0, 99, 1}, // TGParameterCutoff {0, 99, 1}, // TGParameterResonance @@ -362,7 +375,7 @@ const CUIMenu::TParameter CUIMenu::s_TGFXDelayParam[AudioEffectDelay::Param::UNK {0, 100, 1}, // FEEDBACK, {0, 100, 1}, // TONE {0, 1, 1, ToOnOff}, // PING_PONG - {0, 100, 1} // MIX + {0, 100, 1, ToMix} // MIX }; // must match AudioEffectLPF::Param @@ -382,7 +395,7 @@ const CUIMenu::TParameter CUIMenu::s_TGFXDS1Param[AudioEffectDS1::Param::UNKNOWN {1, 99, 1} // LEVEL }; -// must match AudioEffectDS1::Param +// must match AudioEffectBigMuff::Param const CUIMenu::TParameter CUIMenu::s_TGFXBigMuffParam[AudioEffectBigMuff::Param::UNKNOWN] = { {0, 1, 1, ToOnOff}, // BYPASS @@ -406,6 +419,19 @@ const CUIMenu::TParameter CUIMenu::s_TGFXTalReverb3Param[AudioEffectTalReverb3:: {0, 1, 1, ToOnOff} // POWER }; +// must match AudioEffectPlateReverb::Param +const CUIMenu::TParameter CUIMenu::s_TGFXReverbParam[AudioEffectPlateReverb::Param::UNKNOWN] = +{ + {0, 1, 1, ToOnOff}, // BYPASS + {0, 99, 1}, // SIZE + {0, 99, 1}, // HIGH_DAMP + {0, 99, 1}, // LOW_DAMP + {0, 99, 1}, // LOW_PASS + {0, 99, 1}, // DIFFUSION + {0, 100, 1, ToMix}, // MIX + {0, 99, 1}, // LEVEL +}; + // must match DexedVoiceParameters in Synth_Dexed const CUIMenu::TParameter CUIMenu::s_VoiceParameter[] = { @@ -1731,6 +1757,19 @@ string CUIMenu::ToFXType (int nValue) return getFXTypeName(nValue); } +string CUIMenu::ToMix (int nValue) +{ + switch (nValue) + { + case 0: + return "Dry"; + case 100: + return "Wet"; + default: + return to_string (nValue); + } +} + void CUIMenu::TGShortcutHandler (TMenuEvent Event) { assert (m_nCurrentMenuDepth >= 2); @@ -2455,6 +2494,9 @@ CUIMenu::TMenuItem* CUIMenu::getFXMenuItem(unsigned type) case EFFECT_TALREVERB3: menu = s_FXTalReverb3; break; + case EFFECT_REVERB: + menu = s_FXReverb; + break; case EFFECT_NONE: default: menu = s_FXNone; @@ -2510,6 +2552,9 @@ CUIMenu::TParameter CUIMenu::getFXParameter(unsigned type, unsigned nParam) case EFFECT_TALREVERB3: pParam = s_TGFXTalReverb3Param[nParam]; break; + case EFFECT_REVERB: + pParam = s_TGFXReverbParam[nParam]; + break; default: break; } diff --git a/src/uimenu.h b/src/uimenu.h index 530b332..06bef4e 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -127,6 +127,7 @@ private: static std::string ToPortaGlissando (int nValue); static std::string ToPolyMono (int nValue); static std::string ToFXType (int nValue); + static std::string ToMix (int nValue); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); @@ -171,6 +172,7 @@ private: static TMenuItem s_FXDS1[]; static TMenuItem s_FXBigMuff[]; static TMenuItem s_FXTalReverb3[]; + static TMenuItem s_FXReverb[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; @@ -190,6 +192,7 @@ private: static const TParameter s_TGFXDS1Param[]; static const TParameter s_TGFXBigMuffParam[]; static const TParameter s_TGFXTalReverb3Param[]; + static const TParameter s_TGFXReverbParam[]; static const TParameter s_VoiceParameter[]; static const TParameter s_OPParameter[];