@@ -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() { | ||||