diff --git a/plugin.json b/plugin.json
index 02a9634..582fe2b 100644
--- a/plugin.json
+++ b/plugin.json
@@ -329,6 +329,22 @@
"Utility",
"Polyphonic"
]
+ },
+ {
+ "slug": "Gates",
+ "name": "Gates",
+ "description": "Gate processor",
+ "tags": [
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Process",
+ "name": "Process",
+ "description": "CV processor",
+ "tags": [
+ "Polyphonic"
+ ]
}
]
}
\ No newline at end of file
diff --git a/res/Compare.svg b/res/Compare.svg
index 2d90c79..4312c4a 100644
--- a/res/Compare.svg
+++ b/res/Compare.svg
@@ -39,8 +39,8 @@
id="namedview210"
showgrid="false"
inkscape:zoom="1.7566021"
- inkscape:cx="-38.246552"
- inkscape:cy="209.86956"
+ inkscape:cx="-69.046764"
+ inkscape:cy="171.2647"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
@@ -49,52 +49,52 @@
id="defs9">
+ id="uuid-c64f22f2-9902-4383-a90c-2ce3d9bf4a00"
+ data-name="FND BG"
+ style="display:inline">
+ style="fill:url(#uuid-ceb1f0ca-0ca2-46a9-982b-2ba7e59fdccb)"
+ id="rect11"
+ x="0"
+ y="0" />
+ id="uuid-0cf2d9fd-764c-4eb5-8d95-894a7f181361"
+ data-name="FND GRAPH"
+ style="display:inline">
-
+ id="g74">
+ style="opacity:0.68999999;isolation:isolate;fill:none"
+ id="circle62" />
+ id="g68">
+ d="m 48.29822,97.10256 c 6.2955,-3.78272 10.15833,-10.61025 10.15833,-17.95479 0,-11.491 -9.45566,-20.94666 -20.94666,-20.94666 -11.491,0 -20.94666,9.45566 -20.94666,20.94666 0,7.39639 3.91756,14.2646 10.28394,18.02967"
+ style="fill:none;stroke:#1f1f1f;stroke-width:0.80000001px;stroke-linecap:round;stroke-miterlimit:10"
+ id="path64"
+ inkscape:connector-curvature="0" />
+ id="g66" />
+ y2="78.999901"
+ style="fill:none"
+ id="line70" />
+ x1="37.509899"
+ y1="58.201111"
+ x2="37.509899"
+ y2="71.622688"
+ style="fill:none;stroke:#1f1f1f;stroke-width:0.80000001px;stroke-linecap:round;stroke-miterlimit:10"
+ id="line72" />
+ id="g84">
-
-
-
+ style="fill:#1f1f1f"
+ id="circle76" />
+
+
+
+ id="uuid-30565932-5eae-46d1-839e-14a2da3e712f"
+ data-name="FND TXT"
+ style="display:inline">
-
-
-
+ id="g93">
+
+
+
-
-
-
+ id="g101">
+
+
+
-
-
-
-
+ id="g111">
+
+
+
+
-
-
-
+ id="g119">
+
+
+
-
-
-
-
+ id="g129">
+
+
+
+
-
-
-
+ id="g137">
+
+
+
-
-
-
+ id="g145">
+
+
+
-
-
-
+ id="g153">
+
+
+
+ d="m 19.26953,139.13867 1.76172,-3.9292 c 0.09375,-0.20996 0.26367,-0.33887 0.50098,-0.33887 h 0.04004 c 0.2373,0 0.40039,0.12891 0.49512,0.33887 l 1.76074,3.9292 c 0.03418,0.0615 0.04785,0.12207 0.04785,0.17627 0,0.22363 -0.16895,0.3999 -0.39258,0.3999 -0.19629,0 -0.33203,-0.11523 -0.40723,-0.2915 l -0.38574,-0.88721 h -2.30371 l -0.39941,0.91455 c -0.06738,0.16943 -0.20996,0.26416 -0.38574,0.26416 -0.2168,0 -0.38672,-0.16943 -0.38672,-0.38623 0,-0.061 0.02051,-0.12207 0.05469,-0.18994 z m 3.10254,-1.34131 -0.83301,-1.91748 -0.83398,1.91748 z"
+ style="fill:#1f1f1f"
+ id="path155"
+ inkscape:connector-curvature="0" />
-
-
-
+ d="m 51.71289,135.3584 c 0,-0.2373 0.18359,-0.41992 0.41992,-0.41992 h 1.70703 c 0.54297,0 0.96875,0.14893 1.24023,0.41992 0.20996,0.20996 0.31836,0.46777 0.31836,0.78613 v 0.0137 c 0,0.56885 -0.3252,0.87402 -0.67773,1.05664 0.55566,0.18945 0.94238,0.50781 0.94238,1.15186 v 0.0132 c 0,0.84717 -0.69824,1.30078 -1.75488,1.30078 h -1.77539 c -0.23633,0 -0.41992,-0.18262 -0.41992,-0.41992 z m 1.95801,1.57861 c 0.53516,0 0.89453,-0.20996 0.89453,-0.64355 v -0.0137 c 0,-0.37256 -0.29785,-0.60303 -0.83301,-0.60303 H 52.5332 v 1.26025 z m 0.24414,2.00537 c 0.56934,0 0.91504,-0.22363 0.91504,-0.65039 v -0.0137 c 0,-0.39941 -0.31934,-0.63672 -0.97656,-0.63672 h -1.32031 v 1.30078 h 1.38184 z"
+ style="fill:#1f1f1f"
+ id="path157"
+ inkscape:connector-curvature="0" />
-
-
-
-
-
-
-
+ id="g173">
+
+
+
+
+
+
+
-
-
+ d="m 5.26953,23.93262 v -0.02539 c 0,-2.48975 1.87695,-4.5293 4.56641,-4.5293 1.31445,0 2.20215,0.35059 2.92773,0.88867 0.20117,0.1499 0.375,0.4248 0.375,0.7627 0,0.52588 -0.4248,0.93848 -0.9502,0.93848 -0.2627,0 -0.43848,-0.09961 -0.5752,-0.1875 -0.53906,-0.40039 -1.10156,-0.62549 -1.78906,-0.62549 -1.47656,0 -2.54102,1.22607 -2.54102,2.72754 v 0.0249 c 0,1.50146 1.03906,2.75293 2.54102,2.75293 0.8125,0 1.35059,-0.25049 1.90137,-0.68848 0.14941,-0.125 0.35059,-0.2124 0.5752,-0.2124 0.48828,0 0.90039,0.40039 0.90039,0.88818 0,0.30029 -0.14941,0.53809 -0.32422,0.68848 -0.78906,0.68799 -1.71484,1.10059 -3.11523,1.10059 -2.57812,0 -4.49219,-1.98926 -4.49219,-4.50391 z"
+ style="fill:#1f1f1f"
+ id="path175"
+ inkscape:connector-curvature="0" />
+
+
+
+
+
+
+
diff --git a/res/Logic.svg b/res/Logic.svg
index e8ab8b1..418b4fa 100644
--- a/res/Logic.svg
+++ b/res/Logic.svg
@@ -11,11 +11,11 @@
height="380"
viewBox="0 0 75 380"
version="1.1"
- id="svg184"
+ id="svg182"
sodipodi:docname="LOGIC.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ id="metadata186">
@@ -36,49 +36,49 @@
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
- id="namedview186"
+ id="namedview184"
showgrid="false"
inkscape:zoom="1.7566021"
- inkscape:cx="6.8846065"
- inkscape:cy="228.3692"
+ inkscape:cx="-3.4927966"
+ inkscape:cy="234.97865"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
- inkscape:current-layer="svg184" />
+ inkscape:current-layer="svg182" />
-
+ id="g18">
+ id="rect14" />
+ id="rect16" />
+ id="g24">
+ id="rect20" />
+ id="rect22" />
+ id="g30">
+ id="rect26" />
+ id="rect28" />
+ id="g36">
+ id="rect32" />
+ id="rect34" />
+ id="g42">
+ id="rect38" />
+ id="rect40" />
+ id="g48">
+ id="rect44" />
+ id="rect46" />
+ id="g54">
+ id="rect50" />
+ id="rect52" />
+ id="g60">
+ id="rect56" />
+ id="rect58" />
+ id="g70">
+ id="circle62" />
+ id="path64" />
+ id="path66" />
+ id="path68" />
+ id="g81">
+ id="path73" />
+ id="path75" />
+ id="path77" />
+ id="path79" />
+ id="g91">
+ id="path83" />
+ id="path85" />
+ id="path87" />
+ id="path89" />
+ id="g97">
+ id="path93" />
+ id="path95" />
+ id="g105">
+ id="path99" />
+ id="path101" />
+ id="path103" />
+ id="g113">
+ id="path107" />
+ id="path109" />
+ id="path111" />
+ id="g123">
+ id="path115" />
+ id="path117" />
+ id="path119" />
+ id="path121" />
+ id="g131">
+ id="path125" />
+ id="path127" />
+ id="path129" />
+ id="g141">
+ id="path133" />
+ id="path135" />
+ id="path137" />
+ id="path139" />
+ id="path143" />
+ id="path145" />
+ id="path147" />
+ id="g159">
+ id="path149" />
+ id="path151" />
+ id="path153" />
+ id="path155" />
+ id="path157" />
+
diff --git a/src/Gates.cpp b/src/Gates.cpp
new file mode 100644
index 0000000..935e147
--- /dev/null
+++ b/src/Gates.cpp
@@ -0,0 +1,205 @@
+#include "plugin.hpp"
+
+
+struct Gates : Module {
+ enum ParamId {
+ LENGTH_PARAM,
+ RESET_PARAM,
+ PARAMS_LEN
+ };
+ enum InputId {
+ LENGTH_INPUT,
+ IN_INPUT,
+ RESET_INPUT,
+ INPUTS_LEN
+ };
+ enum OutputId {
+ RISE_OUTPUT,
+ FALL_OUTPUT,
+ FLIP_OUTPUT,
+ FLOP_OUTPUT,
+ GATE_OUTPUT,
+ END_OUTPUT,
+ OUTPUTS_LEN
+ };
+ enum LightId {
+ RESET_LIGHT,
+ ENUMS(RISE_LIGHT, 2),
+ ENUMS(FALL_LIGHT, 2),
+ ENUMS(FLIP_LIGHT, 2),
+ ENUMS(FLOP_LIGHT, 2),
+ ENUMS(GATE_LIGHT, 2),
+ ENUMS(END_LIGHT, 2),
+ LIGHTS_LEN
+ };
+
+ dsp::BooleanTrigger resetParamTrigger;
+ bool state[16] = {};
+ dsp::SchmittTrigger resetTrigger[16];
+ dsp::PulseGenerator risePulse[16];
+ dsp::PulseGenerator fallPulse[16];
+ dsp::PulseGenerator eogPulse[16];
+ bool flop[16] = {};
+ float gateTime[16] = {};
+ dsp::ClockDivider lightDivider;
+
+ Gates() {
+ config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
+ configParam(LENGTH_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(0.1f), "Gate length", " ms", 2, 1000);
+ configButton(RESET_PARAM, "Reset flip/flop");
+ configInput(LENGTH_INPUT, "Gate length");
+ configInput(IN_INPUT, "Gate");
+ configInput(RESET_INPUT, "Reset flip/flop");
+ configOutput(RISE_OUTPUT, "Rising edge trigger");
+ configOutput(FALL_OUTPUT, "Falling edge trigger");
+ configOutput(FLIP_OUTPUT, "Flip");
+ configOutput(FLOP_OUTPUT, "Flop");
+ configOutput(GATE_OUTPUT, "Gate");
+ configOutput(END_OUTPUT, "End of gate");
+
+ lightDivider.setDivision(32);
+ for (int c = 0; c < 16; c++) {
+ gateTime[c] = INFINITY;
+ }
+ }
+
+ void process(const ProcessArgs& args) override {
+ int channels = inputs[IN_INPUT].getChannels();
+
+ bool anyRise = false;
+ bool anyFall = false;
+ bool anyFlip = false;
+ bool anyFlop = false;
+ bool anyGate = false;
+ bool anyEnd = false;
+
+ // Reset
+ if (resetParamTrigger.process(params[RESET_PARAM].getValue() > 0.f)) {
+ for (int c = 0; c < 16; c++) {
+ flop[c] = false;
+ }
+ }
+
+ // Process channels
+ for (int c = 0; c < channels; c++) {
+ float in = inputs[IN_INPUT].getVoltage(c);
+
+ if (state[c]) {
+ // HIGH to LOW
+ if (in <= 0.1f) {
+ state[c] = false;
+ fallPulse[c].trigger(1e-3f);
+ }
+ }
+ else {
+ // LOW to HIGH
+ if (in >= 2.f) {
+ state[c] = true;
+ risePulse[c].trigger(1e-3f);
+ // Flip flop
+ flop[c] ^= true;
+ // Gate
+ gateTime[c] = 0.f;
+ }
+ }
+
+ // Reset
+ if (resetTrigger[c].process(inputs[RESET_INPUT].getVoltage(c), 0.1f, 2.f)) {
+ flop[c] = false;
+ }
+
+ // Gate
+ float gatePitch = params[LENGTH_PARAM].getValue() + inputs[LENGTH_INPUT].getPolyVoltage(c);
+ float gateLength = dsp::approxExp2_taylor5(gatePitch + 30.f) / 1073741824;
+ if (std::isfinite(gateTime[c]) && gateTime[c] >= gateLength) {
+ gateTime[c] = INFINITY;
+ eogPulse[c].trigger(1e-3f);
+ }
+ gateTime[c] += args.sampleTime;
+
+ // Outputs
+ bool rise = risePulse[c].process(args.sampleTime);
+ outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c);
+ anyRise = anyRise || rise;
+
+ bool fall = fallPulse[c].process(args.sampleTime);
+ outputs[FALL_OUTPUT].setVoltage(fall ? 10.f : 0.f, c);
+ anyFall = anyFall || fall;
+
+ outputs[FLIP_OUTPUT].setVoltage(!flop[c] ? 10.f : 0.f, c);
+ anyFlip = anyFlip || !flop[c];
+
+ outputs[FLOP_OUTPUT].setVoltage(flop[c] ? 10.f : 0.f, c);
+ anyFlop = anyFlop || flop[c];
+
+ bool gate = std::isfinite(gateTime[c]);
+ outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c);
+ anyGate = anyGate || gate;
+
+ bool end = eogPulse[c].process(args.sampleTime);
+ outputs[END_OUTPUT].setVoltage(end ? 10.f : 0.f, c);
+ anyEnd = anyEnd || end;
+ }
+
+ outputs[RISE_OUTPUT].setChannels(channels);
+ outputs[FALL_OUTPUT].setChannels(channels);
+ outputs[FLIP_OUTPUT].setChannels(channels);
+ outputs[FLOP_OUTPUT].setChannels(channels);
+ outputs[GATE_OUTPUT].setChannels(channels);
+ outputs[END_OUTPUT].setChannels(channels);
+
+ if (lightDivider.process()) {
+ float lightTime = args.sampleTime * lightDivider.getDivision();
+ lights[RESET_LIGHT].setBrightness(params[RESET_PARAM].getValue() > 0.f);
+ lights[RISE_LIGHT + 0].setBrightnessSmooth(anyRise && channels <= 1, lightTime);
+ lights[RISE_LIGHT + 1].setBrightnessSmooth(anyRise && channels > 1, lightTime);
+ lights[FALL_LIGHT + 0].setBrightnessSmooth(anyFall && channels <= 1, lightTime);
+ lights[FALL_LIGHT + 1].setBrightnessSmooth(anyFall && channels > 1, lightTime);
+ lights[FLIP_LIGHT + 0].setBrightnessSmooth(anyFlip && channels <= 1, lightTime);
+ lights[FLIP_LIGHT + 1].setBrightnessSmooth(anyFlip && channels > 1, lightTime);
+ lights[FLOP_LIGHT + 0].setBrightnessSmooth(anyFlop && channels <= 1, lightTime);
+ lights[FLOP_LIGHT + 1].setBrightnessSmooth(anyFlop && channels > 1, lightTime);
+ lights[GATE_LIGHT + 0].setBrightnessSmooth(anyGate && channels <= 1, lightTime);
+ lights[GATE_LIGHT + 1].setBrightnessSmooth(anyGate && channels > 1, lightTime);
+ lights[END_LIGHT + 0].setBrightnessSmooth(anyEnd && channels <= 1, lightTime);
+ lights[END_LIGHT + 1].setBrightnessSmooth(anyEnd && channels > 1, lightTime);
+ }
+ }
+};
+
+
+struct GatesWidget : ModuleWidget {
+ GatesWidget(Gates* module) {
+ setModule(module);
+ setPanel(createPanel(asset::plugin(pluginInstance, "res/Gates.svg")));
+
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+
+ addParam(createParamCentered(mm2px(Vec(12.646, 26.755)), module, Gates::LENGTH_PARAM));
+ addParam(createLightParamCentered>(mm2px(Vec(18.146, 52.31)), module, Gates::RESET_PARAM, Gates::RESET_LIGHT));
+
+ addInput(createInputCentered(mm2px(Vec(7.299, 52.31)), module, Gates::LENGTH_INPUT));
+ addInput(createInputCentered(mm2px(Vec(7.297, 67.53)), module, Gates::IN_INPUT));
+ addInput(createInputCentered(mm2px(Vec(18.132, 67.53)), module, Gates::RESET_INPUT));
+
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 82.732)), module, Gates::RISE_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 82.732)), module, Gates::FALL_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 97.958)), module, Gates::FLIP_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 97.958)), module, Gates::FLOP_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 113.115)), module, Gates::GATE_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 113.115)), module, Gates::END_OUTPUT));
+
+ addChild(createLightCentered>>(mm2px(Vec(11.027, 79.007)), module, Gates::RISE_LIGHT));
+ addChild(createLightCentered>>(mm2px(Vec(21.864, 79.007)), module, Gates::FALL_LIGHT));
+ addChild(createLightCentered>>(mm2px(Vec(11.027, 94.233)), module, Gates::FLIP_LIGHT));
+ addChild(createLightCentered>>(mm2px(Vec(21.864, 94.233)), module, Gates::FLOP_LIGHT));
+ addChild(createLightCentered>>(mm2px(Vec(11.027, 109.393)), module, Gates::GATE_LIGHT));
+ addChild(createLightCentered>>(mm2px(Vec(21.864, 109.393)), module, Gates::END_LIGHT));
+ }
+};
+
+
+Model* modelGates = createModel("Gates");
\ No newline at end of file
diff --git a/src/Process.cpp b/src/Process.cpp
new file mode 100644
index 0000000..02e2b29
--- /dev/null
+++ b/src/Process.cpp
@@ -0,0 +1,76 @@
+#include "plugin.hpp"
+
+
+struct Process : Module {
+ enum ParamId {
+ SLEW_PARAM,
+ PUSH_PARAM,
+ PARAMS_LEN
+ };
+ enum InputId {
+ SLEW_INPUT,
+ IN_INPUT,
+ GATE_INPUT,
+ INPUTS_LEN
+ };
+ enum OutputId {
+ SH1_OUTPUT,
+ SH2_OUTPUT,
+ TH_OUTPUT,
+ HT_OUTPUT,
+ SLEW_OUTPUT,
+ GLIDE_OUTPUT,
+ OUTPUTS_LEN
+ };
+ enum LightId {
+ LIGHTS_LEN
+ };
+
+ Process() {
+ config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
+ configParam(SLEW_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(0.1f), "Slew", " ms/V", 2, 1000);
+ configButton(PUSH_PARAM, "Gate");
+ configInput(SLEW_INPUT, "Slew");
+ configInput(IN_INPUT, "Voltage");
+ configInput(GATE_INPUT, "Gate");
+ configOutput(SH1_OUTPUT, "Sample & hold");
+ configOutput(SH2_OUTPUT, "Sample & hold 2");
+ configOutput(TH_OUTPUT, "Trigger & hold");
+ configOutput(HT_OUTPUT, "Hold & trigger");
+ configOutput(SLEW_OUTPUT, "Slew");
+ configOutput(GLIDE_OUTPUT, "Glide");
+ }
+
+ void process(const ProcessArgs& args) override {
+ }
+};
+
+
+struct ProcessWidget : ModuleWidget {
+ ProcessWidget(Process* module) {
+ setModule(module);
+ setPanel(createPanel(asset::plugin(pluginInstance, "res/Process.svg")));
+
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+
+ addParam(createParamCentered(mm2px(Vec(12.646, 26.755)), module, Process::SLEW_PARAM));
+ // addParam(createParamCentered(mm2px(Vec(18.136, 52.31)), module, Process::PUSH_PARAM));
+
+ addInput(createInputCentered(mm2px(Vec(7.299, 52.31)), module, Process::SLEW_INPUT));
+ addInput(createInputCentered(mm2px(Vec(7.297, 67.53)), module, Process::IN_INPUT));
+ addInput(createInputCentered(mm2px(Vec(18.122, 67.53)), module, Process::GATE_INPUT));
+
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 82.732)), module, Process::SH1_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 82.732)), module, Process::SH2_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 97.958)), module, Process::TH_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 97.923)), module, Process::HT_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(7.297, 113.115)), module, Process::SLEW_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.134, 113.115)), module, Process::GLIDE_OUTPUT));
+ }
+};
+
+
+Model* modelProcess = createModel("Process");
\ No newline at end of file
diff --git a/src/plugin.cpp b/src/plugin.cpp
index dd2b1dd..f737025 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -38,4 +38,6 @@ void init(Plugin* p) {
p->addModel(modelFade);
p->addModel(modelLogic);
p->addModel(modelCompare);
+ p->addModel(modelGates);
+ p->addModel(modelProcess);
}
diff --git a/src/plugin.hpp b/src/plugin.hpp
index 989de51..ad57997 100644
--- a/src/plugin.hpp
+++ b/src/plugin.hpp
@@ -38,6 +38,8 @@ extern Model* modelCVMix;
extern Model* modelFade;
extern Model* modelLogic;
extern Model* modelCompare;
+extern Model* modelGates;
+extern Model* modelProcess;
struct DigitalDisplay : Widget {