BogaudioModules

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

commit 0358eba8d2beece08d69f47b2f738fa18b182d97
parent 96a1d785b9119307e37211806290caff78f1f629
Author: Matt Demanett <matt@demanett.net>
Date:   Sat, 17 Feb 2018 16:33:51 -0500

Replace sine oscillator with more stable one; fixes to sine bank; alternate triangle output configuration in sine bank tests using negative amplitudes.

Diffstat:
Mbenchmarks/oscillator.cpp | 12------------
Msrc/Test.cpp | 48++++++++++++++++--------------------------------
Msrc/dsp/oscillator.cpp | 152+++++++++++--------------------------------------------------------------------
Msrc/dsp/oscillator.hpp | 87++++++++++++++-----------------------------------------------------------------
4 files changed, 52 insertions(+), 247 deletions(-)

diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp @@ -56,15 +56,3 @@ static void BM_SineBankOscillator(benchmark::State& state) { } } BENCHMARK(BM_SineBankOscillator); - -static void BM_SineBankOscillator2(benchmark::State& state) { - SineBankOscillator2 o(44100.0, 440.0, 100); - for (int i = 1, n = o.partialCount(); i <= n; ++i) { - o.setPartial(i, i, 1.0 / (float)i); - } - - for (auto _ : state) { - o.next(); - } -} -BENCHMARK(BM_SineBankOscillator2); diff --git a/src/Test.cpp b/src/Test.cpp @@ -62,7 +62,6 @@ struct Test : Module { TriangleOscillator _triangle; #elif SINEBANK SineBankOscillator _sineBank; - SineBankOscillator2 _sineBank2; #endif Test() @@ -79,7 +78,6 @@ struct Test : Module { , _triangle(44100.0, 1000.0, 5.0) #elif SINEBANK , _sineBank(44101.0, 1000.0, 50) - , _sineBank2(44101.0, 1000.0, 50) #endif { onReset(); @@ -93,9 +91,6 @@ struct Test : Module { for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { _sineBank.setPartial(i, i, baseAmplitude / (float)i, &phase); } - for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) { - _sineBank2.setPartial(i, i, baseAmplitude / (float)i, &phase); - } break; } @@ -104,20 +99,24 @@ struct Test : Module { for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : 0.0); } - for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) { - _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : 0.0); - } break; } case 3: { // triangle - float phase = M_PI / 2.0; - for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { - _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase); + if (false) { + float phase = M_PI / 2.0; + for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { + _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase); + } } - for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) { - _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase); + else { + float phase = 0.0f; + _sineBank.setPartial(1, 1.0f, baseAmplitude, &phase); + for (int i = 2, n = _sineBank.partialCount(); i < n; ++i) { + float k = 2*i - 1; + _sineBank.setPartial(i, k, powf(-1.0f, k) * baseAmplitude/(k * k), &phase); + } } break; } @@ -127,9 +126,6 @@ struct Test : Module { for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : baseAmplitude / (float)(2 * i)); } - for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) { - _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : baseAmplitude / (float)(2 * i)); - } break; } @@ -138,19 +134,10 @@ struct Test : Module { float phase = 0.0; float factor = 0.717; float factor2 = factor; - { - float multiple = 1.0; - for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { - _sineBank.setPartial(i, multiple, baseAmplitude / multiple, &phase); - multiple += i % 2 == 1 ? factor : factor2; - } - } - { - float multiple = 1.0; - for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) { - _sineBank2.setPartial(i, multiple, baseAmplitude / multiple, &phase); - multiple += i % 2 == 1 ? factor : factor2; - } + float multiple = 1.0; + for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { + _sineBank.setPartial(i, multiple, baseAmplitude / multiple, &phase); + multiple += i % 2 == 1 ? factor : factor2; } break; } @@ -211,9 +198,6 @@ void Test::step() { _sineBank.setSampleRate(engineGetSampleRate()); _sineBank.setFrequency(oscillatorPitch()); outputs[OUT_OUTPUT].value = _sineBank.next(); - _sineBank2.setSampleRate(engineGetSampleRate()); - _sineBank2.setFrequency(oscillatorPitch()); - outputs[OUT2_OUTPUT].value = _sineBank2.next(); #endif } diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -24,56 +24,23 @@ float Phasor::_next() { } -void SineOscillator::setPhase(float phase) { - float x = cosf(phase) * _amplitude; - float y = sinf(phase) * _amplitude; - for (int i = 0; i < _n; ++i) { - _x[i] = x; - _y[i] = y; - } - _step = 0; +// A New Recursive Quadrature Oscillator, Martin Vicanek, 2015 - http://vicanek.de/articles/QuadOsc.pdf +void SineOscillator::setPhase(double phase) { + _x = cos(phase); + _y = sin(phase); } -void SineOscillator::updateDeltaTheta() { - float deltaTheta = (_frequency / _sampleRate) * 2.0f * M_PI; - for (int i = 0; i < _n; ++i) { - _sinDeltaTheta[i] = sinf((i + 1) * deltaTheta); - _cosDeltaTheta[i] = cosf((i + 1) * deltaTheta); - } +void SineOscillator::update() { + double w = (_frequency / _sampleRate) * 2.0 * M_PI; + _k1 = tan(w / 2.0); + _k2 = 2.0 * _k1 / (1 + _k1*_k1); } float SineOscillator::_next() { - ++_sampleCount; - - if (_step == 0) { - const int n1 = _n - 1; - if (_sampleCount > _maxSamplesBeforeNormalize) { - _sampleCount = 0; - - // https://dsp.stackexchange.com/questions/124/how-to-implement-a-digital-oscillator - // float g = (3.0f - (_x[n1]*_x[n1] + _y[n1]*_y[n1])) / 2.0f; // would work if _amplitude was always 1.0? - float g = _amplitude / sqrtf(_x[n1]*_x[n1] + _y[n1]*_y[n1]); - _x[n1] *= g; - _y[n1] *= g; - } - - for (int i = 0; i < n1; ++i) { - _x[i] = _x[n1]; - _y[i] = _y[n1]; - } - - float t[_n]; - for (int i = 0; i < _n; ++i) { - t[i] = _x[i]*_cosDeltaTheta[i] - _y[i]*_sinDeltaTheta[i]; - _y[i] = _x[i]*_sinDeltaTheta[i] + _y[i]*_cosDeltaTheta[i]; - _x[i] = t[i]; - } - } - - float out = _y[_step]; - ++_step; - _step %= _n; - return out; + double t = _x - _k1*_y; + _y = _y + _k2*t; + _x = t - _k1*_y; + return _amplitude * _y; } @@ -132,31 +99,23 @@ void SineBankOscillator::setPartial(int i, float frequencyRatio, float amplitude return; } - if (amplitude > 0.01) { - _partials[i - 1].enabled = true; - _partials[i - 1].frequencyRatio = frequencyRatio; - _partials[i - 1].frequency = _frequency * frequencyRatio; - _partials[i - 1].sine.setFrequency(_frequency * frequencyRatio); - _partials[i - 1].amplitude = amplitude; + Partial& p = _partials[i - 1]; + if (amplitude > 0.01f || amplitude < -0.01f) { + p.enabled = true; + p.frequencyRatio = frequencyRatio; + p.frequency = _frequency * frequencyRatio; + p.sine.setFrequency((double)_frequency * (double)frequencyRatio); + p.amplitude = amplitude; if (phase) { - _partials[i - 1].sine.setPhase(*phase); + p.sine.setPhase(*phase); } } else { - _partials[i - 1].enabled = false; - } -} - -void SineBankOscillator::disablePartial(int i) { - if (i > (int)_partials.size()) { - return; + p.enabled = false; } - _partials[i - 1].enabled = false; } void SineBankOscillator::_sampleRateChanged() { - Phasor::_sampleRateChanged(); - _maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate; for (Partial& p : _partials) { p.sine.setSampleRate(_sampleRate); @@ -164,8 +123,6 @@ void SineBankOscillator::_sampleRateChanged() { } void SineBankOscillator::_frequencyChanged() { - Phasor::_frequencyChanged(); - for (Partial& p : _partials) { p.frequency = _frequency * p.frequencyRatio; p.sine.setFrequency(_frequency * p.frequencyRatio); @@ -173,16 +130,6 @@ void SineBankOscillator::_frequencyChanged() { } float SineBankOscillator::_next() { - Phasor::_next(); - - if (++_steps >= _stepsToReset) { - _steps = 0; - // float phase = _phase * M_PI; - // for (Partial& p : _partials) { - // p.sine.setPhase(phase * p.frequencyRatio); - // } - } - float next = 0.0; for (Partial& p : _partials) { if (p.enabled && p.frequency < _maxPartialFrequency) { @@ -194,60 +141,3 @@ float SineBankOscillator::_next() { } return next; } - - -void SineBankOscillator2::setPartial(int i, float frequencyRatio, float amplitude, float* phase) { - if (i > (int)_partials.size()) { - return; - } - - Partial& p = _partials[i - 1]; - if (amplitude > 0.01) { - p.enabled = true; - p.frequencyRatio = frequencyRatio; - p.amplitude = amplitude; - if (phase) { - p.phase = _radiansToPhase(*phase); - } - _updatePartial(p); - } - else { - p.enabled = false; - } -} - -void SineBankOscillator2::_updatePartial(Partial& p) { - const float d = (float)pow(10, resolution); - p.frequency = _frequency * p.frequencyRatio; - p.frequency *= d; - p.frequency = roundf(p.frequency); - p.deltaPhase = (phase_t)p.frequency; - p.frequency /= d; - // printf("UPDATE fr=%f f=%f dp=%u k=%d mp=%u f0=%f\n", p.frequencyRatio, p.frequency, p.deltaPhase, resolution, _maxPhase, _frequency); -} - -void SineBankOscillator2::_sampleRateChanged() { - _maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate; - _maxPhase = pow(10, resolution) * _sampleRate; - for (Partial& p : _partials) { - _updatePartial(p); - // need to scale phase? - } -} - -void SineBankOscillator2::_frequencyChanged() { - for (Partial& p : _partials) { - _updatePartial(p); - } -} - -float SineBankOscillator2::_next() { - float next = 0.0; - for (Partial& p : _partials) { - p.phase = (p.phase + p.deltaPhase) % _maxPhase; - if (p.enabled && p.frequencyRatio * _frequency < _maxPartialFrequency) { - next += p.amplitude * sinf(_phaseToRadians(p.phase)); - } - } - return next; -} diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp @@ -71,39 +71,34 @@ struct Phasor : OscillatorGenerator { }; struct SineOscillator : OscillatorGenerator { - static const int _n = 4; - int _step = 0; - float _x[_n]; - float _y[_n]; - float _sinDeltaTheta[_n]; - float _cosDeltaTheta[_n]; - unsigned int _sampleCount = 0; - unsigned int _maxSamplesBeforeNormalize = 1000 + (Seeds::next() % 100); - float _amplitude; + double _k1, _k2; + double _x; + double _y; + double _amplitude; SineOscillator( - float sampleRate, - float frequency, - float amplitude = 1.0, - float initialPhase = 0.0 + double sampleRate, + double frequency, + double amplitude = 1.0, + double initialPhase = 0.0 ) : OscillatorGenerator(sampleRate, frequency) , _amplitude(amplitude) { setPhase(initialPhase); - updateDeltaTheta(); + update(); } virtual void _sampleRateChanged() override { - updateDeltaTheta(); + update(); } virtual void _frequencyChanged() override { - updateDeltaTheta(); + update(); } - void setPhase(float phase); - void updateDeltaTheta(); + void setPhase(double phase); + void update(); virtual float _next() override; }; @@ -161,7 +156,7 @@ struct TriangleOscillator : Phasor { virtual float _next() override; }; -struct SineBankOscillator : Phasor { +struct SineBankOscillator : OscillatorGenerator { struct Partial { bool enabled; float frequency; @@ -180,8 +175,6 @@ struct SineBankOscillator : Phasor { const float _maxPartialFrequencySRRatio = 0.48; float _maxPartialFrequency = 0.0; - unsigned _steps = 0; - unsigned _stepsToReset = 1000; std::vector<Partial> _partials; SineBankOscillator( @@ -189,49 +182,6 @@ struct SineBankOscillator : Phasor { float frequency, int partialCount ) - : Phasor(sampleRate, frequency) - , _partials(partialCount) - { - _sampleRateChanged(); - _frequencyChanged(); - } - - int partialCount() { - return _partials.size(); - } - - // one-based indexes. - void setPartial(int i, float frequencyRatio, float amplitude, float* phase = NULL); - void disablePartial(int i); - - virtual void _sampleRateChanged() override; - virtual void _frequencyChanged() override; - virtual float _next() override; -}; - -struct SineBankOscillator2 : OscillatorGenerator { - typedef uint64_t phase_t; - const int resolution = 2; - - struct Partial { - bool enabled = false; - float frequencyRatio = 1.0; - float frequency = 1.0; - float amplitude = 1.0; - phase_t phase = 0.0; - phase_t deltaPhase = 0.0; - }; - - phase_t _maxPhase = 0.0; - const float _maxPartialFrequencySRRatio = 0.48; - float _maxPartialFrequency = 0.0; - std::vector<Partial> _partials; - - SineBankOscillator2( - float sampleRate, - float frequency, - int partialCount - ) : OscillatorGenerator(sampleRate, frequency) , _partials(partialCount) { @@ -243,16 +193,9 @@ struct SineBankOscillator2 : OscillatorGenerator { return _partials.size(); } - // one-based indexes. + // one-based index. void setPartial(int i, float frequencyRatio, float amplitude, float* phase = NULL); - void _updatePartial(Partial& p); - float _phaseToRadians(phase_t p) { - return (p / (float)_maxPhase) * 2.0f * M_PI; - } - phase_t _radiansToPhase(float r) { - return ((phase_t)roundf(_maxPhase * (r / (2.0f * M_PI)))) % _maxPhase; - } virtual void _sampleRateChanged() override; virtual void _frequencyChanged() override; virtual float _next() override;