BogaudioModules

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

commit bb7a046f8056de15265675b666a43b96f9ad7d85
parent fb59d0920be570106a8f7b1afa7978128d3d9234
Author: Matt Demanett <matt@demanett.net>
Date:   Thu, 11 Jan 2018 00:49:03 -0500

Some rudimentary filter stuff.

Diffstat:
Ares-src/Test-src.svg | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares/Test.svg | 0
Asrc/Test.cpp | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/bogaudio.cpp | 4++++
Msrc/bogaudio.hpp | 5+++++
Msrc/dsp/dsp.hpp | 1+
Asrc/dsp/filter.cpp | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/dsp/filter.hpp | 49+++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 356 insertions(+), 0 deletions(-)

diff --git a/res-src/Test-src.svg b/res-src/Test-src.svg @@ -0,0 +1,146 @@ +<svg + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="45" + height="380" + viewBox="0 0 45 380" +> + <style> + text { + fill: #333; + font-family: 'Roboto', sans-serif; + font-weight: bold; + } + text.title { + font-family: 'Comfortaa', sans-serif; + font-weight: normal; + } + text.brand { + font-family: 'Audiowide', sans-serif; + font-weight: bold; + } + </style> + + <defs> + <symbol id="knob" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="-5,0 5,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-5 0,5" stroke-width="1" stroke="#00f" /> + <circle cx="0" cy="0" r="12.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knobguide" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <g transform="rotate(-240) translate(15 0)"> + <text font-size="5.0pt" transform="translate(3 0) rotate(240) translate(-2.2 2.2)">0</text> + </g> + <g transform="rotate(-210) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-180) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-150) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-120) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-90) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-60) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-30) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(0) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(30) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(60) translate(15 0)"> + <text font-size="5.0pt" transform="translate(3 0) rotate(-60) translate(-4 2.2)">10</text> + </g> + </g> + </symbol> + + <symbol id="input" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#0f0" fill="#0f0" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#0f0" fill="none" /> + </g> + </symbol> + + <symbol id="output" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#f00" fill="#f00" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#f00" fill="none" /> + </g> + </symbol> + </defs> + + <rect width="100%" height="100%" fill="#ddd" /> + <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" /> + <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" /> + <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> + + <!-- <polyline points="22.5,0 22.5,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 68)" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 127)" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 177)" /> --> + + <g transform="rotate(-90) translate(-376 13)"> + <text class="title" font-size="7pt" letter-spacing="2.5px">test</text> + <g transform="translate(0 12)"> + <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text> + <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" /> + </g> + </g> + + <g transform="translate(0 25)"> + <text font-size="6pt" letter-spacing="2px" transform="translate(5.5 0)">P1</text> + <use id="PARAM1_PARAM" xlink:href="#knob" transform="translate(0 -6)" /> + <use xlink:href="#knobguide" transform="translate(0 -6)" /> + </g> + + <g transform="translate(0 63)"> + <g transform="translate(5.5 0)"> + <rect width="34" height="38" rx="5" fill="#fafafa" /> + <use id="CV1_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(12.5 35)">CV</text> + </g> + </g> + + <g transform="translate(0 125)"> + <text font-size="6pt" letter-spacing="2px" transform="translate(5.5 0)">P2</text> + <use id="PARAM2_PARAM" xlink:href="#knob" transform="translate(0 -6)" /> + <use xlink:href="#knobguide" transform="translate(0 -6)" /> + </g> + + <g transform="translate(0 165)"> + <g transform="translate(5.5 0)"> + <rect width="34" height="38" rx="5" fill="#fafafa" /> + <use id="CV2_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(12.5 35)">CV</text> + </g> + </g> + <g transform="translate(0 255)"> + <g transform="translate(5.5 0)"> + <rect width="34" height="10" fill="#fafafa" transform="translate(0 63)" /> + <rect width="34" height="70" rx="5" fill="#fafafa" /> + <use id="IN_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(12.5 35)">IN</text> + </g> + <g transform="translate(5.5 41)"> + <rect width="34" height="10" fill="#bbb" transform="translate(0 -3)" /> + <rect width="34" height="35" rx="5" fill="#bbb" /> + <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 0)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(8.5 32)">OUT</text> + </g> + </g> +</svg> diff --git a/res/Test.svg b/res/Test.svg Binary files differ. diff --git a/src/Test.cpp b/src/Test.cpp @@ -0,0 +1,94 @@ + +#include "bogaudio.hpp" +#include "dsp/dsp.hpp" + +using namespace bogaudio::dsp; + +struct Test : Module { + enum ParamsIds { + PARAM1_PARAM, + PARAM2_PARAM, + NUM_PARAMS + }; + + enum InputsIds { + CV1_INPUT, + CV2_INPUT, + IN_INPUT, + NUM_INPUTS + }; + + enum OutputsIds { + OUT_OUTPUT, + NUM_OUTPUTS + }; + + enum LightsIds { + NUM_LIGHTS + }; + + LowPassFilter _lpf; + + Test() + : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) + , _lpf(44100.0, 1000.0, 1.0) + { + reset(); + } + + virtual void reset() override; + virtual void step() override; +}; + +void Test::reset() { +} + +void Test::step() { + if (!inputs[IN_INPUT].active || !outputs[OUT_OUTPUT].active) { + return; + } + + _lpf.setParams( + engineGetSampleRate(), + 10000.0 * clampf(params[PARAM1_PARAM].value, 0.0, 1.0), + std::max(10.0 * clampf(params[PARAM2_PARAM].value, 0.0, 1.0), 0.1) + ); + outputs[OUT_OUTPUT].value = _lpf.next(inputs[IN_INPUT].value); +} + + +TestWidget::TestWidget() { + Test *module = new Test(); + setModule(module); + box.size = Vec(RACK_GRID_WIDTH * 3, RACK_GRID_HEIGHT); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Test.svg"))); + addChild(panel); + } + + addChild(createScrew<ScrewSilver>(Vec(0, 0))); + addChild(createScrew<ScrewSilver>(Vec(box.size.x - 15, 365))); + + // generated by svg_widgets.rb + auto param1ParamPosition = Vec(9.5, 28.5); + auto param2ParamPosition = Vec(9.5, 128.5); + + auto cv1InputPosition = Vec(10.5, 66.0); + auto cv2InputPosition = Vec(10.5, 168.0); + auto inInputPosition = Vec(10.5, 258.0); + + auto outOutputPosition = Vec(10.5, 296.0); + // end generated by svg_widgets.rb + + addParam(createParam<Knob26>(param1ParamPosition, module, Test::PARAM1_PARAM, 0.0, 1.0, 0.5)); + addParam(createParam<Knob26>(param2ParamPosition, module, Test::PARAM2_PARAM, 0.0, 1.0, 0.5)); + + addInput(createInput<Port24>(cv1InputPosition, module, Test::CV1_INPUT)); + addInput(createInput<Port24>(cv2InputPosition, module, Test::CV2_INPUT)); + addInput(createInput<Port24>(inInputPosition, module, Test::IN_INPUT)); + + addOutput(createOutput<Port24>(outOutputPosition, module, Test::OUT_OUTPUT)); +} diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp @@ -28,4 +28,8 @@ void init(rack::Plugin *p) { p->addModel(createModel<SampleHoldWidget>("Bogaudio", "Bogaudio-SampleHold", "S&H", SAMPLE_AND_HOLD_TAG, DUAL_TAG, UTILITY_TAG)); p->addModel(createModel<SwitchWidget>("Bogaudio", "Bogaudio-Switch", "Switch", SWITCH_TAG, UTILITY_TAG)); p->addModel(createModel<VCAWidget>("Bogaudio", "Bogaudio-VCA", "VCA", AMPLIFIER_TAG, DUAL_TAG, UTILITY_TAG)); + +#ifdef EXPERIMENTAL + p->addModel(createModel<TestWidget>("Bogaudio", "Bogaudio-Test", "Test")); +#endif } diff --git a/src/bogaudio.hpp b/src/bogaudio.hpp @@ -76,4 +76,9 @@ struct VCAWidget : ModuleWidget { VCAWidget(); }; + +struct TestWidget : ModuleWidget { + TestWidget(); +}; + } // namespae bogaudio diff --git a/src/dsp/dsp.hpp b/src/dsp/dsp.hpp @@ -5,5 +5,6 @@ #include "buffer.hpp" #include "analyzer.hpp" +#include "filter.hpp" #include "oscillator.hpp" #include "noise.hpp" diff --git a/src/dsp/filter.cpp b/src/dsp/filter.cpp @@ -0,0 +1,57 @@ + +#include <math.h> + +#include "dsp.hpp" + +using namespace bogaudio::dsp; + +// See: http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + +void BiquadFilter::setParams(float b0, float b1, float b2, float a0, float a1, float a2) { + _b0 = b0 / a0; + _b1 = b1 / a0; + _b2 = b2 / a0; + _a1 = a1 / a0; + _a2 = a2 / a0; + // printf("Biquad set params: b0=%f b1=%f b2=%f a1=%f a2=%f\n", _b0, _b1, _b2, _a1, _a2); +} + +float BiquadFilter::next(float sample) { + _x[2] = _x[1]; + _x[1] = _x[0]; + _x[0] = sample; + + _y[2] = _y[1]; + _y[1] = _y[0]; + _y[0] = _b0 * _x[0]; + _y[0] += _b1 * _x[1]; + _y[0] += _b2 * _x[2]; + _y[0] -= _a1 * _y[1]; + _y[0] -= _a2 * _y[2]; + + return _y[0]; +} + + +void LowPassFilter::setParams(float sampleRate, float cutoff, float q) { + if (_sampleRate == sampleRate && _cutoff == cutoff && _q == q) { + return; + } + // printf("\nLPF set param: sr=%f c=%f q=%f\n", _sampleRate, _cutoff, _q); + _sampleRate = sampleRate; + _cutoff = cutoff; + _q = q; + + float w0 = 2.0 * M_PI * _cutoff / _sampleRate; + float cosw0 = cosf(w0); + float alpha = sinf(w0) / (2.0 * _q); + + _biquad.setParams( + (1.0 - cosw0) / 2.0, + 1.0 - cosw0, + (1.0 - cosw0) / 2.0, + 1.0 + alpha, + -2.0 * cosw0, + 1.0 - alpha + ); +} diff --git a/src/dsp/filter.hpp b/src/dsp/filter.hpp @@ -0,0 +1,49 @@ + +namespace bogaudio { +namespace dsp { + +struct Filter { + Filter() {} + virtual ~Filter() {} + + virtual float next(float sample) = 0; +}; + +struct BiquadFilter : Filter { + float _b0 = 0.0; + float _b1 = 0.0; + float _b2 = 0.0; + float _a1 = 0.0; + float _a2 = 0.0 ; + + float _x[3] {}; + float _y[3] {}; + + BiquadFilter() {} + + void setParams(float b0, float b1, float b2, float a0, float a1, float a2); + virtual float next(float sample) override; +}; + +struct LowPassFilter : Filter { + float _sampleRate; + float _cutoff; + float _q; + + BiquadFilter _biquad; + + LowPassFilter(float sampleRate, float cutoff, float q) + : _sampleRate(sampleRate) + , _cutoff(cutoff) + , _q(q) + { + } + + void setParams(float sampleRate, float cutoff, float q); + virtual float next(float sample) override { + return _biquad.next(sample); + } +}; + +} // namespace dsp +} // namespace bogaudio