Added LP Filter Effect

pull/764/head
jnonis 7 months ago
parent 75f4333831
commit 9b1ea33966
  1. 1
      src/effect_base.h
  2. 52
      src/effect_delay.cpp
  3. 117
      src/effect_lpf.h
  4. 30
      src/effects.h
  5. 24
      src/minidexed.cpp
  6. 10
      src/uimenu.cpp

@ -7,6 +7,7 @@
#define EFFECT_NONE 0
#define EFFECT_CHORUS 1
#define EFFECT_DELAY 2
#define EFFECT_LPF 3
class AudioEffect
{

@ -1,30 +1,30 @@
#include <circle/logger.h>
#include "effect_delay.h"
LOGMODULE ("fx chorus");
LOGMODULE ("fx delay");
AudioEffectDelay::AudioEffectDelay(float32_t samplerate) : AudioEffect(samplerate)
{
bufferSize = (int) samplerate * MAX_DELAY_TIME;
bufferL = new float32_t[this->bufferSize];
bufferR = new float32_t[this->bufferSize];
index = 0;
this->bufferSize = (int) samplerate * MAX_DELAY_TIME;
this->bufferL = new float32_t[this->bufferSize];
this->bufferR = new float32_t[this->bufferSize];
this->index = 0;
for (size_t i = 0; i < bufferSize; i++)
for (size_t i = 0; i < this->bufferSize; i++)
{
bufferL[i] = 0.0f;
bufferR[i] = 0.0f;
this->bufferL[i] = 0.0f;
this->bufferR[i] = 0.0f;
}
timeL = 0.36f;
timeR = 0.36f;
feedback = 0.3f;
this->timeL = 0.36f;
this->timeR = 0.36f;
this->feedback = 0.3f;
}
AudioEffectDelay::~AudioEffectDelay()
{
delete bufferL;
delete bufferR;
delete this->bufferL;
delete this->bufferR;
}
unsigned AudioEffectDelay::getId()
@ -37,30 +37,30 @@ void AudioEffectDelay::doProcess(const float32_t* inblockL, const float32_t* inb
for (uint16_t i=0; i < len; i++)
{
// Update buffers
bufferL[index] = inblockL[i];
bufferR[index] = inblockR[i];
this->bufferL[index] = inblockL[i];
this->bufferR[index] = inblockR[i];
// Calculate offsets
int offsetL = index - (timeL * samplerate);
int offsetL = this->index - (this->timeL * this->samplerate);
if (offsetL < 0) {
offsetL = bufferSize + offsetL;
offsetL = this->bufferSize + offsetL;
}
int offsetR = index - (timeR * samplerate);
int offsetR = this->index - (this->timeR * this->samplerate);
if (offsetR < 0) {
offsetR = bufferSize + offsetR;
offsetR = this->bufferSize + offsetR;
}
bufferL[index] += bufferL[offsetL] * feedback;
bufferR[index] += bufferR[offsetR] * feedback;
this->bufferL[index] += this->bufferL[offsetL] * this->feedback;
this->bufferR[index] += this->bufferR[offsetR] * this->feedback;
outblockL[i] = bufferL[index];
outblockR[i] = bufferR[index];
outblockL[i] = this->bufferL[index];
outblockR[i] = this->bufferR[index];
// Update index
index++;
if (index >= bufferSize)
this->index++;
if (this->index >= this->bufferSize)
{
index = 0;
this->index = 0;
}
}
}

@ -0,0 +1,117 @@
#ifndef _EFFECT_LPF_H
#define _EFFECT_LPF_H
#include "effect_base.h"
class AudioEffectLPF : public AudioEffect
{
public:
static constexpr float32_t MIN_CUTOFF = 0.00001f;
static constexpr float32_t MAX_CUTOFF = 8000.0f;
static constexpr float32_t MIN_RES = 0.0f;
static constexpr float32_t MAX_RES = 1.0f;
AudioEffectLPF(float32_t samplerate) : AudioEffect(samplerate)
{
// Setup init values
this->setCutoff(2000.0f);
this->setResonance(MIN_RES);
}
virtual ~AudioEffectLPF()
{
}
virtual unsigned getId()
{
return EFFECT_LPF;
}
/**
* Set the static cutoff frequency of the filter.
* Cutoff frequency must be between MIN_CUTOFF and MAX_CUTOFF.
* Envelope signal varies the cutoff frequency from this static value.
*/
void setCutoff(float32_t cutoff)
{
// Check limits
cutoff = (cutoff < MIN_CUTOFF) ? MIN_CUTOFF : cutoff;
cutoff = (cutoff > MAX_CUTOFF) ? MAX_CUTOFF : cutoff;
this->cutoff = cutoff;
recalculate();
}
/**
* Set the resonance of the filter.
* Valid values are between 0.0 and 1.0 where
* 0.0 is no resonance and 1.0 is full resonance or oscillation.
*/
void setResonance(float32_t resonance)
{
// Check limits
resonance = (resonance < MIN_RES) ? MIN_RES : resonance;
resonance = (resonance > MAX_RES) ? MAX_RES : resonance;
this->resonance = resonance;
recalculate();
}
protected:
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
for (int i = 0; i < len; i++) {
// Get a sample to process
float32_t s = inblockL[i];
// Return processed sample from filter
outblockL[i] = processSample(s);
}
}
private:
float32_t cutoff;
float32_t resonance;
float32_t x, r, p, k, y1, y2, y3, y4, oldx, oldy1, oldy2, oldy3;
/**
* Recalculate filter parameters on changes to cutoff or resonance
*/
void recalculate()
{
float32_t f = (cutoff + cutoff) / this->samplerate;
p = f * (1.8 - (0.8 * f));
k = p + p - 1.0;
float32_t t = (1.0 - p) * 1.386249;
float32_t t2 = 12.0 + t * t;
r = resonance * (t2 + 6.0 * t) / (t2 - 6.0 * t);
}
/**
* Process a single sample through the filter
*/
float32_t processSample(float32_t input)
{
// Process input
//x = ((float32_t) input/ F32_MAX) - r * y4;
x = input - r * y4;
// Four cascaded one pole filters (bilinear transform)
y1 = x * p + oldx * p - k * y1;
y2 = y1 * p + oldy1 * p - k * y2;
y3 = y2 * p + oldy2 * p - k * y3;
y4 = y3 * p + oldy3 * p - k * y4;
// Clipper band limited sigmoid
y4 -= (y4 * y4 * y4) / 6.0;
oldx = x;
oldy1 = y1;
oldy2 = y2;
oldy3 = y3;
//return (float32_t) (y4 * F32_MAX);
return y4;
}
};
#endif // _EFFECT_LPF_H

@ -1,8 +1,38 @@
#ifndef _EFFECTS_H
#define _EFFECTS_H
#include <string>
#include "effect_base.h"
#include "effect_chorus.h"
#include "effect_delay.h"
#include "effect_lpf.h"
inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate)
{
switch (type)
{
case EFFECT_CHORUS:
return new AudioEffectChorus(samplerate);
case EFFECT_DELAY:
return new AudioEffectDelay(samplerate);
case EFFECT_LPF:
return new AudioEffectLPF(samplerate);
case EFFECT_NONE:
default:
return new AudioEffectNone(samplerate);
}
}
inline std::string getFXTypeName(int nValue)
{
switch (nValue)
{
case EFFECT_CHORUS: return "Juno Chorus";
case EFFECT_DELAY: return "Delay";
case EFFECT_LPF: return "LP Filter";
case EFFECT_NONE:
default: return "None";
}
}
#endif // _EFFECTS_H

@ -591,28 +591,16 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG)
void CMiniDexed::setInsertFXType (unsigned nType, unsigned nTG)
{
nType=constrain((int) nType, 0, 2);
assert (nTG < CConfig::ToneGenerators);
m_InsertFXSpinLock[nTG]->Acquire();
delete m_InsertFX[nTG];
switch (nType)
{
case EFFECT_CHORUS:
m_InsertFX[nTG] = new AudioEffectChorus(m_pConfig->GetSampleRate());
break;
case EFFECT_DELAY:
m_InsertFX[nTG] = new AudioEffectDelay(m_pConfig->GetSampleRate());
break;
case EFFECT_NONE:
default:
m_InsertFX[nTG] = new AudioEffectNone(m_pConfig->GetSampleRate());
break;
// If the effect type is already set just return
if (m_InsertFX[nTG]->getId() == nType) {
return;
}
m_InsertFXSpinLock[nTG]->Acquire();
delete m_InsertFX[nTG];
m_InsertFX[nTG] = newAudioEffect(nType, m_pConfig->GetSampleRate());
m_InsertFXSpinLock[nTG]->Release();
m_UI.ParameterChanged ();

@ -250,7 +250,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, 2, 1, ToFXType}, // TGParameterInsertFXType
{0, 3, 1, ToFXType}, // TGParameterInsertFXType
{-99, 99, 1}, // TGParameterMasterTune
{0, 99, 1}, // TGParameterCutoff
{0, 99, 1}, // TGParameterResonance
@ -1252,13 +1252,7 @@ string CUIMenu::ToPolyMono (int nValue)
string CUIMenu::ToFXType (int nValue)
{
switch (nValue)
{
case EFFECT_CHORUS: return "Juno Chorus";
case EFFECT_DELAY: return "Delay";
case EFFECT_NONE:
default: return "None";
}
return getFXTypeName(nValue);
}
void CUIMenu::TGShortcutHandler (TMenuEvent Event)

Loading…
Cancel
Save