FXRack finalization

pull/409/head
abscisys 2 years ago
parent 4fb79f858a
commit e18c0f284e
  1. 112
      src/fx_flanger.cpp
  2. 26
      src/fx_flanger.h
  3. 25
      src/minidexed.cpp
  4. 1
      src/minidexed.h
  5. 7
      src/performance.ini
  6. 12
      src/performanceconfig.cpp
  7. 3
      src/performanceconfig.h
  8. 31
      src/test/fxrack_test.cpp
  9. 2
      src/uimenu.cpp

@ -2,17 +2,22 @@
#include <cmath>
Flanger::Flanger(float32_t sampling_rate, float32_t delay_time, float32_t frequency, float32_t depth, float32_t feedback) :
Flanger::Flanger(float32_t sampling_rate, float32_t rate, float32_t depth, float32_t feedback) :
FXElement(sampling_rate),
MaxDelayLineSize(static_cast<unsigned>(2.0f * MAX_FLANGER_DELAY * sampling_rate / 1000.0f)),
delay_line_index_(0),
lfo_(sampling_rate, LFO::Waveform::Sine, 0.1f, 10.0f)
MaxDelayLineSize(static_cast<unsigned>(MAX_FLANGER_DELAY * sampling_rate)),
write_index_(0)
{
this->delay_lineL_ = new float32_t[this->MaxDelayLineSize];
this->delay_lineR_ = new float32_t[this->MaxDelayLineSize];
this->setDelayTime(delay_time);
this->setFrequency(frequency);
memset(this->delay_lineL_, 0, this->MaxDelayLineSize * sizeof(float32_t));
memset(this->delay_lineR_, 0, this->MaxDelayLineSize * sizeof(float32_t));
memset(this->feedback_samples_, 0, 2 * sizeof(float32_t));
this->lfo_[LFO_Index::LFO_L] = new LFO(sampling_rate, LFO::Waveform::Sine, 0.1f, 5.0f);
this->lfo_[LFO_Index::LFO_R] = new LFO(sampling_rate, LFO::Waveform::Sine, 0.1f, 5.0f, Constants::MPI_2);
this->setRate(rate);
this->setDepth(depth);
this->setFeedback(feedback);
}
@ -21,52 +26,96 @@ Flanger::~Flanger()
{
delete[] this->delay_lineL_;
delete[] this->delay_lineR_;
delete this->lfo_[LFO_Index::LFO_L];
delete this->lfo_[LFO_Index::LFO_R];
}
inline float32_t linearIterpolationnterp(float32_t inX, float32_t inY, float32_t inPhase)
{
return (1.0f - inPhase) * inX + inPhase * inY;
}
void Flanger::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
// Calculate the delay time based on the depth and rate parameters
float32_t delay = this->getDelayTime() + this->getDepth() * this->lfo_.process();
// Write sample and any feedback into delay buffers
this->delay_lineL_[this->write_index_] = inL + this->feedback_samples_[0];
this->delay_lineR_[this->write_index_] = inR + this->feedback_samples_[1];
// Convert the delay time to samples
unsigned delay_samples = static_cast<unsigned>(delay * this->getSamplingRate() / 1000.0f);
++this->write_index_;
if(this->write_index_ >= this->MaxDelayLineSize)
{
this->write_index_ -= this->MaxDelayLineSize;
}
// mix the input audio with the delayed audio and the feedback signal
outL = inL + this->delay_lineL_[(this->delay_line_index_ + this->delay_line_size_ - delay_samples) % this->delay_line_size_] * (1.0 - this->getFeedback());
outR = inR + this->delay_lineR_[(this->delay_line_index_ + this->delay_line_size_ - delay_samples) % this->delay_line_size_] * (1.0 - this->getFeedback());
// Configure LFO for effect processing
float32_t lfo_l = this->lfo_[LFO_L]->process() * this->depth_;
float32_t lfo_r = this->lfo_[LFO_R]->process() * this->depth_;
// Update the delay buffer with the mixed audio and the feedback signal
this->delay_lineL_[this->delay_line_index_] = inL + outL * this->getFeedback();
this->delay_lineR_[this->delay_line_index_] = inR + outR * this->getFeedback();
// Map LFO range to millisecond range according to Chorus or Flanger effect
float32_t lfoMappedL = mapfloat(lfo_l, -1.0f, 1.0f, 0.001f, 0.005f);
float32_t lfoMappedR = mapfloat(lfo_r, -1.0f, 1.0f, 0.001f, 0.005f);
this->delay_line_index_ = (this->delay_line_index_ + 1) % this->delay_line_size_;
// Calculate delay lengths in samples
float32_t delayTimeSamplesL = this->getSamplingRate() * lfoMappedL;
float32_t delayTimeSamplesR = this->getSamplingRate() * lfoMappedR;
// Calculate read head positions
float32_t delayReadHeadL = this->write_index_ - delayTimeSamplesL;
if(delayReadHeadL < 0.0f)
{
delayReadHeadL += this->MaxDelayLineSize;
}
float32_t delayReadHeadR = this->write_index_ - delayTimeSamplesR;
if(delayReadHeadR < 0.0f)
{
delayReadHeadR += this->MaxDelayLineSize;
}
void Flanger::setDelayTime(float32_t delayMS)
// Calculate linear interpolation point for left channel
int currentL = (int)delayReadHeadL;
int nextL = currentL + 1;
float32_t fractionL = delayReadHeadL - currentL;
if(nextL >= static_cast<int>(this->MaxDelayLineSize))
{
this->delay_time_ms_ = constrain(delayMS, 1.0f, MAX_FLANGER_DELAY);
this->adjustDelayCofficients();
nextL -= this->MaxDelayLineSize;
}
float32_t Flanger::getDelayTime() const
// Calculate linear interpolation point for right channel
int currentR = (int)delayReadHeadR;
int nextR = currentR + 1;
float32_t fractionR = delayReadHeadR - currentR;
if(nextR >= static_cast<int>(this->MaxDelayLineSize))
{
return this->delay_time_ms_;
nextR -= this->MaxDelayLineSize;
}
void Flanger::setFrequency(float32_t frequency)
// Interpolate and read from delay buffer
float32_t delay_sample_l = linearIterpolationnterp(this->delay_lineL_[currentL], this->delay_lineL_[nextL], fractionL);
float32_t delay_sample_r = linearIterpolationnterp(this->delay_lineR_[currentR], this->delay_lineR_[nextR], fractionR);
// Store delayed samples as feedback
this->feedback_samples_[0] = delay_sample_l * this->feedback_;
this->feedback_samples_[1] = delay_sample_r * this->feedback_;
outL = delay_sample_l;
outR = delay_sample_r;
}
void Flanger::setRate(float32_t rate)
{
this->lfo_.setNormalizedFrequency(frequency);
this->lfo_[LFO_Index::LFO_L]->setNormalizedFrequency(rate);
this->lfo_[LFO_Index::LFO_R]->setNormalizedFrequency(rate);
}
float32_t Flanger::getFrequency() const
float32_t Flanger::getRate() const
{
return this->lfo_.getNormalizedFrequency();
return this->lfo_[LFO_Index::LFO_L]->getNormalizedFrequency();
}
void Flanger::setDepth(float32_t depth)
{
this->depth_ = constrain(depth, 0.0f, MAX_FLANGER_DELAY);
this->adjustDelayCofficients();
this->depth_ = constrain(depth, 0.0f, 1.0f);
}
float32_t Flanger::getDepth() const
@ -76,15 +125,10 @@ float32_t Flanger::getDepth() const
void Flanger::setFeedback(float32_t feedback)
{
this->feedback_ = constrain(feedback, 0.0f, 1.0f);
this->feedback_ = constrain(feedback, 0.0f, 0.97f);
}
float32_t Flanger::getFeedback() const
{
return this->feedback_;
}
void Flanger::adjustDelayCofficients()
{
this->delay_line_size_ = static_cast<unsigned>(this->getSamplingRate() * (this->getDelayTime() + this->getDepth()) / 1000.0f);
}

@ -20,23 +20,26 @@
#include "fx_components.h"
#define MAX_FLANGER_DELAY 20.0f
#define MAX_FLANGER_DELAY 2.0f
class Flanger : public FXElement
{
DISALLOW_COPY_AND_ASSIGN(Flanger);
public:
Flanger(float32_t sampling_rate, float32_t delay_time = 5.0f, float32_t frequency = 0.05f, float32_t depth = 1.0f, float32_t feedback = 0.25f);
enum LFO_Index
{
LFO_L = 0,
LFO_R
};
Flanger(float32_t sampling_rate, float32_t rate = 0.5f, float32_t depth = 0.5f, float32_t feedback = 0.0f);
virtual ~Flanger();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setDelayTime(float32_t delayMS);
float32_t getDelayTime() const;
void setFrequency(float32_t frequency);
float32_t getFrequency() const;
void setRate(float32_t rate);
float32_t getRate() const;
void setDepth(float32_t depth);
float32_t getDepth() const;
@ -45,16 +48,13 @@ public:
float32_t getFeedback() const;
private:
inline void adjustDelayCofficients();
const unsigned MaxDelayLineSize;
unsigned delay_line_index_;
unsigned delay_line_size_;
float32_t* delay_lineL_;
float32_t* delay_lineR_;
unsigned write_index_;
float32_t feedback_samples_[2];
float32_t delay_time_ms_; // Delay time in milliseconds (0.0 - 10.0)
LFO lfo_;
LFO* lfo_[2];
float32_t depth_; // Depth of the flanger effect in milliseconds (0.0 - 10.0)
float32_t feedback_; // Amount of feedback to apply to the delay line
};

@ -180,10 +180,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
// FXChain > Flanger parameters
this->SetParameter(ParameterFXChainFlangerEnable, 1);
this->SetParameter(ParameterFXChainFlangerWet, 50);
this->SetParameter(ParameterFXChainFlangerDelayTime, 10);
this->SetParameter(ParameterFXChainFlangerRate, 15);
this->SetParameter(ParameterFXChainFlangerDepth, 10);
this->SetParameter(ParameterFXChainFlangerFeedback, 20);
this->SetParameter(ParameterFXChainFlangerRate, 3);
this->SetParameter(ParameterFXChainFlangerDepth, 75);
this->SetParameter(ParameterFXChainFlangerFeedback, 50);
// FXChain > Orbitone parameters
this->SetParameter(ParameterFXChainOrbitoneEnable, 1);
@ -195,7 +194,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
this->SetParameter(ParameterFXChainPhaserEnable, 1);
this->SetParameter(ParameterFXChainPhaserWet, 50);
this->SetParameter(ParameterFXChainPhaserRate, 5);
this->SetParameter(ParameterFXChainPhaserDepth, 45);
this->SetParameter(ParameterFXChainPhaserDepth, 99);
this->SetParameter(ParameterFXChainPhaserFeedback, 50);
this->SetParameter(ParameterFXChainPhaserNbStages, 12);
// FXChain > Delay parameters
this->SetParameter(ParameterFXChainDelayEnable, 1);
@ -816,28 +817,22 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue)
this->fx_rack->getFlanger()->setWetLevel(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainFlangerDelayTime:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getFlanger()->setDelayTime(mapfloat(nValue, 0, 99, 1.0f, MAX_FLANGER_DELAY));
this->m_FXSpinLock.Release();
break;
case ParameterFXChainFlangerRate:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getFlanger()->setFrequency(nValue / 99.0f);
this->fx_rack->getFlanger()->setRate(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainFlangerDepth:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getFlanger()->setDepth(mapfloat(nValue, 0, 99, 0.0f, MAX_FLANGER_DELAY));
this->fx_rack->getFlanger()->setDepth(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainFlangerFeedback:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getFlanger()->setFeedback(nValue / 99.0f);
this->fx_rack->getFlanger()->setFeedback(mapfloat(nValue, 0, 99, 0.0f, 0.97f));
this->m_FXSpinLock.Release();
break;
@ -1407,7 +1402,6 @@ bool CMiniDexed::DoSavePerformance (void)
this->m_PerformanceConfig.SetFXChainChorusDepth(this->m_nParameter[ParameterFXChainChorusDepth]);
this->m_PerformanceConfig.SetFXChainFlangerEnable(!!this->m_nParameter[ParameterFXChainFlangerEnable]);
this->m_PerformanceConfig.SetFXChainFlangerWet(this->m_nParameter[ParameterFXChainFlangerWet]);
this->m_PerformanceConfig.SetFXChainFlangerDelayTime(this->m_nParameter[ParameterFXChainFlangerDelayTime]);
this->m_PerformanceConfig.SetFXChainFlangerRate(this->m_nParameter[ParameterFXChainFlangerRate]);
this->m_PerformanceConfig.SetFXChainFlangerDepth(this->m_nParameter[ParameterFXChainFlangerDepth]);
this->m_PerformanceConfig.SetFXChainFlangerFeedback(this->m_nParameter[ParameterFXChainFlangerFeedback]);
@ -1836,7 +1830,6 @@ void CMiniDexed::LoadPerformanceParameters(void)
this->SetParameter(ParameterFXChainChorusDepth, this->m_PerformanceConfig.GetFXChainChorusDepth());
this->SetParameter(ParameterFXChainFlangerEnable, this->m_PerformanceConfig.GetFXChainFlangerEnable());
this->SetParameter(ParameterFXChainFlangerWet, this->m_PerformanceConfig.GetFXChainFlangerWet());
this->SetParameter(ParameterFXChainFlangerDelayTime, this->m_PerformanceConfig.GetFXChainFlangerDelayTime());
this->SetParameter(ParameterFXChainFlangerRate, this->m_PerformanceConfig.GetFXChainFlangerRate());
this->SetParameter(ParameterFXChainFlangerDepth, this->m_PerformanceConfig.GetFXChainFlangerDepth());
this->SetParameter(ParameterFXChainFlangerFeedback, this->m_PerformanceConfig.GetFXChainFlangerFeedback());

@ -160,7 +160,6 @@ public:
// FXChain > Flanger parameters
ParameterFXChainFlangerEnable,
ParameterFXChainFlangerWet,
ParameterFXChainFlangerDelayTime,
ParameterFXChainFlangerRate,
ParameterFXChainFlangerDepth,
ParameterFXChainFlangerFeedback,

@ -295,10 +295,9 @@ FXChainChorusRate=40
FXChainChorusDepth=50
FXChainFlangerEnable=0
FXChainFlangerWet=50
FXChainFlangerDelayTime=10
FXChainFlangerRate=15
FXChainFlangerDepth=10
FXChainFlangerFeedback=20
FXChainFlangerRate=3
FXChainFlangerDepth=75
FXChainFlangerFeedback=50
FXChainOrbitoneEnable=0
FXChainOrbitoneWet=80
FXChainOrbitoneRate=40

@ -171,7 +171,6 @@ bool CPerformanceConfig::Load (void)
this->m_nFXChainChorusDepth = this->m_Properties.GetNumber("FXChainChorusDepth", 50);
this->m_bFXChainFlangerEnable = this->m_Properties.GetNumber("FXChainFlangerEnable", 1);
this->m_nFXChainFlangerWet = this->m_Properties.GetNumber("FXChainFlangerWet", 50);
this->m_nFXChainFlangerDelayTime = this->m_Properties.GetNumber("FXChainFlangerDelayTime", 10);
this->m_nFXChainFlangerRate = this->m_Properties.GetNumber("FXChainFlangerRate", 15);
this->m_nFXChainFlangerDepth = this->m_Properties.GetNumber("FXChainFlangerDepth", 10);
this->m_nFXChainFlangerFeedback = this->m_Properties.GetNumber("FXChainFlangerFeedback", 20);
@ -328,7 +327,6 @@ bool CPerformanceConfig::Save (void)
this->m_Properties.SetNumber("FXChainChorusDepth", m_nFXChainChorusDepth);
this->m_Properties.SetNumber("FXChainFlangerEnable", m_bFXChainFlangerEnable ? 1 : 0);
this->m_Properties.SetNumber("FXChainFlangerWet", m_nFXChainFlangerWet);
this->m_Properties.SetNumber("FXChainFlangerDelayTime", m_nFXChainFlangerDelayTime);
this->m_Properties.SetNumber("FXChainFlangerRate", m_nFXChainFlangerRate);
this->m_Properties.SetNumber("FXChainFlangerDepth", m_nFXChainFlangerDepth);
this->m_Properties.SetNumber("FXChainFlangerFeedback", m_nFXChainFlangerFeedback);
@ -1058,11 +1056,6 @@ unsigned CPerformanceConfig::GetFXChainFlangerWet(void) const
return this->m_nFXChainFlangerWet;
}
unsigned CPerformanceConfig::GetFXChainFlangerDelayTime(void) const
{
return this->m_nFXChainFlangerDelayTime;
}
unsigned CPerformanceConfig::GetFXChainFlangerRate(void) const
{
return this->m_nFXChainFlangerRate;
@ -1238,11 +1231,6 @@ void CPerformanceConfig::SetFXChainFlangerWet(unsigned nValue)
this->m_nFXChainFlangerWet = nValue;
}
void CPerformanceConfig::SetFXChainFlangerDelayTime(unsigned nValue)
{
this->m_nFXChainFlangerDelayTime = nValue;
}
void CPerformanceConfig::SetFXChainFlangerRate(unsigned nValue)
{
this->m_nFXChainFlangerRate = nValue;

@ -129,7 +129,6 @@ public:
unsigned GetFXChainChorusDepth(void) const;
bool GetFXChainFlangerEnable(void) const;
unsigned GetFXChainFlangerWet(void) const;
unsigned GetFXChainFlangerDelayTime(void) const;
unsigned GetFXChainFlangerRate(void) const;
unsigned GetFXChainFlangerDepth(void) const;
unsigned GetFXChainFlangerFeedback(void) const;
@ -166,7 +165,6 @@ public:
void SetFXChainChorusDepth(unsigned nValue);
void SetFXChainFlangerEnable(bool bValue);
void SetFXChainFlangerWet(unsigned nValue);
void SetFXChainFlangerDelayTime(unsigned nValue);
void SetFXChainFlangerRate(unsigned nValue);
void SetFXChainFlangerDepth(unsigned nValue);
void SetFXChainFlangerFeedback(unsigned nValue);
@ -272,7 +270,6 @@ private:
unsigned m_nFXChainChorusDepth;
bool m_bFXChainFlangerEnable;
unsigned m_nFXChainFlangerWet;
unsigned m_nFXChainFlangerDelayTime;
unsigned m_nFXChainFlangerRate;
unsigned m_nFXChainFlangerDepth;
unsigned m_nFXChainFlangerFeedback;

@ -142,8 +142,8 @@ void testFXRack(unsigned& step, unsigned fxSwitch)
rack->setWetLevel(1.0f);
rack->getTube()->setEnable(Active(fxSwitch, FXSitch::Tube));
rack->getTube()->setWetLevel(1.0f);
rack->getTube()->setOverdrive(1.0f);
rack->getTube()->setWetLevel(0.25f);
rack->getTube()->setOverdrive(0.25f);
rack->getChorus()->setEnable(Active(fxSwitch, FXSitch::Chorus));
rack->getChorus()->setWetLevel(0.5f);
@ -154,7 +154,8 @@ void testFXRack(unsigned& step, unsigned fxSwitch)
rack->getPhaser()->setWetLevel(1.0f);
rack->getPhaser()->setRate(0.1f);
rack->getPhaser()->setDepth(1.0f);
rack->getPhaser()->setFeedback(0.75f);
rack->getPhaser()->setFeedback(0.5f);
rack->getPhaser()->setNbStages(12);
rack->getOrbitone()->setEnable(Active(fxSwitch, FXSitch::Orbitone));
rack->getOrbitone()->setWetLevel(0.8f);
@ -163,10 +164,9 @@ void testFXRack(unsigned& step, unsigned fxSwitch)
rack->getFlanger()->setEnable(Active(fxSwitch, FXSitch::Flanger));
rack->getFlanger()->setWetLevel(0.5f);
rack->getFlanger()->setDelayTime(0.8f);
rack->getFlanger()->setFrequency(0.25f);
rack->getFlanger()->setDepth(0.8f);
rack->getFlanger()->setFeedback(0.75f);
rack->getFlanger()->setRate(0.03f);
rack->getFlanger()->setDepth(0.75f);
rack->getFlanger()->setFeedback(0.5f);
rack->getDelay()->setEnable(Active(fxSwitch, FXSitch::Delay));
rack->getDelay()->setWetLevel(0.6f);
@ -175,8 +175,8 @@ void testFXRack(unsigned& step, unsigned fxSwitch)
rack->getDelay()->setFeedbak(0.5f);
rack->getShimmerReverb()->setEnable(Active(fxSwitch, FXSitch::Shimmer));
rack->getShimmerReverb()->setWetLevel(0.7f);
rack->getShimmerReverb()->setInputGain(0.45f);
rack->getShimmerReverb()->setWetLevel(0.5f);
rack->getShimmerReverb()->setInputGain(0.35f);
rack->getShimmerReverb()->setTime(0.89f);
rack->getShimmerReverb()->setDiffusion(0.75f);
rack->getShimmerReverb()->setLP(0.8f);
@ -215,12 +215,21 @@ int main()
// testFlutter(step);
// testSVF(step);
// testFXRack(step, FXSitch::Tube);
// testFXRack(step, FXSitch::Flanger); // to be fixed -> feedback deletes FX effect
testFXRack(step, FXSitch::Phaser);
// testFXRack(step, FXSitch::Flanger);
// testFXRack(step, FXSitch::Phaser);
// testFXRack(step, FXSitch::Chorus);
// testFXRack(step, FXSitch::Orbitone);
// testFXRack(step, FXSitch::Delay);
// testFXRack(step, FXSitch::Shimmer);
testFXRack(
step,
FXSitch::Tube |
FXSitch::Chorus |
FXSitch::Flanger |
FXSitch::Orbitone |
FXSitch::Phaser |
FXSitch::Delay |
FXSitch::Shimmer);
return 0;
}

@ -177,7 +177,6 @@ const CUIMenu::TMenuItem CUIMenu::s_FXChainFlanger[] =
{
{"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerEnable},
{"Wet Lvl", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerWet},
{"Delay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerDelayTime},
{"Rate", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerRate},
{"Depth", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerDepth},
{"Feedbck", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainFlangerFeedback},
@ -327,7 +326,6 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow
// FXChain > Flanger parameters
{0, 1, 1, ToOnOff}, // ParameterFXChainFlangerEnable
{0, 99, 1}, // ParameterFXChainFlangerWet
{0, 99, 1}, // ParameterFXChainFlangerDelayTime
{0, 99, 1}, // ParameterFXChainFlangerRate
{0, 99, 1}, // ParameterFXChainFlangerDepth
{0, 99, 1}, // ParameterFXChainFlangerFeedback

Loading…
Cancel
Save