BogaudioModules

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

commit 101deccadf1aec5fe2a7bb2a8e7a2388384d7ce5
parent 585f917e5fd8f0b284b5f3f50062d01f97b49618
Author: Matt Demanett <matt@demanett.net>
Date:   Sat, 16 Mar 2019 21:17:15 -0400

Work-in-progress random walk modules.

Diffstat:
Ares-src/Walk-src.svg | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares-src/Walk2-src.svg | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares/Walk.svg | 0
Ares/Walk2.svg | 0
Msrc/Test.cpp | 36++++++++++++++++++++++++++++++++++++
Msrc/Test.hpp | 18+++++++++++++++++-
Asrc/Walk.cpp | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Walk.hpp | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Walk2.cpp | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Walk2.hpp | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/bogaudio.cpp | 7+++++++
Msrc/dsp/buffer.hpp | 9+++------
Msrc/dsp/filter.hpp | 8+++++++-
Msrc/dsp/noise.cpp | 30++++++++++++++++++++++++++++++
Msrc/dsp/noise.hpp | 30+++++++++++++++++++++++++++++-
15 files changed, 1041 insertions(+), 9 deletions(-)

diff --git a/res-src/Walk-src.svg b/res-src/Walk-src.svg @@ -0,0 +1,172 @@ +<svg + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="45" + height="380" + viewBox="0 0 45 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-medium" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="-5,0 5,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-5 0,5" stroke-width="1" stroke="#00f" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knob-smallest" viewBox="0 0 16px 16px"> + <g transform="translate(8 8)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle r="7.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knobguide-change" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="0,0 4,0" stroke-width="1.0" stroke="#333" transform="rotate(-240) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-210) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-180) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-150) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-120) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-90) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-60) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-30) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(0) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(30) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(60) translate(17 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="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-small" viewBox="0 0 6.4px 6.4px"> + <rect width="6.4" height="6.4" fill="#0f0" /> + </symbol> + </defs> + + <rect width="100%" height="100%" fill="#ddd" /> + <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" /> + <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" /> + <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> + + <g transform="rotate(-90) translate(-376 13)"> + <text class="title" font-size="7pt" letter-spacing="2.5px">WALK</text> + <g transform="translate(0 12)"> + <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text> + <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" /> + </g> + </g> + + <!-- <polyline points="0,0 0,300" stroke="#0f0" stroke-width="1" fill="none" transform="translate(22.5 0)" /> --> + + <g transform="translate(0 25)"> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(10 0)">RATE</text> + <use id="RATE_PARAM" xlink:href="#knob-medium" transform="translate(0 3)" /> + <use xlink:href="#knobguide-change" transform="translate(0 3)" /> + <g transform="translate(5.5 49)"> + <rect width="34" height="39" rx="5" fill="#fafafa" /> + <use id="RATE_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(11 35)">CV</text> + </g> + </g> + + <g transform="translate(0 128)"> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(4.5 0)">OFFSET</text> + <use id="OFFSET_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 9)" /> + <use xlink:href="#knobguide-centertick" transform="translate(2.5 -3)" /> + </g> + + <g transform="translate(0 169)"> + <text font-size="6pt" letter-spacing="2.0px" transform="translate(5.5 0)">SCALE</text> + <use id="SCALE_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 9)" /> + <use xlink:href="#knobguide-maxtick" transform="translate(2.5 -3)" /> + </g> + + <g transform="translate(0 202)"> + <g transform="translate(0 5)"> + <g transform="translate(5.5 0)"> + <rect width="34" height="10" fill="#fafafa" transform="translate(0 78)" /> + <rect width="34" height="82" rx="5" fill="#fafafa" /> + <use id="HOLD_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(5.5 35)">GATE</text> + </g> + </g> + + <g transform="translate(0 5)"> + <g transform="translate(7 41)"> + <use id="TRACK_PARAM" xlink:href="#button-small" transform="translate(22 -1.3)" /> + <use id="TRACK_LIGHT" xlink:href="#light-small" transform="translate(0 0)" /> + <text font-size="5pt" letter-spacing="0.5px" transform="translate(7.3 5.5)">TRK</text> + </g> + + <g transform="translate(5.5 54)"> + <rect width="34" height="10" fill="#bbb" transform="translate(0 -3)" /> + <rect width="34" height="70" rx="5" fill="#bbb" /> + <use id="HOLD_OUTPUT" xlink:href="#output" transform="translate(5 0)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(5.8 32)">HOLD</text> + <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 35)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(8.3 67)">OUT</text> + </g> + </g> + </g> +</svg> diff --git a/res-src/Walk2-src.svg b/res-src/Walk2-src.svg @@ -0,0 +1,239 @@ +<svg + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="210" + height="380" + viewBox="0 0 210 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="display" viewBox="0 0 190px 190px"> + <rect cx="0" cy="0" width="190" height="190" fill="#222" /> + </symbol> + + <symbol id="knob-medium" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="-5,0 5,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-5 0,5" stroke-width="1" stroke="#00f" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knob-smallest" viewBox="0 0 16px 16px"> + <g transform="translate(8 8)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle r="7.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knobguide-change" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="0,0 4,0" stroke-width="1.0" stroke="#333" transform="rotate(-240) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-210) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-180) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-150) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-120) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-90) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-60) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-30) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(0) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(30) translate(17 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(60) translate(17 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="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-small" viewBox="0 0 6.4px 6.4px"> + <rect width="6.4" height="6.4" fill="#0f0" /> + </symbol> + </defs> + + <rect width="100%" height="100%" fill="#ddd" /> + <polyline points="1,1 209,1 209,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" /> + <polyline points="0.5,0.5 209.5,0.5 209.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" /> + <polyline points="0,0 210,0 210,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> + + <!-- <rect width="70" height="20" fill="#0f0" transform="translate(0 0)" /> --> + <!-- <rect width="70" height="20" fill="#0f0" transform="translate(140 0)" /> --> + <!-- <rect width="65" height="20" fill="#0f0" transform="translate(0 360)" /> --> + <!-- <rect width="65" height="20" fill="#0f0" transform="translate(145 360)" /> --> + <text class="title" x="69" y="19" font-size="12pt" letter-spacing="4px">WALK2</text> + <g transform="translate(65 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> + + <!-- <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(54.5 0)" /> --> + <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(105 0)" /> --> + <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(154.5 0)" /> --> + <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(200 0)" /> --> + <!-- <polyline points="0,0 210,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 259)" /> --> + <!-- <polyline points="0,0 210,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 254.5)" /> --> + <!-- <polyline points="0,0 210,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 296)" /> --> + <!-- <polyline points="0,0 210,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 320.5)" /> --> + + <g transform="translate(10 25)"> + <use id="DISPLAY_WIDGET" xlink:href="#display" /> + </g> + + <g transform="translate(0 227)"> + <g transform="translate(6 0)"> + <text font-size="8pt" transform="translate(45 0)">X</text> + <polyline points="0,0 30,0" stroke="#333" stroke-width="1" fill="none" transform="translate(13 -4)" /> + <polyline points="0,0 30,0" stroke="#333" stroke-width="1" fill="none" transform="translate(53 -4)" /> + </g> + <g transform="translate(111 0)"> + <text font-size="8pt" transform="translate(40 0)">Y</text> + <polyline points="0,0 30,0" stroke="#333" stroke-width="1" fill="none" transform="translate(8 -4)" /> + <polyline points="0,0 30,0" stroke="#333" stroke-width="1" fill="none" transform="translate(48 -4)" /> + </g> + </g> + + <g transform="translate(12 235)"> + <g transform="translate(-2 0)"> + <text font-size="7pt" letter-spacing="1.5px" transform="translate(9 33.5) rotate(270)">RATE</text> + <use id="RATE_X_PARAM" xlink:href="#knob-medium" transform="translate(10 -3)" /> + </g> + <use xlink:href="#knobguide-change" transform="translate(8 -3)" /> + </g> + + <g transform="translate(145.5 235)"> + <g transform="translate(-2 0)"> + <text font-size="7pt" letter-spacing="1.5px" transform="translate(47 5) rotate(90)">RATE</text> + <use id="RATE_Y_PARAM" xlink:href="#knob-medium" transform="translate(0 -3)" /> + </g> + <use xlink:href="#knobguide-change" transform="translate(-2 -3)" /> + </g> + + <g transform="translate(105 234)"> + <text font-size="7pt" letter-spacing="2px" transform="translate(3.3 17) rotate(270)">OFF</text> + + <use id="OFFSET_X_PARAM" xlink:href="#knob-smallest" transform="translate(-30 0)" /> + <use xlink:href="#knobguide-centertick" transform="translate(-42 -12)" /> + + <use id="OFFSET_Y_PARAM" xlink:href="#knob-smallest" transform="translate(14 0)" /> + <use xlink:href="#knobguide-centertick" transform="translate(2 -12)" /> + </g> + + <g transform="translate(105 262.5)"> + <text font-size="7pt" letter-spacing="2px" transform="translate(3.3 17) rotate(270)">SCL</text> + + <use id="SCALE_X_PARAM" xlink:href="#knob-smallest" transform="translate(-30 0)" /> + <use xlink:href="#knobguide-maxtick" transform="translate(-42 -12)" /> + + <use id="SCALE_Y_PARAM" xlink:href="#knob-smallest" transform="translate(14 0)" /> + <use xlink:href="#knobguide-maxtick" transform="translate(2 -12)" /> + </g> + + <g transform="translate(0 292)"> + <g transform="translate(72 0)"> + <use id="TRACK_X_PARAM" xlink:href="#button-small" transform="translate(22 -1.3)" /> + <use id="TRACK_X_LIGHT" xlink:href="#light-small" transform="translate(0 0)" /> + <text font-size="5pt" letter-spacing="0.5px" transform="translate(7.3 5.5)">TRK</text> + </g> + <g transform="translate(109 0)"> + <use id="TRACK_Y_PARAM" xlink:href="#button-small" transform="translate(22 -1.3)" /> + <use id="TRACK_Y_LIGHT" xlink:href="#light-small" transform="translate(0 0)" /> + <text font-size="5pt" letter-spacing="0.5px" transform="translate(7.3 5.5)">TRK</text> + </g> + </g> + + <g transform="translate(7 281)"> + <rect width="61" height="79" rx="5" fill="#fafafa" /> + <rect width="22" height="79" rx="5" fill="#bbb" transform="translate(40)" /> + <rect width="20" height="79" fill="#bbb" transform="translate(31)" /> + <use id="HOLD_X_INPUT" xlink:href="#input" transform="translate(3.5 3)" /> + <use id="HOLD_X_OUTPUT" xlink:href="#output" transform="translate(34.5 3)" /> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(2 36)">GATE</text> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(35.5 36)">HOLD</text> + <use id="RATE_X_INPUT" xlink:href="#input" transform="translate(3.5 42)" /> + <use id="OUT_X_OUTPUT" xlink:href="#output" transform="translate(34.5 42)" /> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(3.5 75)">RATE</text> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(37 75)">OUT</text> + </g> + + <g transform="translate(142 281)"> + <rect width="61" height="79" rx="5" fill="#fafafa" /> + <rect width="22" height="79" rx="5" fill="#bbb" transform="translate(40)" /> + <rect width="20" height="79" fill="#bbb" transform="translate(31)" /> + <use id="HOLD_Y_INPUT" xlink:href="#input" transform="translate(3.5 3)" /> + <use id="HOLD_Y_OUTPUT" xlink:href="#output" transform="translate(34.5 3)" /> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(2 36)">GATE</text> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(35.5 36)">HOLD</text> + <use id="RATE_Y_INPUT" xlink:href="#input" transform="translate(3.5 42)" /> + <use id="OUT_Y_OUTPUT" xlink:href="#output" transform="translate(34.5 42)" /> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(3.5 75)">RATE</text> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(37 75)">OUT</text> + </g> + + <g transform="translate(74.5 310)"> + <rect width="61" height="40" rx="5" fill="#fafafa" /> + <rect width="22" height="40" rx="5" fill="#bbb" transform="translate(40)" /> + <rect width="20" height="40" fill="#bbb" transform="translate(31)" /> + <use id="JUMP_INPUT" xlink:href="#input" transform="translate(3.5 3)" /> + <use id="DISTANCE_OUTPUT" xlink:href="#output" transform="translate(34.5 3)" /> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(2 36)">JUMP</text> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(35.5 36)">DIST</text> + </g> +</svg> diff --git a/res/Walk.svg b/res/Walk.svg Binary files differ. diff --git a/res/Walk2.svg b/res/Walk2.svg Binary files differ. diff --git a/src/Test.cpp b/src/Test.cpp @@ -409,6 +409,42 @@ void Test::step() { float in = inputs[IN_INPUT].value; outputs[OUT_OUTPUT].value = _saturator.next(in); outputs[OUT2_OUTPUT].value = clamp(in, -Saturator::limit, Saturator::limit); + +#elif BROWNIAN + const float maxDiv = 1000.0f; + float change = clamp(1.0f - params[PARAM1_PARAM].value, 0.01f, 1.0f); + float smooth = clamp(params[PARAM2_PARAM].value, 0.01f, 1.0f); + smooth *= smooth; + _filter1.setParams(engineGetSampleRate(), smooth * engineGetSampleRate() * 0.49f); + _filter2.setParams(engineGetSampleRate(), smooth * engineGetSampleRate() * 0.49f); + + _last1 = _last1 + _noise1.next() / (change * maxDiv); + outputs[OUT_OUTPUT].value = _filter1.next(_last1); + if (_last1 > 5.0f || _last1 < -5.0f) { + _last1 = 0.0f; + } + + _last2 = _last2 + _noise1.next() / (change * maxDiv); + outputs[OUT2_OUTPUT].value = _filter2.next(_last2); + if (_last2 > 5.0f || _last2 < -5.0f) { + _last2 = 0.0f; + } + + // // "leaky integrator" + // float alpha = params[PARAM1_PARAM].value; + // alpha = clamp(1.0f - alpha*alpha, 0.00001f, 1.0f); + // float sample = 5.0f * _noise1.next(); + // _last1 = alpha*_last1 + (1.0f - alpha)*sample; + // outputs[OUT_OUTPUT].value = _last1; + +#elif RANDOMWALK + float change = params[PARAM1_PARAM].value; + change *= change; + change *= change; + _walk1.setParams(engineGetSampleRate(), change); + _walk2.setParams(engineGetSampleRate(), change); + outputs[OUT_OUTPUT].value = _walk1.next(); + outputs[OUT2_OUTPUT].value = _walk2.next(); #endif } diff --git a/src/Test.hpp b/src/Test.hpp @@ -17,7 +17,7 @@ extern Model* modelTest; // #define OVERSAMPLED_BL 1 // #define ANTIALIASING 1 // #define DECIMATORS 1 -#define INTERPOLATOR 1 +// #define INTERPOLATOR 1 // #define FM 1 // #define PM 1 // #define FEEDBACK_PM 1 @@ -27,6 +27,8 @@ extern Model* modelTest; // #define RMS 1 // #define RAVG 1 // #define SATURATOR 1 +// #define BROWNIAN 1 +#define RANDOMWALK 1 #include "pitch.hpp" #ifdef LPF @@ -86,6 +88,10 @@ extern Model* modelTest; #elif SATURATOR #include "dsp/oscillator.hpp" #include "dsp/signal.hpp" +#elif BROWNIAN +#include "dsp/noise.hpp" +#elif RANDOMWALK +#include "dsp/noise.hpp" #else #error what #endif @@ -215,6 +221,16 @@ struct Test : Module { Trigger _reset; #elif SATURATOR Saturator _saturator; +#elif BROWNIAN + WhiteNoiseGenerator _noise1; + GaussianNoiseGenerator _noise2; + LowPassFilter _filter1; + LowPassFilter _filter2; + float _last1 = 0.0f; + float _last2 = 0.0f; +#elif RANDOMWALK + RandomWalk _walk1; + RandomWalk _walk2; #endif Test() diff --git a/src/Walk.cpp b/src/Walk.cpp @@ -0,0 +1,87 @@ + +#include "Walk.hpp" + +void Walk::onReset() { + _trigger.reset(); + _modulationStep = modulationSteps; +} + +void Walk::onSampleRateChange() { + _modulationStep = modulationSteps; +} + +void Walk::step() { + lights[TRACK_LIGHT].value = params[TRACK_PARAM].value; + + ++_modulationStep; + if (_modulationStep >= modulationSteps) { + _modulationStep = 0; + + float rate = params[RATE_PARAM].value; + if (inputs[RATE_INPUT].active) { + rate *= clamp(inputs[RATE_INPUT].value / 10.0f, 0.0f, 1.0f); + } + rate *= rate; + rate *= rate; + _walk.setParams(engineGetSampleRate(), rate); + } + + float out = _walk.next(); + out *= params[SCALE_PARAM].value; + out += params[OFFSET_PARAM].value * 5.0f; + outputs[OUT_OUTPUT].value = out; + + bool triggered = _trigger.process(inputs[HOLD_INPUT].value); + if (params[TRACK_PARAM].value > 0.5f ? _trigger.isHigh() : triggered) { + _hold = out; + } + outputs[HOLD_OUTPUT].value = _hold; +} + +struct WalkWidget : ModuleWidget { + static constexpr int hp = 3; + + WalkWidget(Walk* module) : ModuleWidget(module) { + box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Walk.svg"))); + addChild(panel); + } + + addChild(Widget::create<ScrewSilver>(Vec(0, 0))); + addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365))); + + // generated by svg_widgets.rb + auto rateParamPosition = Vec(8.0, 36.0); + auto offsetParamPosition = Vec(14.5, 137.0); + auto scaleParamPosition = Vec(14.5, 178.0); + auto trackParamPosition = Vec(29.0, 246.7); + + auto rateInputPosition = Vec(10.5, 77.0); + auto holdInputPosition = Vec(10.5, 210.0); + + auto holdOutputPosition = Vec(10.5, 261.0); + auto outOutputPosition = Vec(10.5, 296.0); + + auto trackLightPosition = Vec(7.0, 248.0); + // end generated by svg_widgets.rb + + addParam(ParamWidget::create<Knob29>(rateParamPosition, module, Walk::RATE_PARAM, 0.0, 1.0, 0.1)); + addParam(ParamWidget::create<Knob16>(offsetParamPosition, module, Walk::OFFSET_PARAM, -1.0, 1.0, 0.0)); + addParam(ParamWidget::create<Knob16>(scaleParamPosition, module, Walk::SCALE_PARAM, 0.0, 1.0, 1.0)); + addParam(ParamWidget::create<StatefulButton9>(trackParamPosition, module, Walk::TRACK_PARAM, 0.0, 1.0, 0.0)); + + addInput(Port::create<Port24>(rateInputPosition, Port::INPUT, module, Walk::RATE_INPUT)); + addInput(Port::create<Port24>(holdInputPosition, Port::INPUT, module, Walk::HOLD_INPUT)); + + addOutput(Port::create<Port24>(holdOutputPosition, Port::OUTPUT, module, Walk::HOLD_OUTPUT)); + addOutput(Port::create<Port24>(outOutputPosition, Port::OUTPUT, module, Walk::OUT_OUTPUT)); + + addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(trackLightPosition, module, Walk::TRACK_LIGHT)); + } +}; + +Model* modelWalk = createModel<Walk, WalkWidget>("Bogaudio-Walk", "Walk", "random-walk CV source", RANDOM_TAG); diff --git a/src/Walk.hpp b/src/Walk.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "bogaudio.hpp" +#include "dsp/noise.hpp" + +using namespace bogaudio::dsp; + +extern Model* modelWalk; + +namespace bogaudio { + +struct Walk : Module { + enum ParamsIds { + RATE_PARAM, + OFFSET_PARAM, + SCALE_PARAM, + TRACK_PARAM, + NUM_PARAMS + }; + + enum InputsIds { + RATE_INPUT, + HOLD_INPUT, + NUM_INPUTS + }; + + enum OutputsIds { + HOLD_OUTPUT, + OUT_OUTPUT, + NUM_OUTPUTS + }; + + enum LightsIds { + TRACK_LIGHT, + NUM_LIGHTS + }; + + const int modulationSteps = 100; + int _modulationStep = 0; + Trigger _trigger; + RandomWalk _walk; + float _hold = 0.0f; + + Walk() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + onReset(); + } + + void onReset() override; + void onSampleRateChange() override; + void step() override; +}; + +} // namespace bogaudio diff --git a/src/Walk2.cpp b/src/Walk2.cpp @@ -0,0 +1,281 @@ + +#include "Walk2.hpp" + +void Walk2::onReset() { + _triggerX.reset(); + _triggerY.reset(); + _jumpTrigger.reset(); + _modulationStep = modulationSteps; +} + +void Walk2::onSampleRateChange() { + _modulationStep = modulationSteps; + _historySteps = (historySeconds * engineGetSampleRate()) / historyPoints; +} + +void Walk2::step() { + lights[TRACK_X_LIGHT].value = params[TRACK_X_PARAM].value; + lights[TRACK_Y_LIGHT].value = params[TRACK_Y_PARAM].value; + + ++_modulationStep; + if (_modulationStep >= modulationSteps) { + _modulationStep = 0; + + float rateX = params[RATE_X_PARAM].value; + if (inputs[RATE_X_INPUT].active) { + rateX *= clamp(inputs[RATE_X_INPUT].value / 10.0f, 0.0f, 1.0f); + } + rateX *= rateX; + rateX *= rateX; + _walkX.setParams(engineGetSampleRate(), rateX); + + float rateY = params[RATE_Y_PARAM].value; + if (inputs[RATE_Y_INPUT].active) { + rateY *= clamp(inputs[RATE_Y_INPUT].value / 10.0f, 0.0f, 1.0f); + } + rateY *= rateY; + rateY *= rateY; + _walkY.setParams(engineGetSampleRate(), rateY); + } + + if (_jumpTrigger.process(inputs[JUMP_INPUT].value)) { + _walkX.jump(); + _walkY.jump(); + } + + float outX = _walkX.next(); + outX *= params[SCALE_X_PARAM].value; + outX += params[OFFSET_X_PARAM].value * 5.0f; + outputs[OUT_X_OUTPUT].value = outX; + + bool triggeredX = _triggerX.process(inputs[HOLD_X_INPUT].value); + if (params[TRACK_X_PARAM].value > 0.5f ? _triggerX.isHigh() : triggeredX) { + _holdX = outX; + } + outputs[HOLD_X_OUTPUT].value = _holdX; + + float outY = _walkY.next(); + outY *= params[SCALE_Y_PARAM].value; + outY += params[OFFSET_Y_PARAM].value * 5.0f; + outputs[OUT_Y_OUTPUT].value = outY; + + bool triggeredY = _triggerY.process(inputs[HOLD_Y_INPUT].value); + if (params[TRACK_Y_PARAM].value > 0.5f ? _triggerY.isHigh() : triggeredY) { + _holdY = outY; + } + outputs[HOLD_Y_OUTPUT].value = _holdY; + + outputs[DISTANCE_OUTPUT].value = sqrtf(outX*outX + outY*outY) * 0.707107f; // scaling constant is 10 / squrt(200) + + if (_historyStep == 0) { + _outsX.push(outX); + _holdsX.push(_holdX); + _outsY.push(outY); + _holdsY.push(_holdY); + } + _historyStep = ++_historyStep % _historySteps; +} + +struct Walk2Display : TransparentWidget { + const int _insetAround = 4; + + const NVGcolor _axisColor = nvgRGBA(0xff, 0xff, 0xff, 0x70); + const NVGcolor _textColor = nvgRGBA(0xff, 0xff, 0xff, 0xc0); + const NVGcolor _traceColor = nvgRGBA(0xff, 0x00, 0x00, 0xd0); + const NVGcolor _holdColor = nvgRGBA(0x00, 0xff, 0x00, 0xd0); + + Walk2* _module; + const Vec _size; + const Vec _drawSize; + int _midX, _midY; + std::shared_ptr<Font> _font; + + Walk2Display( + Walk2* module, + Vec size + ) + : _module(module) + , _size(size) + , _drawSize(_size.x - 2*_insetAround, _size.y - 2*_insetAround) + , _midX(_size.x / 2) + , _midY(_size.y / 2) + , _font(Font::load(assetPlugin(plugin, "res/fonts/inconsolata.ttf"))) + { + } + + void draw(NVGcontext* vg) override { + drawBackground(vg); + float strokeWidth = std::max(1.0f, 3 - gRackScene->zoomWidget->zoom); + + nvgSave(vg); + nvgScissor(vg, _insetAround, _insetAround, _size.x - _insetAround, _size.y - _insetAround); + drawAxes(vg, strokeWidth); + drawTrace(vg, _traceColor, _module->_outsX, _module->_outsY); + drawTrace(vg, _holdColor, _module->_holdsX, _module->_holdsY); + nvgRestore(vg); + } + + void drawBackground(NVGcontext* vg) { + nvgSave(vg); + nvgBeginPath(vg); + nvgRect(vg, 0, 0, _size.x, _size.y); + nvgFillColor(vg, nvgRGBA(0x00, 0x00, 0x00, 0xff)); + nvgFill(vg); + nvgStrokeColor(vg, nvgRGBA(0xc0, 0xc0, 0xc0, 0xff)); + nvgStroke(vg); + nvgRestore(vg); + } + + void drawAxes(NVGcontext* vg, float strokeWidth) { + nvgSave(vg); + nvgStrokeColor(vg, _axisColor); + nvgStrokeWidth(vg, strokeWidth); + + nvgBeginPath(vg); + nvgMoveTo(vg, _insetAround, _midY); + nvgLineTo(vg, _size.x - _insetAround, _midY); + nvgStroke(vg); + + nvgBeginPath(vg); + nvgMoveTo(vg, _midX, _insetAround); + nvgLineTo(vg, _midX, _size.y - _insetAround); + nvgStroke(vg); + + nvgRestore(vg); + } + + void drawTrace(NVGcontext* vg, NVGcolor color, HistoryBuffer<float>& x, HistoryBuffer<float>& y) { + nvgSave(vg); + nvgGlobalCompositeOperation(vg, NVG_LIGHTER); + + // int n = _module->historyPoints; + // float beginRadius = std::max(1.0f, 2.0f - gRackScene->zoomWidget->zoom); + // float endRadius = std::max(0.01f, 0.8f - gRackScene->zoomWidget->zoom); + // float radiusStep = (beginRadius - endRadius) / (float)n; + // float radius = beginRadius; + // float alphaStep = (color.a - 0.1f) / (float)n; + // for (int i = 0; i < n; ++i) { + // nvgBeginPath(vg); + // nvgCircle(vg, cvToPixel(_midX, _drawSize.x, x.value(i)), cvToPixel(_midY, _drawSize.y, y.value(i)), radius); + // nvgStrokeColor(vg, color); + // nvgFillColor(vg, color); + // nvgStroke(vg); + // nvgFill(vg); + // radius -= radiusStep; + // color.a -= alphaStep; + // } + + int n = _module->historyPoints; + float beginWidth = std::max(1.0f, 4.0f - gRackScene->zoomWidget->zoom); + float endWidth = std::max(0.5f, 2.0f - gRackScene->zoomWidget->zoom); + float widthStep = (beginWidth - endWidth) / (float)n; + float width = endWidth; + float endAlpha = 0.1f; + float alphaStep = (color.a - endAlpha) / (float)n; + color.a = endAlpha; + for (int i = n - 1; i > 0; --i) { + nvgBeginPath(vg); + nvgMoveTo(vg, cvToPixel(_midX, _drawSize.x, x.value(i - 1)), cvToPixel(_midY, _drawSize.y, y.value(i - 1))); + nvgLineTo(vg, cvToPixel(_midX, _drawSize.x, x.value(i)), cvToPixel(_midY, _drawSize.y, y.value(i))); + nvgStrokeWidth(vg, width); + nvgStrokeColor(vg, color); + nvgStroke(vg); + width += widthStep; + color.a += alphaStep; + } + nvgBeginPath(vg); + nvgCircle(vg, cvToPixel(_midX, _drawSize.x, x.value(0)), cvToPixel(_midY, _drawSize.y, y.value(0)), 0.5f * width); + nvgStrokeColor(vg, color); + nvgFillColor(vg, color); + nvgStroke(vg); + nvgFill(vg); + + nvgRestore(vg); + } + + inline float cvToPixel(float mid, float extent, float cv) { + return mid + 0.1f * extent * cv; + } +}; + +struct Walk2Widget : ModuleWidget { + static constexpr int hp = 14; + + Walk2Widget(Walk2* module) : ModuleWidget(module) { + box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Walk2.svg"))); + addChild(panel); + } + + { + auto inset = Vec(10, 25); + int dim = box.size.x - 2*inset.x; + auto size = Vec(dim, dim); + auto display = new Walk2Display(module, size); + display->box.pos = inset; + display->box.size = size; + addChild(display); + } + + addChild(Widget::create<ScrewSilver>(Vec(15, 0))); + addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0))); + addChild(Widget::create<ScrewSilver>(Vec(15, 365))); + addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365))); + + // generated by svg_widgets.rb + auto rateXParamPosition = Vec(28.0, 240.0); + auto rateYParamPosition = Vec(151.5, 240.0); + auto offsetXParamPosition = Vec(75.0, 234.0); + auto offsetYParamPosition = Vec(119.0, 234.0); + auto scaleXParamPosition = Vec(75.0, 262.5); + auto scaleYParamPosition = Vec(119.0, 262.5); + auto trackXParamPosition = Vec(94.0, 290.7); + auto trackYParamPosition = Vec(131.0, 290.7); + + auto holdXInputPosition = Vec(10.5, 284.0); + auto rateXInputPosition = Vec(10.5, 323.0); + auto holdYInputPosition = Vec(145.5, 284.0); + auto rateYInputPosition = Vec(145.5, 323.0); + auto jumpInputPosition = Vec(78.0, 313.0); + + auto holdXOutputPosition = Vec(41.5, 284.0); + auto outXOutputPosition = Vec(41.5, 323.0); + auto holdYOutputPosition = Vec(176.5, 284.0); + auto outYOutputPosition = Vec(176.5, 323.0); + auto distanceOutputPosition = Vec(109.0, 313.0); + + auto trackXLightPosition = Vec(72.0, 292.0); + auto trackYLightPosition = Vec(109.0, 292.0); + // end generated by svg_widgets.rb + + addParam(ParamWidget::create<Knob29>(rateXParamPosition, module, Walk2::RATE_X_PARAM, 0.0, 1.0, 0.1)); + addParam(ParamWidget::create<Knob29>(rateYParamPosition, module, Walk2::RATE_Y_PARAM, 0.0, 1.0, 0.1)); + addParam(ParamWidget::create<Knob16>(offsetXParamPosition, module, Walk2::OFFSET_X_PARAM, -1.0, 1.0, 0.0)); + addParam(ParamWidget::create<Knob16>(offsetYParamPosition, module, Walk2::OFFSET_Y_PARAM, -1.0, 1.0, 0.0)); + addParam(ParamWidget::create<Knob16>(scaleXParamPosition, module, Walk2::SCALE_X_PARAM, 0.0, 1.0, 1.0)); + addParam(ParamWidget::create<Knob16>(scaleYParamPosition, module, Walk2::SCALE_Y_PARAM, 0.0, 1.0, 1.0)); + addParam(ParamWidget::create<StatefulButton9>(trackXParamPosition, module, Walk2::TRACK_X_PARAM, 0.0, 1.0, 0.0)); + addParam(ParamWidget::create<StatefulButton9>(trackYParamPosition, module, Walk2::TRACK_Y_PARAM, 0.0, 1.0, 0.0)); + + addInput(Port::create<Port24>(holdXInputPosition, Port::INPUT, module, Walk2::HOLD_X_INPUT)); + addInput(Port::create<Port24>(rateXInputPosition, Port::INPUT, module, Walk2::RATE_X_INPUT)); + addInput(Port::create<Port24>(holdYInputPosition, Port::INPUT, module, Walk2::HOLD_Y_INPUT)); + addInput(Port::create<Port24>(rateYInputPosition, Port::INPUT, module, Walk2::RATE_Y_INPUT)); + addInput(Port::create<Port24>(jumpInputPosition, Port::INPUT, module, Walk2::JUMP_INPUT)); + + addOutput(Port::create<Port24>(holdXOutputPosition, Port::OUTPUT, module, Walk2::HOLD_X_OUTPUT)); + addOutput(Port::create<Port24>(outXOutputPosition, Port::OUTPUT, module, Walk2::OUT_X_OUTPUT)); + addOutput(Port::create<Port24>(holdYOutputPosition, Port::OUTPUT, module, Walk2::HOLD_Y_OUTPUT)); + addOutput(Port::create<Port24>(outYOutputPosition, Port::OUTPUT, module, Walk2::OUT_Y_OUTPUT)); + addOutput(Port::create<Port24>(distanceOutputPosition, Port::OUTPUT, module, Walk2::DISTANCE_OUTPUT)); + + addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(trackXLightPosition, module, Walk2::TRACK_X_LIGHT)); + addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(trackYLightPosition, module, Walk2::TRACK_Y_LIGHT)); + } +}; + +Model* modelWalk2 = createModel<Walk2, Walk2Widget>("Bogaudio-Walk2", "Walk2", ""); diff --git a/src/Walk2.hpp b/src/Walk2.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include "bogaudio.hpp" +#include "dsp/buffer.hpp" +#include "dsp/noise.hpp" + +using namespace bogaudio::dsp; + +extern Model* modelWalk2; + +namespace bogaudio { + +struct Walk2 : Module { + enum ParamsIds { + RATE_X_PARAM, + RATE_Y_PARAM, + OFFSET_X_PARAM, + OFFSET_Y_PARAM, + SCALE_X_PARAM, + SCALE_Y_PARAM, + TRACK_X_PARAM, + TRACK_Y_PARAM, + NUM_PARAMS + }; + + enum InputsIds { + HOLD_X_INPUT, + RATE_X_INPUT, + HOLD_Y_INPUT, + RATE_Y_INPUT, + JUMP_INPUT, + NUM_INPUTS + }; + + enum OutputsIds { + HOLD_X_OUTPUT, + OUT_X_OUTPUT, + HOLD_Y_OUTPUT, + OUT_Y_OUTPUT, + DISTANCE_OUTPUT, + NUM_OUTPUTS + }; + + enum LightsIds { + TRACK_X_LIGHT, + TRACK_Y_LIGHT, + NUM_LIGHTS + }; + + const int modulationSteps = 100; + int _modulationStep = 0; + + const float historySeconds = 1.0f; + const int historyPoints = 100; + int _historySteps; + int _historyStep = 0; + + Trigger _triggerX, _triggerY; + RandomWalk _walkX, _walkY; + Trigger _jumpTrigger; + float _holdX = 0.0f, _holdY = 0.0f; + HistoryBuffer<float> _outsX, _outsY, _holdsX, _holdsY; + + Walk2() + : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) + , _outsX(historyPoints, 0.0f) + , _outsY(historyPoints, 0.0f) + , _holdsX(historyPoints, 0.0f) + , _holdsY(historyPoints, 0.0f) + { + onReset(); + onSampleRateChange(); + } + + void onReset() override; + void onSampleRateChange() override; + void step() override; +}; + +} // namespace bogaudio diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp @@ -50,6 +50,8 @@ #include "VCM.hpp" #include "VCO.hpp" #include "VU.hpp" +#include "Walk.hpp" +#include "Walk2.hpp" #include "XCO.hpp" #include "XFade.hpp" @@ -86,6 +88,11 @@ void init(rack::Plugin *p) { p->addModel(modelADSR); p->addModel(modelFollow); +#ifdef EXPERIMENTAL + p->addModel(modelWalk2); + p->addModel(modelWalk); +#endif + p->addModel(modelMix4); p->addModel(modelMix8); p->addModel(modelVCM); diff --git a/src/dsp/buffer.hpp b/src/dsp/buffer.hpp @@ -134,7 +134,7 @@ struct HistoryBuffer { HistoryBuffer(int size, T initialValue) : _size(size) - , _i(size) + , _i(0) { assert(size > 0); _buf = new T[size]; @@ -145,15 +145,12 @@ struct HistoryBuffer { } inline void push(T s) { - ++_i; - if (_i >= _size) { - _i = 0; - } + _i = ++_i % _size; _buf[_i] = s; } inline T value(int i) { - assert(i <= 0 && -i <= _size); + assert(i >= 0 && i < _size); int j = _i - i; if (j < 0) { j += _size; diff --git a/src/dsp/filter.hpp b/src/dsp/filter.hpp @@ -45,6 +45,11 @@ struct BiquadFilter : Filter { } } + void reset() { + _x[0] = _x[1] = _x[2] = 0.0; + _y[0] = _y[1] = _y[2] = 0.0; + } + float next(float sample) override { _x[2] = _x[1]; _x[1] = _x[0]; @@ -94,7 +99,8 @@ struct LowPassFilter : Filter { setParams(sampleRate, cutoff, q); } - void setParams(float sampleRate, float cutoff, float q); + void setParams(float sampleRate, float cutoff, float q = 0.001f); + void reset() { _biquad.reset(); } float next(float sample) override { return _biquad.next(sample); } diff --git a/src/dsp/noise.cpp b/src/dsp/noise.cpp @@ -1,4 +1,6 @@ +#include <algorithm> + #include "noise.hpp" using namespace bogaudio::dsp; @@ -21,3 +23,31 @@ Seeds& Seeds::getInstance() { unsigned int Seeds::next() { return getInstance()._next(); }; + + +void RandomWalk::setParams(float sampleRate, float change) { + assert(sampleRate > 0.0f); + assert(change >= 0.0f); + assert(change <= 1.0f); + + _filter.setParams(sampleRate, std::max(2.0f, change * 0.49f * sampleRate)); + + const float maxDamp = 0.98; + const float minDamp = 0.9999; + _damp = maxDamp + (1 - change)*(minDamp - maxDamp); +} + +void RandomWalk::jump() { + // FIXME + _bias = _noise.next() * 5.0f; + _filter.reset(); +} + +float RandomWalk::_next() { + float delta = _noise.next(); + if ((_lastOut >= _max - _bias && delta > 0.0f) || (_lastOut <= _min - _bias && delta < 0.0f)) { + delta = -delta; + } + _last = _damp*_last + delta; + return _lastOut = std::min(std::max(_bias + _filter.next(_last), _min), _max); +} diff --git a/src/dsp/noise.hpp b/src/dsp/noise.hpp @@ -3,6 +3,7 @@ #include <random> #include "base.hpp" +#include "filter.hpp" namespace bogaudio { namespace dsp { @@ -78,12 +79,39 @@ struct BlueNoiseGenerator : NoiseGenerator { struct GaussianNoiseGenerator : NoiseGenerator { std::normal_distribution<float> _normal; - GaussianNoiseGenerator() : _normal(0, 1.0) {} + GaussianNoiseGenerator(float mean = 0.0f, float stdDev = 1.0f) : _normal(mean, stdDev) {} float _next() override { return _normal(_generator); } }; +struct RandomWalk : Generator { + float _min; + float _max; + float _last = 0.0f; + float _lastOut = 0.0f; + float _damp; + float _bias = 0.0f; + WhiteNoiseGenerator _noise; + LowPassFilter _filter; + + RandomWalk( + float min = -5.0f, + float max = 5.0f, + float sampleRate = 1000.0f, + float change = 0.5f + ) + : _min(min) + , _max(max) + { + setParams(sampleRate, change); + } + + void setParams(float sampleRate = 1000.0f, float change = 0.5f); + void jump(); + float _next() override; +}; + } // namespace dsp } // namespace bogaudio