#include "plugin.hpp" struct Unity : Module { enum ParamIds { AVG1_PARAM, AVG2_PARAM, NUM_PARAMS }; enum InputIds { ENUMS(IN_INPUTS, 2 * 6), NUM_INPUTS }; enum OutputIds { MIX1_OUTPUT, INV1_OUTPUT, MIX2_OUTPUT, INV2_OUTPUT, NUM_OUTPUTS }; enum LightIds { ENUMS(VU_LIGHTS, 2 * 5), NUM_LIGHTS }; bool merge = false; dsp::VuMeter2 vuMeters[2]; dsp::ClockDivider lightDivider; Unity() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(AVG1_PARAM, 0.0, 1.0, 0.0, "Ch 1 average mode"); configParam(AVG2_PARAM, 0.0, 1.0, 0.0, "Ch 2 average mode"); lightDivider.setDivision(256); } void process(const ProcessArgs &args) override { float mix[2] = {}; int count[2] = {}; for (int i = 0; i < 2; i++) { // Inputs for (int j = 0; j < 6; j++) { mix[i] += inputs[IN_INPUTS + 6 * i + j].getVoltage(); if (inputs[IN_INPUTS + 6 * i + j].isConnected()) 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 (count[i] > 0 && (int) std::round(params[AVG1_PARAM + i].getValue()) == 1) mix[i] /= count[i]; // Outputs outputs[MIX1_OUTPUT + 2 * i].setVoltage(mix[i]); outputs[INV1_OUTPUT + 2 * i].setVoltage(-mix[i]); vuMeters[i].process(args.sampleTime, mix[i] / 10.f); } if (lightDivider.process()) { // Lights for (int i = 0; i < 2; i++) { lights[VU_LIGHTS + 5 * i + 0].setBrightness(vuMeters[i].getBrightness(0.f, 0.f)); for (int j = 1; j < 5; j++) { lights[VU_LIGHTS + 5 * i + j].setBrightness(vuMeters[i].getBrightness(-6.f * (j + 1), -6.f * j)); } } } } void onReset() override { merge = false; } json_t *dataToJson() override { json_t *rootJ = json_object(); // merge json_object_set_new(rootJ, "merge", json_boolean(merge)); return rootJ; } void dataFromJson(json_t *rootJ) override { // merge json_t *mergeJ = json_object_get(rootJ, "merge"); if (mergeJ) merge = json_boolean_value(mergeJ); } }; struct UnityMergeItem : MenuItem { Unity *unity; void onAction(const event::Action &e) override { unity->merge ^= true; } void step() override { rightText = CHECKMARK(unity->merge); } }; struct UnityWidget : ModuleWidget { UnityWidget(Unity *module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Unity.svg"))); addChild(createWidget(Vec(15, 0))); addChild(createWidget(Vec(box.size.x - 30, 0))); addChild(createWidget(Vec(15, 365))); addChild(createWidget(Vec(box.size.x - 30, 365))); addParam(createParam(mm2px(Vec(12.867, 52.961)), module, Unity::AVG1_PARAM)); addParam(createParam(mm2px(Vec(12.867, 107.006)), module, Unity::AVG2_PARAM)); addInput(createInput(mm2px(Vec(2.361, 17.144)), module, Unity::IN_INPUTS + 0 * 6 + 0)); addInput(createInput(mm2px(Vec(19.907, 17.144)), module, Unity::IN_INPUTS + 0 * 6 + 1)); addInput(createInput(mm2px(Vec(2.361, 28.145)), module, Unity::IN_INPUTS + 0 * 6 + 2)); addInput(createInput(mm2px(Vec(19.907, 28.145)), module, Unity::IN_INPUTS + 0 * 6 + 3)); addInput(createInput(mm2px(Vec(2.361, 39.145)), module, Unity::IN_INPUTS + 0 * 6 + 4)); addInput(createInput(mm2px(Vec(19.907, 39.145)), module, Unity::IN_INPUTS + 0 * 6 + 5)); addInput(createInput(mm2px(Vec(2.361, 71.145)), module, Unity::IN_INPUTS + 1 * 6 + 0)); addInput(createInput(mm2px(Vec(19.907, 71.145)), module, Unity::IN_INPUTS + 1 * 6 + 1)); addInput(createInput(mm2px(Vec(2.361, 82.145)), module, Unity::IN_INPUTS + 1 * 6 + 2)); addInput(createInput(mm2px(Vec(19.907, 82.145)), module, Unity::IN_INPUTS + 1 * 6 + 3)); addInput(createInput(mm2px(Vec(2.361, 93.144)), module, Unity::IN_INPUTS + 1 * 6 + 4)); addInput(createInput(mm2px(Vec(19.907, 93.144)), module, Unity::IN_INPUTS + 1 * 6 + 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::VU_LIGHTS + 0 * 5 + 0)); addChild(createLight>(mm2px(Vec(13.652, 25.163)), module, Unity::VU_LIGHTS + 0 * 5 + 1)); addChild(createLight>(mm2px(Vec(13.652, 30.663)), module, Unity::VU_LIGHTS + 0 * 5 + 2)); addChild(createLight>(mm2px(Vec(13.652, 36.162)), module, Unity::VU_LIGHTS + 0 * 5 + 3)); addChild(createLight>(mm2px(Vec(13.652, 41.662)), module, Unity::VU_LIGHTS + 0 * 5 + 4)); addChild(createLight>(mm2px(Vec(13.652, 73.663)), module, Unity::VU_LIGHTS + 1 * 5 + 0)); addChild(createLight>(mm2px(Vec(13.652, 79.163)), module, Unity::VU_LIGHTS + 1 * 5 + 1)); addChild(createLight>(mm2px(Vec(13.652, 84.663)), module, Unity::VU_LIGHTS + 1 * 5 + 2)); addChild(createLight>(mm2px(Vec(13.652, 90.162)), module, Unity::VU_LIGHTS + 1 * 5 + 3)); addChild(createLight>(mm2px(Vec(13.652, 95.662)), module, Unity::VU_LIGHTS + 1 * 5 + 4)); } void appendContextMenu(Menu *menu) override { menu->addChild(new MenuEntry); Unity *unity = dynamic_cast(module); assert(unity); UnityMergeItem *mergeItem = createMenuItem("Merge channels 1 & 2"); mergeItem->unity = unity; menu->addChild(mergeItem); } }; Model *modelUnity = createModel("Unity");