| @@ -10,14 +10,24 @@ | |||||
| #include <nanosvg.h> | #include <nanosvg.h> | ||||
| /** Remaps Ctrl to Cmd on Mac | |||||
| Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place of Ctrl on Linux/Windows. | |||||
| */ | |||||
| #ifdef ARCH_MAC | #ifdef ARCH_MAC | ||||
| #define WINDOW_MOD GLFW_MOD_SUPER | |||||
| #define WINDOW_MOD_KEY_NAME "Cmd" | |||||
| #define WINDOW_MOD_CTRL GLFW_MOD_SUPER | |||||
| #define WINDOW_MOD_CTRL_NAME "Cmd" | |||||
| #else | #else | ||||
| #define WINDOW_MOD GLFW_MOD_CONTROL | |||||
| #define WINDOW_MOD_KEY_NAME "Ctrl" | |||||
| #define WINDOW_MOD_CTRL GLFW_MOD_CONTROL | |||||
| #define WINDOW_MOD_CTRL_NAME "Ctrl" | |||||
| #endif | #endif | ||||
| /** Filters actual mod keys from the mod flags. | |||||
| Use this if you don't care about GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK. | |||||
| Example usage: | |||||
| if ((e.mod & WINDOW_MOD_MASK) == (WINDOW_MOD | GLFW_MOD_SHIFT)) ... | |||||
| */ | |||||
| #define WINDOW_MOD_MASK (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) | |||||
| namespace rack { | namespace rack { | ||||
| @@ -70,8 +80,10 @@ struct Window { | |||||
| void close(); | void close(); | ||||
| void cursorLock(); | void cursorLock(); | ||||
| void cursorUnlock(); | void cursorUnlock(); | ||||
| bool isModPressed(); | |||||
| bool isShiftPressed(); | |||||
| /** Gets the current keyboard mod state | |||||
| Don't call this from a Key event. Simply use `e.mods` instead. | |||||
| */ | |||||
| int getMods(); | |||||
| math::Vec getWindowSize(); | math::Vec getWindowSize(); | ||||
| void setWindowSize(math::Vec size); | void setWindowSize(math::Vec size); | ||||
| math::Vec getWindowPos(); | math::Vec getWindowPos(); | ||||
| @@ -0,0 +1,249 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
| <svg | |||||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||||
| xmlns:cc="http://creativecommons.org/ns#" | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:svg="http://www.w3.org/2000/svg" | |||||
| xmlns="http://www.w3.org/2000/svg" | |||||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
| width="50.799999mm" | |||||
| height="128.50069mm" | |||||
| viewBox="0 0 50.799999 128.50069" | |||||
| version="1.1" | |||||
| id="svg26618" | |||||
| inkscape:version="0.92.2 2405546, 2018-03-11" | |||||
| sodipodi:docname="CV-CC.svg"> | |||||
| <defs | |||||
| id="defs26612" /> | |||||
| <sodipodi:namedview | |||||
| id="base" | |||||
| pagecolor="#ffffff" | |||||
| bordercolor="#666666" | |||||
| borderopacity="1.0" | |||||
| inkscape:pageopacity="0.0" | |||||
| inkscape:pageshadow="2" | |||||
| inkscape:zoom="1.979899" | |||||
| inkscape:cx="85.567542" | |||||
| inkscape:cy="333.70852" | |||||
| inkscape:document-units="mm" | |||||
| inkscape:current-layer="layer2" | |||||
| showgrid="false" | |||||
| fit-margin-top="0" | |||||
| fit-margin-left="0" | |||||
| fit-margin-right="0" | |||||
| fit-margin-bottom="0" | |||||
| inkscape:snap-bbox="true" | |||||
| inkscape:snap-nodes="false" | |||||
| inkscape:snap-bbox-midpoints="true" | |||||
| inkscape:bbox-nodes="true" | |||||
| inkscape:window-width="1600" | |||||
| inkscape:window-height="882" | |||||
| inkscape:window-x="0" | |||||
| inkscape:window-y="18" | |||||
| inkscape:window-maximized="0" /> | |||||
| <metadata | |||||
| id="metadata26615"> | |||||
| <rdf:RDF> | |||||
| <cc:Work | |||||
| rdf:about=""> | |||||
| <dc:format>image/svg+xml</dc:format> | |||||
| <dc:type | |||||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
| <dc:title></dc:title> | |||||
| </cc:Work> | |||||
| </rdf:RDF> | |||||
| </metadata> | |||||
| <g | |||||
| inkscape:label="Layer 1" | |||||
| inkscape:groupmode="layer" | |||||
| id="layer1" | |||||
| transform="translate(-362.22837,-118.49952)"> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9519" | |||||
| d="m 362.32207,118.59323 h 50.61256 V 246.9065 h -50.61256 z m 0,0" | |||||
| style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9521" | |||||
| d="m 413.02837,118.49952 h -50.8 V 247.0002 h 50.8 z m -0.18743,128.31327 H 362.41439 V 118.68694 h 50.42655 z m 0,0" | |||||
| style="fill:#ababab;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9555" | |||||
| d="m 370.22785,195.95078 h 34.79962" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9557" | |||||
| d="m 370.22785,207.55111 h 34.79962" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9559" | |||||
| d="m 370.22785,219.15143 h 34.79962" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9561" | |||||
| d="m 370.22785,230.75037 h 34.79962" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path12881" | |||||
| d="m 384.87504,242.85644 c -0.11715,0 -0.22323,-0.0661 -0.27562,-0.1695 l -1.00182,-2.00504 c -0.0772,-0.15296 -0.0152,-0.33762 0.13779,-0.41479 0.15159,-0.0758 0.33761,-0.0138 0.41342,0.13918 l 0.72623,1.45245 0.72623,-1.45245 c 0.0758,-0.15296 0.26183,-0.21497 0.41339,-0.13918 0.15296,0.0772 0.21498,0.26183 0.13783,0.41479 l -1.00186,2.00504 c -0.0523,0.10336 -0.15846,0.1695 -0.27559,0.1695" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path12883" | |||||
| d="m 390.38028,242.85644 c -0.11575,0 -0.22324,-0.0661 -0.27559,-0.1695 l -1.00182,-2.00504 c -0.0772,-0.15296 -0.0152,-0.33762 0.1378,-0.41479 0.15159,-0.0758 0.33761,-0.0138 0.41342,0.13918 l 0.72619,1.45245 0.72761,-1.45245 c 0.0758,-0.15296 0.26045,-0.21497 0.41341,-0.13918 0.1516,0.0772 0.21361,0.26183 0.1378,0.41479 l -1.00319,2.00504 c -0.051,0.10336 -0.15847,0.1695 -0.27563,0.1695" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path12885" | |||||
| d="m 387.77717,242.85644 c -0.72207,0 -1.3105,-0.58705 -1.3105,-1.31051 0,-0.72209 0.58843,-1.31052 1.3105,-1.31052 0.28663,0 0.55813,0.091 0.78687,0.26183 0.13642,0.10197 0.16401,0.29628 0.062,0.4327 -0.10336,0.13505 -0.2963,0.16261 -0.43272,0.0606 -0.11987,-0.091 -0.26458,-0.13919 -0.41617,-0.13919 -0.38308,0 -0.69314,0.31145 -0.69314,0.69454 0,0.38309 0.31006,0.69453 0.69314,0.69453 0.15159,0 0.2963,-0.0482 0.41617,-0.13918 0.13642,-0.10198 0.32936,-0.0744 0.43272,0.062 0.10199,0.13505 0.0744,0.32935 -0.062,0.43132 -0.22874,0.17088 -0.50024,0.26183 -0.78687,0.26183" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path12887" | |||||
| d="m 388.19888,241.53077 c 0,0.22186 -0.18055,0.40101 -0.40104,0.40101 -0.22186,0 -0.401,-0.17915 -0.401,-0.40101 0,-0.22186 0.17914,-0.40101 0.401,-0.40101 0.22049,0 0.40104,0.17915 0.40104,0.40101" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 382.2781,128.11472 c 0.47407,0 0.78825,-0.1378 1.05834,-0.36931 0.0551,-0.0551 0.11024,-0.13229 0.11024,-0.23703 0,-0.16536 -0.1433,-0.29765 -0.30868,-0.29765 -0.0771,0 -0.1433,0.0276 -0.19293,0.0717 -0.1874,0.14882 -0.36929,0.23151 -0.64492,0.23151 -0.50711,0 -0.85989,-0.42444 -0.85989,-0.93156 v -0.005 c 0,-0.50711 0.36382,-0.92604 0.85989,-0.92604 0.23153,0 0.42443,0.0772 0.60636,0.21497 0.0496,0.0276 0.1047,0.0606 0.1929,0.0606 0.18192,0 0.32522,-0.13781 0.32522,-0.3142 0,-0.11575 -0.0606,-0.20946 -0.12679,-0.25907 -0.24803,-0.1819 -0.54567,-0.30317 -0.99218,-0.30317 -0.9095,0 -1.54341,0.68903 -1.54341,1.53238 v 0.011 c 0,0.84887 0.64495,1.52135 1.51585,1.52135 z m 0,0" | |||||
| id="path24553" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 385.20172,128.10921 h 0.0441 c 0.17638,0 0.29763,-0.0937 0.36378,-0.25356 l 0.97014,-2.32062 c 0.0166,-0.0386 0.0332,-0.0937 0.0332,-0.14331 0,-0.1819 -0.14334,-0.31419 -0.31972,-0.31419 -0.15434,0 -0.27009,0.0992 -0.31419,0.20395 l -0.74965,1.94027 -0.73861,-1.91823 c -0.0496,-0.13229 -0.15988,-0.22599 -0.33073,-0.22599 -0.18193,0 -0.32523,0.1378 -0.32523,0.3197 0,0.0551 0.0166,0.10473 0.0386,0.15985 l 0.9591,2.29857 c 0.0661,0.15985 0.19293,0.25356 0.36932,0.25356 z m 0,0" | |||||
| id="path24545" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 387.17918,127.0619 h 0.7331 c 0.17089,0 0.31419,-0.1378 0.31419,-0.30868 0,-0.17088 -0.1433,-0.30868 -0.31419,-0.30868 h -0.7331 c -0.17089,0 -0.30868,0.1378 -0.30868,0.30868 0,0.17088 0.13779,0.30868 0.30868,0.30868 z m 0,0" | |||||
| id="path24549" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 390.30112,128.11472 c 0.47406,0 0.78824,-0.1378 1.05833,-0.36931 0.0551,-0.0551 0.11025,-0.13229 0.11025,-0.23703 0,-0.16536 -0.1433,-0.29765 -0.30869,-0.29765 -0.0771,0 -0.14329,0.0276 -0.19293,0.0717 -0.1874,0.14882 -0.36929,0.23151 -0.64491,0.23151 -0.50712,0 -0.8599,-0.42444 -0.8599,-0.93156 v -0.005 c 0,-0.50711 0.36382,-0.92604 0.8599,-0.92604 0.23152,0 0.42442,0.0772 0.60635,0.21497 0.0496,0.0276 0.10471,0.0606 0.1929,0.0606 0.18193,0 0.32522,-0.13781 0.32522,-0.3142 0,-0.11575 -0.0606,-0.20946 -0.12678,-0.25907 -0.24804,-0.1819 -0.54568,-0.30317 -0.99219,-0.30317 -0.9095,0 -1.5434,0.68902 -1.5434,1.53238 v 0.011 c 0,0.84887 0.64495,1.52135 1.51585,1.52135 z m 0,0" | |||||
| id="path24541" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 393.37282,128.11472 c 0.47407,0 0.78825,-0.1378 1.05834,-0.36931 0.0551,-0.0551 0.11024,-0.13229 0.11024,-0.23703 0,-0.16536 -0.1433,-0.29765 -0.30868,-0.29765 -0.0771,0 -0.1433,0.0276 -0.19293,0.0717 -0.1874,0.14882 -0.36929,0.23151 -0.64492,0.23151 -0.50711,0 -0.85989,-0.42444 -0.85989,-0.93156 v -0.005 c 0,-0.50711 0.36382,-0.92604 0.85989,-0.92604 0.23153,0 0.42443,0.0772 0.60636,0.21497 0.0496,0.0276 0.1047,0.0606 0.1929,0.0606 0.18192,0 0.32522,-0.13781 0.32522,-0.3142 0,-0.11575 -0.0606,-0.20946 -0.12679,-0.25907 -0.24803,-0.1819 -0.54567,-0.30317 -0.99218,-0.30317 -0.9095,0 -1.54341,0.68903 -1.54341,1.53238 v 0.011 c 0,0.84887 0.64495,1.52135 1.51585,1.52135 z m 0,0" | |||||
| id="path24537" /> | |||||
| </g> | |||||
| <g | |||||
| inkscape:groupmode="layer" | |||||
| id="layer2" | |||||
| inkscape:label="widgets" | |||||
| style="display:none"> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="path27377" | |||||
| cx="7.9994998" | |||||
| cy="77.451263" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="77.451263" | |||||
| cx="19.599819" | |||||
| id="circle28184" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28186" | |||||
| cx="31.199474" | |||||
| cy="77.451263" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="77.451263" | |||||
| cx="42.799793" | |||||
| id="circle28188" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="89.050903" | |||||
| cx="7.9994998" | |||||
| id="circle28190" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28192" | |||||
| cx="19.599819" | |||||
| cy="89.050903" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="89.050903" | |||||
| cx="31.199474" | |||||
| id="circle28194" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28196" | |||||
| cx="42.799793" | |||||
| cy="89.050903" | |||||
| r="2" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28198" | |||||
| cx="7.9994998" | |||||
| cy="100.65122" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="100.65122" | |||||
| cx="19.599819" | |||||
| id="circle28200" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28202" | |||||
| cx="31.199474" | |||||
| cy="100.65122" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="100.65122" | |||||
| cx="42.799793" | |||||
| id="circle28204" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="112.25155" | |||||
| cx="7.9994998" | |||||
| id="circle28206" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28208" | |||||
| cx="19.599819" | |||||
| cy="112.25155" | |||||
| r="2" /> | |||||
| <circle | |||||
| r="2" | |||||
| cy="112.25155" | |||||
| cx="31.199474" | |||||
| id="circle28210" | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> | |||||
| <circle | |||||
| style="opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="circle28212" | |||||
| cx="42.799793" | |||||
| cy="112.25155" | |||||
| r="2" /> | |||||
| <rect | |||||
| style="opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.87907022;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
| id="rect28214" | |||||
| width="44.00074" | |||||
| height="54.666771" | |||||
| x="3.39961" | |||||
| y="14.83872" /> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,146 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
| <svg | |||||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||||
| xmlns:cc="http://creativecommons.org/ns#" | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:svg="http://www.w3.org/2000/svg" | |||||
| xmlns="http://www.w3.org/2000/svg" | |||||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
| width="50.799999mm" | |||||
| height="128.50069mm" | |||||
| viewBox="0 0 50.799999 128.50069" | |||||
| version="1.1" | |||||
| id="svg28661" | |||||
| inkscape:version="0.92.2 2405546, 2018-03-11" | |||||
| sodipodi:docname="CV-GATE.svg"> | |||||
| <defs | |||||
| id="defs28655" /> | |||||
| <sodipodi:namedview | |||||
| id="base" | |||||
| pagecolor="#ffffff" | |||||
| bordercolor="#666666" | |||||
| borderopacity="1.0" | |||||
| inkscape:pageopacity="0.0" | |||||
| inkscape:pageshadow="2" | |||||
| inkscape:zoom="1.4" | |||||
| inkscape:cx="299.51464" | |||||
| inkscape:cy="255.96778" | |||||
| inkscape:document-units="mm" | |||||
| inkscape:current-layer="layer1" | |||||
| showgrid="false" | |||||
| fit-margin-top="0" | |||||
| fit-margin-left="0" | |||||
| fit-margin-right="0" | |||||
| fit-margin-bottom="0" | |||||
| inkscape:window-width="1600" | |||||
| inkscape:window-height="882" | |||||
| inkscape:window-x="0" | |||||
| inkscape:window-y="18" | |||||
| inkscape:window-maximized="0" /> | |||||
| <metadata | |||||
| id="metadata28658"> | |||||
| <rdf:RDF> | |||||
| <cc:Work | |||||
| rdf:about=""> | |||||
| <dc:format>image/svg+xml</dc:format> | |||||
| <dc:type | |||||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
| <dc:title></dc:title> | |||||
| </cc:Work> | |||||
| </rdf:RDF> | |||||
| </metadata> | |||||
| <g | |||||
| inkscape:label="Layer 1" | |||||
| inkscape:groupmode="layer" | |||||
| id="layer1" | |||||
| transform="translate(-423.18863,-118.49952)"> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9523" | |||||
| d="m 423.28099,118.59323 h 50.61394 V 246.9065 h -50.61394 z m 0,0" | |||||
| style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9525" | |||||
| d="m 473.98863,118.49952 h -50.8 V 247.0002 h 50.8 z m -0.18739,128.31327 H 423.37469 V 118.68694 h 50.42655 z m 0,0" | |||||
| style="fill:#ababab;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9547" | |||||
| d="m 431.13717,195.95078 h 34.79959" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9549" | |||||
| d="m 431.13717,207.55111 h 34.79959" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9551" | |||||
| d="m 431.13717,219.15143 h 34.79959" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9553" | |||||
| d="m 431.13717,230.75037 h 34.79959" | |||||
| style="fill:none;stroke:#000000;stroke-width:0.35277775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path13127" | |||||
| d="m 445.83534,242.85644 c -0.11715,0 -0.22465,-0.0661 -0.27562,-0.1695 l -1.0032,-2.00504 c -0.0758,-0.15296 -0.0138,-0.33762 0.1378,-0.41479 0.15296,-0.0758 0.33761,-0.0138 0.41342,0.13918 l 0.7276,1.45245 0.72623,-1.45245 c 0.0758,-0.15296 0.2618,-0.21497 0.41339,-0.13918 0.15296,0.0772 0.21498,0.26183 0.13783,0.41479 l -1.00186,2.00504 c -0.0523,0.10336 -0.15984,0.1695 -0.27559,0.1695" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path13129" | |||||
| d="m 451.34058,242.85644 c -0.11712,0 -0.22324,-0.0661 -0.27559,-0.1695 l -1.00185,-2.00504 c -0.0771,-0.15296 -0.0152,-0.33762 0.13783,-0.41479 0.15155,-0.0758 0.3376,-0.0138 0.41338,0.13918 l 0.72623,1.45245 0.72623,-1.45245 c 0.0758,-0.15296 0.26183,-0.21497 0.41342,-0.13918 0.15296,0.0772 0.21498,0.26183 0.13917,0.41479 l -1.00319,2.00504 c -0.051,0.10336 -0.15847,0.1695 -0.27563,0.1695" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path13131" | |||||
| d="m 448.73747,242.85644 c -0.72348,0 -1.3105,-0.58705 -1.3105,-1.31051 0,-0.72209 0.58702,-1.31052 1.3105,-1.31052 0.28663,0 0.55813,0.091 0.78687,0.26183 0.13642,0.10197 0.16397,0.29628 0.0606,0.4327 -0.10199,0.13505 -0.29492,0.16261 -0.43134,0.0606 -0.11988,-0.091 -0.26459,-0.13919 -0.41617,-0.13919 -0.38309,0 -0.69452,0.31145 -0.69452,0.69454 0,0.38309 0.31143,0.69453 0.69452,0.69453 0.15158,0 0.29629,-0.0482 0.41617,-0.13918 0.13642,-0.10198 0.32935,-0.0744 0.43134,0.062 0.10333,0.13505 0.0758,0.32935 -0.0606,0.43132 -0.22874,0.17088 -0.50024,0.26183 -0.78687,0.26183" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path13133" | |||||
| d="m 449.15914,241.53077 c 0,0.22186 -0.18051,0.40101 -0.40237,0.40101 -0.22049,0 -0.39963,-0.17915 -0.39963,-0.40101 0,-0.22186 0.17914,-0.40101 0.39963,-0.40101 0.22186,0 0.40237,0.17915 0.40237,0.40101" | |||||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 440.45065,128.11472 c 0.47406,0 0.78825,-0.1378 1.05833,-0.36931 0.0551,-0.0551 0.11024,-0.13229 0.11024,-0.23703 0,-0.16536 -0.14329,-0.29765 -0.30868,-0.29765 -0.0772,0 -0.14329,0.0276 -0.19293,0.0717 -0.1874,0.14882 -0.36929,0.23151 -0.64491,0.23151 -0.50712,0 -0.8599,-0.42444 -0.8599,-0.93156 v -0.005 c 0,-0.50711 0.36382,-0.92604 0.8599,-0.92604 0.23153,0 0.42442,0.0772 0.60635,0.21497 0.0496,0.0276 0.10471,0.0606 0.1929,0.0606 0.18193,0 0.32523,-0.13781 0.32523,-0.3142 0,-0.11575 -0.0606,-0.20946 -0.12679,-0.25907 -0.24804,-0.1819 -0.54568,-0.30317 -0.99219,-0.30317 -0.9095,0 -1.5434,0.68903 -1.5434,1.53238 v 0.011 c 0,0.84887 0.64495,1.52135 1.51585,1.52135 z m 0,0" | |||||
| id="path24277" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 443.37426,128.10921 h 0.0441 c 0.17639,0 0.29764,-0.0937 0.36378,-0.25356 l 0.97014,-2.32062 c 0.0166,-0.0386 0.0332,-0.0937 0.0332,-0.14331 0,-0.1819 -0.14333,-0.31419 -0.31972,-0.31419 -0.15434,0 -0.27009,0.0992 -0.31418,0.20395 l -0.74966,1.94027 -0.73861,-1.91823 c -0.0496,-0.13229 -0.15988,-0.22599 -0.33073,-0.22599 -0.18193,0 -0.32522,0.1378 -0.32522,0.3197 0,0.0551 0.0166,0.10473 0.0386,0.15985 l 0.95909,2.29857 c 0.0661,0.15985 0.19294,0.25356 0.36933,0.25356 z m 0,0" | |||||
| id="path24273" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 445.35299,127.0619 h 0.73311 c 0.17088,0 0.31418,-0.1378 0.31418,-0.30868 0,-0.17088 -0.1433,-0.30868 -0.31418,-0.30868 h -0.73311 c -0.17089,0 -0.30868,0.1378 -0.30868,0.30868 0,0.17088 0.13779,0.30868 0.30868,0.30868 z m 0,0" | |||||
| id="path24269" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 448.51353,128.11472 c 0.44647,0 0.79925,-0.14882 1.03628,-0.29765 0.15984,-0.0882 0.23149,-0.22049 0.23149,-0.41341 v -0.71658 c 0,-0.18191 -0.1433,-0.33073 -0.32519,-0.33073 h -0.74415 c -0.15984,0 -0.28663,0.13229 -0.28663,0.28663 0,0.15434 0.12679,0.28112 0.28663,0.28112 h 0.44098 v 0.41892 c -0.16539,0.12127 -0.38033,0.1819 -0.61737,0.1819 -0.52366,0 -0.89849,-0.39687 -0.89849,-0.94258 v -0.005 c 0,-0.50711 0.38033,-0.92604 0.8544,-0.92604 0.27559,0 0.46852,0.0772 0.64491,0.20395 0.0496,0.0331 0.10474,0.0662 0.19844,0.0662 0.18189,0 0.32522,-0.14332 0.32522,-0.31971 0,-0.12678 -0.0717,-0.21497 -0.13779,-0.26458 -0.26459,-0.1819 -0.56226,-0.28663 -1.00873,-0.28663 -0.89849,0 -1.55445,0.68902 -1.55445,1.53237 v 0.011 c 0,0.87643 0.63391,1.52135 1.55445,1.52135 z m 0,0" | |||||
| id="path24265" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 450.19155,127.78399 c 0,0.17088 0.12679,0.30868 0.29767,0.30868 0.1378,0 0.24804,-0.0772 0.30314,-0.20394 l 0.20398,-0.49059 h 1.30637 l 0.19844,0.46854 c 0.0606,0.13229 0.15984,0.22599 0.31418,0.22599 0.17089,0 0.30868,-0.14331 0.30868,-0.31419 0,-0.0441 -0.0109,-0.0882 -0.0332,-0.13229 l -1.03628,-2.33164 c -0.0717,-0.15985 -0.19844,-0.25907 -0.37483,-0.25907 h -0.0386 c -0.17639,0 -0.30868,0.0992 -0.38033,0.25907 l -1.03078,2.33164 c -0.0219,0.0441 -0.0386,0.0937 -0.0386,0.1378 z m 1.04732,-0.95911 0.41339,-0.97565 0.40792,0.97565 z m 0,0" | |||||
| id="path24261" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 453.98691,127.76194 c 0,0.18191 0.1433,0.33073 0.32519,0.33073 0.18193,0 0.32522,-0.14882 0.32522,-0.33073 v -2.06154 h 0.62841 c 0.16534,0 0.29764,-0.13229 0.29764,-0.29766 0,-0.16536 -0.1323,-0.30316 -0.29764,-0.30316 h -1.90723 c -0.16534,0 -0.29763,0.1378 -0.29763,0.30316 0,0.16537 0.13229,0.29766 0.29763,0.29766 h 0.62841 z m 0,0" | |||||
| id="path24257" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277775" | |||||
| d="m 456.35147,128.06511 h 1.65915 c 0.16538,0 0.29217,-0.12678 0.29217,-0.28663 0,-0.15985 -0.12679,-0.29214 -0.29217,-0.29214 h -1.33943 v -0.62288 h 1.12999 c 0.15984,0 0.29213,-0.12678 0.29213,-0.28663 0,-0.16536 -0.13229,-0.29214 -0.29213,-0.29214 h -1.12999 v -0.60083 h 1.32292 c 0.15984,0 0.29214,-0.12678 0.29214,-0.29214 0,-0.15985 -0.1323,-0.29214 -0.29214,-0.29214 h -1.64264 c -0.18189,0 -0.32523,0.14882 -0.32523,0.33072 v 2.3096 c 0,0.1819 0.14334,0.32521 0.32523,0.32521 z m 0,0" | |||||
| id="path24253" /> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,117 @@ | |||||
| #include "Core.hpp" | |||||
| template <int N> | |||||
| struct CCMidiOutput : midi::Output { | |||||
| int ccs[N]; | |||||
| int lastValues[N]; | |||||
| CCMidiOutput() { | |||||
| reset(); | |||||
| } | |||||
| void reset() { | |||||
| for (int n = 0; n < N; n++) { | |||||
| ccs[n] = n; | |||||
| lastValues[n] = -1; | |||||
| } | |||||
| } | |||||
| void setCC(int cc, int n) { | |||||
| ccs[n] = cc; | |||||
| } | |||||
| void setValue(int value, int n) { | |||||
| if (value == lastValues[n]) | |||||
| return; | |||||
| lastValues[n] = value; | |||||
| // CC | |||||
| midi::Message m; | |||||
| m.setStatus(0xb); | |||||
| m.setNote(ccs[n]); | |||||
| m.setValue(value); | |||||
| sendMessage(m); | |||||
| } | |||||
| }; | |||||
| struct CV_CC : Module { | |||||
| enum ParamIds { | |||||
| NUM_PARAMS | |||||
| }; | |||||
| enum InputIds { | |||||
| ENUMS(CC_INPUTS, 16), | |||||
| NUM_INPUTS | |||||
| }; | |||||
| enum OutputIds { | |||||
| NUM_OUTPUTS | |||||
| }; | |||||
| enum LightIds { | |||||
| NUM_LIGHTS | |||||
| }; | |||||
| CCMidiOutput<16> midiOutput; | |||||
| float rateLimiterPhase = 0.f; | |||||
| CV_CC() { | |||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
| } | |||||
| void step() override { | |||||
| const float rateLimiterPeriod = 0.010f; | |||||
| rateLimiterPhase += app()->engine->getSampleTime() / rateLimiterPeriod; | |||||
| if (rateLimiterPhase >= 1.f) { | |||||
| rateLimiterPhase -= 1.f; | |||||
| } | |||||
| else { | |||||
| return; | |||||
| } | |||||
| for (int n = 0; n < 16; n++) { | |||||
| int value = (int) std::round(inputs[CC_INPUTS + n].getVoltage() / 10.f * 127); | |||||
| value = clamp(value, 0, 127); | |||||
| midiOutput.setValue(value, n); | |||||
| } | |||||
| } | |||||
| }; | |||||
| struct CV_CCWidget : ModuleWidget { | |||||
| CV_CCWidget(CV_CC *module) { | |||||
| setModule(module); | |||||
| setPanel(SVG::load(asset::system("res/Core/CV-CC.svg"))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 77)), module, CV_CC::CC_INPUTS + 0)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 77)), module, CV_CC::CC_INPUTS + 1)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 77)), module, CV_CC::CC_INPUTS + 2)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 77)), module, CV_CC::CC_INPUTS + 3)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 89)), module, CV_CC::CC_INPUTS + 4)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 89)), module, CV_CC::CC_INPUTS + 5)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 89)), module, CV_CC::CC_INPUTS + 6)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 89)), module, CV_CC::CC_INPUTS + 7)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 101)), module, CV_CC::CC_INPUTS + 8)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 101)), module, CV_CC::CC_INPUTS + 9)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 101)), module, CV_CC::CC_INPUTS + 10)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 101)), module, CV_CC::CC_INPUTS + 11)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 112)), module, CV_CC::CC_INPUTS + 12)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 112)), module, CV_CC::CC_INPUTS + 13)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_CC::CC_INPUTS + 14)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_CC::CC_INPUTS + 15)); | |||||
| MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.4, 14.839))); | |||||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||||
| if (module) | |||||
| midiWidget->midiIO = &module->midiOutput; | |||||
| // midiWidget->createGridChoices(); | |||||
| addChild(midiWidget); | |||||
| } | |||||
| }; | |||||
| Model *modelCV_CC = createModel<CV_CC, CV_CCWidget>("CV-CC"); | |||||
| @@ -0,0 +1,159 @@ | |||||
| #include "Core.hpp" | |||||
| template <int N> | |||||
| struct GateMidiOutput : midi::Output { | |||||
| int vels[N]; | |||||
| bool lastGates[N]; | |||||
| int notes[N]; | |||||
| GateMidiOutput() { | |||||
| reset(); | |||||
| } | |||||
| void reset() { | |||||
| for (int n = 0; n < N; n++) { | |||||
| vels[n] = 100; | |||||
| lastGates[n] = false; | |||||
| notes[n] = 60 + n; | |||||
| } | |||||
| } | |||||
| void panic() { | |||||
| reset(); | |||||
| // Send all note off commands | |||||
| for (int note = 0; note <= 127; note++) { | |||||
| // Note off | |||||
| midi::Message m; | |||||
| m.setStatus(0x8); | |||||
| m.setNote(note); | |||||
| m.setValue(0); | |||||
| sendMessage(m); | |||||
| } | |||||
| } | |||||
| void setVelocity(int vel, int n) { | |||||
| vels[n] = vel; | |||||
| } | |||||
| void setGate(bool gate, int n) { | |||||
| if (gate && !lastGates[n]) { | |||||
| // Note on | |||||
| midi::Message m; | |||||
| m.setStatus(0x9); | |||||
| m.setNote(notes[n]); | |||||
| m.setValue(vels[n]); | |||||
| sendMessage(m); | |||||
| } | |||||
| else if (!gate && lastGates[n]) { | |||||
| // Note off | |||||
| midi::Message m; | |||||
| m.setStatus(0x8); | |||||
| m.setNote(notes[n]); | |||||
| m.setValue(vels[n]); | |||||
| sendMessage(m); | |||||
| } | |||||
| lastGates[n] = gate; | |||||
| } | |||||
| void setNote(int note, int n) { | |||||
| if (note == notes[n]) | |||||
| return; | |||||
| if (lastGates[n]) { | |||||
| // Note off | |||||
| midi::Message m1; | |||||
| m1.setStatus(0x8); | |||||
| m1.setNote(notes[n]); | |||||
| m1.setValue(vels[n]); | |||||
| sendMessage(m1); | |||||
| // Note on | |||||
| midi::Message m2; | |||||
| m2.setStatus(0x9); | |||||
| m2.setNote(note); | |||||
| m2.setValue(vels[n]); | |||||
| sendMessage(m2); | |||||
| } | |||||
| notes[n] = note; | |||||
| } | |||||
| }; | |||||
| struct CV_Gate : Module { | |||||
| enum ParamIds { | |||||
| NUM_PARAMS | |||||
| }; | |||||
| enum InputIds { | |||||
| ENUMS(GATE_INPUTS, 16), | |||||
| NUM_INPUTS | |||||
| }; | |||||
| enum OutputIds { | |||||
| NUM_OUTPUTS | |||||
| }; | |||||
| enum LightIds { | |||||
| NUM_LIGHTS | |||||
| }; | |||||
| GateMidiOutput<16> midiOutput; | |||||
| bool velocityMode = false; | |||||
| CV_Gate() { | |||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
| } | |||||
| void step() override { | |||||
| for (int n = 0; n < 16; n++) { | |||||
| if (velocityMode) { | |||||
| int vel = (int) std::round(inputs[GATE_INPUTS + n].getVoltage() / 10.f * 127); | |||||
| vel = clamp(vel, 0, 127); | |||||
| midiOutput.setVelocity(vel, n); | |||||
| midiOutput.setGate(vel > 0, n); | |||||
| } | |||||
| else { | |||||
| bool gate = inputs[GATE_INPUTS + n].getVoltage() >= 1.f; | |||||
| midiOutput.setVelocity(100, n); | |||||
| midiOutput.setGate(gate, n); | |||||
| } | |||||
| } | |||||
| } | |||||
| }; | |||||
| struct CV_GateWidget : ModuleWidget { | |||||
| CV_GateWidget(CV_Gate *module) { | |||||
| setModule(module); | |||||
| setPanel(SVG::load(asset::system("res/Core/CV-Gate.svg"))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 77)), module, CV_Gate::GATE_INPUTS + 0)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 77)), module, CV_Gate::GATE_INPUTS + 1)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 77)), module, CV_Gate::GATE_INPUTS + 2)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 77)), module, CV_Gate::GATE_INPUTS + 3)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 89)), module, CV_Gate::GATE_INPUTS + 4)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 89)), module, CV_Gate::GATE_INPUTS + 5)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 89)), module, CV_Gate::GATE_INPUTS + 6)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 89)), module, CV_Gate::GATE_INPUTS + 7)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 101)), module, CV_Gate::GATE_INPUTS + 8)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 101)), module, CV_Gate::GATE_INPUTS + 9)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 101)), module, CV_Gate::GATE_INPUTS + 10)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 101)), module, CV_Gate::GATE_INPUTS + 11)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8, 112)), module, CV_Gate::GATE_INPUTS + 12)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(20, 112)), module, CV_Gate::GATE_INPUTS + 13)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_Gate::GATE_INPUTS + 14)); | |||||
| addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_Gate::GATE_INPUTS + 15)); | |||||
| MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.4, 14.839))); | |||||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||||
| if (module) | |||||
| midiWidget->midiIO = &module->midiOutput; | |||||
| // midiWidget->createGridChoices(); | |||||
| addChild(midiWidget); | |||||
| } | |||||
| }; | |||||
| Model *modelCV_Gate = createModel<CV_Gate, CV_GateWidget>("CV-Gate"); | |||||
| @@ -52,7 +52,7 @@ struct PolyphonicMidiOutput : midi::Output { | |||||
| } | } | ||||
| } | } | ||||
| void setVel(int vel, int c) { | |||||
| void setVelocity(int vel, int c) { | |||||
| vels[c] = vel; | vels[c] = vel; | ||||
| } | } | ||||
| @@ -229,16 +229,26 @@ struct CV_MIDI : Module { | |||||
| }; | }; | ||||
| PolyphonicMidiOutput<PORT_MAX_CHANNELS> midiOutput; | PolyphonicMidiOutput<PORT_MAX_CHANNELS> midiOutput; | ||||
| float rateLimiterPhase = 0.f; | |||||
| CV_MIDI() { | CV_MIDI() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| } | } | ||||
| void step() override { | void step() override { | ||||
| const float rateLimiterPeriod = 0.005f; | |||||
| rateLimiterPhase += app()->engine->getSampleTime() / rateLimiterPeriod; | |||||
| if (rateLimiterPhase >= 1.f) { | |||||
| rateLimiterPhase -= 1.f; | |||||
| } | |||||
| else { | |||||
| return; | |||||
| } | |||||
| for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) { | for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) { | ||||
| int vel = (int) std::round(inputs[VEL_INPUT].normalize(10.f * 100 / 127, c) / 10.f * 127); | int vel = (int) std::round(inputs[VEL_INPUT].normalize(10.f * 100 / 127, c) / 10.f * 127); | ||||
| vel = clamp(vel, 0, 127); | vel = clamp(vel, 0, 127); | ||||
| midiOutput.setVel(vel, c); | |||||
| midiOutput.setVelocity(vel, c); | |||||
| int note = (int) std::round(inputs[PITCH_INPUT].getVoltage(c) * 12.f + 60.f); | int note = (int) std::round(inputs[PITCH_INPUT].getVoltage(c) * 12.f + 60.f); | ||||
| note = clamp(note, 0, 127); | note = clamp(note, 0, 127); | ||||
| @@ -262,9 +272,6 @@ struct CV_MIDI : Module { | |||||
| mw = clamp(mw, 0, 127); | mw = clamp(mw, 0, 127); | ||||
| midiOutput.setModWheel(mw); | midiOutput.setModWheel(mw); | ||||
| bool clk = inputs[CLK_INPUT].value >= 1.f; | |||||
| midiOutput.setClock(clk); | |||||
| int vol = (int) std::round(inputs[VOL_INPUT].normalize(10.f) / 10.f * 127); | int vol = (int) std::round(inputs[VOL_INPUT].normalize(10.f) / 10.f * 127); | ||||
| vol = clamp(vol, 0, 127); | vol = clamp(vol, 0, 127); | ||||
| midiOutput.setVolume(vol); | midiOutput.setVolume(vol); | ||||
| @@ -273,6 +280,9 @@ struct CV_MIDI : Module { | |||||
| pan = clamp(pan, 0, 127); | pan = clamp(pan, 0, 127); | ||||
| midiOutput.setPan(pan); | midiOutput.setPan(pan); | ||||
| bool clk = inputs[CLK_INPUT].value >= 1.f; | |||||
| midiOutput.setClock(clk); | |||||
| bool start = inputs[START_INPUT].value >= 1.f; | bool start = inputs[START_INPUT].value >= 1.f; | ||||
| midiOutput.setStart(start); | midiOutput.setStart(start); | ||||
| @@ -14,7 +14,7 @@ void init(rack::Plugin *p) { | |||||
| p->sourceUrl = "https://github.com/VCVRack/Rack"; | p->sourceUrl = "https://github.com/VCVRack/Rack"; | ||||
| modelAudioInterface->name = "Audio"; | modelAudioInterface->name = "Audio"; | ||||
| modelAudioInterface->description = ""; | |||||
| modelAudioInterface->description = "Sends audio and CV to/from an audio device"; | |||||
| modelAudioInterface->tags = {"External"}; | modelAudioInterface->tags = {"External"}; | ||||
| p->addModel(modelAudioInterface); | p->addModel(modelAudioInterface); | ||||
| @@ -43,6 +43,16 @@ void init(rack::Plugin *p) { | |||||
| modelCV_MIDI->tags = {"External", "MIDI"}; | modelCV_MIDI->tags = {"External", "MIDI"}; | ||||
| p->addModel(modelCV_MIDI); | p->addModel(modelCV_MIDI); | ||||
| modelCV_CC->name = "CV-CC"; | |||||
| modelCV_CC->description = ""; | |||||
| modelCV_CC->tags = {"External", "MIDI"}; | |||||
| p->addModel(modelCV_CC); | |||||
| modelCV_Gate->name = "CV-Gate"; | |||||
| modelCV_Gate->description = ""; | |||||
| modelCV_Gate->tags = {"External", "MIDI"}; | |||||
| p->addModel(modelCV_Gate); | |||||
| modelBlank->name = "Blank"; | modelBlank->name = "Blank"; | ||||
| modelBlank->description = ""; | modelBlank->description = ""; | ||||
| modelBlank->tags = {"Blank"}; | modelBlank->tags = {"Blank"}; | ||||
| @@ -11,6 +11,8 @@ extern Model *modelQuadMIDIToCVInterface; | |||||
| extern Model *modelMIDICCToCVInterface; | extern Model *modelMIDICCToCVInterface; | ||||
| extern Model *modelMIDITriggerToCVInterface; | extern Model *modelMIDITriggerToCVInterface; | ||||
| extern Model *modelCV_MIDI; | extern Model *modelCV_MIDI; | ||||
| extern Model *modelCV_CC; | |||||
| extern Model *modelCV_Gate; | |||||
| extern Model *modelBlank; | extern Model *modelBlank; | ||||
| extern Model *modelNotes; | extern Model *modelNotes; | ||||
| @@ -67,7 +67,7 @@ void Knob::onDragMove(const event::DragMove &e) { | |||||
| float delta = KNOB_SENSITIVITY * -e.mouseDelta.y * speed * range; | float delta = KNOB_SENSITIVITY * -e.mouseDelta.y * speed * range; | ||||
| // Drag slower if Mod is held | // Drag slower if Mod is held | ||||
| if (app()->window->isModPressed()) | |||||
| if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) | |||||
| delta /= 16.f; | delta /= 16.f; | ||||
| if (snap) { | if (snap) { | ||||
| @@ -16,12 +16,13 @@ namespace rack { | |||||
| ModuleWidget::~ModuleWidget() { | ModuleWidget::~ModuleWidget() { | ||||
| if (module) { | |||||
| delete module; | |||||
| } | |||||
| setModule(NULL); | |||||
| } | } | ||||
| void ModuleWidget::setModule(Module *module) { | void ModuleWidget::setModule(Module *module) { | ||||
| if (this->module) { | |||||
| delete this->module; | |||||
| } | |||||
| this->module = module; | this->module = module; | ||||
| } | } | ||||
| @@ -338,7 +339,7 @@ void ModuleWidget::onHover(const event::Hover &e) { | |||||
| // Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. | // Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. | ||||
| if (glfwGetKey(app()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(app()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { | if (glfwGetKey(app()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(app()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { | ||||
| if (!app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| ModuleWidget_removeAction(this); | ModuleWidget_removeAction(this); | ||||
| e.consume(NULL); | e.consume(NULL); | ||||
| return; | return; | ||||
| @@ -348,8 +349,9 @@ void ModuleWidget::onHover(const event::Hover &e) { | |||||
| void ModuleWidget::onButton(const event::Button &e) { | void ModuleWidget::onButton(const event::Button &e) { | ||||
| OpaqueWidget::onButton(e); | OpaqueWidget::onButton(e); | ||||
| if (e.getConsumed() == this) { | if (e.getConsumed() == this) { | ||||
| if (e.button == 1) { | |||||
| if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | |||||
| createContextMenu(); | createContextMenu(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -359,43 +361,43 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { | |||||
| if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
| switch (e.key) { | switch (e.key) { | ||||
| case GLFW_KEY_I: { | case GLFW_KEY_I: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| reset(); | reset(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_R: { | case GLFW_KEY_R: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| randomize(); | randomize(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_C: { | case GLFW_KEY_C: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| copyClipboard(); | copyClipboard(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_V: { | case GLFW_KEY_V: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| pasteClipboard(); | pasteClipboard(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_D: { | case GLFW_KEY_D: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| app()->scene->rackWidget->cloneModule(this); | app()->scene->rackWidget->cloneModule(this); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_U: { | case GLFW_KEY_U: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| disconnect(); | disconnect(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_E: { | case GLFW_KEY_E: { | ||||
| if (app()->window->isModPressed() && !app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| ModuleWidget_bypassAction(this); | ModuleWidget_bypassAction(this); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| @@ -436,7 +438,7 @@ struct ModuleDisconnectItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModuleDisconnectItem() { | ModuleDisconnectItem() { | ||||
| text = "Disconnect cables"; | text = "Disconnect cables"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+U"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+U"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| moduleWidget->disconnect(); | moduleWidget->disconnect(); | ||||
| @@ -447,7 +449,7 @@ struct ModuleResetItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModuleResetItem() { | ModuleResetItem() { | ||||
| text = "Initialize"; | text = "Initialize"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+I"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+I"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| moduleWidget->reset(); | moduleWidget->reset(); | ||||
| @@ -458,7 +460,7 @@ struct ModuleRandomizeItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModuleRandomizeItem() { | ModuleRandomizeItem() { | ||||
| text = "Randomize"; | text = "Randomize"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+R"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+R"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| moduleWidget->randomize(); | moduleWidget->randomize(); | ||||
| @@ -469,7 +471,7 @@ struct ModuleCopyItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModuleCopyItem() { | ModuleCopyItem() { | ||||
| text = "Copy preset"; | text = "Copy preset"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+C"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+C"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| moduleWidget->copyClipboard(); | moduleWidget->copyClipboard(); | ||||
| @@ -480,7 +482,7 @@ struct ModulePasteItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModulePasteItem() { | ModulePasteItem() { | ||||
| text = "Paste preset"; | text = "Paste preset"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+V"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+V"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| moduleWidget->pasteClipboard(); | moduleWidget->pasteClipboard(); | ||||
| @@ -511,7 +513,7 @@ struct ModuleCloneItem : MenuItem { | |||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| ModuleCloneItem() { | ModuleCloneItem() { | ||||
| text = "Duplicate"; | text = "Duplicate"; | ||||
| rightText = WINDOW_MOD_KEY_NAME "+D"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+D"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->scene->rackWidget->cloneModule(moduleWidget); | app()->scene->rackWidget->cloneModule(moduleWidget); | ||||
| @@ -524,7 +526,7 @@ struct ModuleBypassItem : MenuItem { | |||||
| text = "Bypass"; | text = "Bypass"; | ||||
| } | } | ||||
| void step() override { | void step() override { | ||||
| rightText = WINDOW_MOD_KEY_NAME "+E"; | |||||
| rightText = WINDOW_MOD_CTRL_NAME "+E"; | |||||
| if (!moduleWidget->module) | if (!moduleWidget->module) | ||||
| return; | return; | ||||
| if (moduleWidget->module->bypass) | if (moduleWidget->module->bypass) | ||||
| @@ -119,7 +119,7 @@ void ParamWidget::fromJson(json_t *rootJ) { | |||||
| void ParamWidget::onButton(const event::Button &e) { | void ParamWidget::onButton(const event::Button &e) { | ||||
| // Right click to reset | // Right click to reset | ||||
| if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && !(e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) { | |||||
| if (paramQuantity && paramQuantity->isBounded()) { | if (paramQuantity && paramQuantity->isBounded()) { | ||||
| float oldValue = paramQuantity->getValue(); | float oldValue = paramQuantity->getValue(); | ||||
| paramQuantity->reset(); | paramQuantity->reset(); | ||||
| @@ -141,7 +141,7 @@ void ParamWidget::onButton(const event::Button &e) { | |||||
| } | } | ||||
| // Shift-click to open value entry | // Shift-click to open value entry | ||||
| if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && !(e.mods & WINDOW_MOD) && (e.mods & GLFW_MOD_SHIFT)) { | |||||
| if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) { | |||||
| // Create ParamField | // Create ParamField | ||||
| MenuOverlay *overlay = new MenuOverlay; | MenuOverlay *overlay = new MenuOverlay; | ||||
| app()->scene->addChild(overlay); | app()->scene->addChild(overlay); | ||||
| @@ -72,7 +72,10 @@ void PortWidget::onButton(const event::Button &e) { | |||||
| void PortWidget::onDragStart(const event::DragStart &e) { | void PortWidget::onDragStart(const event::DragStart &e) { | ||||
| // Try to grab cable on top of stack | // Try to grab cable on top of stack | ||||
| CableWidget *cable = NULL; | CableWidget *cable = NULL; | ||||
| if (type == INPUT || !app()->window->isModPressed()) { | |||||
| if (type == OUTPUT && (app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| // Keep cable NULL | |||||
| } | |||||
| else { | |||||
| cable = app()->scene->rackWidget->cableContainer->getTopCable(this); | cable = app()->scene->rackWidget->cableContainer->getTopCable(this); | ||||
| } | } | ||||
| @@ -591,11 +591,11 @@ void RackWidget::draw(NVGcontext *vg) { | |||||
| void RackWidget::onHover(const event::Hover &e) { | void RackWidget::onHover(const event::Hover &e) { | ||||
| // Scroll with arrow keys | // Scroll with arrow keys | ||||
| float arrowSpeed = 30.0; | float arrowSpeed = 30.0; | ||||
| if (app()->window->isShiftPressed() && app()->window->isModPressed()) | |||||
| if ((app()->window->getMods() & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL |GLFW_MOD_SHIFT)) | |||||
| arrowSpeed /= 16.0; | arrowSpeed /= 16.0; | ||||
| else if (app()->window->isShiftPressed()) | |||||
| else if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) | |||||
| arrowSpeed *= 4.0; | arrowSpeed *= 4.0; | ||||
| else if (app()->window->isModPressed()) | |||||
| else if ((app()->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) | |||||
| arrowSpeed /= 4.0; | arrowSpeed /= 4.0; | ||||
| ScrollWidget *scrollWidget = app()->scene->scrollWidget; | ScrollWidget *scrollWidget = app()->scene->scrollWidget; | ||||
| @@ -84,49 +84,49 @@ void Scene::onHoverKey(const event::HoverKey &e) { | |||||
| if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
| switch (e.key) { | switch (e.key) { | ||||
| case GLFW_KEY_N: { | case GLFW_KEY_N: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| rackWidget->reset(); | rackWidget->reset(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_Q: { | case GLFW_KEY_Q: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| app()->window->close(); | app()->window->close(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_O: { | case GLFW_KEY_O: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| rackWidget->loadDialog(); | rackWidget->loadDialog(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if ((e.mods & WINDOW_MOD) && (e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL | GLFW_MOD_SHIFT)) { | |||||
| rackWidget->revert(); | rackWidget->revert(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_S: { | case GLFW_KEY_S: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| rackWidget->saveDialog(); | rackWidget->saveDialog(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if ((e.mods & WINDOW_MOD) && (e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL | GLFW_MOD_SHIFT)) { | |||||
| rackWidget->saveAsDialog(); | rackWidget->saveAsDialog(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_V: { | case GLFW_KEY_V: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| rackWidget->pastePresetClipboard(); | rackWidget->pastePresetClipboard(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_Z: { | case GLFW_KEY_Z: { | ||||
| if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| app()->history->undo(); | app()->history->undo(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if ((e.mods & WINDOW_MOD) && (e.mods & GLFW_MOD_SHIFT)) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL | GLFW_MOD_SHIFT)) { | |||||
| app()->history->redo(); | app()->history->redo(); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| @@ -33,12 +33,13 @@ void Switch::onDragStart(const event::DragStart &e) { | |||||
| else { | else { | ||||
| if (paramQuantity) { | if (paramQuantity) { | ||||
| float oldValue = paramQuantity->getValue(); | float oldValue = paramQuantity->getValue(); | ||||
| // Increment value by 1, or reset back to minimum | |||||
| if (paramQuantity->isMax()) { | if (paramQuantity->isMax()) { | ||||
| // Reset value back to minimum | |||||
| paramQuantity->setMin(); | paramQuantity->setMin(); | ||||
| } | } | ||||
| else { | else { | ||||
| paramQuantity->setValue(std::floor(paramQuantity->getValue() + 1)); | |||||
| // Increment value by 1 | |||||
| paramQuantity->setValue(std::round(paramQuantity->getValue()) + 1.f); | |||||
| } | } | ||||
| float newValue = paramQuantity->getValue(); | float newValue = paramQuantity->getValue(); | ||||
| @@ -35,7 +35,7 @@ struct MenuButton : Button { | |||||
| struct NewItem : MenuItem { | struct NewItem : MenuItem { | ||||
| NewItem() { | NewItem() { | ||||
| text = "New"; | text = "New"; | ||||
| rightText = "(" WINDOW_MOD_KEY_NAME "+N)"; | |||||
| rightText = "(" WINDOW_MOD_CTRL_NAME "+N)"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->scene->rackWidget->reset(); | app()->scene->rackWidget->reset(); | ||||
| @@ -46,7 +46,7 @@ struct NewItem : MenuItem { | |||||
| struct OpenItem : MenuItem { | struct OpenItem : MenuItem { | ||||
| OpenItem() { | OpenItem() { | ||||
| text = "Open"; | text = "Open"; | ||||
| rightText = "(" WINDOW_MOD_KEY_NAME "+O)"; | |||||
| rightText = "(" WINDOW_MOD_CTRL_NAME "+O)"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->scene->rackWidget->loadDialog(); | app()->scene->rackWidget->loadDialog(); | ||||
| @@ -57,7 +57,7 @@ struct OpenItem : MenuItem { | |||||
| struct SaveItem : MenuItem { | struct SaveItem : MenuItem { | ||||
| SaveItem() { | SaveItem() { | ||||
| text = "Save"; | text = "Save"; | ||||
| rightText = "(" WINDOW_MOD_KEY_NAME "+S)"; | |||||
| rightText = "(" WINDOW_MOD_CTRL_NAME "+S)"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->scene->rackWidget->saveDialog(); | app()->scene->rackWidget->saveDialog(); | ||||
| @@ -68,7 +68,7 @@ struct SaveItem : MenuItem { | |||||
| struct SaveAsItem : MenuItem { | struct SaveAsItem : MenuItem { | ||||
| SaveAsItem() { | SaveAsItem() { | ||||
| text = "Save as"; | text = "Save as"; | ||||
| rightText = "(" WINDOW_MOD_KEY_NAME "+Shift+S)"; | |||||
| rightText = "(" WINDOW_MOD_CTRL_NAME "+Shift+S)"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->scene->rackWidget->saveAsDialog(); | app()->scene->rackWidget->saveAsDialog(); | ||||
| @@ -109,7 +109,7 @@ struct DisconnectCablesItem : MenuItem { | |||||
| struct QuitItem : MenuItem { | struct QuitItem : MenuItem { | ||||
| QuitItem() { | QuitItem() { | ||||
| text = "Quit"; | text = "Quit"; | ||||
| rightText = "(" WINDOW_MOD_KEY_NAME "+Q)"; | |||||
| rightText = "(" WINDOW_MOD_CTRL_NAME "+Q)"; | |||||
| } | } | ||||
| void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
| app()->window->close(); | app()->window->close(); | ||||
| @@ -63,8 +63,8 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||||
| void sendMessage(midi::Message message) override { | void sendMessage(midi::Message message) override { | ||||
| unsigned char msg[3]; | unsigned char msg[3]; | ||||
| msg[0] = message.cmd; | msg[0] = message.cmd; | ||||
| msg[0] = message.data1; | |||||
| msg[0] = message.data2; | |||||
| msg[1] = message.data1; | |||||
| msg[2] = message.data2; | |||||
| rtMidiOut->sendMessage(msg, 3); | rtMidiOut->sendMessage(msg, 3); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -94,7 +94,7 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_LEFT: { | case GLFW_KEY_LEFT: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| while (--cursor > 0) { | while (--cursor > 0) { | ||||
| if (text[cursor] == ' ') | if (text[cursor] == ' ') | ||||
| break; | break; | ||||
| @@ -103,12 +103,12 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| else { | else { | ||||
| cursor--; | cursor--; | ||||
| } | } | ||||
| if (!app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == 0) { | |||||
| selection = cursor; | selection = cursor; | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_RIGHT: { | case GLFW_KEY_RIGHT: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| while (++cursor < (int) text.size()) { | while (++cursor < (int) text.size()) { | ||||
| if (text[cursor] == ' ') | if (text[cursor] == ' ') | ||||
| break; | break; | ||||
| @@ -117,7 +117,7 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| else { | else { | ||||
| cursor++; | cursor++; | ||||
| } | } | ||||
| if (!app()->window->isShiftPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == 0) { | |||||
| selection = cursor; | selection = cursor; | ||||
| } | } | ||||
| } break; | } break; | ||||
| @@ -128,14 +128,14 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| selection = cursor = text.size(); | selection = cursor = text.size(); | ||||
| } break; | } break; | ||||
| case GLFW_KEY_V: { | case GLFW_KEY_V: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| const char *newText = glfwGetClipboardString(app()->window->win); | const char *newText = glfwGetClipboardString(app()->window->win); | ||||
| if (newText) | if (newText) | ||||
| insertText(newText); | insertText(newText); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_X: { | case GLFW_KEY_X: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| if (cursor != selection) { | if (cursor != selection) { | ||||
| int begin = std::min(cursor, selection); | int begin = std::min(cursor, selection); | ||||
| std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | ||||
| @@ -145,7 +145,7 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_C: { | case GLFW_KEY_C: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| if (cursor != selection) { | if (cursor != selection) { | ||||
| int begin = std::min(cursor, selection); | int begin = std::min(cursor, selection); | ||||
| std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | ||||
| @@ -154,7 +154,7 @@ void TextField::onSelectKey(const event::SelectKey &e) { | |||||
| } | } | ||||
| } break; | } break; | ||||
| case GLFW_KEY_A: { | case GLFW_KEY_A: { | ||||
| if (app()->window->isModPressed()) { | |||||
| if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
| selectAll(); | selectAll(); | ||||
| } | } | ||||
| } break; | } break; | ||||
| @@ -66,6 +66,7 @@ static void mouseButtonCallback(GLFWwindow *win, int button, int action, int mod | |||||
| if (button == GLFW_MOUSE_BUTTON_LEFT) { | if (button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
| if (mods & GLFW_MOD_CONTROL) { | if (mods & GLFW_MOD_CONTROL) { | ||||
| button = GLFW_MOUSE_BUTTON_RIGHT; | button = GLFW_MOUSE_BUTTON_RIGHT; | ||||
| mods &= ~GLFW_MOD_CONTROL; | |||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -123,12 +124,12 @@ static void cursorEnterCallback(GLFWwindow *win, int entered) { | |||||
| static void scrollCallback(GLFWwindow *win, double x, double y) { | static void scrollCallback(GLFWwindow *win, double x, double y) { | ||||
| Window *window = (Window*) glfwGetWindowUserPointer(win); | Window *window = (Window*) glfwGetWindowUserPointer(win); | ||||
| math::Vec scrollDelta = math::Vec(x, y); | math::Vec scrollDelta = math::Vec(x, y); | ||||
| #if ARCH_LIN || ARCH_WIN | |||||
| if (window->isShiftPressed()) | |||||
| scrollDelta = math::Vec(y, x); | |||||
| #endif | |||||
| scrollDelta = scrollDelta.mult(50.0); | scrollDelta = scrollDelta.mult(50.0); | ||||
| // Flip coordinates if shift is held | |||||
| if ((window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) | |||||
| scrollDelta = scrollDelta.flip(); | |||||
| app()->event->handleScroll(window->mousePos, scrollDelta); | app()->event->handleScroll(window->mousePos, scrollDelta); | ||||
| } | } | ||||
| @@ -142,7 +143,7 @@ static void keyCallback(GLFWwindow *win, int key, int scancode, int action, int | |||||
| app()->event->handleKey(window->mousePos, key, scancode, action, mods); | app()->event->handleKey(window->mousePos, key, scancode, action, mods); | ||||
| // Keyboard MIDI driver | // Keyboard MIDI driver | ||||
| if (!(mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER))) { | |||||
| if ((mods & WINDOW_MOD_MASK) == 0) { | |||||
| if (action == GLFW_PRESS) { | if (action == GLFW_PRESS) { | ||||
| keyboard::press(key); | keyboard::press(key); | ||||
| } | } | ||||
| @@ -380,16 +381,17 @@ void Window::cursorUnlock() { | |||||
| } | } | ||||
| } | } | ||||
| bool Window::isModPressed() { | |||||
| #ifdef ARCH_MAC | |||||
| return glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS; | |||||
| #else | |||||
| return glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; | |||||
| #endif | |||||
| } | |||||
| bool Window::isShiftPressed() { | |||||
| return glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS; | |||||
| int Window::getMods() { | |||||
| int mods = 0; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_SHIFT; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_CONTROL; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_ALT; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_SUPER; | |||||
| return mods; | |||||
| } | } | ||||
| math::Vec Window::getWindowSize() { | math::Vec Window::getWindowSize() { | ||||