BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

commit 36aefaf5422c61a92f00fbe53f91538a9c5fd63d
parent 92d485cae583ece05e887127b89e6a67b75948d5
Author: Matt Demanett <matt@demanett.net>
Date:   Sun, 18 Mar 2018 15:25:19 -0400

Experiment with saw saturation.

Diffstat:
Msrc/Test.cpp | 13+++++++++++++
Msrc/Test.hpp | 14+++++++++++++-
Msrc/dsp/oscillator.cpp | 27++++++++++++++++++++++++++-
Msrc/dsp/oscillator.hpp | 24++++++++++++++++++++++--
4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/src/Test.cpp b/src/Test.cpp @@ -65,6 +65,19 @@ void Test::step() { _saw2.setQuality(params[PARAM2_PARAM].value * 200); outputs[OUT2_OUTPUT].value = _saw2.next(); +#elif SATSAW + float saturation = params[PARAM2_PARAM].value * 10.0f; + _saw.setSampleRate(engineGetSampleRate()); + _saw.setFrequency(oscillatorPitch()); + _saw.setSaturation(saturation); + outputs[OUT_OUTPUT].value = _saw.next(); + + _saw2.setSampleRate(engineGetSampleRate()); + _saw2.setFrequency(oscillatorPitch()); + _saw2.setSaturation(saturation); + _saw2.setQuality(params[PARAM3_PARAM].value * 200); + outputs[OUT2_OUTPUT].value = _saw2.next(); + #elif TRIANGLE _triangle.setSampleRate(engineGetSampleRate()); _triangle.setFrequency(oscillatorPitch()); diff --git a/src/Test.hpp b/src/Test.hpp @@ -7,8 +7,9 @@ extern Model* modelTest; // #define LPF 1 // #define LPFNOISE 1 // #define SINE 1 -#define SQUARE 1 +// #define SQUARE 1 // #define SAW 1 +#define SATSAW 1 // #define TRIANGLE 1 // #define SINEBANK 1 // #define OVERSAMPLING 1 @@ -30,6 +31,8 @@ extern Model* modelTest; #include "dsp/oscillator.hpp" #elif SAW #include "dsp/oscillator.hpp" +#elif SATSAW +#include "dsp/oscillator.hpp" #elif TRIANGLE #include "dsp/oscillator.hpp" #elif SINEBANK @@ -97,6 +100,9 @@ struct Test : Module { #elif SAW SawOscillator _saw; BandLimitedSawOscillator _saw2; +#elif SATSAW + SaturatingSawOscillator _saw; + BandLimitedSawOscillator _saw2; #elif TRIANGLE TriangleOscillator _triangle; #elif SINEBANK @@ -140,6 +146,9 @@ struct Test : Module { #elif SAW , _saw(44100.0, 1000.0, 5.0) , _saw2(44100.0, 1000.0, 5.0, 8) + #elif SATSAW + , _saw(44100.0, 1000.0, 5.0) + , _saw2(44100.0, 1000.0, 5.0, 8) #elif TRIANGLE , _triangle(44100.0, 1000.0, 5.0) #elif SINEBANK @@ -174,6 +183,9 @@ struct Test : Module { #elif SAW _saw2.setPhase(M_PI); +#elif SATSAW + _saw2.setPhase(M_PI); + #elif SINEBANK const float baseAmplitude = 5.0; switch (5) { diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -79,6 +79,31 @@ float SawOscillator::_nextForPhase(float phase) { } +void SaturatingSawOscillator::setSaturation(float saturation) { + if (_saturation != saturation) { + assert(saturation >= 0.0f); + _saturation = saturation; + if (_saturation < 1.0f) { + _saturationNormalization = 1.0f / tanhf(_saturation * M_PI); + } + else { + _saturationNormalization = 1.0f; + } + } +} + +float SaturatingSawOscillator::_nextForPhase(float phase) { + float sample = SawOscillator::_nextForPhase(phase); + if (_saturation >= 0.1f) { + // FIXME: amplitudes, tanh approximation or table. + sample /= _amplitude; + sample = tanhf(sample * _saturation * M_PI) * _saturationNormalization; + sample *= _amplitude; + } + return sample; +} + + void BandLimitedSawOscillator::setQuality(int quality) { if (_quality != quality) { assert(quality >= 0); @@ -94,7 +119,7 @@ void BandLimitedSawOscillator::_update() { } float BandLimitedSawOscillator::_nextForPhase(float phase) { - float sample = SawOscillator::_nextForPhase(phase); + float sample = SaturatingSawOscillator::_nextForPhase(phase); if (phase > maxPhase - _qd) { float i = (maxPhase - phase) / _qd; i = (1.0f - i) * _halfTableLen; diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp @@ -156,7 +156,27 @@ struct SawOscillator : Phasor { virtual float _nextForPhase(float phase) override; }; -struct BandLimitedSawOscillator : SawOscillator { +struct SaturatingSawOscillator : SawOscillator { + float _saturation; + float _saturationNormalization; + + SaturatingSawOscillator( + float sampleRate, + float frequency, + float amplitude = 1.0f + ) + : SawOscillator(sampleRate, frequency, amplitude) + , _saturation(0.0f) + , _saturationNormalization(1.0f) + { + } + + void setSaturation(float saturation); + + virtual float _nextForPhase(float phase) override; +}; + +struct BandLimitedSawOscillator : SaturatingSawOscillator { int _quality; const Table& _table; float _qd = 0.0f; @@ -169,7 +189,7 @@ struct BandLimitedSawOscillator : SawOscillator { int quality = 5, const Table& table = StaticBlepTable::table() ) - : SawOscillator(sampleRate, frequency, amplitude) + : SaturatingSawOscillator(sampleRate, frequency, amplitude) , _quality(quality) , _table(table) , _halfTableLen(_table.length() / 2)