commit 4c75016c67d09d04897c083b655253876266de20
parent 7274a10e2599a090a81dd08bbab5774e320cdb7f
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 14 Apr 2021 23:34:43 -0400
LGSW: switch with onboard logic. #172
Diffstat:
16 files changed, 1260 insertions(+), 46 deletions(-)
diff --git a/README-prerelease.md b/README-prerelease.md
@@ -1329,6 +1329,31 @@ If the context menu option "Save latched state to patch" is enabled, and latchin
_Polyphony:_ If polyphonic input is present at GATE, then the module is polyphonic in the standard way, independently switching the independent polyphonic channels on the high/low inputs (the button will switch all channels). Additionally, if the input at GATE is not present or monophonic, but polyphonic cables are are present at any high/low inputs, and such an input is switched to the output, it is duplicated to the output with channels intact.
+#### <a name="lgsw"></a> LGSW
+
+LGSW is a version of <a href="#switch">SWITCH</a> with two gate inputs and onboard logic.
+
+If nothing is patched to either of the gate inputs, or if just one is patched (either one), the behavior of the module is identical to SWITCH (the logic section has no effect).
+
+If both gate inputs are in use, then the logic will evaluate to true according to the gate states and the logic mode:
+ - OR: true if either gate is high.
+ - AND: true if both gates are high.
+ - XOR: true if exactly one of the gates is high.
+ - NOR: true if neither of the gates is high.
+ - NAND: true if both gates are low.
+
+When LATCH is off, and both gates are in use, the module outputs the HIGH input whenever the logic is true or the button is held.
+
+When LATCH is on, and both gates are in use, the latch will toggle when the logic state changes, or when the button is pressed.
+
+The logic mode can be set by CV. Using a CV for the logic overrides whatever selection was made with the small mode-select button. A O-5V CV will select the mode as:
+ - OR: less than 1V.
+ - AND: 1V but less than 2V.
+ - XOR: 2V but less than 3V.
+ - NOR: 3V but less than 4V.
+ - NAND: 4V or more.
+
+_Polyphony:_ Same as <a href="#switch">SWITCH</a>, except that the polyphony channel count is set by the topmost gate input only.
### <a name="misc"></a> Miscellaneous
diff --git a/plugin.json b/plugin.json
@@ -1109,6 +1109,17 @@
]
},
{
+ "slug": "Bogaudio-Lgsw",
+ "name": "LGSW",
+ "description": "2-way signal router with logic",
+ "manualUrl": "https://github.com/bogaudio/BogaudioModules/blob/master/README.md#lgsw",
+ "tags": [
+ "Switch",
+ "Logic",
+ "Polyphonic"
+ ]
+ },
+ {
"slug": "Bogaudio-Blank3",
"name": "BLANK3",
"description": "3HP blank panel",
diff --git a/res-pp/Lgsw-dark-pp.svg b/res-pp/Lgsw-dark-pp.svg
@@ -0,0 +1,285 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="45.0" height="380.0" viewBox="0 0 45.0 380.0">
+ <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;
+}
+
+polyline {
+ stroke: #333;
+}
+polyline.guide {
+ stroke: #0f0;
+}
+path {
+ stroke: #333;
+}
+
+rect.module-background, .background-fill {
+ fill: #ddd;
+}
+polyline.module-border-inner {
+ stroke: #e4e4e4;
+}
+polyline.module-border-middle {
+ stroke: #ebebeb;
+}
+polyline.module-border-outer {
+ stroke: #f2f2f2;
+}
+
+g.io-group {
+}
+rect.input-background, rect.input-background-filler {
+ fill: #fafafa;
+}
+rect.output-background, rect.output-background-filler {
+ fill: #bbb;
+}
+text.input-label, text.output-label {
+ /* font-size: 6pt; */
+}
+polyline.input-label, polyline.output-label {
+}
+path.input-label, path.output-label {
+}
+
+circle.port-rim {
+ stroke: #f0f0f0;
+}
+circle.port-barrel {
+ stroke: #222;
+ fill: #222;
+}
+circle.knob-center {
+ fill: #eee;
+}
+circle.knob-rim {
+ fill: #333;
+}
+circle.knob-tick {
+ fill: #fff;
+}
+polyline.knob-tick {
+ stroke: #fff;
+}
+
+
+text {
+ fill: #eee;
+}
+
+polyline {
+ stroke: #ccc;
+}
+path {
+ stroke: #ccc;
+}
+
+rect.module-background, .background-fill {
+ fill: #111;
+}
+polyline.module-border-inner {
+ stroke: #191919;
+}
+polyline.module-border-middle {
+ stroke: #111;
+}
+polyline.module-border-outer {
+ stroke: #000;
+}
+
+rect.input-background, rect.input-background-filler {
+ fill: #aaa;
+}
+rect.output-background, rect.output-background-filler {
+ fill: #666;
+}
+text.input-label {
+ fill: #222;
+}
+polyline.input-label, path.input-label {
+ stroke: #222;
+}
+text.output-label {
+ fill: #ddd;
+}
+polyline.output-label, path.output-label {
+ stroke: #ddd;
+}
+
+circle.port-rim {
+ stroke: #c0c0c0;
+}
+circle.port-barrel {
+ stroke: #222;
+ fill: #222;
+}
+circle.knob-center {
+ fill: #888;
+}
+circle.knob-rim {
+ fill: #444;
+}
+circle.knob-tick {
+ fill: #fff;
+}
+polyline.knob-tick {
+ stroke: #fff;
+}
+</style>
+
+
+
+ <rect class="module-background background-fill" width="45.0" height="380.0"/>
+
+
+ <polyline class="module-border-inner" points="1,1 44.0,1 44.0,379.0 1,379.0 1,1" stroke-width="0.5" fill="none"/>
+ <polyline class="module-border-middle" points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke-width="0.8" fill="none"/>
+ <polyline class="module-border-outer" points="0,0 45.0,0 45.0,380.0 0,380.0 0,0" stroke-width="1" fill="none"/>
+
+ <g transform="rotate(-90) translate(-376.0 13)">
+ <text class="title" font-size="7pt" letter-spacing="2.5px">LGSW</text>
+ <g transform="translate(0 12)">
+ <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text>
+ <rect class="background-fill" width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)"/>
+ </g>
+ </g>
+
+
+ <g transform="translate(0 18)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="82" rx="5"/>
+ <g transform="translate(8 4)"><svg id="GATE_PARAM">
+ <g transform="translate(9 9)">
+ <circle cx="0" cy="0" r="8.5" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ <g transform="translate(5 26)"><svg id="GATE_A_INPUT">
+ <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>
+ </svg></g>
+ <g transform="translate(5 54)"><svg id="GATE_B_INPUT">
+ <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>
+ </svg></g>
+ </g>
+
+ <g transform="translate(4.5 88)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(0 6)">LATCH</text>
+ <g transform="translate(27 -1)"><svg id="LATCH_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ </g>
+
+ <g transform="translate(0 102)">
+ <g transform="translate(15 0)">
+ <g transform="translate(0 0)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_OR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">OR</text>
+ </g>
+
+ <g transform="translate(0 12)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_AND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">AND</text>
+ </g>
+
+ <g transform="translate(0 24)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_XOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">XOR</text>
+ </g>
+
+ <g transform="translate(0 36)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NOR</text>
+ </g>
+
+ <g transform="translate(0 48)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NAND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NAND</text>
+ </g>
+
+ <g transform="translate(1 58)"><svg id="LOGIC_MODE_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+
+ <g class="io-group" transform="translate(-7.5 70)">
+ <rect class="input-background" width="30" height="30" rx="5"/>
+ <g transform="translate(3 3)"><svg id="LOGIC_MODE_INPUT">
+ <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>
+ </svg></g>
+ </g>
+ </g>
+ </g>
+
+ <g transform="translate(0 209)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="74" rx="5"/>
+ <rect class="input-background-filler" width="34" height="10" transform="translate(0 64)"/>
+ <g transform="translate(5 3)"><svg id="HIGH_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="1px" transform="translate(11.0 35)">HIGH</text>
+ <g transform="translate(2 29.3)"><svg id="HIGH_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g transform="translate(5.5 36)">
+ <g transform="translate(5 3)"><svg id="LOW_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="2px" transform="translate(11.0 35)">LOW</text>
+ <g transform="translate(2 29.3)"><svg id="LOW_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g class="io-group" transform="translate(5.5 77)">
+ <rect class="output-background-filler" width="34" height="10" transform="translate(0 -3)"/>
+ <rect class="output-background" width="34" height="35" rx="5"/>
+ <g transform="translate(5 0)"><svg id="OUT_OUTPUT">
+ <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>
+ </svg></g>
+ <text class="output-label" font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/res-pp/Lgsw-lowcontrast-pp.svg b/res-pp/Lgsw-lowcontrast-pp.svg
@@ -0,0 +1,285 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="45.0" height="380.0" viewBox="0 0 45.0 380.0">
+ <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;
+}
+
+polyline {
+ stroke: #333;
+}
+polyline.guide {
+ stroke: #0f0;
+}
+path {
+ stroke: #333;
+}
+
+rect.module-background, .background-fill {
+ fill: #ddd;
+}
+polyline.module-border-inner {
+ stroke: #e4e4e4;
+}
+polyline.module-border-middle {
+ stroke: #ebebeb;
+}
+polyline.module-border-outer {
+ stroke: #f2f2f2;
+}
+
+g.io-group {
+}
+rect.input-background, rect.input-background-filler {
+ fill: #fafafa;
+}
+rect.output-background, rect.output-background-filler {
+ fill: #bbb;
+}
+text.input-label, text.output-label {
+ /* font-size: 6pt; */
+}
+polyline.input-label, polyline.output-label {
+}
+path.input-label, path.output-label {
+}
+
+circle.port-rim {
+ stroke: #f0f0f0;
+}
+circle.port-barrel {
+ stroke: #222;
+ fill: #222;
+}
+circle.knob-center {
+ fill: #eee;
+}
+circle.knob-rim {
+ fill: #333;
+}
+circle.knob-tick {
+ fill: #fff;
+}
+polyline.knob-tick {
+ stroke: #fff;
+}
+
+
+text {
+ fill: #b3b3b3;
+}
+
+polyline {
+ stroke: #b3b3b3;
+}
+path {
+ stroke: #b3b3b3;
+}
+
+rect.module-background, .background-fill {
+ fill: #333;
+}
+polyline.module-border-inner {
+ stroke: #191919;
+}
+polyline.module-border-middle {
+ stroke: #111;
+}
+polyline.module-border-outer {
+ stroke: #000;
+}
+
+rect.input-background, rect.input-background-filler {
+ fill: #b3b3b3;
+}
+rect.output-background, rect.output-background-filler {
+ fill: #888;
+}
+text.input-label {
+ fill: #666;
+}
+polyline.input-label, path.input-label {
+ stroke: #666;
+}
+text.output-label {
+ fill: #ccc;
+}
+polyline.output-label, path.output-label {
+ stroke: #ccc;
+}
+
+circle.port-rim {
+ stroke: #bbb;
+}
+circle.port-barrel {
+ stroke: #222;
+ fill: #222;
+}
+circle.knob-center {
+ fill: #bbb;
+}
+circle.knob-rim {
+ fill: #555;
+}
+circle.knob-tick {
+ fill: #fff;
+}
+polyline.knob-tick {
+ stroke: #fff;
+}
+</style>
+
+
+
+ <rect class="module-background background-fill" width="45.0" height="380.0"/>
+
+
+ <polyline class="module-border-inner" points="1,1 44.0,1 44.0,379.0 1,379.0 1,1" stroke-width="0.5" fill="none"/>
+ <polyline class="module-border-middle" points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke-width="0.8" fill="none"/>
+ <polyline class="module-border-outer" points="0,0 45.0,0 45.0,380.0 0,380.0 0,0" stroke-width="1" fill="none"/>
+
+ <g transform="rotate(-90) translate(-376.0 13)">
+ <text class="title" font-size="7pt" letter-spacing="2.5px">LGSW</text>
+ <g transform="translate(0 12)">
+ <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text>
+ <rect class="background-fill" width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)"/>
+ </g>
+ </g>
+
+
+ <g transform="translate(0 18)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="82" rx="5"/>
+ <g transform="translate(8 4)"><svg id="GATE_PARAM">
+ <g transform="translate(9 9)">
+ <circle cx="0" cy="0" r="8.5" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ <g transform="translate(5 26)"><svg id="GATE_A_INPUT">
+ <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>
+ </svg></g>
+ <g transform="translate(5 54)"><svg id="GATE_B_INPUT">
+ <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>
+ </svg></g>
+ </g>
+
+ <g transform="translate(4.5 88)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(0 6)">LATCH</text>
+ <g transform="translate(27 -1)"><svg id="LATCH_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ </g>
+
+ <g transform="translate(0 102)">
+ <g transform="translate(15 0)">
+ <g transform="translate(0 0)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_OR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">OR</text>
+ </g>
+
+ <g transform="translate(0 12)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_AND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">AND</text>
+ </g>
+
+ <g transform="translate(0 24)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_XOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">XOR</text>
+ </g>
+
+ <g transform="translate(0 36)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NOR</text>
+ </g>
+
+ <g transform="translate(0 48)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NAND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NAND</text>
+ </g>
+
+ <g transform="translate(1 58)"><svg id="LOGIC_MODE_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+
+ <g class="io-group" transform="translate(-7.5 70)">
+ <rect class="input-background" width="30" height="30" rx="5"/>
+ <g transform="translate(3 3)"><svg id="LOGIC_MODE_INPUT">
+ <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>
+ </svg></g>
+ </g>
+ </g>
+ </g>
+
+ <g transform="translate(0 209)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="74" rx="5"/>
+ <rect class="input-background-filler" width="34" height="10" transform="translate(0 64)"/>
+ <g transform="translate(5 3)"><svg id="HIGH_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="1px" transform="translate(11.0 35)">HIGH</text>
+ <g transform="translate(2 29.3)"><svg id="HIGH_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g transform="translate(5.5 36)">
+ <g transform="translate(5 3)"><svg id="LOW_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="2px" transform="translate(11.0 35)">LOW</text>
+ <g transform="translate(2 29.3)"><svg id="LOW_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g class="io-group" transform="translate(5.5 77)">
+ <rect class="output-background-filler" width="34" height="10" transform="translate(0 -3)"/>
+ <rect class="output-background" width="34" height="35" rx="5"/>
+ <g transform="translate(5 0)"><svg id="OUT_OUTPUT">
+ <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>
+ </svg></g>
+ <text class="output-label" font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/res-pp/Lgsw-pp.svg b/res-pp/Lgsw-pp.svg
@@ -0,0 +1,221 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="45.0" height="380.0" viewBox="0 0 45.0 380.0">
+ <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;
+}
+
+polyline {
+ stroke: #333;
+}
+polyline.guide {
+ stroke: #0f0;
+}
+path {
+ stroke: #333;
+}
+
+rect.module-background, .background-fill {
+ fill: #ddd;
+}
+polyline.module-border-inner {
+ stroke: #e4e4e4;
+}
+polyline.module-border-middle {
+ stroke: #ebebeb;
+}
+polyline.module-border-outer {
+ stroke: #f2f2f2;
+}
+
+g.io-group {
+}
+rect.input-background, rect.input-background-filler {
+ fill: #fafafa;
+}
+rect.output-background, rect.output-background-filler {
+ fill: #bbb;
+}
+text.input-label, text.output-label {
+ /* font-size: 6pt; */
+}
+polyline.input-label, polyline.output-label {
+}
+path.input-label, path.output-label {
+}
+
+circle.port-rim {
+ stroke: #f0f0f0;
+}
+circle.port-barrel {
+ stroke: #222;
+ fill: #222;
+}
+circle.knob-center {
+ fill: #eee;
+}
+circle.knob-rim {
+ fill: #333;
+}
+circle.knob-tick {
+ fill: #fff;
+}
+polyline.knob-tick {
+ stroke: #fff;
+}
+</style>
+
+
+
+ <rect class="module-background background-fill" width="45.0" height="380.0"/>
+
+
+ <polyline class="module-border-inner" points="1,1 44.0,1 44.0,379.0 1,379.0 1,1" stroke-width="0.5" fill="none"/>
+ <polyline class="module-border-middle" points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke-width="0.8" fill="none"/>
+ <polyline class="module-border-outer" points="0,0 45.0,0 45.0,380.0 0,380.0 0,0" stroke-width="1" fill="none"/>
+
+ <g transform="rotate(-90) translate(-376.0 13)">
+ <text class="title" font-size="7pt" letter-spacing="2.5px">LGSW</text>
+ <g transform="translate(0 12)">
+ <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text>
+ <rect class="background-fill" width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)"/>
+ </g>
+ </g>
+
+
+ <g transform="translate(0 18)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="82" rx="5"/>
+ <g transform="translate(8 4)"><svg id="GATE_PARAM">
+ <g transform="translate(9 9)">
+ <circle cx="0" cy="0" r="8.5" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ <g transform="translate(5 26)"><svg id="GATE_A_INPUT">
+ <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>
+ </svg></g>
+ <g transform="translate(5 54)"><svg id="GATE_B_INPUT">
+ <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>
+ </svg></g>
+ </g>
+
+ <g transform="translate(4.5 88)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(0 6)">LATCH</text>
+ <g transform="translate(27 -1)"><svg id="LATCH_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+ </g>
+
+ <g transform="translate(0 102)">
+ <g transform="translate(15 0)">
+ <g transform="translate(0 0)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_OR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">OR</text>
+ </g>
+
+ <g transform="translate(0 12)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_AND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">AND</text>
+ </g>
+
+ <g transform="translate(0 24)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_XOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">XOR</text>
+ </g>
+
+ <g transform="translate(0 36)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NOR_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NOR</text>
+ </g>
+
+ <g transform="translate(0 48)">
+ <g transform="translate(-7.5 1)"><svg id="LOGIC_NAND_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NAND</text>
+ </g>
+
+ <g transform="translate(1 58)"><svg id="LOGIC_MODE_PARAM">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00"/>
+ </g>
+ </svg></g>
+
+ <g class="io-group" transform="translate(-7.5 70)">
+ <rect class="input-background" width="30" height="30" rx="5"/>
+ <g transform="translate(3 3)"><svg id="LOGIC_MODE_INPUT">
+ <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>
+ </svg></g>
+ </g>
+ </g>
+ </g>
+
+ <g transform="translate(0 209)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="74" rx="5"/>
+ <rect class="input-background-filler" width="34" height="10" transform="translate(0 64)"/>
+ <g transform="translate(5 3)"><svg id="HIGH_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="1px" transform="translate(11.0 35)">HIGH</text>
+ <g transform="translate(2 29.3)"><svg id="HIGH_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g transform="translate(5.5 36)">
+ <g transform="translate(5 3)"><svg id="LOW_INPUT">
+ <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>
+ </svg></g>
+ <text class="input-label" font-size="5pt" letter-spacing="2px" transform="translate(11.0 35)">LOW</text>
+ <g transform="translate(2 29.3)"><svg id="LOW_LIGHT">
+ <rect width="6.4" height="6.4" fill="#0f0"/>
+ </svg></g>
+ </g>
+ <g class="io-group" transform="translate(5.5 77)">
+ <rect class="output-background-filler" width="34" height="10" transform="translate(0 -3)"/>
+ <rect class="output-background" width="34" height="35" rx="5"/>
+ <g transform="translate(5 0)"><svg id="OUT_OUTPUT">
+ <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>
+ </svg></g>
+ <text class="output-label" font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/res-src/Lgsw-src.svg b/res-src/Lgsw-src.svg
@@ -0,0 +1,76 @@
+<module hp="3">
+ <style/>
+
+ <def xlink:href="#module3" var-name="LGSW"/>
+
+ <g transform="translate(0 18)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="82" rx="5"/>
+ <def id="GATE_PARAM" xlink:href="#button" transform="translate(8 4)"/>
+ <def id="GATE_A_INPUT" xlink:href="#input" transform="translate(5 26)"/>
+ <def id="GATE_B_INPUT" xlink:href="#input" transform="translate(5 54)"/>
+ </g>
+
+ <g transform="translate(4.5 88)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(0 6)">LATCH</text>
+ <def id="LATCH_PARAM" xlink:href="#button-small" transform="translate(27 -1)"/>
+ </g>
+
+ <g transform="translate(0 102)" var-leftpad="15">
+ <g transform="translate($leftpad 0)" var-spacing="12">
+ <g transform="translate(0 0)">
+ <def id="LOGIC_OR_LIGHT" xlink:href="#light-small" transform="translate(-7.5 1)"/>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">OR</text>
+ </g>
+
+ <g transform="translate(0 $spacing)">
+ <def id="LOGIC_AND_LIGHT" xlink:href="#light-small" transform="translate(-7.5 1)"/>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">AND</text>
+ </g>
+
+ <g transform="translate(0 $spacing*2)">
+ <def id="LOGIC_XOR_LIGHT" xlink:href="#light-small" transform="translate(-7.5 1)"/>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">XOR</text>
+ </g>
+
+ <g transform="translate(0 $spacing*3)">
+ <def id="LOGIC_NOR_LIGHT" xlink:href="#light-small" transform="translate(-7.5 1)"/>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NOR</text>
+ </g>
+
+ <g transform="translate(0 $spacing*4)">
+ <def id="LOGIC_NAND_LIGHT" xlink:href="#light-small" transform="translate(-7.5 1)"/>
+ <text font-size="5pt" letter-spacing="0.5px" transform="translate(1 6.7)">NAND</text>
+ </g>
+
+ <def id="LOGIC_MODE_PARAM" xlink:href="#button-small" transform="translate(1 $spacing*5-2)"/>
+
+ <g class="io-group" transform="translate(7.5-$leftpad $spacing*6-2)">
+ <rect class="input-background" width="30" height="30" rx="5"/>
+ <def id="LOGIC_MODE_INPUT" xlink:href="#input" transform="translate(3 3)"/>
+ </g>
+ </g>
+ </g>
+
+ <g transform="translate(0 209)">
+ <g class="io-group" transform="translate(5.5 0)">
+ <rect class="input-background" width="34" height="74" rx="5"/>
+ <rect class="input-background-filler" width="34" height="10" transform="translate(0 64)"/>
+ <def id="HIGH_INPUT" xlink:href="#input" transform="translate(5 3)"/>
+ <text class="input-label" font-size="5pt" letter-spacing="1px" transform="translate(11.0 35)">HIGH</text>
+ <def id="HIGH_LIGHT" xlink:href="#light-small" transform="translate(2 29.3)"/>
+ </g>
+ <g transform="translate(5.5 36)">
+ <def id="LOW_INPUT" xlink:href="#input" transform="translate(5 3)"/>
+ <text class="input-label" font-size="5pt" letter-spacing="2px" transform="translate(11.0 35)">LOW</text>
+ <def id="LOW_LIGHT" xlink:href="#light-small" transform="translate(2 29.3)"/>
+ </g>
+ <g class="io-group" transform="translate(5.5 77)">
+ <rect class="output-background-filler" width="34" height="10" transform="translate(0 -3)"/>
+ <rect class="output-background" width="34" height="35" rx="5"/>
+ <def id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 0)"/>
+ <text class="output-label" font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+ </g>
+</module>
diff --git a/res/Lgsw-dark.svg b/res/Lgsw-dark.svg
Binary files differ.
diff --git a/res/Lgsw-lowcontrast.svg b/res/Lgsw-lowcontrast.svg
Binary files differ.
diff --git a/res/Lgsw.svg b/res/Lgsw.svg
Binary files differ.
diff --git a/src/Lgsw.cpp b/src/Lgsw.cpp
@@ -0,0 +1,213 @@
+
+#include "Lgsw.hpp"
+
+void Lgsw::resetChannel(int c) {
+ _buttonTriggers[c].reset();
+ _aTriggers[c].reset();
+ _bTriggers[c].reset();
+ _lastLogicTrue[c] = false;
+}
+
+void Lgsw::reset() {
+ for (int i = 0; i < _channels; ++i) {
+ resetChannel(i);
+ _latchedHigh[i] = false;
+ }
+}
+
+int Lgsw::channels() {
+ return inputs[GATE_A_INPUT].getChannels();
+}
+
+void Lgsw::channelsChanged(int before, int after) {
+ for (; before < after; ++before) {
+ resetChannel(before);
+ }
+}
+
+void Lgsw::modulate() {
+ _latch = params[LATCH_PARAM].getValue() > 0.5f;
+}
+
+void Lgsw::processAlways(const ProcessArgs& args) {
+ _highLightSum = 0;
+ _lowLightSum = 0;
+}
+
+void Lgsw::processChannel(const ProcessArgs& args, int c) {
+ bool buttonTriggered = _buttonTriggers[c].process(params[GATE_PARAM].getValue());
+ bool aTriggered = _aTriggers[c].process(inputs[GATE_A_INPUT].getVoltage(c));
+ bool bTriggered = _bTriggers[c].process(inputs[GATE_B_INPUT].getVoltage(c));
+
+ if (inputs[LOGIC_MODE_INPUT].isConnected()) {
+ float cv = clamp(inputs[LOGIC_MODE_INPUT].getVoltage(c), 0.0f, 4.5f);
+ _logic = (Logic)(int)cv;
+ }
+ else {
+ _logic = (Logic)clamp((int)params[LOGIC_MODE_PARAM].getValue(), 0, 4);
+ }
+
+ bool triggered = buttonTriggered;
+ bool logicTrue = false;
+ if (inputs[GATE_A_INPUT].isConnected()) {
+ if (inputs[GATE_B_INPUT].isConnected()) {
+ switch (_logic) {
+ case OR_LOGIC: {
+ logicTrue = _aTriggers[c].isHigh() || _bTriggers[c].isHigh();
+ break;
+ }
+ case AND_LOGIC: {
+ logicTrue = _aTriggers[c].isHigh() && _bTriggers[c].isHigh();
+ break;
+ }
+ case XOR_LOGIC: {
+ logicTrue = _aTriggers[c].isHigh() != _bTriggers[c].isHigh();
+ break;
+ }
+ case NOR_LOGIC: {
+ logicTrue = !(_aTriggers[c].isHigh() || _bTriggers[c].isHigh());
+ break;
+ }
+ case NAND_LOGIC: {
+ logicTrue = !(_aTriggers[c].isHigh() && _bTriggers[c].isHigh());
+ break;
+ }
+ }
+
+ triggered = triggered || (logicTrue && !_lastLogicTrue[c]);
+ _lastLogicTrue[c] = logicTrue;
+ }
+ else {
+ triggered = triggered || aTriggered;
+ logicTrue = _aTriggers[c].isHigh();
+ _lastLogicTrue[c] = false;
+ }
+ }
+ else if (inputs[GATE_B_INPUT].isConnected()) {
+ triggered = triggered || bTriggered;
+ logicTrue = _bTriggers[c].isHigh();
+ _lastLogicTrue[c] = false;
+ }
+
+ if (_latch) {
+ if (triggered) {
+ _latchedHigh[c] = !_latchedHigh[c];
+ }
+ }
+ else {
+ _latchedHigh[c] = false;
+ }
+
+ if (_latchedHigh[c] || (!_latch && (logicTrue || _buttonTriggers[c].isHigh()))) {
+ ++_highLightSum;
+
+ if (_channels == 1) {
+ outputs[OUT_OUTPUT].setChannels(inputs[HIGH_INPUT].getChannels());
+ outputs[OUT_OUTPUT].writeVoltages(inputs[HIGH_INPUT].getVoltages());
+ }
+ else {
+ outputs[OUT_OUTPUT].setChannels(_channels);
+ outputs[OUT_OUTPUT].setVoltage(inputs[HIGH_INPUT].getPolyVoltage(c), c);
+ }
+ }
+ else {
+ ++_lowLightSum;
+
+ if (_channels == 1) {
+ outputs[OUT_OUTPUT].setChannels(inputs[LOW_INPUT].getChannels());
+ outputs[OUT_OUTPUT].writeVoltages(inputs[LOW_INPUT].getVoltages());
+ }
+ else {
+ outputs[OUT_OUTPUT].setChannels(_channels);
+ outputs[OUT_OUTPUT].setVoltage(inputs[LOW_INPUT].getPolyVoltage(c), c);
+ }
+ }
+}
+
+void Lgsw::postProcessAlways(const ProcessArgs& args) {
+ lights[HIGH_LIGHT].value = _highLightSum * _inverseChannels;
+ lights[LOW_LIGHT].value = _lowLightSum * _inverseChannels;
+
+ lights[LOGIC_OR_LIGHT].value = 0.0f;
+ lights[LOGIC_AND_LIGHT].value = 0.0f;
+ lights[LOGIC_XOR_LIGHT].value = 0.0f;
+ lights[LOGIC_NOR_LIGHT].value = 0.0f;
+ lights[LOGIC_NAND_LIGHT].value = 0.0f;
+ switch (_logic) {
+ case OR_LOGIC: {
+ lights[LOGIC_OR_LIGHT].value = 1.0f;
+ break;
+ }
+ case AND_LOGIC: {
+ lights[LOGIC_AND_LIGHT].value = 1.0f;
+ break;
+ }
+ case XOR_LOGIC: {
+ lights[LOGIC_XOR_LIGHT].value = 1.0f;
+ break;
+ }
+ case NOR_LOGIC: {
+ lights[LOGIC_NOR_LIGHT].value = 1.0f;
+ break;
+ }
+ case NAND_LOGIC: {
+ lights[LOGIC_NAND_LIGHT].value = 1.0f;
+ break;
+ }
+ }
+}
+
+struct LgswWidget : SaveLatchToPatchModuleWidget {
+ static constexpr int hp = 3;
+
+ LgswWidget(Lgsw* module) {
+ setModule(module);
+ box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
+ setPanel(box.size, "Lgsw");
+ createScrews();
+
+ // generated by svg_widgets.rb
+ auto gateParamPosition = Vec(13.5, 22.0);
+ auto latchParamPosition = Vec(31.5, 105.0);
+ auto logicModeParamPosition = Vec(16.0, 178.0);
+
+ auto gateAInputPosition = Vec(10.5, 44.0);
+ auto gateBInputPosition = Vec(10.5, 72.0);
+ auto logicModeInputPosition = Vec(10.5, 193.0);
+ auto high1InputPosition = Vec(10.5, 230.0);
+ auto low1InputPosition = Vec(10.5, 266.0);
+
+ auto out1OutputPosition = Vec(10.5, 304.0);
+
+ auto logicOrLightPosition = Vec(7.5, 121.0);
+ auto logicAndLightPosition = Vec(7.5, 133.0);
+ auto logicXorLightPosition = Vec(7.5, 145.0);
+ auto logicNorLightPosition = Vec(7.5, 157.0);
+ auto logicNandLightPosition = Vec(7.5, 169.0);
+ auto high1LightPosition = Vec(7.5, 256.3);
+ auto low1LightPosition = Vec(7.5, 292.3);
+ // end generated by svg_widgets.rb
+
+ addParam(createParam<Button18>(gateParamPosition, module, Lgsw::GATE_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(latchParamPosition, module, Lgsw::LATCH_PARAM));
+ addParam(createParam<StatefulButton9>(logicModeParamPosition, module, Lgsw::LOGIC_MODE_PARAM));
+
+ addInput(createInput<Port24>(gateAInputPosition, module, Lgsw::GATE_A_INPUT));
+ addInput(createInput<Port24>(gateBInputPosition, module, Lgsw::GATE_B_INPUT));
+ addInput(createInput<Port24>(logicModeInputPosition, module, Lgsw::LOGIC_MODE_INPUT));
+ addInput(createInput<Port24>(high1InputPosition, module, Lgsw::HIGH_INPUT));
+ addInput(createInput<Port24>(low1InputPosition, module, Lgsw::LOW_INPUT));
+
+ addOutput(createOutput<Port24>(out1OutputPosition, module, Lgsw::OUT_OUTPUT));
+
+ addChild(createLight<SmallLight<GreenLight>>(logicOrLightPosition, module, Lgsw::LOGIC_OR_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(logicAndLightPosition, module, Lgsw::LOGIC_AND_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(logicXorLightPosition, module, Lgsw::LOGIC_XOR_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(logicNorLightPosition, module, Lgsw::LOGIC_NOR_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(logicNandLightPosition, module, Lgsw::LOGIC_NAND_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(high1LightPosition, module, Lgsw::HIGH_LIGHT));
+ addChild(createLight<SmallLight<GreenLight>>(low1LightPosition, module, Lgsw::LOW_LIGHT));
+ }
+};
+
+Model* modelLgsw = createModel<Lgsw, LgswWidget>("Bogaudio-Lgsw", "LGSW", "2-way signal router with logic", "Switch", "Logic", "Polyphonic");
diff --git a/src/Lgsw.hpp b/src/Lgsw.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "bogaudio.hpp"
+#include "save_latch_to_patch.hpp"
+
+extern Model* modelLgsw;
+
+namespace bogaudio {
+
+struct Lgsw : SaveLatchToPatchModule {
+ enum ParamsIds {
+ GATE_PARAM,
+ LATCH_PARAM,
+ LOGIC_MODE_PARAM,
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ GATE_A_INPUT,
+ GATE_B_INPUT,
+ LOGIC_MODE_INPUT,
+ HIGH_INPUT,
+ LOW_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ enum LightsIds {
+ LOGIC_OR_LIGHT,
+ LOGIC_AND_LIGHT,
+ LOGIC_XOR_LIGHT,
+ LOGIC_NOR_LIGHT,
+ LOGIC_NAND_LIGHT,
+ HIGH_LIGHT,
+ LOW_LIGHT,
+ NUM_LIGHTS
+ };
+
+ enum Logic {
+ OR_LOGIC,
+ AND_LOGIC,
+ XOR_LOGIC,
+ NOR_LOGIC,
+ NAND_LOGIC
+ };
+
+ Trigger _buttonTriggers[maxChannels];
+ Trigger _aTriggers[maxChannels];
+ Trigger _bTriggers[maxChannels];
+ bool _lastLogicTrue[maxChannels] {};
+ int _highLightSum = 0;
+ int _lowLightSum = 0;
+ Logic _logic = OR_LOGIC;
+
+ Lgsw() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ configParam(GATE_PARAM, 0.0f, 10.0f, 0.0f, "Gate");
+ configParam(LATCH_PARAM, 0.0f, 1.0f, 0.0f, "Latch");
+ configParam(LOGIC_MODE_PARAM, 0.0f, 4.0f, 0.0f, "Logic");
+ }
+
+ void resetChannel(int c);
+ void reset() override;
+ int channels() override;
+ void channelsChanged(int before, int after) override;
+ void modulate() override;
+ void processAlways(const ProcessArgs& args) override;
+ void processChannel(const ProcessArgs& args, int _c) override;
+ void postProcessAlways(const ProcessArgs& args) override;
+};
+
+} // namespace bogaudio
diff --git a/src/Switch.cpp b/src/Switch.cpp
@@ -1,40 +1,10 @@
#include "Switch.hpp"
-#define SAVE_LATCHED_TO_PATCH "save_latched_to_patch"
-#define LATCHED_STATE "latched_state"
-
void bogaudio::Switch::reset() {
for (int i = 0; i < _channels; ++i) {
_trigger[i].reset();
- }
-}
-
-json_t* bogaudio::Switch::toJson(json_t* root) {
- json_object_set_new(root, SAVE_LATCHED_TO_PATCH, json_boolean(_saveLatchedToPatch));
- if (_saveLatchedToPatch && _latch) {
- json_t* a = json_array();
- for (int c = 0; c < maxChannels; ++c) {
- json_array_append_new(a, json_boolean(_latchedHigh[c]));
- }
- json_object_set_new(root, LATCHED_STATE, a);
- }
- return root;
-}
-
-void bogaudio::Switch::fromJson(json_t* root) {
- json_t* sl = json_object_get(root, SAVE_LATCHED_TO_PATCH);
- if (sl) {
- _saveLatchedToPatch = json_is_true(sl);
- json_t* a = json_object_get(root, LATCHED_STATE);
- if (_saveLatchedToPatch && a && json_array_size(a) == maxChannels) {
- for (int c = 0; c < maxChannels; ++c) {
- json_t* ls = json_array_get(a, c);
- if (ls && json_is_true(ls)) {
- _latchedHigh[c] = true;
- }
- }
- }
+ _latchedHigh[i] = false;
}
}
@@ -43,9 +13,8 @@ int bogaudio::Switch::channels() {
}
void bogaudio::Switch::channelsChanged(int before, int after) {
- while (before < after) {
+ for (; before < after; ++before) {
_trigger[before].reset();
- ++before;
}
}
@@ -118,7 +87,7 @@ void bogaudio::Switch::postProcessAlways(const ProcessArgs& args) {
lights[LOW2_LIGHT].value = _low2LightSum * _inverseChannels;
}
-struct SwitchWidget : BGModuleWidget {
+struct SwitchWidget : SaveLatchToPatchModuleWidget {
static constexpr int hp = 3;
SwitchWidget(bogaudio::Switch* module) {
@@ -163,12 +132,6 @@ struct SwitchWidget : BGModuleWidget {
addChild(createLight<SmallLight<GreenLight>>(high2LightPosition, module, bogaudio::Switch::HIGH2_LIGHT));
addChild(createLight<SmallLight<GreenLight>>(low2LightPosition, module, bogaudio::Switch::LOW2_LIGHT));
}
-
- void contextMenu(Menu* menu) override {
- auto m = dynamic_cast<bogaudio::Switch*>(module);
- assert(m);
- menu->addChild(new BoolOptionMenuItem("Save latched state to patch", [m]() { return &m->_saveLatchedToPatch; }));
- }
};
Model* modelSwitch = bogaudio::createModel<bogaudio::Switch, SwitchWidget>("Bogaudio-Switch", "SWITCH", "2-way signal router", "Switch", "Polyphonic");
diff --git a/src/Switch.hpp b/src/Switch.hpp
@@ -1,12 +1,13 @@
#pragma once
#include "bogaudio.hpp"
+#include "save_latch_to_patch.hpp"
extern Model* modelSwitch;
namespace bogaudio {
-struct Switch : BGModule {
+struct Switch : SaveLatchToPatchModule {
enum ParamsIds {
GATE_PARAM,
LATCH_PARAM,
@@ -36,10 +37,7 @@ struct Switch : BGModule {
NUM_LIGHTS
};
- bool _saveLatchedToPatch = false;
Trigger _trigger[maxChannels];
- bool _latchedHigh[maxChannels] {};
- bool _latch = false;
int _high1LightSum = 0;
int _low1LightSum = 0;
int _high2LightSum = 0;
@@ -52,8 +50,6 @@ struct Switch : BGModule {
}
void reset() override;
- json_t* toJson(json_t* root) override;
- void fromJson(json_t* root) override;
int channels() override;
void channelsChanged(int before, int after) override;
void modulate() override;
diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp
@@ -38,6 +38,7 @@
#include "Inv.hpp"
#include "Lag.hpp"
#include "LFO.hpp"
+#include "Lgsw.hpp"
#include "LLFO.hpp"
#include "LLPG.hpp"
#include "Lmtr.hpp"
@@ -249,6 +250,7 @@ void init(rack::Plugin *p) {
p->addModel(modelSlew);
p->addModel(modelSums);
p->addModel(modelSwitch);
+ p->addModel(modelLgsw);
p->addModel(modelBlank3);
p->addModel(modelBlank6);
diff --git a/src/save_latch_to_patch.cpp b/src/save_latch_to_patch.cpp
@@ -0,0 +1,39 @@
+#include "save_latch_to_patch.hpp"
+
+#define SAVE_LATCHED_TO_PATCH "save_latched_to_patch"
+#define LATCHED_STATE "latched_state"
+
+json_t* SaveLatchToPatchModule::toJson(json_t* root) {
+ json_object_set_new(root, SAVE_LATCHED_TO_PATCH, json_boolean(_saveLatchedToPatch));
+ if (_saveLatchedToPatch && _latch) {
+ json_t* a = json_array();
+ for (int c = 0; c < maxChannels; ++c) {
+ json_array_append_new(a, json_boolean(_latchedHigh[c]));
+ }
+ json_object_set_new(root, LATCHED_STATE, a);
+ }
+ return root;
+}
+
+void SaveLatchToPatchModule::fromJson(json_t* root) {
+ json_t* sl = json_object_get(root, SAVE_LATCHED_TO_PATCH);
+ if (sl) {
+ _saveLatchedToPatch = json_is_true(sl);
+ json_t* a = json_object_get(root, LATCHED_STATE);
+ if (_saveLatchedToPatch && a && json_array_size(a) == maxChannels) {
+ for (int c = 0; c < maxChannels; ++c) {
+ json_t* ls = json_array_get(a, c);
+ if (ls && json_is_true(ls)) {
+ _latchedHigh[c] = true;
+ }
+ }
+ }
+ }
+}
+
+
+void SaveLatchToPatchModuleWidget::contextMenu(Menu* menu) {
+ auto m = dynamic_cast<SaveLatchToPatchModule*>(module);
+ assert(m);
+ menu->addChild(new BoolOptionMenuItem("Save latched state to patch", [m]() { return &m->_saveLatchedToPatch; }));
+}
diff --git a/src/save_latch_to_patch.hpp b/src/save_latch_to_patch.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "bogaudio.hpp"
+
+using namespace rack;
+
+namespace bogaudio {
+
+struct SaveLatchToPatchModule : BGModule {
+ bool _saveLatchedToPatch = false;
+ bool _latchedHigh[maxChannels] {};
+ bool _latch = false;
+
+ json_t* toJson(json_t* root) override;
+ void fromJson(json_t* root) override;
+};
+
+struct SaveLatchToPatchModuleWidget : BGModuleWidget {
+ void contextMenu(Menu* menu) override;
+};
+
+} // namespace bogaudio