@@ -1,6 +1,4 @@ | |||
<?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#" | |||
@@ -9,243 +7,246 @@ | |||
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="15.239719mm" | |||
height="128.49931mm" | |||
viewBox="0 0 15.23972 128.49931" | |||
width="45" | |||
height="380" | |||
viewBox="0 0 45 380" | |||
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 | |||
id="metadata55288"> | |||
id="metadata158"> | |||
<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> | |||
<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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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 | |||
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" | |||
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> | |||
</svg> |
@@ -48,14 +48,12 @@ struct LFO : Module { | |||
float clockFreq = 1.f; | |||
dsp::Timer clockTimer; | |||
dsp::BooleanTrigger offsetTrigger; | |||
dsp::BooleanTrigger invertTrigger; | |||
dsp::ClockDivider lightDivider; | |||
LFO() { | |||
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 { | |||
float getDisplayValue() override { | |||
@@ -95,8 +93,6 @@ struct LFO : Module { | |||
} | |||
void onReset() override { | |||
offset = false; | |||
invert = false; | |||
for (int c = 0; c < 16; c += 4) { | |||
phases[c / 4] = 0.f; | |||
} | |||
@@ -109,14 +105,8 @@ struct LFO : Module { | |||
float fmParam = params[FM_PARAM].getValue(); | |||
float pwParam = params[PW_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 | |||
if (inputs[CLOCK_INPUT].isConnected()) { | |||
@@ -227,39 +217,6 @@ struct LFO : Module { | |||
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<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(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)); | |||
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, LFO::FM_INPUT)); | |||
@@ -7,6 +7,13 @@ struct Random : Module { | |||
SHAPE_PARAM, | |||
OFFSET_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 | |||
}; | |||
enum InputIds { | |||
@@ -14,6 +21,9 @@ struct Random : Module { | |||
SHAPE_INPUT, | |||
TRIGGER_INPUT, | |||
EXTERNAL_INPUT, | |||
// new in 2.0 | |||
PROB_INPUT, | |||
RANDOM_INPUT, | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
@@ -21,35 +31,64 @@ struct Random : Module { | |||
LINEAR_OUTPUT, | |||
SMOOTH_OUTPUT, | |||
EXPONENTIAL_OUTPUT, | |||
// new in 2.0 | |||
GATE_OUTPUT, // TODO | |||
NUM_OUTPUTS | |||
}; | |||
enum LightIds { | |||
RATE_LIGHT, | |||
SHAPE_LIGHT, | |||
PROB_LIGHT, | |||
RANDOM_LIGHT, | |||
OFFSET_LIGHT, | |||
NUM_LIGHTS | |||
}; | |||
dsp::SchmittTrigger trigTrigger; | |||
dsp::BooleanTrigger offsetTrigger; | |||
float lastValue = 0.f; | |||
float value = 0.f; | |||
float clockPhase = 0.f; | |||
int trigFrame = 0; | |||
int lastTrigFrames = INT_MAX; | |||
bool offset = false; | |||
Random() { | |||
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(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(SHAPE_INPUT, "Shape"); | |||
configInput(PROB_INPUT, "Probability"); | |||
configInput(RANDOM_INPUT, "Randomness"); | |||
configInput(TRIGGER_INPUT, "Trigger"); | |||
configInput(EXTERNAL_INPUT, "External"); | |||
configOutput(STEPPED_OUTPUT, "Stepped"); | |||
configOutput(LINEAR_OUTPUT, "Linear"); | |||
configOutput(SMOOTH_OUTPUT, "Smooth"); | |||
configOutput(EXPONENTIAL_OUTPUT, "Exponential"); | |||
configOutput(GATE_OUTPUT, "Gate"); | |||
onReset(); | |||
} | |||
void onReset() override { | |||
offset = false; | |||
} | |||
void trigger() { | |||
@@ -87,6 +126,10 @@ struct Random : Module { | |||
} | |||
void process(const ProcessArgs& args) override { | |||
if (offsetTrigger.process(params[OFFSET_PARAM].getValue() > 0.f)) { | |||
offset ^= true; | |||
} | |||
if (inputs[TRIGGER_INPUT].isConnected()) { | |||
// Advance clock phase based on tempo estimate | |||
trigFrame++; | |||
@@ -104,7 +147,7 @@ struct Random : Module { | |||
else { | |||
// Advance clock phase by rate | |||
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 deltaPhase = std::fmin(clockFreq * args.sampleTime, 0.5f); | |||
clockPhase += deltaPhase; | |||
@@ -115,10 +158,9 @@ struct Random : Module { | |||
} | |||
} | |||
// Shape | |||
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); | |||
// Stepped | |||
@@ -178,6 +220,35 @@ struct Random : Module { | |||
// Lights | |||
lights[RATE_LIGHT].setSmoothBrightness(0.f, args.sampleTime); | |||
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(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::SchmittTrigger clockTrigger; | |||
dsp::SchmittTrigger runTrigger; | |||
dsp::SchmittTrigger resetTrigger; | |||
dsp::PulseGenerator clockPulse; | |||
dsp::PulseGenerator runPulse; | |||
dsp::PulseGenerator resetPulse; | |||
/** Phase of internal LFO */ | |||
@@ -147,9 +145,12 @@ struct SEQ3 : Module { | |||
void process(const ProcessArgs& args) override { | |||
// Run | |||
// 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; | |||
runPulse.trigger(1e-3f); | |||
} | |||
// Run input overrides button | |||
if (inputs[RUN_INPUT].isConnected()) { | |||
running = (inputs[RUN_INPUT].getVoltage() >= 2.f); | |||
} | |||
// Reset | |||
@@ -218,7 +219,7 @@ struct SEQ3 : Module { | |||
outputs[STEPS_OUTPUT].setVoltage((numSteps - 1) * 1.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); | |||
lights[CLOCK_LIGHT].setSmoothBrightness(clockGate, args.sampleTime); | |||
@@ -24,6 +24,9 @@ struct Scope : Module { | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
// new in 2.0 | |||
X_OUTPUT, | |||
Y_OUTPUT, | |||
NUM_OUTPUTS | |||
}; | |||
enum LightIds { | |||
@@ -353,36 +356,31 @@ struct ScopeWidget : ModuleWidget { | |||
setModule(module); | |||
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 { | |||
Viz* module; | |||
std::shared_ptr<Font> font; | |||
VizDisplay() { | |||
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(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; | |||
bool offset = false; | |||
bool invert = false; | |||
float_4 phases[4] = {}; | |||
float lastPos = 0.f; | |||
@@ -52,9 +50,8 @@ struct WTLFO : Module { | |||
WTLFO() { | |||
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 { | |||
float getDisplayValue() override { | |||
@@ -88,8 +85,6 @@ struct WTLFO : Module { | |||
} | |||
void onReset() override { | |||
offset = false; | |||
invert = false; | |||
wavetable.reset(); | |||
// Reset state | |||
@@ -100,12 +95,6 @@ struct WTLFO : Module { | |||
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 { | |||
std::string path = system::join(getPatchStorageDirectory(), "wavetable.wav"); | |||
// 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 { | |||
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()); | |||
@@ -158,72 +137,71 @@ struct WTLFO : Module { | |||
float posCvParam = params[POS_CV_PARAM].getValue(); | |||
// Check valid wave and wavetable size | |||
if (wavetable.waveLen < 2) { | |||
clearOutput(); | |||
return; | |||
} | |||
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); | |||
@@ -248,10 +226,6 @@ struct WTLFO : Module { | |||
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)); | |||
// Merge wavetable | |||
json_t* wavetableJ = wavetable.toJson(); | |||
json_object_update(rootJ, wavetableJ); | |||
@@ -260,14 +234,6 @@ struct WTLFO : Module { | |||
} | |||
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.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(26.647, 56.388)), module, WTLFO::POS_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(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(28.662, 96.859)), module, WTLFO::POS_INPUT)); | |||
@@ -84,6 +84,8 @@ struct Wavetable { | |||
/** Returns the number of waves in the wavetable. */ | |||
size_t getWaveCount() const { | |||
if (waveLen == 0) | |||
return 0; | |||
return samples.size() / waveLen; | |||
} | |||
@@ -145,8 +147,6 @@ struct Wavetable { | |||
} | |||
void load(std::string path) { | |||
samples.clear(); | |||
std::string ext = string::lowercase(system::getExtension(path)); | |||
if (ext == ".wav") { | |||
// Load WAV | |||
@@ -158,6 +158,7 @@ struct Wavetable { | |||
#endif | |||
return; | |||
samples.clear(); | |||
samples.resize(wav.totalPCMFrameCount * wav.channels); | |||
drwav_read_pcm_frames_f32(&wav, wav.totalPCMFrameCount, samples.data()); | |||
@@ -166,6 +167,7 @@ struct Wavetable { | |||
else { | |||
// Load bytes from file | |||
std::vector<uint8_t> data = system::readFile(path); | |||
samples.clear(); | |||
if (ext == ".f32") { | |||
size_t len = data.size() / sizeof(float); | |||