commit e3c0ca241d78414132927c5a4f574f18185edbc3
parent 833e283eb76eca7c9a33a4aa798ce10be168bdf1
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 15 Apr 2020 22:17:15 -0400
POLYOFF8/16: polyphonic offset/scale. #106
Diffstat:
13 files changed, 1334 insertions(+), 6 deletions(-)
diff --git a/plugin.json b/plugin.json
@@ -623,8 +623,8 @@
]
},
{
- "slug": "Bogaudio-PolyCon",
- "name": "POLYCON16",
+ "slug": "Bogaudio-PolyCon8",
+ "name": "POLYCON8",
"description": "Polyphonic per-channel constant voltages",
"tags": [
"Utility",
@@ -632,8 +632,8 @@
]
},
{
- "slug": "Bogaudio-PolyCon8",
- "name": "POLYCON8",
+ "slug": "Bogaudio-PolyCon",
+ "name": "POLYCON16",
"description": "Polyphonic per-channel constant voltages",
"tags": [
"Utility",
@@ -641,6 +641,22 @@
]
},
{
+ "slug": "Bogaudio-PolyOff8",
+ "name": "POLYOFF8",
+ "description": "Polyphonic per-channel offset and scale",
+ "tags": [
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Bogaudio-PolyOff16",
+ "name": "POLYOFF16",
+ "description": "Polyphonic per-channel offset and scale",
+ "tags": [
+ "Polyphonic"
+ ]
+ },
+ {
"slug": "Bogaudio-PolyMult",
"name": "POLYMULT",
"description": "Mono-to-poly multiple",
diff --git a/res-src/PolyOff16-src.svg b/res-src/PolyOff16-src.svg
@@ -0,0 +1,282 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="240"
+ height="380"
+ viewBox="0 0 240 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-channels" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <text font-size="5pt" transform="rotate(-240) translate(14 0) rotate(240) translate(-2 2)">1</text>
+ <text font-size="5pt" transform="rotate(-180) translate(14 0) rotate(180) translate(-2 2)">4</text>
+ <text font-size="5pt" transform="rotate(-100) translate(14 0) rotate(100) translate(-2 2)">8</text>
+ <text font-size="5pt" transform="rotate(-20) translate(13 0) rotate(20) translate(-2 2)">12</text>
+ <text font-size="5pt" transform="rotate(60) translate(13 0) rotate(-60) translate(-1.8 3)">16</text>
+
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-220) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-200) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-160) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-140) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-120) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-80) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-60) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-40) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(0) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(20) translate(10 0)" />
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(40) translate(10 0)" />
+ </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="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="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 239,1 239,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 239.5,0.5 239.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 240,0 240,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(180 0)" /> -->
+ <!-- <rect width="80" height="20" fill="#0f0" transform="translate(0 360)" /> -->
+ <!-- <rect width="80" height="20" fill="#0f0" transform="translate(160 360)" /> -->
+
+ <text class="title" x="57" y="19" font-size="12pt" letter-spacing="4px">POLYOFF16</text>
+ <g transform="translate(80 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(5.5 24)">
+ <rect width="34" height="289" rx="5" fill="#fafafa" transform="translate(0 0)" />
+ <use id="CV1_INPUT" xlink:href="#input" transform="translate(5 5)" />
+ <use id="CV2_INPUT" xlink:href="#input" transform="translate(5 40)" />
+ <use id="CV3_INPUT" xlink:href="#input" transform="translate(5 75)" />
+ <use id="CV4_INPUT" xlink:href="#input" transform="translate(5 110)" />
+ <use id="CV5_INPUT" xlink:href="#input" transform="translate(5 145)" />
+ <use id="CV6_INPUT" xlink:href="#input" transform="translate(5 180)" />
+ <use id="CV7_INPUT" xlink:href="#input" transform="translate(5 215)" />
+ <use id="CV8_INPUT" xlink:href="#input" transform="translate(5 250)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(4 284)">IN/CV</text>
+ </g>
+
+ <g transform="translate(125.5 24)">
+ <rect width="34" height="289" rx="5" fill="#fafafa" transform="translate(0 0)" />
+ <use id="CV9_INPUT" xlink:href="#input" transform="translate(5 5)" />
+ <use id="CV10_INPUT" xlink:href="#input" transform="translate(5 40)" />
+ <use id="CV11_INPUT" xlink:href="#input" transform="translate(5 75)" />
+ <use id="CV12_INPUT" xlink:href="#input" transform="translate(5 110)" />
+ <use id="CV13_INPUT" xlink:href="#input" transform="translate(5 145)" />
+ <use id="CV14_INPUT" xlink:href="#input" transform="translate(5 180)" />
+ <use id="CV15_INPUT" xlink:href="#input" transform="translate(5 215)" />
+ <use id="CV16_INPUT" xlink:href="#input" transform="translate(5 250)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(4 284)">IN/CV</text>
+ </g>
+
+ <g transform="translate(0 33)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">1</text>
+ <use id="CHANNEL1_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET1_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE1_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 68)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">2</text>
+ <use id="CHANNEL2_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET2_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE2_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 103)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">3</text>
+ <use id="CHANNEL3_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET3_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE3_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 138)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">4</text>
+ <use id="CHANNEL4_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET4_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE4_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 173)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">5</text>
+ <use id="CHANNEL5_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET5_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE5_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 208)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">6</text>
+ <use id="CHANNEL6_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET6_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE6_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 243)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">7</text>
+ <use id="CHANNEL7_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET7_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE7_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(0 278)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">8</text>
+ <use id="CHANNEL8_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET8_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE8_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+
+ <g transform="translate(120 33)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">9</text>
+ <use id="CHANNEL9_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET9_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE9_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 68)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">10</text>
+ <use id="CHANNEL10_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET10_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE10_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 103)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">11</text>
+ <use id="CHANNEL11_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET11_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE11_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 138)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">12</text>
+ <use id="CHANNEL12_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET12_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE12_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 173)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">13</text>
+ <use id="CHANNEL13_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET13_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE13_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 208)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">14</text>
+ <use id="CHANNEL14_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET14_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE14_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 243)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">15</text>
+ <use id="CHANNEL15_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET15_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE15_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+ <g transform="translate(120 278)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">16</text>
+ <use id="CHANNEL16_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET16_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE16_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ </g>
+
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(55 308)">OFFSET</text>
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(88.5 308)">SCALE</text>
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(175 308)">OFFSET</text>
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(208.5 308)">SCALE</text>
+
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(0 330)" /> -->
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(180 330)" /> -->
+
+ <g transform="translate(73 320)">
+ <text font-size="6pt" letter-spacing="1.5px" transform="translate(-4 39) rotate(-90) translate(6.5 0)">CHAN</text>
+ <use id="CHANNELS_PARAM" xlink:href="#knob-smallest" transform="translate(10 12)" />
+ <use xlink:href="#knobguide-channels" transform="translate(-2 0)" />
+ </g>
+
+ <g transform="translate(115 318)">
+ <rect width="60" height="40" rx="5" fill="#fafafa" />
+ <rect width="24" height="40" rx="5" fill="#bbb" transform="translate(38)" />
+ <rect width="20" height="40" fill="#bbb" transform="translate(31)" />
+ <use id="IN_INPUT" xlink:href="#input" transform="translate(3.5 4)" />
+ <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(34.5 4)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(11 36)">IN</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(36 36)">OUT</text>
+ </g>
+</svg>
diff --git a/res-src/PolyOff8-src.svg b/res-src/PolyOff8-src.svg
@@ -0,0 +1,208 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="120"
+ height="380"
+ viewBox="0 0 120 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-channels8" viewBox="0 0 40px 40px">
+ <g transform="translate(20 20)">
+ <text font-size="5pt" transform="rotate(-240) translate(14 0) rotate(240) translate(-2 2)">1</text>
+ <text font-size="5pt" transform="rotate(-197.1) translate(14 0) rotate(197.1) translate(-2 2)">2</text>
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-154.3) translate(10 0)" />
+ <text font-size="5pt" transform="rotate(-111.4) translate(14 0) rotate(111.4) translate(-2 2)">4</text>
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-68.6) translate(10 0)" />
+ <text font-size="5pt" transform="rotate(-25.7) translate(13 0) rotate(25.7) translate(-2 2)">6</text>
+ <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(17.1) translate(10 0)" />
+ <text font-size="5pt" transform="rotate(60) translate(13 0) rotate(-60) translate(-1.8 3)">8</text>
+ </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="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="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 119,1 119,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 119.5,0.5 119.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 120,0 120,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <text class="title" x="29" y="17" font-size="9pt" letter-spacing="3px">POLYOFF8</text>
+ <g transform="translate(5.5 374)">
+ <text class="brand" font-size="6.5pt" letter-spacing="2px">BOGAUDIO</text>
+ <rect width="1.5" height="2" fill="#ddd" transform="translate(21 -4)" />
+ </g>
+
+ <!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="30" height="20" fill="#0f0" transform="translate(120 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(5 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(15 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(48.5 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(135 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(115 0)" /> -->
+
+ <g transform="translate(5.5 24)">
+ <rect width="34" height="289" rx="5" fill="#fafafa" transform="translate(0 0)" />
+ <use id="CV1_INPUT" xlink:href="#input" transform="translate(5 5)" />
+ <use id="CV2_INPUT" xlink:href="#input" transform="translate(5 40)" />
+ <use id="CV3_INPUT" xlink:href="#input" transform="translate(5 75)" />
+ <use id="CV4_INPUT" xlink:href="#input" transform="translate(5 110)" />
+ <use id="CV5_INPUT" xlink:href="#input" transform="translate(5 145)" />
+ <use id="CV6_INPUT" xlink:href="#input" transform="translate(5 180)" />
+ <use id="CV7_INPUT" xlink:href="#input" transform="translate(5 215)" />
+ <use id="CV8_INPUT" xlink:href="#input" transform="translate(5 250)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(4 284)">IN/CV</text>
+ </g>
+
+ <g transform="translate(0 33)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">1</text>
+ <use id="CHANNEL1_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET1_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE1_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 68)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">2</text>
+ <use id="CHANNEL2_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET2_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE2_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 103)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">3</text>
+ <use id="CHANNEL3_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET3_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE3_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 138)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">4</text>
+ <use id="CHANNEL4_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET4_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE4_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 173)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">5</text>
+ <use id="CHANNEL5_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET5_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE5_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 208)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">6</text>
+ <use id="CHANNEL6_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET6_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE6_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 243)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">7</text>
+ <use id="CHANNEL7_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET7_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE7_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 278)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">8</text>
+ <use id="CHANNEL8_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET8_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE8_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(55 308)">OFFSET</text>
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(88.5 308)">SCALE</text>
+
+ <g transform="translate(11 320)">
+ <text font-size="6pt" letter-spacing="1.5px" transform="translate(0 39) rotate(-90) translate(6.5 0)">CHAN</text>
+ <use id="CHANNELS_PARAM" xlink:href="#knob-smallest" transform="translate(12 12)" />
+ <use xlink:href="#knobguide-channels8" transform="translate(0 0)" />
+ </g>
+
+ <g transform="translate(52 318)">
+ <rect width="60" height="40" rx="5" fill="#fafafa" />
+ <rect width="24" height="40" rx="5" fill="#bbb" transform="translate(38)" />
+ <rect width="20" height="40" fill="#bbb" transform="translate(31)" />
+ <use id="IN_INPUT" xlink:href="#input" transform="translate(3.5 4)" />
+ <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(34.5 4)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(11 36)">IN</text>
+ <text font-size="6pt" letter-spacing="2px" transform="translate(36 36)">OUT</text>
+ </g>
+</svg>
diff --git a/res-src/PolyOffX-src.svg b/res-src/PolyOffX-src.svg
@@ -0,0 +1,191 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="120"
+ height="380"
+ viewBox="0 0 120 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="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 119,1 119,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 119.5,0.5 119.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 120,0 120,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <text class="title" x="27" y="17" font-size="9pt" letter-spacing="3px">POLYOFFX</text>
+ <g transform="translate(5.5 374)">
+ <text class="brand" font-size="6.5pt" letter-spacing="2px">BOGAUDIO</text>
+ <rect width="1.5" height="2" fill="#ddd" transform="translate(21 -4)" />
+ </g>
+
+ <!-- <rect width="30" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="30" height="20" fill="#0f0" transform="translate(120 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(5 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(15 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(48.5 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(135 0)" /> -->
+ <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(115 0)" /> -->
+
+ <g transform="translate(5.5 24)">
+ <rect width="34" height="289" rx="5" fill="#fafafa" transform="translate(0 0)" />
+ <use id="IN9_INPUT" xlink:href="#input" transform="translate(5 5)" />
+ <use id="IN10_INPUT" xlink:href="#input" transform="translate(5 40)" />
+ <use id="IN11_INPUT" xlink:href="#input" transform="translate(5 75)" />
+ <use id="IN12_INPUT" xlink:href="#input" transform="translate(5 110)" />
+ <use id="IN13_INPUT" xlink:href="#input" transform="translate(5 145)" />
+ <use id="IN14_INPUT" xlink:href="#input" transform="translate(5 180)" />
+ <use id="IN15_INPUT" xlink:href="#input" transform="translate(5 215)" />
+ <use id="IN16_INPUT" xlink:href="#input" transform="translate(5 250)" />
+ <text font-size="6pt" letter-spacing="1px" transform="translate(4 284)">IN/CV</text>
+ </g>
+
+ <g transform="translate(0 33)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(46.5 8)">9</text>
+ <use id="CHANNEL9_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET9_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE9_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 68)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">10</text>
+ <use id="CHANNEL10_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET10_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE10_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 103)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">11</text>
+ <use id="CHANNEL11_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET11_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE11_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 138)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">12</text>
+ <use id="CHANNEL12_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET12_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE12_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 173)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">13</text>
+ <use id="CHANNEL13_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET13_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE13_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 208)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">14</text>
+ <use id="CHANNEL14_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET14_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE14_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 243)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">15</text>
+ <use id="CHANNEL15_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET15_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE15_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <g transform="translate(0 278)">
+ <text font-size="5pt" letter-spacing="1px" transform="translate(44 8)">16</text>
+ <use id="CHANNEL16_LIGHT" xlink:href="#light-tiny" transform="translate(46.8 10)" />
+ <use id="OFFSET16_PARAM" xlink:href="#knob-smallest" transform="translate(62.5 0)" />
+ <use xlink:href="#knobguide-centertick" transform="translate(50.5 -12)" />
+ <use id="SCALE16_PARAM" xlink:href="#knob-smallest" transform="translate(93.5 0)" />
+ <use xlink:href="#knobguide-maxtick" transform="translate(81.5 -12)" />
+ <!-- <polyline points="0,0 150,0" stroke="#f00" stroke-width="1" fill="none" transform="translate(0 8)" /> -->
+ </g>
+
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(55 308)">OFFSET</text>
+ <text font-size="6pt" letter-spacing="0.3px" transform="translate(88.5 308)">SCALE</text>
+</svg>
diff --git a/res-src/SixteenHP-src.svg b/res-src/SixteenHP-src.svg
@@ -0,0 +1,43 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="240"
+ height="380"
+ viewBox="0 0 240 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>
+ </defs>
+
+ <rect width="100%" height="100%" fill="#ddd" />
+ <polyline points="1,1 239,1 239,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 239.5,0.5 239.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 240,0 240,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(0 0)" /> -->
+ <!-- <rect width="60" height="20" fill="#0f0" transform="translate(180 0)" /> -->
+ <!-- <rect width="80" height="20" fill="#0f0" transform="translate(0 360)" /> -->
+ <!-- <rect width="80" height="20" fill="#0f0" transform="translate(160 360)" /> -->
+
+ <text class="title" x="62" y="19" font-size="12pt" letter-spacing="4px">16HP-16HP</text>
+ <g transform="translate(80 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>
+</svg>
diff --git a/res/PolyOff16.svg b/res/PolyOff16.svg
Binary files differ.
diff --git a/res/PolyOff8.svg b/res/PolyOff8.svg
Binary files differ.
diff --git a/src/PolyCon16.hpp b/src/PolyCon16.hpp
@@ -61,7 +61,7 @@ struct PolyCon16 : OutputRangeModule<BGModule> {
PolyCon16() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
- configParam<OutputRangeParamQuantity>(CHANNELS_PARAM, 1.0f, 16.0f, 1.0f, "Polyphony channels");
+ configParam(CHANNELS_PARAM, 1.0f, 16.0f, 1.0f, "Polyphony channels");
configParam<OutputRangeParamQuantity>(CHANNEL1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1", "V", 0.0f, 10.0f);
configParam<OutputRangeParamQuantity>(CHANNEL2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2", "V", 0.0f, 10.0f);
configParam<OutputRangeParamQuantity>(CHANNEL3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3", "V", 0.0f, 10.0f);
diff --git a/src/PolyOff16.cpp b/src/PolyOff16.cpp
@@ -0,0 +1,215 @@
+
+#include "PolyOff16.hpp"
+
+void PolyOff16::processAll(const ProcessArgs& args) {
+ int cn = 1;
+ if (inputs[IN_INPUT].isConnected()) {
+ cn = clamp(inputs[IN_INPUT].getChannels(), 1, 16);
+ outputs[OUT_OUTPUT].setChannels(cn);
+
+ for (int c = 0; c < cn; ++c) {
+ float out = clamp(params[OFFSET1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ if (inputs[CV1_INPUT + c].isConnected()) {
+ out *= clamp(inputs[CV1_INPUT + c].getVoltage() / 5.0f, -1.0f, 1.0f);
+ }
+ out += _rangeOffset;
+ out *= _rangeScale;
+ out += inputs[IN_INPUT].getPolyVoltage(c);
+ out *= clamp(params[SCALE1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ outputs[OUT_OUTPUT].setVoltage(clamp(out, -12.0f, 12.0f), c);
+ }
+ }
+ else {
+ cn = clamp(params[CHANNELS_PARAM].getValue(), 1.0f, 16.0f);
+ outputs[OUT_OUTPUT].setChannels(cn);
+
+ for (int c = 0; c < cn; ++c) {
+ float out = clamp(params[OFFSET1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ out += _rangeOffset;
+ out *= _rangeScale;
+ out += inputs[CV1_INPUT + c].getVoltage();
+ out *= clamp(params[SCALE1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ outputs[OUT_OUTPUT].setVoltage(clamp(out, -12.0f, 12.0f), c);
+ }
+ }
+
+ for (int c = 0; c < 16; ++c) {
+ lights[CHANNEL1_LIGHT + c].value = (c < cn) * 1.0f;
+ }
+}
+
+struct PolyOff16Widget : ModuleWidget {
+ static constexpr int hp = 16;
+
+ PolyOff16Widget(PolyOff16* 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/PolyOff16.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 offset1ParamPosition = Vec(62.5, 33.0);
+ auto scale1ParamPosition = Vec(93.5, 33.0);
+ auto offset2ParamPosition = Vec(62.5, 68.0);
+ auto scale2ParamPosition = Vec(93.5, 68.0);
+ auto offset3ParamPosition = Vec(62.5, 103.0);
+ auto scale3ParamPosition = Vec(93.5, 103.0);
+ auto offset4ParamPosition = Vec(62.5, 138.0);
+ auto scale4ParamPosition = Vec(93.5, 138.0);
+ auto offset5ParamPosition = Vec(62.5, 173.0);
+ auto scale5ParamPosition = Vec(93.5, 173.0);
+ auto offset6ParamPosition = Vec(62.5, 208.0);
+ auto scale6ParamPosition = Vec(93.5, 208.0);
+ auto offset7ParamPosition = Vec(62.5, 243.0);
+ auto scale7ParamPosition = Vec(93.5, 243.0);
+ auto offset8ParamPosition = Vec(62.5, 278.0);
+ auto scale8ParamPosition = Vec(93.5, 278.0);
+ auto offset9ParamPosition = Vec(182.5, 33.0);
+ auto scale9ParamPosition = Vec(213.5, 33.0);
+ auto offset10ParamPosition = Vec(182.5, 68.0);
+ auto scale10ParamPosition = Vec(213.5, 68.0);
+ auto offset11ParamPosition = Vec(182.5, 103.0);
+ auto scale11ParamPosition = Vec(213.5, 103.0);
+ auto offset12ParamPosition = Vec(182.5, 138.0);
+ auto scale12ParamPosition = Vec(213.5, 138.0);
+ auto offset13ParamPosition = Vec(182.5, 173.0);
+ auto scale13ParamPosition = Vec(213.5, 173.0);
+ auto offset14ParamPosition = Vec(182.5, 208.0);
+ auto scale14ParamPosition = Vec(213.5, 208.0);
+ auto offset15ParamPosition = Vec(182.5, 243.0);
+ auto scale15ParamPosition = Vec(213.5, 243.0);
+ auto offset16ParamPosition = Vec(182.5, 278.0);
+ auto scale16ParamPosition = Vec(213.5, 278.0);
+ auto channelsParamPosition = Vec(83.0, 332.0);
+
+ auto cv1InputPosition = Vec(10.5, 29.0);
+ auto cv2InputPosition = Vec(10.5, 64.0);
+ auto cv3InputPosition = Vec(10.5, 99.0);
+ auto cv4InputPosition = Vec(10.5, 134.0);
+ auto cv5InputPosition = Vec(10.5, 169.0);
+ auto cv6InputPosition = Vec(10.5, 204.0);
+ auto cv7InputPosition = Vec(10.5, 239.0);
+ auto cv8InputPosition = Vec(10.5, 274.0);
+ auto cv9InputPosition = Vec(130.5, 29.0);
+ auto cv10InputPosition = Vec(130.5, 64.0);
+ auto cv11InputPosition = Vec(130.5, 99.0);
+ auto cv12InputPosition = Vec(130.5, 134.0);
+ auto cv13InputPosition = Vec(130.5, 169.0);
+ auto cv14InputPosition = Vec(130.5, 204.0);
+ auto cv15InputPosition = Vec(130.5, 239.0);
+ auto cv16InputPosition = Vec(130.5, 274.0);
+ auto inInputPosition = Vec(118.5, 322.0);
+
+ auto outOutputPosition = Vec(149.5, 322.0);
+
+ auto channel1LightPosition = Vec(46.8, 43.0);
+ auto channel2LightPosition = Vec(46.8, 78.0);
+ auto channel3LightPosition = Vec(46.8, 113.0);
+ auto channel4LightPosition = Vec(46.8, 148.0);
+ auto channel5LightPosition = Vec(46.8, 183.0);
+ auto channel6LightPosition = Vec(46.8, 218.0);
+ auto channel7LightPosition = Vec(46.8, 253.0);
+ auto channel8LightPosition = Vec(46.8, 288.0);
+ auto channel9LightPosition = Vec(166.8, 43.0);
+ auto channel10LightPosition = Vec(166.8, 78.0);
+ auto channel11LightPosition = Vec(166.8, 113.0);
+ auto channel12LightPosition = Vec(166.8, 148.0);
+ auto channel13LightPosition = Vec(166.8, 183.0);
+ auto channel14LightPosition = Vec(166.8, 218.0);
+ auto channel15LightPosition = Vec(166.8, 253.0);
+ auto channel16LightPosition = Vec(166.8, 288.0);
+ // end generated by svg_widgets.rb
+
+ addParam(createParam<Knob16>(offset1ParamPosition, module, PolyOff16::OFFSET1_PARAM));
+ addParam(createParam<Knob16>(scale1ParamPosition, module, PolyOff16::SCALE1_PARAM));
+ addParam(createParam<Knob16>(offset2ParamPosition, module, PolyOff16::OFFSET2_PARAM));
+ addParam(createParam<Knob16>(scale2ParamPosition, module, PolyOff16::SCALE2_PARAM));
+ addParam(createParam<Knob16>(offset3ParamPosition, module, PolyOff16::OFFSET3_PARAM));
+ addParam(createParam<Knob16>(scale3ParamPosition, module, PolyOff16::SCALE3_PARAM));
+ addParam(createParam<Knob16>(offset4ParamPosition, module, PolyOff16::OFFSET4_PARAM));
+ addParam(createParam<Knob16>(scale4ParamPosition, module, PolyOff16::SCALE4_PARAM));
+ addParam(createParam<Knob16>(offset5ParamPosition, module, PolyOff16::OFFSET5_PARAM));
+ addParam(createParam<Knob16>(scale5ParamPosition, module, PolyOff16::SCALE5_PARAM));
+ addParam(createParam<Knob16>(offset6ParamPosition, module, PolyOff16::OFFSET6_PARAM));
+ addParam(createParam<Knob16>(scale6ParamPosition, module, PolyOff16::SCALE6_PARAM));
+ addParam(createParam<Knob16>(offset7ParamPosition, module, PolyOff16::OFFSET7_PARAM));
+ addParam(createParam<Knob16>(scale7ParamPosition, module, PolyOff16::SCALE7_PARAM));
+ addParam(createParam<Knob16>(offset8ParamPosition, module, PolyOff16::OFFSET8_PARAM));
+ addParam(createParam<Knob16>(scale8ParamPosition, module, PolyOff16::SCALE8_PARAM));
+ addParam(createParam<Knob16>(offset9ParamPosition, module, PolyOff16::OFFSET9_PARAM));
+ addParam(createParam<Knob16>(scale9ParamPosition, module, PolyOff16::SCALE9_PARAM));
+ addParam(createParam<Knob16>(offset10ParamPosition, module, PolyOff16::OFFSET10_PARAM));
+ addParam(createParam<Knob16>(scale10ParamPosition, module, PolyOff16::SCALE10_PARAM));
+ addParam(createParam<Knob16>(offset11ParamPosition, module, PolyOff16::OFFSET11_PARAM));
+ addParam(createParam<Knob16>(scale11ParamPosition, module, PolyOff16::SCALE11_PARAM));
+ addParam(createParam<Knob16>(offset12ParamPosition, module, PolyOff16::OFFSET12_PARAM));
+ addParam(createParam<Knob16>(scale12ParamPosition, module, PolyOff16::SCALE12_PARAM));
+ addParam(createParam<Knob16>(offset13ParamPosition, module, PolyOff16::OFFSET13_PARAM));
+ addParam(createParam<Knob16>(scale13ParamPosition, module, PolyOff16::SCALE13_PARAM));
+ addParam(createParam<Knob16>(offset14ParamPosition, module, PolyOff16::OFFSET14_PARAM));
+ addParam(createParam<Knob16>(scale14ParamPosition, module, PolyOff16::SCALE14_PARAM));
+ addParam(createParam<Knob16>(offset15ParamPosition, module, PolyOff16::OFFSET15_PARAM));
+ addParam(createParam<Knob16>(scale15ParamPosition, module, PolyOff16::SCALE15_PARAM));
+ addParam(createParam<Knob16>(offset16ParamPosition, module, PolyOff16::OFFSET16_PARAM));
+ addParam(createParam<Knob16>(scale16ParamPosition, module, PolyOff16::SCALE16_PARAM));
+ {
+ auto w = createParam<Knob16>(channelsParamPosition, module, PolyOff16::CHANNELS_PARAM);
+ dynamic_cast<Knob*>(w)->snap = true;
+ addParam(w);
+ }
+
+ addInput(createInput<Port24>(cv1InputPosition, module, PolyOff16::CV1_INPUT));
+ addInput(createInput<Port24>(cv2InputPosition, module, PolyOff16::CV2_INPUT));
+ addInput(createInput<Port24>(cv3InputPosition, module, PolyOff16::CV3_INPUT));
+ addInput(createInput<Port24>(cv4InputPosition, module, PolyOff16::CV4_INPUT));
+ addInput(createInput<Port24>(cv5InputPosition, module, PolyOff16::CV5_INPUT));
+ addInput(createInput<Port24>(cv6InputPosition, module, PolyOff16::CV6_INPUT));
+ addInput(createInput<Port24>(cv7InputPosition, module, PolyOff16::CV7_INPUT));
+ addInput(createInput<Port24>(cv8InputPosition, module, PolyOff16::CV8_INPUT));
+ addInput(createInput<Port24>(cv9InputPosition, module, PolyOff16::CV9_INPUT));
+ addInput(createInput<Port24>(cv10InputPosition, module, PolyOff16::CV10_INPUT));
+ addInput(createInput<Port24>(cv11InputPosition, module, PolyOff16::CV11_INPUT));
+ addInput(createInput<Port24>(cv12InputPosition, module, PolyOff16::CV12_INPUT));
+ addInput(createInput<Port24>(cv13InputPosition, module, PolyOff16::CV13_INPUT));
+ addInput(createInput<Port24>(cv14InputPosition, module, PolyOff16::CV14_INPUT));
+ addInput(createInput<Port24>(cv15InputPosition, module, PolyOff16::CV15_INPUT));
+ addInput(createInput<Port24>(cv16InputPosition, module, PolyOff16::CV16_INPUT));
+ addInput(createInput<Port24>(inInputPosition, module, PolyOff16::IN_INPUT));
+
+ addOutput(createOutput<Port24>(outOutputPosition, module, PolyOff16::OUT_OUTPUT));
+
+ addChild(createLight<TinyLight<GreenLight>>(channel1LightPosition, module, PolyOff16::CHANNEL1_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel2LightPosition, module, PolyOff16::CHANNEL2_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel3LightPosition, module, PolyOff16::CHANNEL3_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel4LightPosition, module, PolyOff16::CHANNEL4_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel5LightPosition, module, PolyOff16::CHANNEL5_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel6LightPosition, module, PolyOff16::CHANNEL6_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel7LightPosition, module, PolyOff16::CHANNEL7_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel8LightPosition, module, PolyOff16::CHANNEL8_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel9LightPosition, module, PolyOff16::CHANNEL9_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel10LightPosition, module, PolyOff16::CHANNEL10_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel11LightPosition, module, PolyOff16::CHANNEL11_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel12LightPosition, module, PolyOff16::CHANNEL12_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel13LightPosition, module, PolyOff16::CHANNEL13_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel14LightPosition, module, PolyOff16::CHANNEL14_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel15LightPosition, module, PolyOff16::CHANNEL15_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel16LightPosition, module, PolyOff16::CHANNEL16_LIGHT));
+ }
+
+ void appendContextMenu(Menu* menu) override {
+ menu->addChild(new MenuLabel());
+ OutputRangeOptionMenuItem::addOutputRangeOptionsToMenu(module, menu);
+ }
+};
+
+Model* modelPolyOff16 = createModel<PolyOff16, PolyOff16Widget>("Bogaudio-PolyOff16", "POLYOFF16", "Polyphonic per-channel offset and scale", "Polyphonic");
diff --git a/src/PolyOff16.hpp b/src/PolyOff16.hpp
@@ -0,0 +1,134 @@
+#pragma once
+
+#include "bogaudio.hpp"
+#include "output_range.hpp"
+
+extern Model* modelPolyOff16;
+
+namespace bogaudio {
+
+struct PolyOff16 : OutputRangeModule<BGModule> {
+ enum ParamsIds {
+ OFFSET1_PARAM,
+ SCALE1_PARAM,
+ OFFSET2_PARAM,
+ SCALE2_PARAM,
+ OFFSET3_PARAM,
+ SCALE3_PARAM,
+ OFFSET4_PARAM,
+ SCALE4_PARAM,
+ OFFSET5_PARAM,
+ SCALE5_PARAM,
+ OFFSET6_PARAM,
+ SCALE6_PARAM,
+ OFFSET7_PARAM,
+ SCALE7_PARAM,
+ OFFSET8_PARAM,
+ SCALE8_PARAM,
+ OFFSET9_PARAM,
+ SCALE9_PARAM,
+ OFFSET10_PARAM,
+ SCALE10_PARAM,
+ OFFSET11_PARAM,
+ SCALE11_PARAM,
+ OFFSET12_PARAM,
+ SCALE12_PARAM,
+ OFFSET13_PARAM,
+ SCALE13_PARAM,
+ OFFSET14_PARAM,
+ SCALE14_PARAM,
+ OFFSET15_PARAM,
+ SCALE15_PARAM,
+ OFFSET16_PARAM,
+ SCALE16_PARAM,
+ CHANNELS_PARAM,
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ CV1_INPUT,
+ CV2_INPUT,
+ CV3_INPUT,
+ CV4_INPUT,
+ CV5_INPUT,
+ CV6_INPUT,
+ CV7_INPUT,
+ CV8_INPUT,
+ CV9_INPUT,
+ CV10_INPUT,
+ CV11_INPUT,
+ CV12_INPUT,
+ CV13_INPUT,
+ CV14_INPUT,
+ CV15_INPUT,
+ CV16_INPUT,
+ IN_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ enum LightsIds {
+ CHANNEL1_LIGHT,
+ CHANNEL2_LIGHT,
+ CHANNEL3_LIGHT,
+ CHANNEL4_LIGHT,
+ CHANNEL5_LIGHT,
+ CHANNEL6_LIGHT,
+ CHANNEL7_LIGHT,
+ CHANNEL8_LIGHT,
+ CHANNEL9_LIGHT,
+ CHANNEL10_LIGHT,
+ CHANNEL11_LIGHT,
+ CHANNEL12_LIGHT,
+ CHANNEL13_LIGHT,
+ CHANNEL14_LIGHT,
+ CHANNEL15_LIGHT,
+ CHANNEL16_LIGHT,
+ NUM_LIGHTS
+ };
+
+ PolyOff16() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ configParam<OutputRangeParamQuantity>(OFFSET1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 offset");
+ configParam(SCALE1_PARAM, -1.0f, 1.0f, 1.0f, "Channel 1 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 offset");
+ configParam(SCALE2_PARAM, -1.0f, 1.0f, 1.0f, "Channel 2 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 offset");
+ configParam(SCALE3_PARAM, -1.0f, 1.0f, 1.0f, "Channel 3 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 offset");
+ configParam(SCALE4_PARAM, -1.0f, 1.0f, 1.0f, "Channel 4 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET5_PARAM, -1.0f, 1.0f, 0.0f, "Channel 5 offset");
+ configParam(SCALE5_PARAM, -1.0f, 1.0f, 1.0f, "Channel 5 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET6_PARAM, -1.0f, 1.0f, 0.0f, "Channel 6 offset");
+ configParam(SCALE6_PARAM, -1.0f, 1.0f, 1.0f, "Channel 6 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET7_PARAM, -1.0f, 1.0f, 0.0f, "Channel 7 offset");
+ configParam(SCALE7_PARAM, -1.0f, 1.0f, 1.0f, "Channel 7 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET8_PARAM, -1.0f, 1.0f, 0.0f, "Channel 8 offset");
+ configParam(SCALE8_PARAM, -1.0f, 1.0f, 1.0f, "Channel 8 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET9_PARAM, -1.0f, 1.0f, 0.0f, "Channel 9 offset");
+ configParam(SCALE9_PARAM, -1.0f, 1.0f, 1.0f, "Channel 9 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET10_PARAM, -1.0f, 1.0f, 0.0f, "Channel 10 offset");
+ configParam(SCALE10_PARAM, -1.0f, 1.0f, 1.0f, "Channel 10 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET11_PARAM, -1.0f, 1.0f, 0.0f, "Channel 11 offset");
+ configParam(SCALE11_PARAM, -1.0f, 1.0f, 1.0f, "Channel 11 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET12_PARAM, -1.0f, 1.0f, 0.0f, "Channel 12 offset");
+ configParam(SCALE12_PARAM, -1.0f, 1.0f, 1.0f, "Channel 12 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET13_PARAM, -1.0f, 1.0f, 0.0f, "Channel 13 offset");
+ configParam(SCALE13_PARAM, -1.0f, 1.0f, 1.0f, "Channel 13 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET14_PARAM, -1.0f, 1.0f, 0.0f, "Channel 14 offset");
+ configParam(SCALE14_PARAM, -1.0f, 1.0f, 1.0f, "Channel 14 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET15_PARAM, -1.0f, 1.0f, 0.0f, "Channel 15 offset");
+ configParam(SCALE15_PARAM, -1.0f, 1.0f, 1.0f, "Channel 15 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET16_PARAM, -1.0f, 1.0f, 0.0f, "Channel 16 offset");
+ configParam(SCALE16_PARAM, -1.0f, 1.0f, 1.0f, "Channel 16 scale", "%", 0.0f, 100.0f);
+ configParam(CHANNELS_PARAM, 1.0f, 16.0f, 1.0f, "Polyphony channels");
+ }
+
+ void processAll(const ProcessArgs& args) override;
+};
+
+} // namespace bogaudio
diff --git a/src/PolyOff8.cpp b/src/PolyOff8.cpp
@@ -0,0 +1,149 @@
+
+#include "PolyOff8.hpp"
+
+void PolyOff8::processAll(const ProcessArgs& args) {
+ int cn = 1;
+ if (inputs[IN_INPUT].isConnected()) {
+ cn = clamp(inputs[IN_INPUT].getChannels(), 1, 8);
+ outputs[OUT_OUTPUT].setChannels(cn);
+
+ for (int c = 0; c < cn; ++c) {
+ float out = clamp(params[OFFSET1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ if (inputs[CV1_INPUT + c].isConnected()) {
+ out *= clamp(inputs[CV1_INPUT + c].getVoltage() / 5.0f, -1.0f, 1.0f);
+ }
+ out += _rangeOffset;
+ out *= _rangeScale;
+ out += inputs[IN_INPUT].getPolyVoltage(c);
+ out *= clamp(params[SCALE1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ outputs[OUT_OUTPUT].setVoltage(clamp(out, -12.0f, 12.0f), c);
+ }
+ }
+ else {
+ cn = clamp(params[CHANNELS_PARAM].getValue(), 1.0f, 8.0f);
+ outputs[OUT_OUTPUT].setChannels(cn);
+
+ for (int c = 0; c < cn; ++c) {
+ float out = clamp(params[OFFSET1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ out += _rangeOffset;
+ out *= _rangeScale;
+ out += inputs[CV1_INPUT + c].getVoltage();
+ out *= clamp(params[SCALE1_PARAM + 2 * c].getValue(), -1.0f, 1.0f);
+ outputs[OUT_OUTPUT].setVoltage(clamp(out, -12.0f, 12.0f), c);
+ }
+ }
+
+ for (int c = 0; c < 8; ++c) {
+ lights[CHANNEL1_LIGHT + c].value = (c < cn) * 1.0f;
+ }
+}
+
+struct PolyOff8Widget : ModuleWidget {
+ static constexpr int hp = 8;
+
+ PolyOff8Widget(PolyOff8* 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/PolyOff8.svg")));
+ addChild(panel);
+ }
+
+ addChild(createWidget<ScrewSilver>(Vec(0, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 15, 365)));
+
+ // generated by svg_widgets.rb
+ auto offset1ParamPosition = Vec(62.5, 33.0);
+ auto scale1ParamPosition = Vec(93.5, 33.0);
+ auto offset2ParamPosition = Vec(62.5, 68.0);
+ auto scale2ParamPosition = Vec(93.5, 68.0);
+ auto offset3ParamPosition = Vec(62.5, 103.0);
+ auto scale3ParamPosition = Vec(93.5, 103.0);
+ auto offset4ParamPosition = Vec(62.5, 138.0);
+ auto scale4ParamPosition = Vec(93.5, 138.0);
+ auto offset5ParamPosition = Vec(62.5, 173.0);
+ auto scale5ParamPosition = Vec(93.5, 173.0);
+ auto offset6ParamPosition = Vec(62.5, 208.0);
+ auto scale6ParamPosition = Vec(93.5, 208.0);
+ auto offset7ParamPosition = Vec(62.5, 243.0);
+ auto scale7ParamPosition = Vec(93.5, 243.0);
+ auto offset8ParamPosition = Vec(62.5, 278.0);
+ auto scale8ParamPosition = Vec(93.5, 278.0);
+ auto channelsParamPosition = Vec(23.0, 332.0);
+
+ auto cv1InputPosition = Vec(10.5, 29.0);
+ auto cv2InputPosition = Vec(10.5, 64.0);
+ auto cv3InputPosition = Vec(10.5, 99.0);
+ auto cv4InputPosition = Vec(10.5, 134.0);
+ auto cv5InputPosition = Vec(10.5, 169.0);
+ auto cv6InputPosition = Vec(10.5, 204.0);
+ auto cv7InputPosition = Vec(10.5, 239.0);
+ auto cv8InputPosition = Vec(10.5, 274.0);
+ auto inInputPosition = Vec(55.5, 322.0);
+
+ auto outOutputPosition = Vec(86.5, 322.0);
+
+ auto channel1LightPosition = Vec(46.8, 43.0);
+ auto channel2LightPosition = Vec(46.8, 78.0);
+ auto channel3LightPosition = Vec(46.8, 113.0);
+ auto channel4LightPosition = Vec(46.8, 148.0);
+ auto channel5LightPosition = Vec(46.8, 183.0);
+ auto channel6LightPosition = Vec(46.8, 218.0);
+ auto channel7LightPosition = Vec(46.8, 253.0);
+ auto channel8LightPosition = Vec(46.8, 288.0);
+ // end generated by svg_widgets.rb
+
+ addParam(createParam<Knob16>(offset1ParamPosition, module, PolyOff8::OFFSET1_PARAM));
+ addParam(createParam<Knob16>(scale1ParamPosition, module, PolyOff8::SCALE1_PARAM));
+ addParam(createParam<Knob16>(offset2ParamPosition, module, PolyOff8::OFFSET2_PARAM));
+ addParam(createParam<Knob16>(scale2ParamPosition, module, PolyOff8::SCALE2_PARAM));
+ addParam(createParam<Knob16>(offset3ParamPosition, module, PolyOff8::OFFSET3_PARAM));
+ addParam(createParam<Knob16>(scale3ParamPosition, module, PolyOff8::SCALE3_PARAM));
+ addParam(createParam<Knob16>(offset4ParamPosition, module, PolyOff8::OFFSET4_PARAM));
+ addParam(createParam<Knob16>(scale4ParamPosition, module, PolyOff8::SCALE4_PARAM));
+ addParam(createParam<Knob16>(offset5ParamPosition, module, PolyOff8::OFFSET5_PARAM));
+ addParam(createParam<Knob16>(scale5ParamPosition, module, PolyOff8::SCALE5_PARAM));
+ addParam(createParam<Knob16>(offset6ParamPosition, module, PolyOff8::OFFSET6_PARAM));
+ addParam(createParam<Knob16>(scale6ParamPosition, module, PolyOff8::SCALE6_PARAM));
+ addParam(createParam<Knob16>(offset7ParamPosition, module, PolyOff8::OFFSET7_PARAM));
+ addParam(createParam<Knob16>(scale7ParamPosition, module, PolyOff8::SCALE7_PARAM));
+ addParam(createParam<Knob16>(offset8ParamPosition, module, PolyOff8::OFFSET8_PARAM));
+ addParam(createParam<Knob16>(scale8ParamPosition, module, PolyOff8::SCALE8_PARAM));
+ {
+ auto w = createParam<Knob16>(channelsParamPosition, module, PolyOff8::CHANNELS_PARAM);
+ dynamic_cast<Knob*>(w)->snap = true;
+ addParam(w);
+ }
+
+ addInput(createInput<Port24>(cv1InputPosition, module, PolyOff8::CV1_INPUT));
+ addInput(createInput<Port24>(cv2InputPosition, module, PolyOff8::CV2_INPUT));
+ addInput(createInput<Port24>(cv3InputPosition, module, PolyOff8::CV3_INPUT));
+ addInput(createInput<Port24>(cv4InputPosition, module, PolyOff8::CV4_INPUT));
+ addInput(createInput<Port24>(cv5InputPosition, module, PolyOff8::CV5_INPUT));
+ addInput(createInput<Port24>(cv6InputPosition, module, PolyOff8::CV6_INPUT));
+ addInput(createInput<Port24>(cv7InputPosition, module, PolyOff8::CV7_INPUT));
+ addInput(createInput<Port24>(cv8InputPosition, module, PolyOff8::CV8_INPUT));
+ addInput(createInput<Port24>(inInputPosition, module, PolyOff8::IN_INPUT));
+
+ addOutput(createOutput<Port24>(outOutputPosition, module, PolyOff8::OUT_OUTPUT));
+
+ addChild(createLight<TinyLight<GreenLight>>(channel1LightPosition, module, PolyOff8::CHANNEL1_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel2LightPosition, module, PolyOff8::CHANNEL2_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel3LightPosition, module, PolyOff8::CHANNEL3_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel4LightPosition, module, PolyOff8::CHANNEL4_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel5LightPosition, module, PolyOff8::CHANNEL5_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel6LightPosition, module, PolyOff8::CHANNEL6_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel7LightPosition, module, PolyOff8::CHANNEL7_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(channel8LightPosition, module, PolyOff8::CHANNEL8_LIGHT));
+ }
+
+ void appendContextMenu(Menu* menu) override {
+ menu->addChild(new MenuLabel());
+ OutputRangeOptionMenuItem::addOutputRangeOptionsToMenu(module, menu);
+ }
+};
+
+Model* modelPolyOff8 = createModel<PolyOff8, PolyOff8Widget>("Bogaudio-PolyOff8", "POLYOFF8", "Polyphonic per-channel offset and scale", "Polyphonic");
diff --git a/src/PolyOff8.hpp b/src/PolyOff8.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include "bogaudio.hpp"
+#include "output_range.hpp"
+
+extern Model* modelPolyOff8;
+
+namespace bogaudio {
+
+struct PolyOff8 : OutputRangeModule<BGModule> {
+ enum ParamsIds {
+ OFFSET1_PARAM,
+ SCALE1_PARAM,
+ OFFSET2_PARAM,
+ SCALE2_PARAM,
+ OFFSET3_PARAM,
+ SCALE3_PARAM,
+ OFFSET4_PARAM,
+ SCALE4_PARAM,
+ OFFSET5_PARAM,
+ SCALE5_PARAM,
+ OFFSET6_PARAM,
+ SCALE6_PARAM,
+ OFFSET7_PARAM,
+ SCALE7_PARAM,
+ OFFSET8_PARAM,
+ SCALE8_PARAM,
+ CHANNELS_PARAM,
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ CV1_INPUT,
+ CV2_INPUT,
+ CV3_INPUT,
+ CV4_INPUT,
+ CV5_INPUT,
+ CV6_INPUT,
+ CV7_INPUT,
+ CV8_INPUT,
+ IN_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ enum LightsIds {
+ CHANNEL1_LIGHT,
+ CHANNEL2_LIGHT,
+ CHANNEL3_LIGHT,
+ CHANNEL4_LIGHT,
+ CHANNEL5_LIGHT,
+ CHANNEL6_LIGHT,
+ CHANNEL7_LIGHT,
+ CHANNEL8_LIGHT,
+ NUM_LIGHTS
+ };
+
+ PolyOff8() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ configParam<OutputRangeParamQuantity>(OFFSET1_PARAM, -1.0f, 1.0f, 0.0f, "Channel 1 offset");
+ configParam(SCALE1_PARAM, -1.0f, 1.0f, 1.0f, "Channel 1 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET2_PARAM, -1.0f, 1.0f, 0.0f, "Channel 2 offset");
+ configParam(SCALE2_PARAM, -1.0f, 1.0f, 1.0f, "Channel 2 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET3_PARAM, -1.0f, 1.0f, 0.0f, "Channel 3 offset");
+ configParam(SCALE3_PARAM, -1.0f, 1.0f, 1.0f, "Channel 3 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET4_PARAM, -1.0f, 1.0f, 0.0f, "Channel 4 offset");
+ configParam(SCALE4_PARAM, -1.0f, 1.0f, 1.0f, "Channel 4 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET5_PARAM, -1.0f, 1.0f, 0.0f, "Channel 5 offset");
+ configParam(SCALE5_PARAM, -1.0f, 1.0f, 1.0f, "Channel 5 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET6_PARAM, -1.0f, 1.0f, 0.0f, "Channel 6 offset");
+ configParam(SCALE6_PARAM, -1.0f, 1.0f, 1.0f, "Channel 6 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET7_PARAM, -1.0f, 1.0f, 0.0f, "Channel 7 offset");
+ configParam(SCALE7_PARAM, -1.0f, 1.0f, 1.0f, "Channel 7 scale", "%", 0.0f, 100.0f);
+ configParam<OutputRangeParamQuantity>(OFFSET8_PARAM, -1.0f, 1.0f, 0.0f, "Channel 8 offset");
+ configParam(SCALE8_PARAM, -1.0f, 1.0f, 1.0f, "Channel 8 scale", "%", 0.0f, 100.0f);
+ configParam(CHANNELS_PARAM, 1.0f, 8.0f, 1.0f, "Polyphony channels");
+ }
+
+ void processAll(const ProcessArgs& args) override;
+};
+
+} // namespace bogaudio
diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp
@@ -55,6 +55,8 @@
#include "Pgmr.hpp"
#include "PolyCon8.hpp"
#include "PolyCon16.hpp"
+#include "PolyOff8.hpp"
+#include "PolyOff16.hpp"
#include "PolyMult.hpp"
#include "Pressor.hpp"
#include "Pulse.hpp"
@@ -174,8 +176,10 @@ void init(rack::Plugin *p) {
p->addModel(modelArp);
p->addModel(modelAssign);
p->addModel(modelUnison);
- p->addModel(modelPolyCon16);
p->addModel(modelPolyCon8);
+ p->addModel(modelPolyCon16);
+ p->addModel(modelPolyOff8);
+ p->addModel(modelPolyOff16);
p->addModel(modelPolyMult);
p->addModel(modelBool);