BogaudioModules

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

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:
Mplugin.json | 18++++++++++++++++++
Ares-src/Mix4x-src.svg | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares-src/Mix8x-src.svg | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares/Mix4x.svg | 0
Ares/Mix8x.svg | 0
Msrc/FFB.hpp | 28++++++++++++++--------------
Msrc/FMOp.hpp | 2+-
Msrc/Mix1.cpp | 4+---
Msrc/Mix4.cpp | 240+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/Mix4.hpp | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/Mix8.cpp | 312++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/Mix8.hpp | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/Mono.hpp | 2+-
Msrc/Pan.cpp | 5+++--
Msrc/TestExpander.hpp | 3+--
Msrc/VCA.hpp | 2+-
Msrc/VCM.hpp | 2+-
Msrc/bogaudio.cpp | 2++
Msrc/expanders.hpp | 8++++----
Msrc/mixer.cpp | 54+++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/mixer.hpp | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/param_quantities.cpp | 8++++----
Msrc/param_quantities.hpp | 2+-
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;