From 002c2b985ced72af1a35e98b1479527540581f3a Mon Sep 17 00:00:00 2001 From: jnonis Date: Sat, 6 Jul 2024 21:07:16 +0000 Subject: [PATCH] Added Ping Pong Mode and Mix control to Delay FX --- src/effect_delay.cpp | 91 +++++++++++++++++++++++++++++++++++--------- src/effect_delay.h | 15 ++++++++ src/uimenu.cpp | 6 ++- 3 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/effect_delay.cpp b/src/effect_delay.cpp index d62b7c9..90db731 100644 --- a/src/effect_delay.cpp +++ b/src/effect_delay.cpp @@ -1,3 +1,7 @@ +/* + * Stereo Delay + * Javier Nonis (https://github.com/jnonis) - 2024 + */ #include #include "effect_delay.h" @@ -19,7 +23,9 @@ AudioEffectDelay::AudioEffectDelay(float32_t samplerate) : AudioEffect(samplerat this->timeL = 0.36f; this->timeR = 0.36f; - this->feedback = 0.5f; + this->feedback = 0.6f; + this->pingPongMode = false; + this->setMix(0.5f); } AudioEffectDelay::~AudioEffectDelay() @@ -53,6 +59,12 @@ void AudioEffectDelay::setParameter(unsigned param, unsigned value) case AudioEffectDelay::Param::TONE: this->lpf->setParameter(AudioEffectLPF::Param::CUTOFF, value); break; + case AudioEffectDelay::Param::PING_PONG: + this->pingPongMode = (value == 1); + break; + case AudioEffectDelay::Param::MIX: + this->setMix((float32_t) value / 100.0f); + break; default: break; } @@ -72,35 +84,80 @@ unsigned AudioEffectDelay::getParameter(unsigned param) return roundf(this->feedback * 100); case AudioEffectDelay::Param::TONE: return this->lpf->getParameter(AudioEffectLPF::Param::CUTOFF); + case AudioEffectDelay::Param::PING_PONG: + return this->pingPongMode ? 1 : 0; + case AudioEffectDelay::Param::MIX: + return roundf(this->mix * 100); default: return 0; } } +void AudioEffectDelay::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; + } +} void AudioEffectDelay::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len) { for (uint16_t i=0; i < len; i++) { - // Update buffers - this->bufferL[index] = inblockL[i]; - this->bufferR[index] = inblockR[i]; + float32_t inL = inblockL[i]; + float32_t inR = inblockR[i]; + if (this->pingPongMode) + { + // Ping Pong mode only uses timeL + // Calculate offsets + int offsetL = this->index - (this->timeL * this->samplerate); + if (offsetL < 0) + { + offsetL = this->bufferSize + offsetL; + } + + // We need to feed the buffers each other + this->bufferL[index] = this->lpf->processSampleR(this->bufferR[offsetL]) * this->feedback; + this->bufferR[index] = this->lpf->processSampleL(this->bufferL[offsetL]) * this->feedback; - // Calculate offsets - int offsetL = this->index - (this->timeL * this->samplerate); - if (offsetL < 0) { - offsetL = this->bufferSize + offsetL; - } - int offsetR = this->index - (this->timeR * this->samplerate); - if (offsetR < 0) { - offsetR = this->bufferSize + offsetR; + outblockL[i] = (inL * this->dryMix) + (this->bufferL[index] * this->wetMix); + outblockR[i] = (inR * this->dryMix) + (this->bufferR[index] * this->wetMix); + + // Update buffers + this->bufferL[index] += (inL + inR) * 0.5f; } + else + { + // Calculate offsets + int offsetL = this->index - (this->timeL * this->samplerate); + if (offsetL < 0) + { + offsetL = this->bufferSize + offsetL; + } + int offsetR = this->index - (this->timeR * this->samplerate); + if (offsetR < 0) + { + offsetR = this->bufferSize + offsetR; + } + + this->bufferL[index] = this->lpf->processSampleL(this->bufferL[offsetL]) * this->feedback; + this->bufferR[index] = this->lpf->processSampleR(this->bufferR[offsetR]) * this->feedback; + + outblockL[i] = (inL * this->dryMix) + (this->bufferL[index] * this->wetMix); + outblockR[i] = (inR * this->dryMix) + (this->bufferR[index] * this->wetMix); - this->bufferL[index] += this->lpf->processSampleL(this->bufferL[offsetL]) * this->feedback; - this->bufferR[index] += this->lpf->processSampleR(this->bufferR[offsetR]) * this->feedback; - - outblockL[i] = this->bufferL[index]; - outblockR[i] = this->bufferR[index]; + // Update buffers + this->bufferL[index] += inL; + this->bufferR[index] += inR; + } // Update index this->index++; diff --git a/src/effect_delay.h b/src/effect_delay.h index 13903cb..1d2d514 100644 --- a/src/effect_delay.h +++ b/src/effect_delay.h @@ -1,3 +1,10 @@ +/* + * Stereo Delay + * Features: + * - Tone control using Low Pass Filter + * - Ping Pong mode. + * Javier Nonis (https://github.com/jnonis) - 2024 + */ #ifndef _EFFECT_DELAY_H #define _EFFECT_DELAY_H @@ -16,6 +23,8 @@ public: TIME_R, FEEDBACK, TONE, + PING_PONG, + MIX, UNKNOWN }; @@ -41,6 +50,12 @@ private: float32_t timeR; // Right delay time in seconds (0.0 - 2.0) float32_t feedback; // Feedback (0.0 - 1.0) AudioEffectLPF* lpf; + bool pingPongMode; + float32_t mix; + float32_t dryMix; + float32_t wetMix; + + void setMix(float32_t mix); }; #endif // _EFFECT_DELAY_H \ No newline at end of file diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 2474e48..3276e99 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -167,6 +167,8 @@ const CUIMenu::TMenuItem CUIMenu::s_FXDelay[] = {"Time R", EditTGFXParameter, 0, AudioEffectDelay::Param::TIME_R}, {"Feedback", EditTGFXParameter, 0, AudioEffectDelay::Param::FEEDBACK}, {"Tone", EditTGFXParameter, 0, AudioEffectDelay::Param::TONE}, + {"Ping Pong", EditTGFXParameter, 0, AudioEffectDelay::Param::PING_PONG}, + {"Mix", EditTGFXParameter, 0, AudioEffectDelay::Param::MIX}, {0} }; @@ -349,7 +351,9 @@ const CUIMenu::TParameter CUIMenu::s_TGFXDelayParam[AudioEffectDelay::Param::UNK {0, AudioEffectDelay::MAX_DELAY_TIME * 1000, 1}, // TIME_L {0, AudioEffectDelay::MAX_DELAY_TIME * 1000, 1}, // TIME_R {0, 100, 1}, // FEEDBACK, - {0, 100, 1} // TONE + {0, 100, 1}, // TONE + {0, 1, 1, ToOnOff}, // PING_PONG + {0, 100, 1} // MIX }; // must match AudioEffectLPF::Param