BogaudioModules

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

commit 8b91d0ca4ed12c9da190c819667f8a75f3e7772c
parent 2eb603fb5eb79ad2231776ef0d84fa7bda75fdcd
Author: Matt Demanett <matt@demanett.net>
Date:   Thu, 15 Feb 2018 21:23:10 -0500

Progress(?) on a stable sine bank.

Diffstat:
Mbenchmarks/oscillator.cpp | 12++++++++++++
Msrc/Test.cpp | 45++++++++++++++++++++++++++++++++++++++-------
Msrc/dsp/oscillator.cpp | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/dsp/oscillator.hpp | 50++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 161 insertions(+), 11 deletions(-)

diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp @@ -56,3 +56,15 @@ 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 @@ -42,6 +42,7 @@ struct Test : Module { enum OutputsIds { OUT_OUTPUT, + OUT2_OUTPUT, NUM_OUTPUTS }; @@ -61,6 +62,7 @@ struct Test : Module { TriangleOscillator _triangle; #elif SINEBANK SineBankOscillator _sineBank; + SineBankOscillator2 _sineBank2; #endif Test() @@ -76,20 +78,24 @@ struct Test : Module { #elif TRIANGLE , _triangle(44100.0, 1000.0, 5.0) #elif SINEBANK - , _sineBank(44101.0, 1000.0, 100) + , _sineBank(44101.0, 1000.0, 50) + , _sineBank2(44101.0, 1000.0, 50) #endif { reset(); #ifdef SINEBANK const float baseAmplitude = 5.0; - switch (1) { + switch (5) { case 1: { // saw float phase = M_PI; 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; } @@ -98,6 +104,9 @@ 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; } @@ -107,6 +116,9 @@ struct Test : Module { 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); + } break; } @@ -115,16 +127,30 @@ 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; } case 5: { // ? - float phase = M_PI; - float multiple = 1.0; - for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) { - _sineBank.setPartial(i, multiple, baseAmplitude / multiple, &phase); - multiple += 0.9; + 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; + } } break; } @@ -185,6 +211,9 @@ 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 } @@ -220,6 +249,7 @@ TestWidget::TestWidget() { auto inInputPosition = Vec(10.5, 258.0); auto outOutputPosition = Vec(10.5, 296.0); + auto out2OutputPosition = Vec(20.5, 316.0); // end generated by svg_widgets.rb addParam(createParam<Knob26>(param1ParamPosition, module, Test::PARAM1_PARAM, 0.0, 1.0, 0.5)); @@ -230,4 +260,5 @@ TestWidget::TestWidget() { addInput(createInput<Port24>(inInputPosition, module, Test::IN_INPUT)); addOutput(createOutput<Port24>(outOutputPosition, module, Test::OUT_OUTPUT)); + addOutput(createOutput<Port24>(out2OutputPosition, module, Test::OUT2_OUTPUT)); } diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -179,10 +179,10 @@ float SineBankOscillator::_next() { if (++_steps >= _stepsToReset) { _steps = 0; - float phase = _phase * M_PI; - for (Partial& p : _partials) { - p.sine.setPhase(phase * p.frequencyRatio); - } + // float phase = _phase * M_PI; + // for (Partial& p : _partials) { + // p.sine.setPhase(phase * p.frequencyRatio); + // } } float next = 0.0; @@ -196,3 +196,60 @@ 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 @@ -1,6 +1,7 @@ #pragma once #include <stdlib.h> +#include <stdint.h> #include <vector> #include "base.hpp" @@ -208,5 +209,54 @@ struct SineBankOscillator : Phasor { 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) + { + _sampleRateChanged(); + _frequencyChanged(); + } + + int partialCount() { + return _partials.size(); + } + + // one-based indexes. + 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; +}; + } // namespace dsp } // namespace bogaudio