|
|
|
@ -1,3 +1,7 @@ |
|
|
|
|
/*
|
|
|
|
|
* Stereo Delay |
|
|
|
|
* Javier Nonis (https://github.com/jnonis) - 2024
|
|
|
|
|
*/ |
|
|
|
|
#include <circle/logger.h> |
|
|
|
|
#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; |
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
if (offsetL < 0) |
|
|
|
|
{ |
|
|
|
|
offsetL = this->bufferSize + offsetL; |
|
|
|
|
} |
|
|
|
|
int offsetR = this->index - (this->timeR * this->samplerate); |
|
|
|
|
if (offsetR < 0) { |
|
|
|
|
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; |
|
|
|
|
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]; |
|
|
|
|
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; |
|
|
|
|
this->bufferR[index] += inR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update index
|
|
|
|
|
this->index++; |
|
|
|
|