BogaudioModules

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

commit 28c7763e6deb296bb373ab87f03ff04171b70176
parent de4d71f50145de05dc07a86b3d05afb8e78602ae
Author: Matt Demanett <matt@demanett.net>
Date:   Sun, 10 Jun 2018 17:26:54 -0400

Performance improvements; some slew limit fixes; etc fixes.

Diffstat:
MMakefile | 2+-
Msrc/Detune.cpp | 38++++++++++++++++++--------------------
Msrc/Detune.hpp | 5+++++
Msrc/FMOp.cpp | 62++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/FMOp.hpp | 4+++-
Msrc/Pan.cpp | 4++--
Msrc/Reftone.cpp | 18++++++++++++------
Msrc/Reftone.hpp | 5+++--
Msrc/Stack.cpp | 22+++++++++++++++++-----
Msrc/Stack.hpp | 5+++++
Msrc/VCA.cpp | 13++++++++++---
Msrc/VCA.hpp | 9+++++++--
Msrc/VCAmp.cpp | 6++++--
Msrc/VCAmp.hpp | 1+
Msrc/XFade.cpp | 29++++++++++++++++++++++-------
Msrc/XFade.hpp | 8+++++++-
Msrc/dsp/signal.hpp | 2+-
Msrc/mixer.cpp | 2+-
18 files changed, 165 insertions(+), 70 deletions(-)

diff --git a/Makefile b/Makefile @@ -28,7 +28,7 @@ BENCHMARK_OBJECTS = $(patsubst %, build/%.o, $(BENCHMARK_SOURCES)) BENCHMARK_DEPS = $(patsubst %, build/%.d, $(BENCHMARK_SOURCES)) -include $(BENCHMARK_DEPS) benchmark: $(BENCHMARK_OBJECTS) - $(CXX) -o $@ $^ ../../build/src/util.cpp.o -lbenchmark -lpthread + $(CXX) -o $@ $^ -lbenchmark -lpthread benchmark_clean: rm -f benchmark $(BENCHMARK_OBJECTS) diff --git a/src/Detune.cpp b/src/Detune.cpp @@ -8,35 +8,33 @@ void Detune::step() { float cents = params[CENTS_PARAM].value; if (inputs[CV_INPUT].active) { - cents *= clamp(inputs[CV_INPUT].value, 0.0f, 10.0f) / 10.0; + cents *= clamp(inputs[CV_INPUT].value / 10.0f, 0.0f, 1.0f); cents = roundf(cents); } - cents /= 100.0; + cents /= 100.0f; + float inCV = 0.0f; if (inputs[IN_INPUT].active) { - float cv = inputs[IN_INPUT].value; - outputs[THRU_OUTPUT].value = cv; - if (cents < 0.001) { - outputs[OUT_PLUS_OUTPUT].value = cv; - outputs[OUT_MINUS_OUTPUT].value = cv; - } - else { - float semitone = cvToSemitone(cv); - outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(semitone + cents); - outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(semitone - cents); - } + inCV = inputs[IN_INPUT].value; } - else { - outputs[THRU_OUTPUT].value = 0.0; - if (cents < 0.001) { - outputs[OUT_PLUS_OUTPUT].value = 0.0; - outputs[OUT_MINUS_OUTPUT].value = 0.0; + + if (_cents != cents || _inCV != inCV) { + _cents = cents; + _inCV = inCV; + if (_cents < 0.001f) { + _plusCV = _inCV; + _minusCV = _inCV; } else { - outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(referenceSemitone + cents); - outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(referenceSemitone - cents); + float semitone = cvToSemitone(_inCV); + _plusCV = semitoneToCV(semitone + cents); + _minusCV = semitoneToCV(semitone - cents); } } + + outputs[THRU_OUTPUT].value = _inCV; + outputs[OUT_PLUS_OUTPUT].value = _plusCV; + outputs[OUT_MINUS_OUTPUT].value = _minusCV; } struct DetuneWidget : ModuleWidget { diff --git a/src/Detune.hpp b/src/Detune.hpp @@ -32,6 +32,11 @@ struct Detune : Module { NUM_LIGHTS }; + float _cents = -1.0f; + float _inCV = -1000.0f; + float _plusCV; + float _minusCV; + Detune() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } diff --git a/src/FMOp.cpp b/src/FMOp.cpp @@ -15,7 +15,6 @@ void FMOp::onSampleRateChange() { float sampleRate = engineGetSampleRate(); _envelope.setSampleRate(sampleRate); _phasor.setSampleRate(sampleRate); - _sineTable.setSampleRate(sampleRate); _decimator.setParams(sampleRate, oversample); _maxFrequency = 0.475f * sampleRate; _feedbackSL.setParams(sampleRate, slewLimitTime); @@ -127,11 +126,18 @@ void FMOp::step() { if (_feedbackEnvelopeOn) { feedback *= envelope; } + bool feedbackOn = feedback > 0.001f; + + float out = _levelSL.next(_level); + if (_levelEnvelopeOn) { + out *= envelope; + } float offset = 0.0f; - if (feedback > 0.001f) { + if (feedbackOn) { offset = feedback * _feedbackDelayedSample; } + if (inputs[FM_INPUT].active) { float depth = _depthSL.next(_depth); if (_depthEnvelopeOn) { @@ -139,23 +145,47 @@ void FMOp::step() { } offset += inputs[FM_INPUT].value * depth * 2.0f; } - for (int i = 0; i < oversample; ++i) { - _phasor.advancePhase(); - _buffer[i] = _sineTable.nextFromPhasor(_phasor, Phasor::radiansToPhase(offset)); - } - float out = _levelSL.next(_level); - if (_levelEnvelopeOn) { - out *= envelope; - } - if (_linearLevel) { - out *= _decimator.next(_buffer); + + float sample = 0.0f; + if (out > 0.0001f) { + Phasor::phase_delta_t o = offset > 0.0f ? Phasor::radiansToPhase(offset) : 0; + if (feedbackOn) { + if (_oversampleMix < 1.0f) { + _oversampleMix += oversampleMixIncrement; + } + } + else if (_oversampleMix > 0.0f) { + _oversampleMix -= oversampleMixIncrement; + } + + if (_oversampleMix > 0.0f) { + for (int i = 0; i < oversample; ++i) { + _phasor.advancePhase(); + _buffer[i] = _sineTable.nextFromPhasor(_phasor, o); + } + sample = _oversampleMix * _decimator.next(_buffer); + } + else { + _phasor.advancePhase(oversample); + } + if (_oversampleMix < 1.0f) { + sample += (1.0f - _oversampleMix) * _sineTable.nextFromPhasor(_phasor, o); + } + + if (_linearLevel) { + sample *= out; + } + else { + out = (1.0f - out) * Amplifier::minDecibels; + _amplifier.setLevel(out); + sample = _amplifier.next(sample); + } } else { - out = (1.0f - out) * Amplifier::minDecibels; - _amplifier.setLevel(out); - out = _amplifier.next(_decimator.next(_buffer)); + _phasor.advancePhase(oversample); } - outputs[AUDIO_OUTPUT].value = _feedbackDelayedSample = amplitude * out; + + outputs[AUDIO_OUTPUT].value = _feedbackDelayedSample = amplitude * sample; } struct LinearLevelMenuItem : MenuItem { diff --git a/src/FMOp.hpp b/src/FMOp.hpp @@ -56,6 +56,7 @@ struct FMOp : Module { const int modulationSteps = 100; static constexpr int oversample = 8; const float slewLimitTime = 1.0f; + const float oversampleMixIncrement = 0.01f; int _steps = 0; float _feedback = 0.0f; float _feedbackDelayedSample = 0.0f; @@ -67,10 +68,11 @@ struct FMOp : Module { bool _depthEnvelopeOn = false; float _maxFrequency = 0.0f; float _buffer[oversample]; + float _oversampleMix = 0.0f; ADSR _envelope; Phasor _phasor; SineTableOscillator _sineTable; - LPFDecimator _decimator; + CICDecimator _decimator; SchmittTrigger _gateTrigger; SlewLimiter _feedbackSL; SlewLimiter _depthSL; diff --git a/src/Pan.cpp b/src/Pan.cpp @@ -2,8 +2,8 @@ #include "Pan.hpp" void Pan::onSampleRateChange() { - _slew1.setParams(engineGetSampleRate(), 2.0f); - _slew2.setParams(engineGetSampleRate(), 2.0f); + _slew1.setParams(engineGetSampleRate(), 100.0f); + _slew2.setParams(engineGetSampleRate(), 100.0f); } void Pan::step() { diff --git a/src/Reftone.cpp b/src/Reftone.cpp @@ -6,13 +6,20 @@ void Reftone::step() { const int referencePitch = 0; const int referenceOctave = 4; - _pitch = params[PITCH_PARAM].value; - _octave = params[OCTAVE_PARAM].value; - _fine = params[FINE_PARAM].value; - _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine); + if (!( + _pitch == params[PITCH_PARAM].value && + _octave == params[OCTAVE_PARAM].value && + _fine == params[FINE_PARAM].value + )) { + _pitch = params[PITCH_PARAM].value; + _octave = params[OCTAVE_PARAM].value; + _fine = params[FINE_PARAM].value; + _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine); + _cv = frequencyToCV(_frequency); + } if (outputs[CV_OUTPUT].active) { - outputs[CV_OUTPUT].value = frequencyToCV(_frequency); + outputs[CV_OUTPUT].value = _cv; } else { outputs[CV_OUTPUT].value = 0.0; @@ -172,7 +179,6 @@ float ReftoneDisplay::textRenderWidth(NVGcontext* vg, const char* s, int size) { return strlen(s) * (size / 2.1); } - struct ReftoneWidget : ModuleWidget { ReftoneWidget(Reftone* module) : ModuleWidget(module) { box.size = Vec(RACK_GRID_WIDTH * 3, RACK_GRID_HEIGHT); diff --git a/src/Reftone.hpp b/src/Reftone.hpp @@ -34,8 +34,9 @@ struct Reftone : Module { int _pitch = 9; int _octave = 4; - float _fine = 0.0; - float _frequency = 440.0; + float _fine = 0.0f; + float _frequency = 440.0f; + float _cv = frequencyToCV(_frequency); SineOscillator _sine; Reftone() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { diff --git a/src/Stack.cpp b/src/Stack.cpp @@ -16,15 +16,27 @@ void Stack::step() { semitones = roundf(semitones); } + float inCV = 0.0f; if (inputs[IN_INPUT].active) { - float cv = clamp(inputs[IN_INPUT].value, _minCVOut, _maxCVOut); - outputs[THRU_OUTPUT].value = cv; - outputs[OUT_OUTPUT].value = clamp(semitoneToCV(cvToSemitone(cv) + semitones + params[FINE_PARAM].value), _minCVOut, _maxCVOut); + inCV = clamp(inputs[IN_INPUT].value, _minCVOut, _maxCVOut); + } + + float fine = params[FINE_PARAM].value; + + if (_semitones != semitones || _inCV != inCV || _fine != fine) { + _semitones = semitones; + _inCV = inCV; + _fine = fine; + _outCV = clamp(semitoneToCV((_inCV != 0.0f ? cvToSemitone(_inCV) : referenceSemitone) + _semitones + _fine), _minCVOut, _maxCVOut); + } + + if (inputs[IN_INPUT].active) { + outputs[THRU_OUTPUT].value = _inCV; } else { - outputs[THRU_OUTPUT].value = semitones / 10.0; - outputs[OUT_OUTPUT].value = clamp(semitoneToCV(referenceSemitone + semitones + params[FINE_PARAM].value), _minCVOut, _maxCVOut); + outputs[THRU_OUTPUT].value = _semitones / 10.0; } + outputs[OUT_OUTPUT].value = _outCV; } struct StackWidget : ModuleWidget { diff --git a/src/Stack.hpp b/src/Stack.hpp @@ -38,6 +38,11 @@ struct Stack : Module { const float _minCVOut = semitoneToCV(24.0); // C1 const float _maxCVOut = semitoneToCV(120.0); // C9 + float _semitones = -1000.0f; + float _inCV = -1000.0f; + float _fine = -1000.0f; + float _outCV; + Stack() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } diff --git a/src/VCA.cpp b/src/VCA.cpp @@ -1,19 +1,26 @@ #include "VCA.hpp" +void VCA::onSampleRateChange() { + float sampleRate = engineGetSampleRate(); + _levelSL1.setParams(sampleRate, 100.0f); + _levelSL2.setParams(sampleRate, 100.0f); +} + void VCA::step() { bool linear = params[LINEAR_PARAM].value > 0.5f; lights[LINEAR_LIGHT].value = linear; - channelStep(inputs[IN1_INPUT], outputs[OUT1_OUTPUT], params[LEVEL1_PARAM], inputs[CV1_INPUT], _amplifier1, linear); - channelStep(inputs[IN2_INPUT], outputs[OUT2_OUTPUT], params[LEVEL2_PARAM], inputs[CV2_INPUT], _amplifier2, linear); + channelStep(inputs[IN1_INPUT], outputs[OUT1_OUTPUT], params[LEVEL1_PARAM], inputs[CV1_INPUT], _amplifier1, _levelSL1, linear); + channelStep(inputs[IN2_INPUT], outputs[OUT2_OUTPUT], params[LEVEL2_PARAM], inputs[CV2_INPUT], _amplifier2, _levelSL1, linear); } -void VCA::channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, bool linear) { +void VCA::channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, SlewLimiter& levelSL, bool linear) { if (input.active && output.active) { float level = knob.value; if (cv.active) { level *= clamp(cv.value / 10.0f, 0.0f, 1.0f); } + level = levelSL.next(level); if (linear) { output.value = level * input.value; } diff --git a/src/VCA.hpp b/src/VCA.hpp @@ -37,12 +37,17 @@ struct VCA : Module { }; Amplifier _amplifier1; + SlewLimiter _levelSL1; Amplifier _amplifier2; + SlewLimiter _levelSL2; - VCA() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + VCA() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + onSampleRateChange(); + } + void onSampleRateChange() override; void step() override; - void channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, bool linear); + void channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, SlewLimiter& levelSL, bool linear); }; } // namespace bogaudio diff --git a/src/VCAmp.cpp b/src/VCAmp.cpp @@ -2,7 +2,9 @@ #include "VCAmp.hpp" void VCAmp::onSampleRateChange() { - _rms.setSampleRate(engineGetSampleRate()); + float sampleRate = engineGetSampleRate(); + _levelSL.setParams(sampleRate, 10.0f); + _rms.setSampleRate(sampleRate); } void VCAmp::step() { @@ -13,7 +15,7 @@ void VCAmp::step() { } level *= maxDecibels - minDecibels; level += minDecibels; - _amplifier.setLevel(level); + _amplifier.setLevel(_levelSL.next(level)); outputs[OUT_OUTPUT].value = _amplifier.next(inputs[IN_INPUT].value); _rmsLevel = _rms.next(outputs[OUT_OUTPUT].value / 5.0f); } diff --git a/src/VCAmp.hpp b/src/VCAmp.hpp @@ -33,6 +33,7 @@ struct VCAmp : Module { const float maxDecibels = 12.0f; const float minDecibels = Amplifier::minDecibels; Amplifier _amplifier; + SlewLimiter _levelSL; RootMeanSquare _rms; float _rmsLevel = 0.0f; diff --git a/src/XFade.cpp b/src/XFade.cpp @@ -1,24 +1,39 @@ #include "XFade.hpp" +void XFade::onSampleRateChange() { + _mixSL.setParams(engineGetSampleRate(), 100.0f); +} + void XFade::step() { bool linear = params[LINEAR_PARAM].value > 0.5f; lights[LINEAR_LIGHT].value = linear; + if (!outputs[OUT_OUTPUT].active) { + return; + } float mix = params[MIX_PARAM].value; if (inputs[MIX_INPUT].active) { mix *= clamp(inputs[MIX_INPUT].value / 5.0f, -1.0f, 1.0f); } + mix = _mixSL.next(mix); + + float curveIn = params[CURVE_PARAM].value; + + if (_linear != linear || _mix != mix || _curveIn != curveIn) { + _linear = linear; + _mix = mix; + _curveIn = curveIn; + if (!linear) { + curveIn = powf(params[CURVE_PARAM].value, 0.082f); + } + curveIn *= 2.0f; + curveIn -= 1.0f; - float curve = params[CURVE_PARAM].value; - if (!linear) { - curve = powf(params[CURVE_PARAM].value, 0.082f); + _mixer.setParams(mix, curveIn, linear); } - curve *= 2.0f; - curve -= 1.0f; - _mix.setParams(mix, curve, linear); - outputs[OUT_OUTPUT].value = _mix.next(inputs[A_INPUT].value, inputs[B_INPUT].value); + outputs[OUT_OUTPUT].value = _mixer.next(inputs[A_INPUT].value, inputs[B_INPUT].value); } struct XFadeWidget : ModuleWidget { diff --git a/src/XFade.hpp b/src/XFade.hpp @@ -34,11 +34,17 @@ struct XFade : Module { NUM_LIGHTS }; - CrossFader _mix; + bool _linear = false; + float _mix = 0.0f; + float _curveIn = -1.0f; + SlewLimiter _mixSL; + CrossFader _mixer; XFade() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + onSampleRateChange(); } + void onSampleRateChange() override; void step() override; }; diff --git a/src/dsp/signal.hpp b/src/dsp/signal.hpp @@ -124,7 +124,7 @@ struct SlewLimiter { setParams(sampleRate, milliseconds); } - void setParams(float sampleRate, float milliseconds); + void setParams(float sampleRate, float milliseconds = 1.0f); float next(float sample); }; diff --git a/src/mixer.cpp b/src/mixer.cpp @@ -3,7 +3,7 @@ const float MixerChannel::maxDecibels = 6.0f; const float MixerChannel::minDecibels = Amplifier::minDecibels; -const float MixerChannel::slewTimeMS = 1.0f; +const float MixerChannel::slewTimeMS = 10.0f; void MixerChannel::setSampleRate(float sampleRate) { _slewLimiter.setParams(sampleRate, slewTimeMS);