BogaudioModules

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

commit b9de1058b50ed44df3b6b8d540f208081ed65776
parent a76c24aeba9b3fc966d0b53584136ad0c756b500
Author: Matt Demanett <matt@demanett.net>
Date:   Sun, 15 Apr 2018 14:42:29 -0400

Integer phasors.

Diffstat:
Msrc/EightFO.cpp | 6+++---
Msrc/EightFO.hpp | 36++++++++++++++++++------------------
Msrc/FMOp.cpp | 3+--
Msrc/VCO.cpp | 2+-
Msrc/XCO.cpp | 8++++----
Msrc/XCO.hpp | 10+++++-----
Msrc/dsp/oscillator.cpp | 157++++++++++++++++++++-----------------------------------------------------------
Msrc/dsp/oscillator.hpp | 58+++++++++++++++++++++++++++++-----------------------------
8 files changed, 101 insertions(+), 179 deletions(-)

diff --git a/src/EightFO.cpp b/src/EightFO.cpp @@ -109,15 +109,15 @@ void EightFO::step() { updateOutput(useSample, outputs[PHASE0_OUTPUT], _phase0Offset, _phase0Sample, _phase0Active); } -float EightFO::phaseOffset(Param& p, Input& i, float baseOffset) { - float o = p.value * Phasor::maxPhase; +Phasor::phase_delta_t EightFO::phaseOffset(Param& p, Input& i, Phasor::phase_delta_t baseOffset) { + float o = p.value * Phasor::maxPhase / 2.0f; if (i.active) { o *= clamp(i.value / 5.0f, -1.0f, 1.0f); } return baseOffset - o; } -void EightFO::updateOutput(bool useSample, Output& output, float& offset, float& sample, bool& active) { +void EightFO::updateOutput(bool useSample, Output& output, Phasor::phase_delta_t& offset, float& sample, bool& active) { if (output.active) { if (useSample && active) { output.value = sample; diff --git a/src/EightFO.hpp b/src/EightFO.hpp @@ -73,14 +73,14 @@ struct EightFO : Module { const int modulationSteps = 100; const float amplitude = 5.0f; - const float basePhase7Offset = Phasor::radiansToPhase(1.75f * M_PI); - const float basePhase6Offset = Phasor::radiansToPhase(1.5f * M_PI); - const float basePhase5Offset = Phasor::radiansToPhase(1.25f * M_PI); - const float basePhase4Offset = Phasor::radiansToPhase(M_PI); - const float basePhase3Offset = Phasor::radiansToPhase(0.75f * M_PI); - const float basePhase2Offset = Phasor::radiansToPhase(0.5f * M_PI); - const float basePhase1Offset = Phasor::radiansToPhase(0.25f * M_PI); - const float basePhase0Offset = Phasor::radiansToPhase(0.0f); + const Phasor::phase_delta_t basePhase7Offset = Phasor::radiansToPhase(1.75f * M_PI); + const Phasor::phase_delta_t basePhase6Offset = Phasor::radiansToPhase(1.5f * M_PI); + const Phasor::phase_delta_t basePhase5Offset = Phasor::radiansToPhase(1.25f * M_PI); + const Phasor::phase_delta_t basePhase4Offset = Phasor::radiansToPhase(M_PI); + const Phasor::phase_delta_t basePhase3Offset = Phasor::radiansToPhase(0.75f * M_PI); + const Phasor::phase_delta_t basePhase2Offset = Phasor::radiansToPhase(0.5f * M_PI); + const Phasor::phase_delta_t basePhase1Offset = Phasor::radiansToPhase(0.25f * M_PI); + const Phasor::phase_delta_t basePhase0Offset = Phasor::radiansToPhase(0.0f); int _modulationStep = 0; Wave _wave = NO_WAVE; @@ -97,14 +97,14 @@ struct EightFO : Module { SawOscillator _ramp; SquareOscillator _square; - float _phase7Offset = 0.0f; - float _phase6Offset = 0.0f; - float _phase5Offset = 0.0f; - float _phase4Offset = 0.0f; - float _phase3Offset = 0.0f; - float _phase2Offset = 0.0f; - float _phase1Offset = 0.0f; - float _phase0Offset = 0.0f; + Phasor::phase_delta_t _phase7Offset = 0.0f; + Phasor::phase_delta_t _phase6Offset = 0.0f; + Phasor::phase_delta_t _phase5Offset = 0.0f; + Phasor::phase_delta_t _phase4Offset = 0.0f; + Phasor::phase_delta_t _phase3Offset = 0.0f; + Phasor::phase_delta_t _phase2Offset = 0.0f; + Phasor::phase_delta_t _phase1Offset = 0.0f; + Phasor::phase_delta_t _phase0Offset = 0.0f; float _phase7Sample = 0.0f; float _phase6Sample = 0.0f; @@ -132,8 +132,8 @@ struct EightFO : Module { virtual void onReset() override; virtual void onSampleRateChange() override; virtual void step() override; - float phaseOffset(Param& p, Input& i, float baseOffset); - void updateOutput(bool useSample, Output& output, float& offset, float& sample, bool& active); + Phasor::phase_delta_t phaseOffset(Param& p, Input& i, Phasor::phase_delta_t baseOffset); + void updateOutput(bool useSample, Output& output, Phasor::phase_delta_t& offset, float& sample, bool& active); }; } // namespace bogaudio diff --git a/src/FMOp.cpp b/src/FMOp.cpp @@ -112,10 +112,9 @@ void FMOp::step() { if (inputs[FM_INPUT].active) { offset += inputs[FM_INPUT].value * _depth * 2.0f; } - offset = Phasor::radiansToPhase(offset); for (int i = 0; i < oversample; ++i) { _phasor.advancePhase(); - _buffer[i] = _sineTable.nextFromPhasor(_phasor, offset); + _buffer[i] = _sineTable.nextFromPhasor(_phasor, Phasor::radiansToPhase(offset)); } float out = _decimator.next(oversample, _buffer); out *= _level; diff --git a/src/VCO.cpp b/src/VCO.cpp @@ -56,7 +56,7 @@ void VCO::step() { } float frequency = _baseHz; - float phaseOffset = 0.0f; + Phasor::phase_delta_t phaseOffset = 0; if (inputs[FM_INPUT].active && _fmDepth > 0.01f) { float fm = inputs[FM_INPUT].value * _fmDepth; if (_fmLinearMode) { diff --git a/src/XCO.cpp b/src/XCO.cpp @@ -84,7 +84,7 @@ void XCO::step() { } float frequency = _baseHz; - float phaseOffset = 0.0f; + Phasor::phase_delta_t phaseOffset = 0; if (inputs[FM_INPUT].active && _fmDepth > 0.01f) { float fm = inputs[FM_INPUT].value * _fmDepth; if (_fmLinearMode) { @@ -131,7 +131,7 @@ void XCO::step() { float sawOut = 0.0f; float triangleOut = 0.0f; float sineOut = 0.0f; - float sineFeedbackOffset = sineFeedback ? Phasor::radiansToPhase(_sineFeedback * _sineFeedbackDelayedSample) : 0.0f; + Phasor::phase_delta_t sineFeedbackOffset = sineFeedback ? Phasor::radiansToPhase(_sineFeedback * _sineFeedbackDelayedSample) : 0.0f; if (squareOversample || sawOversample || triangleOversample || sineOversample) { for (int i = 0; i < oversample; ++i) { @@ -189,12 +189,12 @@ void XCO::step() { outputs[MIX_OUTPUT].value = squareOut + sawOut + triangleOut + sineOut; } -float XCO::phaseOffset(Param& param, Input& input) { +Phasor::phase_delta_t XCO::phaseOffset(Param& param, Input& input) { float v = param.value; if (input.active) { v *= clamp(input.value / 5.0f, -1.0f, 1.0f); } - return -v; + return -v * Phasor::maxPhase / 2.0f; } float XCO::level(Param& param, Input& input) { diff --git a/src/XCO.hpp b/src/XCO.hpp @@ -79,10 +79,10 @@ struct XCO : Module { float _triangleSampleWidth = 0.0f; float _sineFeedback = 0.0f; float _sineFeedbackDelayedSample = 0.0f; - float _squarePhaseOffset = 0.0f; - float _sawPhaseOffset = 0.0f; - float _trianglePhaseOffset = 0.0f; - float _sinePhaseOffset = 0.0f; + Phasor::phase_delta_t _squarePhaseOffset = 0.0f; + Phasor::phase_delta_t _sawPhaseOffset = 0.0f; + Phasor::phase_delta_t _trianglePhaseOffset = 0.0f; + Phasor::phase_delta_t _sinePhaseOffset = 0.0f; float _squareMix = 1.0f; float _sawMix = 1.0f; float _triangleMix = 1.0f; @@ -113,7 +113,7 @@ struct XCO : Module { virtual void onReset() override; virtual void onSampleRateChange() override; virtual void step() override; - float phaseOffset(Param& param, Input& input); + Phasor::phase_delta_t phaseOffset(Param& param, Input& input); float level(Param& param, Input& input); void setSampleRate(float sampleRate); void setFrequency(float frequency); diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -14,10 +14,10 @@ void Phasor::setSampleWidth(float sw) { if (_sampleWidth != sw) { _sampleWidth = sw; if (_sampleWidth > 0.001f) { - _samplePhase = _sampleWidth * maxPhase; + _samplePhase = _sampleWidth * (float)maxPhase; } else { - _samplePhase = 0.0f; + _samplePhase = 0; } } } @@ -26,104 +26,37 @@ void Phasor::setPhase(float radians) { _phase = radiansToPhase(radians); } -float Phasor::nextFromPhasor(const Phasor& phasor, float offset) { - float p = phasor._phase + offset; - while (p >= maxPhase) { - p -= maxPhase; +float Phasor::nextFromPhasor(const Phasor& phasor, phase_delta_t offset) { + offset += phasor._phase; + if (_samplePhase > 0) { + offset -= offset % _samplePhase; } - while (p < 0.0f) { - p += maxPhase; - } - - if (_samplePhase > 0.0f) { - p -= fmodf(p, _samplePhase); - } - return _nextForPhase(p); + return _nextForPhase(offset); } void Phasor::_update() { - _delta = (_frequency / _sampleRate) * maxPhase; - if (_delta >= maxPhase) { - _delta -= maxPhase; - if (_delta >= maxPhase) { - _delta = fmodf(_delta, maxPhase); - } - } - else if (_delta < 0.0f) { - _delta += maxPhase; - if (_delta < 0.0f) { - _delta = maxPhase - fmodf(-_delta, maxPhase); - } - } -} - -float Phasor::nextForPhase(float phase) { - while (phase >= maxPhase) { - phase -= maxPhase; - } - while (phase < 0.0f) { - phase += maxPhase; - } - return _nextForPhase(phase); -} - -void Phasor::advancePhase() { - _phase += _delta; - if (_phase >= maxPhase) { - _phase -= maxPhase; - } - if (_phase < 0.0f) { - _phase += maxPhase; - } - assert(_phase >= 0.0f); - assert(_phase < maxPhase); -} - -void Phasor::advancePhase(int n) { - assert(n > 0); - _phase += n * _delta; - if (_phase >= maxPhase) { - _phase -= maxPhase; - } - if (_phase < 0.0f) { - _phase += maxPhase; - } - assert(_phase >= 0.0f); - assert(_phase < maxPhase); -} - -void Phasor::advancePhasePositive() { - assert(_delta >= 0.0f); - _phase += _delta; - if (_phase >= maxPhase) { - _phase -= maxPhase; - } - assert(_phase < maxPhase); + _delta = ((phase_delta_t)((_frequency / _sampleRate) * maxPhase)) % maxPhase; } float Phasor::_next() { advancePhase(); - if (_samplePhase > 0.0f) { - return _nextForPhase(_phase - fmodf(_phase, _samplePhase)); + if (_samplePhase > 0) { + return _nextForPhase(_phase - (_phase % _samplePhase)); } return _nextForPhase(_phase); } -float Phasor::_nextForPhase(float phase) { +float Phasor::_nextForPhase(phase_t phase) { return phase; } -float TablePhasor::_nextForPhase(float phase) { - while (phase >= maxPhase) { - phase -= maxPhase; - } - while (phase < 0.0f) { - phase += maxPhase; - } - - float fi = phase * (_tableLength / 2); +float TablePhasor::_nextForPhase(phase_t phase) { + float fi = (phase / (float)maxPhase) * _tableLength; int i = (int)fi; + if (i >= _tableLength) { + i %= _tableLength; + } float v1 = _table.value(i); if (_tableLength >= 1024) { return v1; @@ -153,8 +86,8 @@ float SineOscillator::_next() { } -float SawOscillator::_nextForPhase(float phase) { - return phase - halfMaxPhase; +float SawOscillator::_nextForPhase(phase_t phase) { + return (phase / (float)maxPhase) * 2.0f - 1.0f; } @@ -171,7 +104,7 @@ void SaturatingSawOscillator::setSaturation(float saturation) { } } -float SaturatingSawOscillator::_nextForPhase(float phase) { +float SaturatingSawOscillator::_nextForPhase(phase_t phase) { float sample = SawOscillator::_nextForPhase(phase); if (_saturation >= 0.1f) { sample = tanhf(sample * _saturation * M_PI) * _saturationNormalization; @@ -194,15 +127,15 @@ void BandLimitedSawOscillator::_update() { _qd = q * _delta; } -float BandLimitedSawOscillator::_nextForPhase(float phase) { +float BandLimitedSawOscillator::_nextForPhase(phase_t phase) { float sample = SaturatingSawOscillator::_nextForPhase(phase); if (phase > maxPhase - _qd) { - float i = (maxPhase - phase) / _qd; + float i = (maxPhase - phase) / (float)_qd; i = (1.0f - i) * _halfTableLen; sample -= _table.value((int)i); } else if (phase < _qd) { - float i = phase / _qd; + float i = phase / (float)_qd; i *= _halfTableLen - 1; i += _halfTableLen; sample -= _table.value((int)i); @@ -218,18 +151,15 @@ void SquareOscillator::setPulseWidth(float pw) { _pulseWidthInput = pw; if (pw >= maxPulseWidth) { - _pulseWidth = maxPulseWidth; + pw = maxPulseWidth; } else if (pw <= minPulseWidth) { - _pulseWidth = minPulseWidth; - } - else { - _pulseWidth = pw; + pw = minPulseWidth; } - _pulseWidth *= maxPhase; + _pulseWidth = maxPhase * pw; } -float SquareOscillator::_nextForPhase(float phase) { +float SquareOscillator::_nextForPhase(phase_t phase) { if (positive) { if (phase >= _pulseWidth) { positive = false; @@ -252,44 +182,37 @@ void BandLimitedSquareOscillator::setPulseWidth(float pw) { _pulseWidthInput = pw; if (pw >= maxPulseWidth) { - _pulseWidth = maxPulseWidth; + pw = maxPulseWidth; } else if (pw <= minPulseWidth) { - _pulseWidth = minPulseWidth; + pw = minPulseWidth; } - else { - _pulseWidth = pw; - } - _pulseWidth *= maxPhase; + _pulseWidth = maxPhase * pw; - if (_pulseWidth >= 1.0f) { - _offset = _pulseWidth - 1.0f; + if (pw > 0.5) { + _offset = 2.0f * pw - 1.0f; } else { - _offset = -(1.0f - _pulseWidth); + _offset = -(1.0f - 2.0f * pw); } } -float BandLimitedSquareOscillator::_nextForPhase(float phase) { +float BandLimitedSquareOscillator::_nextForPhase(phase_t phase) { float sample = -BandLimitedSawOscillator::_nextForPhase(phase); - phase -= _pulseWidth; - if (phase < 0.0f) { - phase += maxPhase; - } - sample += BandLimitedSawOscillator::_nextForPhase(phase); + sample += BandLimitedSawOscillator::_nextForPhase(phase - _pulseWidth); return sample + _offset; } -float TriangleOscillator::_nextForPhase(float phase) { - float p = maxPhase * phase; +float TriangleOscillator::_nextForPhase(phase_t phase) { + float p = (phase / (float)maxPhase) * 4.0f; if (phase < quarterMaxPhase) { return p; } if (phase < threeQuartersMaxPhase) { - return maxPhase - p; + return 2.0f - p; } - return p - twiceMaxPhase; + return p - 4.0f; } @@ -346,10 +269,10 @@ void SineBankOscillator::_frequencyChanged() { } } -float SineBankOscillator::next(float phaseOffset) { +float SineBankOscillator::next(Phasor::phase_t phaseOffset) { float next = 0.0; for (Partial& p : _partials) { - p.sine.advancePhasePositive(); + p.sine.advancePhase(); if (p.frequency < _maxPartialFrequency && (p.amplitude > 0.001 || p.amplitude < -0.001 || p.amplitudeSteps > 0)) { if (p.amplitudeSteps > 0) { if (p.amplitudeSteps == 1) { 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 <math.h> #include <vector> @@ -54,13 +55,16 @@ struct OscillatorGenerator : Oscillator, Generator { }; struct Phasor : OscillatorGenerator { - static constexpr float maxPhase = 2.0f; + typedef uint32_t phase_t; + typedef int64_t phase_delta_t; + static constexpr phase_t maxPhase = UINT32_MAX; + static constexpr float twoPI = 2.0f * M_PI; static constexpr float maxSampleWidth = 0.25f; - float _delta; - double _phase = 0.0; + phase_delta_t _delta; + phase_t _phase = 0; float _sampleWidth = 0.0f; - float _samplePhase = 0.0f; + phase_t _samplePhase = 0; Phasor( float sampleRate = 1000.0f, @@ -81,19 +85,18 @@ struct Phasor : OscillatorGenerator { _update(); } - void setSampleWidth(float sw); // fraction of maxPhase. + void setSampleWidth(float sw); void setPhase(float radians); - float nextFromPhasor(const Phasor& phasor, float offset = 0.0f); // offset is not radians, but local phase. - float nextForPhase(float phase); // local phase, not radians. + float nextFromPhasor(const Phasor& phasor, phase_delta_t offset = 0); + inline float nextForPhase(phase_t phase) { return _nextForPhase(phase); } virtual void _update(); - void advancePhase(); - void advancePhase(int n); - void advancePhasePositive(); + inline void advancePhase() { _phase += _delta; } + inline void advancePhase(int n) { assert(n > 0); _phase += n * _delta; } virtual float _next() override final; - virtual float _nextForPhase(float phase); + virtual float _nextForPhase(phase_t phase); - inline static float radiansToPhase(float radians) { return radians / M_PI; } - inline static float phaseToRadians(float phase) { return phase * M_PI; } + inline static phase_delta_t radiansToPhase(float radians) { return (radians / twoPI) * maxPhase; } + inline static float phaseToRadians(phase_t phase) { return (phase / (float)maxPhase) * twoPI; } }; struct TablePhasor : Phasor { @@ -111,7 +114,7 @@ struct TablePhasor : Phasor { { } - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct SineOscillator : OscillatorGenerator { @@ -154,8 +157,6 @@ struct SineTableOscillator : TablePhasor { }; struct SawOscillator : Phasor { - const float halfMaxPhase = 0.5f * maxPhase; - SawOscillator( float sampleRate = 1000.0f, float frequency = 100.0f @@ -164,7 +165,7 @@ struct SawOscillator : Phasor { { } - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct SaturatingSawOscillator : SawOscillator { @@ -183,13 +184,13 @@ struct SaturatingSawOscillator : SawOscillator { void setSaturation(float saturation); - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct BandLimitedSawOscillator : SaturatingSawOscillator { int _quality; const Table& _table; - float _qd = 0.0f; + phase_delta_t _qd = 0; float _halfTableLen; BandLimitedSawOscillator( @@ -209,14 +210,14 @@ struct BandLimitedSawOscillator : SaturatingSawOscillator { void setQuality(int quality); virtual void _update() override; - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct SquareOscillator : Phasor { const float minPulseWidth = 0.03f; const float maxPulseWidth = 1.0f - minPulseWidth; float _pulseWidthInput; - float _pulseWidth = 0.5; + phase_t _pulseWidth = maxPhase / 2; bool positive = true; SquareOscillator( @@ -229,14 +230,14 @@ struct SquareOscillator : Phasor { void setPulseWidth(float pw); - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct BandLimitedSquareOscillator : BandLimitedSawOscillator { const float minPulseWidth = 0.03f; const float maxPulseWidth = 1.0f - minPulseWidth; float _pulseWidthInput; - float _pulseWidth; + phase_delta_t _pulseWidth; float _offset; BandLimitedSquareOscillator( @@ -252,13 +253,12 @@ struct BandLimitedSquareOscillator : BandLimitedSawOscillator { void setPulseWidth(float pw); - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct TriangleOscillator : Phasor { - const float quarterMaxPhase = 0.25f * maxPhase; - const float threeQuartersMaxPhase = 0.75f * maxPhase; - const float twiceMaxPhase = 2.0f * maxPhase; + const phase_t quarterMaxPhase = maxPhase * 0.25f; + const phase_t threeQuartersMaxPhase = maxPhase * 0.75f; TriangleOscillator( float sampleRate = 1000.0f, @@ -268,7 +268,7 @@ struct TriangleOscillator : Phasor { { } - virtual float _nextForPhase(float phase) override; + virtual float _nextForPhase(phase_t phase) override; }; struct SineBankOscillator : Oscillator { @@ -323,7 +323,7 @@ struct SineBankOscillator : Oscillator { virtual void _sampleRateChanged() override; virtual void _frequencyChanged() override; - float next(float phaseOffset = 0.0f); // Phasor "phase", not radians. + float next(Phasor::phase_t phaseOffset = 0.0f); }; } // namespace dsp