Optize existing effect and add the Orbitone effect

pull/409/head
abscisys 2 years ago
parent 154cf690cb
commit 2542be1148
  1. 2
      src/Makefile
  2. 9
      src/fx.cpp
  3. 16
      src/fx.h
  4. 98
      src/fx_orbitone.cpp
  5. 75
      src/fx_orbitone.h
  6. 51
      src/fx_phaser.cpp
  7. 8
      src/fx_phaser.h
  8. 59
      src/fx_rack.cpp
  9. 10
      src/fx_rack.h
  10. 83
      src/fx_shimmer_reverb.cpp
  11. 4
      src/fx_shimmer_reverb.h
  12. 85
      src/fx_tape_delay.cpp
  13. 4
      src/fx_tape_delay.h

@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \
mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \
sysexfileloader.o performanceconfig.o perftimer.o \ sysexfileloader.o performanceconfig.o perftimer.o \
effect_compressor.o effect_platervbstereo.o \ effect_compressor.o effect_platervbstereo.o \
fx.o fx_phaser.o fx_tape_delay.o fx_shimmer_reverb.o fx_rack.o \ fx.o fx_orbitone.o fx_phaser.o fx_tape_delay.o fx_shimmer_reverb.o fx_rack.o \
uibuttons.o midipin.o uibuttons.o midipin.o
OPTIMIZE = -O3 OPTIMIZE = -O3

@ -14,6 +14,15 @@ float32_t FXBase::getSamplingRate() const
return this->SamplingRate; return this->SamplingRate;
} }
FXElement::FXElement(float32_t sampling_rate) :
FXBase(sampling_rate)
{
}
FXElement::~FXElement()
{
}
FX::FX(float32_t sampling_rate) : FX::FX(float32_t sampling_rate) :
FXBase(sampling_rate) FXBase(sampling_rate)
{ {

@ -41,14 +41,28 @@ private:
const float32_t SamplingRate; const float32_t SamplingRate;
}; };
class FXElement : public FXBase
{
DISALLOW_COPY_AND_ASSIGN(FXElement);
protected:
FXElement(float32_t sampling_rate);
public:
virtual ~FXElement();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) = 0;
};
class FX : public FXBase class FX : public FXBase
{ {
DISALLOW_COPY_AND_ASSIGN(FX); DISALLOW_COPY_AND_ASSIGN(FX);
protected: protected:
FX(float32_t sampling_rate); FX(float32_t sampling_rate);
virtual ~FX();
public: public:
virtual ~FX();
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) = 0; virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) = 0;
}; };

@ -0,0 +1,98 @@
#include "fx_orbitone.h"
#include <cmath>
OrbitoneParameter::OrbitoneParameter(float32_t sampling_rate, float32_t feedback) :
FXBase(sampling_rate),
feedback_(feedback)
{
}
OrbitoneParameter::~OrbitoneParameter()
{
}
void OrbitoneParameter::setFeedback(float32_t feedback)
{
this->feedback_ = constrain(feedback, 0.0f, 1.0f);
}
float32_t OrbitoneParameter::getFeedback() const
{
return this->feedback_;
}
// OrbitoneStage implementation
OrbitoneStage::OrbitoneStage(float32_t sampling_rate, OrbitoneParameter* params, float32_t frequency) :
FXElement(sampling_rate),
params_(params),
frequency_(frequency),
phase_(0.0f)
{
this->phase_increment_ = 2.0f * PI * frequency / this->getSamplingRate();
}
void OrbitoneStage::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
// Generate a sine wave using the stage's oscillator
float32_t osc = sin(this->phase_);
// Update the phase of the oscillator
this->phase_ += this->phase_increment_;
if(this->phase_ > 2.0f * PI) {
this->phase_ -= 2.0f * PI;
}
// Apply feedback to the stage's input
outL = inL + osc * this->params_->getFeedback();
outR = inR + osc * this->params_->getFeedback();
}
// Orbitone implementation
Orbitone::Orbitone(float32_t sampling_rate, float32_t feedback) :
FXElement(sampling_rate),
params_(sampling_rate, feedback)
{
for(unsigned i = 0; i < NUM_ORBITONR_STAGES; ++i)
{
float32_t frequency = 440.0 * pow(2.0f, (i - 1) / 12.0f); // Sets the frequency of each stage to be a multiple of 440 Hz
this->stages_[i] = new OrbitoneStage(sampling_rate, &this->params_, frequency);
}
}
Orbitone::~Orbitone()
{
for(unsigned i = 0; i < NUM_ORBITONR_STAGES; ++i)
{
delete this->stages_[i];
}
}
void Orbitone::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
// Process the input sample through each stage of the phaser
float32_t sampleL = inL;
float32_t sampleR = inR;
for(unsigned s = 0; s < NUM_ORBITONR_STAGES; ++s)
{
this->stages_[s]->processSample(sampleL, sampleR, sampleL, sampleR);
}
// Modulate the output of the phaser using the LFO
outL = sampleL;
outR = sampleR;
}
void Orbitone::setFeedback(float32_t feedback)
{
this->params_.setFeedback(feedback);
}
float32_t Orbitone::getFeedback() const
{
return this->params_.getFeedback();
}

@ -0,0 +1,75 @@
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// fx_orbitone.h
//
// Stereo Orbitone audio effects proposed in the context of the MiniDexed project
//
#pragma once
#include "fx.h"
class OrbitoneStage;
class OrbitoneParameter : public FXBase
{
friend class OrbitoneStage;
DISALLOW_COPY_AND_ASSIGN(OrbitoneParameter);
public:
OrbitoneParameter(float32_t sampling_rate, float32_t feedback = 0.5f);
virtual ~OrbitoneParameter();
void setFeedback(float32_t feedback);
inline float32_t getFeedback() const;
private:
float32_t feedback_; // Amount of feedback to apply to the stage's input
};
class OrbitoneStage : public FXElement
{
DISALLOW_COPY_AND_ASSIGN(OrbitoneStage);
public:
OrbitoneStage(float32_t sampling_rate, OrbitoneParameter* params, float32_t frequency);
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
private:
OrbitoneParameter* params_;
float32_t frequency_; // Frequency of the stage oscillator in Hz
float32_t phase_; // Phase of the stage's oscillator
float32_t phase_increment_; // Amount to increment the phase at each sample
};
#define NUM_ORBITONR_STAGES 4
class Orbitone : public FXElement
{
DISALLOW_COPY_AND_ASSIGN(Orbitone);
public:
Orbitone(float32_t sampling_rate, float32_t feedback = 0.5f);
virtual ~Orbitone();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setFeedback(float32_t feedback);
inline float32_t getFeedback() const;
private:
OrbitoneParameter params_;
OrbitoneStage* stages_[NUM_ORBITONR_STAGES];
};

@ -51,14 +51,14 @@ float32_t PhaserParameter::getQ() const
// PhaserStage implementation // PhaserStage implementation
PhaserStage::PhaserStage(float32_t sampling_rate, PhaserParameter* params) : PhaserStage::PhaserStage(float32_t sampling_rate, PhaserParameter* params) :
FXBase(sampling_rate), FXElement(sampling_rate),
params_(params) params_(params)
{ {
memset(this->z1, 0, 2 * sizeof(float32_t)); memset(this->z1, 0, 2 * sizeof(float32_t));
memset(this->z2, 0, 2 * sizeof(float32_t)); memset(this->z2, 0, 2 * sizeof(float32_t));
} }
void PhaserStage::process(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) void PhaserStage::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
outL = (this->params_->a0 * inL + this->params_->a1 * this->z1[0] + this->params_->a2 * this->z2[0]) / this->params_->a0; outL = (this->params_->a0 * inL + this->params_->a1 * this->z1[0] + this->params_->a2 * this->z2[0]) / this->params_->a0;
this->z2[0] = this->z1[0]; this->z2[0] = this->z1[0];
@ -73,7 +73,7 @@ void PhaserStage::process(float32_t inL, float32_t inR, float32_t& outL, float32
// Phaser implementation // Phaser implementation
Phaser::Phaser(float32_t sampling_rate, float32_t frequency, float32_t q) : Phaser::Phaser(float32_t sampling_rate, float32_t frequency, float32_t q) :
FX(sampling_rate), FXElement(sampling_rate),
params_(sampling_rate, frequency, q), params_(sampling_rate, frequency, q),
phase_(0.0f), phase_(0.0f),
phase_increment_(0.0f) phase_increment_(0.0f)
@ -93,37 +93,24 @@ Phaser::~Phaser()
} }
} }
void Phaser::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) void Phaser::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
float sampleL; // Process the input sample through each stage of the phaser
float sampleR; float32_t sampleL = inL;
for(unsigned i = 0; i < nSamples; ++i) float32_t sampleR = inR;
for(unsigned s = 0; s < NUM_PHASER_STAGES; ++s)
{ {
// Process the input sample through each stage of the phaser this->stages_[s]->processSample(sampleL, sampleR, sampleL, sampleR);
sampleL = *left_input; }
sampleR = *right_input;
for(unsigned s = 0; s < NUM_PHASER_STAGES; ++s) // Modulate the output of the phaser using the LFO
{ outL = sampleL * (0.5f + 0.5f * cos(this->phase_));
this->stages_[s]->process(sampleL, sampleR, sampleL, sampleR); outR = sampleR * (0.5f + 0.5f * cos(this->phase_));;
}
// Update the phase of the LFO
// Modulate the output of the phaser using the LFO this->phase_ += this->phase_increment_;
*left_output = sampleL * (0.5f + 0.5f * cos(this->phase_)); if(this->phase_ > 2.0f * PI) {
*right_output = sampleR * (0.5f + 0.5f * cos(this->phase_));; this->phase_ -= 2.0 * PI;
// Update the phase of the LFO
this->phase_ += this->phase_increment_;
if(this->phase_ > 2.0f * PI) {
this->phase_ -= 2.0 * PI;
}
// Move to next input sample
++left_input;
++right_input;
// Move to next output sample
++left_output;
++right_output;
} }
} }

@ -46,14 +46,14 @@ private:
float32_t a0, a1, a2, b1, b2; // Coefficients for the stage's filter float32_t a0, a1, a2, b1, b2; // Coefficients for the stage's filter
}; };
class PhaserStage : public FXBase class PhaserStage : public FXElement
{ {
DISALLOW_COPY_AND_ASSIGN(PhaserStage); DISALLOW_COPY_AND_ASSIGN(PhaserStage);
public: public:
PhaserStage(float32_t sampling_rate, PhaserParameter* params); PhaserStage(float32_t sampling_rate, PhaserParameter* params);
void process(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR); virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
private: private:
PhaserParameter* params_; // All paremters of the phaser including the inner coefficients PhaserParameter* params_; // All paremters of the phaser including the inner coefficients
@ -62,7 +62,7 @@ private:
#define NUM_PHASER_STAGES 6 #define NUM_PHASER_STAGES 6
class Phaser : public FX class Phaser : public FXElement
{ {
DISALLOW_COPY_AND_ASSIGN(Phaser); DISALLOW_COPY_AND_ASSIGN(Phaser);
@ -70,7 +70,7 @@ public:
Phaser(float32_t sampling_rate, float32_t frequency = 0.5f, float32_t q = 1.0f); Phaser(float32_t sampling_rate, float32_t frequency = 0.5f, float32_t q = 1.0f);
virtual ~Phaser(); virtual ~Phaser();
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setFrequency(float32_t frequency); void setFrequency(float32_t frequency);
inline float32_t getFrequency() const; inline float32_t getFrequency() const;

@ -1,7 +1,7 @@
#include "fx_rack.h" #include "fx_rack.h"
FXUnit::FXUnit(float32_t sampling_rate, FX& fx, float32_t wet_level) : FXUnit::FXUnit(float32_t sampling_rate, FXElement& fx, float32_t wet_level) :
FX(sampling_rate), FXElement(sampling_rate),
fx_(fx) fx_(fx)
{ {
this->setWetLevel(wet_level); this->setWetLevel(wet_level);
@ -11,24 +11,13 @@ FXUnit::~FXUnit()
{ {
} }
void FXUnit::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) void FXUnit::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
this->fx_.process(left_input, right_input, left_output, right_output, nSamples); this->fx_.processSample(inL, inR, outL, outR);
for(unsigned i = 0; i < nSamples; ++i) // Mix wet and dry signals
{ outL = this->getWetLevel() * outL + (1.0f - this->getWetLevel()) * inL;
// Mix wet and dry signals outR = this->getWetLevel() * outR + (1.0f - this->getWetLevel()) * inR;
*left_output = this->getWetLevel() * *left_output + (1.0f - this->getWetLevel()) * *left_input;
*right_output = this->getWetLevel() * *right_output + (1.0f - this->getWetLevel()) * *left_input;
// Move to next input sample
++left_input;
++right_input;
// Move to next output sample
++left_output;
++right_output;
}
} }
void FXUnit::setWetLevel(float32_t wet_level) void FXUnit::setWetLevel(float32_t wet_level)
@ -61,16 +50,40 @@ FXRack::~FXRack()
void FXRack::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) void FXRack::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples)
{ {
for(FXChain::iterator it = this->fx_chain_.begin(); it != this->fx_chain_.end(); it++) float32_t sampleInL;
float32_t sampleInR;
float32_t sampleOutL;
float32_t sampleOutR;
for(unsigned i = 0; i < nSamples; ++i)
{ {
(*it)->process(left_input, right_input, left_output, right_output, nSamples); sampleInL = *left_input;
sampleInR = *right_input;
sampleOutL = 0.0f;
sampleOutR = 0.0f;
for(FXChain::iterator it = this->fx_chain_.begin(); it != this->fx_chain_.end(); it++)
{
(*it)->processSample(sampleInL, sampleInR, sampleOutL, sampleOutR);
sampleInL = sampleOutL;
sampleInR = sampleOutR;
}
left_input = left_output; *left_output = sampleOutL;
right_input = right_output; *right_output = sampleOutR;
// Move inputs by 1 sample
++left_input;
++right_input;
// Move outputs by 1 sample
++left_input;
++right_input;
} }
} }
void FXRack::registerFX(FX* fx) void FXRack::registerFX(FXElement* fx)
{ {
this->fx_chain_.push_back(new FXUnit(this->getSamplingRate(), *fx)); this->fx_chain_.push_back(new FXUnit(this->getSamplingRate(), *fx));
} }

@ -26,21 +26,21 @@
#include <vector> #include <vector>
class FXUnit : public FX class FXUnit : public FXElement
{ {
DISALLOW_COPY_AND_ASSIGN(FXUnit); DISALLOW_COPY_AND_ASSIGN(FXUnit);
public: public:
FXUnit(float32_t sampling_rate, FX& fx, float32_t wet_level = 0.5f); FXUnit(float32_t sampling_rate, FXElement& fx, float32_t wet_level = 0.5f);
virtual ~FXUnit(); virtual ~FXUnit();
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setWetLevel(float32_t wet_level); void setWetLevel(float32_t wet_level);
inline float32_t getWetLevel() const; inline float32_t getWetLevel() const;
private: private:
FX& fx_; // Embedded FX FXElement& fx_; // Embedded FX
float32_t wet_level_; // How much the signal is affected by the inner FX (0.0 - 1.0) float32_t wet_level_; // How much the signal is affected by the inner FX (0.0 - 1.0)
}; };
@ -57,7 +57,7 @@ public:
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override;
private: private:
void registerFX(FX* fx); void registerFX(FXElement* fx);
FXChain fx_chain_; FXChain fx_chain_;
}; };

@ -8,7 +8,7 @@ ShimmerReverb::ShimmerReverb(float32_t sampling_rate,
float32_t right_delay_time, float32_t right_delay_time,
float32_t shimmer_frequency, float32_t shimmer_frequency,
float32_t shimmer_amplitude, float32_t shimmer_amplitude,
float32_t decay_time) : FX(sampling_rate), float32_t decay_time) : FXElement(sampling_rate),
DelayLineLength(static_cast<unsigned>(SHIMMER_MAX_DELAY_TIME * sampling_rate)), DelayLineLength(static_cast<unsigned>(SHIMMER_MAX_DELAY_TIME * sampling_rate)),
write_pos_L_(0), write_pos_L_(0),
write_pos_R_(0), write_pos_R_(0),
@ -33,53 +33,42 @@ ShimmerReverb::~ShimmerReverb()
delete[] this->delay_line_R_; delete[] this->delay_line_R_;
} }
void ShimmerReverb::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) void ShimmerReverb::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
for(unsigned i = 0; i < nSamples; ++i) // Calculate shimmer offset based on current phase
{ float32_t shimmerOffsetL = this->getShimmerAmplitude() * sin(this->shimmer_phase_ * 2.0f * PI);
// Calculate shimmer offset based on current phase float32_t shimmerOffsetR = this->getShimmerAmplitude() * cos(this->shimmer_phase_ * 2.0f * PI);
float32_t shimmerOffsetL = this->getShimmerAmplitude() * sin(this->shimmer_phase_ * 2.0f * PI);
float32_t shimmerOffsetR = this->getShimmerAmplitude() * cos(this->shimmer_phase_ * 2.0f * PI); // Calculate read position for left and right channel delay lines
int readPosL = this->write_pos_L_ - (int)(this->delay_time_L_ * this->getSamplingRate()) - (int)(shimmerOffsetL * this->getSamplingRate());
// Calculate read position for left and right channel delay lines int readPosR = this->write_pos_R_ - (int)(this->delay_time_R_ * this->getSamplingRate()) - (int)(shimmerOffsetR * this->getSamplingRate());
int readPosL = this->write_pos_L_ - (int)(this->delay_time_L_ * this->getSamplingRate()) - (int)(shimmerOffsetL * this->getSamplingRate());
int readPosR = this->write_pos_R_ - (int)(this->delay_time_R_ * this->getSamplingRate()) - (int)(shimmerOffsetR * this->getSamplingRate()); // Wrap read position around the end of the delay line if necessary
if(readPosL < 0) readPosL += this->DelayLineLength;
// Wrap read position around the end of the delay line if necessary if(readPosR < 0) readPosR += this->DelayLineLength;
if(readPosL < 0) readPosL += this->DelayLineLength;
if(readPosR < 0) readPosR += this->DelayLineLength; // Read32_t left and right channel delay line samples
float32_t delaySampleL = this->delay_line_L_[readPosL];
// Read32_t left and right channel delay line samples float32_t delaySampleR = this->delay_line_R_[readPosR];
float32_t delaySampleL = this->delay_line_L_[readPosL];
float32_t delaySampleR = this->delay_line_R_[readPosR]; // Calculate reverb decay factor
float32_t decay = std::pow(0.001f, 1.0f / (this->decay_time_ * this->getSamplingRate()));
// Calculate reverb decay factor
float32_t decay = std::pow(0.001f, 1.0f / (this->decay_time_ * this->getSamplingRate())); // Calculate output samples
outL = inL + delaySampleL * decay;
// Calculate output samples outR = inR + delaySampleR * decay;
*left_output = *left_input + delaySampleL * decay;
*right_output = *right_input + delaySampleR * decay; // Write input samples to delay lines
this->delay_line_L_[this->write_pos_L_] = outL;
// Write input samples to delay lines this->delay_line_R_[this->write_pos_R_] = outR;
this->delay_line_L_[this->write_pos_L_] = *left_input;
this->delay_line_R_[this->write_pos_R_] = *right_input; // Increment write position and wrap around the end of the delay line if necessary
this->write_pos_L_ = (this->write_pos_L_ + 1) % this->DelayLineLength;
// Increment write position and wrap around the end of the delay line if necessary this->write_pos_R_ = (this->write_pos_R_ + 1) % this->DelayLineLength;
this->write_pos_L_ = (this->write_pos_L_ + 1) % this->DelayLineLength;
this->write_pos_R_ = (this->write_pos_R_ + 1) % this->DelayLineLength; // Increment shimmer phase
this->shimmer_phase_ += this->getShimmerFrequency() / this->getSamplingRate();
// Increment shimmer phase if(this->shimmer_phase_ > 1.0f) this->shimmer_phase_ -= 1.0f;
this->shimmer_phase_ += this->getShimmerFrequency() / this->getSamplingRate();
if(this->shimmer_phase_ > 1.0f) this->shimmer_phase_ -= 1.0f;
// Move to next input sample
++left_input;
++right_input;
// Move to next output sample
++left_output;
++right_output;
}
} }
void ShimmerReverb::setLeftDelayTime(float32_t delay_time_L) void ShimmerReverb::setLeftDelayTime(float32_t delay_time_L)

@ -23,7 +23,7 @@
#define SHIMMER_MAX_DELAY_TIME 2.0f #define SHIMMER_MAX_DELAY_TIME 2.0f
class ShimmerReverb : public FX class ShimmerReverb : public FXElement
{ {
DISALLOW_COPY_AND_ASSIGN(ShimmerReverb); DISALLOW_COPY_AND_ASSIGN(ShimmerReverb);
@ -37,7 +37,7 @@ public:
virtual ~ShimmerReverb(); virtual ~ShimmerReverb();
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setLeftDelayTime(float32_t delay_time_L); void setLeftDelayTime(float32_t delay_time_L);
inline float32_t getLeftDelayTime() const; inline float32_t getLeftDelayTime() const;

@ -4,7 +4,7 @@
#include <algorithm> #include <algorithm>
TapeDelay::TapeDelay(const float32_t sampling_rate, float32_t default_delay_time, float32_t default_flutter_level, float32_t default_feedback_level) : TapeDelay::TapeDelay(const float32_t sampling_rate, float32_t default_delay_time, float32_t default_flutter_level, float32_t default_feedback_level) :
FX(sampling_rate), FXElement(sampling_rate),
MaxSampleDelayTime(sampling_rate * MAX_DELAY_TIME), MaxSampleDelayTime(sampling_rate * MAX_DELAY_TIME),
left_read_pos_(0), left_read_pos_(0),
right_read_pos_(0) right_read_pos_(0)
@ -23,55 +23,44 @@ TapeDelay::~TapeDelay()
delete[] this->right_buffer_; delete[] this->right_buffer_;
} }
void TapeDelay::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) void TapeDelay::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
for(size_t i = 0; i < nSamples; ++i) // calculate the fluttered delay time
float32_t fluttered_delay_time = this->getDelayTime() + this->getFlutteredDelayTime();
// Calculate write positions
int left_write_pos = this->left_read_pos_ - static_cast<int>(fluttered_delay_time);
while(left_write_pos < 0)
{
left_write_pos += this->MaxSampleDelayTime;
}
int right_write_pos = this->right_read_pos_ - static_cast<int>(fluttered_delay_time);
while(right_write_pos < 0)
{
right_write_pos += this->MaxSampleDelayTime;
}
// Write input to delay buffers
this->left_buffer_[left_write_pos] = inL;
this->right_buffer_[right_write_pos] = inR;
// Read from delay buffers and apply feedback
outL = this->left_buffer_[this->left_read_pos_];
outR = this->right_buffer_[this->right_read_pos_];
this->left_buffer_[left_write_pos] += outL * this->getFeedbackLevel();
this->right_buffer_[right_write_pos] += outR * this->getFeedbackLevel();
// Increment read positions
++this->left_read_pos_;
if(this->left_read_pos_ >= this->MaxSampleDelayTime)
{
this->left_read_pos_ -= this->MaxSampleDelayTime;
}
++this->right_read_pos_;
if(this->right_read_pos_ >= this->MaxSampleDelayTime)
{ {
// calculate the fluttered delay time this->right_read_pos_ -= this->MaxSampleDelayTime;
float32_t fluttered_delay_time = this->getDelayTime() + this->getFlutteredDelayTime();
// Calculate write positions
int left_write_pos = this->left_read_pos_ - static_cast<int>(fluttered_delay_time);
while(left_write_pos < 0)
{
left_write_pos += this->MaxSampleDelayTime;
}
int right_write_pos = this->right_read_pos_ - static_cast<int>(fluttered_delay_time);
while(right_write_pos < 0)
{
right_write_pos += this->MaxSampleDelayTime;
}
// Write input to delay buffers
this->left_buffer_[left_write_pos] = *left_input;
this->right_buffer_[right_write_pos] = *right_input;
// Read from delay buffers and apply feedback
*left_output = this->left_buffer_[this->left_read_pos_];
*right_output = this->right_buffer_[this->right_read_pos_];
this->left_buffer_[left_write_pos] += *left_output * this->getFeedbackLevel();
this->right_buffer_[right_write_pos] += *right_output * this->getFeedbackLevel();
// Increment read positions
++this->left_read_pos_;
if(this->left_read_pos_ >= this->MaxSampleDelayTime)
{
this->left_read_pos_ -= this->MaxSampleDelayTime;
}
++this->right_read_pos_;
if(this->right_read_pos_ >= this->MaxSampleDelayTime)
{
this->right_read_pos_ -= this->MaxSampleDelayTime;
}
// Move to next input sample
++left_input;
++right_input;
// Move to next output sample
++left_output;
++right_output;
} }
} }

@ -25,7 +25,7 @@
#define MAX_DELAY_TIME 2 #define MAX_DELAY_TIME 2
class TapeDelay : public FX class TapeDelay : public FXElement
{ {
DISALLOW_COPY_AND_ASSIGN(TapeDelay); DISALLOW_COPY_AND_ASSIGN(TapeDelay);
@ -33,7 +33,7 @@ public:
TapeDelay(const float32_t sampling_rate, float32_t default_delay_time = 0.25f, float32_t default_flutter_level = 0.05f, float32_t default_wet_level = 0.5f); TapeDelay(const float32_t sampling_rate, float32_t default_delay_time = 0.25f, float32_t default_flutter_level = 0.05f, float32_t default_wet_level = 0.5f);
virtual ~TapeDelay(); virtual ~TapeDelay();
virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setDelayTime(float32_t delay_time); void setDelayTime(float32_t delay_time);
inline float32_t getDelayTime() const; inline float32_t getDelayTime() const;

Loading…
Cancel
Save