BogaudioModules

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

commit 089e3cf463a63599471a47bcb12530ce462908de
parent 1a6789342ec35b4cd9c150e5c97d1e324dfefa69
Author: Matt Demanett <matt@demanett.net>
Date:   Wed, 10 Feb 2021 23:11:12 -0500

Stepped random oscillator; oscillators minor cleanups; widened oscillator phase_t.

Diffstat:
Msrc/EightFO.cpp | 2+-
Msrc/Sine.cpp | 2+-
Msrc/Test.cpp | 24++++++++++++++++++++++++
Msrc/Test.hpp | 12+++++++++++-
Msrc/XCO.cpp | 2+-
Msrc/dsp/oscillator.cpp | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/dsp/oscillator.hpp | 56++++++++++++++++++++++++++++++++++----------------------
7 files changed, 146 insertions(+), 60 deletions(-)

diff --git a/src/EightFO.cpp b/src/EightFO.cpp @@ -143,7 +143,7 @@ void EightFO::processChannel(const ProcessArgs& args, int c) { } Phasor::phase_delta_t EightFO::phaseOffset(int c, Param& p, Input& i, Phasor::phase_delta_t baseOffset) { - float o = p.getValue() * Phasor::maxPhase / 2.0f; + float o = p.getValue() * Phasor::cyclePhase / 2.0f; if (i.isConnected()) { o *= clamp(i.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); } diff --git a/src/Sine.cpp b/src/Sine.cpp @@ -90,7 +90,7 @@ void Sine::processChannel(const ProcessArgs& args, int c) { if (inputs[PHASE_INPUT].isConnected()) { phaseOffset *= clamp(inputs[PHASE_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); } - e.additionalPhaseOffset = -phaseOffset * 0.5f * Phasor::maxPhase; + e.additionalPhaseOffset = -phaseOffset * 0.5f * Phasor::cyclePhase; VCOBase::processChannel(args, c); diff --git a/src/Test.cpp b/src/Test.cpp @@ -511,6 +511,30 @@ void Test::processAll(const ProcessArgs& args) { float in = inputs[IN_INPUT].getVoltage(); outputs[OUT_OUTPUT].setVoltage(_smoother.next(in)); +#elif STEPPED_RANDOM + const float octaves = 7.0f; + float frequency = params[PARAM1_PARAM].getValue(); + frequency *= 2.0f; + frequency -= 1.0f; + frequency *= octaves; + frequency += inputs[CV1_INPUT].getVoltage(); + frequency = clamp(frequency, -octaves, octaves); + // frequency -= 4.0f; + frequency = cvToFrequency(frequency); + frequency = std::min(frequency, 0.49f*APP->engine->getSampleRate()); + + _stepped.setSampleRate(APP->engine->getSampleRate()); + _stepped.setFrequency(frequency); + if (_trigger.next(inputs[CV3_INPUT].getVoltage())) { + _stepped.resetPhase(); + } + outputs[OUT_OUTPUT].setVoltage(_stepped.next() * 5.0f); + + if ((_stepped._phase / SteppedRandomOscillator::cyclePhase) > (_lastPhase / SteppedRandomOscillator::cyclePhase)) { + _lastPhase = _stepped._phase; + _lastNoise = _noise.next() * 5.0f; + } + outputs[OUT2_OUTPUT].setVoltage(_lastNoise); #endif } diff --git a/src/Test.hpp b/src/Test.hpp @@ -32,7 +32,8 @@ extern Model* modelTest; // #define INTEGRATOR 1 // #define RANDOMWALK 1 // #define DCBLOCKER 1 -#define LFO_SMOOTHER 1 +// #define LFO_SMOOTHER 1 +#define STEPPED_RANDOM 1 #include "pitch.hpp" #ifdef LPF @@ -107,6 +108,9 @@ extern Model* modelTest; #elif LFO_SMOOTHER #include "dsp/signal.hpp" #include "dsp/pitch.hpp" +#elif STEPPED_RANDOM +#include "dsp/oscillator.hpp" +#include "dsp/noise.hpp" #else #error what #endif @@ -262,6 +266,12 @@ struct Test : BGModule { float next(float sample); }; Smoother _smoother; +#elif STEPPED_RANDOM + PositiveZeroCrossing _trigger; + SteppedRandomOscillator _stepped; + SteppedRandomOscillator::phase_t _lastPhase = 0; + WhiteNoiseGenerator _noise; + float _lastNoise = 0.0f; #endif Test() diff --git a/src/XCO.cpp b/src/XCO.cpp @@ -285,7 +285,7 @@ Phasor::phase_delta_t XCO::phaseOffset(int c, Param& param, Input& input) { if (input.isConnected()) { v *= clamp(input.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); } - return -v * Phasor::maxPhase / 2.0f; + return -v * Phasor::cyclePhase / 2.0f; } float XCO::level(int c, Param& param, Input& input) { diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -1,5 +1,6 @@ #include "oscillator.hpp" +#include "noise.hpp" using namespace bogaudio::dsp; @@ -13,7 +14,7 @@ void Phasor::setSampleWidth(float sw) { if (_sampleWidth != sw) { _sampleWidth = sw; if (_sampleWidth > 0.001f) { - _samplePhase = _sampleWidth * (float)maxPhase; + _samplePhase = _sampleWidth * (float)cyclePhase; } else { _samplePhase = 0; @@ -38,40 +39,35 @@ float Phasor::nextFromPhasor(const Phasor& phasor, phase_delta_t offset) { if (_samplePhase > 0) { offset -= offset % _samplePhase; } - return _nextForPhase(offset); + return nextForPhase(offset); } void Phasor::_update() { - _delta = ((phase_delta_t)((_frequency / _sampleRate) * maxPhase)) % maxPhase; + _delta = ((phase_delta_t)((_frequency / _sampleRate) * cyclePhase)) % cyclePhase; } float Phasor::_next() { advancePhase(); if (_samplePhase > 0) { - return _nextForPhase(_phase - (_phase % _samplePhase)); + return nextForPhase(_phase - (_phase % _samplePhase)); } - return _nextForPhase(_phase); + return nextForPhase(_phase); } -float Phasor::_nextForPhase(phase_t phase) { +float Phasor::nextForPhase(phase_t phase) { return phase; } -float TablePhasor::_nextForPhase(phase_t phase) { +float TablePhasor::nextForPhase(phase_t phase) { if (_tableLength >= 1024) { - int i = (((((uint64_t)phase) << 16) / maxPhase) * _tableLength) >> 16; - if (i >= _tableLength) { - i %= _tableLength; - } + int i = (((((uint64_t)phase) << 16) / cyclePhase) * _tableLength) >> 16; + i %= _tableLength; return _table.value(i); } - float fi = (phase / (float)maxPhase) * _tableLength; - int i = (int)fi; - if (i >= _tableLength) { - i %= _tableLength; - } + float fi = (phase / (float)cyclePhase) * _tableLength; + int i = (int)fi % _tableLength; float v1 = _table.value(i); float v2 = _table.value(i + 1 == _tableLength ? 0 : i + 1); return v1 + (fi - i)*(v2 - v1); @@ -98,8 +94,8 @@ float SineOscillator::_next() { } -float SawOscillator::_nextForPhase(phase_t phase) { - return (phase / (float)maxPhase) * 2.0f - 1.0f; +float SawOscillator::nextForPhase(phase_t phase) { + return ((phase % cyclePhase) / (float)cyclePhase) * 2.0f - 1.0f; } @@ -118,8 +114,8 @@ void SaturatingSawOscillator::setSaturation(float saturation) { } } -float SaturatingSawOscillator::_nextForPhase(phase_t phase) { - float sample = SawOscillator::_nextForPhase(phase); +float SaturatingSawOscillator::nextForPhase(phase_t phase) { + float sample = SawOscillator::nextForPhase(phase); if (_saturation >= 0.1f) { sample = _tanhf.value(sample * _saturation * M_PI) * _saturationNormalization; } @@ -141,10 +137,12 @@ void BandLimitedSawOscillator::_update() { _qd = q * _delta; } -float BandLimitedSawOscillator::_nextForPhase(phase_t phase) { - float sample = SaturatingSawOscillator::_nextForPhase(phase); - if (phase > maxPhase - _qd) { - float i = (maxPhase - phase) / (float)_qd; +float BandLimitedSawOscillator::nextForPhase(phase_t phase) { + phase %= cyclePhase; + + float sample = SaturatingSawOscillator::nextForPhase(phase); + if (phase > cyclePhase - _qd) { + float i = (cyclePhase - phase) / (float)_qd; i = (1.0f - i) * _halfTableLen; sample -= _table.value((int)i); } @@ -170,10 +168,12 @@ void SquareOscillator::setPulseWidth(float pw) { else if (pw <= minPulseWidth) { pw = minPulseWidth; } - _pulseWidth = maxPhase * pw; + _pulseWidth = cyclePhase * pw; } -float SquareOscillator::_nextForPhase(phase_t phase) { +float SquareOscillator::nextForPhase(phase_t phase) { + phase %= cyclePhase; + if (positive) { if (phase >= _pulseWidth) { positive = false; @@ -201,7 +201,7 @@ void BandLimitedSquareOscillator::setPulseWidth(float pw) { else if (pw <= minPulseWidth) { pw = minPulseWidth; } - _pulseWidth = maxPhase * pw; + _pulseWidth = cyclePhase * pw; if (pw > 0.5) { _offset = 2.0f * pw - 1.0f; @@ -211,25 +211,65 @@ void BandLimitedSquareOscillator::setPulseWidth(float pw) { } } -float BandLimitedSquareOscillator::_nextForPhase(phase_t phase) { - float sample = -BandLimitedSawOscillator::_nextForPhase(phase); - sample += BandLimitedSawOscillator::_nextForPhase(phase - _pulseWidth); +float BandLimitedSquareOscillator::nextForPhase(phase_t phase) { + float sample = -BandLimitedSawOscillator::nextForPhase(phase); + sample += BandLimitedSawOscillator::nextForPhase(phase - _pulseWidth); return sample + _offset; } -float TriangleOscillator::_nextForPhase(phase_t phase) { - float p = (phase / (float)maxPhase) * 4.0f; - if (phase < quarterMaxPhase) { +float TriangleOscillator::nextForPhase(phase_t phase) { + phase %= cyclePhase; + + float p = (phase / (float)cyclePhase) * 4.0f; + if (phase < quarterCyclePhase) { return p; } - if (phase < threeQuartersMaxPhase) { + if (phase < threeQuartersCyclePhase) { return 2.0f - p; } return p - 4.0f; } +SteppedRandomOscillator::SteppedRandomOscillator( + float sampleRate, + float frequency, + phase_t seed +) +: Phasor(sampleRate, frequency) +, _n(4096) +, _k(4093) // prime less than _n +{ + if (seed == 0) { + _seed = Seeds::getInstance().next(); + } + else { + _seed = seed; + } + + WhiteNoiseGenerator noise; + _t = new float[_n]; + for (phase_t i = 0; i < _n; ++i) { + _t[i] = noise.next(); + } +} + +SteppedRandomOscillator::~SteppedRandomOscillator() { + delete[] _t; +} + +void SteppedRandomOscillator::resetPhase() { + _phase -= _phase % cyclePhase; + _phase += cyclePhase; +} + +float SteppedRandomOscillator::nextForPhase(phase_t phase) { + phase_t i = phase / cyclePhase; + return _t[(_seed + i + (_seed + i) % _k) % _n]; +} + + void SineBankOscillator::setPartial(int i, float frequencyRatio, float amplitude) { setPartialFrequencyRatio(i, frequencyRatio); setPartialAmplitude(i, amplitude); diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp @@ -56,9 +56,9 @@ struct OscillatorGenerator : Oscillator, Generator { }; struct Phasor : OscillatorGenerator { - typedef uint32_t phase_t; + typedef uint64_t phase_t; typedef int64_t phase_delta_t; - static constexpr phase_t maxPhase = UINT32_MAX; + static constexpr phase_t cyclePhase = 1L << 32; static constexpr float twoPI = 2.0f * M_PI; static constexpr float maxSampleWidth = 0.25f; @@ -87,19 +87,18 @@ struct Phasor : OscillatorGenerator { } void setSampleWidth(float sw); - void resetPhase(); + virtual void resetPhase(); void setPhase(float radians); void syncPhase(const Phasor& phasor); float nextFromPhasor(const Phasor& phasor, phase_delta_t offset = 0); - inline float nextForPhase(phase_t phase) { return _nextForPhase(phase); } + virtual float nextForPhase(phase_t phase); virtual void _update(); inline void advancePhase() { _phase += _delta; } inline void advancePhase(int n) { assert(n > 0); _phase += n * _delta; } float _next() override final; - virtual float _nextForPhase(phase_t phase); - inline static phase_delta_t radiansToPhase(float radians) { return (radians / twoPI) * maxPhase; } - inline static float phaseToRadians(phase_t phase) { return (phase / (float)maxPhase) * twoPI; } + inline static phase_delta_t radiansToPhase(float radians) { return (radians / twoPI) * cyclePhase; } + inline static float phaseToRadians(phase_t phase) { return (phase / (float)cyclePhase) * twoPI; } }; struct TablePhasor : Phasor { @@ -117,7 +116,7 @@ struct TablePhasor : Phasor { { } - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct SineOscillator : OscillatorGenerator { @@ -168,7 +167,7 @@ struct SawOscillator : Phasor { { } - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct SaturatingSawOscillator : SawOscillator { @@ -187,14 +186,13 @@ struct SaturatingSawOscillator : SawOscillator { } void setSaturation(float saturation); - - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct BandLimitedSawOscillator : SaturatingSawOscillator { int _quality; const Table& _table; - phase_delta_t _qd = 0; + phase_t _qd = 0; float _halfTableLen; BandLimitedSawOscillator( @@ -212,9 +210,8 @@ struct BandLimitedSawOscillator : SaturatingSawOscillator { } void setQuality(int quality); - void _update() override; - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct SquareOscillator : Phasor { @@ -222,7 +219,7 @@ struct SquareOscillator : Phasor { static constexpr float maxPulseWidth = 1.0f - minPulseWidth; static constexpr float defaultPulseWidth = 0.5f; float _pulseWidthInput; - phase_t _pulseWidth = maxPhase * defaultPulseWidth; + phase_t _pulseWidth = cyclePhase * defaultPulseWidth; bool positive = true; SquareOscillator( @@ -234,8 +231,7 @@ struct SquareOscillator : Phasor { } void setPulseWidth(float pw); - - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct BandLimitedSquareOscillator : BandLimitedSawOscillator { @@ -257,13 +253,12 @@ struct BandLimitedSquareOscillator : BandLimitedSawOscillator { } void setPulseWidth(float pw); - - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; }; struct TriangleOscillator : Phasor { - const phase_t quarterMaxPhase = maxPhase * 0.25f; - const phase_t threeQuartersMaxPhase = maxPhase * 0.75f; + const phase_t quarterCyclePhase = cyclePhase * 0.25f; + const phase_t threeQuartersCyclePhase = cyclePhase * 0.75f; TriangleOscillator( float sampleRate = 1000.0f, @@ -273,7 +268,24 @@ struct TriangleOscillator : Phasor { { } - float _nextForPhase(phase_t phase) override; + float nextForPhase(phase_t phase) override; +}; + +struct SteppedRandomOscillator : Phasor { + const phase_t _n; + const phase_t _k; + float* _t = NULL; + phase_t _seed; + + SteppedRandomOscillator( + float sampleRate = 1000.0f, + float frequency = 100.0f, + phase_t seed = 0 + ); + ~SteppedRandomOscillator(); + + void resetPhase() override; + float nextForPhase(phase_t phase) override; }; struct SineBankOscillator : Oscillator {