BogaudioModules

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

commit 46bc16deb7e5315c7255d2419c564bdf2e55dafe
parent 904643efba9cb13158d0fba992c847cd016a04c9
Author: Matt Demanett <matt@demanett.net>
Date:   Wed, 31 Jan 2018 01:38:25 -0500

Basic saw/square/triangle oscillator DSP; test harness.

Diffstat:
Mbenchmarks/oscillator.cpp | 32++++++++++++++++++++++++++++++++
Msrc/Test.cpp | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/dsp/oscillator.cpp | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/dsp/oscillator.hpp | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 254 insertions(+), 1 deletion(-)

diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp @@ -5,6 +5,14 @@ using namespace bogaudio::dsp; +static void BM_Phasor(benchmark::State& state) { + Phasor p(44100.0, 440.0); + for (auto _ : state) { + p.next(); + } +} +BENCHMARK(BM_Phasor); + static void BM_SineOscillator(benchmark::State& state) { SineOscillator o(44100.0, 440.0); for (auto _ : state) { @@ -12,3 +20,27 @@ static void BM_SineOscillator(benchmark::State& state) { } } BENCHMARK(BM_SineOscillator); + +static void BM_SawOscillator(benchmark::State& state) { + SawOscillator o(44100.0, 440.0); + for (auto _ : state) { + o.next(); + } +} +BENCHMARK(BM_SawOscillator); + +static void BM_SquareOscillator(benchmark::State& state) { + SquareOscillator o(44100.0, 440.0); + for (auto _ : state) { + o.next(); + } +} +BENCHMARK(BM_SquareOscillator); + +static void BM_TriangleOscillator(benchmark::State& state) { + TriangleOscillator o(44100.0, 440.0); + for (auto _ : state) { + o.next(); + } +} +BENCHMARK(BM_TriangleOscillator); diff --git a/src/Test.cpp b/src/Test.cpp @@ -1,6 +1,25 @@ +// #define LPF 1 +// #define SINE 1 +// #define SQUARE 1 +#define SAW 1 +// #define TRIANGLE 1 + #include "bogaudio.hpp" +#include "pitch.hpp" +#ifdef LPF #include "dsp/filter.hpp" +#elif SINE +#include "dsp/oscillator.hpp" +#elif SQUARE +#include "dsp/oscillator.hpp" +#elif SAW +#include "dsp/oscillator.hpp" +#elif TRIANGLE +#include "dsp/oscillator.hpp" +#else +#error what +#endif using namespace bogaudio::dsp; @@ -27,33 +46,91 @@ struct Test : Module { NUM_LIGHTS }; +#ifdef LPF LowPassFilter _lpf; +#elif SINE + SineOscillator _sine; +#elif SQUARE + SquareOscillator _square; +#elif SAW + SawOscillator _saw; +#elif TRIANGLE + TriangleOscillator _triangle; +#endif Test() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) +#ifdef LPF , _lpf(44100.0, 1000.0, 1.0) +#elif SINE + , _sine(44100.0, 1000.0, 5.0) +#elif SQUARE + , _square(44100.0, 1000.0, 5.0) +#elif SAW + , _saw(44100.0, 1000.0, 5.0) +#elif TRIANGLE + , _triangle(44100.0, 1000.0, 5.0) +#endif { reset(); } virtual void reset() override; virtual void step() override; + float oscillatorPitch(); }; void Test::reset() { } void Test::step() { - if (!inputs[IN_INPUT].active || !outputs[OUT_OUTPUT].active) { + if (!outputs[OUT_OUTPUT].active) { return; } +#ifdef LPF + if (!inputs[IN_INPUT].active) { + return; + } _lpf.setParams( engineGetSampleRate(), 10000.0 * clampf(params[PARAM1_PARAM].value, 0.0, 1.0), std::max(10.0 * clampf(params[PARAM2_PARAM].value, 0.0, 1.0), 0.1) ); outputs[OUT_OUTPUT].value = _lpf.next(inputs[IN_INPUT].value); + +#elif SINE + _sine.setSampleRate(engineGetSampleRate()); + _sine.setFrequency(oscillatorPitch()); + outputs[OUT_OUTPUT].value = _sine.next(); + +#elif SQUARE + _square.setSampleRate(engineGetSampleRate()); + _square.setFrequency(oscillatorPitch()); + float pw = params[PARAM2_PARAM].value; + if (inputs[CV2_INPUT].active) { + pw += clampf(inputs[CV2_INPUT].value, -5.0, 5.0) / 10.0; + } + _square.setPulseWidth(pw); + outputs[OUT_OUTPUT].value = _square.next(); + +#elif SAW + _saw.setSampleRate(engineGetSampleRate()); + _saw.setFrequency(oscillatorPitch()); + outputs[OUT_OUTPUT].value = _saw.next(); + +#elif TRIANGLE + _triangle.setSampleRate(engineGetSampleRate()); + _triangle.setFrequency(oscillatorPitch()); + outputs[OUT_OUTPUT].value = _triangle.next(); +#endif +} + +float Test::oscillatorPitch() { + if (inputs[CV1_INPUT].active) { + return cvToFrequency(inputs[CV1_INPUT].value); + } + return 10000.0 * powf(params[PARAM1_PARAM].value, 2.0); } diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -4,6 +4,21 @@ using namespace bogaudio::dsp; +void Phasor::updateDelta() { + float sampleTime = 1.0 / _sampleRate; + float cycleTime = 1.0 / _frequency; + _delta = (sampleTime / cycleTime) * 2.0f; +} + +float Phasor::_next() { + _phase += _delta; + if (_phase >= 2.0) { + _phase -= 2.0; + } + return _phase; +} + + void SineOscillator::updateDeltaTheta() { float sampleTime = 1.0 / _sampleRate; float cycleTime = 1.0 / _frequency; @@ -29,8 +44,58 @@ float SineOscillator::_next() { _x[i] = t[i]; } } + float out = _y[_step]; ++_step; _step %= _n; return out; } + + +float SawOscillator::_next() { + Phasor::_next(); + return _amplitude * (_phase - 1.0f); +} + + +void SquareOscillator::setPulseWidth(float pw) { + if (pw >= 0.9) { + _pulseWidth = 0.9; + } + else if (pw <= 0.1) { + _pulseWidth = 0.1; + } + else { + _pulseWidth = pw; + } + _pulseWidth *= 2.0; +} + +float SquareOscillator::_next() { + Phasor::_next(); + if (positive) { + if (_phase >= _pulseWidth) { + positive = false; + return _negativeAmplitude; + } + return _amplitude; + } + if (_phase < _pulseWidth) { + positive = true; + return _amplitude; + } + return _negativeAmplitude; +} + + +float TriangleOscillator::_next() { + Phasor::_next(); + float p = 2.0 * _phase; + if (_phase < 0.5) { + return _amplitude * p; + } + if (_phase < 1.5) { + return _amplitude * (2.0 - p); + } + return _amplitude * (p - 4.0); +} diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp @@ -37,6 +37,31 @@ struct OscillatorGenerator : Generator { virtual void _frequencyChanged() {} }; +struct Phasor : OscillatorGenerator { + float _delta; + double _phase = 0.0; + + Phasor( + float sampleRate, + float frequency + ) + : OscillatorGenerator(sampleRate, frequency) + { + updateDelta(); + } + + virtual void _sampleRateChanged() override { + updateDelta(); + } + + virtual void _frequencyChanged() override { + updateDelta(); + } + + void updateDelta(); + virtual float _next() override; +}; + struct SineOscillator : OscillatorGenerator { static const int _n = 4; int _step = 0; @@ -71,5 +96,59 @@ struct SineOscillator : OscillatorGenerator { virtual float _next() override; }; +struct SawOscillator : Phasor { + float _amplitude; + + SawOscillator( + float sampleRate, + float frequency, + float amplitude = 1.0 + ) + : Phasor(sampleRate, frequency) + , _amplitude(amplitude) + { + } + + virtual float _next() override; +}; + +struct SquareOscillator : Phasor { + float _amplitude; + float _negativeAmplitude; + float _pulseWidth = 0.5; + bool positive = true; + + SquareOscillator( + float sampleRate, + float frequency, + float amplitude = 1.0 + ) + : Phasor(sampleRate, frequency) + , _amplitude(amplitude) + , _negativeAmplitude(-amplitude) + { + } + + void setPulseWidth(float pw); + + virtual float _next() override; +}; + +struct TriangleOscillator : Phasor { + float _amplitude; + + TriangleOscillator( + float sampleRate, + float frequency, + float amplitude = 1.0 + ) + : Phasor(sampleRate, frequency) + , _amplitude(amplitude) + { + } + + virtual float _next() override; +}; + } // namespace dsp } // namespace bogaudio