BogaudioModules

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

commit 3d4f7c1a481cb2060d574f1174aa810de47dc32e
parent 0569b10136b6d94550319991ff52a0720e4977ed
Author: Matt Demanett <matt@demanett.net>
Date:   Tue, 10 Apr 2018 21:17:33 -0400

VCO/XCO fixes.

Diffstat:
Msrc/VCO.cpp | 39+++++++++++++++++----------------------
Msrc/VCO.hpp | 2--
Msrc/XCO.cpp | 97++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/XCO.hpp | 3+--
Msrc/dsp/oscillator.cpp | 15++++++++++++++-
Msrc/dsp/oscillator.hpp | 1+
6 files changed, 82 insertions(+), 75 deletions(-)

diff --git a/src/VCO.cpp b/src/VCO.cpp @@ -35,7 +35,7 @@ void VCO::step() { _baseVOct += clamp(inputs[PITCH_INPUT].value, -5.0f, 5.0f); } if (_slowMode) { - _baseVOct -= 5.0f; + _baseVOct -= 7.0f; } _baseHz = cvToFrequency(_baseVOct); @@ -88,29 +88,17 @@ void VCO::step() { float squareOut = 0.0f; float sawOut = 0.0f; float triangleOut = 0.0f; - _phasor.advancePhase(); - if (mix > 0.0f) { - if (outputs[SQUARE_OUTPUT].active) { - squareOut += mix * amplitude * _square.nextFromPhasor(_phasor, phaseOffset); - } - if (outputs[SAW_OUTPUT].active) { - sawOut += mix * amplitude * _saw.nextFromPhasor(_phasor, phaseOffset); - } - if (outputs[TRIANGLE_OUTPUT].active) { - triangleOut += mix * amplitude * _triangle.nextFromPhasor(_phasor, phaseOffset); - } - } if (oMix > 0.0f) { for (int i = 0; i < oversample; ++i) { - _oversamplePhasor.advancePhase(); + _phasor.advancePhase(); if (outputs[SQUARE_OUTPUT].active) { - _squareBuffer[i] = _square.nextFromPhasor(_oversamplePhasor, phaseOffset); + _squareBuffer[i] = _square.nextFromPhasor(_phasor, phaseOffset); } if (outputs[SAW_OUTPUT].active) { - _sawBuffer[i] = _saw.nextFromPhasor(_oversamplePhasor, phaseOffset); + _sawBuffer[i] = _saw.nextFromPhasor(_phasor, phaseOffset); } if (outputs[TRIANGLE_OUTPUT].active) { - _triangleBuffer[i] = _saw.nextFromPhasor(_oversamplePhasor, phaseOffset); + _triangleBuffer[i] = _triangle.nextFromPhasor(_phasor, phaseOffset); } } if (outputs[SQUARE_OUTPUT].active) { @@ -124,8 +112,17 @@ void VCO::step() { } } else { - for (int i = 0; i < oversample; ++i) { - _oversamplePhasor.advancePhase(); + _phasor.advancePhase(oversample); + } + if (mix > 0.0f) { + if (outputs[SQUARE_OUTPUT].active) { + squareOut += mix * amplitude * _square.nextFromPhasor(_phasor, phaseOffset); + } + if (outputs[SAW_OUTPUT].active) { + sawOut += mix * amplitude * _saw.nextFromPhasor(_phasor, phaseOffset); + } + if (outputs[TRIANGLE_OUTPUT].active) { + triangleOut += mix * amplitude * _triangle.nextFromPhasor(_phasor, phaseOffset); } } @@ -138,7 +135,6 @@ void VCO::step() { void VCO::setSampleRate(float sampleRate) { _oversampleThreshold = 0.06f * sampleRate; _phasor.setSampleRate(sampleRate); - _oversamplePhasor.setSampleRate(sampleRate); _square.setSampleRate(sampleRate); _saw.setSampleRate(sampleRate); _squareDecimator.setParams(sampleRate, oversample); @@ -149,8 +145,7 @@ void VCO::setSampleRate(float sampleRate) { void VCO::setFrequency(float frequency) { if (_frequency != frequency && frequency < 0.47f * _phasor._sampleRate) { _frequency = frequency; - _phasor.setFrequency(_frequency); - _oversamplePhasor.setFrequency(_frequency / (float)oversample); + _phasor.setFrequency(_frequency / (float)oversample); _square.setFrequency(_frequency); _saw.setFrequency(_frequency); } diff --git a/src/VCO.hpp b/src/VCO.hpp @@ -56,7 +56,6 @@ struct VCO : Module { SchmittTrigger _syncTrigger; Phasor _phasor; - Phasor _oversamplePhasor; BandLimitedSquareOscillator _square; BandLimitedSawOscillator _saw; TriangleOscillator _triangle; @@ -71,7 +70,6 @@ struct VCO : Module { VCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) , _phasor(0.0f, 1.0f) - , _oversamplePhasor(0.0f, 1.0f) , _square(0.0f, 0.0f) , _saw(0.0f, 0.0f) , _triangle(0.0f, 0.0f) diff --git a/src/XCO.cpp b/src/XCO.cpp @@ -36,7 +36,7 @@ void XCO::step() { _baseVOct += clamp(inputs[PITCH_INPUT].value, -5.0f, 5.0f); } if (_slowMode) { - _baseVOct -= 5.0f; + _baseVOct -= 7.0f; } _baseHz = cvToFrequency(_baseVOct); @@ -59,11 +59,11 @@ void XCO::step() { } _saw.setSaturation(saturation * 10.f); - float sample = params[TRIANGLE_SAMPLE_PARAM].value * Phasor::maxSampleWidth; + _triangleSampleWidth = params[TRIANGLE_SAMPLE_PARAM].value * Phasor::maxSampleWidth; if (inputs[TRIANGLE_SAMPLE_INPUT].active) { - sample *= clamp(inputs[TRIANGLE_SAMPLE_INPUT].value / 10.0f, 0.0f, 1.0f); + _triangleSampleWidth *= clamp(inputs[TRIANGLE_SAMPLE_INPUT].value / 10.0f, 0.0f, 1.0f); } - _triangle.setSampleWidth(sample); + _triangle.setSampleWidth(_triangleSampleWidth); _sineFeedback = params[SINE_FEEDBACK_PARAM].value; if (inputs[SINE_FEEDBACK_INPUT].active) { @@ -113,70 +113,73 @@ void XCO::step() { oMix = 0.0f; } + bool triangleSample = _triangleSampleWidth > 0.001f; + bool sineFeedback = _sineFeedback > 0.001f; bool squareActive = outputs[MIX_OUTPUT].active || outputs[SQUARE_OUTPUT].active; bool sawActive = outputs[MIX_OUTPUT].active || outputs[SAW_OUTPUT].active; bool triangleActive = outputs[MIX_OUTPUT].active || outputs[TRIANGLE_OUTPUT].active; bool sineActive = outputs[MIX_OUTPUT].active || outputs[SINE_OUTPUT].active; + bool squareOversample = squareActive && oMix > 0.0f; + bool sawOversample = sawActive && oMix > 0.0f; + bool triangleOversample = triangleActive && (triangleSample || oMix > 0.0f); + bool sineOversample = sineActive && sineFeedback; + bool squareNormal = squareActive && mix > 0.0f; + bool sawNormal = sawActive && mix > 0.0f; + bool triangleNormal = triangleActive && !triangleSample && mix > 0.0f; + bool sineNormal = sineActive && !sineFeedback; float squareOut = 0.0f; float sawOut = 0.0f; float triangleOut = 0.0f; float sineOut = 0.0f; - float sineFeedbackOffset = 0.0f; - if (_sineFeedback > 0.001f) { - sineFeedbackOffset = Phasor::radiansToPhase(_sineFeedback * _phasor.next()); - } - else { - _phasor.advancePhase(); - } - - if (mix > 0.0f) { - if (squareActive) { - squareOut += mix * amplitude * _squareMix * _square.nextFromPhasor(_phasor, _squarePhaseOffset + phaseOffset); - } - if (sawActive) { - sawOut += mix * amplitude * _sawMix * _saw.nextFromPhasor(_phasor, _sawPhaseOffset + phaseOffset); - } - if (triangleActive) { - triangleOut += mix * amplitude * _triangleMix * _triangle.nextFromPhasor(_phasor, _trianglePhaseOffset + phaseOffset); - } - if (sineActive) { - sineOut += mix * amplitude * _sineMix * _sine.nextFromPhasor(_phasor, sineFeedbackOffset + _sinePhaseOffset + phaseOffset); - } - } + float sineFeedbackOffset = sineFeedback ? Phasor::radiansToPhase(_sineFeedback * _phasor._phase) : 0.0f; - if (oMix > 0.0f) { + if (squareOversample || sawOversample || triangleOversample || sineOversample) { for (int i = 0; i < oversample; ++i) { - _oversamplePhasor.advancePhase(); - if (squareActive) { - _squareBuffer[i] = _square.nextFromPhasor(_oversamplePhasor, _squarePhaseOffset + phaseOffset); + _phasor.advancePhase(); + if (squareOversample) { + _squareBuffer[i] = _square.nextFromPhasor(_phasor, _squarePhaseOffset + phaseOffset); } - if (sawActive) { - _sawBuffer[i] = _saw.nextFromPhasor(_oversamplePhasor, _sawPhaseOffset + phaseOffset); + if (sawOversample) { + _sawBuffer[i] = _saw.nextFromPhasor(_phasor, _sawPhaseOffset + phaseOffset); } - if (triangleActive) { - _triangleBuffer[i] = _triangle.nextFromPhasor(_oversamplePhasor, _trianglePhaseOffset + phaseOffset); + if (triangleOversample) { + _triangleBuffer[i] = _triangle.nextFromPhasor(_phasor, _trianglePhaseOffset + phaseOffset); } - if (sineActive) { - _sineBuffer[i] = _sine.nextFromPhasor(_oversamplePhasor, sineFeedbackOffset + _sinePhaseOffset + phaseOffset); + if (sineOversample) { + _sineBuffer[i] = _sine.nextFromPhasor(_phasor, sineFeedbackOffset + _sinePhaseOffset + phaseOffset); } } - if (squareActive) { + if (squareOversample) { squareOut += oMix * amplitude * _squareDecimator.next(oversample, _squareBuffer); } - if (sawActive) { + if (sawOversample) { sawOut += oMix * amplitude * _sawDecimator.next(oversample, _sawBuffer); } - if (triangleActive) { - triangleOut += oMix * amplitude * _triangleDecimator.next(oversample, _triangleBuffer); + if (triangleOversample) { + triangleOut += amplitude * _triangleDecimator.next(oversample, _triangleBuffer); + if (!triangleSample) { + triangleOut *= oMix; + } } - if (sineActive) { - sineOut += oMix * amplitude * _sineDecimator.next(oversample, _sineBuffer); + if (sineOversample) { + sineOut += amplitude * _sineDecimator.next(oversample, _sineBuffer); } } else { - for (int i = 0; i < oversample; ++i) { - _oversamplePhasor.advancePhase(); - } + _phasor.advancePhase(oversample); + } + + if (squareNormal) { + squareOut += mix * amplitude * _squareMix * _square.nextFromPhasor(_phasor, _squarePhaseOffset + phaseOffset); + } + if (sawNormal) { + sawOut += mix * amplitude * _sawMix * _saw.nextFromPhasor(_phasor, _sawPhaseOffset + phaseOffset); + } + if (triangleNormal) { + triangleOut += mix * amplitude * _triangleMix * _triangle.nextFromPhasor(_phasor, _trianglePhaseOffset + phaseOffset); + } + if (sineNormal) { + sineOut += amplitude * _sineMix * _sine.nextFromPhasor(_phasor, sineFeedbackOffset + _sinePhaseOffset + phaseOffset); } outputs[SQUARE_OUTPUT].value = squareOut; @@ -205,7 +208,6 @@ float XCO::level(Param& param, Input& input) { void XCO::setSampleRate(float sampleRate) { _oversampleThreshold = 0.06f * sampleRate; _phasor.setSampleRate(sampleRate); - _oversamplePhasor.setSampleRate(sampleRate); _square.setSampleRate(sampleRate); _saw.setSampleRate(sampleRate); _squareDecimator.setParams(sampleRate, oversample); @@ -217,8 +219,7 @@ void XCO::setSampleRate(float sampleRate) { void XCO::setFrequency(float frequency) { if (_frequency != frequency && frequency < 0.47f * _phasor._sampleRate) { _frequency = frequency; - _phasor.setFrequency(_frequency); - _oversamplePhasor.setFrequency(_frequency / (float)oversample); + _phasor.setFrequency(_frequency / (float)oversample); _square.setFrequency(_frequency); _saw.setFrequency(_frequency); } diff --git a/src/XCO.hpp b/src/XCO.hpp @@ -76,6 +76,7 @@ struct XCO : Module { bool _slowMode = false; float _fmDepth = 0.0f; bool _fmLinearMode = false; + float _triangleSampleWidth = 0.0f; float _sineFeedback = 0.0f; float _squarePhaseOffset = 0.0f; float _sawPhaseOffset = 0.0f; @@ -88,7 +89,6 @@ struct XCO : Module { SchmittTrigger _syncTrigger; Phasor _phasor; - Phasor _oversamplePhasor; BandLimitedSquareOscillator _square; BandLimitedSawOscillator _saw; TriangleOscillator _triangle; @@ -105,7 +105,6 @@ struct XCO : Module { XCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) , _phasor(0.0f, 1.0f) - , _oversamplePhasor(0.0f, 1.0f) , _square(0.0f, 0.0f) , _saw(0.0f, 0.0f) , _triangle(0.0f, 0.0f) diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp @@ -79,6 +79,19 @@ void Phasor::advancePhase() { 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; @@ -161,7 +174,7 @@ void SaturatingSawOscillator::setSaturation(float saturation) { float SaturatingSawOscillator::_nextForPhase(float phase) { float sample = SawOscillator::_nextForPhase(phase); if (_saturation >= 0.1f) { - sample = tanhf(-sample * _saturation * M_PI) * _saturationNormalization; + sample = tanhf(sample * _saturation * M_PI) * _saturationNormalization; } return sample; } diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp @@ -87,6 +87,7 @@ struct Phasor : OscillatorGenerator { float nextForPhase(float phase); // local phase, not radians. virtual void _update(); void advancePhase(); + void advancePhase(int n); void advancePhasePositive(); virtual float _next() override final; virtual float _nextForPhase(float phase);