BogaudioModules

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

commit 0156f1d17b206255129835b0009eb9511cd69a99
parent c4dc8c4a069f0c092c5cd3af439886f3e7b04afe
Author: Matt Demanett <matt@demanett.net>
Date:   Fri, 10 Jul 2020 00:26:44 -0400

FFB: replace silly VCA thing with frequency CV.

Diffstat:
Mres-src/FFB-src.svg | 14+++++++-------
Mres/FFB.svg | 0
Msrc/FFB.cpp | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/FFB.hpp | 7++++++-
4 files changed, 70 insertions(+), 31 deletions(-)

diff --git a/res-src/FFB-src.svg b/res-src/FFB-src.svg @@ -55,14 +55,14 @@ </g> </symbol> - <symbol id="knobguide-mintick" viewBox="0 0 40px 40px"> + <symbol id="knobguide-centertick" viewBox="0 0 40px 40px"> <g transform="translate(20 20)"> - <g transform="rotate(-240) translate(10 0)"> + <g transform="rotate(-90) translate(10 0)"> <polyline points="0,0 4,0" stroke-width="1" stroke="#333" /> </g> - <path d="M 0 -12.5 A 12.5 12.5 0 0 1 12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(0)" /> + <path d="M 0 -12.5 A 12.5 12.5 0 0 1 12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(20)" /> <path d="M 0 -12.5 A 12.5 12.5 0 0 1 12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(43)" /> - <path d="M 0 -12.5 A 12.5 12.5 0 0 0 -12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(0)" /> + <path d="M 0 -12.5 A 12.5 12.5 0 0 0 -12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(-20)" /> <path d="M 0 -12.5 A 12.5 12.5 0 0 0 -12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(-43)" /> </g> </symbol> @@ -183,9 +183,9 @@ <!-- <use id="LOWWPASS_LIGHT" xlink:href="#light-small" transform="translate(1 8.5)" /> --> </g> <g transform="translate(41 228)"> - <text font-size="6pt" letter-spacing="2px" transform="translate(12.5 6)">CV</text> + <text font-size="6pt" letter-spacing="2px" transform="translate(6 6)">FREQ</text> <use id="CV_PARAM" xlink:href="#knob-smallest" transform="translate(11 18.5)" /> - <use xlink:href="#knobguide-mintick" transform="translate(-1 6.5)" /> + <use xlink:href="#knobguide-centertick" transform="translate(-1 6.5)" /> </g> <g transform="translate(80.5 228)"> <text font-size="6pt" letter-spacing="2px" transform="translate(12.5 6)">HP</text> @@ -203,7 +203,7 @@ </g> <g transform="translate(32 0)"> <use id="CV_INPUT" xlink:href="#input" transform="translate(3 4)" /> - <text font-size="6pt" letter-spacing="2px" transform="translate(8.5 39)">CV</text> + <text font-size="6pt" letter-spacing="2px" transform="translate(5.5 39)">FCV</text> </g> </g> <g transform="translate(13 320)"> diff --git a/res/FFB.svg b/res/FFB.svg Binary files differ. diff --git a/src/FFB.cpp b/src/FFB.cpp @@ -1,34 +1,67 @@ #include "FFB.hpp" +#include "dsp/pitch.hpp" void FFB::Engine::sampleRateChange() { float sr = APP->engine->getSampleRate(); for (int i = 0; i < 14; i++) { _slews[i].setParams(sr, 1.0f, 1.0f); } + configureBands(sr, _semitonesOffset); +} + +void FFB::Engine::setSemitonesOffset(float semitonesOffset) { + if (_semitonesOffset != semitonesOffset) { + _semitonesOffset = semitonesOffset; + configureBands(APP->engine->getSampleRate(), _semitonesOffset); + } +} - auto bp = [this, sr](int i, float cutoff) { +void FFB::Engine::configureBands(float sr, float semitonesOffset) { + _lowPass.setParams( + sr, + MultimodeFilter::BUTTERWORTH_TYPE, + 12.0f, + MultimodeFilter::LOWPASS_MODE, + bandFrequency(0, semitonesOffset), + 0.0f + ); + for (int i = 0; i < 12; ++i) { _bandPasses[i].setParams( sr, - cutoff, + bandFrequency(i + 1, semitonesOffset), 0.22f / MultimodeFilter::maxBWPitch, MultimodeFilter::PITCH_BANDWIDTH_MODE ); + } + _highPass.setParams( + sr, + MultimodeFilter::BUTTERWORTH_TYPE, + 12.0f, + MultimodeFilter::HIGHPASS_MODE, + bandFrequency(13, semitonesOffset), + 0.0f + ); +} + +float FFB::Engine::bandFrequency(int i, float semitonesOffset) { + static const float fs[14] = { + 95.0f, + 125.0f, + 175.0f, + 250.0f, + 350.0f, + 500.0f, + 700.0f, + 1000.0f, + 1400.0f, + 2000.0f, + 2800.0f, + 4000.0f, + 5600.0f, + 6900.0f }; - _lowPass.setParams(sr, MultimodeFilter::BUTTERWORTH_TYPE, 12.0f, MultimodeFilter::LOWPASS_MODE, 95.0f, 0.0f); - bp(0, 125.0f); - bp(1, 175.0f); - bp(2, 250.0f); - bp(3, 350.0f); - bp(4, 500.0f); - bp(5, 700.0f); - bp(6, 1000.0f); - bp(7, 1400.0f); - bp(8, 2000.0f); - bp(9, 2800.0f); - bp(10, 4000.0f); - bp(11, 5600.0f); - _highPass.setParams(sr, MultimodeFilter::BUTTERWORTH_TYPE, 12.0f, MultimodeFilter::HIGHPASS_MODE, 6900.0f, 0.0f); + return semitoneToFrequency(frequencyToSemitone(fs[i]) + semitonesOffset); } void FFB::sampleRateChange() { @@ -63,18 +96,19 @@ void FFB::modulate() { void FFB::modulateChannel(int c) { Engine& e = *_engines[c]; - float cv = 1.0f; - if (inputs[CV_INPUT].isConnected()) { - cv = clamp(inputs[CV_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); - cv *= clamp(params[CV_PARAM].getValue(), 0.0f, 1.0f); - } - for (int i = 0; i < 14; ++i) { - float level = e._slews[i].next(_levels[i] * cv); + float level = e._slews[i].next(_levels[i]); level = 1.0f - level; level *= Amplifier::minDecibels; e._amplifiers[i].setLevel(level); } + + float semitones = clamp(params[CV_PARAM].getValue(), -1.0f, 1.0f); + if (inputs[CV_INPUT].isConnected()) { + semitones *= clamp(inputs[CV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); + } + semitones *= 12.0f; + e.setSemitonesOffset(semitones); } void FFB::processChannel(const ProcessArgs& args, int c) { diff --git a/src/FFB.hpp b/src/FFB.hpp @@ -52,12 +52,17 @@ struct FFB : BGModule { MultimodeFilter8 _highPass; Amplifier _amplifiers[14]; bogaudio::dsp::SlewLimiter _slews[14]; + float _semitonesOffset = 0.0f; + float _bandFrequencies[14] {}; Engine() { sampleRateChange(); } void sampleRateChange(); + void setSemitonesOffset(float semitonesOffset); + void configureBands(float sr, float semitonesOffset); + float bandFrequency(int i, float semitonesOffset); }; Engine* _engines[maxChannels] {}; @@ -78,7 +83,7 @@ struct FFB : BGModule { configParam<AmplifierParamQuantity>(BAND_8_PARAM, 0.0f, 1.0f, 1.0f, "Band 8 level"); configParam<AmplifierParamQuantity>(BAND_12_PARAM, 0.0f, 1.0f, 1.0f, "Band 12 level"); configParam<AmplifierParamQuantity>(LOWPASS_PARAM, 0.0f, 1.0f, 1.0f, "Lowpass level"); - configParam(CV_PARAM, 0.0f, 1.0f, 1.0f, "Level CV", "%", 0.0f, 100.0f); + configParam(CV_PARAM, -1.0f, 1.0f, 0.0f, "Frequency offset", " semitones", 0.0f, 12.0f); configParam<AmplifierParamQuantity>(HIGHPASS_PARAM, 0.0f, 1.0f, 1.0f, "Highpass level"); }