Fixing the Shimmer Reverb

pull/409/head
abscisys 2 years ago
parent 17030e8065
commit 6da53dcac5
  1. 3
      .gitignore
  2. 2
      src/Makefile
  3. 1
      src/fx.cpp
  4. 18
      src/fx_components.cpp
  5. 3
      src/fx_components.h
  6. 307
      src/fx_engine.hpp
  7. 4
      src/fx_rack.cpp
  8. 6
      src/fx_rack.h
  9. 193
      src/fx_shimmer_reverb.cpp
  10. 55
      src/fx_shimmer_reverb.h
  11. 116
      src/fx_shimmer_reverb2.cpp
  12. 67
      src/fx_shimmer_reverb2.h
  13. 5
      src/fx_svf.cpp
  14. 29
      src/minidexed.cpp
  15. 5
      src/minidexed.h
  16. 9
      src/performance.ini
  17. 36
      src/performanceconfig.cpp
  18. 15
      src/performanceconfig.h
  19. 21
      src/test/Makefile
  20. 199
      src/test/fxrack_test.cpp
  21. 10
      src/test/wave.h
  22. 60
      src/test/wavein.cpp
  23. 1
      src/test/waveout.cpp
  24. 10
      src/uimenu.cpp

3
.gitignore vendored

@ -48,4 +48,5 @@ sdcard
.vscode/
# temporary tests
src/test/fxrack_test
src/test/fxrack_test
src/test/result.wav

@ -12,7 +12,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \
effect_compressor.o effect_platervbstereo.o \
fx.o fx_components.o \
fx_svf.o fx_tube.o fx_chorus.o fx_flanger.o fx_orbitone.o fx_phaser.o \
fx_tape_delay.o fx_shimmer_reverb2.o fx_rack.o \
fx_tape_delay.o fx_shimmer_reverb.o fx_rack.o \
uibuttons.o midipin.o
OPTIMIZE = -O3

@ -23,6 +23,7 @@ FXElement::~FXElement()
{
}
FX::FX(float32_t sampling_rate) :
FXBase(sampling_rate)
{

@ -15,8 +15,12 @@ LFO::LFO(float32_t sampling_rate, Waveform waveform, float32_t min_frequency, fl
FXBase(sampling_rate),
min_frequency_(min_frequency),
max_frequency_(max_frequency),
waveform_(waveform),
normalized_frequency_(-1.0f),
frequency_(0.0f),
phase_(0.0f),
last_sample_(0.0f),
phase_increment_(0.0f),
current_sample_(0.0f),
new_phase_(true),
rnd_generator_(rnd_device_()),
rnd_distribution_(-1.0f, 1.0f)
@ -94,7 +98,7 @@ float32_t LFO::process()
}
else
{
out = this->last_sample_;
out = this->current_sample_;
}
break;
case Waveform::Noise:
@ -102,7 +106,7 @@ float32_t LFO::process()
break;
}
this->last_sample_ = out;
this->current_sample_ = out;
this->phase_ += this->phase_increment_;
if(this->phase_ >= Constants::M2PI)
@ -118,6 +122,12 @@ float32_t LFO::process()
return out;
}
float32_t LFO::current() const
{
return this->current_sample_;
}
////////////////////////////////////
// JitterGenerator implementation //
////////////////////////////////////
@ -125,6 +135,8 @@ JitterGenerator::JitterGenerator(float32_t sampling_rate) :
FXBase(sampling_rate),
rnd_generator_(rnd_device_()),
rnd_distribution_(-1.0f, 1.0f),
speed_(-1.0f),
magnitude_(-1.0f),
phase_(0.0f),
phase_increment_(0.0f)
{

@ -54,6 +54,7 @@ public:
float32_t getFrequency() const;
float32_t process();
float32_t current() const;
private:
const float32_t min_frequency_;
@ -63,7 +64,7 @@ private:
float32_t frequency_;
float32_t phase_;
float32_t phase_increment_;
float32_t last_sample_;
float32_t current_sample_;
bool new_phase_;
std::random_device rnd_device_;
std::mt19937 rnd_generator_;

@ -0,0 +1,307 @@
#pragma once
#include "fx_components.h"
#include <algorithm>
#include <climits>
#include <cassert>
#define MAKE_INTEGRAL_FRACTIONAL(x) \
int32_t x ## _integral = static_cast<int32_t>(x); \
float x ## _fractional = x - static_cast<float>(x ## _integral);
enum Format
{
FORMAT_12_BIT,
FORMAT_16_BIT,
FORMAT_32_BIT
};
enum LFOIndex
{
LFO_1,
LFO_2
};
template <Format format>
struct DataType
{
};
inline int16_t clip16(int32_t x)
{
if(x > INT16_MAX)
{
return INT16_MAX;
}
if(x < INT16_MIN)
{
return INT16_MIN;
}
return static_cast<int16_t>(x);
}
template <>
struct DataType<FORMAT_16_BIT>
{
typedef uint16_t T;
static inline float32_t decompress(T value)
{
return static_cast<float>(static_cast<int16_t>(value)) / 4096.0f;
}
static inline T compress(float32_t value)
{
return clip16(static_cast<int32_t>(value * 4096.0f));
}
};
template <
size_t size,
Format format = FORMAT_16_BIT>
class FxEngine : public FXBase
{
DISALLOW_COPY_AND_ASSIGN(FxEngine);
public:
typedef typename DataType<format>::T T;
FxEngine(float32_t sampling_rate) :
FXBase(sampling_rate)
{
this->buffer_ = new uint16_t[size];
this->lfo_[LFO_1] = new LFO(sampling_rate, LFO::Waveform::Sine, 0.0f, 32.0f);
this->lfo_[LFO_2] = new LFO(sampling_rate, LFO::Waveform::Sine, 0.0f, 32.0f);
this->clear();
}
~FxEngine()
{
delete[] this->buffer_;
delete this->lfo_[LFO_1];
delete this->lfo_[LFO_2];
}
void clear()
{
memset(this->buffer_, 0, size * sizeof(uint16_t));
this->write_ptr_ = 0;
}
struct Empty
{
};
template <int32_t l, typename T = Empty>
struct Reserve
{
typedef T Tail;
enum
{
length = l
};
};
template <typename Memory, int32_t index>
struct DelayLine
{
enum
{
length = DelayLine<typename Memory::Tail, index - 1>::length,
base = DelayLine<Memory, index - 1>::base + DelayLine<Memory, index - 1>::length + 1
};
};
template <typename Memory>
struct DelayLine<Memory, 0>
{
enum
{
length = Memory::length,
base = 0
};
};
class Context
{
DISALLOW_COPY_AND_ASSIGN(Context);
friend class FxEngine;
public:
Context() :
accumulator_(0.0f),
previous_read_(0.0f),
buffer_(nullptr),
write_ptr_(0)
{
memset(this->lfo_value_, 0, 2 * sizeof(float32_t));
}
~Context()
{
}
inline void load(float32_t value)
{
this->accumulator_ = value;
}
inline void read(float32_t value, float32_t scale)
{
this->accumulator_ += value * scale;
}
inline void read(float32_t value)
{
this->accumulator_ += value;
}
inline void write(float32_t &value)
{
value = this->accumulator_;
}
inline void write(float32_t &value, float32_t scale)
{
value = this->accumulator_;
this->accumulator_ *= scale;
}
template <typename D>
inline void write(D &d, int32_t offset, float32_t scale)
{
assert(D::base + D::length <= size);
T w = DataType<format>::compress(this->accumulator_);
if(offset == -1)
{
this->buffer_[(this->write_ptr_ + D::base + D::length - 1) & MASK] = w;
}
else
{
this->buffer_[(this->write_ptr_ + D::base + offset) & MASK] = w;
}
this->accumulator_ *= scale;
}
template <typename D>
inline void write(D &d, float32_t scale)
{
this->write(d, 0, scale);
}
template <typename D>
inline void writeAllPass(D &d, int32_t offset, float32_t scale)
{
this->write(d, offset, scale);
this->accumulator_ += this->previous_read_;
}
template <typename D>
inline void writeAllPass(D &d, float32_t scale)
{
this->writeAllPass(d, 0, scale);
}
template <typename D>
inline void read(D &d, int32_t offset, float32_t scale)
{
assert(D::base + D::length <= size);
T r;
if(offset == -1)
{
r = this->buffer_[(this->write_ptr_ + D::base + D::length - 1) & MASK];
}
else
{
r = this->buffer_[(this->write_ptr_ + D::base + offset) & MASK];
}
float32_t r_f = DataType<format>::decompress(r);
this->previous_read_ = r_f;
this->accumulator_ += r_f * scale;
}
template <typename D>
inline void read(D &d, float32_t scale)
{
this->read(d, 0, scale);
}
inline void lp(float32_t &state, float32_t coefficient)
{
state += coefficient * (this->accumulator_ - state);
this->accumulator_ = state;
}
inline void hp(float32_t &state, float32_t coefficient)
{
state += coefficient * (this->accumulator_ - state);
this->accumulator_ -= state;
}
template <typename D>
inline void interpolate(D &d, float32_t offset, float32_t scale)
{
assert(D::base + D::length <= size);
MAKE_INTEGRAL_FRACTIONAL(offset);
float32_t a = DataType<format>::decompress(this->buffer_[(this->write_ptr_ + offset_integral + D::base) & MASK]);
float32_t b = DataType<format>::decompress(this->buffer_[(this->write_ptr_ + offset_integral + D::base + 1) & MASK]);
float32_t x = a + (b - a) * offset_fractional;
this->previous_read_ = x;
this->accumulator_ += x * scale;
}
template <typename D>
inline void interpolate(D &d, float32_t offset, LFOIndex index, float32_t amplitude, float32_t scale)
{
assert(D::base + D::length <= size);
offset += amplitude * lfo_value_[index];
MAKE_INTEGRAL_FRACTIONAL(offset);
float32_t a = DataType<format>::decompress(this->buffer_[(this->write_ptr_ + offset_integral + D::base) & MASK]);
float32_t b = DataType<format>::decompress(this->buffer_[(this->write_ptr_ + offset_integral + D::base + 1) & MASK]);
float32_t x = a + (b - a) * offset_fractional;
this->previous_read_ = x;
this->accumulator_ += x * scale;
}
private:
float32_t accumulator_;
float32_t previous_read_;
float32_t lfo_value_[2];
T* buffer_;
int32_t write_ptr_;
};
inline void setLFOFrequency(LFOIndex index, float32_t frequency)
{
this->lfo_[index]->setFrequency(frequency);
}
inline void start(Context *c)
{
--this->write_ptr_;
if(this->write_ptr_ < 0)
{
this->write_ptr_ += size;
}
c->accumulator_ = 0.0f;
c->previous_read_ = 0.0f;
c->buffer_ = buffer_;
c->write_ptr_ = write_ptr_;
c->lfo_value_[LFO_1] = this->lfo_[LFO_1]->process();
c->lfo_value_[LFO_2] = this->lfo_[LFO_2]->process();
}
private:
enum
{
MASK = size - 1
};
uint16_t* buffer_;
unsigned write_ptr_;
LFO* lfo_[2];
};

@ -15,7 +15,7 @@ FXRack::FXRack(float32_t sampling_rate, bool enable, float32_t wet) :
this->fxOrbitone_ = new FXUnit<Orbitone>(sampling_rate);
this->fxPhaser_ = new FXUnit<Phaser>(sampling_rate);
this->fxTapeDelay_ = new FXUnit<TapeDelay>(sampling_rate);
this->fxShimmerReverb_ = new ShimmerReverb2(sampling_rate);
this->fxShimmerReverb_ = new FXUnit<ShimmerReverb>(sampling_rate);
this->registerFX(this->fxTube_);
this->registerFX(this->fxChorus_);
@ -144,7 +144,7 @@ FXUnit<TapeDelay>* FXRack::getTapeDelay()
return this->fxTapeDelay_;
}
ShimmerReverb2* FXRack::getShimmerReverb()
FXUnit<ShimmerReverb>* FXRack::getShimmerReverb()
{
return this->fxShimmerReverb_;
}

@ -26,7 +26,7 @@
#include "fx_orbitone.h"
#include "fx_phaser.h"
#include "fx_tape_delay.h"
#include "fx_shimmer_reverb2.h"
#include "fx_shimmer_reverb.h"
#include <vector>
@ -55,7 +55,7 @@ public:
FXUnit<Orbitone>* getOrbitone();
FXUnit<Phaser>* getPhaser();
FXUnit<TapeDelay>* getTapeDelay();
ShimmerReverb2* getShimmerReverb();
FXUnit<ShimmerReverb>* getShimmerReverb();
private:
void registerFX(FXElement* fx);
@ -70,5 +70,5 @@ private:
FXUnit<Orbitone>* fxOrbitone_;
FXUnit<Phaser>* fxPhaser_;
FXUnit<TapeDelay>* fxTapeDelay_;
ShimmerReverb2* fxShimmerReverb_;
FXUnit<ShimmerReverb>* fxShimmerReverb_;
};

@ -3,124 +3,147 @@
#include <cmath>
#include <algorithm>
#define SHIMMER_MAX_DELAY_TIME 2.0f
ShimmerReverb::ShimmerReverb(float32_t sampling_rate,
float32_t left_delay_time,
float32_t right_delay_time,
float32_t shimmer_frequency,
float32_t shimmer_amplitude,
float32_t decay_time) : FXElement(sampling_rate),
DelayLineLength(static_cast<unsigned>(2.0f * SHIMMER_MAX_DELAY_TIME * sampling_rate)),
write_pos_L_(0),
write_pos_R_(0),
shimmer_phase_(0.0f)
{
this->delay_line_L_ = new float32_t[this->DelayLineLength];
this->delay_line_R_ = new float32_t[this->DelayLineLength];
#define TAIL , -1
memset(this->delay_line_L_, 0, this->DelayLineLength * sizeof(float32_t));
memset(this->delay_line_R_, 0, this->DelayLineLength * sizeof(float32_t));
this->setLeftDelayTime(left_delay_time);
this->setRightDelayTime(right_delay_time);
this->setShimmerFrequency(shimmer_frequency);
this->setShimmerAmplitude(shimmer_amplitude);
this->setDecayTime(decay_time);
ShimmerReverb::ShimmerReverb(float32_t sampling_rate) :
FXElement(sampling_rate),
engine_(sampling_rate)
{
this->engine_.setLFOFrequency(LFO_1, 0.5f / sampling_rate);
this->engine_.setLFOFrequency(LFO_2, 0.3f / sampling_rate);
this->setInputGain(1.0f);
this->setLP(0.7f);
this->setDiffusion(0.625f);
}
ShimmerReverb::~ShimmerReverb()
{
delete[] this->delay_line_L_;
delete[] this->delay_line_R_;
}
void ShimmerReverb::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
const static float32_t M2PI = 2.0f * PI;
// Calculate shimmer offset based on current phase
float32_t shimmerOffsetL = this->getShimmerAmplitude() * sin(this->shimmer_phase_);
float32_t shimmerOffsetR = this->getShimmerAmplitude() * cos(this->shimmer_phase_);
// Calculate read position for left and right channel delay lines
unsigned readPosL = static_cast<unsigned>(this->DelayLineLength + this->write_pos_L_ - (this->delay_time_L_ + shimmerOffsetL) * this->getSamplingRate()) % this->DelayLineLength;
unsigned readPosR = static_cast<unsigned>(this->DelayLineLength + this->write_pos_R_ - (this->delay_time_R_ + shimmerOffsetR) * this->getSamplingRate()) % this->DelayLineLength;
// Read32_t left and right channel delay line samples
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 output samples
outL = inL + delaySampleL * decay;
outR = inR + delaySampleR * decay;
// This is the Griesinger topology described in the Dattorro paper
// (4 AP diffusers on the input, then a loop of 2x 2AP+1Delay).
// Modulation is applied in the loop of the first diffuser AP for additional
// smearing; and to the two long delays for a slow shimmer/chorus effect.
typedef Engine::Reserve<113,
Engine::Reserve<162,
Engine::Reserve<241,
Engine::Reserve<399,
Engine::Reserve<1653,
Engine::Reserve<2038,
Engine::Reserve<3411,
Engine::Reserve<1913,
Engine::Reserve<1663,
Engine::Reserve<4782> > > > > > > > > > Memory;
Engine::DelayLine<Memory, 0> ap1;
Engine::DelayLine<Memory, 1> ap2;
Engine::DelayLine<Memory, 2> ap3;
Engine::DelayLine<Memory, 3> ap4;
Engine::DelayLine<Memory, 4> dap1a;
Engine::DelayLine<Memory, 5> dap1b;
Engine::DelayLine<Memory, 6> del1;
Engine::DelayLine<Memory, 7> dap2a;
Engine::DelayLine<Memory, 8> dap2b;
Engine::DelayLine<Memory, 9> del2;
Engine::Context c;
const float32_t kap = this->diffusion_;
const float32_t klp = this->lp_;
const float32_t krt = this->reverb_time_;
const float32_t gain = this->input_gain_;
float32_t lp_1 = this->lp_decay_1_;
float32_t lp_2 = this->lp_decay_2_;
float32_t wet;
float32_t apout = 0.0f;
engine_.start(&c);
// Write input samples to delay lines
this->delay_line_L_[this->write_pos_L_] = outL;
this->delay_line_R_[this->write_pos_R_] = outR;
// 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;
this->write_pos_R_ = (this->write_pos_R_ + 1) % this->DelayLineLength;
// Increment shimmer phase
this->shimmer_phase_ += this->shimmer_phase_increment_;
if(this->shimmer_phase_ > M2PI)
{
this->shimmer_phase_ -= M2PI;
}
}
void ShimmerReverb::setLeftDelayTime(float32_t delay_time_L)
{
this->delay_time_L_ = constrain(delay_time_L, 0.0f, 1.0f);
}
float32_t ShimmerReverb::getLeftDelayTime() const
{
return this->delay_time_L_;
// Smear AP1 inside the loop.
c.interpolate(ap1, 10.0f, LFO_1, 60.0f, 1.0f);
c.write(ap1, 100, 0.0f);
c.read(inL + inR, gain);
// Diffuse through 4 allpasses.
c.read(ap1 TAIL, kap);
c.writeAllPass(ap1, -kap);
c.read(ap2 TAIL, kap);
c.writeAllPass(ap2, -kap);
c.read(ap3 TAIL, kap);
c.writeAllPass(ap3, -kap);
c.read(ap4 TAIL, kap);
c.writeAllPass(ap4, -kap);
c.write(apout);
// Main reverb loop.
c.load(apout);
c.interpolate(del2, 4680.0f, LFO_2, 100.0f, krt);
c.lp(lp_1, klp);
c.read(dap1a TAIL, -kap);
c.writeAllPass(dap1a, kap);
c.read(dap1b TAIL, kap);
c.writeAllPass(dap1b, -kap);
c.write(del1, 2.0f);
c.write(wet, 0.0f);
outR += wet;
c.load(apout);
// c.Interpolate(del1, 4450.0f, LFO_1, 50.0f, krt);
c.read(del1 TAIL, krt);
c.lp(lp_2, klp);
c.read(dap2a TAIL, kap);
c.writeAllPass(dap2a, -kap);
c.read(dap2b TAIL, -kap);
c.writeAllPass(dap2b, kap);
c.write(del2, 2.0f);
c.write(wet, 0.0f);
outR += wet;
this->lp_decay_1_ = lp_1;
this->lp_decay_2_ = lp_2;
}
void ShimmerReverb::setRightDelayTime(float32_t delay_time_R)
void ShimmerReverb::setInputGain(float32_t gain)
{
this->delay_time_R_ = constrain(delay_time_R, 0.0f, 1.0f);
this->input_gain_ = constrain(gain, 0.0f, 1.0f);
}
float32_t ShimmerReverb::getRightDelayTime() const
float32_t ShimmerReverb::getInputGain() const
{
return this->delay_time_R_;
return this->input_gain_;
}
void ShimmerReverb::setShimmerFrequency(float32_t frequency)
void ShimmerReverb::setTime(float32_t time)
{
this->shimmer_frequency_ = constrain(frequency, 0.0f, 1.0f);
this->shimmer_phase_increment_ = Constants::M2PI * mapfloat(this->shimmer_frequency_, 0.0f, 1.0f, 20.0f, 20000.0f) / this->getSamplingRate();
this->reverb_time_ = constrain(time, 0.0f, 1.0f);
}
float32_t ShimmerReverb::getShimmerFrequency() const
float32_t ShimmerReverb::getTime() const
{
return this->shimmer_frequency_;
return this->reverb_time_;
}
void ShimmerReverb::setShimmerAmplitude(float32_t amplitude)
void ShimmerReverb::setDiffusion(float32_t diffusion)
{
this->shimmer_amplitude_ = constrain(amplitude, 0.0f, 1.0f);
this->diffusion_ = constrain(diffusion, 0.0f, 1.0f);
}
float32_t ShimmerReverb::getShimmerAmplitude() const
float32_t ShimmerReverb::getDiffusion() const
{
return this->shimmer_amplitude_;
return this->diffusion_;
}
void ShimmerReverb::setDecayTime(float32_t decay_time)
void ShimmerReverb::setLP(float32_t lp)
{
this->decay_time_ = constrain(decay_time, 0.0f, 1.0f);
this->lp_ = constrain(lp, 0.0f, 1.0f);
}
float32_t ShimmerReverb::getDecayTime() const
float32_t ShimmerReverb::getLP() const
{
return this->decay_time_;
return this->lp_;
}

@ -13,59 +13,48 @@
//
//
// fx_shimmer_reverb.h
// fx_shimmer_reverb3.h
//
// Stereo Shimmer reverb proposed in the context of the MiniDexed project
// Stereo Shimmer Reverb proposed in the context of the MiniDexed project
// It is adapted from the Shimmer Reverb that could be found on Cloud EuroRack module from Mutable Instrruments
//
#pragma once
#include "fx_components.h"
#include "fx_engine.hpp"
class ShimmerReverb : public FXElement
{
DISALLOW_COPY_AND_ASSIGN(ShimmerReverb);
public:
ShimmerReverb( float32_t sampling_rate,
float32_t left_delay_time = 0.5f,
float32_t right_delay_time = 0.6f,
float32_t shimmer_frequency = 2.0f,
float32_t shimmer_amplitude = 0.5f,
float32_t decay_time = 2.0f);
ShimmerReverb(float32_t sampling_rate);
virtual ~ShimmerReverb();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setLeftDelayTime(float32_t delay_time_L);
float32_t getLeftDelayTime() const;
void setInputGain(float32_t gain);
float32_t getInputGain() const;
void setRightDelayTime(float32_t delay_time_R);
float32_t getRightDelayTime() const;
void setTime(float32_t time);
float32_t getTime() const;
void setShimmerFrequency(float32_t frequency);
float32_t getShimmerFrequency() const;
void setDiffusion(float32_t diffusion);
float32_t getDiffusion() const;
void setShimmerAmplitude(float32_t amplitude);
float32_t getShimmerAmplitude() const;
void setDecayTime(float32_t decay_time);
float32_t getDecayTime() const;
void setLP(float32_t lp);
float32_t getLP() const;
private:
const unsigned DelayLineLength;
float32_t* delay_line_L_;
float32_t* delay_line_R_;
typedef FxEngine<16384, FORMAT_16_BIT> Engine;
Engine engine_;
// Current write position for left and right channel delay lines
unsigned write_pos_L_;
unsigned write_pos_R_;
float32_t shimmer_phase_;
float32_t shimmer_phase_increment_;
float32_t input_gain_;
float32_t reverb_time_;
float32_t diffusion_;
float32_t lp_;
float32_t delay_time_L_; // Left channel delay time in seconds
float32_t delay_time_R_; // Right channel delay time in seconds
float32_t shimmer_frequency_; // Shimmer frequency parameter in Hz (0.0 === 20Hz - 1.0 === 20kHz)
float32_t shimmer_amplitude_; // Shimmer amplitude (0.0 - 1.0)
float32_t decay_time_; // Reverb decay time in seconds
};
float32_t lp_decay_1_;
float32_t lp_decay_2_;
};

@ -1,116 +0,0 @@
#include "fx_shimmer_reverb2.h"
#include <cmath>
#include <algorithm>
ShimmerReverb2::ShimmerReverb2( float32_t sampling_rate,
float32_t decay,
float32_t diffusion,
float32_t pitch_shift) :
FXElement(sampling_rate),
FXUnitModule(),
reverb_buffer_index_(0)
{
this->setDecay(decay);
this->setDiffusion(diffusion);
this->setPitchShift(pitch_shift);
}
ShimmerReverb2::~ShimmerReverb2()
{
}
void ShimmerReverb2::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
if(!this->isEnable())
{
outL = inL;
outR = inR;
return;
}
// Processing left channel
{
// Read the sample from the reverb buffer
float32_t reverb_sample = this->reverb_buffer_L_[this->reverb_buffer_index_];
// Calculate the pitch-shifted sample
float32_t pitch_shift_sample = reverb_sample * this->getPitchShift();
// Interpolate the pitch-shifted sample to the original pitch
float32_t pitch_shift_frac = pitch_shift_sample - std::floor(pitch_shift_sample);
unsigned pitch_shift_index = static_cast<unsigned>(SHIMMER_BUFFER_SIZE + std::floor(pitch_shift_sample)) % SHIMMER_BUFFER_SIZE;
float32_t pitch_shift_interp =
(1.0f - pitch_shift_frac) * this->reverb_buffer_L_[pitch_shift_index] +
pitch_shift_frac * this->reverb_buffer_L_[(pitch_shift_index + 1) % SHIMMER_BUFFER_SIZE];
// Calculate the wet (reverb) and dry (original) samples
float32_t dry_level = 1.0f - this->getWetLevel();
float32_t wet_sample = dry_level * inL + this->getWetLevel() * pitch_shift_interp;
float32_t dry_sample = this->getWetLevel() * inL + dry_level * pitch_shift_interp;
outL = dry_sample;
// Write the wet sample to the reverb buffer with the diffusion coefficient applied
this->reverb_buffer_L_[this->reverb_buffer_index_] = wet_sample + (reverb_sample * (1.0f - this->getDiffusion() / this->getSamplingRate() / this->getDecay()));
}
// Processing right channel
{
// Read the sample from the reverb buffer
float32_t reverb_sample = this->reverb_buffer_R_[this->reverb_buffer_index_];
// Calculate the pitch-shifted sample
float32_t pitch_shift_sample = reverb_sample * this->getPitchShift();
// Interpolate the pitch-shifted sample to the original pitch
float32_t pitch_shift_frac = pitch_shift_sample - std::floor(pitch_shift_sample);
unsigned pitch_shift_index = static_cast<unsigned>(SHIMMER_BUFFER_SIZE + std::floor(pitch_shift_sample)) % SHIMMER_BUFFER_SIZE;
float32_t pitch_shift_interp =
(1.0f - pitch_shift_frac) * this->reverb_buffer_R_[pitch_shift_index] +
pitch_shift_frac * this->reverb_buffer_R_[(pitch_shift_index + 1) % SHIMMER_BUFFER_SIZE];
// Calculate the wet (reverb) and dry (original) samples
float32_t dry_level = 1.0f - this->getWetLevel();
float32_t wet_sample = dry_level * inR + this->getWetLevel() * pitch_shift_interp;
float32_t dry_sample = this->getWetLevel() * inR + dry_level * pitch_shift_interp;
outR = dry_sample;
// Write the wet sample to the reverb buffer with the diffusion coefficient applied
this->reverb_buffer_R_[this->reverb_buffer_index_] = wet_sample + (reverb_sample * (1.0f - this->getDiffusion() / this->getSamplingRate() / this->getDecay()));
}
// Increment the buffer index and wrap around if necessary
this->reverb_buffer_index_ = (this->reverb_buffer_index_ + 1) % SHIMMER_BUFFER_SIZE;
}
void ShimmerReverb2::setDecay(float32_t decay)
{
this->decay_ = constrain(decay, SHIMMER_MIN_DECAY, SHIMMER_MAX_DECAY);
}
float32_t ShimmerReverb2::getDecay() const
{
return this->decay_;
}
void ShimmerReverb2::setDiffusion(float32_t diffusion)
{
this->diffusion_ = constrain(diffusion, 0.0f, 1.0f);
}
float32_t ShimmerReverb2::getDiffusion() const
{
return this->diffusion_;
}
void ShimmerReverb2::setPitchShift(float32_t pitch_shift)
{
this->pitch_shift_ = constrain(pitch_shift, SHIMMER_MIN_PITCH_RATIO, SHIMMER_MAX_PITCH_RATIO);
}
float32_t ShimmerReverb2::getPitchShift() const
{
return this->pitch_shift_;
}

@ -1,67 +0,0 @@
// 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_shimmer_reverb2.h
//
// Stereo Shimmer reverb proposed in the context of the MiniDexed project
//
#pragma once
#include "fx_components.h"
#include "fx_unit.hpp"
#define SHIMMER_BUFFER_SIZE 1024
#define SHIMMER_MIN_DECAY 0.0f
#define SHIMMER_MAX_DECAY 10.0f
#define SHIMMER_MIN_PITCH_RATIO 0.5f
#define SHIMMER_MAX_PITCH_RATIO 2.0f
class ShimmerReverb2 :
public virtual FXElement,
public virtual FXUnitModule
{
DISALLOW_COPY_AND_ASSIGN(ShimmerReverb2);
public:
ShimmerReverb2( float32_t sampling_rate,
float32_t decay = 3.0f,
float32_t diffusion = 0.5f,
float32_t pitch_shift = 2.0f);
virtual ~ShimmerReverb2();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setDecay(float32_t delay_time_L);
float32_t getDecay() const;
void setDiffusion(float32_t delay_time_R);
float32_t getDiffusion() const;
void setPitchShift(float32_t frequency);
float32_t getPitchShift() const;
private:
float32_t reverb_buffer_L_[SHIMMER_BUFFER_SIZE];
float32_t reverb_buffer_R_[SHIMMER_BUFFER_SIZE];
unsigned reverb_buffer_index_;
// Current write position for left and right channel delay lines
float32_t decay_; // Reverb decay time in seconds (0 - 10)
float32_t diffusion_; // The degree to which the reverb is spread out over time (0 - 1)
float32_t pitch_shift_; // Determines the pitch shift ratio applied to the reverb (0.5 - 2.0)
};

@ -5,11 +5,14 @@
StateVariableFilter::StateVariableFilter(float32_t sampling_rate, Type type, float32_t cutoff) :
FXElement(sampling_rate),
type_(type),
cutoff_(0.0f)
cutoff_(0.0f),
resonance_(0.0f),
peak_gain_(0.0f)
{
memset(this->z1_, 0, 2 * sizeof(float32_t));
memset(this->z2_, 0, 2 * sizeof(float32_t));
this->setPeakGainDB(1.0f);
this->setCutoff(cutoff);
this->setResonance(0.0f);
}

@ -208,9 +208,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
// FXChain > ShimmerReverb parameters
this->SetParameter(ParameterFXChainShimmerReverbEnable, 1);
this->SetParameter(ParameterFXChainShimmerReverbWet, 70);
this->SetParameter(ParameterFXChainShimmerReverbDecay, 30);
this->SetParameter(ParameterFXChainShimmerReverbInputGain, 99);
this->SetParameter(ParameterFXChainShimmerReverbTime, 80);
this->SetParameter(ParameterFXChainShimmerReverbDiffusion, 80);
this->SetParameter(ParameterFXChainShimmerReverbPitchShift, 99);
this->SetParameter(ParameterFXChainShimmerReverbLP, 70);
#endif
// END setup FXRack
};
@ -944,10 +945,16 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue)
this->fx_rack->getShimmerReverb()->setWetLevel(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainShimmerReverbDecay:
case ParameterFXChainShimmerReverbInputGain:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getShimmerReverb()->setDecay(mapfloat(nValue, 0, 99, SHIMMER_MIN_DECAY, SHIMMER_MAX_DECAY));
this->fx_rack->getShimmerReverb()->setInputGain(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainShimmerReverbTime:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getShimmerReverb()->setTime(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainShimmerReverbDiffusion:
@ -956,10 +963,10 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue)
this->fx_rack->getShimmerReverb()->setDiffusion(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
case ParameterFXChainShimmerReverbPitchShift:
case ParameterFXChainShimmerReverbLP:
nValue = constrain((int)nValue, 0, 99);
this->m_FXSpinLock.Acquire();
this->fx_rack->getShimmerReverb()->setPitchShift(mapfloat(nValue, 0, 99, SHIMMER_MIN_PITCH_RATIO, SHIMMER_MAX_PITCH_RATIO));
this->fx_rack->getShimmerReverb()->setLP(nValue / 99.0f);
this->m_FXSpinLock.Release();
break;
#endif
@ -1415,9 +1422,10 @@ bool CMiniDexed::DoSavePerformance (void)
this->m_PerformanceConfig.SetFXChainTapeDelayFeedback(this->m_nParameter[ParameterFXChainTapeDelayFeedback]);
this->m_PerformanceConfig.SetFXChainShimmerReverbEnable(!!this->m_nParameter[ParameterFXChainShimmerReverbEnable]);
this->m_PerformanceConfig.SetFXChainShimmerReverbWet(this->m_nParameter[ParameterFXChainShimmerReverbWet]);
this->m_PerformanceConfig.SetFXChainShimmerReverbDecay(this->m_nParameter[ParameterFXChainShimmerReverbDecay]);
this->m_PerformanceConfig.SetFXChainShimmerReverbInputGain(this->m_nParameter[ParameterFXChainShimmerReverbInputGain]);
this->m_PerformanceConfig.SetFXChainShimmerReverbTime(this->m_nParameter[ParameterFXChainShimmerReverbTime]);
this->m_PerformanceConfig.SetFXChainShimmerReverbDiffusion(this->m_nParameter[ParameterFXChainShimmerReverbDiffusion]);
this->m_PerformanceConfig.SetFXChainShimmerReverbPitchShift(this->m_nParameter[ParameterFXChainShimmerReverbPitchShift]);
this->m_PerformanceConfig.SetFXChainShimmerReverbLP(this->m_nParameter[ParameterFXChainShimmerReverbLP]);
#endif
// END FXRack parameters
@ -1842,9 +1850,10 @@ void CMiniDexed::LoadPerformanceParameters(void)
this->SetParameter(ParameterFXChainTapeDelayFeedback, this->m_PerformanceConfig.GetFXChainTapeDelayFeedback());
this->SetParameter(ParameterFXChainShimmerReverbEnable, this->m_PerformanceConfig.GetFXChainShimmerReverbEnable());
this->SetParameter(ParameterFXChainShimmerReverbWet, this->m_PerformanceConfig.GetFXChainShimmerReverbWet());
this->SetParameter(ParameterFXChainShimmerReverbDecay, this->m_PerformanceConfig.GetFXChainShimmerReverbDecay());
this->SetParameter(ParameterFXChainShimmerReverbInputGain, this->m_PerformanceConfig.GetFXChainShimmerReverbInputGain());
this->SetParameter(ParameterFXChainShimmerReverbTime, this->m_PerformanceConfig.GetFXChainShimmerReverbTime());
this->SetParameter(ParameterFXChainShimmerReverbDiffusion, this->m_PerformanceConfig.GetFXChainShimmerReverbDiffusion());
this->SetParameter(ParameterFXChainShimmerReverbPitchShift, this->m_PerformanceConfig.GetFXChainShimmerReverbPitchShift());
this->SetParameter(ParameterFXChainShimmerReverbLP, this->m_PerformanceConfig.GetFXChainShimmerReverbLP());
#endif
}

@ -188,9 +188,10 @@ public:
// FXChain > ShimmerReverb parameters
ParameterFXChainShimmerReverbEnable,
ParameterFXChainShimmerReverbWet,
ParameterFXChainShimmerReverbDecay,
ParameterFXChainShimmerReverbInputGain,
ParameterFXChainShimmerReverbTime,
ParameterFXChainShimmerReverbDiffusion,
ParameterFXChainShimmerReverbPitchShift,
ParameterFXChainShimmerReverbLP,
#endif
// END FXRack global parameters definition

@ -313,8 +313,9 @@ FXChainTapeDelayLeftDelayTime=15
FXChainTapeDelayRightDelayTime=22
FXChainTapeDelayFlutter=0
FXChainTapeDelayFeedback=35
FXChainShimmerReverbEnable=0
FXChainShimmerReverbEnable=1
FXChainShimmerReverbWet=70
FXChainShimmerReverbDecay=30
FXChainShimmerReverbDiffusion=80
FXChainShimmerReverbPitchShift=99
FXChainShimmerReverbInputGain=45
FXChainShimmerReverbTime=89
FXChainShimmerReverbDiffusion=75
FXChainShimmerReverbLP=80

@ -191,9 +191,10 @@ bool CPerformanceConfig::Load (void)
this->m_nFXChainTapeDelayFeedback = this->m_Properties.GetNumber("FXChainTapeDelayFeedback", 35);
this->m_bFXChainShimmerReverbEnable = this->m_Properties.GetNumber("FXChainShimmerReverbEnable", 1);
this->m_nFXChainShimmerReverbWet = this->m_Properties.GetNumber("FXChainShimmerReverbWet", 70);
this->m_nFXChainShimmerReverbDecay = this->m_Properties.GetNumber("FXChainShimmerReverbDecay", 30);
this->m_nFXChainShimmerReverbInputGain = this->m_Properties.GetNumber("FXChainShimmerReverbInputGain", 30);
this->m_nFXChainShimmerReverbTime = this->m_Properties.GetNumber("FXChainShimmerReverbTime", 30);
this->m_nFXChainShimmerReverbDiffusion = this->m_Properties.GetNumber("FXChainShimmerReverbDiffusion", 30);
this->m_nFXChainShimmerReverbPitchShift = this->m_Properties.GetNumber("FXChainShimmerReverbPitchShift", 99);
this->m_nFXChainShimmerReverbLP = this->m_Properties.GetNumber("FXChainShimmerReverbLP", 99);
#endif
return bResult;
@ -346,9 +347,10 @@ bool CPerformanceConfig::Save (void)
this->m_Properties.SetNumber("FXChainTapeDelayFeedback", m_nFXChainTapeDelayFeedback);
this->m_Properties.SetNumber("FXChainShimmerReverbEnable", m_bFXChainShimmerReverbEnable ? 1 : 0);
this->m_Properties.SetNumber("FXChainShimmerReverbWet", m_nFXChainShimmerReverbWet);
this->m_Properties.SetNumber("FXChainShimmerReverbDecay", m_nFXChainShimmerReverbDecay);
this->m_Properties.SetNumber("FXChainShimmerReverbInputGain", m_nFXChainShimmerReverbInputGain);
this->m_Properties.SetNumber("FXChainShimmerReverbTime", m_nFXChainShimmerReverbTime);
this->m_Properties.SetNumber("FXChainShimmerReverbDiffusion", m_nFXChainShimmerReverbDiffusion);
this->m_Properties.SetNumber("FXChainShimmerReverbPitchShift", m_nFXChainShimmerReverbPitchShift);
this->m_Properties.SetNumber("FXChainShimmerReverbLP", m_nFXChainShimmerReverbLP);
#endif
return m_Properties.Save ();
@ -1154,9 +1156,14 @@ unsigned CPerformanceConfig::GetFXChainShimmerReverbWet(void) const
return this->m_nFXChainShimmerReverbWet;
}
unsigned CPerformanceConfig::GetFXChainShimmerReverbDecay(void) const
unsigned CPerformanceConfig::GetFXChainShimmerReverbInputGain(void) const
{
return this->m_nFXChainShimmerReverbDecay;
return this->m_nFXChainShimmerReverbInputGain;
}
unsigned CPerformanceConfig::GetFXChainShimmerReverbTime(void) const
{
return this->m_nFXChainShimmerReverbTime;
}
unsigned CPerformanceConfig::GetFXChainShimmerReverbDiffusion(void) const
@ -1164,9 +1171,9 @@ unsigned CPerformanceConfig::GetFXChainShimmerReverbDiffusion(void) const
return this->m_nFXChainShimmerReverbDiffusion;
}
unsigned CPerformanceConfig::GetFXChainShimmerReverbPitchShift(void) const
unsigned CPerformanceConfig::GetFXChainShimmerReverbLP(void) const
{
return this->m_nFXChainShimmerReverbPitchShift;
return this->m_nFXChainShimmerReverbLP;
}
void CPerformanceConfig::SetFXChainEnable(bool bValue)
@ -1324,9 +1331,14 @@ void CPerformanceConfig::SetFXChainShimmerReverbWet(unsigned nValue)
this->m_nFXChainShimmerReverbWet = nValue;
}
void CPerformanceConfig::SetFXChainShimmerReverbDecay(unsigned nValue)
void CPerformanceConfig::SetFXChainShimmerReverbInputGain(unsigned nValue)
{
this->m_nFXChainShimmerReverbInputGain = nValue;
}
void CPerformanceConfig::SetFXChainShimmerReverbTime(unsigned nValue)
{
this->m_nFXChainShimmerReverbDecay = nValue;
this->m_nFXChainShimmerReverbTime = nValue;
}
void CPerformanceConfig::SetFXChainShimmerReverbDiffusion(unsigned nValue)
@ -1334,9 +1346,9 @@ void CPerformanceConfig::SetFXChainShimmerReverbDiffusion(unsigned nValue)
this->m_nFXChainShimmerReverbDiffusion = nValue;
}
void CPerformanceConfig::SetFXChainShimmerReverbPitchShift(unsigned nValue)
void CPerformanceConfig::SetFXChainShimmerReverbLP(unsigned nValue)
{
this->m_nFXChainShimmerReverbPitchShift = nValue;
this->m_nFXChainShimmerReverbLP = nValue;
}
#endif

@ -149,9 +149,10 @@ public:
unsigned GetFXChainTapeDelayFeedback(void) const;
bool GetFXChainShimmerReverbEnable(void) const;
unsigned GetFXChainShimmerReverbWet(void) const;
unsigned GetFXChainShimmerReverbDecay(void) const;
unsigned GetFXChainShimmerReverbInputGain(void) const;
unsigned GetFXChainShimmerReverbTime(void) const;
unsigned GetFXChainShimmerReverbDiffusion(void) const;
unsigned GetFXChainShimmerReverbPitchShift(void) const;
unsigned GetFXChainShimmerReverbLP(void) const;
void SetFXChainEnable(bool bValue);
void SetFXChainWet(unsigned nValue);
@ -184,9 +185,10 @@ public:
void SetFXChainTapeDelayFeedback(unsigned nValue);
void SetFXChainShimmerReverbEnable(unsigned nValue);
void SetFXChainShimmerReverbWet(unsigned nValue);
void SetFXChainShimmerReverbDecay(unsigned nValue);
void SetFXChainShimmerReverbInputGain(unsigned nValue);
void SetFXChainShimmerReverbTime(unsigned nValue);
void SetFXChainShimmerReverbDiffusion(unsigned nValue);
void SetFXChainShimmerReverbPitchShift(unsigned nValue);
void SetFXChainShimmerReverbLP(unsigned nValue);
#endif
bool VoiceDataFilled(unsigned nTG);
@ -288,9 +290,10 @@ private:
unsigned m_nFXChainTapeDelayFeedback;
bool m_bFXChainShimmerReverbEnable;
unsigned m_nFXChainShimmerReverbWet;
unsigned m_nFXChainShimmerReverbDecay;
unsigned m_nFXChainShimmerReverbInputGain;
unsigned m_nFXChainShimmerReverbTime;
unsigned m_nFXChainShimmerReverbDiffusion;
unsigned m_nFXChainShimmerReverbPitchShift;
unsigned m_nFXChainShimmerReverbLP;
#endif
};

@ -1,8 +1,9 @@
CXX := gcc
CXXFLAGS := -g -O2
DEFINES :=
# CXXFLAGS := -O2
CXXFLAGS := -g
DEFINES := -DCPU=x86
INCLUDES := -I../../CMSIS_5/CMSIS/DSP/Include/ -I../../CMSIS_5/CMSIS/Core/Include/
GCC := $(CXX) $(INCLUDES) $(CXXFLAGS)
GCC := $(CXX) $(INCLUDES) $(CXXFLAGS)
LD := gcc
LIBS := -lm -lstdc++
@ -10,7 +11,6 @@ LIBS := -lm -lstdc++
OBJS := \
wavein.o \
waveout.o \
waveplay.o \
fx.o \
fx_components.o \
fx_svf.o \
@ -20,14 +20,14 @@ OBJS := \
fx_orbitone.o \
fx_flanger.o \
fx_tape_delay.o \
fx_shimmer_reverb2.o \
fx_shimmer_reverb.o \
fx_rack.o \
fxrack_test.o
test: fxrack_test
./fxrack_test
# %.o: ../%.cpp
# %.o: ../%.cpp
# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
wavein.o: wavein.cpp
@ -36,8 +36,8 @@ wavein.o: wavein.cpp
waveout.o: waveout.cpp
$(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
waveplay.o: waveplay.cpp
$(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
# waveplay.o: waveplay.cpp
# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
fx.o: ../fx.cpp
$(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
@ -66,7 +66,10 @@ fx_flanger.o: ../fx_flanger.cpp
fx_tape_delay.o: ../fx_tape_delay.cpp
$(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
fx_shimmer_reverb2.o: ../fx_shimmer_reverb2.cpp
../fx_shimmer_reverb3.cpp: ../fx_engine.hpp
touch ../fx_shimmer_reverb3.cpp
fx_shimmer_reverb.o: ../fx_shimmer_reverb.cpp
$(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@
fx_rack.o: ../fx_rack.cpp

@ -10,30 +10,117 @@ using namespace std;
#define MAX_SVF_SAMPLES 10000000
#define MAX_NB_ERRORS 100
void testFlutter()
enum CosineOscillatorMode
{
COSINE_OSCILLATOR_APPROXIMATE,
COSINE_OSCILLATOR_EXACT
};
class CosineOscillator
{
public:
CosineOscillator() {}
~CosineOscillator() {}
template <CosineOscillatorMode mode>
inline void Init(float frequency)
{
if (mode == COSINE_OSCILLATOR_APPROXIMATE)
{
InitApproximate(frequency);
}
else
{
iir_coefficient_ = 2.0f * cosf(2.0f * M_PI * frequency);
initial_amplitude_ = iir_coefficient_ * 0.25f;
}
Start();
}
inline void InitApproximate(float frequency)
{
float sign = 16.0f;
frequency -= 0.25f;
if (frequency < 0.0f)
{
frequency = -frequency;
}
else
{
if (frequency > 0.5f)
{
frequency -= 0.5f;
}
else
{
sign = -16.0f;
}
}
iir_coefficient_ = sign * frequency * (1.0f - 2.0f * frequency);
initial_amplitude_ = iir_coefficient_ * 0.25f;
}
inline void Start()
{
y1_ = initial_amplitude_;
y0_ = 0.5f;
}
inline float value() const
{
return y1_ + 0.5f;
}
inline float Next()
{
float temp = y0_;
y0_ = iir_coefficient_ * y0_ - y1_;
y1_ = temp;
return temp + 0.5f;
}
private:
float y1_;
float y0_;
float iir_coefficient_;
float initial_amplitude_;
DISALLOW_COPY_AND_ASSIGN(CosineOscillator);
};
void testCosineOsc(unsigned& step)
{
cout << "Step #" << (++step) << ": Testing CosineOscillator" << endl;
CosineOscillator osc;
osc.template Init<CosineOscillatorMode::COSINE_OSCILLATOR_APPROXIMATE>(32.0f * 0.5f / 32000.0f);
for(unsigned i = 0; i < 2000; ++i)
{
cout << "LFO #" << i << ": " << osc.Next() << endl;
}
}
void testFlutter(unsigned& step)
{
cout << "Step #" << (++step) << ": Testing JitterGenerator" << endl;
JitterGenerator jg(44100.0f);
jg.setSpeed(1.0f);
jg.setMagnitude(0.1f);
for(unsigned i = 0; i < 1000; ++i)
for (unsigned i = 0; i < 1000; ++i)
{
cout << jg.process() << endl;
}
}
int main()
void testSVF(unsigned& step, std::mt19937& gen, std::uniform_real_distribution<float32_t> dist)
{
// testFlutter();
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float32_t> dist(-1.0f, 1.0f);
unsigned step = 0;
float32_t inL, inR;
float32_t outL, outR;
StateVariableFilter svf(44100.0f, StateVariableFilter::Type::LPF, 12000.0f);
cout << "Step #" << (++step) << ": Testing SVF in LPF mode" << endl;
{
svf.setFilterType(StateVariableFilter::Type::LPF);
@ -41,15 +128,17 @@ int main()
svf.setResonance(0.0f);
unsigned nbSamples = 0;
unsigned nbErrors = 0;
while(nbErrors < MAX_NB_ERRORS && nbSamples < MAX_SVF_SAMPLES)
while (nbErrors < MAX_NB_ERRORS && nbSamples < MAX_SVF_SAMPLES)
{
nbSamples++;
inL = dist(gen);
inR = dist(gen);
svf.processSample(inL, inR, outL, outR);
if(std::abs(outL) > 1.0f) nbErrors++;
if(std::abs(outR) > 1.0f) nbErrors++;
if (std::abs(outL) > 1.0f)
nbErrors++;
if (std::abs(outR) > 1.0f)
nbErrors++;
}
cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl;
}
@ -61,48 +150,73 @@ int main()
svf.setResonance(0.0f);
unsigned nbSamples = 0;
unsigned nbErrors = 0;
while(nbErrors < MAX_NB_ERRORS && nbSamples < MAX_SVF_SAMPLES)
while (nbErrors < MAX_NB_ERRORS && nbSamples < MAX_SVF_SAMPLES)
{
nbSamples++;
inL = dist(gen);
inR = dist(gen);
svf.processSample(inL, inR, outL, outR);
if(std::abs(outL) > 1.0f) nbErrors++;
if(std::abs(outR) > 1.0f) nbErrors++;
}
if (std::abs(outL) > 1.0f)
nbErrors++;
if (std::abs(outR) > 1.0f)
nbErrors++;
}
cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl;
}
}
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float32_t> dist(-1.0f, 1.0f);
unsigned step = 0;
// testCosineOsc(step);
// testFlutter(step, gen, dist);
// testSVF(step);
cout << "Step #" << (++step) << ": Intanciation FXRack" << endl;
FXRack* rack = new FXRack(44100.0f);
FXRack *rack = new FXRack(44100.0f);
cout << "Step #" << (++step) << ": Test preparation" << endl;
rack->setEnable(true);
rack->setWetLevel(1.0f);
rack->getTube()->setEnable(false);
rack->getTube()->setWetLevel(1.0f);
rack->getTube()->setOverdrive(1.0f);
rack->getChorus()->setEnable(false);
rack->getPhaser()->setEnable(false);
rack->getOrbitone()->setEnable(true);
rack->getOrbitone()->setEnable(false);
rack->getOrbitone()->setWetLevel(0.8f);
rack->getOrbitone()->setFeedback(1.0f);
rack->getFlanger()->setEnable(false);
rack->getTapeDelay()->setEnable(false);
// rack->getTapeDelay()->setWetLevel(0.6f);
// rack->getTapeDelay()->setLeftDelayTime(0.1f);
// rack->getTapeDelay()->setLeftDelayTime(0.05f);
// rack->getTapeDelay()->setFlutterLevel(0.25f);
// rack->getTapeDelay()->setFeedbak(0.5f);
rack->getTapeDelay()->setWetLevel(0.6f);
rack->getTapeDelay()->setLeftDelayTime(0.075f);
rack->getTapeDelay()->setLeftDelayTime(0.05f);
rack->getTapeDelay()->setFlutterLevel(0.0f);
rack->getTapeDelay()->setFeedbak(0.5f);
rack->getShimmerReverb()->setEnable(true);
rack->getShimmerReverb()->setWetLevel(60);
rack->getShimmerReverb()->setDecay(30);
rack->getShimmerReverb()->setDiffusion(80);
rack->getShimmerReverb()->setPitchShift(99);
rack->getShimmerReverb()->setWetLevel(0.7f);
rack->getShimmerReverb()->setInputGain(0.45f);
rack->getShimmerReverb()->setTime(0.89f);
rack->getShimmerReverb()->setDiffusion(0.75f);
rack->getShimmerReverb()->setLP(0.8f);
const unsigned nSamples = 3000;
const unsigned nSamples = 1;
float32_t inSamples[2][nSamples];
float32_t outSamples[2][nSamples];
for(unsigned i = 0; i < nSamples; ++i)
for (unsigned i = 0; i < nSamples; ++i)
{
inSamples[0][i] = dist(gen);
inSamples[1][i] = dist(gen);
@ -115,22 +229,35 @@ int main()
rack->process(inSamples[0], inSamples[1], outSamples[0], outSamples[1], nSamples);
cout << "Step #" << (++step) << ": Render results" << endl;
for(unsigned i = 0; i < nSamples; ++i)
for (unsigned i = 0; i < nSamples; ++i)
{
std::cout << "#" << i << " " << inSamples[0][i] << " --> " << outSamples[0][i] << " = " << ((outSamples[0][i] - inSamples[0][i]) * 100.0f / inSamples[0][i]) << "%" << std::endl;
}
unsigned nbRepeats = 4;
unsigned size;
float32_t** samples = readWaveFile("test.wav", size);
float32_t* sampleOutL = new float32_t[size];
float32_t* sampleOutR = new float32_t[size];
rack->process(samples[0], samples[1], sampleOutL, sampleOutR, size);
float32_t* sampleOutL = new float32_t[size * nbRepeats];
float32_t* sampleOutR = new float32_t[size * nbRepeats];
memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t));
memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t));
for (unsigned i = 0; i < nbRepeats; ++i)
{
rack->process(samples[0], samples[1], sampleOutL + i * size, sampleOutR + i * size, size);
}
playSound(sampleOutL, sampleOutR, size, 44100, 16);
saveWaveFile("result.wav", sampleOutL, sampleOutR, nbRepeats * size, 44100, 16);
delete[] sampleOutL;
delete[] sampleOutR;
delete[] samples[0];
delete[] samples[1];
delete[] samples;
cout << "Step #" << (++step) << ": Test cleanup" << endl;
delete rack;
return 0;
}
}

@ -29,8 +29,8 @@ void saveWaveFile(const std::string& fileName,
int sampleRate,
int bitsPerSample);
void playSound(float32_t* LChannel,
float32_t* RChannel,
unsigned size,
int sampleRate,
int bitsPerSample);
// void playSound(float32_t* LChannel,
// float32_t* RChannel,
// unsigned size,
// int sampleRate,
// int bitsPerSample);

@ -2,6 +2,7 @@
#include <fstream>
#include <iostream>
#include <cassert>
float32_t** readWaveFile(const std::string& fileName, unsigned& size)
{
@ -15,6 +16,10 @@ float32_t** readWaveFile(const std::string& fileName, unsigned& size)
WaveHeader header;
file.read((char*)&header, sizeof(header));
std::cout << "Sampling rate: " << header.sampleRate << std::endl;
std::cout << "# channels: " << header.numChannels << std::endl;
std::cout << "Resolution: " << header.bitsPerSample << " bits" << std::endl;
if(strncmp(header.chunkId, "RIFF", 4) != 0 || strncmp(header.format, "WAVE", 4) != 0)
{
std::cerr << "Error: not a WAVE file" << std::endl;
@ -32,43 +37,71 @@ float32_t** readWaveFile(const std::string& fileName, unsigned& size)
float32_t* RChannel = new float32_t[size];
unsigned i = 0;
while(!file.eof())
while(!file.eof() && i < size)
{
if(header.bitsPerSample == 8)
{
uint8_t LSample;
uint8_t RSample;
file.read((char*)&LSample, 1);
file.read((char*)&RSample, 1);
LChannel[i] = LSample / 128.0f - 1.0f;
RChannel[i] = RSample / 128.0f - 1.0f;
if(header.numChannels == 2)
{
uint8_t RSample;
file.read((char*)&RSample, 1);
RChannel[i] = RSample / 128.0f - 1.0f;
}
else
{
RChannel[i] = LChannel[i];
}
}
else if (header.bitsPerSample == 16)
{
int16_t LSample;
int16_t RSample;
file.read((char*)&LSample, 2);
file.read((char*)&RSample, 2);
LChannel[i] = LSample / 32768.0f;
RChannel[i] = RSample / 32768.0f;
if(header.numChannels == 2)
{
int16_t RSample;
file.read((char*)&RSample, 2);
RChannel[i] = RSample / 32768.0f;
}
else
{
RChannel[i] = LChannel[i];
}
}
else if (header.bitsPerSample == 24)
{
int32_t LSample;
int32_t RSample;
file.read((char*)&LSample, 3);
file.read((char*)&RSample, 3);
LChannel[i] = LSample / 8388608.0f;
RChannel[i] = RSample / 8388608.0f;
if(header.numChannels == 2)
{
int32_t RSample;
file.read((char*)&RSample, 3);
RChannel[i] = RSample / 8388608.0f;
}
else
{
RChannel[i] = LChannel[i];
}
}
else if (header.bitsPerSample == 32)
{
int32_t LSample;
int32_t RSample;
file.read((char*)&LSample, 4);
file.read((char*)&RSample, 4);
LChannel[i] = LSample / 2147483648.0f;
RChannel[i] = RSample / 2147483648.0f;
if(header.numChannels == 2)
{
int32_t RSample;
file.read((char*)&RSample, 4);
RChannel[i] = RSample / 2147483648.0f;
}
else
{
RChannel[i] = LChannel[i];
}
}
else
{
@ -78,6 +111,7 @@ float32_t** readWaveFile(const std::string& fileName, unsigned& size)
++i;
}
assert(i == size);
float32_t** result = new float32_t*[2];
result[0] = LChannel;

@ -28,6 +28,7 @@ void saveWaveFile(const std::string& fileName,
header.subchunk2Size = size * header.blockAlign;
header.chunkSize = 36 + header.subchunk2Size;
header.subchunk1Size = 16;
header.audioFormat = 1;
std::strncpy(header.chunkId, "RIFF", 4);
std::strncpy(header.format, "WAVE", 4);

@ -217,9 +217,10 @@ const CUIMenu::TMenuItem CUIMenu::s_FXChainShimmerReverb[] =
{
{"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbEnable},
{"Wet Lvl", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbWet},
{"Decay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDecay},
{"Gain", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbInputGain},
{"Time", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbTime},
{"Diffus", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDiffusion},
{"PtchShft", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbPitchShift},
{"LowPass", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbLP},
{0}
};
@ -353,9 +354,10 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow
// FXChain > ShimmerReverb parameters
{0, 1, 1, ToOnOff}, // ParameterFXChainShimmerReverbEnable
{0, 99, 1}, // ParameterFXChainShimmerReverbWet
{0, 99, 1}, // ParameterFXChainShimmerReverbDecay
{0, 99, 1}, // ParameterFXChainShimmerReverbInputGain
{0, 99, 1}, // ParameterFXChainShimmerReverbTime
{0, 99, 1}, // ParameterFXChainShimmerReverbDiffusion
{0, 99, 1}, // ParameterFXChainShimmerReverbPitchShift
{0, 99, 1}, // ParameterFXChainShimmerReverbLP
#endif
// END FXRack global parameters mapping definition

Loading…
Cancel
Save