diff --git a/res/8VERT.svg b/res/8vert.svg
similarity index 100%
rename from res/8VERT.svg
rename to res/8vert.svg
diff --git a/res/Mutes.svg b/res/Mutes.svg
new file mode 100644
index 0000000..640902c
--- /dev/null
+++ b/res/Mutes.svg
@@ -0,0 +1,1274 @@
+
+
+
+
diff --git a/res/Unity.svg b/res/Unity.svg
new file mode 100644
index 0000000..68d9790
--- /dev/null
+++ b/res/Unity.svg
@@ -0,0 +1,1791 @@
+
+
+
+
diff --git a/src/8VERT.cpp b/src/8vert.cpp
similarity index 93%
rename from src/8VERT.cpp
rename to src/8vert.cpp
index adde761..355520f 100644
--- a/src/8VERT.cpp
+++ b/src/8vert.cpp
@@ -1,7 +1,7 @@
#include "Fundamental.hpp"
-struct _8VERT : Module {
+struct _8vert : Module {
enum ParamIds {
NUM_PARAMS = 8
};
@@ -15,11 +15,11 @@ struct _8VERT : Module {
NUM_LIGHTS = 16
};
- _8VERT() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
+ _8vert() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
};
-void _8VERT::step() {
+void _8vert::step() {
float lastIn = 10.0;
for (int i = 0; i < 8; i++) {
lastIn = inputs[i].normalize(lastIn);
@@ -31,14 +31,14 @@ void _8VERT::step() {
}
-_8VERTWidget::_8VERTWidget() {
- _8VERT *module = new _8VERT();
+_8vertWidget::_8vertWidget() {
+ _8vert *module = new _8vert();
setModule(module);
box.size = Vec(8 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
SVGPanel *panel = new SVGPanel();
panel->box.size = box.size;
- panel->setBackground(SVG::load(assetPlugin(plugin, "res/8VERT.svg")));
+ panel->setBackground(SVG::load(assetPlugin(plugin, "res/8vert.svg")));
addChild(panel);
addChild(createScrew(Vec(15, 0)));
diff --git a/src/ADSR.cpp b/src/ADSR.cpp
index fbaed53..6fe9b8e 100644
--- a/src/ADSR.cpp
+++ b/src/ADSR.cpp
@@ -133,7 +133,7 @@ ADSRWidget::ADSRWidget() {
addOutput(createOutput(Vec(87, 320), module, ADSR::ENVELOPE_OUTPUT));
addChild(createLight>(Vec(94, 41), module, ADSR::ATTACK_LIGHT));
- addChild(createLight>(Vec(94, 108), module, ADSR::DECAY_LIGHT));
+ addChild(createLight>(Vec(94, 109), module, ADSR::DECAY_LIGHT));
addChild(createLight>(Vec(94, 175), module, ADSR::SUSTAIN_LIGHT));
- addChild(createLight>(Vec(94, 241), module, ADSR::RELEASE_LIGHT));
+ addChild(createLight>(Vec(94, 242), module, ADSR::RELEASE_LIGHT));
}
diff --git a/src/Fundamental.cpp b/src/Fundamental.cpp
index 9b0367d..e2f7290 100644
--- a/src/Fundamental.cpp
+++ b/src/Fundamental.cpp
@@ -18,7 +18,9 @@ void init(rack::Plugin *p) {
p->addModel(createModel("Fundamental", "Fundamental", "Delay", "Delay"));
p->addModel(createModel("Fundamental", "Fundamental", "ADSR", "ADSR"));
p->addModel(createModel("Fundamental", "Fundamental", "VCMixer", "VC Mixer"));
- p->addModel(createModel<_8VERTWidget>("Fundamental", "Fundamental", "8VERT", "8VERT"));
+ p->addModel(createModel<_8vertWidget>("Fundamental", "Fundamental", "8vert", "8vert"));
+ p->addModel(createModel("Fundamental", "Fundamental", "Unity", "Unity"));
+ p->addModel(createModel("Fundamental", "Fundamental", "Mutes", "Mutes"));
p->addModel(createModel("Fundamental", "Fundamental", "Scope", "Scope"));
p->addModel(createModel("Fundamental", "Fundamental", "SEQ3", "SEQ-3"));
}
diff --git a/src/Fundamental.hpp b/src/Fundamental.hpp
index 74aa0c2..4f85f83 100644
--- a/src/Fundamental.hpp
+++ b/src/Fundamental.hpp
@@ -46,8 +46,17 @@ struct VCMixerWidget : ModuleWidget {
VCMixerWidget();
};
-struct _8VERTWidget : ModuleWidget {
- _8VERTWidget();
+struct _8vertWidget : ModuleWidget {
+ _8vertWidget();
+};
+
+struct UnityWidget : ModuleWidget {
+ UnityWidget();
+ Menu *createContextMenu() override;
+};
+
+struct MutesWidget : ModuleWidget {
+ MutesWidget();
};
struct ScopeWidget : ModuleWidget {
diff --git a/src/Mutes.cpp b/src/Mutes.cpp
new file mode 100644
index 0000000..f323e25
--- /dev/null
+++ b/src/Mutes.cpp
@@ -0,0 +1,137 @@
+#include "Fundamental.hpp"
+#include "dsp/digital.hpp"
+
+
+struct Mutes : Module {
+ enum ParamIds {
+ MUTE_PARAM,
+ NUM_PARAMS = MUTE_PARAM + 10
+ };
+ enum InputIds {
+ IN_INPUT,
+ NUM_INPUTS = IN_INPUT + 10
+ };
+ enum OutputIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS = OUT_OUTPUT + 10
+ };
+ enum LightIds {
+ MUTE_LIGHT,
+ NUM_LIGHTS = MUTE_LIGHT + 10
+ };
+
+ bool state[10];
+ SchmittTrigger muteTrigger[10];
+
+ Mutes() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
+ reset();
+ }
+ void step() override;
+
+ void reset() override {
+ for (int i = 0; i < 10; i++) {
+ state[i] = true;
+ }
+ }
+ void randomize() override {
+ for (int i = 0; i < 10; i++) {
+ state[i] = (randomf() < 0.5);
+ }
+ }
+
+ json_t *toJson() override {
+ json_t *rootJ = json_object();
+ // states
+ json_t *statesJ = json_array();
+ for (int i = 0; i < 8; i++) {
+ json_t *stateJ = json_boolean(state[i]);
+ json_array_append_new(statesJ, stateJ);
+ }
+ json_object_set_new(rootJ, "states", statesJ);
+ return rootJ;
+ }
+ void fromJson(json_t *rootJ) override {
+ // states
+ json_t *statesJ = json_object_get(rootJ, "states");
+ if (statesJ) {
+ for (int i = 0; i < 8; i++) {
+ json_t *stateJ = json_array_get(statesJ, i);
+ if (stateJ)
+ state[i] = json_boolean_value(stateJ);
+ }
+ }
+ }
+};
+
+void Mutes::step() {
+ for (int i = 0; i < 10; i++) {
+ if (muteTrigger[i].process(params[MUTE_PARAM + i].value))
+ state[i] ^= true;
+ float in = inputs[IN_INPUT + i].value;
+ outputs[OUT_OUTPUT + i].value = state[i] ? in : 0.0;
+ lights[MUTE_LIGHT + i].setBrightness(state[i] ? 0.9 : 0.0);
+ }
+}
+
+
+template
+struct MuteLight : BASE {
+ MuteLight() {
+ this->box.size = mm2px(Vec(6.0, 6.0));
+ }
+};
+
+MutesWidget::MutesWidget() {
+ Mutes *module = new Mutes();
+ setModule(module);
+ setPanel(SVG::load(assetPlugin(plugin, "res/Mutes.svg")));
+
+ addChild(createScrew(Vec(15, 0)));
+ addChild(createScrew(Vec(box.size.x - 30, 0)));
+ addChild(createScrew(Vec(15, 365)));
+ addChild(createScrew(Vec(box.size.x - 30, 365)));
+
+ addParam(createParam(mm2px(Vec(16.57, 18.165)), module, Mutes::MUTE_PARAM + 0, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 28.164)), module, Mutes::MUTE_PARAM + 1, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 38.164)), module, Mutes::MUTE_PARAM + 2, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 48.165)), module, Mutes::MUTE_PARAM + 3, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 58.164)), module, Mutes::MUTE_PARAM + 4, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 68.165)), module, Mutes::MUTE_PARAM + 5, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 78.164)), module, Mutes::MUTE_PARAM + 6, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 88.164)), module, Mutes::MUTE_PARAM + 7, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 98.165)), module, Mutes::MUTE_PARAM + 8, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(16.57, 108.166)), module, Mutes::MUTE_PARAM + 9, 0.0, 1.0, 0.0));
+
+ addInput(createInput(mm2px(Vec(4.214, 17.81)), module, Mutes::IN_INPUT + 0));
+ addInput(createInput(mm2px(Vec(4.214, 27.809)), module, Mutes::IN_INPUT + 1));
+ addInput(createInput(mm2px(Vec(4.214, 37.809)), module, Mutes::IN_INPUT + 2));
+ addInput(createInput(mm2px(Vec(4.214, 47.81)), module, Mutes::IN_INPUT + 3));
+ addInput(createInput(mm2px(Vec(4.214, 57.81)), module, Mutes::IN_INPUT + 4));
+ addInput(createInput(mm2px(Vec(4.214, 67.809)), module, Mutes::IN_INPUT + 5));
+ addInput(createInput(mm2px(Vec(4.214, 77.81)), module, Mutes::IN_INPUT + 6));
+ addInput(createInput(mm2px(Vec(4.214, 87.81)), module, Mutes::IN_INPUT + 7));
+ addInput(createInput(mm2px(Vec(4.214, 97.809)), module, Mutes::IN_INPUT + 8));
+ addInput(createInput(mm2px(Vec(4.214, 107.809)), module, Mutes::IN_INPUT + 9));
+
+ addOutput(createOutput(mm2px(Vec(28.214, 17.81)), module, Mutes::OUT_OUTPUT + 0));
+ addOutput(createOutput(mm2px(Vec(28.214, 27.809)), module, Mutes::OUT_OUTPUT + 1));
+ addOutput(createOutput(mm2px(Vec(28.214, 37.809)), module, Mutes::OUT_OUTPUT + 2));
+ addOutput(createOutput(mm2px(Vec(28.214, 47.81)), module, Mutes::OUT_OUTPUT + 3));
+ addOutput(createOutput(mm2px(Vec(28.214, 57.809)), module, Mutes::OUT_OUTPUT + 4));
+ addOutput(createOutput(mm2px(Vec(28.214, 67.809)), module, Mutes::OUT_OUTPUT + 5));
+ addOutput(createOutput(mm2px(Vec(28.214, 77.81)), module, Mutes::OUT_OUTPUT + 6));
+ addOutput(createOutput(mm2px(Vec(28.214, 87.81)), module, Mutes::OUT_OUTPUT + 7));
+ addOutput(createOutput(mm2px(Vec(28.214, 97.809)), module, Mutes::OUT_OUTPUT + 8));
+ addOutput(createOutput(mm2px(Vec(28.214, 107.809)), module, Mutes::OUT_OUTPUT + 9));
+
+ addChild(createLight>(mm2px(Vec(17.32, 18.915)), module, Mutes::MUTE_LIGHT + 0));
+ addChild(createLight>(mm2px(Vec(17.32, 28.916)), module, Mutes::MUTE_LIGHT + 1));
+ addChild(createLight>(mm2px(Vec(17.32, 38.915)), module, Mutes::MUTE_LIGHT + 2));
+ addChild(createLight>(mm2px(Vec(17.32, 48.915)), module, Mutes::MUTE_LIGHT + 3));
+ addChild(createLight>(mm2px(Vec(17.32, 58.916)), module, Mutes::MUTE_LIGHT + 4));
+ addChild(createLight>(mm2px(Vec(17.32, 68.916)), module, Mutes::MUTE_LIGHT + 5));
+ addChild(createLight>(mm2px(Vec(17.32, 78.915)), module, Mutes::MUTE_LIGHT + 6));
+ addChild(createLight>(mm2px(Vec(17.32, 88.916)), module, Mutes::MUTE_LIGHT + 7));
+ addChild(createLight>(mm2px(Vec(17.32, 98.915)), module, Mutes::MUTE_LIGHT + 8));
+ addChild(createLight>(mm2px(Vec(17.32, 108.915)), module, Mutes::MUTE_LIGHT + 9));
+}
diff --git a/src/SEQ3.cpp b/src/SEQ3.cpp
index 720f9c8..24eb5e2 100644
--- a/src/SEQ3.cpp
+++ b/src/SEQ3.cpp
@@ -228,14 +228,14 @@ SEQ3Widget::SEQ3Widget() {
addParam(createParam(Vec(18, 56), module, SEQ3::CLOCK_PARAM, -2.0, 6.0, 2.0));
addParam(createParam(Vec(60, 61-1), module, SEQ3::RUN_PARAM, 0.0, 1.0, 0.0));
- addChild(createLight>(Vec(65, 65), module, SEQ3::RUNNING_LIGHT));
+ addChild(createLight>(Vec(64.4, 64.4), module, SEQ3::RUNNING_LIGHT));
addParam(createParam(Vec(99, 61-1), module, SEQ3::RESET_PARAM, 0.0, 1.0, 0.0));
- addChild(createLight>(Vec(104, 65), module, SEQ3::RESET_LIGHT));
+ addChild(createLight>(Vec(103.4, 64.4), module, SEQ3::RESET_LIGHT));
addParam(createParam(Vec(132, 56), module, SEQ3::STEPS_PARAM, 1.0, 8.0, 8.0));
- addChild(createLight>(Vec(180, 65), module, SEQ3::GATES_LIGHT));
- addChild(createLight>(Vec(219, 65), module, SEQ3::ROW_LIGHTS));
- addChild(createLight>(Vec(257, 65), module, SEQ3::ROW_LIGHTS + 1));
- addChild(createLight>(Vec(296, 65), module, SEQ3::ROW_LIGHTS + 2));
+ addChild(createLight>(Vec(179.4, 64.4), module, SEQ3::GATES_LIGHT));
+ addChild(createLight>(Vec(218.4, 64.4), module, SEQ3::ROW_LIGHTS));
+ addChild(createLight>(Vec(256.4, 64.4), module, SEQ3::ROW_LIGHTS + 1));
+ addChild(createLight>(Vec(295.4, 64.4), module, SEQ3::ROW_LIGHTS + 2));
static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289};
addInput(createInput(Vec(portX[0]-1, 98), module, SEQ3::CLOCK_INPUT));
@@ -252,7 +252,7 @@ SEQ3Widget::SEQ3Widget() {
addParam(createParam(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i, 0.0, 10.0, 0.0));
addParam(createParam(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i, 0.0, 10.0, 0.0));
addParam(createParam(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i, 0.0, 1.0, 0.0));
- addChild(createLight>(Vec(portX[i]+7, 282), module, SEQ3::GATE_LIGHTS + i));
+ addChild(createLight>(Vec(portX[i]+6.4, 281.4), module, SEQ3::GATE_LIGHTS + i));
addOutput(createOutput(Vec(portX[i]-1, 307), module, SEQ3::GATE_OUTPUT + i));
}
}
diff --git a/src/Scope.cpp b/src/Scope.cpp
index 86809a4..186e21a 100644
--- a/src/Scope.cpp
+++ b/src/Scope.cpp
@@ -338,8 +338,8 @@ ScopeWidget::ScopeWidget() {
addInput(createInput(Vec(63, 319), module, Scope::Y_INPUT));
addInput(createInput(Vec(154, 319), module, Scope::TRIG_INPUT));
- addChild(createLight>(Vec(104, 251), module, Scope::PLOT_LIGHT));
- addChild(createLight>(Vec(104, 296), module, Scope::LISSAJOUS_LIGHT));
- addChild(createLight>(Vec(150, 251), module, Scope::INTERNAL_LIGHT));
- addChild(createLight>(Vec(150, 296), module, Scope::EXTERNAL_LIGHT));
+ addChild(createLight>(Vec(104, 251), module, Scope::PLOT_LIGHT));
+ addChild(createLight>(Vec(104, 296), module, Scope::LISSAJOUS_LIGHT));
+ addChild(createLight>(Vec(150, 251), module, Scope::INTERNAL_LIGHT));
+ addChild(createLight>(Vec(150, 296), module, Scope::EXTERNAL_LIGHT));
}
diff --git a/src/Unity.cpp b/src/Unity.cpp
new file mode 100644
index 0000000..938e28e
--- /dev/null
+++ b/src/Unity.cpp
@@ -0,0 +1,160 @@
+#include "Fundamental.hpp"
+
+
+struct Unity : Module {
+ enum ParamIds {
+ AVG1_PARAM,
+ AVG2_PARAM,
+ NUM_PARAMS
+ };
+ enum InputIds {
+ IN1_INPUT,
+ IN2_INPUT = IN1_INPUT + 6,
+ NUM_INPUTS = IN2_INPUT + 6
+ };
+ enum OutputIds {
+ MIX1_OUTPUT,
+ INV1_OUTPUT,
+ MIX2_OUTPUT,
+ INV2_OUTPUT,
+ NUM_OUTPUTS
+ };
+ enum LightIds {
+ VU1_LIGHT,
+ VU2_LIGHT = VU1_LIGHT + 5,
+ NUM_LIGHTS = VU2_LIGHT + 5
+ };
+
+ bool merge = false;
+
+ Unity() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
+ void step() override;
+
+ void reset() override {
+ merge = false;
+ }
+
+ json_t *toJson() override {
+ json_t *rootJ = json_object();
+ // merge
+ json_object_set_new(rootJ, "merge", json_boolean(merge));
+ return rootJ;
+ }
+
+ void fromJson(json_t *rootJ) override {
+ // merge
+ json_t *mergeJ = json_object_get(rootJ, "merge");
+ if (mergeJ)
+ merge = json_boolean_value(mergeJ);
+ }
+};
+
+void Unity::step() {
+ float mix[2] = {};
+ int count[2] = {};
+
+ for (int i = 0; i < 2; i++) {
+ // Inputs
+ for (int j = 0; j < 6; j++) {
+ mix[i] += inputs[IN1_INPUT + 6*i + j].value;
+ if (inputs[IN1_INPUT + 6*i + j].active)
+ count[i]++;
+ }
+ }
+
+ // Combine
+ if (merge) {
+ mix[0] += mix[1];
+ mix[1] = mix[0];
+ count[0] += count[1];
+ count[1] = count[0];
+ }
+
+ for (int i = 0; i < 2; i++) {
+ // Params
+ if ((int) params[AVG1_PARAM + i].value == 1 && count[i] > 0)
+ mix[i] /= count[i];
+
+ // Outputs
+ outputs[MIX1_OUTPUT + 2*i].value = mix[i];
+ outputs[INV1_OUTPUT + 2*i].value = -mix[i];
+ // Lights
+ float dB = logf(fabsf(mix[i] / 10.0)) / logf(20.0) * 10.0;
+ for (int j = 0; j < 5; j++) {
+ float b = clampf(dB / 3.0 + 1 + j, 0.0, 1.0);
+ lights[VU1_LIGHT + 5*i + j].setBrightnessSmooth(b);
+ }
+ }
+}
+
+
+UnityWidget::UnityWidget() {
+ Unity *module = new Unity();
+ setModule(module);
+ setPanel(SVG::load(assetPlugin(plugin, "res/Unity.svg")));
+
+ addChild(createScrew(Vec(15, 0)));
+ addChild(createScrew(Vec(box.size.x - 30, 0)));
+ addChild(createScrew(Vec(15, 365)));
+ addChild(createScrew(Vec(box.size.x - 30, 365)));
+
+ addParam(createParam(mm2px(Vec(12.867, 52.961)), module, Unity::AVG1_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(mm2px(Vec(12.867, 107.006)), module, Unity::AVG2_PARAM, 0.0, 1.0, 0.0));
+
+ addInput(createInput(mm2px(Vec(2.361, 17.144)), module, Unity::IN1_INPUT + 0));
+ addInput(createInput(mm2px(Vec(19.907, 17.144)), module, Unity::IN1_INPUT + 1));
+ addInput(createInput(mm2px(Vec(2.361, 28.145)), module, Unity::IN1_INPUT + 2));
+ addInput(createInput(mm2px(Vec(19.907, 28.145)), module, Unity::IN1_INPUT + 3));
+ addInput(createInput(mm2px(Vec(2.361, 39.145)), module, Unity::IN1_INPUT + 4));
+ addInput(createInput(mm2px(Vec(19.907, 39.145)), module, Unity::IN1_INPUT + 5));
+ addInput(createInput(mm2px(Vec(2.361, 71.145)), module, Unity::IN2_INPUT + 0));
+ addInput(createInput(mm2px(Vec(19.907, 71.145)), module, Unity::IN2_INPUT + 1));
+ addInput(createInput(mm2px(Vec(2.361, 82.145)), module, Unity::IN2_INPUT + 2));
+ addInput(createInput(mm2px(Vec(19.907, 82.145)), module, Unity::IN2_INPUT + 3));
+ addInput(createInput(mm2px(Vec(2.361, 93.144)), module, Unity::IN2_INPUT + 4));
+ addInput(createInput(mm2px(Vec(19.907, 93.144)), module, Unity::IN2_INPUT + 5));
+
+ addOutput(createOutput(mm2px(Vec(2.361, 54.15)), module, Unity::MIX1_OUTPUT));
+ addOutput(createOutput(mm2px(Vec(19.907, 54.15)), module, Unity::INV1_OUTPUT));
+ addOutput(createOutput(mm2px(Vec(2.361, 108.144)), module, Unity::MIX2_OUTPUT));
+ addOutput(createOutput(mm2px(Vec(19.907, 108.144)), module, Unity::INV2_OUTPUT));
+
+ addChild(createLight>(mm2px(Vec(13.652, 19.663)), module, Unity::VU1_LIGHT + 0));
+ addChild(createLight>(mm2px(Vec(13.652, 25.163)), module, Unity::VU1_LIGHT + 1));
+ addChild(createLight>(mm2px(Vec(13.652, 30.663)), module, Unity::VU1_LIGHT + 2));
+ addChild(createLight>(mm2px(Vec(13.652, 36.162)), module, Unity::VU1_LIGHT + 3));
+ addChild(createLight>(mm2px(Vec(13.652, 41.662)), module, Unity::VU1_LIGHT + 4));
+ addChild(createLight>(mm2px(Vec(13.652, 73.663)), module, Unity::VU2_LIGHT + 0));
+ addChild(createLight>(mm2px(Vec(13.652, 79.163)), module, Unity::VU2_LIGHT + 1));
+ addChild(createLight>(mm2px(Vec(13.652, 84.663)), module, Unity::VU2_LIGHT + 2));
+ addChild(createLight>(mm2px(Vec(13.652, 90.162)), module, Unity::VU2_LIGHT + 3));
+ addChild(createLight>(mm2px(Vec(13.652, 95.662)), module, Unity::VU2_LIGHT + 4));
+}
+
+
+struct UnityMergeItem : MenuItem {
+ Unity *unity;
+ void onAction(EventAction &e) override {
+ unity->merge ^= true;
+ }
+ void step() override {
+ rightText = (unity->merge) ? "✔" : "";
+ }
+};
+
+Menu *UnityWidget::createContextMenu() {
+ Menu *menu = ModuleWidget::createContextMenu();
+
+ MenuLabel *spacerLabel = new MenuLabel();
+ menu->pushChild(spacerLabel);
+
+ Unity *unity = dynamic_cast(module);
+ assert(unity);
+
+ UnityMergeItem *mergeItem = new UnityMergeItem();
+ mergeItem->text = "Merge channels 1 & 2";
+ mergeItem->unity = unity;
+ menu->pushChild(mergeItem);
+
+ return menu;
+}