BogaudioModules

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

commit 638ec265b390a22492efd04464740ef14b51b982
parent ccf5c5b43cb43113324d1c1b99fbab97e254be02
Author: Matt Demanett <matt@demanett.net>
Date:   Thu, 24 May 2018 21:37:51 -0400

Add shape control and linear toggle to XFade; fix Knob29 positioning.

Diffstat:
Mres-src/ADSR-src.svg | 2+-
Mres-src/CVDelay-src.svg | 2+-
Mres-src/DGate-src.svg | 2+-
Mres-src/Follow-src.svg | 2+-
Mres-src/Offset-src.svg | 2+-
Mres-src/RM-src.svg | 2+-
Mres-src/XFade-src.svg | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mres/ADSR.svg | 0
Mres/CVDelay.svg | 0
Mres/DGate.svg | 0
Mres/Follow.svg | 0
Mres/Offset.svg | 0
Mres/RM.svg | 0
Mres/XFade.svg | 0
Msrc/ADSR.cpp | 8++++----
Msrc/CVDelay.cpp | 6+++---
Msrc/DGate.cpp | 6+++---
Msrc/Follow.cpp | 4++--
Msrc/Offset.cpp | 5++---
Msrc/RM.cpp | 6+++---
Msrc/XFade.cpp | 29+++++++++++++++++++++++++++--
Msrc/XFade.hpp | 3+++
Msrc/dsp/signal.cpp | 51+++++++++++++++++++++++++++++++++++++++++++++------
Msrc/dsp/signal.hpp | 12++++++++++--
24 files changed, 171 insertions(+), 38 deletions(-)

diff --git a/res-src/ADSR-src.svg b/res-src/ADSR-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/CVDelay-src.svg b/res-src/CVDelay-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/DGate-src.svg b/res-src/DGate-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/Follow-src.svg b/res-src/Follow-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/Offset-src.svg b/res-src/Offset-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/RM-src.svg b/res-src/RM-src.svg @@ -27,7 +27,7 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> diff --git a/res-src/XFade-src.svg b/res-src/XFade-src.svg @@ -27,7 +27,15 @@ <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="14.5" stroke-width="1" stroke="#00f" fill="none" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knob-smallest" viewBox="0 0 16px 16px"> + <g transform="translate(8 8)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle r="7.5" stroke-width="1" stroke="#00f" fill="none" /> </g> </symbol> @@ -47,6 +55,45 @@ </g> </symbol> + <symbol id="knobguide-curve" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="0,0 2,0" stroke-width="1" stroke="#333" transform="rotate(-180) translate(9.5 0)" /> + <g transform="rotate(-180) translate(16 0) rotate(180) translate(-2.5 -2.5)"> + <!-- <rect width="5" height="5" stroke-width="1" stroke="#0f0" fill="none" /> --> + <polyline points="0,0 2.5,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + <polyline points="5,0 2.5,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + </g> + + <polyline points="0,0 2,0" stroke-width="0.3" stroke="#333" transform="rotate(-135) translate(9.5 0)" /> + + <polyline points="0,0 2,0" stroke-width="1" stroke="#333" transform="rotate(-90) translate(9.5 0)" /> + <g transform="rotate(-90) translate(16 0) rotate(90) translate(-2.5 -2.5)"> + <!-- <rect width="5" height="5" stroke-width="1" stroke="#0f0" fill="none" /> --> + <polyline points="0,0 5,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + <polyline points="5,0 0,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + </g> + + <polyline points="0,0 2,0" stroke-width="0.3" stroke="#333" transform="rotate(-45) translate(9.5 0)" /> + + <polyline points="0,0 2,0" stroke-width="1" stroke="#333" transform="rotate(0) translate(9.5 0)" /> + <g transform="rotate(0) translate(16 0) rotate(-0) translate(-2.5 -2.5)"> + <!-- <rect width="5" height="5" stroke-width="1" stroke="#0f0" fill="none" /> --> + <polyline points="2.5,0 5,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + <polyline points="2.5,0 0,5" stroke-width="1" stroke="#333" stroke-linecap="round" fill="none" transform="translate(0 0)" /> + </g> + </g> + </symbol> + + <symbol id="button" viewBox="0 0 9px 9px"> + <g transform="translate(4.5 4.5)"> + <circle cx="0" cy="0" r="4.1" stroke-width="1" stroke="#00f" fill="#f00" /> + </g> + </symbol> + + <symbol id="light-small" viewBox="0 0 6.4px 6.4px"> + <rect width="6.4" height="6.4" fill="#0f0" /> + </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" /> @@ -67,6 +114,8 @@ <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="0,0 0,380" stroke-width="0.5" stroke="#0f0" transform="translate(22.5 0)" /> --> + <g transform="rotate(-90) translate(-376 13)"> <text class="title" font-size="7pt" letter-spacing="2.5px">XFADE</text> <g transform="translate(0 12)"> @@ -78,7 +127,7 @@ <g transform="translate(0 25)"> <text font-size="6pt" letter-spacing="1px" transform="translate(14 0)">MIX</text> <use id="MIX_PARAM" xlink:href="#knob" transform="translate(0 3)" /> - <use xlink:href="#knobguide-mixab" transform="scale(1) translate(0 3)" /> + <use xlink:href="#knobguide-mixab" transform="translate(0 3)" /> <g transform="translate(5.5 49)"> <rect width="34" height="38" rx="5" fill="#fafafa" /> <use id="MIX_INPUT" xlink:href="#input" transform="translate(5 3)" /> @@ -86,6 +135,18 @@ </g> </g> + <g transform="translate(0 131)"> + <text font-size="6pt" letter-spacing="1px" transform="translate(7.5 0)">SHAPE</text> + <use id="CURVE_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 17.5)" /> + <use xlink:href="#knobguide-curve" transform="translate(0 3)" /> + </g> + + <g transform="translate(6.7 178)"> + <use id="LINEAR_LIGHT" xlink:href="#light-small" transform="translate(0 0.5)" /> + <text font-size="5pt" letter-spacing="1px" transform="translate(8 6)">LIN</text> + <use id="LINEAR_PARAM" xlink:href="#button" transform="translate(22.5 -1)" /> + </g> + <g transform="translate(0 210)"> <g transform="translate(5.5 0)"> <rect width="34" height="10" fill="#fafafa" transform="translate(0 63)" /> @@ -102,6 +163,4 @@ <text font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">MIX</text> </g> </g> - - <!-- <polyline points="0,0 45,0" stroke-width="0.5" stroke="#0f0" transform="translate(0 73)" /> --> </svg> diff --git a/res/ADSR.svg b/res/ADSR.svg Binary files differ. diff --git a/res/CVDelay.svg b/res/CVDelay.svg Binary files differ. diff --git a/res/DGate.svg b/res/DGate.svg Binary files differ. diff --git a/res/Follow.svg b/res/Follow.svg Binary files differ. diff --git a/res/Offset.svg b/res/Offset.svg Binary files differ. diff --git a/res/RM.svg b/res/RM.svg Binary files differ. diff --git a/res/XFade.svg b/res/XFade.svg Binary files differ. diff --git a/src/ADSR.cpp b/src/ADSR.cpp @@ -54,10 +54,10 @@ struct ADSRWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto attackParamPosition = Vec(7.5, 32.5); - auto decayParamPosition = Vec(7.5, 89.5); - auto sustainParamPosition = Vec(7.5, 146.5); - auto releaseParamPosition = Vec(7.5, 203.5); + auto attackParamPosition = Vec(8.0, 33.0); + auto decayParamPosition = Vec(8.0, 90.0); + auto sustainParamPosition = Vec(8.0, 147.0); + auto releaseParamPosition = Vec(8.0, 204.0); auto linearParamPosition = Vec(32.0, 245.7); auto gateInputPosition = Vec(10.5, 265.0); diff --git a/src/CVDelay.cpp b/src/CVDelay.cpp @@ -15,7 +15,7 @@ void CVDelay::step() { if (inputs[MIX_INPUT].active) { mix *= clamp(inputs[MIX_INPUT].value / 5.0f, -1.0f, 1.0f); } - _mix.setMix(mix); + _mix.setParams(mix); float in = inputs[IN_INPUT].value; float delayed = _delay.next(in); @@ -37,8 +37,8 @@ struct CVDelayWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto timeParamPosition = Vec(7.5, 35.5); - auto mixParamPosition = Vec(7.5, 141.5); + auto timeParamPosition = Vec(8.0, 36.0); + auto mixParamPosition = Vec(8.0, 142.0); auto timeInputPosition = Vec(10.5, 77.0); auto mixInputPosition = Vec(10.5, 183.0); diff --git a/src/DGate.cpp b/src/DGate.cpp @@ -85,10 +85,10 @@ struct DGateWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto delayParamPosition = Vec(7.5, 32.5); - auto gateParamPosition = Vec(7.5, 91.5); + auto delayParamPosition = Vec(8.0, 33.0); + auto gateParamPosition = Vec(8.0, 92.0); auto loopParamPosition = Vec(15.0, 144.5); - auto triggerParamPosition = Vec(13.5, 190.0); + auto triggerParamPosition = Vec(13.5, 191.0); auto triggerInputPosition = Vec(10.5, 213.0); diff --git a/src/Follow.cpp b/src/Follow.cpp @@ -37,8 +37,8 @@ struct FollowWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto responseParamPosition = Vec(7.5, 35.5); - auto scaleParamPosition = Vec(7.5, 141.5); + auto responseParamPosition = Vec(8.0, 36.0); + auto scaleParamPosition = Vec(8.0, 142.0); auto responseInputPosition = Vec(10.5, 77.0); auto scaleInputPosition = Vec(10.5, 183.0); diff --git a/src/Offset.cpp b/src/Offset.cpp @@ -36,10 +36,9 @@ struct OffsetWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(0, 0))); addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); - float knobNudge = 0.4; // generated by svg_widgets.rb - auto offsetParamPosition = Vec(7.5 + knobNudge, 39.5 + knobNudge); - auto scaleParamPosition = Vec(7.5 + knobNudge, 151.5 + knobNudge); + auto offsetParamPosition = Vec(8.0, 40.0); + auto scaleParamPosition = Vec(8.0, 152.0); auto offsetInputPosition = Vec(10.5, 81.0); auto scaleInputPosition = Vec(10.5, 193.0); diff --git a/src/RM.cpp b/src/RM.cpp @@ -27,7 +27,7 @@ void RM::step() { if (inputs[MIX_INPUT].active) { mix *= clamp(inputs[MIX_INPUT].value / 5.0f, -1.0f, 1.0f); } - _mix.setMix(mix); + _mix.setParams(mix, 0.889f, false); outputs[OUT_OUTPUT].value = _mix.next(carrier, modulator * carrier * 0.2f); } @@ -47,8 +47,8 @@ struct RMWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto modulatorDepthParamPosition = Vec(7.5, 35.5); - auto mixParamPosition = Vec(7.5, 141.5); + auto modulatorDepthParamPosition = Vec(8.0, 36.0); + auto mixParamPosition = Vec(8.0, 142.0); auto modulatorDepthInputPosition = Vec(10.5, 77.0); auto mixInputPosition = Vec(10.5, 183.0); diff --git a/src/XFade.cpp b/src/XFade.cpp @@ -2,11 +2,22 @@ #include "XFade.hpp" void XFade::step() { + bool linear = params[LINEAR_PARAM].value > 0.5f; + lights[LINEAR_LIGHT].value = linear; + float mix = params[MIX_PARAM].value; if (inputs[MIX_INPUT].active) { mix *= clamp(inputs[MIX_INPUT].value / 5.0f, -1.0f, 1.0f); } - _mix.setMix(mix); + + float curve = params[CURVE_PARAM].value; + if (!linear) { + curve = powf(params[CURVE_PARAM].value, 0.082f); + } + 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); } @@ -25,22 +36,36 @@ struct XFadeWidget : ModuleWidget { addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); // generated by svg_widgets.rb - auto mixParamPosition = Vec(7.5, 35.5); + auto mixParamPosition = Vec(8.0, 36.0); + auto curveParamPosition = Vec(14.5, 148.5); + auto linearParamPosition = Vec(29.4, 175.9); auto mixInputPosition = Vec(10.5, 77.0); auto aInputPosition = Vec(10.5, 213.0); auto bInputPosition = Vec(10.5, 248.0); auto outOutputPosition = Vec(10.5, 286.0); + + auto linearLightPosition = Vec(6.5, 177.5); // end generated by svg_widgets.rb addParam(ParamWidget::create<Knob29>(mixParamPosition, module, XFade::MIX_PARAM, -1.0, 1.0, 0.0)); + { + auto w = ParamWidget::create<Knob16>(curveParamPosition, module, XFade::CURVE_PARAM, 0.0, 1.0, 0.5); + auto k = dynamic_cast<SVGKnob*>(w); + k->minAngle = -0.5 * M_PI; + k->maxAngle = 0.5 * M_PI; + addParam(w); + } + addParam(ParamWidget::create<StatefulButton9>(linearParamPosition, module, XFade::LINEAR_PARAM, 0.0, 1.0, 0.0)); addInput(Port::create<Port24>(mixInputPosition, Port::INPUT, module, XFade::MIX_INPUT)); addInput(Port::create<Port24>(aInputPosition, Port::INPUT, module, XFade::A_INPUT)); addInput(Port::create<Port24>(bInputPosition, Port::INPUT, module, XFade::B_INPUT)); addOutput(Port::create<Port24>(outOutputPosition, Port::OUTPUT, module, XFade::OUT_OUTPUT)); + + addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(linearLightPosition, module, XFade::LINEAR_LIGHT)); } }; diff --git a/src/XFade.hpp b/src/XFade.hpp @@ -12,6 +12,8 @@ namespace bogaudio { struct XFade : Module { enum ParamsIds { MIX_PARAM, + CURVE_PARAM, + LINEAR_PARAM, NUM_PARAMS }; @@ -28,6 +30,7 @@ struct XFade : Module { }; enum LightsIds { + LINEAR_LIGHT, NUM_LIGHTS }; diff --git a/src/dsp/signal.cpp b/src/dsp/signal.cpp @@ -194,23 +194,62 @@ float SlewLimiter::next(float sample) { } -void CrossFader::setMix(float mix) { +void CrossFader::setParams(float mix, float curve, bool linear) { assert(mix >= -1.0f && mix <= 1.0f); - if (_mix != mix) { + assert(curve >= -1.0f && curve <= 1.0f); + if (_mix != mix || _curve != curve || _linear != linear) { _mix = mix; - if (_mix < 0.0f) { + _curve = curve; + _linear = linear; + + float aMax, aMin; + float bMax, bMin; + if (_curve < 0.0f) { + aMax = 0.0f; + aMin = _curve + 2.0f; + bMax = 2.0f; + bMin = 0.0f - _curve; + } + else { + aMax = _curve; + aMin = 2.0f; + bMax = 2.0f - _curve; + bMin = 0.0f; + } + + float m = _mix + 1.0f; + if (m < aMax) { _aMix = 1.0f; - _bMix = 1.0f + _mix; + } + else if (m > aMin) { + _aMix = 0.0f; } else { - _aMix = 1.0f - _mix; + _aMix = 1.0f - ((m - aMax) / (aMin - aMax)); + } + + if (m > bMax) { _bMix = 1.0f; } + else if (m < bMin) { + _bMix = 0.0f; + } + else { + _bMix = (m - bMin) / (bMax - bMin); + } + + if (!_linear) { + _aAmp.setLevel((1.0f - _aMix) * Amplifier::minDecibels); + _bAmp.setLevel((1.0f - _bMix) * Amplifier::minDecibels); + } } } float CrossFader::next(float a, float b) { - return _aMix * a + _bMix * b; + if (_linear) { + return _aMix * a + _bMix * b; + } + return _aAmp.next(a) + _bAmp.next(b); } diff --git a/src/dsp/signal.hpp b/src/dsp/signal.hpp @@ -123,14 +123,22 @@ struct SlewLimiter { struct CrossFader { float _mix = 2.0f; + float _curve = 1.0f; + bool _linear = true; float _aMix; float _bMix; + Amplifier _aAmp; + Amplifier _bAmp; CrossFader() { - setMix(0.0f); + setParams(0.0f); } - void setMix(float mix); // -1 to 1, 0 for equal output of both inputs. + void setParams( + float mix, // -1 to 1, 0 for equal output of both inputs. + float curve = 1.0f, // -1 to 1: at -1, A will cut fully as mix goes to 0; at 0, A cuts over full mix; at 1, A cuts from 0 to 1. B symmetric. + bool linear = true// cut is linear in amplitude if true; linear in decibels otherwise. + ); float next(float a, float b); };