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:
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);
};