From f2006bd880639072d1fac9a342eb0eb5a403ae3d Mon Sep 17 00:00:00 2001 From: abscisys Date: Wed, 4 Jan 2023 21:05:14 +0100 Subject: [PATCH] Fixing the Tube effect so it has more presence --- src/fx_components.cpp | 55 ++++++++++++++++++++++++++++++- src/fx_components.h | 5 ++- src/fx_engine.hpp | 4 +-- src/fx_shimmer_reverb.cpp | 5 ++- src/fx_shimmer_reverb.h | 2 +- src/fx_tube.cpp | 10 +++--- src/fx_tube.h | 2 +- src/test/Makefile | 10 ++++-- src/test/fxrack_test.cpp | 68 ++++++++++++++++++++------------------- src/test/waveout.cpp | 2 ++ 10 files changed, 117 insertions(+), 46 deletions(-) diff --git a/src/fx_components.cpp b/src/fx_components.cpp index fe03a3c..d689aa9 100644 --- a/src/fx_components.cpp +++ b/src/fx_components.cpp @@ -189,7 +189,7 @@ float32_t JitterGenerator::process() ////////////////////////////////// // softSaturate implemlentation // ////////////////////////////////// -float32_t softSaturate(float32_t in, float32_t threshold) +float32_t softSaturator1(float32_t in, float32_t threshold) { float32_t x = std::abs(in); float32_t y = 0.0f; @@ -211,3 +211,56 @@ float32_t softSaturate(float32_t in, float32_t threshold) return (in < 0.0f) ? -y : y; } + +float32_t softSaturator2(float32_t input, float32_t saturation) +{ + constexpr static float kTubeCurve = 4.0f; + constexpr static float kTubeBias = 0.5f; + + float absInput = std::abs(input); + float output = 0.0f; + if(absInput > kTubeBias) + { + output = (kTubeCurve + saturation) * (absInput - kTubeBias) / (1.0f - kTubeBias); + } + else + { + output = (kTubeCurve + saturation) * absInput / (1.0f + kTubeCurve * absInput); + } + + // Clip the output if overdrive is set to 1 + // output = std::min(1.0f, output); + if(output > 1.0f) + { + output = 1.0f; + } + else + { + output -= output * output * output / 3.0f; + } + + if(input < 0.0f) + { + output = -output; + } + + return output; +} + +float32_t waveFolder(float32_t input, float32_t bias) +{ + bias = 0.5 + (2.0f - bias) / 4.0f; + float32_t output = std::abs(input) / bias; + + if(output > 1.0f) + { + output = 2.0f - output; + } + + if(input < 0.0f) + { + output = -output; + } + + return output; +} \ No newline at end of file diff --git a/src/fx_components.h b/src/fx_components.h index e7f92a4..619a444 100644 --- a/src/fx_components.h +++ b/src/fx_components.h @@ -257,4 +257,7 @@ private: float32_t phase_increment_; }; -float32_t softSaturate(float32_t in, float32_t threshold); +float32_t softSaturator1(float32_t in, float32_t threshold); +float32_t softSaturator2(float32_t in, float32_t saturation); + +float32_t waveFolder(float32_t input, float32_t bias); \ No newline at end of file diff --git a/src/fx_engine.hpp b/src/fx_engine.hpp index 10c6a72..3975631 100644 --- a/src/fx_engine.hpp +++ b/src/fx_engine.hpp @@ -99,13 +99,13 @@ public: { }; - template + template struct Reserve { typedef T Tail; enum { - length = l + length = _length }; }; diff --git a/src/fx_shimmer_reverb.cpp b/src/fx_shimmer_reverb.cpp index bc7989f..18c12c7 100644 --- a/src/fx_shimmer_reverb.cpp +++ b/src/fx_shimmer_reverb.cpp @@ -8,7 +8,10 @@ ShimmerReverb::ShimmerReverb(float32_t sampling_rate) : FXElement(sampling_rate), - engine_(sampling_rate) + engine_(sampling_rate), + input_gain_(-1.0f), + diffusion_(-1.0f), + lp_(-1.0f) { this->engine_.setLFOFrequency(LFO_1, 0.5f); this->engine_.setLFOFrequency(LFO_2, 0.3f); diff --git a/src/fx_shimmer_reverb.h b/src/fx_shimmer_reverb.h index 34d235b..9369336 100644 --- a/src/fx_shimmer_reverb.h +++ b/src/fx_shimmer_reverb.h @@ -47,7 +47,7 @@ public: float32_t getLP() const; private: - typedef FxEngine<16384, FORMAT_16_BIT> Engine; + typedef FxEngine<16384, FORMAT_16_BIT, true> Engine; Engine engine_; float32_t input_gain_; diff --git a/src/fx_tube.cpp b/src/fx_tube.cpp index ed91eb1..db55dc8 100644 --- a/src/fx_tube.cpp +++ b/src/fx_tube.cpp @@ -3,7 +3,9 @@ #include Tube::Tube(float32_t samplingRate) : - FXElement(samplingRate) + FXElement(samplingRate), + overdrive_(0.0f), + saturation_(0.0f) { this->setOverdrive(0.0f); } @@ -14,14 +16,14 @@ Tube::~Tube() void Tube::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { - outL = softSaturate(inL, this->threshold_); - outR = softSaturate(inR, this->threshold_); + outL = softSaturator2(inL, this->saturation_); + outR = softSaturator2(inR, this->saturation_); } void Tube::setOverdrive(float32_t overdrive) { this->overdrive_ = constrain(overdrive, 0.0f, 1.0f); - this->threshold_ = 1.0f - this->overdrive_; + this->saturation_ = 2.0f * this->overdrive_; } float32_t Tube::getOverdrive() const diff --git a/src/fx_tube.h b/src/fx_tube.h index 00b7e76..11dfb80 100644 --- a/src/fx_tube.h +++ b/src/fx_tube.h @@ -35,5 +35,5 @@ public: private: float32_t overdrive_; - float32_t threshold_; + float32_t saturation_; }; \ No newline at end of file diff --git a/src/test/Makefile b/src/test/Makefile index 116b014..5f61429 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -51,12 +51,18 @@ fx_svf.o: ../fx_svf.cpp fx_tube.o: ../fx_tube.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +../fx_chorus.cpp: ../fx_engine.hpp + touch ../fx_chorus.cpp + 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.cpp: ../fx_engine.hpp + touch ../fx_orbitone.cpp + fx_orbitone.o: ../fx_orbitone.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ @@ -66,8 +72,8 @@ fx_flanger.o: ../fx_flanger.cpp fx_delay.o: ../fx_delay.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -../fx_shimmer_reverb3.cpp: ../fx_engine.hpp - touch ../fx_shimmer_reverb3.cpp +../fx_shimmer_reverb.cpp: ../fx_engine.hpp + touch ../fx_shimmer_reverb.cpp fx_shimmer_reverb.o: ../fx_shimmer_reverb.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ diff --git a/src/test/fxrack_test.cpp b/src/test/fxrack_test.cpp index 4c048fd..29888d4 100644 --- a/src/test/fxrack_test.cpp +++ b/src/test/fxrack_test.cpp @@ -119,7 +119,20 @@ void testSVF(unsigned& step) } } -void testFXRack(unsigned& step) +enum FXSitch +{ + Tube = 1 << 0, + Chorus = 1 << 1, + Phaser = 1 << 2, + Orbitone = 1 << 3, + Flanger = 1 << 4, + Delay = 1 << 5, + Shimmer = 1 << 6 +}; + +#define Active(fxSwitch, FxID) (fxSwitch & FxID) == FxID + +void testFXRack(unsigned& step, unsigned fxSwitch) { cout << "Step #" << (++step) << ": Intanciation FXRack" << endl; FXRack *rack = new FXRack(44100.0f); @@ -128,59 +141,42 @@ void testFXRack(unsigned& step) rack->setEnable(true); rack->setWetLevel(1.0f); - rack->getTube()->setEnable(false); + rack->getTube()->setEnable(Active(fxSwitch, FXSitch::Tube)); rack->getTube()->setWetLevel(1.0f); rack->getTube()->setOverdrive(1.0f); - rack->getChorus()->setEnable(false); + rack->getChorus()->setEnable(Active(fxSwitch, FXSitch::Chorus)); rack->getChorus()->setWetLevel(0.5f); rack->getChorus()->setRate(0.4f); rack->getChorus()->setDepth(0.5f); - rack->getPhaser()->setEnable(false); + rack->getPhaser()->setEnable(Active(fxSwitch, FXSitch::Phaser)); - rack->getOrbitone()->setEnable(true); + rack->getOrbitone()->setEnable(Active(fxSwitch, FXSitch::Orbitone)); rack->getOrbitone()->setWetLevel(0.8f); rack->getOrbitone()->setRate(0.4f); rack->getOrbitone()->setDepth(0.5f); - rack->getFlanger()->setEnable(false); + rack->getFlanger()->setEnable(Active(fxSwitch, FXSitch::Flanger)); + rack->getFlanger()->setWetLevel(0.5f); + rack->getFlanger()->setDelayTime(0.8f); + rack->getFlanger()->setFrequency(0.25f); + rack->getFlanger()->setDepth(0.8f); + rack->getFlanger()->setFeedback(0.75f); - rack->getDelay()->setEnable(false); + rack->getDelay()->setEnable(Active(fxSwitch, FXSitch::Delay)); rack->getDelay()->setWetLevel(0.6f); rack->getDelay()->setLeftDelayTime(0.075f); rack->getDelay()->setLeftDelayTime(0.05f); rack->getDelay()->setFeedbak(0.5f); - rack->getShimmerReverb()->setEnable(false); + rack->getShimmerReverb()->setEnable(Active(fxSwitch, FXSitch::Shimmer)); 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 = 1; - 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 nbRepeats = 4; unsigned size; @@ -195,7 +191,7 @@ void testFXRack(unsigned& step) rack->process(samples[0], samples[1], sampleOutL + i * size, sampleOutR + i * size, size); } - saveWaveFile("result.wav", sampleOutL, sampleOutR, nbRepeats * size, 44100, 16); + saveWaveFile("result.wav", sampleOutL, sampleOutR, nbRepeats * size, static_cast(FS), 16); delete[] sampleOutL; delete[] sampleOutR; @@ -211,10 +207,16 @@ int main() { unsigned step = 0; - testLFO(step); + // testLFO(step); // testFlutter(step); // testSVF(step); - // testFXRack(step); + testFXRack(step, FXSitch::Tube); + // testFXRack(step, FXSitch::Flanger); // to be fixed -> feedback deletes FX effect + // testFXRack(step, FXSitch::Phaser); // to be fixed -> far too load but saturation is interested + // testFXRack(step, FXSitch::Chorus); + // testFXRack(step, FXSitch::Orbitone); + // testFXRack(step, FXSitch::Delay); + // testFXRack(step, FXSitch::Shimmer); return 0; } diff --git a/src/test/waveout.cpp b/src/test/waveout.cpp index 5ebf5cd..8794a56 100644 --- a/src/test/waveout.cpp +++ b/src/test/waveout.cpp @@ -82,4 +82,6 @@ void saveWaveFile(const std::string& fileName, std::cerr << "Error: unsupported bit depth: " << bitsPerSample << std::endl; return; } + + file.close(); }