@@ -1,6 +1,4 @@ | |||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
<svg | <svg | ||||
xmlns:dc="http://purl.org/dc/elements/1.1/" | xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
xmlns:cc="http://creativecommons.org/ns#" | xmlns:cc="http://creativecommons.org/ns#" | ||||
@@ -9,243 +7,246 @@ | |||||
xmlns="http://www.w3.org/2000/svg" | xmlns="http://www.w3.org/2000/svg" | ||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
width="15.239719mm" | |||||
height="128.49931mm" | |||||
viewBox="0 0 15.23972 128.49931" | |||||
width="45" | |||||
height="380" | |||||
viewBox="0 0 45 380" | |||||
version="1.1" | version="1.1" | ||||
id="svg55291" | |||||
inkscape:version="0.92.4 5da689c313, 2019-01-14" | |||||
sodipodi:docname="Viz.svg"> | |||||
<defs | |||||
id="defs55285" /> | |||||
<sodipodi:namedview | |||||
id="base" | |||||
pagecolor="#ffffff" | |||||
bordercolor="#666666" | |||||
borderopacity="1.0" | |||||
inkscape:pageopacity="0.0" | |||||
inkscape:pageshadow="2" | |||||
inkscape:zoom="0.98994949" | |||||
inkscape:cx="-61.964416" | |||||
inkscape:cy="199.87911" | |||||
inkscape:document-units="mm" | |||||
inkscape:current-layer="layer3" | |||||
showgrid="false" | |||||
fit-margin-top="0" | |||||
fit-margin-left="0" | |||||
fit-margin-right="0" | |||||
fit-margin-bottom="0" | |||||
inkscape:snap-bbox="true" | |||||
inkscape:snap-bbox-midpoints="true" | |||||
inkscape:snap-nodes="false" | |||||
inkscape:window-width="1600" | |||||
inkscape:window-height="882" | |||||
inkscape:window-x="0" | |||||
inkscape:window-y="18" | |||||
inkscape:window-maximized="0" | |||||
inkscape:snap-page="true" | |||||
inkscape:bbox-nodes="true" /> | |||||
id="svg154" | |||||
sodipodi:docname="VIZ.svg" | |||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"> | |||||
<metadata | <metadata | ||||
id="metadata55288"> | |||||
id="metadata158"> | |||||
<rdf:RDF> | <rdf:RDF> | ||||
<cc:Work | <cc:Work | ||||
rdf:about=""> | rdf:about=""> | ||||
<dc:format>image/svg+xml</dc:format> | <dc:format>image/svg+xml</dc:format> | ||||
<dc:type | <dc:type | ||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
<dc:title></dc:title> | |||||
</cc:Work> | </cc:Work> | ||||
</rdf:RDF> | </rdf:RDF> | ||||
</metadata> | </metadata> | ||||
<sodipodi:namedview | |||||
pagecolor="#ffffff" | |||||
bordercolor="#666666" | |||||
borderopacity="1" | |||||
objecttolerance="10" | |||||
gridtolerance="10" | |||||
guidetolerance="10" | |||||
inkscape:pageopacity="0" | |||||
inkscape:pageshadow="2" | |||||
inkscape:window-width="716" | |||||
inkscape:window-height="480" | |||||
id="namedview156" | |||||
showgrid="false" | |||||
inkscape:zoom="0.62105263" | |||||
inkscape:cx="22.5" | |||||
inkscape:cy="190" | |||||
inkscape:window-x="0" | |||||
inkscape:window-y="0" | |||||
inkscape:window-maximized="0" | |||||
inkscape:current-layer="svg154" /> | |||||
<defs | |||||
id="defs7"> | |||||
<linearGradient | |||||
id="a7c85910-efa2-49be-b51d-63d3f80a4577" | |||||
x1="22.5" | |||||
x2="22.5" | |||||
y2="380" | |||||
gradientUnits="userSpaceOnUse"> | |||||
<stop | |||||
offset="0" | |||||
stop-color="#ebebeb" | |||||
id="stop2" /> | |||||
<stop | |||||
offset="1" | |||||
stop-color="#e1e1e1" | |||||
id="stop4" /> | |||||
</linearGradient> | |||||
</defs> | |||||
<g | <g | ||||
inkscape:label="Layer 1" | |||||
id="b13fbb94-2523-43f1-8b7b-76c02900e16c" | |||||
data-name="FND BG"> | |||||
<rect | |||||
width="45" | |||||
height="380" | |||||
fill="url(#a7c85910-efa2-49be-b51d-63d3f80a4577)" | |||||
id="rect9" /> | |||||
</g> | |||||
<g | |||||
id="b87e7f95-1233-4dde-a5c0-e29fb2f84614" | |||||
data-name="FND GRAPH"> | |||||
<g | |||||
id="g20"> | |||||
<circle | |||||
cx="23.00165" | |||||
cy="355.83101" | |||||
r="1.18571" | |||||
fill="#1f1f1f" | |||||
id="circle12" /> | |||||
<path | |||||
d="M14.35927,359.753a.91214.91214,0,0,1-.8158-.50418l-2.96428-5.92857a.91209.91209,0,0,1,1.6316-.8158l2.14848,4.297,2.14848-4.297a.91209.91209,0,0,1,1.6316.8158l-2.96428,5.92857A.91211.91211,0,0,1,14.35927,359.753Z" | |||||
fill="#1f1f1f" | |||||
id="path14" /> | |||||
<path | |||||
d="M30.64073,359.753a.91211.91211,0,0,1-.8158-.50418l-2.96428-5.92857a.91209.91209,0,0,1,1.6316-.8158l2.14848,4.297,2.14848-4.297a.91209.91209,0,0,1,1.6316.8158l-2.96428,5.92857A.91214.91214,0,0,1,30.64073,359.753Z" | |||||
fill="#1f1f1f" | |||||
id="path16" /> | |||||
<path | |||||
d="M22.94242,359.753a3.87637,3.87637,0,1,1,2.32653-6.97719.91209.91209,0,1,1-1.09557,1.45854,2.034,2.034,0,0,0-1.231-.40991,2.0522,2.0522,0,1,0,0,4.10439,2.034,2.034,0,0,0,1.231-.40991.91209.91209,0,1,1,1.09557,1.45854A3.8448,3.8448,0,0,1,22.94242,359.753Z" | |||||
fill="#1f1f1f" | |||||
id="path18" /> | |||||
</g> | |||||
</g> | |||||
<g | |||||
id="b148c7a9-98ae-44fd-9639-16f535c2406c" | |||||
data-name="FND TXT"> | |||||
<g | |||||
id="g31"> | |||||
<path | |||||
d="M13.52246,314.58691a.41321.41321,0,0,1,.41992-.41992h1.4502a1.5914,1.5914,0,0,1,1.80176,1.58545v.01318c0,1.064-.85352,1.61915-1.89649,1.61915h-.94238v1.1455a.41652.41652,0,0,1-.833,0Zm1.80176,2.0459c.63086,0,1.02344-.35205,1.02344-.84668v-.01367c0-.55566-.39942-.84668-1.02344-.84668h-.96875v1.707Z" | |||||
fill="#1f1f1f" | |||||
id="path23" /> | |||||
<path | |||||
d="M18.06348,316.55176v-.01367a2.47974,2.47974,0,0,1,4.959-.01368v.01368a2.47973,2.47973,0,0,1-4.959.01367Zm4.085,0v-.01367a1.624,1.624,0,0,0-1.61231-1.68653,1.60217,1.60217,0,0,0-1.59863,1.67285v.01368a1.61919,1.61919,0,0,0,1.6123,1.68017A1.5965,1.5965,0,0,0,22.14844,316.55176Z" | |||||
fill="#1f1f1f" | |||||
id="path25" /> | |||||
<path | |||||
d="M24.24023,314.54639a.41652.41652,0,0,1,.833,0v3.604H27.2207a.3794.3794,0,1,1,0,.75879H24.66016a.41322.41322,0,0,1-.41993-.41992Z" | |||||
fill="#1f1f1f" | |||||
id="path27" /> | |||||
<path | |||||
d="M29.31152,317.06641l-1.63281-2.24219a.51886.51886,0,0,1-.09473-.29151.40608.40608,0,0,1,.41993-.3999.48091.48091,0,0,1,.40722.251l1.32032,1.90381,1.34179-1.91065a.47823.47823,0,0,1,.39942-.25049.39566.39566,0,0,1,.40722.40625.50945.50945,0,0,1-.11523.29834l-1.61914,2.21534v1.48388a.417.417,0,0,1-.834,0Z" | |||||
fill="#1f1f1f" | |||||
id="path29" /> | |||||
</g> | |||||
<g | |||||
id="g39"> | |||||
<path | |||||
d="M14.93555,27.66064,12.0957,20.86621a1.19766,1.19766,0,0,1-.11328-.46289.94554.94554,0,0,1,.96387-.95068,1.00032,1.00032,0,0,1,.97559.67529l2.19042,5.668,2.21387-5.73047a.99864.99864,0,0,1,.92578-.61279.92914.92914,0,0,1,.95117.92578,1.12318,1.12318,0,0,1-.0996.42529l-2.86524,6.85693a1.13167,1.13167,0,0,1-1.08887.76319h-.125A1.13165,1.13165,0,0,1,14.93555,27.66064Z" | |||||
id="path33" /> | |||||
<path | |||||
d="M21.64355,20.416a.96338.96338,0,1,1,1.92676,0v6.98144a.96338.96338,0,1,1-1.92676,0Z" | |||||
id="path35" /> | |||||
<path | |||||
d="M25.30469,27.43555v-.03809a1.35575,1.35575,0,0,1,.35058-.90039l4.542-5.28027H26.30566a.84906.84906,0,0,1-.85058-.83838.86.86,0,0,1,.85058-.85108h5.59278a.86018.86018,0,0,1,.85156.85108v.0376a1.38072,1.38072,0,0,1-.35059.90087l-4.542,5.27979h4.041a.86017.86017,0,0,1,.85156.85107.84928.84928,0,0,1-.85156.83838H26.15625A.86039.86039,0,0,1,25.30469,27.43555Z" | |||||
id="path37" /> | |||||
</g> | |||||
</g> | |||||
<g | |||||
id="b7f3c585-bc80-4700-89be-f9c3dbe33dbd" | |||||
data-name="components" | |||||
inkscape:groupmode="layer" | inkscape:groupmode="layer" | ||||
id="layer1" | |||||
transform="translate(-56.676971,-41.503207)"> | |||||
style="display:none"> | |||||
<circle | |||||
id="b316d787-fbe9-48b7-af86-7b559295a9a0" | |||||
data-name="Poly#PJ301MPort" | |||||
cx="22.500031" | |||||
cy="334" | |||||
r="5" | |||||
style="fill:#00ff00" /> | |||||
<rect | |||||
id="ec9dac3c-8600-4714-ac89-1ca8235b202d" | |||||
data-name="Screen" | |||||
x="0.0094299996" | |||||
y="38.5" | |||||
width="44.99057" | |||||
height="263.81198" | |||||
style="fill:#ffff00" /> | |||||
<path | <path | ||||
id="a738cb83-2bec-4c75-ad4b-f3faa67405e3" | |||||
data-name="Viz01#RedLight" | |||||
d="m 32.06413,50.35079 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95726,2.95726 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="M 56.769292,41.596914 H 71.82299 V 169.91019 H 56.769292 Z m 0,0" | |||||
id="path29725" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="be0c28f2-d866-4418-8214-6c352f6b1a6d" | |||||
data-name="Viz02#RedLight" | |||||
d="M 32.06413,65.993 A 2.9572,2.9572 0 1 0 35.02091,68.95061 2.95726,2.95726 0 0 0 32.06413,65.993" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#ababab;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="M 71.91669,41.503207 H 56.676971 V 170.00252 H 71.91669 Z M 71.72929,169.81649 H 56.863026 V 41.69062 H 71.72929 Z m 0,0" | |||||
id="path29727" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="e85e0c58-aa6b-4289-af1c-3011309e1e2d" | |||||
data-name="Viz03#RedLight" | |||||
d="m 32.06413,81.63517 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95725,2.95725 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="M 71.91669,158.86384 H 56.676971 V 70.738287 H 71.91669 Z m 0,0" | |||||
id="path41613" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="bd060286-7cf5-4364-a6f0-f97535566d3b" | |||||
data-name="Viz04#RedLight" | |||||
d="m 32.06413,97.27736 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95725,2.95725 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 61.03021,56.442517 c 0,0.08268 0.0662,0.148827 0.15434,0.148827 0.0827,0 0.14884,-0.06615 0.14884,-0.148827 v -0.418923 h 0.34724 c 0.38037,0 0.68904,-0.203952 0.68904,-0.589803 v -0.0055 c 0,-0.347267 -0.25357,-0.578778 -0.65595,-0.578778 h -0.52917 c -0.0882,0 -0.15434,0.06615 -0.15434,0.154341 z m 0.30318,-0.694531 v -0.617361 h 0.35278 c 0.23149,0 0.37483,0.104729 0.37483,0.30868 0,0.1819 -0.14334,0.308681 -0.37483,0.308681 z m 0,0" | |||||
id="path52181" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="a2a5d779-761f-40c8-8b34-165ba96232ef" | |||||
data-name="Viz05#RedLight" | |||||
d="m 32.06413,112.91955 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95725,2.95725 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 63.58436,56.607882 c 0.52917,0 0.90399,-0.4079 0.90399,-0.892969 v -0.0055 c 0,-0.48507 -0.36928,-0.887455 -0.89845,-0.887455 -0.52917,0 -0.90953,0.407899 -0.90953,0.892969 v 0.0055 c 0,0.485069 0.37482,0.887458 0.90399,0.887458 z m 0.006,-0.281122 c -0.341771,0 -0.58981,-0.275607 -0.58981,-0.611847 v -0.0055 c 0,-0.33624 0.24253,-0.606337 0.58427,-0.606337 0.34177,0 0.58981,0.275608 0.58981,0.611851 v 0.0055 c 0,0.336243 -0.24254,0.606337 -0.58427,0.606337 z m 0,0" | |||||
id="path52177" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="f1d5e052-5737-49c1-b5d8-86c945792406" | |||||
data-name="Viz06#RedLight" | |||||
d="m 32.06413,128.56173 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 64.92781,56.425979 c 0,0.0882 0.0661,0.15434 0.15434,0.15434 h 0.93154 c 0.0772,0 0.14334,-0.06063 0.14334,-0.137802 0,-0.07717 -0.0662,-0.137805 -0.14334,-0.137805 h -0.7827 v -1.317403 c 0,-0.08268 -0.0662,-0.14883 -0.14884,-0.14883 -0.0882,0 -0.15434,0.06615 -0.15434,0.14883 z m 0,0" | |||||
id="path52173" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="b1d22013-9978-4d5e-b9ab-b78b3ef18f74" | |||||
data-name="Viz07#RedLight" | |||||
d="m 32.06413,144.20392 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 66.77524,56.442517 c 0,0.08268 0.0661,0.148827 0.14883,0.148827 0.0882,0 0.15434,-0.06615 0.15434,-0.148827 v -0.540191 l 0.58981,-0.810288 c 0.0219,-0.02755 0.0386,-0.06615 0.0386,-0.104729 0,-0.08268 -0.0551,-0.14883 -0.1488,-0.14883 -0.0606,0 -0.10474,0.03306 -0.14333,0.08819 l -0.49058,0.700046 -0.47956,-0.694532 c -0.0386,-0.05512 -0.0827,-0.09371 -0.14884,-0.09371 -0.0882,0 -0.15434,0.06615 -0.15434,0.14883 0,0.03858 0.0166,0.07166 0.0386,0.104729 l 0.59532,0.815799 z m 0,0" | |||||
id="path52169" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="b4aa208f-29f3-4f29-8b76-cf6911e754e7" | |||||
data-name="Viz08#RedLight" | |||||
d="m 32.06413,159.84611 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 62.10576,51.11244 h 0.0441 c 0.17639,0 0.29764,-0.09371 0.36378,-0.253559 l 0.97014,-2.320616 c 0.0166,-0.03858 0.0332,-0.09371 0.0332,-0.143316 0,-0.181901 -0.14333,-0.314193 -0.31972,-0.314193 -0.15434,0 -0.27008,0.09922 -0.31418,0.20395 l -0.74965,1.940278 -0.73865,-1.91823 c -0.0496,-0.132291 -0.15984,-0.225998 -0.33073,-0.225998 -0.18189,0 -0.32519,0.137804 -0.32519,0.319705 0,0.05512 0.0166,0.104731 0.0386,0.159852 l 0.95913,2.298568 c 0.0662,0.159853 0.19293,0.253559 0.36932,0.253559 z m 0,0" | |||||
id="path52149" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="fb234c65-d014-4d90-b008-a118c103c162" | |||||
data-name="Viz09#RedLight" | |||||
d="m 32.06413,175.4883 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 64.00674,50.765175 c 0,0.181901 0.14333,0.330729 0.32523,0.330729 0.18189,0 0.32522,-0.148828 0.32522,-0.330729 v -2.359202 c 0,-0.181901 -0.14333,-0.325217 -0.32522,-0.325217 -0.1819,0 -0.32523,0.143316 -0.32523,0.325217 z m 0,0" | |||||
id="path52153" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="bcc91c36-0d79-434c-8b71-a61a285ec8b2" | |||||
data-name="Viz10#RedLight" | |||||
d="m 32.06413,191.13049 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95726,2.95726 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.35277778" | |||||
d="m 65.53363,51.068343 h 1.94579 c 0.15434,0 0.28663,-0.12678 0.28663,-0.28112 0,-0.159852 -0.13229,-0.292144 -0.28663,-0.292144 H 66.1069 l 1.5379,-1.785938 c 0.0771,-0.09371 0.12125,-0.187413 0.12125,-0.303168 v -0.01103 c 0,-0.159853 -0.13229,-0.292144 -0.28663,-0.292144 h -1.89619 c -0.15433,0 -0.28663,0.132291 -0.28663,0.292144 0,0.15434 0.1323,0.28112 0.28663,0.28112 h 1.31742 L 65.36275,50.462 c -0.0772,0.08819 -0.11575,0.192926 -0.11575,0.303169 v 0.01653 c 0,0.15434 0.13229,0.286632 0.28663,0.286632 z m 0,0" | |||||
id="path52145" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="ff26f033-6c49-4097-9c80-513ecb0d37ae" | |||||
data-name="Viz11#RedLight" | |||||
d="m 32.06413,206.77268 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95726,2.95726 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="m 64.86667,161.97821 c 0,0.22048 -0.17917,0.401 -0.40104,0.401 -0.22048,0 -0.401,-0.18052 -0.401,-0.401 0,-0.22187 0.18052,-0.40101 0.401,-0.40101 0.22187,0 0.40104,0.17914 0.40104,0.40101" | |||||
id="path41767" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="b167d49e-5d45-4a75-9619-ee0b949dffba" | |||||
data-name="Viz12#RedLight" | |||||
d="m 32.06413,222.41487 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95726,2.95726 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="m 61.54421,163.30388 c -0.11712,0 -0.22461,-0.0661 -0.277,-0.17088 l -1.00182,-2.00367 c -0.0758,-0.15296 -0.0152,-0.33762 0.1378,-0.41478 0.15296,-0.0758 0.3376,-0.0138 0.41342,0.1378 l 0.7276,1.45383 0.72623,-1.45383 c 0.0758,-0.15159 0.26046,-0.2136 0.41342,-0.1378 0.15293,0.0772 0.21357,0.26182 0.13779,0.41478 L 61.8198,163.133 c -0.0524,0.10473 -0.15984,0.17088 -0.27559,0.17088" | |||||
id="path41769" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="e7e19aaa-128a-408c-b3e8-326320883bbd" | |||||
data-name="Viz13#RedLight" | |||||
d="m 32.06413,238.05706 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95725,2.95725 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="m 67.04948,163.30388 c -0.11715,0 -0.22327,-0.0661 -0.27562,-0.17088 l -1.00319,-2.00367 c -0.0758,-0.15296 -0.0138,-0.33762 0.13779,-0.41478 0.15296,-0.0758 0.33761,-0.0138 0.4148,0.1378 l 0.72622,1.45383 0.7262,-1.45383 c 0.0758,-0.15159 0.26183,-0.2136 0.41342,-0.1378 0.15296,0.0772 0.21498,0.26182 0.13921,0.41478 l -1.00324,2.00367 c -0.0524,0.10473 -0.15846,0.17088 -0.27559,0.17088" | |||||
id="path41771" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | <path | ||||
id="b0b208d4-3cbd-4123-a6cd-a37202080f38" | |||||
data-name="Viz14#RedLight" | |||||
d="m 32.06413,253.69925 a 2.9572,2.9572 0 1 0 2.95678,2.95761 2.95725,2.95725 0 0 0 -2.95678,-2.95761" | |||||
inkscape:connector-curvature="0" | inkscape:connector-curvature="0" | ||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277778" | |||||
d="m 64.44634,163.30388 c -0.72344,0 -1.3105,-0.58843 -1.3105,-1.31052 0,-0.72347 0.58706,-1.31051 1.3105,-1.31051 0.28663,0 0.55813,0.0909 0.78687,0.26183 0.13504,0.10197 0.16263,0.29627 0.0606,0.43132 -0.10199,0.13643 -0.29489,0.16399 -0.43134,0.062 -0.12125,-0.0909 -0.26458,-0.13918 -0.41617,-0.13918 -0.38308,0 -0.69452,0.31144 -0.69452,0.69453 0,0.3831 0.31144,0.69316 0.69452,0.69316 0.15159,0 0.29492,-0.0469 0.41617,-0.13781 0.13645,-0.10197 0.32935,-0.0758 0.43134,0.0606 0.10199,0.13642 0.0744,0.33073 -0.0606,0.4327 -0.22874,0.17088 -0.50024,0.26183 -0.78687,0.26183" | |||||
id="path41773" /> | |||||
</g> | |||||
<g | |||||
inkscape:groupmode="layer" | |||||
id="layer3" | |||||
inkscape:label="widgets" | |||||
style="display:none"> | |||||
<rect | |||||
style="opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.64763796;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" | |||||
id="rect61217" | |||||
width="15.239719" | |||||
height="88.125549" | |||||
x="0" | |||||
y="29.235081" /> | |||||
<circle | |||||
style="opacity:1;vector-effect:none;fill:#00ff00;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="path61183" | |||||
cx="7.619174" | |||||
cy="21.3465" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="33.626202" | |||||
cx="10.854124" | |||||
id="circle61185" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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:#ff00ff;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="circle61187" | |||||
cx="10.854124" | |||||
cy="38.916489" | |||||
r="1" /> | |||||
<circle | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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="circle61189" | |||||
cx="10.854124" | |||||
cy="44.205402" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="49.495689" | |||||
cx="10.854124" | |||||
id="circle61191" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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:#ff00ff;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="circle61193" | |||||
cx="10.854124" | |||||
cy="54.784603" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="60.07489" | |||||
cx="10.854124" | |||||
id="circle61195" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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="1" | |||||
cy="65.3638" | |||||
cx="10.854124" | |||||
id="circle61197" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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:#ff00ff;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="circle61199" | |||||
cx="10.854124" | |||||
cy="70.654091" | |||||
r="1" /> | |||||
<circle | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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="circle61201" | |||||
cx="10.854124" | |||||
cy="75.943008" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="81.233292" | |||||
cx="10.854124" | |||||
id="circle61203" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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="1" | |||||
cy="86.522209" | |||||
cx="10.854124" | |||||
id="circle61205" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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:#ff00ff;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="circle61207" | |||||
cx="10.854124" | |||||
cy="91.812492" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="97.10141" | |||||
cx="10.854124" | |||||
id="circle61209" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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:#ff00ff;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="circle61211" | |||||
cx="10.854124" | |||||
cy="102.39169" | |||||
r="1" /> | |||||
<circle | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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="circle61213" | |||||
cx="10.854124" | |||||
cy="107.6806" | |||||
r="1" /> | |||||
<circle | |||||
r="1" | |||||
cy="112.97089" | |||||
cx="10.854124" | |||||
id="circle61215" | |||||
style="opacity:1;vector-effect:none;fill:#ff00ff;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" /> | |||||
style="fill:#ff00ff" /> | |||||
<path | |||||
id="f363b55a-6ce5-48f0-b481-c589380adc0c" | |||||
data-name="Viz15#RedLight" | |||||
d="m 32.06413,269.34143 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | |||||
style="fill:#ff00ff" /> | |||||
<path | |||||
id="fd7b9cfd-8efe-4008-a366-7629c9ec33ee" | |||||
data-name="Viz16#RedLight" | |||||
d="m 32.06413,284.98362 a 2.9572,2.9572 0 1 0 2.95678,2.95762 2.95727,2.95727 0 0 0 -2.95678,-2.95762" | |||||
inkscape:connector-curvature="0" | |||||
style="fill:#ff00ff" /> | |||||
</g> | </g> | ||||
</svg> | </svg> |
@@ -48,14 +48,12 @@ struct LFO : Module { | |||||
float clockFreq = 1.f; | float clockFreq = 1.f; | ||||
dsp::Timer clockTimer; | dsp::Timer clockTimer; | ||||
dsp::BooleanTrigger offsetTrigger; | |||||
dsp::BooleanTrigger invertTrigger; | |||||
dsp::ClockDivider lightDivider; | dsp::ClockDivider lightDivider; | ||||
LFO() { | LFO() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
configButton(OFFSET_PARAM, "Offset 0-10V"); | |||||
configButton(INVERT_PARAM, "Invert"); | |||||
configSwitch(OFFSET_PARAM, 0.f, 1.f, 0.f, "Offset", {"Bipolar", "Unipolar"}); | |||||
configSwitch(INVERT_PARAM, 0.f, 1.f, 0.f, "Invert"); | |||||
struct FrequencyQuantity : ParamQuantity { | struct FrequencyQuantity : ParamQuantity { | ||||
float getDisplayValue() override { | float getDisplayValue() override { | ||||
@@ -95,8 +93,6 @@ struct LFO : Module { | |||||
} | } | ||||
void onReset() override { | void onReset() override { | ||||
offset = false; | |||||
invert = false; | |||||
for (int c = 0; c < 16; c += 4) { | for (int c = 0; c < 16; c += 4) { | ||||
phases[c / 4] = 0.f; | phases[c / 4] = 0.f; | ||||
} | } | ||||
@@ -109,14 +105,8 @@ struct LFO : Module { | |||||
float fmParam = params[FM_PARAM].getValue(); | float fmParam = params[FM_PARAM].getValue(); | ||||
float pwParam = params[PW_PARAM].getValue(); | float pwParam = params[PW_PARAM].getValue(); | ||||
float pwmParam = params[PWM_PARAM].getValue(); | float pwmParam = params[PWM_PARAM].getValue(); | ||||
// Buttons | |||||
if (offsetTrigger.process(params[OFFSET_PARAM].getValue() > 0.f)) { | |||||
offset ^= true; | |||||
} | |||||
if (invertTrigger.process(params[INVERT_PARAM].getValue() > 0.f)) { | |||||
invert ^= true; | |||||
} | |||||
bool offset = params[OFFSET_PARAM].getValue() > 0.f; | |||||
bool invert = params[INVERT_PARAM].getValue() > 0.f; | |||||
// Clock | // Clock | ||||
if (inputs[CLOCK_INPUT].isConnected()) { | if (inputs[CLOCK_INPUT].isConnected()) { | ||||
@@ -227,39 +217,6 @@ struct LFO : Module { | |||||
lights[INVERT_LIGHT].setBrightness(invert); | lights[INVERT_LIGHT].setBrightness(invert); | ||||
} | } | ||||
} | } | ||||
json_t* dataToJson() override { | |||||
json_t* rootJ = json_object(); | |||||
// offset | |||||
json_object_set_new(rootJ, "offset", json_boolean(offset)); | |||||
// invert | |||||
json_object_set_new(rootJ, "invert", json_boolean(invert)); | |||||
return rootJ; | |||||
} | |||||
void dataFromJson(json_t* rootJ) override { | |||||
// offset | |||||
json_t* offsetJ = json_object_get(rootJ, "offset"); | |||||
if (offsetJ) | |||||
offset = json_boolean_value(offsetJ); | |||||
// invert | |||||
json_t* invertJ = json_object_get(rootJ, "invert"); | |||||
if (invertJ) | |||||
invert = json_boolean_value(invertJ); | |||||
} | |||||
void paramsFromJson(json_t* rootJ) override { | |||||
Module::paramsFromJson(rootJ); | |||||
// In <2.0, OFFSET_PARAM and INVERT_PARAM were toggle switches instead of momentary buttons, so if params are on after deserializing, set boolean states instead. | |||||
if (params[OFFSET_PARAM].getValue() > 0.f) { | |||||
offset = true; | |||||
params[OFFSET_PARAM].setValue(0.f); | |||||
} | |||||
if (params[INVERT_PARAM].getValue() > 0.f) { | |||||
invert = true; | |||||
params[INVERT_PARAM].setValue(0.f); | |||||
} | |||||
} | |||||
}; | }; | ||||
@@ -276,8 +233,8 @@ struct LFOWidget : ModuleWidget { | |||||
addParam(createParamCentered<RoundHugeBlackKnob>(mm2px(Vec(22.902, 29.803)), module, LFO::FREQ_PARAM)); | addParam(createParamCentered<RoundHugeBlackKnob>(mm2px(Vec(22.902, 29.803)), module, LFO::FREQ_PARAM)); | ||||
addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(22.861, 56.388)), module, LFO::PW_PARAM)); | addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(22.861, 56.388)), module, LFO::PW_PARAM)); | ||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(6.604, 80.603)), module, LFO::FM_PARAM)); | addParam(createParamCentered<Trimpot>(mm2px(Vec(6.604, 80.603)), module, LFO::FM_PARAM)); | ||||
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(17.441, 80.603)), module, LFO::INVERT_PARAM, LFO::INVERT_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(28.279, 80.603)), module, LFO::OFFSET_PARAM, LFO::OFFSET_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightLatch<MediumSimpleLight<WhiteLight>>>(mm2px(Vec(17.441, 80.603)), module, LFO::INVERT_PARAM, LFO::INVERT_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightLatch<MediumSimpleLight<WhiteLight>>>(mm2px(Vec(28.279, 80.603)), module, LFO::OFFSET_PARAM, LFO::OFFSET_LIGHT)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(39.116, 80.603)), module, LFO::PWM_PARAM)); | addParam(createParamCentered<Trimpot>(mm2px(Vec(39.116, 80.603)), module, LFO::PWM_PARAM)); | ||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, LFO::FM_INPUT)); | addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, LFO::FM_INPUT)); | ||||
@@ -7,6 +7,13 @@ struct Random : Module { | |||||
SHAPE_PARAM, | SHAPE_PARAM, | ||||
OFFSET_PARAM, | OFFSET_PARAM, | ||||
MODE_PARAM, | MODE_PARAM, | ||||
// new in 2.0 | |||||
PROB_PARAM, // TODO | |||||
RANDOM_PARAM, // TODO | |||||
RATE_CV_PARAM, | |||||
SHAPE_CV_PARAM, | |||||
PROB_CV_PARAM, | |||||
RANDOM_CV_PARAM, | |||||
NUM_PARAMS | NUM_PARAMS | ||||
}; | }; | ||||
enum InputIds { | enum InputIds { | ||||
@@ -14,6 +21,9 @@ struct Random : Module { | |||||
SHAPE_INPUT, | SHAPE_INPUT, | ||||
TRIGGER_INPUT, | TRIGGER_INPUT, | ||||
EXTERNAL_INPUT, | EXTERNAL_INPUT, | ||||
// new in 2.0 | |||||
PROB_INPUT, | |||||
RANDOM_INPUT, | |||||
NUM_INPUTS | NUM_INPUTS | ||||
}; | }; | ||||
enum OutputIds { | enum OutputIds { | ||||
@@ -21,35 +31,64 @@ struct Random : Module { | |||||
LINEAR_OUTPUT, | LINEAR_OUTPUT, | ||||
SMOOTH_OUTPUT, | SMOOTH_OUTPUT, | ||||
EXPONENTIAL_OUTPUT, | EXPONENTIAL_OUTPUT, | ||||
// new in 2.0 | |||||
GATE_OUTPUT, // TODO | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
enum LightIds { | enum LightIds { | ||||
RATE_LIGHT, | RATE_LIGHT, | ||||
SHAPE_LIGHT, | SHAPE_LIGHT, | ||||
PROB_LIGHT, | |||||
RANDOM_LIGHT, | |||||
OFFSET_LIGHT, | |||||
NUM_LIGHTS | NUM_LIGHTS | ||||
}; | }; | ||||
dsp::SchmittTrigger trigTrigger; | dsp::SchmittTrigger trigTrigger; | ||||
dsp::BooleanTrigger offsetTrigger; | |||||
float lastValue = 0.f; | float lastValue = 0.f; | ||||
float value = 0.f; | float value = 0.f; | ||||
float clockPhase = 0.f; | float clockPhase = 0.f; | ||||
int trigFrame = 0; | int trigFrame = 0; | ||||
int lastTrigFrames = INT_MAX; | int lastTrigFrames = INT_MAX; | ||||
bool offset = false; | |||||
Random() { | Random() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
configParam(RATE_PARAM, std::log2(0.002f), std::log2(2000.f), std::log2(2.f), "Rate", " Hz", 2); | configParam(RATE_PARAM, std::log2(0.002f), std::log2(2000.f), std::log2(2.f), "Rate", " Hz", 2); | ||||
configParam(SHAPE_PARAM, 0.f, 1.f, 0.5f, "Shape", "%", 0, 100); | |||||
configSwitch(OFFSET_PARAM, 0.f, 1.f, 1.f, "Offset", {"Bipolar", "Unipolar"}); | |||||
configSwitch(MODE_PARAM, 0.f, 1.f, 1.f, "Randomness mode", {"Relative", "Absolute"}); | |||||
configParam(SHAPE_PARAM, 0.f, 1.f, 1.f, "Shape", "%", 0, 100); | |||||
configParam(PROB_PARAM, 0.f, 1.f, 1.f, "Probability", "%", 0, 100); | |||||
configParam(RANDOM_PARAM, 0.f, 1.f, 1.f, "Randomness", "%", 0, 100); | |||||
configParam(RATE_CV_PARAM, -1.f, 1.f, 0.f, "Rate CV", "%", 0, 100); | |||||
getParamQuantity(RATE_CV_PARAM)->randomizeEnabled = false; | |||||
configParam(SHAPE_CV_PARAM, -1.f, 1.f, 0.f, "Shape CV", "%", 0, 100); | |||||
getParamQuantity(SHAPE_CV_PARAM)->randomizeEnabled = false; | |||||
configParam(PROB_CV_PARAM, -1.f, 1.f, 0.f, "Probability CV", "%", 0, 100); | |||||
getParamQuantity(PROB_CV_PARAM)->randomizeEnabled = false; | |||||
configParam(RANDOM_CV_PARAM, -1.f, 1.f, 0.f, "Randomness CV", "%", 0, 100); | |||||
getParamQuantity(RANDOM_CV_PARAM)->randomizeEnabled = false; | |||||
configButton(OFFSET_PARAM, "Offset 0-10V"); | |||||
configInput(RATE_INPUT, "Rate"); | configInput(RATE_INPUT, "Rate"); | ||||
configInput(SHAPE_INPUT, "Shape"); | configInput(SHAPE_INPUT, "Shape"); | ||||
configInput(PROB_INPUT, "Probability"); | |||||
configInput(RANDOM_INPUT, "Randomness"); | |||||
configInput(TRIGGER_INPUT, "Trigger"); | configInput(TRIGGER_INPUT, "Trigger"); | ||||
configInput(EXTERNAL_INPUT, "External"); | configInput(EXTERNAL_INPUT, "External"); | ||||
configOutput(STEPPED_OUTPUT, "Stepped"); | configOutput(STEPPED_OUTPUT, "Stepped"); | ||||
configOutput(LINEAR_OUTPUT, "Linear"); | configOutput(LINEAR_OUTPUT, "Linear"); | ||||
configOutput(SMOOTH_OUTPUT, "Smooth"); | configOutput(SMOOTH_OUTPUT, "Smooth"); | ||||
configOutput(EXPONENTIAL_OUTPUT, "Exponential"); | configOutput(EXPONENTIAL_OUTPUT, "Exponential"); | ||||
configOutput(GATE_OUTPUT, "Gate"); | |||||
onReset(); | |||||
} | |||||
void onReset() override { | |||||
offset = false; | |||||
} | } | ||||
void trigger() { | void trigger() { | ||||
@@ -87,6 +126,10 @@ struct Random : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
if (offsetTrigger.process(params[OFFSET_PARAM].getValue() > 0.f)) { | |||||
offset ^= true; | |||||
} | |||||
if (inputs[TRIGGER_INPUT].isConnected()) { | if (inputs[TRIGGER_INPUT].isConnected()) { | ||||
// Advance clock phase based on tempo estimate | // Advance clock phase based on tempo estimate | ||||
trigFrame++; | trigFrame++; | ||||
@@ -104,7 +147,7 @@ struct Random : Module { | |||||
else { | else { | ||||
// Advance clock phase by rate | // Advance clock phase by rate | ||||
float rate = params[RATE_PARAM].getValue(); | float rate = params[RATE_PARAM].getValue(); | ||||
rate += inputs[RATE_PARAM].getVoltage(); | |||||
rate += inputs[RATE_PARAM].getVoltage() * params[RATE_CV_PARAM].getValue(); | |||||
float clockFreq = std::pow(2.f, rate); | float clockFreq = std::pow(2.f, rate); | ||||
float deltaPhase = std::fmin(clockFreq * args.sampleTime, 0.5f); | float deltaPhase = std::fmin(clockFreq * args.sampleTime, 0.5f); | ||||
clockPhase += deltaPhase; | clockPhase += deltaPhase; | ||||
@@ -115,10 +158,9 @@ struct Random : Module { | |||||
} | } | ||||
} | } | ||||
// Shape | // Shape | ||||
float shape = params[SHAPE_PARAM].getValue(); | float shape = params[SHAPE_PARAM].getValue(); | ||||
shape += inputs[SHAPE_INPUT].getVoltage() / 10.f; | |||||
shape += inputs[SHAPE_INPUT].getVoltage() / 10.f * params[SHAPE_CV_PARAM].getValue(); | |||||
shape = clamp(shape, 0.f, 1.f); | shape = clamp(shape, 0.f, 1.f); | ||||
// Stepped | // Stepped | ||||
@@ -178,6 +220,35 @@ struct Random : Module { | |||||
// Lights | // Lights | ||||
lights[RATE_LIGHT].setSmoothBrightness(0.f, args.sampleTime); | lights[RATE_LIGHT].setSmoothBrightness(0.f, args.sampleTime); | ||||
lights[SHAPE_LIGHT].setBrightness(shape); | lights[SHAPE_LIGHT].setBrightness(shape); | ||||
lights[OFFSET_LIGHT].setBrightness(offset); | |||||
} | |||||
void paramsFromJson(json_t* rootJ) override { | |||||
// In <2.0, there were no attenuverters, so set them to 1.0 in case they are not overwritten. | |||||
params[RATE_CV_PARAM].setValue(1.f); | |||||
params[SHAPE_CV_PARAM].setValue(1.f); | |||||
params[PROB_CV_PARAM].setValue(1.f); | |||||
params[RANDOM_CV_PARAM].setValue(1.f); | |||||
Module::paramsFromJson(rootJ); | |||||
// In <2.0, OFFSET_PARAM was a toggle switch instead of a momentary button, so if param is on after deserializing, set boolean states instead. | |||||
if (params[OFFSET_PARAM].getValue() > 0.f) { | |||||
offset = true; | |||||
params[OFFSET_PARAM].setValue(0.f); | |||||
} | |||||
} | |||||
json_t* dataToJson() override { | |||||
json_t* rootJ = json_object(); | |||||
// offset | |||||
json_object_set_new(rootJ, "offset", json_boolean(offset)); | |||||
return rootJ; | |||||
} | |||||
void dataFromJson(json_t* rootJ) override { | |||||
// offset | |||||
json_t* offsetJ = json_object_get(rootJ, "offset"); | |||||
if (offsetJ) | |||||
offset = json_boolean_value(offsetJ); | |||||
} | } | ||||
}; | }; | ||||
@@ -192,20 +263,28 @@ struct RandomWidget : ModuleWidget { | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | 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))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(7.215, 30.858)), module, Random::RATE_PARAM, Random::RATE_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(18.214, 30.858)), module, Random::SHAPE_PARAM, Random::SHAPE_LIGHT)); | |||||
addParam(createParamCentered<CKSS>(mm2px(Vec(7.214, 78.259)), module, Random::OFFSET_PARAM)); | |||||
addParam(createParamCentered<CKSS>(mm2px(Vec(18.214, 78.259)), module, Random::MODE_PARAM)); | |||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(6.479, 33.605)), module, Random::RATE_PARAM, Random::RATE_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(17.315, 33.605)), module, Random::PROB_PARAM, Random::PROB_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(28.152, 33.605)), module, Random::RANDOM_PARAM, Random::RANDOM_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(mm2px(Vec(38.98, 33.605)), module, Random::SHAPE_PARAM, Random::SHAPE_LIGHT)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(6.479, 64.347)), module, Random::RATE_CV_PARAM)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(17.317, 64.347)), module, Random::PROB_CV_PARAM)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(28.154, 64.347)), module, Random::RANDOM_CV_PARAM)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(38.991, 64.347)), module, Random::SHAPE_CV_PARAM)); | |||||
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(28.154, 96.859)), module, Random::OFFSET_PARAM, Random::OFFSET_LIGHT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.214, 50.726)), module, Random::RATE_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.214, 50.726)), module, Random::SHAPE_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.214, 64.513)), module, Random::TRIGGER_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.214, 64.513)), module, Random::EXTERNAL_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.479, 80.549)), module, Random::RATE_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.317, 80.549)), module, Random::PROB_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.154, 80.553)), module, Random::RANDOM_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(38.991, 80.557)), module, Random::SHAPE_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.479, 96.859)), module, Random::TRIGGER_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.317, 96.859)), module, Random::EXTERNAL_INPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.214, 96.727)), module, Random::STEPPED_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.214, 96.727)), module, Random::LINEAR_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.214, 112.182)), module, Random::SMOOTH_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.214, 112.182)), module, Random::EXPONENTIAL_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(38.991, 96.859)), module, Random::GATE_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(6.479, 113.115)), module, Random::STEPPED_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(17.317, 113.115)), module, Random::LINEAR_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(28.154, 113.115)), module, Random::EXPONENTIAL_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(38.991, 113.115)), module, Random::SMOOTH_OUTPUT)); | |||||
} | } | ||||
}; | }; | ||||
@@ -50,11 +50,9 @@ struct SEQ3 : Module { | |||||
dsp::BooleanTrigger gateTriggers[8]; | dsp::BooleanTrigger gateTriggers[8]; | ||||
dsp::SchmittTrigger clockTrigger; | dsp::SchmittTrigger clockTrigger; | ||||
dsp::SchmittTrigger runTrigger; | |||||
dsp::SchmittTrigger resetTrigger; | dsp::SchmittTrigger resetTrigger; | ||||
dsp::PulseGenerator clockPulse; | dsp::PulseGenerator clockPulse; | ||||
dsp::PulseGenerator runPulse; | |||||
dsp::PulseGenerator resetPulse; | dsp::PulseGenerator resetPulse; | ||||
/** Phase of internal LFO */ | /** Phase of internal LFO */ | ||||
@@ -147,9 +145,12 @@ struct SEQ3 : Module { | |||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
// Run | // Run | ||||
// Use bitwise OR "|" to always evaluate both expressions | // Use bitwise OR "|" to always evaluate both expressions | ||||
if (runButtonTrigger.process(params[RUN_PARAM].getValue()) | runTrigger.process(inputs[RUN_INPUT].getVoltage(), 0.1f, 2.f)) { | |||||
if (runButtonTrigger.process(params[RUN_PARAM].getValue())) { | |||||
running ^= true; | running ^= true; | ||||
runPulse.trigger(1e-3f); | |||||
} | |||||
// Run input overrides button | |||||
if (inputs[RUN_INPUT].isConnected()) { | |||||
running = (inputs[RUN_INPUT].getVoltage() >= 2.f); | |||||
} | } | ||||
// Reset | // Reset | ||||
@@ -218,7 +219,7 @@ struct SEQ3 : Module { | |||||
outputs[STEPS_OUTPUT].setVoltage((numSteps - 1) * 1.f); | outputs[STEPS_OUTPUT].setVoltage((numSteps - 1) * 1.f); | ||||
outputs[CLOCK_OUTPUT].setVoltage(clockGate ? 10.f : 0.f); | outputs[CLOCK_OUTPUT].setVoltage(clockGate ? 10.f : 0.f); | ||||
outputs[RUN_OUTPUT].setVoltage(runPulse.process(args.sampleTime) ? 10.f : 0.f); | |||||
outputs[RUN_OUTPUT].setVoltage(running ? 10.f : 0.f); | |||||
outputs[RESET_OUTPUT].setVoltage(resetGate ? 10.f : 0.f); | outputs[RESET_OUTPUT].setVoltage(resetGate ? 10.f : 0.f); | ||||
lights[CLOCK_LIGHT].setSmoothBrightness(clockGate, args.sampleTime); | lights[CLOCK_LIGHT].setSmoothBrightness(clockGate, args.sampleTime); | ||||
@@ -24,6 +24,9 @@ struct Scope : Module { | |||||
NUM_INPUTS | NUM_INPUTS | ||||
}; | }; | ||||
enum OutputIds { | enum OutputIds { | ||||
// new in 2.0 | |||||
X_OUTPUT, | |||||
Y_OUTPUT, | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
enum LightIds { | enum LightIds { | ||||
@@ -353,36 +356,31 @@ struct ScopeWidget : ModuleWidget { | |||||
setModule(module); | setModule(module); | ||||
setPanel(createPanel(asset::plugin(pluginInstance, "res/Scope.svg"))); | setPanel(createPanel(asset::plugin(pluginInstance, "res/Scope.svg"))); | ||||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(15, 365))); | |||||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365))); | |||||
{ | |||||
ScopeDisplay* display = new ScopeDisplay(); | |||||
display->module = module; | |||||
display->box.pos = Vec(0, 44); | |||||
display->box.size = Vec(box.size.x, 140); | |||||
addChild(display); | |||||
} | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(15, 209), module, Scope::X_SCALE_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(15, 263), module, Scope::X_POS_PARAM)); | |||||
addParam(createParam<RoundBlackSnapKnob>(Vec(61, 209), module, Scope::Y_SCALE_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(61, 263), module, Scope::Y_POS_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(107, 209), module, Scope::TIME_PARAM)); | |||||
addParam(createParam<CKD6>(Vec(106, 262), module, Scope::LISSAJOUS_PARAM)); | |||||
addParam(createParam<RoundBlackKnob>(Vec(153, 209), module, Scope::TRIG_PARAM)); | |||||
addParam(createParam<CKD6>(Vec(152, 262), module, Scope::EXTERNAL_PARAM)); | |||||
addInput(createInput<PJ301MPort>(Vec(17, 319), module, Scope::X_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(63, 319), module, Scope::Y_INPUT)); | |||||
addInput(createInput<PJ301MPort>(Vec(154, 319), module, Scope::TRIG_INPUT)); | |||||
addChild(createLight<SmallLight<GreenLight>>(Vec(104, 251), module, Scope::PLOT_LIGHT)); | |||||
addChild(createLight<SmallLight<GreenLight>>(Vec(104, 296), module, Scope::LISSAJOUS_LIGHT)); | |||||
addChild(createLight<SmallLight<GreenLight>>(Vec(150, 251), module, Scope::INTERNAL_LIGHT)); | |||||
addChild(createLight<SmallLight<GreenLight>>(Vec(150, 296), module, Scope::EXTERNAL_LIGHT)); | |||||
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))); | |||||
// addParam(createParamCentered<LEDButton>(mm2px(Vec(8.643, 80.603)), module, Scope::_1X2_PARAM)); | |||||
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(24.897, 80.551)), module, Scope::X_SCALE_PARAM)); | |||||
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(41.147, 80.551)), module, Scope::Y_SCALE_PARAM)); | |||||
// addParam(createParamCentered<LEDButton>(mm2px(Vec(57.397, 80.521)), module, Scope::TRIG_PARAM)); | |||||
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(8.643, 96.819)), module, Scope::TIME_PARAM)); | |||||
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(24.897, 96.789)), module, Scope::X_POS_PARAM)); | |||||
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(41.147, 96.815)), module, Scope::Y_POS_PARAM)); | |||||
// addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(57.397, 96.815)), module, Scope::THERS_PARAM)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8.643, 113.115)), module, Scope::X_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(33.023, 113.115)), module, Scope::Y_INPUT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(57.397, 113.115)), module, Scope::TRIG_INPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(20.833, 113.115)), module, Scope::X_OUTPUT)); | |||||
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(45.212, 113.115)), module, Scope::Y_OUTPUT)); | |||||
ScopeDisplay* display = createWidget<ScopeDisplay>(Vec(0, 44)); | |||||
display->box.size = Vec(box.size.x, 140); | |||||
display->module = module; | |||||
addChild(display); | |||||
} | } | ||||
}; | }; | ||||
@@ -44,28 +44,30 @@ struct Viz : Module { | |||||
struct VizDisplay : Widget { | struct VizDisplay : Widget { | ||||
Viz* module; | Viz* module; | ||||
std::shared_ptr<Font> font; | |||||
VizDisplay() { | VizDisplay() { | ||||
box.size = mm2px(Vec(15.24, 88.126)); | box.size = mm2px(Vec(15.24, 88.126)); | ||||
font = APP->window->loadFont(asset::plugin(pluginInstance, "res/nunito/Nunito-Bold.ttf")); | |||||
} | } | ||||
void draw(const DrawArgs& args) override { | |||||
for (int c = 0; c < 16; c++) { | |||||
Vec p = Vec(15, 16 + (float) c / 16 * (box.size.y - 10)); | |||||
std::string text = string::f("%d", c + 1); | |||||
nvgFontFaceId(args.vg, font->handle); | |||||
nvgFontSize(args.vg, 11); | |||||
nvgTextLetterSpacing(args.vg, 0.0); | |||||
nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); | |||||
if (module && c < module->lastChannel) | |||||
nvgFillColor(args.vg, nvgRGB(255, 255, 255)); | |||||
else | |||||
nvgFillColor(args.vg, nvgRGB(99, 99, 99)); | |||||
nvgText(args.vg, p.x, p.y, text.c_str(), NULL); | |||||
void drawLayer(const DrawArgs& args, int layer) override { | |||||
if (layer == 1) { | |||||
for (int c = 0; c < 16; c++) { | |||||
Vec p = Vec(15, 16 + (float) c / 16 * (box.size.y - 10)); | |||||
std::string text = string::f("%d", c + 1); | |||||
std::shared_ptr<Font> font = APP->window->loadFont(asset::plugin(pluginInstance, "res/nunito/Nunito-Bold.ttf")); | |||||
nvgFontFaceId(args.vg, font->handle); | |||||
nvgFontSize(args.vg, 11); | |||||
nvgTextLetterSpacing(args.vg, 0.0); | |||||
nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); | |||||
if (module && c < module->lastChannel) | |||||
nvgFillColor(args.vg, nvgRGB(255, 255, 255)); | |||||
else | |||||
nvgFillColor(args.vg, nvgRGB(99, 99, 99)); | |||||
nvgText(args.vg, p.x, p.y, text.c_str(), NULL); | |||||
} | |||||
} | } | ||||
Widget::drawLayer(args, layer); | |||||
} | } | ||||
}; | }; | ||||
@@ -80,28 +82,29 @@ struct VizWidget : ModuleWidget { | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | 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))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.619, 21.346)), module, Viz::POLY_INPUT)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 33.626)), module, Viz::VU_LIGHTS + 0 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 38.916)), module, Viz::VU_LIGHTS + 1 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 44.205)), module, Viz::VU_LIGHTS + 2 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 49.496)), module, Viz::VU_LIGHTS + 3 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 54.785)), module, Viz::VU_LIGHTS + 4 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 60.075)), module, Viz::VU_LIGHTS + 5 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 65.364)), module, Viz::VU_LIGHTS + 6 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 70.654)), module, Viz::VU_LIGHTS + 7 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 75.943)), module, Viz::VU_LIGHTS + 8 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 81.233)), module, Viz::VU_LIGHTS + 9 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 86.522)), module, Viz::VU_LIGHTS + 10 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 91.812)), module, Viz::VU_LIGHTS + 11 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 97.101)), module, Viz::VU_LIGHTS + 12 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 102.392)), module, Viz::VU_LIGHTS + 13 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 107.681)), module, Viz::VU_LIGHTS + 14 * 2)); | |||||
addChild(createLightCentered<SmallLight<GreenRedLight>>(mm2px(Vec(10.854, 112.971)), module, Viz::VU_LIGHTS + 15 * 2)); | |||||
VizDisplay* vizDisplay = createWidget<VizDisplay>(mm2px(Vec(0.0, 29.235))); | |||||
vizDisplay->module = module; | |||||
addChild(vizDisplay); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(2.58, 7.229)), module, Viz::POLY_INPUT)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 11.388)), module, Viz::VU_LIGHTS + 0 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 13.18)), module, Viz::VU_LIGHTS + 1 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 14.971)), module, Viz::VU_LIGHTS + 2 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 16.763)), module, Viz::VU_LIGHTS + 3 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 18.554)), module, Viz::VU_LIGHTS + 4 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 20.345)), module, Viz::VU_LIGHTS + 5 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 22.137)), module, Viz::VU_LIGHTS + 6 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 23.928)), module, Viz::VU_LIGHTS + 7 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 25.719)), module, Viz::VU_LIGHTS + 8 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 27.511)), module, Viz::VU_LIGHTS + 9 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 29.302)), module, Viz::VU_LIGHTS + 10 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 31.094)), module, Viz::VU_LIGHTS + 11 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 32.885)), module, Viz::VU_LIGHTS + 12 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 34.677)), module, Viz::VU_LIGHTS + 13 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 36.468)), module, Viz::VU_LIGHTS + 14 * 2)); | |||||
addChild(createLightCentered<SmallSimpleLight<GreenRedLight>>(mm2px(Vec(3.676, 38.259)), module, Viz::VU_LIGHTS + 15 * 2)); | |||||
VizDisplay* display = createWidget<VizDisplay>(mm2px(Vec(0.0, 9.901))); | |||||
display->box.size = mm2px(Vec(5.161, 29.845)); | |||||
display->module = module; | |||||
addChild(display); | |||||
} | } | ||||
}; | }; | ||||
@@ -36,8 +36,6 @@ struct WTLFO : Module { | |||||
}; | }; | ||||
Wavetable wavetable; | Wavetable wavetable; | ||||
bool offset = false; | |||||
bool invert = false; | |||||
float_4 phases[4] = {}; | float_4 phases[4] = {}; | ||||
float lastPos = 0.f; | float lastPos = 0.f; | ||||
@@ -52,9 +50,8 @@ struct WTLFO : Module { | |||||
WTLFO() { | WTLFO() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
// TODO Change to momentary with backward compatibility in fromJson() | |||||
configButton(OFFSET_PARAM, "Offset 0-10V"); | |||||
configButton(INVERT_PARAM, "Invert wave"); | |||||
configSwitch(OFFSET_PARAM, 0.f, 1.f, 0.f, "Offset", {"Bipolar", "Unipolar"}); | |||||
configSwitch(INVERT_PARAM, 0.f, 1.f, 0.f, "Invert"); | |||||
struct FrequencyQuantity : ParamQuantity { | struct FrequencyQuantity : ParamQuantity { | ||||
float getDisplayValue() override { | float getDisplayValue() override { | ||||
@@ -88,8 +85,6 @@ struct WTLFO : Module { | |||||
} | } | ||||
void onReset() override { | void onReset() override { | ||||
offset = false; | |||||
invert = false; | |||||
wavetable.reset(); | wavetable.reset(); | ||||
// Reset state | // Reset state | ||||
@@ -100,12 +95,6 @@ struct WTLFO : Module { | |||||
clockTimer.reset(); | clockTimer.reset(); | ||||
} | } | ||||
void onRandomize(const RandomizeEvent& e) override { | |||||
Module::onRandomize(e); | |||||
offset = random::get<bool>(); | |||||
invert = random::get<bool>(); | |||||
} | |||||
void onAdd(const AddEvent& e) override { | void onAdd(const AddEvent& e) override { | ||||
std::string path = system::join(getPatchStorageDirectory(), "wavetable.wav"); | std::string path = system::join(getPatchStorageDirectory(), "wavetable.wav"); | ||||
// Silently fails | // Silently fails | ||||
@@ -119,19 +108,9 @@ struct WTLFO : Module { | |||||
} | } | ||||
} | } | ||||
void clearOutput() { | |||||
outputs[WAVE_OUTPUT].setVoltage(0.f); | |||||
outputs[WAVE_OUTPUT].setChannels(1); | |||||
lights[PHASE_LIGHT + 0].setBrightness(0.f); | |||||
lights[PHASE_LIGHT + 1].setBrightness(0.f); | |||||
lights[PHASE_LIGHT + 2].setBrightness(0.f); | |||||
} | |||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
if (offsetTrigger.process(params[OFFSET_PARAM].getValue() > 0.f)) | |||||
offset ^= true; | |||||
if (invertTrigger.process(params[INVERT_PARAM].getValue() > 0.f)) | |||||
invert ^= true; | |||||
bool offset = (params[OFFSET_PARAM].getValue() > 0.f); | |||||
bool invert = (params[INVERT_PARAM].getValue() > 0.f); | |||||
int channels = std::max(1, inputs[FM_INPUT].getChannels()); | int channels = std::max(1, inputs[FM_INPUT].getChannels()); | ||||
@@ -158,72 +137,71 @@ struct WTLFO : Module { | |||||
float posCvParam = params[POS_CV_PARAM].getValue(); | float posCvParam = params[POS_CV_PARAM].getValue(); | ||||
// Check valid wave and wavetable size | // Check valid wave and wavetable size | ||||
if (wavetable.waveLen < 2) { | |||||
clearOutput(); | |||||
return; | |||||
} | |||||
int waveCount = wavetable.getWaveCount(); | int waveCount = wavetable.getWaveCount(); | ||||
if (waveCount < 1) { | |||||
clearOutput(); | |||||
return; | |||||
} | |||||
// Iterate channels | |||||
for (int c = 0; c < channels; c += 4) { | |||||
// Calculate frequency in Hz | |||||
float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam; | |||||
float_4 freq = clockFreq / 2.f * dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f); | |||||
freq = simd::fmin(freq, 1024.f); | |||||
// Accumulate phase | |||||
float_4 phase = phases[c / 4]; | |||||
phase += freq * args.sampleTime; | |||||
// Wrap phase | |||||
phase -= simd::trunc(phase); | |||||
// Reset phase | |||||
float_4 reset = resetTriggers[c / 4].process(simd::rescale(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c), 0.1f, 2.f, 0.f, 1.f)); | |||||
phase = simd::ifelse(reset, 0.f, phase); | |||||
phases[c / 4] = phase; | |||||
// Scale phase from 0 to waveLen | |||||
phase *= wavetable.waveLen; | |||||
// Get wavetable position, scaled from 0 to (waveCount - 1) | |||||
float_4 pos = posParam + inputs[POS_INPUT].getPolyVoltageSimd<float_4>(c) * posCvParam / 10.f; | |||||
pos = simd::clamp(pos); | |||||
pos *= (waveCount - 1); | |||||
if (c == 0) | |||||
lastPos = pos[0]; | |||||
// Get wavetable points | |||||
float_4 out = 0.f; | |||||
for (int cc = 0; cc < 4 && c + cc < channels; cc++) { | |||||
// Get wave indexes | |||||
float phaseF = phase[cc] - std::trunc(phase[cc]); | |||||
size_t i0 = std::trunc(phase[cc]); | |||||
size_t i1 = (i0 + 1) % wavetable.waveLen; | |||||
// Get pos indexes | |||||
float posF = pos[cc] - std::trunc(pos[cc]); | |||||
size_t pos0 = std::trunc(pos[cc]); | |||||
size_t pos1 = pos0 + 1; | |||||
// Get waves | |||||
float out0 = crossfade(wavetable.at(pos0, i0), wavetable.at(pos0, i1), phaseF); | |||||
if (posF > 0.f) { | |||||
float out1 = crossfade(wavetable.at(pos1, i0), wavetable.at(pos1, i1), phaseF); | |||||
out[cc] = crossfade(out0, out1, posF); | |||||
if (wavetable.waveLen >= 2 && waveCount >= 1) { | |||||
// Iterate channels | |||||
for (int c = 0; c < channels; c += 4) { | |||||
// Calculate frequency in Hz | |||||
float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam; | |||||
float_4 freq = clockFreq / 2.f * dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f); | |||||
freq = simd::fmin(freq, 1024.f); | |||||
// Accumulate phase | |||||
float_4 phase = phases[c / 4]; | |||||
phase += freq * args.sampleTime; | |||||
// Wrap phase | |||||
phase -= simd::trunc(phase); | |||||
// Reset phase | |||||
float_4 reset = resetTriggers[c / 4].process(simd::rescale(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c), 0.1f, 2.f, 0.f, 1.f)); | |||||
phase = simd::ifelse(reset, 0.f, phase); | |||||
phases[c / 4] = phase; | |||||
// Scale phase from 0 to waveLen | |||||
phase *= wavetable.waveLen; | |||||
// Get wavetable position, scaled from 0 to (waveCount - 1) | |||||
float_4 pos = posParam + inputs[POS_INPUT].getPolyVoltageSimd<float_4>(c) * posCvParam / 10.f; | |||||
pos = simd::clamp(pos); | |||||
pos *= (waveCount - 1); | |||||
if (c == 0) | |||||
lastPos = pos[0]; | |||||
// Get wavetable points | |||||
float_4 out = 0.f; | |||||
for (int cc = 0; cc < 4 && c + cc < channels; cc++) { | |||||
// Get wave indexes | |||||
float phaseF = phase[cc] - std::trunc(phase[cc]); | |||||
size_t i0 = std::trunc(phase[cc]); | |||||
size_t i1 = (i0 + 1) % wavetable.waveLen; | |||||
// Get pos indexes | |||||
float posF = pos[cc] - std::trunc(pos[cc]); | |||||
size_t pos0 = std::trunc(pos[cc]); | |||||
size_t pos1 = pos0 + 1; | |||||
// Get waves | |||||
float out0 = crossfade(wavetable.at(pos0, i0), wavetable.at(pos0, i1), phaseF); | |||||
if (posF > 0.f) { | |||||
float out1 = crossfade(wavetable.at(pos1, i0), wavetable.at(pos1, i1), phaseF); | |||||
out[cc] = crossfade(out0, out1, posF); | |||||
} | |||||
else { | |||||
out[cc] = out0; | |||||
} | |||||
} | } | ||||
else { | |||||
out[cc] = out0; | |||||
} | |||||
} | |||||
// Invert and offset | |||||
if (invert) | |||||
out *= -1.f; | |||||
if (offset) | |||||
out += 1.f; | |||||
// Invert and offset | |||||
if (invert) | |||||
out *= -1.f; | |||||
if (offset) | |||||
out += 1.f; | |||||
outputs[WAVE_OUTPUT].setVoltageSimd(out * 5.f, c); | |||||
outputs[WAVE_OUTPUT].setVoltageSimd(out * 5.f, c); | |||||
} | |||||
} | |||||
else { | |||||
// Wavetable is invalid, so set 0V | |||||
for (int c = 0; c < channels; c += 4) { | |||||
outputs[WAVE_OUTPUT].setVoltageSimd(float_4(0.f), c); | |||||
} | |||||
} | } | ||||
outputs[WAVE_OUTPUT].setChannels(channels); | outputs[WAVE_OUTPUT].setChannels(channels); | ||||
@@ -248,10 +226,6 @@ struct WTLFO : Module { | |||||
json_t* dataToJson() override { | json_t* dataToJson() override { | ||||
json_t* rootJ = json_object(); | json_t* rootJ = json_object(); | ||||
// offset | |||||
json_object_set_new(rootJ, "offset", json_boolean(offset)); | |||||
// invert | |||||
json_object_set_new(rootJ, "invert", json_boolean(invert)); | |||||
// Merge wavetable | // Merge wavetable | ||||
json_t* wavetableJ = wavetable.toJson(); | json_t* wavetableJ = wavetable.toJson(); | ||||
json_object_update(rootJ, wavetableJ); | json_object_update(rootJ, wavetableJ); | ||||
@@ -260,14 +234,6 @@ struct WTLFO : Module { | |||||
} | } | ||||
void dataFromJson(json_t* rootJ) override { | void dataFromJson(json_t* rootJ) override { | ||||
// offset | |||||
json_t* offsetJ = json_object_get(rootJ, "offset"); | |||||
if (offsetJ) | |||||
offset = json_boolean_value(offsetJ); | |||||
// invert | |||||
json_t* invertJ = json_object_get(rootJ, "invert"); | |||||
if (invertJ) | |||||
invert = json_boolean_value(invertJ); | |||||
// wavetable | // wavetable | ||||
wavetable.fromJson(rootJ); | wavetable.fromJson(rootJ); | ||||
} | } | ||||
@@ -287,9 +253,9 @@ struct WTLFOWidget : ModuleWidget { | |||||
addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(8.913, 56.388)), module, WTLFO::FREQ_PARAM)); | addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(8.913, 56.388)), module, WTLFO::FREQ_PARAM)); | ||||
addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(26.647, 56.388)), module, WTLFO::POS_PARAM)); | addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(26.647, 56.388)), module, WTLFO::POS_PARAM)); | ||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(6.987, 80.603)), module, WTLFO::FM_PARAM)); | addParam(createParamCentered<Trimpot>(mm2px(Vec(6.987, 80.603)), module, WTLFO::FM_PARAM)); | ||||
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(17.824, 80.517)), module, WTLFO::INVERT_PARAM, WTLFO::INVERT_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightLatch<MediumSimpleLight<WhiteLight>>>(mm2px(Vec(17.824, 80.517)), module, WTLFO::INVERT_PARAM, WTLFO::INVERT_LIGHT)); | |||||
addParam(createParamCentered<Trimpot>(mm2px(Vec(28.662, 80.536)), module, WTLFO::POS_CV_PARAM)); | addParam(createParamCentered<Trimpot>(mm2px(Vec(28.662, 80.536)), module, WTLFO::POS_CV_PARAM)); | ||||
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(17.824, 96.859)), module, WTLFO::OFFSET_PARAM, WTLFO::OFFSET_LIGHT)); | |||||
addParam(createLightParamCentered<LEDLightLatch<MediumSimpleLight<WhiteLight>>>(mm2px(Vec(17.824, 96.859)), module, WTLFO::OFFSET_PARAM, WTLFO::OFFSET_LIGHT)); | |||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.987, 96.859)), module, WTLFO::FM_INPUT)); | addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.987, 96.859)), module, WTLFO::FM_INPUT)); | ||||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.662, 96.859)), module, WTLFO::POS_INPUT)); | addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.662, 96.859)), module, WTLFO::POS_INPUT)); | ||||
@@ -84,6 +84,8 @@ struct Wavetable { | |||||
/** Returns the number of waves in the wavetable. */ | /** Returns the number of waves in the wavetable. */ | ||||
size_t getWaveCount() const { | size_t getWaveCount() const { | ||||
if (waveLen == 0) | |||||
return 0; | |||||
return samples.size() / waveLen; | return samples.size() / waveLen; | ||||
} | } | ||||
@@ -145,8 +147,6 @@ struct Wavetable { | |||||
} | } | ||||
void load(std::string path) { | void load(std::string path) { | ||||
samples.clear(); | |||||
std::string ext = string::lowercase(system::getExtension(path)); | std::string ext = string::lowercase(system::getExtension(path)); | ||||
if (ext == ".wav") { | if (ext == ".wav") { | ||||
// Load WAV | // Load WAV | ||||
@@ -158,6 +158,7 @@ struct Wavetable { | |||||
#endif | #endif | ||||
return; | return; | ||||
samples.clear(); | |||||
samples.resize(wav.totalPCMFrameCount * wav.channels); | samples.resize(wav.totalPCMFrameCount * wav.channels); | ||||
drwav_read_pcm_frames_f32(&wav, wav.totalPCMFrameCount, samples.data()); | drwav_read_pcm_frames_f32(&wav, wav.totalPCMFrameCount, samples.data()); | ||||
@@ -166,6 +167,7 @@ struct Wavetable { | |||||
else { | else { | ||||
// Load bytes from file | // Load bytes from file | ||||
std::vector<uint8_t> data = system::readFile(path); | std::vector<uint8_t> data = system::readFile(path); | ||||
samples.clear(); | |||||
if (ext == ".f32") { | if (ext == ".f32") { | ||||
size_t len = data.size() / sizeof(float); | size_t len = data.size() / sizeof(float); | ||||