commit 276f6774b700ffe97c0a6257535a823266312947
parent b7a1696d7c771508ed8c5bb347412785321c7791
Author: Matt Demanett <matt@demanett.net>
Date: Sat, 28 Mar 2020 21:49:03 -0400
MIX4X/MIX8X: EQ and send expanders for MIX4/8.
Diffstat:
23 files changed, 1644 insertions(+), 97 deletions(-)
diff --git a/plugin.json b/plugin.json
@@ -279,6 +279,15 @@
]
},
{
+ "slug": "Bogaudio-Mix8x",
+ "name": "MIX8X",
+ "description": "Expander for MIX8, adds EQs and sends",
+ "tags": [
+ "Mixer",
+ "Expander"
+ ]
+ },
+ {
"slug": "Bogaudio-Mix4",
"name": "MIX4",
"description": "4-channel mixer and panner",
@@ -288,6 +297,15 @@
]
},
{
+ "slug": "Bogaudio-Mix4x",
+ "name": "MIX4X",
+ "description": "Expander for MIX4, adds EQs and sends",
+ "tags": [
+ "Mixer",
+ "Expander"
+ ]
+ },
+ {
"slug": "Bogaudio-Mix1",
"name": "MIX1",
"description": "Fader/amplifier with CV controllable mute",
diff --git a/res-src/Mix4x-src.svg b/res-src/Mix4x-src.svg
@@ -0,0 +1,260 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="225"
+ height="380"
+ viewBox="0 0 225 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-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>
+
+ <symbol id="knobguide-centertick" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <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(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(-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>
+
+ <symbol id="knobguide-maxtick" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <g transform="rotate(60) 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(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(-43)" />
+ </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>
+
+ <symbol id="button-small" viewBox="0 0 9px 9px">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00" />
+ </g>
+ </symbol>
+
+ <symbol id="light-tiny" viewBox="0 0 1.1px 1.1px">
+ <rect width="3.2" height="3.2" fill="#0f0" />
+ </symbol>
+ </defs>
+
+ <rect width="100%" height="100%" fill="#ddd" />
+ <polyline points="1,1 224,1 224,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 224.5,0.5 224.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 225,0 225,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <!-- <rect width="75" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="75" height="20" fill="#0f0" transform="translate(150 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(10 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(215 0)" /> -->
+ <!-- <polyline points="0,0 225,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 360)" /> -->
+
+ <text class="title" x="77" y="19" font-size="12pt" letter-spacing="4px">MIX4X</text>
+ <g transform="translate(72.5 374)">
+ <text class="brand" font-size="8pt" letter-spacing="2px">BOGAUDIO</text>
+ <rect width="3.0" height="3" fill="#ddd" transform="translate(24 -5)" />
+ </g>
+
+ <g transform="translate(4 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH1</text>
+ <use id="LOW1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A1_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B1_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A1_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B1_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(47 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH2</text>
+ <use id="LOW2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A2_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B2_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A2_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B2_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(90 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH3</text>
+ <use id="LOW3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A3_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B3_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A3_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B3_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(133 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH4</text>
+ <use id="LOW4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A4_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B4_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A4_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B4_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(176 20)">
+ <!-- <rect width="39" height="344" fill="#ccc" transform="translate(3 0)" /> -->
+ <g transform="translate(5.5 1)">
+ <rect width="34" height="50" rx="5" fill="#bbb" />
+ <use id="SEND_A_OUTPUT" xlink:href="#output" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14.7 35)">A</text>
+ <rect width="34" height="146" rx="5" fill="#fafafa" transform="translate(0 38)" />
+ <rect width="34" height="5" fill="#fafafa" transform="translate(0 38)" />
+ <use id="L_A_INPUT" xlink:href="#input" transform="translate(5 41)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(15.3 73)">L</text>
+ <use id="R_A_INPUT" xlink:href="#input" transform="translate(5 76)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8 108)">R(L)</text>
+ <use id="LEVEL_A_PARAM" xlink:href="#knob-smallest" transform="translate(9 117)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 145)">LEVEL</text>
+ <use id="LEVEL_A_INPUT" xlink:href="#input" transform="translate(5 149)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11 181)">CV</text>
+ <!-- <g transform="translate(0 29.5)"> -->
+ <!-- <rect width="9" height="36" rx="5" fill="#fafafa" transform="translate(-9 8.5)" /> -->
+ <!-- <rect width="4" height="36" fill="#fafafa" transform="translate(-4 8.5)" /> -->
+ <!-- <text font-size="5pt" letter-spacing="2px" transform="translate(-1 40) rotate(-90)">AUX A</text> -->
+ <!-- </g> -->
+ </g>
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 106)" />
+
+ <g transform="translate(5.5 191)">
+ <rect width="34" height="50" rx="5" fill="#bbb" />
+ <use id="SEND_B_OUTPUT" xlink:href="#output" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14.8 35)">B</text>
+ <rect width="34" height="111" rx="5" fill="#fafafa" transform="translate(0 38)" />
+ <rect width="34" height="5" fill="#fafafa" transform="translate(0 38)" />
+ <use id="L_B_INPUT" xlink:href="#input" transform="translate(5 41)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(15.3 73)">L</text>
+ <use id="R_B_INPUT" xlink:href="#input" transform="translate(5 76)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8 108)">R(L)</text>
+ <use id="LEVEL_B_PARAM" xlink:href="#knob-smallest" transform="translate(9 117)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 145)">LEVEL</text>
+ </g>
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 296)" />
+ <!-- <polyline points="0,0 0,350" stroke="#0f0" stroke-width="1" fill="none" transform="translate(22.5 0)" /> -->
+ </g>
+</svg>
diff --git a/res-src/Mix8x-src.svg b/res-src/Mix8x-src.svg
@@ -0,0 +1,374 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="405"
+ height="380"
+ viewBox="0 0 405 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-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>
+
+ <symbol id="knobguide-centertick" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <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(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(-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>
+
+ <symbol id="knobguide-maxtick" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <g transform="rotate(60) 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(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(-43)" />
+ </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>
+
+ <symbol id="button-small" viewBox="0 0 9px 9px">
+ <g transform="translate(4.5 4.5)">
+ <circle r="4" stroke-width="1" stroke="#00f" fill="#f00" />
+ </g>
+ </symbol>
+
+ <symbol id="light-tiny" viewBox="0 0 1.1px 1.1px">
+ <rect width="3.2" height="3.2" fill="#0f0" />
+ </symbol>
+ </defs>
+
+ <rect width="100%" height="100%" fill="#ddd" />
+ <polyline points="1,1 404,1 404,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 404.5,0.5 404.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 405,0 405,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <!-- <rect width="170" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="170" height="20" fill="#0f0" transform="translate(235 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(10 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(395 0)" /> -->
+
+ <text class="title" x="168" y="19" font-size="12pt" letter-spacing="4px">MIX8X</text>
+ <g transform="translate(162.5 374)">
+ <text class="brand" font-size="8pt" letter-spacing="2px">BOGAUDIO</text>
+ <rect width="3.0" height="3" fill="#ddd" transform="translate(24 -5)" />
+ </g>
+
+ <g transform="translate(4 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH1</text>
+ <use id="LOW1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A1_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B1_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B1_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A1_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B1_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(48 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH2</text>
+ <use id="LOW2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A2_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B2_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B2_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A2_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B2_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(92 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH3</text>
+ <use id="LOW3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A3_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B3_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B3_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A3_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B3_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(136 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH4</text>
+ <use id="LOW4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A4_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B4_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B4_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A4_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B4_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(180 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH5</text>
+ <use id="LOW5_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID5_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH5_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A5_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A5_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B5_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B5_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A5_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B5_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(224 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH6</text>
+ <use id="LOW6_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID6_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH6_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A6_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A6_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B6_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B6_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A6_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B6_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(268 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH7</text>
+ <use id="LOW7_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID7_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH7_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A7_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A7_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B7_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B7_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A7_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B7_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(312 20)">
+ <text font-size="5pt" letter-spacing="2px" transform="translate(13.7 9)">CH8</text>
+ <use id="LOW8_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 23)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 11)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 48)">LOW</text>
+ <use id="MID8_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 69)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 57)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14 94)">MID</text>
+ <use id="HIGH8_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 115)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(2.5 103)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11.5 140)">HIGH</text>
+ <use id="A8_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 160)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 148)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.2 185)">A</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 195)">PRE</text>
+ <use id="PRE_A8_PARAM" xlink:href="#button-small" transform="translate(26 188)" />
+ <use id="B8_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 216)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 204)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(20.4 241)">B</text>
+ <text font-size="5pt" letter-spacing="1px" transform="translate(9 251)">PRE</text>
+ <use id="PRE_B8_PARAM" xlink:href="#button-small" transform="translate(26 244)" />
+ <g transform="translate(5.5 267)">
+ <rect width="34" height="73" rx="5" fill="#fafafa" />
+ <use id="A8_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 35)">CV-A</text>
+ <use id="B8_INPUT" xlink:href="#input" transform="translate(5 38)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(6 70)">CV-B</text>
+ </g>
+ </g>
+
+ <g transform="translate(356 20)">
+ <!-- <rect width="39" height="344" fill="#ccc" transform="translate(3 0)" /> -->
+ <g transform="translate(5.5 1)">
+ <rect width="34" height="50" rx="5" fill="#bbb" />
+ <use id="SEND_A_OUTPUT" xlink:href="#output" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14.7 35)">A</text>
+ <rect width="34" height="146" rx="5" fill="#fafafa" transform="translate(0 38)" />
+ <rect width="34" height="5" fill="#fafafa" transform="translate(0 38)" />
+ <use id="L_A_INPUT" xlink:href="#input" transform="translate(5 41)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(15.3 73)">L</text>
+ <use id="R_A_INPUT" xlink:href="#input" transform="translate(5 76)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8 108)">R(L)</text>
+ <use id="LEVEL_A_PARAM" xlink:href="#knob-smallest" transform="translate(9 117)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 145)">LEVEL</text>
+ <use id="LEVEL_A_INPUT" xlink:href="#input" transform="translate(5 149)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(11 181)">CV</text>
+ </g>
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 106)" />
+
+ <g transform="translate(5.5 191)">
+ <rect width="34" height="50" rx="5" fill="#bbb" />
+ <use id="SEND_B_OUTPUT" xlink:href="#output" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(14.8 35)">B</text>
+ <rect width="34" height="111" rx="5" fill="#fafafa" transform="translate(0 38)" />
+ <rect width="34" height="5" fill="#fafafa" transform="translate(0 38)" />
+ <use id="L_B_INPUT" xlink:href="#input" transform="translate(5 41)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(15.3 73)">L</text>
+ <use id="R_B_INPUT" xlink:href="#input" transform="translate(5 76)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8 108)">R(L)</text>
+ <use id="LEVEL_B_PARAM" xlink:href="#knob-smallest" transform="translate(9 117)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 145)">LEVEL</text>
+ </g>
+ <use xlink:href="#knobguide-maxtick" transform="translate(2.5 296)" />
+ <!-- <polyline points="0,0 0,350" stroke="#0f0" stroke-width="1" fill="none" transform="translate(22.5 0)" /> -->
+ </g>
+</svg>
diff --git a/res/Mix4x.svg b/res/Mix4x.svg
Binary files differ.
diff --git a/res/Mix8x.svg b/res/Mix8x.svg
Binary files differ.
diff --git a/src/FFB.hpp b/src/FFB.hpp
@@ -64,21 +64,21 @@ struct FFB : BGModule {
FFB() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
- configParam<AmpliferParamQuantity>(BAND_1_PARAM, 0.0f, 1.0f, 1.0f, "Band 1 level");
- configParam<AmpliferParamQuantity>(BAND_5_PARAM, 0.0f, 1.0f, 1.0f, "Band 5 level");
- configParam<AmpliferParamQuantity>(BAND_9_PARAM, 0.0f, 1.0f, 1.0f, "Band 9 level");
- configParam<AmpliferParamQuantity>(BAND_2_PARAM, 0.0f, 1.0f, 1.0f, "Band 2 level");
- configParam<AmpliferParamQuantity>(BAND_6_PARAM, 0.0f, 1.0f, 1.0f, "Band 6 level");
- configParam<AmpliferParamQuantity>(BAND_10_PARAM, 0.0f, 1.0f, 1.0f, "Band 10 level");
- configParam<AmpliferParamQuantity>(BAND_3_PARAM, 0.0f, 1.0f, 1.0f, "Band 3 level");
- configParam<AmpliferParamQuantity>(BAND_7_PARAM, 0.0f, 1.0f, 1.0f, "Band 7 level");
- configParam<AmpliferParamQuantity>(BAND_11_PARAM, 0.0f, 1.0f, 1.0f, "Band 11 level");
- configParam<AmpliferParamQuantity>(BAND_4_PARAM, 0.0f, 1.0f, 1.0f, "Band 4 level");
- configParam<AmpliferParamQuantity>(BAND_8_PARAM, 0.0f, 1.0f, 1.0f, "Band 8 level");
- configParam<AmpliferParamQuantity>(BAND_12_PARAM, 0.0f, 1.0f, 1.0f, "Band 12 level");
- configParam<AmpliferParamQuantity>(LOWPASS_PARAM, 0.0f, 1.0f, 1.0f, "Lowpass level");
+ configParam<AmplifierParamQuantity>(BAND_1_PARAM, 0.0f, 1.0f, 1.0f, "Band 1 level");
+ configParam<AmplifierParamQuantity>(BAND_5_PARAM, 0.0f, 1.0f, 1.0f, "Band 5 level");
+ configParam<AmplifierParamQuantity>(BAND_9_PARAM, 0.0f, 1.0f, 1.0f, "Band 9 level");
+ configParam<AmplifierParamQuantity>(BAND_2_PARAM, 0.0f, 1.0f, 1.0f, "Band 2 level");
+ configParam<AmplifierParamQuantity>(BAND_6_PARAM, 0.0f, 1.0f, 1.0f, "Band 6 level");
+ configParam<AmplifierParamQuantity>(BAND_10_PARAM, 0.0f, 1.0f, 1.0f, "Band 10 level");
+ configParam<AmplifierParamQuantity>(BAND_3_PARAM, 0.0f, 1.0f, 1.0f, "Band 3 level");
+ configParam<AmplifierParamQuantity>(BAND_7_PARAM, 0.0f, 1.0f, 1.0f, "Band 7 level");
+ configParam<AmplifierParamQuantity>(BAND_11_PARAM, 0.0f, 1.0f, 1.0f, "Band 11 level");
+ configParam<AmplifierParamQuantity>(BAND_4_PARAM, 0.0f, 1.0f, 1.0f, "Band 4 level");
+ 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<AmpliferParamQuantity>(HIGHPASS_PARAM, 0.0f, 1.0f, 1.0f, "Highpass level");
+ configParam<AmplifierParamQuantity>(HIGHPASS_PARAM, 0.0f, 1.0f, 1.0f, "Highpass level");
}
void sampleRateChange() override;
diff --git a/src/FMOp.hpp b/src/FMOp.hpp
@@ -98,7 +98,7 @@ struct FMOp : BGModule {
void setDisplayValue(float v) override;
};
- struct LevelParamQuantity : AmpliferParamQuantity {
+ struct LevelParamQuantity : AmplifierParamQuantity {
bool isLinear() override;
};
diff --git a/src/Mix1.cpp b/src/Mix1.cpp
@@ -19,10 +19,8 @@ int Mix1::channels() {
void Mix1::addChannel(int c) {
_engines[c] = new MixerChannel(
params[LEVEL_PARAM],
- params[LEVEL_PARAM], // not used
params[MUTE_PARAM],
inputs[LEVEL_INPUT],
- inputs[LEVEL_INPUT], // not used
1000.0f,
&inputs[MUTE_INPUT]
);
@@ -40,7 +38,7 @@ void Mix1::processAlways(const ProcessArgs& args) {
void Mix1::processChannel(const ProcessArgs& args, int c) {
MixerChannel& e = *_engines[c];
- e.next(inputs[IN_INPUT].getVoltage(c), false, false, c);
+ e.next(inputs[IN_INPUT].getVoltage(c), false, c);
_rmsSum += e.rms;
outputs[OUT_OUTPUT].setChannels(_channels);
outputs[OUT_OUTPUT].setVoltage(e.out, c);
diff --git a/src/Mix4.cpp b/src/Mix4.cpp
@@ -20,13 +20,20 @@ void Mix4::sampleRateChange() {
float sr = APP->engine->getSampleRate();
for (int i = 0; i < 4; ++i) {
_channels[i]->setSampleRate(sr);
+ _panSLs[i].setParams(sr, MIXER_PAN_SLEW_MS, 2.0f);
}
_slewLimiter.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
_rms.setSampleRate(sr);
}
-void Mix4::processChannel(const ProcessArgs& args, int _c) {
- bool stereo = outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected();
+void Mix4::processAll(const ProcessArgs& args) {
+ Mix4ExpanderMessage* toExp = &_dummyExpanderMessage;
+ Mix4ExpanderMessage* fromExp = &_dummyExpanderMessage;
+ if (connected()) {
+ toExp = toExpander();
+ fromExp = fromExpander();
+ }
+
bool solo =
params[MUTE1_PARAM].getValue() > 1.5f ||
params[MUTE2_PARAM].getValue() > 1.5f ||
@@ -40,7 +47,8 @@ void Mix4::processChannel(const ProcessArgs& args, int _c) {
} else {
sample = inputs[IN1_INPUT].getVoltageSum();
}
- _channels[0]->next(sample, stereo, solo);
+ _channels[0]->next(sample, solo);
+ toExp->preFader[0] = sample;
for (int i = 1; i < 4; ++i) {
float sample = 0.0f;
@@ -50,7 +58,8 @@ void Mix4::processChannel(const ProcessArgs& args, int _c) {
else if (_polyChannelOffset >= 0) {
sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset + i);
}
- _channels[i]->next(sample, stereo, solo);
+ _channels[i]->next(sample, solo);
+ toExp->preFader[i] = sample;
}
}
@@ -65,27 +74,45 @@ void Mix4::processChannel(const ProcessArgs& args, int _c) {
}
_amplifier.setLevel(_slewLimiter.next(level));
+ float outs[4];
+ for (int i = 0; i < 4; ++i) {
+ toExp->postFader[i] = outs[i] = _channels[i]->out;
+ }
+
float mono = 0.0f;
+ float left = 0.0f;
+ float right = 0.0f;
+ if (connected()) {
+ mono += fromExp->returnA[0] + fromExp->returnB[0];
+ left += fromExp->returnA[0] + fromExp->returnB[0];
+ right += fromExp->returnA[1] + fromExp->returnB[1];
+ std::copy(fromExp->postEQ, fromExp->postEQ + 4, outs);
+ }
+
for (int i = 0; i < 4; ++i) {
- mono += _channels[i]->out;
+ mono += outs[i];
}
mono = _amplifier.next(mono);
mono = _saturator.next(mono);
_rmsLevel = _rms.next(mono) / 5.0f;
- if (stereo) {
- float left = 0.0f;
+ if (outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected()) {
for (int i = 0; i < 4; ++i) {
- left += _channels[i]->left;
+ float pan = clamp(params[PAN1_PARAM + 3 * i].getValue(), -1.0f, 1.0f);
+ if (inputs[PAN1_INPUT + 3 * i].isConnected()) {
+ pan *= clamp(inputs[PAN1_INPUT + 3 * i].getVoltage() / 5.0f, -1.0f, 1.0f);
+ }
+ _panners[i].setPan(_panSLs[i].next(pan));
+ float l, r;
+ _panners[i].next(outs[i], l, r);
+ left += l;
+ right += r;
}
+
left = _amplifier.next(left);
left = _saturator.next(left);
outputs[L_OUTPUT].setVoltage(left);
- float right = 0.0f;
- for (int i = 0; i < 4; ++i) {
- right += _channels[i]->right;
- }
right = _amplifier.next(right);
right = _saturator.next(right);
outputs[R_OUTPUT].setVoltage(right);
@@ -205,3 +232,192 @@ struct Mix4Widget : ModuleWidget {
};
Model* modelMix4 = bogaudio::createModel<Mix4, Mix4Widget>("Bogaudio-Mix4", "MIX4", "4-channel mixer and panner", "Mixer", "Panning");
+
+
+void Mix4x::sampleRateChange() {
+ float sr = APP->engine->getSampleRate();
+ for (int i = 0; i < 4; ++i) {
+ _channels[i]->setSampleRate(sr);
+ }
+ _returnASL.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+ _returnBSL.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+}
+
+void Mix4x::processAll(const ProcessArgs& args) {
+ if (!connected()) {
+ outputs[SEND_A_OUTPUT].setVoltage(0.0f);
+ outputs[SEND_B_OUTPUT].setVoltage(0.0f);
+ return;
+ }
+
+ Mix4ExpanderMessage* from = fromBase();
+ Mix4ExpanderMessage* to = toBase();
+ float sendA = 0.0f;
+ float sendB = 0.0f;
+ for (int i = 0; i < 4; ++i) {
+ _channels[i]->next(from->preFader[i], from->postFader[i]);
+ to->postEQ[i] = _channels[i]->postEQ;
+ sendA += _channels[i]->sendA;
+ sendB += _channels[i]->sendB;
+ }
+ outputs[SEND_A_OUTPUT].setVoltage(_saturatorA.next(sendA));
+ outputs[SEND_B_OUTPUT].setVoltage(_saturatorA.next(sendB));
+
+ float levelA = clamp(params[LEVEL_A_PARAM].getValue(), 0.0f, 1.0f);
+ if (inputs[LEVEL_A_INPUT].isConnected()) {
+ levelA *= clamp(inputs[LEVEL_A_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f);
+ }
+ levelA = 1.0f - levelA;
+ levelA *= Amplifier::minDecibels;
+ _returnAAmp.setLevel(_returnASL.next(levelA));
+ if (inputs[L_A_INPUT].isConnected()) {
+ to->returnA[0] = _returnAAmp.next(inputs[L_A_INPUT].getVoltage());
+ }
+ else {
+ to->returnA[0] = 0.0f;
+ }
+ if (inputs[R_A_INPUT].isConnected()) {
+ to->returnA[1] = _returnAAmp.next(inputs[R_A_INPUT].getVoltage());
+ }
+ else {
+ to->returnA[1] = to->returnA[0];
+ }
+
+ float levelB = clamp(params[LEVEL_B_PARAM].getValue(), 0.0f, 1.0f);
+ levelB = 1.0f - levelB;
+ levelB *= Amplifier::minDecibels;
+ _returnBAmp.setLevel(_returnBSL.next(levelB));
+ if (inputs[L_B_INPUT].isConnected()) {
+ to->returnB[0] = _returnBAmp.next(inputs[L_B_INPUT].getVoltage());
+ }
+ else {
+ to->returnB[0] = 0.0f;
+ }
+ if (inputs[R_B_INPUT].isConnected()) {
+ to->returnB[1] = _returnBAmp.next(inputs[R_B_INPUT].getVoltage());
+ }
+ else {
+ to->returnB[1] = to->returnB[0];
+ }
+}
+
+struct Mix4xWidget : ModuleWidget {
+ static constexpr int hp = 15;
+
+ Mix4xWidget(Mix4x* module) {
+ setModule(module);
+ box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
+
+ {
+ SvgPanel *panel = new SvgPanel();
+ panel->box.size = box.size;
+ panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Mix4x.svg")));
+ addChild(panel);
+ }
+
+ addChild(createWidget<ScrewSilver>(Vec(15, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(15, 365)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));
+
+ // generated by svg_widgets.rb
+ auto low1ParamPosition = Vec(18.5, 43.0);
+ auto mid1ParamPosition = Vec(18.5, 89.0);
+ auto high1ParamPosition = Vec(18.5, 135.0);
+ auto a1ParamPosition = Vec(18.5, 180.0);
+ auto preA1ParamPosition = Vec(30.0, 208.0);
+ auto b1ParamPosition = Vec(18.5, 236.0);
+ auto preB1ParamPosition = Vec(30.0, 264.0);
+ auto low2ParamPosition = Vec(61.5, 43.0);
+ auto mid2ParamPosition = Vec(61.5, 89.0);
+ auto high2ParamPosition = Vec(61.5, 135.0);
+ auto a2ParamPosition = Vec(61.5, 180.0);
+ auto preA2ParamPosition = Vec(73.0, 208.0);
+ auto b2ParamPosition = Vec(61.5, 236.0);
+ auto preB2ParamPosition = Vec(73.0, 264.0);
+ auto low3ParamPosition = Vec(104.5, 43.0);
+ auto mid3ParamPosition = Vec(104.5, 89.0);
+ auto high3ParamPosition = Vec(104.5, 135.0);
+ auto a3ParamPosition = Vec(104.5, 180.0);
+ auto preA3ParamPosition = Vec(116.0, 208.0);
+ auto b3ParamPosition = Vec(104.5, 236.0);
+ auto preB3ParamPosition = Vec(116.0, 264.0);
+ auto low4ParamPosition = Vec(147.5, 43.0);
+ auto mid4ParamPosition = Vec(147.5, 89.0);
+ auto high4ParamPosition = Vec(147.5, 135.0);
+ auto a4ParamPosition = Vec(147.5, 180.0);
+ auto preA4ParamPosition = Vec(159.0, 208.0);
+ auto b4ParamPosition = Vec(147.5, 236.0);
+ auto preB4ParamPosition = Vec(159.0, 264.0);
+ auto levelAParamPosition = Vec(190.5, 138.0);
+ auto levelBParamPosition = Vec(190.5, 328.0);
+
+ auto a1InputPosition = Vec(14.5, 290.0);
+ auto b1InputPosition = Vec(14.5, 325.0);
+ auto a2InputPosition = Vec(57.5, 290.0);
+ auto b2InputPosition = Vec(57.5, 325.0);
+ auto a3InputPosition = Vec(100.5, 290.0);
+ auto b3InputPosition = Vec(100.5, 325.0);
+ auto a4InputPosition = Vec(143.5, 290.0);
+ auto b4InputPosition = Vec(143.5, 325.0);
+ auto lAInputPosition = Vec(186.5, 62.0);
+ auto rAInputPosition = Vec(186.5, 97.0);
+ auto levelAInputPosition = Vec(186.5, 170.0);
+ auto lBInputPosition = Vec(186.5, 252.0);
+ auto rBInputPosition = Vec(186.5, 287.0);
+
+ auto sendAOutputPosition = Vec(186.5, 24.0);
+ auto sendBOutputPosition = Vec(186.5, 214.0);
+ // end generated by svg_widgets.rb
+
+ addParam(createParam<Knob16>(low1ParamPosition, module, Mix4x::LOW1_PARAM));
+ addParam(createParam<Knob16>(mid1ParamPosition, module, Mix4x::MID1_PARAM));
+ addParam(createParam<Knob16>(high1ParamPosition, module, Mix4x::HIGH1_PARAM));
+ addParam(createParam<Knob16>(a1ParamPosition, module, Mix4x::A1_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA1ParamPosition, module, Mix4x::PRE_A1_PARAM));
+ addParam(createParam<Knob16>(b1ParamPosition, module, Mix4x::B1_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB1ParamPosition, module, Mix4x::PRE_B1_PARAM));
+ addParam(createParam<Knob16>(low2ParamPosition, module, Mix4x::LOW2_PARAM));
+ addParam(createParam<Knob16>(mid2ParamPosition, module, Mix4x::MID2_PARAM));
+ addParam(createParam<Knob16>(high2ParamPosition, module, Mix4x::HIGH2_PARAM));
+ addParam(createParam<Knob16>(a2ParamPosition, module, Mix4x::A2_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA2ParamPosition, module, Mix4x::PRE_A2_PARAM));
+ addParam(createParam<Knob16>(b2ParamPosition, module, Mix4x::B2_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB2ParamPosition, module, Mix4x::PRE_B2_PARAM));
+ addParam(createParam<Knob16>(low3ParamPosition, module, Mix4x::LOW3_PARAM));
+ addParam(createParam<Knob16>(mid3ParamPosition, module, Mix4x::MID3_PARAM));
+ addParam(createParam<Knob16>(high3ParamPosition, module, Mix4x::HIGH3_PARAM));
+ addParam(createParam<Knob16>(a3ParamPosition, module, Mix4x::A3_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA3ParamPosition, module, Mix4x::PRE_A3_PARAM));
+ addParam(createParam<Knob16>(b3ParamPosition, module, Mix4x::B3_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB3ParamPosition, module, Mix4x::PRE_B3_PARAM));
+ addParam(createParam<Knob16>(low4ParamPosition, module, Mix4x::LOW4_PARAM));
+ addParam(createParam<Knob16>(mid4ParamPosition, module, Mix4x::MID4_PARAM));
+ addParam(createParam<Knob16>(high4ParamPosition, module, Mix4x::HIGH4_PARAM));
+ addParam(createParam<Knob16>(a4ParamPosition, module, Mix4x::A4_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA4ParamPosition, module, Mix4x::PRE_A4_PARAM));
+ addParam(createParam<Knob16>(b4ParamPosition, module, Mix4x::B4_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB4ParamPosition, module, Mix4x::PRE_B4_PARAM));
+ addParam(createParam<Knob16>(levelAParamPosition, module, Mix4x::LEVEL_A_PARAM));
+ addParam(createParam<Knob16>(levelBParamPosition, module, Mix4x::LEVEL_B_PARAM));
+
+ addInput(createInput<Port24>(a1InputPosition, module, Mix4x::A1_INPUT));
+ addInput(createInput<Port24>(b1InputPosition, module, Mix4x::B1_INPUT));
+ addInput(createInput<Port24>(a2InputPosition, module, Mix4x::A2_INPUT));
+ addInput(createInput<Port24>(b2InputPosition, module, Mix4x::B2_INPUT));
+ addInput(createInput<Port24>(a3InputPosition, module, Mix4x::A3_INPUT));
+ addInput(createInput<Port24>(b3InputPosition, module, Mix4x::B3_INPUT));
+ addInput(createInput<Port24>(a4InputPosition, module, Mix4x::A4_INPUT));
+ addInput(createInput<Port24>(b4InputPosition, module, Mix4x::B4_INPUT));
+ addInput(createInput<Port24>(lAInputPosition, module, Mix4x::L_A_INPUT));
+ addInput(createInput<Port24>(rAInputPosition, module, Mix4x::R_A_INPUT));
+ addInput(createInput<Port24>(levelAInputPosition, module, Mix4x::LEVEL_A_INPUT));
+ addInput(createInput<Port24>(lBInputPosition, module, Mix4x::L_B_INPUT));
+ addInput(createInput<Port24>(rBInputPosition, module, Mix4x::R_B_INPUT));
+
+ addOutput(createOutput<Port24>(sendAOutputPosition, module, Mix4x::SEND_A_OUTPUT));
+ addOutput(createOutput<Port24>(sendBOutputPosition, module, Mix4x::SEND_B_OUTPUT));
+ }
+};
+
+Model* modelMix4x = createModel<Mix4x, Mix4xWidget>("Bogaudio-Mix4x", "MIX4X", "Expander for MIX4, adds EQs and sends", "Mixer", "Expander");
diff --git a/src/Mix4.hpp b/src/Mix4.hpp
@@ -7,10 +7,15 @@
using namespace bogaudio::dsp;
extern Model* modelMix4;
+extern Model* modelMix4x;
namespace bogaudio {
-struct Mix4 : BGModule {
+struct Mix4x;
+
+typedef MixerExpanderMessage<4> Mix4ExpanderMessage;
+
+struct Mix4 : ExpandableModule<Mix4ExpanderMessage, Mix4x> {
enum ParamsIds {
LEVEL1_PARAM,
PAN1_PARAM,
@@ -54,11 +59,14 @@ struct Mix4 : BGModule {
int _polyChannelOffset = -1;
MixerChannel* _channels[4] {};
+ Panner _panners[4];
+ bogaudio::dsp::SlewLimiter _panSLs[4];
Amplifier _amplifier;
bogaudio::dsp::SlewLimiter _slewLimiter;
Saturator _saturator;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
+ Mix4ExpanderMessage _dummyExpanderMessage;
Mix4() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
@@ -78,10 +86,10 @@ struct Mix4 : BGModule {
configParam(MIX_PARAM, 0.0f, 1.0f, levelDefault, "Master level", " dB", 0.0f, MixerChannel::maxDecibels - MixerChannel::minDecibels, MixerChannel::minDecibels);
configParam(MIX_MUTE_PARAM, 0.0f, 1.0f, 0.0f, "Master mute");
- _channels[0] = new MixerChannel(params[LEVEL1_PARAM], params[PAN1_PARAM], params[MUTE1_PARAM], inputs[CV1_INPUT], inputs[PAN1_INPUT]);
- _channels[1] = new MixerChannel(params[LEVEL2_PARAM], params[PAN2_PARAM], params[MUTE2_PARAM], inputs[CV2_INPUT], inputs[PAN2_INPUT]);
- _channels[2] = new MixerChannel(params[LEVEL3_PARAM], params[PAN3_PARAM], params[MUTE3_PARAM], inputs[CV3_INPUT], inputs[PAN3_INPUT]);
- _channels[3] = new MixerChannel(params[LEVEL4_PARAM], params[PAN4_PARAM], params[MUTE4_PARAM], inputs[CV4_INPUT], inputs[PAN4_INPUT]);
+ _channels[0] = new MixerChannel(params[LEVEL1_PARAM], params[MUTE1_PARAM], inputs[CV1_INPUT]);
+ _channels[1] = new MixerChannel(params[LEVEL2_PARAM], params[MUTE2_PARAM], inputs[CV2_INPUT]);
+ _channels[2] = new MixerChannel(params[LEVEL3_PARAM], params[MUTE3_PARAM], inputs[CV3_INPUT]);
+ _channels[3] = new MixerChannel(params[LEVEL4_PARAM], params[MUTE4_PARAM], inputs[CV4_INPUT]);
sampleRateChange();
_rms.setSensitivity(0.05f);
}
@@ -94,7 +102,118 @@ struct Mix4 : BGModule {
json_t* dataToJson() override;
void dataFromJson(json_t* root) override;
void sampleRateChange() override;
- void processChannel(const ProcessArgs& args, int _c) override;
+ void processAll(const ProcessArgs& args) override;
+};
+
+struct Mix4x : ExpanderModule<Mix4ExpanderMessage, Mix4> {
+ enum ParamsIds {
+ LOW1_PARAM,
+ MID1_PARAM,
+ HIGH1_PARAM,
+ A1_PARAM,
+ PRE_A1_PARAM,
+ B1_PARAM,
+ PRE_B1_PARAM,
+ LOW2_PARAM,
+ MID2_PARAM,
+ HIGH2_PARAM,
+ A2_PARAM,
+ PRE_A2_PARAM,
+ B2_PARAM,
+ PRE_B2_PARAM,
+ LOW3_PARAM,
+ MID3_PARAM,
+ HIGH3_PARAM,
+ A3_PARAM,
+ PRE_A3_PARAM,
+ B3_PARAM,
+ PRE_B3_PARAM,
+ LOW4_PARAM,
+ MID4_PARAM,
+ HIGH4_PARAM,
+ A4_PARAM,
+ PRE_A4_PARAM,
+ B4_PARAM,
+ PRE_B4_PARAM,
+ LEVEL_A_PARAM,
+ LEVEL_B_PARAM,
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ A1_INPUT,
+ B1_INPUT,
+ A2_INPUT,
+ B2_INPUT,
+ A3_INPUT,
+ B3_INPUT,
+ A4_INPUT,
+ B4_INPUT,
+ L_A_INPUT,
+ R_A_INPUT,
+ LEVEL_A_INPUT,
+ L_B_INPUT,
+ R_B_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ SEND_A_OUTPUT,
+ SEND_B_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ MixerExpanderChannel* _channels[4] {};
+ Saturator _saturatorA, _saturatorB;
+ Amplifier _returnAAmp, _returnBAmp;
+ bogaudio::dsp::SlewLimiter _returnASL, _returnBSL;
+
+ Mix4x() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
+ configParam<EQParamQuantity>(LOW1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 low", " dB");
+ configParam<EQParamQuantity>(MID1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 mid", " dB");
+ configParam<EQParamQuantity>(HIGH1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 high", " dB");
+ configParam<AmplifierParamQuantity>(A1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 A send");
+ configParam(PRE_A1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 A send pre/post");
+ configParam<AmplifierParamQuantity>(B1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 B send");
+ configParam(PRE_B1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 B send pre/post");
+ configParam<EQParamQuantity>(LOW2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 low", " dB");
+ configParam<EQParamQuantity>(MID2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 mid", " dB");
+ configParam<EQParamQuantity>(HIGH2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 high", " dB");
+ configParam<AmplifierParamQuantity>(A2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 A send");
+ configParam(PRE_A2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 A send pre/post");
+ configParam<AmplifierParamQuantity>(B2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 B send");
+ configParam(PRE_B2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 B send pre/post");
+ configParam<EQParamQuantity>(LOW3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 low", " dB");
+ configParam<EQParamQuantity>(MID3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 mid", " dB");
+ configParam<EQParamQuantity>(HIGH3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 high", " dB");
+ configParam<AmplifierParamQuantity>(A3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 A send");
+ configParam(PRE_A3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 A send pre/post");
+ configParam<AmplifierParamQuantity>(B3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 B send");
+ configParam(PRE_B3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 B send pre/post");
+ configParam<EQParamQuantity>(LOW4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 low", " dB");
+ configParam<EQParamQuantity>(MID4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 mid", " dB");
+ configParam<EQParamQuantity>(HIGH4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 high", " dB");
+ configParam<AmplifierParamQuantity>(A4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 A send");
+ configParam(PRE_A4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 A send pre/post");
+ configParam<AmplifierParamQuantity>(B4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 B send");
+ configParam(PRE_B4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 B send pre/post");
+ configParam<AmplifierParamQuantity>(LEVEL_A_PARAM, 0.0f, 1.0f, 0.8f, "A return level");
+ configParam<AmplifierParamQuantity>(LEVEL_B_PARAM, 0.0f, 1.0f, 0.8f, "B return level");
+
+ _channels[0] = new MixerExpanderChannel(params[LOW1_PARAM], params[MID1_PARAM], params[HIGH1_PARAM], params[A1_PARAM], params[B1_PARAM], params[PRE_A1_PARAM], params[PRE_B1_PARAM], inputs[A1_INPUT], inputs[B1_INPUT]);
+ _channels[1] = new MixerExpanderChannel(params[LOW2_PARAM], params[MID2_PARAM], params[HIGH2_PARAM], params[A2_PARAM], params[B2_PARAM], params[PRE_A2_PARAM], params[PRE_B2_PARAM], inputs[A2_INPUT], inputs[B2_INPUT]);
+ _channels[2] = new MixerExpanderChannel(params[LOW3_PARAM], params[MID3_PARAM], params[HIGH3_PARAM], params[A3_PARAM], params[B3_PARAM], params[PRE_A3_PARAM], params[PRE_B3_PARAM], inputs[A3_INPUT], inputs[B3_INPUT]);
+ _channels[3] = new MixerExpanderChannel(params[LOW4_PARAM], params[MID4_PARAM], params[HIGH4_PARAM], params[A4_PARAM], params[B4_PARAM], params[PRE_A4_PARAM], params[PRE_B4_PARAM], inputs[A4_INPUT], inputs[B4_INPUT]);
+ }
+ virtual ~Mix4x() {
+ for (int i = 0; i < 4; ++i) {
+ delete _channels[i];
+ }
+ }
+
+ void sampleRateChange() override;
+ void processAll(const ProcessArgs& args) override;
};
} // namespace bogaudio
diff --git a/src/Mix8.cpp b/src/Mix8.cpp
@@ -20,13 +20,20 @@ void Mix8::sampleRateChange() {
float sr = APP->engine->getSampleRate();
for (int i = 0; i < 8; ++i) {
_channels[i]->setSampleRate(sr);
+ _panSLs[i].setParams(sr, MIXER_PAN_SLEW_MS, 2.0f);
}
_slewLimiter.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
_rms.setSampleRate(sr);
}
-void Mix8::processChannel(const ProcessArgs& args, int _c) {
- bool stereo = outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected();
+void Mix8::processAll(const ProcessArgs& args) {
+ Mix8ExpanderMessage* toExp = &_dummyExpanderMessage;
+ Mix8ExpanderMessage* fromExp = &_dummyExpanderMessage;
+ if (connected()) {
+ toExp = toExpander();
+ fromExp = fromExpander();
+ }
+
bool solo =
params[MUTE1_PARAM].getValue() > 1.5f ||
params[MUTE2_PARAM].getValue() > 1.5f ||
@@ -44,7 +51,8 @@ void Mix8::processChannel(const ProcessArgs& args, int _c) {
} else {
sample = inputs[IN1_INPUT].getVoltageSum();
}
- _channels[0]->next(sample, stereo, solo);
+ _channels[0]->next(sample, solo);
+ toExp->preFader[0] = sample;
for (int i = 1; i < 8; ++i) {
float sample = 0.0f;
@@ -54,7 +62,8 @@ void Mix8::processChannel(const ProcessArgs& args, int _c) {
else if (_polyChannelOffset >= 0) {
sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset + i);
}
- _channels[i]->next(sample, stereo, solo);
+ _channels[i]->next(sample, solo);
+ toExp->preFader[i] = sample;
}
}
@@ -69,27 +78,45 @@ void Mix8::processChannel(const ProcessArgs& args, int _c) {
}
_amplifier.setLevel(_slewLimiter.next(level));
+ float outs[8];
+ for (int i = 0; i < 8; ++i) {
+ toExp->postFader[i] = outs[i] = _channels[i]->out;
+ }
+
float mono = 0.0f;
+ float left = 0.0f;
+ float right = 0.0f;
+ if (connected()) {
+ mono += fromExp->returnA[0] + fromExp->returnB[0];
+ left += fromExp->returnA[0] + fromExp->returnB[0];
+ right += fromExp->returnA[1] + fromExp->returnB[1];
+ std::copy(fromExp->postEQ, fromExp->postEQ + 8, outs);
+ }
+
for (int i = 0; i < 8; ++i) {
- mono += _channels[i]->out;
+ mono += outs[i];
}
mono = _amplifier.next(mono);
mono = _saturator.next(mono);
_rmsLevel = _rms.next(mono) / 5.0f;
- if (stereo) {
- float left = 0.0f;
+ if (outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected()) {
for (int i = 0; i < 8; ++i) {
- left += _channels[i]->left;
+ float pan = clamp(params[PAN1_PARAM + 3 * i].getValue(), -1.0f, 1.0f);
+ if (inputs[PAN1_INPUT + 3 * i].isConnected()) {
+ pan *= clamp(inputs[PAN1_INPUT + 3 * i].getVoltage() / 5.0f, -1.0f, 1.0f);
+ }
+ _panners[i].setPan(_panSLs[i].next(pan));
+ float l, r;
+ _panners[i].next(outs[i], l, r);
+ left += l;
+ right += r;
}
+
left = _amplifier.next(left);
left = _saturator.next(left);
outputs[L_OUTPUT].setVoltage(left);
- float right = 0.0f;
- for (int i = 0; i < 8; ++i) {
- right += _channels[i]->right;
- }
right = _amplifier.next(right);
right = _saturator.next(right);
outputs[R_OUTPUT].setVoltage(right);
@@ -255,3 +282,264 @@ struct Mix8Widget : ModuleWidget {
};
Model* modelMix8 = bogaudio::createModel<Mix8, Mix8Widget>("Bogaudio-Mix8", "MIX8", "8-channel mixer and panner", "Mixer", "Panning");
+
+
+void Mix8x::sampleRateChange() {
+ float sr = APP->engine->getSampleRate();
+ for (int i = 0; i < 8; ++i) {
+ _channels[i]->setSampleRate(sr);
+ }
+ _returnASL.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+ _returnBSL.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+}
+
+void Mix8x::processAll(const ProcessArgs& args) {
+ if (!connected()) {
+ outputs[SEND_A_OUTPUT].setVoltage(0.0f);
+ outputs[SEND_B_OUTPUT].setVoltage(0.0f);
+ return;
+ }
+
+ Mix8ExpanderMessage* from = fromBase();
+ Mix8ExpanderMessage* to = toBase();
+ float sendA = 0.0f;
+ float sendB = 0.0f;
+ for (int i = 0; i < 8; ++i) {
+ _channels[i]->next(from->preFader[i], from->postFader[i]);
+ to->postEQ[i] = _channels[i]->postEQ;
+ sendA += _channels[i]->sendA;
+ sendB += _channels[i]->sendB;
+ }
+ outputs[SEND_A_OUTPUT].setVoltage(_saturatorA.next(sendA));
+ outputs[SEND_B_OUTPUT].setVoltage(_saturatorA.next(sendB));
+
+ float levelA = clamp(params[LEVEL_A_PARAM].getValue(), 0.0f, 1.0f);
+ if (inputs[LEVEL_A_INPUT].isConnected()) {
+ levelA *= clamp(inputs[LEVEL_A_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f);
+ }
+ levelA = 1.0f - levelA;
+ levelA *= Amplifier::minDecibels;
+ _returnAAmp.setLevel(_returnASL.next(levelA));
+ if (inputs[L_A_INPUT].isConnected()) {
+ to->returnA[0] = _returnAAmp.next(inputs[L_A_INPUT].getVoltage());
+ }
+ else {
+ to->returnA[0] = 0.0f;
+ }
+ if (inputs[R_A_INPUT].isConnected()) {
+ to->returnA[1] = _returnAAmp.next(inputs[R_A_INPUT].getVoltage());
+ }
+ else {
+ to->returnA[1] = to->returnA[0];
+ }
+
+ float levelB = clamp(params[LEVEL_B_PARAM].getValue(), 0.0f, 1.0f);
+ levelB = 1.0f - levelB;
+ levelB *= Amplifier::minDecibels;
+ _returnBAmp.setLevel(_returnBSL.next(levelB));
+ if (inputs[L_B_INPUT].isConnected()) {
+ to->returnB[0] = _returnBAmp.next(inputs[L_B_INPUT].getVoltage());
+ }
+ else {
+ to->returnB[0] = 0.0f;
+ }
+ if (inputs[R_B_INPUT].isConnected()) {
+ to->returnB[1] = _returnBAmp.next(inputs[R_B_INPUT].getVoltage());
+ }
+ else {
+ to->returnB[1] = to->returnB[0];
+ }
+}
+
+struct Mix8xWidget : ModuleWidget {
+ static constexpr int hp = 27;
+
+ Mix8xWidget(Mix8x* module) {
+ setModule(module);
+ box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
+
+ {
+ SvgPanel *panel = new SvgPanel();
+ panel->box.size = box.size;
+ panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Mix8x.svg")));
+ addChild(panel);
+ }
+
+ addChild(createWidget<ScrewSilver>(Vec(15, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(15, 365)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));
+
+ // generated by svg_widgets.rb
+ auto low1ParamPosition = Vec(18.5, 43.0);
+ auto mid1ParamPosition = Vec(18.5, 89.0);
+ auto high1ParamPosition = Vec(18.5, 135.0);
+ auto a1ParamPosition = Vec(18.5, 180.0);
+ auto preA1ParamPosition = Vec(30.0, 208.0);
+ auto b1ParamPosition = Vec(18.5, 236.0);
+ auto preB1ParamPosition = Vec(30.0, 264.0);
+ auto low2ParamPosition = Vec(62.5, 43.0);
+ auto mid2ParamPosition = Vec(62.5, 89.0);
+ auto high2ParamPosition = Vec(62.5, 135.0);
+ auto a2ParamPosition = Vec(62.5, 180.0);
+ auto preA2ParamPosition = Vec(74.0, 208.0);
+ auto b2ParamPosition = Vec(62.5, 236.0);
+ auto preB2ParamPosition = Vec(74.0, 264.0);
+ auto low3ParamPosition = Vec(106.5, 43.0);
+ auto mid3ParamPosition = Vec(106.5, 89.0);
+ auto high3ParamPosition = Vec(106.5, 135.0);
+ auto a3ParamPosition = Vec(106.5, 180.0);
+ auto preA3ParamPosition = Vec(118.0, 208.0);
+ auto b3ParamPosition = Vec(106.5, 236.0);
+ auto preB3ParamPosition = Vec(118.0, 264.0);
+ auto low4ParamPosition = Vec(150.5, 43.0);
+ auto mid4ParamPosition = Vec(150.5, 89.0);
+ auto high4ParamPosition = Vec(150.5, 135.0);
+ auto a4ParamPosition = Vec(150.5, 180.0);
+ auto preA4ParamPosition = Vec(162.0, 208.0);
+ auto b4ParamPosition = Vec(150.5, 236.0);
+ auto preB4ParamPosition = Vec(162.0, 264.0);
+ auto low5ParamPosition = Vec(194.5, 43.0);
+ auto mid5ParamPosition = Vec(194.5, 89.0);
+ auto high5ParamPosition = Vec(194.5, 135.0);
+ auto a5ParamPosition = Vec(194.5, 180.0);
+ auto preA5ParamPosition = Vec(206.0, 208.0);
+ auto b5ParamPosition = Vec(194.5, 236.0);
+ auto preB5ParamPosition = Vec(206.0, 264.0);
+ auto low6ParamPosition = Vec(238.5, 43.0);
+ auto mid6ParamPosition = Vec(238.5, 89.0);
+ auto high6ParamPosition = Vec(238.5, 135.0);
+ auto a6ParamPosition = Vec(238.5, 180.0);
+ auto preA6ParamPosition = Vec(250.0, 208.0);
+ auto b6ParamPosition = Vec(238.5, 236.0);
+ auto preB6ParamPosition = Vec(250.0, 264.0);
+ auto low7ParamPosition = Vec(282.5, 43.0);
+ auto mid7ParamPosition = Vec(282.5, 89.0);
+ auto high7ParamPosition = Vec(282.5, 135.0);
+ auto a7ParamPosition = Vec(282.5, 180.0);
+ auto preA7ParamPosition = Vec(294.0, 208.0);
+ auto b7ParamPosition = Vec(282.5, 236.0);
+ auto preB7ParamPosition = Vec(294.0, 264.0);
+ auto low8ParamPosition = Vec(326.5, 43.0);
+ auto mid8ParamPosition = Vec(326.5, 89.0);
+ auto high8ParamPosition = Vec(326.5, 135.0);
+ auto a8ParamPosition = Vec(326.5, 180.0);
+ auto preA8ParamPosition = Vec(338.0, 208.0);
+ auto b8ParamPosition = Vec(326.5, 236.0);
+ auto preB8ParamPosition = Vec(338.0, 264.0);
+ auto levelAParamPosition = Vec(370.5, 138.0);
+ auto levelBParamPosition = Vec(370.5, 328.0);
+
+ auto a1InputPosition = Vec(14.5, 290.0);
+ auto b1InputPosition = Vec(14.5, 325.0);
+ auto a2InputPosition = Vec(58.5, 290.0);
+ auto b2InputPosition = Vec(58.5, 325.0);
+ auto a3InputPosition = Vec(102.5, 290.0);
+ auto b3InputPosition = Vec(102.5, 325.0);
+ auto a4InputPosition = Vec(146.5, 290.0);
+ auto b4InputPosition = Vec(146.5, 325.0);
+ auto a5InputPosition = Vec(190.5, 290.0);
+ auto b5InputPosition = Vec(190.5, 325.0);
+ auto a6InputPosition = Vec(234.5, 290.0);
+ auto b6InputPosition = Vec(234.5, 325.0);
+ auto a7InputPosition = Vec(278.5, 290.0);
+ auto b7InputPosition = Vec(278.5, 325.0);
+ auto a8InputPosition = Vec(322.5, 290.0);
+ auto b8InputPosition = Vec(322.5, 325.0);
+ auto lAInputPosition = Vec(366.5, 62.0);
+ auto rAInputPosition = Vec(366.5, 97.0);
+ auto levelAInputPosition = Vec(366.5, 170.0);
+ auto lBInputPosition = Vec(366.5, 252.0);
+ auto rBInputPosition = Vec(366.5, 287.0);
+
+ auto sendAOutputPosition = Vec(366.5, 24.0);
+ auto sendBOutputPosition = Vec(366.5, 214.0);
+ // end generated by svg_widgets.rb
+
+ addParam(createParam<Knob16>(low1ParamPosition, module, Mix8x::LOW1_PARAM));
+ addParam(createParam<Knob16>(mid1ParamPosition, module, Mix8x::MID1_PARAM));
+ addParam(createParam<Knob16>(high1ParamPosition, module, Mix8x::HIGH1_PARAM));
+ addParam(createParam<Knob16>(a1ParamPosition, module, Mix8x::A1_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA1ParamPosition, module, Mix8x::PRE_A1_PARAM));
+ addParam(createParam<Knob16>(b1ParamPosition, module, Mix8x::B1_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB1ParamPosition, module, Mix8x::PRE_B1_PARAM));
+ addParam(createParam<Knob16>(low2ParamPosition, module, Mix8x::LOW2_PARAM));
+ addParam(createParam<Knob16>(mid2ParamPosition, module, Mix8x::MID2_PARAM));
+ addParam(createParam<Knob16>(high2ParamPosition, module, Mix8x::HIGH2_PARAM));
+ addParam(createParam<Knob16>(a2ParamPosition, module, Mix8x::A2_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA2ParamPosition, module, Mix8x::PRE_A2_PARAM));
+ addParam(createParam<Knob16>(b2ParamPosition, module, Mix8x::B2_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB2ParamPosition, module, Mix8x::PRE_B2_PARAM));
+ addParam(createParam<Knob16>(low3ParamPosition, module, Mix8x::LOW3_PARAM));
+ addParam(createParam<Knob16>(mid3ParamPosition, module, Mix8x::MID3_PARAM));
+ addParam(createParam<Knob16>(high3ParamPosition, module, Mix8x::HIGH3_PARAM));
+ addParam(createParam<Knob16>(a3ParamPosition, module, Mix8x::A3_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA3ParamPosition, module, Mix8x::PRE_A3_PARAM));
+ addParam(createParam<Knob16>(b3ParamPosition, module, Mix8x::B3_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB3ParamPosition, module, Mix8x::PRE_B3_PARAM));
+ addParam(createParam<Knob16>(low4ParamPosition, module, Mix8x::LOW4_PARAM));
+ addParam(createParam<Knob16>(mid4ParamPosition, module, Mix8x::MID4_PARAM));
+ addParam(createParam<Knob16>(high4ParamPosition, module, Mix8x::HIGH4_PARAM));
+ addParam(createParam<Knob16>(a4ParamPosition, module, Mix8x::A4_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA4ParamPosition, module, Mix8x::PRE_A4_PARAM));
+ addParam(createParam<Knob16>(b4ParamPosition, module, Mix8x::B4_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB4ParamPosition, module, Mix8x::PRE_B4_PARAM));
+ addParam(createParam<Knob16>(low5ParamPosition, module, Mix8x::LOW5_PARAM));
+ addParam(createParam<Knob16>(mid5ParamPosition, module, Mix8x::MID5_PARAM));
+ addParam(createParam<Knob16>(high5ParamPosition, module, Mix8x::HIGH5_PARAM));
+ addParam(createParam<Knob16>(a5ParamPosition, module, Mix8x::A5_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA5ParamPosition, module, Mix8x::PRE_A5_PARAM));
+ addParam(createParam<Knob16>(b5ParamPosition, module, Mix8x::B5_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB5ParamPosition, module, Mix8x::PRE_B5_PARAM));
+ addParam(createParam<Knob16>(low6ParamPosition, module, Mix8x::LOW6_PARAM));
+ addParam(createParam<Knob16>(mid6ParamPosition, module, Mix8x::MID6_PARAM));
+ addParam(createParam<Knob16>(high6ParamPosition, module, Mix8x::HIGH6_PARAM));
+ addParam(createParam<Knob16>(a6ParamPosition, module, Mix8x::A6_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA6ParamPosition, module, Mix8x::PRE_A6_PARAM));
+ addParam(createParam<Knob16>(b6ParamPosition, module, Mix8x::B6_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB6ParamPosition, module, Mix8x::PRE_B6_PARAM));
+ addParam(createParam<Knob16>(low7ParamPosition, module, Mix8x::LOW7_PARAM));
+ addParam(createParam<Knob16>(mid7ParamPosition, module, Mix8x::MID7_PARAM));
+ addParam(createParam<Knob16>(high7ParamPosition, module, Mix8x::HIGH7_PARAM));
+ addParam(createParam<Knob16>(a7ParamPosition, module, Mix8x::A7_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA7ParamPosition, module, Mix8x::PRE_A7_PARAM));
+ addParam(createParam<Knob16>(b7ParamPosition, module, Mix8x::B7_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB7ParamPosition, module, Mix8x::PRE_B7_PARAM));
+ addParam(createParam<Knob16>(low8ParamPosition, module, Mix8x::LOW8_PARAM));
+ addParam(createParam<Knob16>(mid8ParamPosition, module, Mix8x::MID8_PARAM));
+ addParam(createParam<Knob16>(high8ParamPosition, module, Mix8x::HIGH8_PARAM));
+ addParam(createParam<Knob16>(a8ParamPosition, module, Mix8x::A8_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preA8ParamPosition, module, Mix8x::PRE_A8_PARAM));
+ addParam(createParam<Knob16>(b8ParamPosition, module, Mix8x::B8_PARAM));
+ addParam(createParam<IndicatorButtonGreen9>(preB8ParamPosition, module, Mix8x::PRE_B8_PARAM));
+ addParam(createParam<Knob16>(levelAParamPosition, module, Mix8x::LEVEL_A_PARAM));
+ addParam(createParam<Knob16>(levelBParamPosition, module, Mix8x::LEVEL_B_PARAM));
+
+ addInput(createInput<Port24>(a1InputPosition, module, Mix8x::A1_INPUT));
+ addInput(createInput<Port24>(b1InputPosition, module, Mix8x::B1_INPUT));
+ addInput(createInput<Port24>(a2InputPosition, module, Mix8x::A2_INPUT));
+ addInput(createInput<Port24>(b2InputPosition, module, Mix8x::B2_INPUT));
+ addInput(createInput<Port24>(a3InputPosition, module, Mix8x::A3_INPUT));
+ addInput(createInput<Port24>(b3InputPosition, module, Mix8x::B3_INPUT));
+ addInput(createInput<Port24>(a4InputPosition, module, Mix8x::A4_INPUT));
+ addInput(createInput<Port24>(b4InputPosition, module, Mix8x::B4_INPUT));
+ addInput(createInput<Port24>(a5InputPosition, module, Mix8x::A5_INPUT));
+ addInput(createInput<Port24>(b5InputPosition, module, Mix8x::B5_INPUT));
+ addInput(createInput<Port24>(a6InputPosition, module, Mix8x::A6_INPUT));
+ addInput(createInput<Port24>(b6InputPosition, module, Mix8x::B6_INPUT));
+ addInput(createInput<Port24>(a7InputPosition, module, Mix8x::A7_INPUT));
+ addInput(createInput<Port24>(b7InputPosition, module, Mix8x::B7_INPUT));
+ addInput(createInput<Port24>(a8InputPosition, module, Mix8x::A8_INPUT));
+ addInput(createInput<Port24>(b8InputPosition, module, Mix8x::B8_INPUT));
+ addInput(createInput<Port24>(lAInputPosition, module, Mix8x::L_A_INPUT));
+ addInput(createInput<Port24>(rAInputPosition, module, Mix8x::R_A_INPUT));
+ addInput(createInput<Port24>(levelAInputPosition, module, Mix8x::LEVEL_A_INPUT));
+ addInput(createInput<Port24>(lBInputPosition, module, Mix8x::L_B_INPUT));
+ addInput(createInput<Port24>(rBInputPosition, module, Mix8x::R_B_INPUT));
+
+ addOutput(createOutput<Port24>(sendAOutputPosition, module, Mix8x::SEND_A_OUTPUT));
+ addOutput(createOutput<Port24>(sendBOutputPosition, module, Mix8x::SEND_B_OUTPUT));
+ }
+};
+
+Model* modelMix8x = createModel<Mix8x, Mix8xWidget>("Bogaudio-Mix8x", "MIX8X", "Expander for MIX8, adds EQs and sends", "Mixer", "Expander");
diff --git a/src/Mix8.hpp b/src/Mix8.hpp
@@ -7,10 +7,15 @@
using namespace bogaudio::dsp;
extern Model* modelMix8;
+extern Model* modelMix8x;
namespace bogaudio {
-struct Mix8 : BGModule {
+struct Mix8x;
+
+typedef MixerExpanderMessage<8> Mix8ExpanderMessage;
+
+struct Mix8 : ExpandableModule<Mix8ExpanderMessage, Mix8x> {
enum ParamsIds {
LEVEL1_PARAM,
MUTE1_PARAM,
@@ -78,11 +83,14 @@ struct Mix8 : BGModule {
int _polyChannelOffset = -1;
MixerChannel* _channels[8] {};
+ Panner _panners[8];
+ bogaudio::dsp::SlewLimiter _panSLs[8];
Amplifier _amplifier;
bogaudio::dsp::SlewLimiter _slewLimiter;
Saturator _saturator;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
+ Mix8ExpanderMessage _dummyExpanderMessage;
Mix8() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
@@ -114,14 +122,14 @@ struct Mix8 : BGModule {
configParam(MIX_PARAM, 0.0f, 1.0f, levelDefault, "Master level", " dB", 0.0f, MixerChannel::maxDecibels - MixerChannel::minDecibels, MixerChannel::minDecibels);
configParam(MIX_MUTE_PARAM, 0.0f, 1.0f, 0.0f, "Master mute");
- _channels[0] = new MixerChannel(params[LEVEL1_PARAM], params[PAN1_PARAM], params[MUTE1_PARAM], inputs[CV1_INPUT], inputs[PAN1_INPUT]);
- _channels[1] = new MixerChannel(params[LEVEL2_PARAM], params[PAN2_PARAM], params[MUTE2_PARAM], inputs[CV2_INPUT], inputs[PAN2_INPUT]);
- _channels[2] = new MixerChannel(params[LEVEL3_PARAM], params[PAN3_PARAM], params[MUTE3_PARAM], inputs[CV3_INPUT], inputs[PAN3_INPUT]);
- _channels[3] = new MixerChannel(params[LEVEL4_PARAM], params[PAN4_PARAM], params[MUTE4_PARAM], inputs[CV4_INPUT], inputs[PAN4_INPUT]);
- _channels[4] = new MixerChannel(params[LEVEL5_PARAM], params[PAN5_PARAM], params[MUTE5_PARAM], inputs[CV5_INPUT], inputs[PAN5_INPUT]);
- _channels[5] = new MixerChannel(params[LEVEL6_PARAM], params[PAN6_PARAM], params[MUTE6_PARAM], inputs[CV6_INPUT], inputs[PAN6_INPUT]);
- _channels[6] = new MixerChannel(params[LEVEL7_PARAM], params[PAN7_PARAM], params[MUTE7_PARAM], inputs[CV7_INPUT], inputs[PAN7_INPUT]);
- _channels[7] = new MixerChannel(params[LEVEL8_PARAM], params[PAN8_PARAM], params[MUTE8_PARAM], inputs[CV8_INPUT], inputs[PAN8_INPUT]);
+ _channels[0] = new MixerChannel(params[LEVEL1_PARAM], params[MUTE1_PARAM], inputs[CV1_INPUT]);
+ _channels[1] = new MixerChannel(params[LEVEL2_PARAM], params[MUTE2_PARAM], inputs[CV2_INPUT]);
+ _channels[2] = new MixerChannel(params[LEVEL3_PARAM], params[MUTE3_PARAM], inputs[CV3_INPUT]);
+ _channels[3] = new MixerChannel(params[LEVEL4_PARAM], params[MUTE4_PARAM], inputs[CV4_INPUT]);
+ _channels[4] = new MixerChannel(params[LEVEL5_PARAM], params[MUTE5_PARAM], inputs[CV5_INPUT]);
+ _channels[5] = new MixerChannel(params[LEVEL6_PARAM], params[MUTE6_PARAM], inputs[CV6_INPUT]);
+ _channels[6] = new MixerChannel(params[LEVEL7_PARAM], params[MUTE7_PARAM], inputs[CV7_INPUT]);
+ _channels[7] = new MixerChannel(params[LEVEL8_PARAM], params[MUTE8_PARAM], inputs[CV8_INPUT]);
sampleRateChange();
_rms.setSensitivity(0.05f);
}
@@ -134,7 +142,186 @@ struct Mix8 : BGModule {
json_t* dataToJson() override;
void dataFromJson(json_t* root) override;
void sampleRateChange() override;
- void processChannel(const ProcessArgs& args, int _c) override;
+ void processAll(const ProcessArgs& args) override;
+};
+
+struct Mix8x : ExpanderModule<Mix8ExpanderMessage, Mix8> {
+ enum ParamsIds {
+ LOW1_PARAM,
+ MID1_PARAM,
+ HIGH1_PARAM,
+ A1_PARAM,
+ PRE_A1_PARAM,
+ B1_PARAM,
+ PRE_B1_PARAM,
+ LOW2_PARAM,
+ MID2_PARAM,
+ HIGH2_PARAM,
+ A2_PARAM,
+ PRE_A2_PARAM,
+ B2_PARAM,
+ PRE_B2_PARAM,
+ LOW3_PARAM,
+ MID3_PARAM,
+ HIGH3_PARAM,
+ A3_PARAM,
+ PRE_A3_PARAM,
+ B3_PARAM,
+ PRE_B3_PARAM,
+ LOW4_PARAM,
+ MID4_PARAM,
+ HIGH4_PARAM,
+ A4_PARAM,
+ PRE_A4_PARAM,
+ B4_PARAM,
+ PRE_B4_PARAM,
+ LOW5_PARAM,
+ MID5_PARAM,
+ HIGH5_PARAM,
+ A5_PARAM,
+ PRE_A5_PARAM,
+ B5_PARAM,
+ PRE_B5_PARAM,
+ LOW6_PARAM,
+ MID6_PARAM,
+ HIGH6_PARAM,
+ A6_PARAM,
+ PRE_A6_PARAM,
+ B6_PARAM,
+ PRE_B6_PARAM,
+ LOW7_PARAM,
+ MID7_PARAM,
+ HIGH7_PARAM,
+ A7_PARAM,
+ PRE_A7_PARAM,
+ B7_PARAM,
+ PRE_B7_PARAM,
+ LOW8_PARAM,
+ MID8_PARAM,
+ HIGH8_PARAM,
+ A8_PARAM,
+ PRE_A8_PARAM,
+ B8_PARAM,
+ PRE_B8_PARAM,
+ LEVEL_A_PARAM,
+ LEVEL_B_PARAM,
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ A1_INPUT,
+ B1_INPUT,
+ A2_INPUT,
+ B2_INPUT,
+ A3_INPUT,
+ B3_INPUT,
+ A4_INPUT,
+ B4_INPUT,
+ A5_INPUT,
+ B5_INPUT,
+ A6_INPUT,
+ B6_INPUT,
+ A7_INPUT,
+ B7_INPUT,
+ A8_INPUT,
+ B8_INPUT,
+ L_A_INPUT,
+ R_A_INPUT,
+ LEVEL_A_INPUT,
+ L_B_INPUT,
+ R_B_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ SEND_A_OUTPUT,
+ SEND_B_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ MixerExpanderChannel* _channels[8] {};
+ Saturator _saturatorA, _saturatorB;
+ Amplifier _returnAAmp, _returnBAmp;
+ bogaudio::dsp::SlewLimiter _returnASL, _returnBSL;
+
+ Mix8x() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
+ configParam<EQParamQuantity>(LOW1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 low", " dB");
+ configParam<EQParamQuantity>(MID1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 mid", " dB");
+ configParam<EQParamQuantity>(HIGH1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 high", " dB");
+ configParam<AmplifierParamQuantity>(A1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 A send");
+ configParam(PRE_A1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 A send pre/post");
+ configParam<AmplifierParamQuantity>(B1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 B send");
+ configParam(PRE_B1_PARAM, 0.0f, 1.0f, 0.0f, "Channel 1 B send pre/post");
+ configParam<EQParamQuantity>(LOW2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 low", " dB");
+ configParam<EQParamQuantity>(MID2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 mid", " dB");
+ configParam<EQParamQuantity>(HIGH2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 high", " dB");
+ configParam<AmplifierParamQuantity>(A2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 A send");
+ configParam(PRE_A2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 A send pre/post");
+ configParam<AmplifierParamQuantity>(B2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 B send");
+ configParam(PRE_B2_PARAM, 0.0f, 1.0f, 0.0f, "Channel 2 B send pre/post");
+ configParam<EQParamQuantity>(LOW3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 low", " dB");
+ configParam<EQParamQuantity>(MID3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 mid", " dB");
+ configParam<EQParamQuantity>(HIGH3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 high", " dB");
+ configParam<AmplifierParamQuantity>(A3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 A send");
+ configParam(PRE_A3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 A send pre/post");
+ configParam<AmplifierParamQuantity>(B3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 B send");
+ configParam(PRE_B3_PARAM, 0.0f, 1.0f, 0.0f, "Channel 3 B send pre/post");
+ configParam<EQParamQuantity>(LOW4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 low", " dB");
+ configParam<EQParamQuantity>(MID4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 mid", " dB");
+ configParam<EQParamQuantity>(HIGH4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 high", " dB");
+ configParam<AmplifierParamQuantity>(A4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 A send");
+ configParam(PRE_A4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 A send pre/post");
+ configParam<AmplifierParamQuantity>(B4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 B send");
+ configParam(PRE_B4_PARAM, 0.0f, 1.0f, 0.0f, "Channel 4 B send pre/post");
+ configParam<EQParamQuantity>(LOW5_PARAM, -1.0f, 1.0f, 0.0f, "Channel 5 low", " dB");
+ configParam<EQParamQuantity>(MID5_PARAM, -1.0f, 1.0f, 0.0f, "Channel 5 mid", " dB");
+ configParam<EQParamQuantity>(HIGH5_PARAM, -1.0f, 1.0f, 0.0f, "Channel 5 high", " dB");
+ configParam<AmplifierParamQuantity>(A5_PARAM, 0.0f, 1.0f, 0.0f, "Channel 5 A send");
+ configParam(PRE_A5_PARAM, 0.0f, 1.0f, 0.0f, "Channel 5 A send pre/post");
+ configParam<AmplifierParamQuantity>(B5_PARAM, 0.0f, 1.0f, 0.0f, "Channel 5 B send");
+ configParam(PRE_B5_PARAM, 0.0f, 1.0f, 0.0f, "Channel 5 B send pre/post");
+ configParam<EQParamQuantity>(LOW6_PARAM, -1.0f, 1.0f, 0.0f, "Channel 6 low", " dB");
+ configParam<EQParamQuantity>(MID6_PARAM, -1.0f, 1.0f, 0.0f, "Channel 6 mid", " dB");
+ configParam<EQParamQuantity>(HIGH6_PARAM, -1.0f, 1.0f, 0.0f, "Channel 6 high", " dB");
+ configParam<AmplifierParamQuantity>(A6_PARAM, 0.0f, 1.0f, 0.0f, "Channel 6 A send");
+ configParam(PRE_A6_PARAM, 0.0f, 1.0f, 0.0f, "Channel 6 A send pre/post");
+ configParam<AmplifierParamQuantity>(B6_PARAM, 0.0f, 1.0f, 0.0f, "Channel 6 B send");
+ configParam(PRE_B6_PARAM, 0.0f, 1.0f, 0.0f, "Channel 6 B send pre/post");
+ configParam<EQParamQuantity>(LOW7_PARAM, -1.0f, 1.0f, 0.0f, "Channel 7 low", " dB");
+ configParam<EQParamQuantity>(MID7_PARAM, -1.0f, 1.0f, 0.0f, "Channel 7 mid", " dB");
+ configParam<EQParamQuantity>(HIGH7_PARAM, -1.0f, 1.0f, 0.0f, "Channel 7 high", " dB");
+ configParam<AmplifierParamQuantity>(A7_PARAM, 0.0f, 1.0f, 0.0f, "Channel 7 A send");
+ configParam(PRE_A7_PARAM, 0.0f, 1.0f, 0.0f, "Channel 7 A send pre/post");
+ configParam<AmplifierParamQuantity>(B7_PARAM, 0.0f, 1.0f, 0.0f, "Channel 7 B send");
+ configParam(PRE_B7_PARAM, 0.0f, 1.0f, 0.0f, "Channel 7 B send pre/post");
+ configParam<EQParamQuantity>(LOW8_PARAM, -1.0f, 1.0f, 0.0f, "Channel 8 low", " dB");
+ configParam<EQParamQuantity>(MID8_PARAM, -1.0f, 1.0f, 0.0f, "Channel 8 mid", " dB");
+ configParam<EQParamQuantity>(HIGH8_PARAM, -1.0f, 1.0f, 0.0f, "Channel 8 high", " dB");
+ configParam<AmplifierParamQuantity>(A8_PARAM, 0.0f, 1.0f, 0.0f, "Channel 8 A send");
+ configParam(PRE_A8_PARAM, 0.0f, 1.0f, 0.0f, "Channel 8 A send pre/post");
+ configParam<AmplifierParamQuantity>(B8_PARAM, 0.0f, 1.0f, 0.0f, "Channel 8 B send");
+ configParam(PRE_B8_PARAM, 0.0f, 1.0f, 0.0f, "Channel 8 B send pre/post");
+ configParam<AmplifierParamQuantity>(LEVEL_A_PARAM, 0.0f, 1.0f, 0.8f, "A return level");
+ configParam<AmplifierParamQuantity>(LEVEL_B_PARAM, 0.0f, 1.0f, 0.8f, "B return level");
+
+ _channels[0] = new MixerExpanderChannel(params[LOW1_PARAM], params[MID1_PARAM], params[HIGH1_PARAM], params[A1_PARAM], params[B1_PARAM], params[PRE_A1_PARAM], params[PRE_B1_PARAM], inputs[A1_INPUT], inputs[B1_INPUT]);
+ _channels[1] = new MixerExpanderChannel(params[LOW2_PARAM], params[MID2_PARAM], params[HIGH2_PARAM], params[A2_PARAM], params[B2_PARAM], params[PRE_A2_PARAM], params[PRE_B2_PARAM], inputs[A2_INPUT], inputs[B2_INPUT]);
+ _channels[2] = new MixerExpanderChannel(params[LOW3_PARAM], params[MID3_PARAM], params[HIGH3_PARAM], params[A3_PARAM], params[B3_PARAM], params[PRE_A3_PARAM], params[PRE_B3_PARAM], inputs[A3_INPUT], inputs[B3_INPUT]);
+ _channels[3] = new MixerExpanderChannel(params[LOW4_PARAM], params[MID4_PARAM], params[HIGH4_PARAM], params[A4_PARAM], params[B4_PARAM], params[PRE_A4_PARAM], params[PRE_B4_PARAM], inputs[A4_INPUT], inputs[B4_INPUT]);
+ _channels[4] = new MixerExpanderChannel(params[LOW5_PARAM], params[MID5_PARAM], params[HIGH5_PARAM], params[A5_PARAM], params[B5_PARAM], params[PRE_A5_PARAM], params[PRE_B5_PARAM], inputs[A5_INPUT], inputs[B5_INPUT]);
+ _channels[5] = new MixerExpanderChannel(params[LOW6_PARAM], params[MID6_PARAM], params[HIGH6_PARAM], params[A6_PARAM], params[B6_PARAM], params[PRE_A6_PARAM], params[PRE_B6_PARAM], inputs[A6_INPUT], inputs[B6_INPUT]);
+ _channels[6] = new MixerExpanderChannel(params[LOW7_PARAM], params[MID7_PARAM], params[HIGH7_PARAM], params[A7_PARAM], params[B7_PARAM], params[PRE_A7_PARAM], params[PRE_B7_PARAM], inputs[A7_INPUT], inputs[B7_INPUT]);
+ _channels[7] = new MixerExpanderChannel(params[LOW8_PARAM], params[MID8_PARAM], params[HIGH8_PARAM], params[A8_PARAM], params[B8_PARAM], params[PRE_A8_PARAM], params[PRE_B8_PARAM], inputs[A8_INPUT], inputs[B8_INPUT]);
+ }
+ virtual ~Mix8x() {
+ for (int i = 0; i < 8; ++i) {
+ delete _channels[i];
+ }
+ }
+
+ void sampleRateChange() override;
+ void processAll(const ProcessArgs& args) override;
};
} // namespace bogaudio
diff --git a/src/Mono.hpp b/src/Mono.hpp
@@ -42,7 +42,7 @@ struct Mono : BGModule {
Mono() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
configParam(COMPRESSION_PARAM, 0.0f, 1.0f, 0.2f, "Compression", "", 0.0f, 10.0f);
- configParam<AmpliferParamQuantity>(LEVEL_PARAM, 0.0f, 1.0f, 1.0f, "Output level");
+ configParam<AmplifierParamQuantity>(LEVEL_PARAM, 0.0f, 1.0f, 1.0f, "Output level");
}
void sampleRateChange() override;
diff --git a/src/Pan.cpp b/src/Pan.cpp
@@ -3,9 +3,10 @@
#include "mixer.hpp"
void Pan::sampleRateChange() {
+ float sr = APP->engine->getSampleRate();
for (int c = 0; c < maxChannels; ++c) {
- _slew1[c].setParams(APP->engine->getSampleRate(), MixerChannel::panSlewTimeMS, 2.0f);
- _slew2[c].setParams(APP->engine->getSampleRate(), MixerChannel::panSlewTimeMS, 2.0f);
+ _slew1[c].setParams(sr, MIXER_PAN_SLEW_MS, 2.0f);
+ _slew2[c].setParams(sr, MIXER_PAN_SLEW_MS, 2.0f);
}
}
diff --git a/src/TestExpander.hpp b/src/TestExpander.hpp
@@ -8,8 +8,7 @@ extern Model* modelTestExpanderExtension;
namespace bogaudio {
-struct TestExpanderMessage : MessageBase {
- int channels = 0;
+struct TestExpanderMessage : ExpanderMessage {
float sample[BGModule::maxChannels] {};
};
diff --git a/src/VCA.hpp b/src/VCA.hpp
@@ -36,7 +36,7 @@ struct VCA : BGModule {
Amplifier _amplifier2[maxChannels];
bogaudio::dsp::SlewLimiter _levelSL2[maxChannels];
- struct LevelParamQuantity : AmpliferParamQuantity {
+ struct LevelParamQuantity : AmplifierParamQuantity {
bool isLinear() override;
};
diff --git a/src/VCM.hpp b/src/VCM.hpp
@@ -44,7 +44,7 @@ struct VCM : DisableOutputLimitModule {
Amplifier _amplifier3[maxChannels];
Amplifier _amplifier4[maxChannels];
- struct LevelParamQuantity : AmpliferParamQuantity {
+ struct LevelParamQuantity : AmplifierParamQuantity {
bool isLinear() override;
};
diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp
@@ -126,7 +126,9 @@ void init(rack::Plugin *p) {
p->addModel(modelWalk);
p->addModel(modelMix8);
+ p->addModel(modelMix8x);
p->addModel(modelMix4);
+ p->addModel(modelMix4x);
p->addModel(modelMix1);
p->addModel(modelVCM);
p->addModel(modelMute8);
diff --git a/src/expanders.hpp b/src/expanders.hpp
@@ -9,10 +9,10 @@ using namespace rack;
namespace bogaudio {
-struct MessageBase {
+struct ExpanderMessage {
int channels = 0;
- virtual ~MessageBase() {}
+ virtual ~ExpanderMessage() {}
};
template<class MSG, class EM>
@@ -20,7 +20,7 @@ struct ExpandableModule : BGModule {
MSG _messages[2] {};
ExpandableModule() {
- static_assert(std::is_base_of<MessageBase, MSG>::value, "type parameter MSG must derive from MessageBase");
+ static_assert(std::is_base_of<ExpanderMessage, MSG>::value, "type parameter MSG must derive from ExpanderMessage");
rightExpander.producerMessage = &_messages[0];
rightExpander.consumerMessage = &_messages[1];
@@ -59,7 +59,7 @@ struct ExpanderModule : BGModule {
MSG _messages[2] {};
ExpanderModule() {
- static_assert(std::is_base_of<MessageBase, MSG>::value, "type parameter MSG must derive from MessageBase");
+ static_assert(std::is_base_of<ExpanderMessage, MSG>::value, "type parameter MSG must derive from ExpanderMessage");
leftExpander.producerMessage = &_messages[0];
leftExpander.consumerMessage = &_messages[1];
diff --git a/src/mixer.cpp b/src/mixer.cpp
@@ -4,15 +4,13 @@
const float MixerChannel::maxDecibels = 6.0f;
const float MixerChannel::minDecibels = Amplifier::minDecibels;
const float MixerChannel::levelSlewTimeMS = 5.0f;
-const float MixerChannel::panSlewTimeMS = 10.0f;
void MixerChannel::setSampleRate(float sampleRate) {
_levelSL.setParams(sampleRate, levelSlewTimeMS, maxDecibels - minDecibels);
- _panSL.setParams(sampleRate, panSlewTimeMS, 2.0f);
_rms.setSampleRate(sampleRate);
}
-void MixerChannel::next(float sample, bool stereo, bool solo, int c) {
+void MixerChannel::next(float sample, bool solo, int c) {
float mute = _muteParam.getValue();
if (_muteInput) {
mute += clamp(_muteInput->getPolyVoltage(c), 0.0f, 10.0f);
@@ -31,16 +29,50 @@ void MixerChannel::next(float sample, bool stereo, bool solo, int c) {
_amplifier.setLevel(_levelSL.next(level));
}
- left = right = out = _amplifier.next(sample);
+ out = _amplifier.next(sample);
rms = _rms.next(out / 5.0f);
- if (stereo) {
- float pan = clamp(_panParam.getValue(), -1.0f, 1.0f);
- if (_panInput.isConnected()) {
- pan *= clamp(_panInput.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
- }
- _panner.setPan(_panSL.next(pan));
- _panner.next(out, left, right);
+}
+
+
+void MixerExpanderChannel::setSampleRate(float sampleRate) {
+ _sendASL.setParams(sampleRate, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+ _sendBSL.setParams(sampleRate, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels);
+}
+
+float MixerExpanderChannel::knobToDb(Param& p) {
+ float v = clamp(p.getValue(), -1.0f, 1.0f);
+ if (v < 0.0f) {
+ return -v * Equalizer::cutDb;
+ }
+ return v * Equalizer::gainDb;
+}
+
+void MixerExpanderChannel::next(float preFader, float postFader) {
+ _eq.setParams(
+ APP->engine->getSampleRate(),
+ knobToDb(_lowParam),
+ knobToDb(_midParam),
+ knobToDb(_highParam)
+ );
+ postEQ = _eq.next(postFader);
+
+ float level = clamp(_sendAParam.getValue(), 0.0f, 1.0f);
+ if (_sendAInput.isConnected()) {
+ level *= clamp(_sendAInput.getVoltage() / 10.0f, 0.0f, 1.0f);
+ }
+ level = 1.0f - level;
+ level *= Amplifier::minDecibels;
+ _sendAAmp.setLevel(_sendASL.next(level));
+ sendA = _sendAAmp.next(_preAParam.getValue() > 0.5f ? preFader : postEQ);
+
+ level = clamp(_sendBParam.getValue(), 0.0f, 1.0f);
+ if (_sendBInput.isConnected()) {
+ level *= clamp(_sendBInput.getVoltage() / 10.0f, 0.0f, 1.0f);
}
+ level = 1.0f - level;
+ level *= Amplifier::minDecibels;
+ _sendBAmp.setLevel(_sendBSL.next(level));
+ sendB = _sendBAmp.next(_preBParam.getValue() > 0.5f ? preFader : postEQ);
}
diff --git a/src/mixer.hpp b/src/mixer.hpp
@@ -1,50 +1,52 @@
#pragma once
#include "bogaudio.hpp"
+#include "expanders.hpp"
+#include "dsp/filter.hpp"
#include "dsp/signal.hpp"
using namespace bogaudio::dsp;
namespace bogaudio {
+#define MIXER_PAN_SLEW_MS 10.0f
+
+template<int N>
+struct MixerExpanderMessage : ExpanderMessage {
+ float preFader[N] {};
+ float postFader[N] {};
+ float postEQ[N] {};
+ float returnA[2] {};
+ float returnB[2] {};
+};
+
struct MixerChannel {
static const float maxDecibels;
static const float minDecibels;
static const float levelSlewTimeMS;
- static const float panSlewTimeMS;
Amplifier _amplifier;
- Panner _panner;
bogaudio::dsp::SlewLimiter _levelSL;
- bogaudio::dsp::SlewLimiter _panSL;
RootMeanSquare _rms;
Param& _levelParam;
- Param& _panParam;
Param& _muteParam;
Input& _levelInput;
- Input& _panInput;
Input* _muteInput;
float out = 0.0f;
- float left = 0.0f;
- float right = 0.0f;
float rms = 0.0f;
MixerChannel(
Param& level,
- Param& pan,
Param& mute,
Input& levelCv,
- Input& panCv,
float sampleRate = 1000.0f,
Input* muteCv = NULL
)
: _levelParam(level)
- , _panParam(pan)
, _muteParam(mute)
, _levelInput(levelCv)
- , _panInput(panCv)
, _muteInput(muteCv)
{
setSampleRate(sampleRate);
@@ -52,7 +54,58 @@ struct MixerChannel {
}
void setSampleRate(float sampleRate);
- void next(float sample, bool stereo, bool solo, int c = 0); // outputs on out, left, right, rms.
+ void next(float sample, bool solo, int c = 0); // outputs on members out, rms.
+};
+
+struct MixerExpanderChannel {
+ Equalizer _eq;
+ Amplifier _sendAAmp;
+ Amplifier _sendBAmp;
+ bogaudio::dsp::SlewLimiter _sendASL;
+ bogaudio::dsp::SlewLimiter _sendBSL;
+
+ Param& _lowParam;
+ Param& _midParam;
+ Param& _highParam;
+ Param& _sendAParam;
+ Param& _sendBParam;
+ Param& _preAParam;
+ Param& _preBParam;
+ Input& _sendAInput;
+ Input& _sendBInput;
+
+ float postEQ = 0.0f;
+ float sendA = 0.0f;
+ float sendB = 0.0f;
+
+ MixerExpanderChannel(
+ Param& low,
+ Param& mid,
+ Param& high,
+ Param& sendA,
+ Param& sendB,
+ Param& preA,
+ Param& preB,
+ Input& cvA,
+ Input& cvB,
+ float sampleRate = 1000.0f
+ )
+ : _lowParam(low)
+ , _midParam(mid)
+ , _highParam(high)
+ , _sendAParam(sendA)
+ , _sendBParam(sendB)
+ , _preAParam(preA)
+ , _preBParam(preB)
+ , _sendAInput(cvA)
+ , _sendBInput(cvB)
+ {
+ setSampleRate(sampleRate);
+ }
+
+ void setSampleRate(float sampleRate);
+ float knobToDb(Param& p);
+ void next(float preFader, float postFader); // outputs on members postEQ, sendA, sendB
};
struct MuteButton : ToggleButton {
diff --git a/src/param_quantities.cpp b/src/param_quantities.cpp
@@ -6,11 +6,11 @@
using namespace bogaudio;
using namespace bogaudio::dsp;
-bool AmpliferParamQuantity::isLinear() {
+bool AmplifierParamQuantity::isLinear() {
return false;
}
-void AmpliferParamQuantity::setUnits(bool linear) {
+void AmplifierParamQuantity::setUnits(bool linear) {
if (linear) {
unit = "";
}
@@ -19,7 +19,7 @@ void AmpliferParamQuantity::setUnits(bool linear) {
}
}
-float AmpliferParamQuantity::getDisplayValue() {
+float AmplifierParamQuantity::getDisplayValue() {
float v = getValue();
if (!module) {
return v;
@@ -36,7 +36,7 @@ float AmpliferParamQuantity::getDisplayValue() {
return v;
}
-void AmpliferParamQuantity::setDisplayValue(float displayValue) {
+void AmplifierParamQuantity::setDisplayValue(float displayValue) {
if (!module) {
return;
}
diff --git a/src/param_quantities.hpp b/src/param_quantities.hpp
@@ -45,7 +45,7 @@ typedef ScaledSquaringParamQuantity<10> TenXSquaringParamQuantity;
typedef TenXSquaringParamQuantity EnvelopeSegmentParamQuantity;
-struct AmpliferParamQuantity : ParamQuantity {
+struct AmplifierParamQuantity : ParamQuantity {
virtual bool isLinear();
virtual void setUnits(bool linear);
float getDisplayValue() override;