diff --git a/.gitignore b/.gitignore index ace2c61..caa07b1 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,4 @@ sdcard .vscode/ # temporary tests -src/test/ \ No newline at end of file +src/test/fxrack_test \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index 7ac97f7..abb52f3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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_reverb.o fx_rack.o \ + fx_tape_delay.o fx_shimmer_reverb2.o fx_rack.o \ uibuttons.o midipin.o OPTIMIZE = -O3 diff --git a/src/fx_chorus.cpp b/src/fx_chorus.cpp index c19497b..619b120 100644 --- a/src/fx_chorus.cpp +++ b/src/fx_chorus.cpp @@ -4,11 +4,14 @@ #define CHORUS_BUFFER_SIZE 8192 +#define LFO_MIN_FREQ 0.0f +#define LFO_MAX_FREQ 1.0f + Chorus::Chorus(float32_t sampling_rate, unsigned voices, float32_t rate, float32_t depth, float32_t feedback) : FXElement(sampling_rate), NumVoices(voices), sample_position_ratio_(sampling_rate / 1000.0f), - lfo_(sampling_rate, LFO::Waveform::Sine, 0.01f, 1.0f) + lfo_(sampling_rate, LFO::Waveform::Sine, LFO_MIN_FREQ, LFO_MAX_FREQ) { this->delay_buffersL_ = new float32_t*[this->NumVoices]; this->delay_buffersR_ = new float32_t*[this->NumVoices]; diff --git a/src/fx_components.cpp b/src/fx_components.cpp index 8801074..3c240d3 100644 --- a/src/fx_components.cpp +++ b/src/fx_components.cpp @@ -2,9 +2,15 @@ #include +/////////////////////////////// +// Constants implemlentation // +/////////////////////////////// const float32_t Constants::M2PI = 2.0f * PI; const float32_t Constants::M1_PI = 1.0f / PI; +///////////////////////// +// LFO implemlentation // +///////////////////////// LFO::LFO(float32_t sampling_rate, Waveform waveform, float32_t min_frequency, float32_t max_frequency) : FXBase(sampling_rate), min_frequency_(min_frequency), @@ -47,7 +53,7 @@ void LFO::setNormalizedFrequency(float32_t normalized_frequency) float32_t LFO::getNormalizedFrequency() const { - return this->frequency_; + return this->normalized_frequency_; } void LFO::setFrequency(float32_t frequency) @@ -62,6 +68,11 @@ void LFO::setFrequency(float32_t frequency) } } +float32_t LFO::getFrequency() const +{ + return this->frequency_; +} + float32_t LFO::process() { float32_t out = 0.0f; @@ -106,3 +117,84 @@ float32_t LFO::process() return out; } + +//////////////////////////////////// +// JitterGenerator implementation // +//////////////////////////////////// +JitterGenerator::JitterGenerator(float32_t sampling_rate) : + FXBase(sampling_rate), + rnd_generator_(rnd_device_()), + rnd_distribution_(-1.0f, 1.0f), + phase_(0.0f), + phase_increment_(0.0f) +{ + this->setSpeed(1.0f); + this->setMagnitude(0.1f); +} + +JitterGenerator::~JitterGenerator() +{ +} + +void JitterGenerator::setSpeed(float32_t speed) +{ + if(this->speed_ != speed) + { + this->speed_ = speed; + this->phase_increment_ = Constants::M2PI * this->speed_ / this->getSamplingRate(); + } +} + +float32_t JitterGenerator::getSpeed() const +{ + return this->speed_; +} + +void JitterGenerator::setMagnitude(float32_t magnitude) +{ + this->magnitude_ = magnitude; +} + +float32_t JitterGenerator::getMagnitude() const +{ + return this->magnitude_; +} + +float32_t JitterGenerator::process() +{ + float32_t out = std::sin(this->phase_); + + this->phase_ += this->phase_increment_ * (1.0f + this->magnitude_ * this->rnd_distribution_(this->rnd_generator_)); + if(this->phase_ > Constants::M2PI) + { + this->phase_ -= Constants::M2PI; + } + + return out; +} + +////////////////////////////////// +// softSaturate implemlentation // +////////////////////////////////// +float32_t softSaturate(float32_t in, float32_t threshold) +{ + float32_t x = std::abs(in); + float32_t y = 0.0f; + if(x < threshold) + { + y = x; + } + else if(x > threshold) + { + y = threshold + (x - threshold) / (1.0f + std::pow((x - threshold) / (1.0f - threshold), 2.0f)); + } + else if(x > 1.0f) + { + y = (threshold + 1.0f) / 2.0f; + } + + float32_t g = 2.0f / (1.0f + threshold); + y *= g; + + return (in < 0.0f) ? -y : y; +} diff --git a/src/fx_components.h b/src/fx_components.h index 9ac3798..f9eb0c3 100644 --- a/src/fx_components.h +++ b/src/fx_components.h @@ -107,3 +107,31 @@ private: const unsigned size_; T* values_; }; + +class JitterGenerator : public FXBase +{ + DISALLOW_COPY_AND_ASSIGN(JitterGenerator); + +public: + JitterGenerator(float32_t sampling_rate); + virtual ~JitterGenerator(); + + void setSpeed(float32_t speed); + float32_t getSpeed() const; + + void setMagnitude(float32_t magnitude); + float32_t getMagnitude() const; + + float32_t process(); + +private: + std::random_device rnd_device_; + std::mt19937 rnd_generator_; + std::uniform_real_distribution rnd_distribution_; + float32_t speed_; + float32_t magnitude_; + float32_t phase_; + float32_t phase_increment_; +}; + +float32_t softSaturate(float32_t in, float32_t threshold); diff --git a/src/fx_flanger.cpp b/src/fx_flanger.cpp index e4b1607..7949100 100644 --- a/src/fx_flanger.cpp +++ b/src/fx_flanger.cpp @@ -2,8 +2,6 @@ #include -#define MAX_FLANGER_DELAY 20.0f - Flanger::Flanger(float32_t sampling_rate, float32_t delay_time, float32_t frequency, float32_t depth, float32_t feedback) : FXElement(sampling_rate), MaxDelayLineSize(static_cast(2.0f * MAX_FLANGER_DELAY * sampling_rate / 1000.0f)), diff --git a/src/fx_flanger.h b/src/fx_flanger.h index 56fafc4..aea9dc9 100644 --- a/src/fx_flanger.h +++ b/src/fx_flanger.h @@ -20,6 +20,8 @@ #include "fx_components.h" +#define MAX_FLANGER_DELAY 20.0f + class Flanger : public FXElement { DISALLOW_COPY_AND_ASSIGN(Flanger); diff --git a/src/fx_phaser.cpp b/src/fx_phaser.cpp index faab36a..ad133ed 100644 --- a/src/fx_phaser.cpp +++ b/src/fx_phaser.cpp @@ -27,7 +27,7 @@ void PhaserParameter::computeCoefficients() void PhaserParameter::setFrequency(float32_t frequency) { - this->frequency_ = constrain(frequency, 0.1, 10.0); + this->frequency_ = frequency; this->computeCoefficients(); } @@ -75,7 +75,7 @@ void PhaserStage::processSample(float32_t inL, float32_t inR, float32_t& outL, f Phaser::Phaser(float32_t sampling_rate, float32_t frequency, float32_t q) : FXElement(sampling_rate), params_(sampling_rate, frequency, q), - lfo_(sampling_rate, LFO::Waveform::Sine, 0.1f, 10.0f) + lfo_(sampling_rate, LFO::Waveform::Sine, 0.01f, 1.0f) { for(unsigned i = 0; i < NUM_PHASER_STAGES; ++i) { @@ -109,13 +109,13 @@ void Phaser::processSample(float32_t inL, float32_t inR, float32_t& outL, float3 void Phaser::setFrequency(float32_t frequency) { - this->params_.setFrequency(frequency); this->lfo_.setNormalizedFrequency(frequency); + this->params_.setFrequency(this->lfo_.getFrequency()); } inline float32_t Phaser::getFrequency() const { - return this->params_.getFrequency(); + return this->lfo_.getNormalizedFrequency(); } void Phaser::setResonance(float32_t q) diff --git a/src/fx_rack.cpp b/src/fx_rack.cpp index f2a9cde..9b855d9 100644 --- a/src/fx_rack.cpp +++ b/src/fx_rack.cpp @@ -15,7 +15,7 @@ FXRack::FXRack(float32_t sampling_rate, bool enable, float32_t wet) : this->fxOrbitone_ = new FXUnit(sampling_rate); this->fxPhaser_ = new FXUnit(sampling_rate); this->fxTapeDelay_ = new FXUnit(sampling_rate); - this->fxShimmerReverb_ = new FXUnit(sampling_rate); + this->fxShimmerReverb_ = new ShimmerReverb2(sampling_rate); this->registerFX(this->fxTube_); this->registerFX(this->fxChorus_); @@ -144,7 +144,7 @@ FXUnit* FXRack::getTapeDelay() return this->fxTapeDelay_; } -FXUnit* FXRack::getShimmerReverb() +ShimmerReverb2* FXRack::getShimmerReverb() { return this->fxShimmerReverb_; } diff --git a/src/fx_rack.h b/src/fx_rack.h index 558c168..3477035 100644 --- a/src/fx_rack.h +++ b/src/fx_rack.h @@ -19,75 +19,17 @@ #pragma once #include "fx.h" +#include "fx_unit.hpp" #include "fx_tube.h" #include "fx_chorus.h" #include "fx_flanger.h" #include "fx_orbitone.h" #include "fx_phaser.h" #include "fx_tape_delay.h" -#include "fx_shimmer_reverb.h" +#include "fx_shimmer_reverb2.h" #include -template -class FXUnit : public virtual _FXElement -{ - DISALLOW_COPY_AND_ASSIGN(FXUnit); - -public: - FXUnit(float32_t sampling_rate, bool enable = true, float32_t wet_level = 0.5f) : - _FXElement(sampling_rate) - { - this->setEnable(enable); - this->setWetLevel(wet_level); - } - - virtual ~FXUnit() - { - } - - void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) - { - if(!this->isEnable() || this->getWetLevel() == 0.0f) - { - outL = inL; - outR = inR; - } - else - { - _FXElement::processSample(inL, inR, outL, outR); - - float32_t dry = 1.0f - this->getWetLevel(); - outL = this->getWetLevel() * outL + dry * inL; - outR = this->getWetLevel() * outR + dry * inR; - } - } - - void setEnable(bool enable = true) - { - this->enable_ = enable; - } - - inline bool isEnable() const - { - return this->enable_; - } - - void setWetLevel(float32_t wet_level) - { - this->wet_level_ = constrain(wet_level, 0.0f, 1.0f); - } - - inline float32_t getWetLevel() const - { - return this->wet_level_; - } - -private: - bool enable_; - float32_t wet_level_; // How much the signal is affected by the inner FX (0.0 - 1.0) -}; - typedef std::vector FXChain; class FXRack : virtual public FX, virtual public FXElement @@ -113,7 +55,7 @@ public: FXUnit* getOrbitone(); FXUnit* getPhaser(); FXUnit* getTapeDelay(); - FXUnit* getShimmerReverb(); + ShimmerReverb2* getShimmerReverb(); private: void registerFX(FXElement* fx); @@ -128,5 +70,5 @@ private: FXUnit* fxOrbitone_; FXUnit* fxPhaser_; FXUnit* fxTapeDelay_; - FXUnit* fxShimmerReverb_; + ShimmerReverb2* fxShimmerReverb_; }; \ No newline at end of file diff --git a/src/fx_shimmer_reverb.cpp b/src/fx_shimmer_reverb.cpp index ed5642c..2541482 100644 --- a/src/fx_shimmer_reverb.cpp +++ b/src/fx_shimmer_reverb.cpp @@ -96,9 +96,8 @@ float32_t ShimmerReverb::getRightDelayTime() const void ShimmerReverb::setShimmerFrequency(float32_t frequency) { - const static float32_t M2PI = 2.0f * PI; this->shimmer_frequency_ = constrain(frequency, 0.0f, 1.0f); - this->shimmer_phase_increment_ = M2PI * mapfloat(this->shimmer_frequency_, 0.0f, 1.0f, 20.0f, 20000.0f) / this->getSamplingRate(); + this->shimmer_phase_increment_ = Constants::M2PI * mapfloat(this->shimmer_frequency_, 0.0f, 1.0f, 20.0f, 20000.0f) / this->getSamplingRate(); } float32_t ShimmerReverb::getShimmerFrequency() const diff --git a/src/fx_shimmer_reverb.h b/src/fx_shimmer_reverb.h index 6263d97..3c99a75 100644 --- a/src/fx_shimmer_reverb.h +++ b/src/fx_shimmer_reverb.h @@ -19,7 +19,7 @@ // #pragma once -#include "fx.h" +#include "fx_components.h" class ShimmerReverb : public FXElement { diff --git a/src/fx_shimmer_reverb2.cpp b/src/fx_shimmer_reverb2.cpp new file mode 100644 index 0000000..bde9494 --- /dev/null +++ b/src/fx_shimmer_reverb2.cpp @@ -0,0 +1,116 @@ +#include "fx_shimmer_reverb2.h" + +#include +#include + +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(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(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_; +} diff --git a/src/fx_shimmer_reverb2.h b/src/fx_shimmer_reverb2.h new file mode 100644 index 0000000..26ffbda --- /dev/null +++ b/src/fx_shimmer_reverb2.h @@ -0,0 +1,67 @@ +// 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 . +// + +// +// 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) +}; diff --git a/src/fx_tape_delay.cpp b/src/fx_tape_delay.cpp index 550dce1..7be5600 100644 --- a/src/fx_tape_delay.cpp +++ b/src/fx_tape_delay.cpp @@ -3,7 +3,7 @@ #include #define MAX_DELAY_TIME 1.0f -#define MAX_FLUTTER_DELAY_TIME 0.1f +#define MAX_FLUTTER_DELAY_TIME 0.01f #define LPF_CUTOFF_REF 14000.0f #define HPF_CUTOFF_REF 60.0f @@ -40,8 +40,7 @@ TapeDelay::TapeDelay(const float32_t sampling_rate, float32_t default_delay_time read_pos_L_(0), read_pos_R_(0), filter_(sampling_rate), - rnd_generator_(rnd_device_()), - rnd_distribution_(-1.0f, 1.0f) + jitter_generator_(sampling_rate) { this->buffer_L_ = new float32_t[this->MaxSampleDelayTime]; this->buffer_R_ = new float32_t[this->MaxSampleDelayTime]; @@ -52,7 +51,7 @@ TapeDelay::TapeDelay(const float32_t sampling_rate, float32_t default_delay_time this->setLeftDelayTime(default_delay_time); this->setRightDelayTime(default_delay_time); this->setFlutterLevel(default_flutter_level); - this->setFeedbakLevel(default_feedback_level); + this->setFeedbak(default_feedback_level); } TapeDelay::~TapeDelay() @@ -63,28 +62,21 @@ TapeDelay::~TapeDelay() void TapeDelay::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { -int step = 0; -cout << "Delay processing" << endl; - -cout << "Processing #" << (++step) << ": Calculate the fluttered delay time" << endl; // Calculate the fluttered delay time float32_t fluttered_delay_time = this->getFlutteredDelayTime(); this->filter_.setCutoffChangeRatio(fluttered_delay_time); - float32_t fluttered_delay_time_L = (MAX_DELAY_TIME * this->getLeftDelayTime() + fluttered_delay_time) * this->getSamplingRate(); - float32_t fluttered_delay_time_R = (MAX_DELAY_TIME * this->getRightDelayTime() + fluttered_delay_time) * this->getSamplingRate(); + float32_t fluttered_delay_time_L = (MAX_DELAY_TIME * this->getLeftDelayTime() * (1.0f + fluttered_delay_time)) * this->getSamplingRate(); + float32_t fluttered_delay_time_R = (MAX_DELAY_TIME * this->getRightDelayTime() * (1.0f + fluttered_delay_time)) * this->getSamplingRate(); -cout << "Processing #" << (++step) << ": Calculate write positions" << endl; // Calculate write positions unsigned write_pos_L = static_cast(this->MaxSampleDelayTime + this->read_pos_L_ + fluttered_delay_time_L) % this->MaxSampleDelayTime; unsigned write_pos_R = static_cast(this->MaxSampleDelayTime + this->read_pos_R_ + fluttered_delay_time_R) % this->MaxSampleDelayTime; -cout << "Processing #" << (++step) << ": Write input to delay buffers" << endl; // Write input to delay buffers this->buffer_L_[write_pos_L] = inL; this->buffer_R_[write_pos_R] = inR; -cout << "Processing #" << (++step) << ": Read from delay buffers and apply feedback" << endl; // Read from delay buffers and apply feedback this->filter_.processSample( this->buffer_L_[this->read_pos_L_], @@ -92,13 +84,10 @@ cout << "Processing #" << (++step) << ": Read from delay buffers and apply feedb outL, outR ); - // outL = this->buffer_L_[this->read_pos_L_]; - // outR = this->buffer_R_[this->read_pos_R_]; this->buffer_L_[write_pos_L] += outL * this->getFeedbackLevel(); this->buffer_R_[write_pos_R] += outR * this->getFeedbackLevel(); -cout << "Processing #" << (++step) << ": Increment read positions" << endl; // Increment read positions ++this->read_pos_L_; if(this->read_pos_L_ >= this->MaxSampleDelayTime) @@ -110,7 +99,6 @@ cout << "Processing #" << (++step) << ": Increment read positions" << endl; { this->read_pos_R_ -= this->MaxSampleDelayTime; } -cout << "Processing #" << (++step) << ": Completed" << endl; } void TapeDelay::setLeftDelayTime(float32_t delay_time) @@ -136,6 +124,8 @@ float32_t TapeDelay::getRightDelayTime() const void TapeDelay::setFlutterLevel(float32_t flutter_level) { this->flutter_level_ = constrain(flutter_level, 0.0f, 1.0f); + this->jitter_generator_.setSpeed(0.2f * (1.0f - this->flutter_level_)); + this->jitter_generator_.setMagnitude(this->flutter_level_ / 100.0f); } float32_t TapeDelay::getFlutterLevel() const @@ -143,7 +133,7 @@ float32_t TapeDelay::getFlutterLevel() const return this->flutter_level_; } -void TapeDelay::setFeedbakLevel(float32_t feedback) +void TapeDelay::setFeedbak(float32_t feedback) { this->feedback_ = constrain(feedback, 0.0, 1.0); } @@ -156,7 +146,7 @@ float32_t TapeDelay::getFeedbackLevel() const float32_t TapeDelay::getFlutteredDelayTime() { // Genarate a random number in the range [-1.0 , 1.0] - float32_t r = this->rnd_distribution_(this->rnd_generator_); + float32_t r = this->jitter_generator_.process(); // Scale and bias the random number to the desired flutter range return MAX_FLUTTER_DELAY_TIME * r * this->getFlutterLevel(); diff --git a/src/fx_tape_delay.h b/src/fx_tape_delay.h index 78ccea0..e641631 100644 --- a/src/fx_tape_delay.h +++ b/src/fx_tape_delay.h @@ -19,7 +19,7 @@ // #pragma once -#include "fx.h" +#include "fx_components.h" #include "fx_svf.h" #include @@ -41,30 +41,6 @@ class TapeDelay : public FXElement void setCutoffChangeRatio(float32_t ratio); private: - // void processSampleLPF(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR); - // void processSampleHPF(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR); - - - // float32_t a0_lpf_; - // float32_t a1_lpf_; - // float32_t a2_lpf_; - // float32_t b1_lpf_; - // float32_t b2_lpf_; - // float32_t x1_lpf_[2]; - // float32_t x2_lpf_[2]; - // float32_t y1_lpf_[2]; - // float32_t y2_lpf_[2]; - - // float32_t a0_hpf_; - // float32_t a1_hpf_; - // float32_t a2_hpf_; - // float32_t b1_hpf_; - // float32_t b2_hpf_; - // float32_t x1_hpf_[2]; - // float32_t x2_hpf_[2]; - // float32_t y1_hpf_[2]; - // float32_t y2_hpf_[2]; - StateVariableFilter lpf_; StateVariableFilter hpf_; }; @@ -85,7 +61,7 @@ public: void setFlutterLevel(float32_t flutter_level); float32_t getFlutterLevel() const; - void setFeedbakLevel(float32_t feedback); + void setFeedbak(float32_t feedback); float32_t getFeedbackLevel() const; private: @@ -103,8 +79,5 @@ private: float32_t feedback_; // Feedback (0.0 - 1.0) LowHighPassFilter filter_; - - std::random_device rnd_device_; - std::mt19937 rnd_generator_; - std::uniform_real_distribution rnd_distribution_; + JitterGenerator jitter_generator_; }; diff --git a/src/fx_tube.cpp b/src/fx_tube.cpp index 8e8feba..ed91eb1 100644 --- a/src/fx_tube.cpp +++ b/src/fx_tube.cpp @@ -2,11 +2,10 @@ #include -Tube::Tube(float32_t samplingRate, float32_t curve, float32_t bias) : - FXElement(samplingRate), - TubeCurve(curve), - TubeBias(bias) +Tube::Tube(float32_t samplingRate) : + FXElement(samplingRate) { + this->setOverdrive(0.0f); } Tube::~Tube() @@ -15,43 +14,14 @@ Tube::~Tube() void Tube::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { - float32_t absInL = abs(inL); - - float32_t coeff = this->TubeCurve + this->getOverdrive(); - - if(absInL > this->TubeBias) - { - outL = coeff * (absInL - this->TubeBias) / (1.0f - this->TubeBias); - } - else - { - outL = coeff * absInL / (1.0f + this->TubeBias * absInL); - } - - if(inL < 0.0f) - { - outL = -outL; - } - - float32_t absInR = abs(inR); - if(absInR > this->TubeBias) - { - outR = coeff * (absInR - this->TubeBias) / (1.0f - this->TubeBias); - } - else - { - outR = coeff * absInR / (1.0f + this->TubeBias * absInR); - } - - if(inR < 0.0f) - { - outR = -outR; - } + outL = softSaturate(inL, this->threshold_); + outR = softSaturate(inR, this->threshold_); } void Tube::setOverdrive(float32_t overdrive) { this->overdrive_ = constrain(overdrive, 0.0f, 1.0f); + this->threshold_ = 1.0f - this->overdrive_; } float32_t Tube::getOverdrive() const diff --git a/src/fx_tube.h b/src/fx_tube.h index c1b2a2b..00b7e76 100644 --- a/src/fx_tube.h +++ b/src/fx_tube.h @@ -18,14 +18,14 @@ // #pragma once -#include "fx.h" +#include "fx_components.h" class Tube : public FXElement { DISALLOW_COPY_AND_ASSIGN(Tube); public: - Tube(float32_t sampling_rate, float32_t curve = 2.0f, float32_t bias = 0.7f); + Tube(float32_t sampling_rate); virtual ~Tube(); virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override; @@ -34,8 +34,6 @@ public: float32_t getOverdrive() const; private: - const float32_t TubeCurve; - const float32_t TubeBias; - float32_t overdrive_; + float32_t threshold_; }; \ No newline at end of file diff --git a/src/fx_unit.hpp b/src/fx_unit.hpp new file mode 100644 index 0000000..f899cd8 --- /dev/null +++ b/src/fx_unit.hpp @@ -0,0 +1,99 @@ +// 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 . + +// +// fx_unit.h +// +// Unit of FX that handle enable and wet parameters +// +#pragma once + +#include "fx_components.h" + +class FXUnitModule +{ + DISALLOW_COPY_AND_ASSIGN(FXUnitModule); + +public: + FXUnitModule(bool enable = true, float32_t wet_level = 0.5f) + { + this->setEnable(enable); + this->setWetLevel(wet_level); + } + + virtual ~FXUnitModule() + { + } + + virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) = 0; + + void setEnable(bool enable = true) + { + this->enable_ = enable; + } + + inline bool isEnable() const + { + return this->enable_; + } + + void setWetLevel(float32_t wet_level) + { + this->wet_level_ = constrain(wet_level, 0.0f, 1.0f); + } + + inline float32_t getWetLevel() const + { + return this->wet_level_; + } + +protected: + bool enable_; + float32_t wet_level_; // How much the signal is affected by the inner FX (0.0 - 1.0) +}; + +template +class FXUnit : public virtual FXUnitModule, public virtual _FXElement +{ + DISALLOW_COPY_AND_ASSIGN(FXUnit); + +public: + FXUnit(float32_t sampling_rate, bool enable = true, float32_t wet_level = 0.5f) : + FXUnitModule(), + _FXElement(sampling_rate) + { + this->setEnable(enable); + this->setWetLevel(wet_level); + } + + virtual ~FXUnit() + { + } + + void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) + { + if(!this->isEnable() || this->getWetLevel() == 0.0f) + { + outL = inL; + outR = inR; + } + else + { + _FXElement::processSample(inL, inR, outL, outR); + + float32_t dry = 1.0f - this->getWetLevel(); + outL = this->getWetLevel() * outL + dry * inL; + outR = this->getWetLevel() * outR + dry * inR; + } + } +}; \ No newline at end of file diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 34d7f21..cc94a71 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -208,11 +208,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, // FXChain > ShimmerReverb parameters this->SetParameter(ParameterFXChainShimmerReverbEnable, 1); this->SetParameter(ParameterFXChainShimmerReverbWet, 70); - this->SetParameter(ParameterFXChainShimmerReverbDelayTimeLeft, 15); - this->SetParameter(ParameterFXChainShimmerReverbDelayTimeRight, 22); - this->SetParameter(ParameterFXChainShimmerReverbFrequency, 20); - this->SetParameter(ParameterFXChainShimmerReverbAmplitude, 15); - this->SetParameter(ParameterFXChainShimmerReverbDecayTime, 65); + this->SetParameter(ParameterFXChainShimmerReverbDecay, 30); + this->SetParameter(ParameterFXChainShimmerReverbDiffusion, 80); + this->SetParameter(ParameterFXChainShimmerReverbPitchShift, 99); #endif // END setup FXRack }; @@ -749,13 +747,13 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainEnable(!!nValue); + this->fx_rack->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainWet(nValue / 99.0f); + this->fx_rack->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -763,19 +761,19 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainTubeEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainTubeEnable(!!nValue); + this->fx_rack->getTube()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainTubeWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTubeWet(nValue / 99.0f); + this->fx_rack->getTube()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainTubeOverdrive: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTubeOverdrive(nValue / 99.0f); + this->fx_rack->getTube()->setOverdrive(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -783,31 +781,31 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainChorusEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainChorusEnable(!!nValue); + this->fx_rack->getChorus()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainChorusWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainChorusWet(nValue / 99.0f); + this->fx_rack->getChorus()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainChorusRate: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainChorusRate(mapfloat(nValue, 0, 99, 0.1f, 1.0f)); + this->fx_rack->getChorus()->setRate(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainChorusDepth: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainChorusDepth(nValue / 9.9f); + this->fx_rack->getChorus()->setDepth(nValue / 9.9f); this->m_FXSpinLock.Release(); break; case ParameterFXChainChorusFeedback: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainChorusFeedback(nValue / 99.0f); + this->fx_rack->getChorus()->setFeedback(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -815,37 +813,37 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainFlangerEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainFlangerEnable(!!nValue); + this->fx_rack->getFlanger()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainFlangerWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainFlangerWet(nValue / 99.0f); + 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->setFXChainFlangerDelayTime(nValue / 9.9f); + 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->setFXChainFlangerRate(0.1f + nValue / 9.8f); + this->fx_rack->getFlanger()->setFrequency(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainFlangerDepth: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainFlangerDepth(nValue / 9.9f); + this->fx_rack->getFlanger()->setDepth(mapfloat(nValue, 0, 99, 0.0f, MAX_FLANGER_DELAY)); this->m_FXSpinLock.Release(); break; case ParameterFXChainFlangerFeedback: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainFlangerFeedback(nValue / 99.0f); + this->fx_rack->getFlanger()->setFeedback(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -853,19 +851,19 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainOrbitoneEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainOrbitoneEnable(!!nValue); + this->fx_rack->getOrbitone()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainOrbitoneWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainOrbitoneWet(nValue / 99.0f); + this->fx_rack->getOrbitone()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainOrbitoneFeedback: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainOrbitoneFeedback(nValue / 99.0f); + this->fx_rack->getOrbitone()->setFeedback(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -873,25 +871,25 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainPhaserEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainPhaserEnable(!!nValue); + this->fx_rack->getPhaser()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainPhaserWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainPhaserWet(nValue / 99.0f); + this->fx_rack->getPhaser()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainPhaserRate: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainPhaserRate(mapfloat(nValue, 0, 99, 0.01f, 5.0f)); + this->fx_rack->getPhaser()->setFrequency(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainPhaserResonance: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainPhaserResonance(mapfloat(nValue, 0, 99, 0.5f, 10.0f)); + this->fx_rack->getPhaser()->setResonance(mapfloat(nValue, 0, 99, 0.5f, 10.0f)); this->m_FXSpinLock.Release(); break; @@ -899,37 +897,37 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainTapeDelayEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayEnable(!!nValue); + this->fx_rack->getTapeDelay()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainTapeDelayWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayWet(nValue / 99.0f); + this->fx_rack->getTapeDelay()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainTapeDelayLeftDelayTime: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayLeftDelayTime(nValue / 99.0f); + this->fx_rack->getTapeDelay()->setLeftDelayTime(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainTapeDelayRightDelayTime: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayRightDelayTime(nValue / 99.0f); + this->fx_rack->getTapeDelay()->setRightDelayTime(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainTapeDelayFlutter: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayFlutter(nValue / 99.0f); + this->fx_rack->getTapeDelay()->setFlutterLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; case ParameterFXChainTapeDelayFeedback: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainTapeDelayFeedback(nValue / 99.0f); + this->fx_rack->getTapeDelay()->setFeedbak(nValue / 99.0f); this->m_FXSpinLock.Release(); break; @@ -937,43 +935,31 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) case ParameterFXChainShimmerReverbEnable: nValue = constrain((int)nValue, 0, 1); this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbEnable(!!nValue); + this->fx_rack->getShimmerReverb()->setEnable(!!nValue); this->m_FXSpinLock.Release(); break; case ParameterFXChainShimmerReverbWet: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbWet(nValue / 99.0f); + this->fx_rack->getShimmerReverb()->setWetLevel(nValue / 99.0f); this->m_FXSpinLock.Release(); break; - case ParameterFXChainShimmerReverbDelayTimeLeft: + case ParameterFXChainShimmerReverbDecay: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbDelayTimeLeft(nValue / 99.0f); + this->fx_rack->getShimmerReverb()->setDecay(mapfloat(nValue, 0, 99, SHIMMER_MIN_DECAY, SHIMMER_MAX_DECAY)); this->m_FXSpinLock.Release(); break; - case ParameterFXChainShimmerReverbDelayTimeRight: + case ParameterFXChainShimmerReverbDiffusion: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbDelayTimeRight(nValue / 99.0f); + this->fx_rack->getShimmerReverb()->setDiffusion(nValue / 99.0f); this->m_FXSpinLock.Release(); break; - case ParameterFXChainShimmerReverbFrequency: + case ParameterFXChainShimmerReverbPitchShift: nValue = constrain((int)nValue, 0, 99); this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbFrequency(nValue / 99.0f); - this->m_FXSpinLock.Release(); - break; - case ParameterFXChainShimmerReverbAmplitude: - nValue = constrain((int)nValue, 0, 99); - this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbAmplitude(nValue / 99.0f); - this->m_FXSpinLock.Release(); - break; - case ParameterFXChainShimmerReverbDecayTime: - nValue = constrain((int)nValue, 0, 99); - this->m_FXSpinLock.Acquire(); - this->setFXChainShimmerReverbDecayTime(nValue / 99.0f); + this->fx_rack->getShimmerReverb()->setPitchShift(mapfloat(nValue, 0, 99, SHIMMER_MIN_PITCH_RATIO, SHIMMER_MAX_PITCH_RATIO)); this->m_FXSpinLock.Release(); break; #endif @@ -1429,11 +1415,9 @@ 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.SetFXChainShimmerReverbDelayTimeLeft(this->m_nParameter[ParameterFXChainShimmerReverbDelayTimeLeft]); - this->m_PerformanceConfig.SetFXChainShimmerReverbDelayTimeRight(this->m_nParameter[ParameterFXChainShimmerReverbDelayTimeRight]); - this->m_PerformanceConfig.SetFXChainShimmerReverbFrequency(this->m_nParameter[ParameterFXChainShimmerReverbFrequency]); - this->m_PerformanceConfig.SetFXChainShimmerReverbAmplitude(this->m_nParameter[ParameterFXChainShimmerReverbAmplitude]); - this->m_PerformanceConfig.SetFXChainShimmerReverbDecayTime(this->m_nParameter[ParameterFXChainShimmerReverbDecayTime]); + this->m_PerformanceConfig.SetFXChainShimmerReverbDecay(this->m_nParameter[ParameterFXChainShimmerReverbDecay]); + this->m_PerformanceConfig.SetFXChainShimmerReverbDiffusion(this->m_nParameter[ParameterFXChainShimmerReverbDiffusion]); + this->m_PerformanceConfig.SetFXChainShimmerReverbPitchShift(this->m_nParameter[ParameterFXChainShimmerReverbPitchShift]); #endif // END FXRack parameters @@ -1858,11 +1842,9 @@ 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(ParameterFXChainShimmerReverbDelayTimeLeft, this->m_PerformanceConfig.GetFXChainShimmerReverbDelayTimeLeft()); - this->SetParameter(ParameterFXChainShimmerReverbDelayTimeRight, this->m_PerformanceConfig.GetFXChainShimmerReverbDelayTimeRight()); - this->SetParameter(ParameterFXChainShimmerReverbFrequency, this->m_PerformanceConfig.GetFXChainShimmerReverbFrequency()); - this->SetParameter(ParameterFXChainShimmerReverbAmplitude, this->m_PerformanceConfig.GetFXChainShimmerReverbAmplitude()); - this->SetParameter(ParameterFXChainShimmerReverbDecayTime, this->m_PerformanceConfig.GetFXChainShimmerReverbDecayTime()); + this->SetParameter(ParameterFXChainShimmerReverbDecay, this->m_PerformanceConfig.GetFXChainShimmerReverbDecay()); + this->SetParameter(ParameterFXChainShimmerReverbDiffusion, this->m_PerformanceConfig.GetFXChainShimmerReverbDiffusion()); + this->SetParameter(ParameterFXChainShimmerReverbPitchShift, this->m_PerformanceConfig.GetFXChainShimmerReverbPitchShift()); #endif } @@ -2047,186 +2029,3 @@ unsigned CMiniDexed::getModController (unsigned controller, unsigned parameter, } } - -#ifdef FXRACK_ENABLE -void CMiniDexed::setFXChainEnable(bool value) -{ - this->fx_rack->setEnable(value); -} - -void CMiniDexed::setFXChainWet(float32_t value) -{ - this->fx_rack->setWetLevel(value); -} - -void CMiniDexed::setFXChainTubeEnable(bool value) -{ - this->fx_rack->getTube()->setEnable(value); -} - -void CMiniDexed::setFXChainTubeWet(float32_t value) -{ - this->fx_rack->getTube()->setWetLevel(value); -} - -void CMiniDexed::setFXChainTubeOverdrive(float32_t value) -{ - this->fx_rack->getTube()->setOverdrive(value); -} - -void CMiniDexed::setFXChainChorusEnable(bool value) -{ - this->fx_rack->getChorus()->setEnable(value); -} - -void CMiniDexed::setFXChainChorusWet(float32_t value) -{ - this->fx_rack->getChorus()->setWetLevel(value); -} - -void CMiniDexed::setFXChainChorusRate(float32_t value) -{ - this->fx_rack->getChorus()->setRate(value); -} - -void CMiniDexed::setFXChainChorusDepth(float32_t value) -{ - this->fx_rack->getChorus()->setDepth(value); -} - -void CMiniDexed::setFXChainChorusFeedback(float32_t value) -{ - this->fx_rack->getChorus()->setFeedback(value); -} - -void CMiniDexed::setFXChainFlangerEnable(bool value) -{ - this->fx_rack->getFlanger()->setEnable(value); -} - -void CMiniDexed::setFXChainFlangerWet(float32_t value) -{ - this->fx_rack->getFlanger()->setWetLevel(value); -} - -void CMiniDexed::setFXChainFlangerDelayTime(float32_t value) -{ - this->fx_rack->getFlanger()->setDelayTime(value); -} - -void CMiniDexed::setFXChainFlangerRate(float32_t value) -{ - this->fx_rack->getFlanger()->setFrequency(value); -} - -void CMiniDexed::setFXChainFlangerDepth(float32_t value) -{ - this->fx_rack->getFlanger()->setDepth(value); -} - -void CMiniDexed::setFXChainFlangerFeedback(float32_t value) -{ - this->fx_rack->getFlanger()->setFeedback(value); -} - -void CMiniDexed::setFXChainOrbitoneEnable(bool value) -{ - this->fx_rack->getOrbitone()->setEnable(value); -} - -void CMiniDexed::setFXChainOrbitoneWet(float32_t value) -{ - this->fx_rack->getOrbitone()->setWetLevel(value); -} - -void CMiniDexed::setFXChainOrbitoneFeedback(float32_t value) -{ - this->fx_rack->getOrbitone()->setFeedback(value); -} - -void CMiniDexed::setFXChainPhaserEnable(bool value) -{ - this->fx_rack->getPhaser()->setEnable(value); -} - -void CMiniDexed::setFXChainPhaserWet(float32_t value) -{ - this->fx_rack->getPhaser()->setWetLevel(value); -} - -void CMiniDexed::setFXChainPhaserRate(float32_t value) -{ - this->fx_rack->getPhaser()->setFrequency(value); -} - -void CMiniDexed::setFXChainPhaserResonance(float32_t value) -{ - this->fx_rack->getPhaser()->setResonance(value); -} - -void CMiniDexed::setFXChainTapeDelayEnable(bool value) -{ - this->fx_rack->getTapeDelay()->setEnable(value); -} - -void CMiniDexed::setFXChainTapeDelayWet(float32_t value) -{ - this->fx_rack->getTapeDelay()->setWetLevel(value); -} - -void CMiniDexed::setFXChainTapeDelayLeftDelayTime(float32_t value) -{ - this->fx_rack->getTapeDelay()->setLeftDelayTime(value); -} - -void CMiniDexed::setFXChainTapeDelayRightDelayTime(float32_t value) -{ - this->fx_rack->getTapeDelay()->setRightDelayTime(value); -} - -void CMiniDexed::setFXChainTapeDelayFlutter(float32_t value) -{ - this->fx_rack->getTapeDelay()->setFlutterLevel(value); -} - -void CMiniDexed::setFXChainTapeDelayFeedback(float32_t value) -{ - this->fx_rack->getTapeDelay()->setFeedbakLevel(value); -} - -void CMiniDexed::setFXChainShimmerReverbEnable(bool value) -{ - this->fx_rack->getShimmerReverb()->setEnable(value); -} - -void CMiniDexed::setFXChainShimmerReverbWet(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setWetLevel(value); -} - -void CMiniDexed::setFXChainShimmerReverbDelayTimeLeft(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setLeftDelayTime(value); -} - -void CMiniDexed::setFXChainShimmerReverbDelayTimeRight(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setRightDelayTime(value); -} - -void CMiniDexed::setFXChainShimmerReverbFrequency(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setShimmerFrequency(value); -} - -void CMiniDexed::setFXChainShimmerReverbAmplitude(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setShimmerAmplitude(value); -} - -void CMiniDexed::setFXChainShimmerReverbDecayTime(float32_t value) -{ - this->fx_rack->getShimmerReverb()->setDecayTime(value); -} - -#endif \ No newline at end of file diff --git a/src/minidexed.h b/src/minidexed.h index 604ee5d..496e832 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -188,11 +188,9 @@ public: // FXChain > ShimmerReverb parameters ParameterFXChainShimmerReverbEnable, ParameterFXChainShimmerReverbWet, - ParameterFXChainShimmerReverbDelayTimeLeft, - ParameterFXChainShimmerReverbDelayTimeRight, - ParameterFXChainShimmerReverbFrequency, - ParameterFXChainShimmerReverbAmplitude, - ParameterFXChainShimmerReverbDecayTime, + ParameterFXChainShimmerReverbDecay, + ParameterFXChainShimmerReverbDiffusion, + ParameterFXChainShimmerReverbPitchShift, #endif // END FXRack global parameters definition @@ -264,47 +262,6 @@ public: void setMasterVolume (float32_t vol); - // BEGIN FXRack parameters setters - #ifdef FXRACK_ENABLE - void setFXChainEnable(bool value); - void setFXChainWet(float32_t value); - void setFXChainTubeEnable(bool value); - void setFXChainTubeWet(float32_t value); - void setFXChainTubeOverdrive(float32_t value); - void setFXChainChorusEnable(bool value); - void setFXChainChorusWet(float32_t value); - void setFXChainChorusRate(float32_t value); - void setFXChainChorusDepth(float32_t value); - void setFXChainChorusFeedback(float32_t value); - void setFXChainFlangerEnable(bool value); - void setFXChainFlangerWet(float32_t value); - void setFXChainFlangerDelayTime(float32_t value); - void setFXChainFlangerRate(float32_t value); - void setFXChainFlangerDepth(float32_t value); - void setFXChainFlangerFeedback(float32_t value); - void setFXChainOrbitoneEnable(bool value); - void setFXChainOrbitoneWet(float32_t value); - void setFXChainOrbitoneFeedback(float32_t value); - void setFXChainPhaserEnable(bool value); - void setFXChainPhaserWet(float32_t value); - void setFXChainPhaserRate(float32_t value); - void setFXChainPhaserResonance(float32_t value); - void setFXChainTapeDelayEnable(bool value); - void setFXChainTapeDelayWet(float32_t value); - void setFXChainTapeDelayLeftDelayTime(float32_t value); - void setFXChainTapeDelayRightDelayTime(float32_t value); - void setFXChainTapeDelayFlutter(float32_t value); - void setFXChainTapeDelayFeedback(float32_t value); - void setFXChainShimmerReverbEnable(bool value); - void setFXChainShimmerReverbWet(float32_t value); - void setFXChainShimmerReverbDelayTimeLeft(float32_t value); - void setFXChainShimmerReverbDelayTimeRight(float32_t value); - void setFXChainShimmerReverbFrequency(float32_t value); - void setFXChainShimmerReverbAmplitude(float32_t value); - void setFXChainShimmerReverbDecayTime(float32_t value); - #endif - // END FXRack parameters setters - private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note uint8_t m_uchOPMask[CConfig::ToneGenerators]; diff --git a/src/performance.ini b/src/performance.ini index ba7d028..b1f440a 100644 --- a/src/performance.ini +++ b/src/performance.ini @@ -36,7 +36,7 @@ BankNumber1=0 VoiceNumber1=1 MIDIChannel1=255 Volume1=100 -Pan1=0 +Pan1=64 Detune1=-11 Cutoff1=99 Resonance1=0 @@ -64,7 +64,7 @@ AftertouchTarget1=0 BankNumber2=0 VoiceNumber2=1 MIDIChannel2=255 -Volume2=100 +Volume2=0 Pan2=127 Detune2=11 Cutoff2=99 @@ -93,7 +93,7 @@ AftertouchTarget2=0 BankNumber3=0 VoiceNumber3=1 MIDIChannel3=255 -Volume3=100 +Volume3=0 Pan3=48 Detune3=-7 Cutoff3=99 @@ -122,7 +122,7 @@ AftertouchTarget3=0 BankNumber4=0 VoiceNumber4=1 MIDIChannel4=255 -Volume4=100 +Volume4=0 Pan4=80 Detune4=7 Cutoff4=99 @@ -151,7 +151,7 @@ AftertouchTarget4=0 BankNumber5=0 VoiceNumber5=1 MIDIChannel5=0 -Volume5=100 +Volume5=0 Pan5=64 Detune5=0 Cutoff5=99 @@ -180,7 +180,7 @@ AftertouchTarget5=0 BankNumber6=0 VoiceNumber6=1 MIDIChannel6=0 -Volume6=100 +Volume6=0 Pan6=64 Detune6=0 Cutoff6=99 @@ -209,7 +209,7 @@ AftertouchTarget6=0 BankNumber7=0 VoiceNumber7=1 MIDIChannel7=0 -Volume7=100 +Volume7=0 Pan7=64 Detune7=0 Cutoff7=99 @@ -238,7 +238,7 @@ AftertouchTarget7=0 BankNumber8=0 VoiceNumber8=1 MIDIChannel8=0 -Volume8=100 +Volume8=0 Pan8=64 Detune8=0 Cutoff8=99 @@ -282,3 +282,39 @@ ReverbLowDamp=50 ReverbLowPass=30 ReverbDiffusion=65 ReverbLevel=99 + +# FXRack +FXChainEnable=1 +FXChainWet=99 +FXChainTubeEnable=0 +FXChainTubeWet=50 +FXChainTubeOverdrive=10 +FXChainChorusEnable=0 +FXChainChorusWet=50 +FXChainChorusRate=15 +FXChainChorusDepth=10 +FXChainChorusFeedback=20 +FXChainFlangerEnable=0 +FXChainFlangerWet=50 +FXChainFlangerDelayTime=10 +FXChainFlangerRate=15 +FXChainFlangerDepth=10 +FXChainFlangerFeedback=20 +FXChainOrbitoneEnable=0 +FXChainOrbitoneWet=50 +FXChainOrbitoneFeedback=65 +FXChainPhaserEnable=0 +FXChainPhaserWet=50 +FXChainPhaserRate=5 +FXChainPhaserResonance=45 +FXChainTapeDelayEnable=1 +FXChainTapeDelayWet=50 +FXChainTapeDelayLeftDelayTime=15 +FXChainTapeDelayRightDelayTime=22 +FXChainTapeDelayFlutter=0 +FXChainTapeDelayFeedback=35 +FXChainShimmerReverbEnable=0 +FXChainShimmerReverbWet=70 +FXChainShimmerReverbDecay=30 +FXChainShimmerReverbDiffusion=80 +FXChainShimmerReverbPitchShift=99 diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index eb9c972..47b7ab1 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -191,11 +191,9 @@ 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_nFXChainShimmerReverbDelayTimeLeft = this->m_Properties.GetNumber("FXChainShimmerReverbDelayTimeLeft", 15); - this->m_nFXChainShimmerReverbDelayTimeRight = this->m_Properties.GetNumber("FXChainShimmerReverbDelayTimeRight", 22); - this->m_nFXChainShimmerReverbFrequency = this->m_Properties.GetNumber("FXChainShimmerReverbFrequency", 20); - this->m_nFXChainShimmerReverbAmplitude = this->m_Properties.GetNumber("FXChainShimmerReverbAmplitude", 15); - this->m_nFXChainShimmerReverbDecayTime = this->m_Properties.GetNumber("FXChainShimmerReverbDecayTime", 65); + this->m_nFXChainShimmerReverbDecay = this->m_Properties.GetNumber("FXChainShimmerReverbDecay", 30); + this->m_nFXChainShimmerReverbDiffusion = this->m_Properties.GetNumber("FXChainShimmerReverbDiffusion", 30); + this->m_nFXChainShimmerReverbPitchShift = this->m_Properties.GetNumber("FXChainShimmerReverbPitchShift", 99); #endif return bResult; @@ -348,11 +346,9 @@ 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("FXChainShimmerReverbDelayTimeLeft", m_nFXChainShimmerReverbDelayTimeLeft); - this->m_Properties.SetNumber("FXChainShimmerReverbDelayTimeRight", m_nFXChainShimmerReverbDelayTimeRight); - this->m_Properties.SetNumber("FXChainShimmerReverbFrequency", m_nFXChainShimmerReverbFrequency); - this->m_Properties.SetNumber("FXChainShimmerReverbAmplitude", m_nFXChainShimmerReverbAmplitude); - this->m_Properties.SetNumber("FXChainShimmerReverbDecayTime", m_nFXChainShimmerReverbDecayTime); + this->m_Properties.SetNumber("FXChainShimmerReverbDecay", m_nFXChainShimmerReverbDecay); + this->m_Properties.SetNumber("FXChainShimmerReverbDiffusion", m_nFXChainShimmerReverbDiffusion); + this->m_Properties.SetNumber("FXChainShimmerReverbPitchShift", m_nFXChainShimmerReverbPitchShift); #endif return m_Properties.Save (); @@ -1158,29 +1154,19 @@ unsigned CPerformanceConfig::GetFXChainShimmerReverbWet(void) const return this->m_nFXChainShimmerReverbWet; } -unsigned CPerformanceConfig::GetFXChainShimmerReverbDelayTimeLeft(void) const +unsigned CPerformanceConfig::GetFXChainShimmerReverbDecay(void) const { - return this->m_nFXChainShimmerReverbDelayTimeLeft; + return this->m_nFXChainShimmerReverbDecay; } -unsigned CPerformanceConfig::GetFXChainShimmerReverbDelayTimeRight(void) const +unsigned CPerformanceConfig::GetFXChainShimmerReverbDiffusion(void) const { - return this->m_nFXChainShimmerReverbDelayTimeRight; + return this->m_nFXChainShimmerReverbDiffusion; } -unsigned CPerformanceConfig::GetFXChainShimmerReverbFrequency(void) const +unsigned CPerformanceConfig::GetFXChainShimmerReverbPitchShift(void) const { - return this->m_nFXChainShimmerReverbFrequency; -} - -unsigned CPerformanceConfig::GetFXChainShimmerReverbAmplitude(void) const -{ - return this->m_nFXChainShimmerReverbAmplitude; -} - -unsigned CPerformanceConfig::GetFXChainShimmerReverbDecayTime(void) const -{ - return this->m_nFXChainShimmerReverbDecayTime; + return this->m_nFXChainShimmerReverbPitchShift; } void CPerformanceConfig::SetFXChainEnable(bool bValue) @@ -1338,29 +1324,19 @@ void CPerformanceConfig::SetFXChainShimmerReverbWet(unsigned nValue) this->m_nFXChainShimmerReverbWet = nValue; } -void CPerformanceConfig::SetFXChainShimmerReverbDelayTimeLeft(unsigned nValue) -{ - this->m_nFXChainShimmerReverbDelayTimeLeft = nValue; -} - -void CPerformanceConfig::SetFXChainShimmerReverbDelayTimeRight(unsigned nValue) -{ - this->m_nFXChainShimmerReverbDelayTimeRight = nValue; -} - -void CPerformanceConfig::SetFXChainShimmerReverbFrequency(unsigned nValue) +void CPerformanceConfig::SetFXChainShimmerReverbDecay(unsigned nValue) { - this->m_nFXChainShimmerReverbFrequency = nValue; + this->m_nFXChainShimmerReverbDecay = nValue; } -void CPerformanceConfig::SetFXChainShimmerReverbAmplitude(unsigned nValue) +void CPerformanceConfig::SetFXChainShimmerReverbDiffusion(unsigned nValue) { - this->m_nFXChainShimmerReverbAmplitude = nValue; + this->m_nFXChainShimmerReverbDiffusion = nValue; } -void CPerformanceConfig::SetFXChainShimmerReverbDecayTime(unsigned nValue) +void CPerformanceConfig::SetFXChainShimmerReverbPitchShift(unsigned nValue) { - this->m_nFXChainShimmerReverbDecayTime = nValue; + this->m_nFXChainShimmerReverbPitchShift = nValue; } #endif diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 09a2e70..ef42483 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -149,11 +149,9 @@ public: unsigned GetFXChainTapeDelayFeedback(void) const; bool GetFXChainShimmerReverbEnable(void) const; unsigned GetFXChainShimmerReverbWet(void) const; - unsigned GetFXChainShimmerReverbDelayTimeLeft(void) const; - unsigned GetFXChainShimmerReverbDelayTimeRight(void) const; - unsigned GetFXChainShimmerReverbFrequency(void) const; - unsigned GetFXChainShimmerReverbAmplitude(void) const; - unsigned GetFXChainShimmerReverbDecayTime(void) const; + unsigned GetFXChainShimmerReverbDecay(void) const; + unsigned GetFXChainShimmerReverbDiffusion(void) const; + unsigned GetFXChainShimmerReverbPitchShift(void) const; void SetFXChainEnable(bool bValue); void SetFXChainWet(unsigned nValue); @@ -186,11 +184,9 @@ public: void SetFXChainTapeDelayFeedback(unsigned nValue); void SetFXChainShimmerReverbEnable(unsigned nValue); void SetFXChainShimmerReverbWet(unsigned nValue); - void SetFXChainShimmerReverbDelayTimeLeft(unsigned nValue); - void SetFXChainShimmerReverbDelayTimeRight(unsigned nValue); - void SetFXChainShimmerReverbFrequency(unsigned nValue); - void SetFXChainShimmerReverbAmplitude(unsigned nValue); - void SetFXChainShimmerReverbDecayTime(unsigned nValue); + void SetFXChainShimmerReverbDecay(unsigned nValue); + void SetFXChainShimmerReverbDiffusion(unsigned nValue); + void SetFXChainShimmerReverbPitchShift(unsigned nValue); #endif bool VoiceDataFilled(unsigned nTG); @@ -292,11 +288,9 @@ private: unsigned m_nFXChainTapeDelayFeedback; bool m_bFXChainShimmerReverbEnable; unsigned m_nFXChainShimmerReverbWet; - unsigned m_nFXChainShimmerReverbDelayTimeLeft; - unsigned m_nFXChainShimmerReverbDelayTimeRight; - unsigned m_nFXChainShimmerReverbFrequency; - unsigned m_nFXChainShimmerReverbAmplitude; - unsigned m_nFXChainShimmerReverbDecayTime; + unsigned m_nFXChainShimmerReverbDecay; + unsigned m_nFXChainShimmerReverbDiffusion; + unsigned m_nFXChainShimmerReverbPitchShift; #endif }; diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 0000000..50b18b1 --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,83 @@ +CXX := gcc +CXXFLAGS := -g -O2 +DEFINES := +INCLUDES := -I../../CMSIS_5/CMSIS/DSP/Include/ -I../../CMSIS_5/CMSIS/Core/Include/ +GCC := $(CXX) $(INCLUDES) $(CXXFLAGS) + +LD := gcc +LIBS := -lm -lstdc++ + +OBJS := \ + wavein.o \ + waveout.o \ + waveplay.o \ + fx.o \ + fx_components.o \ + fx_svf.o \ + fx_tube.o \ + fx_chorus.o \ + fx_phaser.o \ + fx_orbitone.o \ + fx_flanger.o \ + fx_tape_delay.o \ + fx_shimmer_reverb2.o \ + fx_rack.o \ + fxrack_test.o + +test: fxrack_test + ./fxrack_test + +# %.o: ../%.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +wavein.o: wavein.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +waveout.o: waveout.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 $@ + +fx_components.o: ../fx_components.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_svf.o: ../fx_svf.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_tube.o: ../fx_tube.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_chorus.o: ../fx_chorus.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_phaser.o: ../fx_phaser.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_orbitone.o: ../fx_orbitone.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_flanger.o: ../fx_flanger.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_tape_delay.o: ../fx_tape_delay.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_shimmer_reverb2.o: ../fx_shimmer_reverb2.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fx_rack.o: ../fx_rack.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +fxrack_test.o: fxrack_test.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + + +fxrack_test: $(OBJS) + $(LD) $(OBJS) -o fxrack_test $(LIBS) + +clean: + rm -f *.o fxrack_test diff --git a/src/test/fxrack_test.cpp b/src/test/fxrack_test.cpp new file mode 100644 index 0000000..c691397 --- /dev/null +++ b/src/test/fxrack_test.cpp @@ -0,0 +1,136 @@ +#include "../fx_rack.h" + +#include +#include +#include +#include "wave.h" + +using namespace std; + +#define MAX_SVF_SAMPLES 10000000 +#define MAX_NB_ERRORS 100 + +void testFlutter() +{ + JitterGenerator jg(44100.0f); + jg.setSpeed(1.0f); + jg.setMagnitude(0.1f); + + for(unsigned i = 0; i < 1000; ++i) + { + cout << jg.process() << endl; + } +} + +int main() +{ + // testFlutter(); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution 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); + svf.setCutoff(12000.0f); + svf.setResonance(0.0f); + unsigned nbSamples = 0; + unsigned nbErrors = 0; + 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++; + } + cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl; + } + + cout << "Step #" << (++step) << ": Testing SVF in HPF mode" << endl; + { + svf.setFilterType(StateVariableFilter::Type::LPF); + svf.setCutoff(60.0f); + svf.setResonance(0.0f); + unsigned nbSamples = 0; + unsigned nbErrors = 0; + 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++; + } + cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl; + } + + cout << "Step #" << (++step) << ": Intanciation FXRack" << endl; + FXRack* rack = new FXRack(44100.0f); + + cout << "Step #" << (++step) << ": Test preparation" << endl; + rack->setEnable(true); + rack->setWetLevel(1.0f); + + rack->getTube()->setEnable(false); + rack->getChorus()->setEnable(false); + rack->getPhaser()->setEnable(false); + rack->getOrbitone()->setEnable(true); + 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->getShimmerReverb()->setEnable(true); + rack->getShimmerReverb()->setWetLevel(60); + rack->getShimmerReverb()->setDecay(30); + rack->getShimmerReverb()->setDiffusion(80); + rack->getShimmerReverb()->setPitchShift(99); + + const unsigned nSamples = 3000; + float32_t inSamples[2][nSamples]; + float32_t outSamples[2][nSamples]; + + for(unsigned i = 0; i < nSamples; ++i) + { + inSamples[0][i] = dist(gen); + inSamples[1][i] = dist(gen); + } + + memset(outSamples[0], 0, nSamples * sizeof(float32_t)); + memset(outSamples[1], 0, nSamples * sizeof(float32_t)); + + cout << "Step #" << (++step) << ": Run test" << endl; + rack->process(inSamples[0], inSamples[1], outSamples[0], outSamples[1], nSamples); + + cout << "Step #" << (++step) << ": Render results" << endl; + 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 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); + + playSound(sampleOutL, sampleOutR, size, 44100, 16); + + cout << "Step #" << (++step) << ": Test cleanup" << endl; + delete rack; + + return 0; +} \ No newline at end of file diff --git a/src/test/test.wav b/src/test/test.wav new file mode 100644 index 0000000..84fe1bc Binary files /dev/null and b/src/test/test.wav differ diff --git a/src/test/wave.h b/src/test/wave.h new file mode 100644 index 0000000..fc325c9 --- /dev/null +++ b/src/test/wave.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +struct WaveHeader { + char chunkId[4]; + uint32_t chunkSize; + char format[4]; + char subchunk1Id[4]; + uint32_t subchunk1Size; + uint16_t audioFormat; + uint16_t numChannels; + uint32_t sampleRate; + uint32_t byteRate; + uint16_t blockAlign; + uint16_t bitsPerSample; + char subchunk2Id[4]; + uint32_t subchunk2Size; +}; + +float32_t** readWaveFile(const std::string& fileName, unsigned& size); + +void saveWaveFile(const std::string& fileName, + 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); \ No newline at end of file diff --git a/src/test/wavein.cpp b/src/test/wavein.cpp new file mode 100644 index 0000000..6758c66 --- /dev/null +++ b/src/test/wavein.cpp @@ -0,0 +1,87 @@ +#include "wave.h" + +#include +#include + +float32_t** readWaveFile(const std::string& fileName, unsigned& size) +{ + std::ifstream file(fileName, std::ios::binary); + if(!file) + { + std::cerr << "Error opening file: " << fileName << std::endl; + return nullptr; + } + + WaveHeader header; + file.read((char*)&header, sizeof(header)); + + if(strncmp(header.chunkId, "RIFF", 4) != 0 || strncmp(header.format, "WAVE", 4) != 0) + { + std::cerr << "Error: not a WAVE file" << std::endl; + return nullptr; + } + + if(header.audioFormat != 1) + { + std::cerr << "Error: only support PCM format" << std::endl; + return nullptr; + } + + size = header.subchunk2Size / (header.bitsPerSample / 8); + float32_t* LChannel = new float32_t[size]; + float32_t* RChannel = new float32_t[size]; + + unsigned i = 0; + while(!file.eof()) + { + 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; + } + 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; + } + 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; + } + 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; + } + else + { + std::cerr << "Error: unsupported bit depth: " << header.bitsPerSample << std::endl; + return nullptr; + } + + ++i; + } + + float32_t** result = new float32_t*[2]; + result[0] = LChannel; + result[1] = RChannel; + + return result; +} diff --git a/src/test/waveout.cpp b/src/test/waveout.cpp new file mode 100644 index 0000000..7ddc7df --- /dev/null +++ b/src/test/waveout.cpp @@ -0,0 +1,84 @@ +#include "wave.h" + +#include +#include +#include + +void saveWaveFile(const std::string& fileName, + float32_t* LChannel, + float32_t* RChannel, + unsigned size, + int sampleRate, + int bitsPerSample) +{ + std::ofstream file(fileName, std::ios::binary); + if(!file) + { + std::cerr << "Error opening file: " << fileName << std::endl; + return; + } + + WaveHeader header; + std::memset(&header, 0, sizeof(header)); + header.sampleRate = sampleRate; + header.numChannels = 2; + header.bitsPerSample = bitsPerSample; + header.byteRate = header.sampleRate * header.numChannels * header.bitsPerSample / 8; + header.blockAlign = header.numChannels * header.bitsPerSample / 8; + header.subchunk2Size = size * header.blockAlign; + header.chunkSize = 36 + header.subchunk2Size; + header.subchunk1Size = 16; + + std::strncpy(header.chunkId, "RIFF", 4); + std::strncpy(header.format, "WAVE", 4); + std::strncpy(header.subchunk1Id, "fmt ", 4); + std::strncpy(header.subchunk2Id, "data", 4); + + file.write((char*)&header, sizeof(header)); + + if(bitsPerSample == 8) + { + for (size_t i = 0; i < size; i++) + { + int8_t leftSample = (int8_t)(LChannel[i] * 128.0f + 128.0f); + int8_t rightSample = (int8_t)(RChannel[i] * 128.0f + 128.0f); + file.write((char*)&leftSample, 1); + file.write((char*)&rightSample, 1); + } + } + else if(bitsPerSample == 16) + { + for (size_t i = 0; i < size; i++) + { + int16_t leftSample = (int16_t)(LChannel[i] * 32768.0f); + int16_t rightSample = (int16_t)(RChannel[i] * 32768.0f); + file.write((char*)&leftSample, 2); + file.write((char*)&rightSample, 2); + } + } + else if(bitsPerSample == 24) + { + for(size_t i = 0; i < size; i++) + { + int32_t leftSample = (int32_t)(LChannel[i] * 8388608.0f); + int32_t rightSample = (int32_t)(RChannel[i] * 8388608.0f); + file.write((char*)&leftSample, 3); + file.write((char*)&rightSample, 3); + } + } + else if(bitsPerSample == 32) + { + for (size_t i = 0; i < size; i++) + { + int32_t leftSample = (int32_t)(LChannel[i] * 2147483648.0f); + int32_t rightSample = (int32_t)(RChannel[i] * 2147483648.0f); + file.write((char*)&leftSample, 4); + file.write((char*)&rightSample, 4); + } + } + else + { + std::cerr << "Error: unsupported bit depth: " << bitsPerSample << std::endl; + return; + } +} diff --git a/src/test/waveplay.cpp b/src/test/waveplay.cpp new file mode 100644 index 0000000..f11a3a9 --- /dev/null +++ b/src/test/waveplay.cpp @@ -0,0 +1,116 @@ +#include "wave.h" + +#include +#include +#include + +void playSound(float32_t* LChannel, + float32_t* RChannel, + unsigned size, + int sampleRate, + int bitsPerSample) +{ + // Calculate the number of samples and the size of the audio buffer + int numSamples = size; + int bufferSize = numSamples * bitsPerSample / 8 * 2; + + // Create an audio buffer + std::vector buffer(bufferSize); + + // Fill the audio buffer with the sample data + for(int i = 0; i < numSamples; i++) + { + if(bitsPerSample == 8) + { + // 8-bit samples are unsigned and range from 0 to 255 + uint8_t leftSample = (uint8_t)(LChannel[i] * 128.0f + 128.0f); + uint8_t rightSample = (uint8_t)(RChannel[i] * 128.0f + 128.0f); + buffer[i * 2 + 0] = leftSample; + buffer[i * 2 + 1] = rightSample; + } + else if(bitsPerSample == 16) + { + // 16-bit samples are signed and range from -32768 to 32767 + int16_t leftSample = (int16_t)(LChannel[i] * 32768.0f); + int16_t rightSample = (int16_t)(RChannel[i] * 32768.0f); + buffer[i * 2 + 0] = (uint8_t)leftSample; + buffer[i * 2 + 1] = (uint8_t)(leftSample >> 8); + buffer[i * 2 + 2] = (uint8_t)rightSample; + buffer[i * 2 + 3] = (uint8_t)(rightSample >> 8); + } + else if(bitsPerSample == 24) + { + // 24-bit samples are signed and range from -32768 to 32767 + int32_t leftSample = (int16_t)(LChannel[i] * 8388608.0f); + int32_t rightSample = (int16_t)(RChannel[i] * 8388608.0f); + buffer[i * 3 + 0] = (uint8_t)leftSample; + buffer[i * 3 + 1] = (uint8_t)(leftSample >> 8); + buffer[i * 3 + 2] = (uint8_t)(leftSample >> 16); + buffer[i * 3 + 3] = (uint8_t)rightSample; + buffer[i * 3 + 4] = (uint8_t)(rightSample >> 8); + buffer[i * 3 + 5] = (uint8_t)(rightSample >> 16); + } + else if (bitsPerSample == 32) + { + // 32-bit samples are signed and range from -32768 to 32767 + int32_t leftSample = (int16_t)(LChannel[i] * 2147483648.0f); + int32_t rightSample = (int16_t)(RChannel[i] * 2147483648.0f); + buffer[i * 3 + 0] = (uint8_t)leftSample; + buffer[i * 3 + 1] = (uint8_t)(leftSample >> 8); + buffer[i * 3 + 2] = (uint8_t)(leftSample >> 16); + buffer[i * 3 + 3] = (uint8_t)(leftSample >> 24); + buffer[i * 3 + 4] = (uint8_t)rightSample; + buffer[i * 3 + 5] = (uint8_t)(rightSample >> 8); + buffer[i * 3 + 6] = (uint8_t)(rightSample >> 16); + buffer[i * 3 + 7] = (uint8_t)(rightSample >> 24); + } + else + { + std::cerr << "Error: unsupported bit depth: " << bitsPerSample << std::endl; + return; + } + } + + // Set up the WAVEFORMATEX structure + WAVEFORMATEX waveFormat; + waveFormat.wFormatTag = WAVE_FORMAT_PCM; + waveFormat.nChannels = 2; + waveFormat.nSamplesPerSec = sampleRate; + waveFormat.nAvgBytesPerSec = sampleRate * bitsPerSample / 8 * 2; + waveFormat.nBlockAlign = bitsPerSample / 8 * 2; + waveFormat.wBitsPerSample = bitsPerSample; + waveFormat.cbSize = 0; + + // Set up the WAVEHDR structure + WAVEHDR waveHeader; + waveHeader.lpData = (LPSTR)buffer.data(); + waveHeader.dwBufferLength = bufferSize; + waveHeader.dwBytesRecorded = 0; + waveHeader.dwUser = 0; + waveHeader.dwFlags = 0; + waveHeader.dwLoops = 0; + waveHeader.lpNext = nullptr; + waveHeader.reserved = 0; + + // Open the audio device + HWAVEOUT audioDevice; + MMRESULT result = waveOutOpen(&audioDevice, WAVE_MAPPER, &waveFormat, 0, 0, WAVE_FORMAT_QUERY); + if (result != MMSYSERR_NOERROR) { + std::cerr << "Error opening audio device" << std::endl; + return; + } + + // Prepare the audio buffer for playback + result = waveOutPrepareHeader(audioDevice, &waveHeader, sizeof(WAVEHDR)); + if (result != MMSYSERR_NOERROR) { + std::cerr << "Error preparing audio buffer" << std::endl; + return; + } + + // Play the audio + waveOutWrite(audioDevice, &waveHeader, sizeof(WAVEHDR)); + + // Cleanup + waveOutUnprepareHeader(audioDevice, &waveHeader, sizeof(WAVEHDR)); + waveOutClose(audioDevice); +} \ No newline at end of file diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 9fa6844..1ef3100 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -217,11 +217,9 @@ const CUIMenu::TMenuItem CUIMenu::s_FXChainShimmerReverb[] = { {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbEnable}, {"Wet Lvl", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbWet}, - {"L Delay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDelayTimeLeft}, - {"R Delay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDelayTimeRight}, - {"Freq", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbFrequency}, - {"Amp", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbAmplitude}, - {"Decay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDecayTime}, + {"Decay", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDecay}, + {"Diffus", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbDiffusion}, + {"PtchShft", EditGlobalParameter, 0, CMiniDexed::ParameterFXChainShimmerReverbPitchShift}, {0} }; @@ -355,11 +353,9 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow // FXChain > ShimmerReverb parameters {0, 1, 1, ToOnOff}, // ParameterFXChainShimmerReverbEnable {0, 99, 1}, // ParameterFXChainShimmerReverbWet - {0, 99, 1}, // ParameterFXChainShimmerReverbDelayTimeLeft - {0, 99, 1}, // ParameterFXChainShimmerReverbDelayTimeRight - {0, 99, 1}, // ParameterFXChainShimmerReverbFrequency - {0, 99, 1}, // ParameterFXChainShimmerReverbAmplitude - {0, 99, 1}, // ParameterFXChainShimmerReverbDecayTime + {0, 99, 1}, // ParameterFXChainShimmerReverbDecay + {0, 99, 1}, // ParameterFXChainShimmerReverbDiffusion + {0, 99, 1}, // ParameterFXChainShimmerReverbPitchShift #endif // END FXRack global parameters mapping definition