#include "plugin.hpp" struct Merge : Module { enum ParamIds { NUM_PARAMS }; enum InputIds { ENUMS(MONO_INPUTS, 16), NUM_INPUTS }; enum OutputIds { POLY_OUTPUT, NUM_OUTPUTS }; enum LightIds { ENUMS(CHANNEL_LIGHTS, 16), NUM_LIGHTS }; dsp::ClockDivider lightDivider; int channels = -1; int automaticChannels = 0; Merge() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (int i = 0; i < 16; i++) configInput(MONO_INPUTS + i, string::f("Channel %d", i + 1)); configOutput(POLY_OUTPUT, "Polyphonic"); lightDivider.setDivision(512); onReset(); } void onReset() override { channels = -1; } void process(const ProcessArgs& args) override { int lastChannel = -1; for (int c = 0; c < 16; c++) { float v = 0.f; if (inputs[MONO_INPUTS + c].isConnected()) { lastChannel = c; v = inputs[MONO_INPUTS + c].getVoltage(); } outputs[POLY_OUTPUT].setVoltage(v, c); } automaticChannels = lastChannel + 1; // In order to allow 0 channels, modify `channels` directly instead of using `setChannels()` outputs[POLY_OUTPUT].channels = (channels >= 0) ? channels : automaticChannels; } json_t* dataToJson() override { json_t* rootJ = json_object(); json_object_set_new(rootJ, "channels", json_integer(channels)); return rootJ; } void dataFromJson(json_t* rootJ) override { json_t* channelsJ = json_object_get(rootJ, "channels"); if (channelsJ) channels = json_integer_value(channelsJ); } }; struct MergeChannelDisplay : ChannelDisplay { Merge* module; void step() override { int channels = 16; if (module) { channels = module->channels; if (channels < 0) channels = module->automaticChannels; } text = string::f("%d", channels); } }; struct MergeWidget : ModuleWidget { MergeWidget(Merge* module) { setModule(module); setPanel(createPanel(asset::plugin(pluginInstance, "res/Merge.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))); addInput(createInputCentered(mm2px(Vec(7.281, 41.995)), module, Merge::MONO_INPUTS + 0)); addInput(createInputCentered(mm2px(Vec(7.281, 52.155)), module, Merge::MONO_INPUTS + 1)); addInput(createInputCentered(mm2px(Vec(7.281, 62.315)), module, Merge::MONO_INPUTS + 2)); addInput(createInputCentered(mm2px(Vec(7.281, 72.475)), module, Merge::MONO_INPUTS + 3)); addInput(createInputCentered(mm2px(Vec(7.281, 82.635)), module, Merge::MONO_INPUTS + 4)); addInput(createInputCentered(mm2px(Vec(7.281, 92.795)), module, Merge::MONO_INPUTS + 5)); addInput(createInputCentered(mm2px(Vec(7.281, 102.955)), module, Merge::MONO_INPUTS + 6)); addInput(createInputCentered(mm2px(Vec(7.281, 113.115)), module, Merge::MONO_INPUTS + 7)); addInput(createInputCentered(mm2px(Vec(18.119, 41.995)), module, Merge::MONO_INPUTS + 8)); addInput(createInputCentered(mm2px(Vec(18.119, 52.155)), module, Merge::MONO_INPUTS + 9)); addInput(createInputCentered(mm2px(Vec(18.119, 62.315)), module, Merge::MONO_INPUTS + 10)); addInput(createInputCentered(mm2px(Vec(18.119, 72.475)), module, Merge::MONO_INPUTS + 11)); addInput(createInputCentered(mm2px(Vec(18.119, 82.635)), module, Merge::MONO_INPUTS + 12)); addInput(createInputCentered(mm2px(Vec(18.119, 92.795)), module, Merge::MONO_INPUTS + 13)); addInput(createInputCentered(mm2px(Vec(18.119, 102.955)), module, Merge::MONO_INPUTS + 14)); addInput(createInputCentered(mm2px(Vec(18.119, 113.115)), module, Merge::MONO_INPUTS + 15)); addOutput(createOutputCentered(mm2px(Vec(7.281, 21.967)), module, Merge::POLY_OUTPUT)); MergeChannelDisplay* display = createWidget(mm2px(Vec(14.02, 18.611))); display->box.size = mm2px(Vec(8.197, 8.197)); display->module = module; addChild(display); } void appendContextMenu(Menu* menu) override { Merge* module = dynamic_cast(this->module); menu->addChild(new MenuSeparator); std::vector channelLabels; channelLabels.push_back(string::f("Automatic (%d)", module->automaticChannels)); for (int i = 0; i <= 16; i++) { channelLabels.push_back(string::f("%d", i)); } menu->addChild(createIndexSubmenuItem("Channels", channelLabels, [=]() {return module->channels + 1;}, [=](int i) {module->channels = i - 1;} )); } }; Model* modelMerge = createModel("Merge");