You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.8KB

  1. #include "plugin.hpp"
  2. struct Merge : Module {
  3. enum ParamIds {
  4. NUM_PARAMS
  5. };
  6. enum InputIds {
  7. ENUMS(MONO_INPUTS, 16),
  8. NUM_INPUTS
  9. };
  10. enum OutputIds {
  11. POLY_OUTPUT,
  12. NUM_OUTPUTS
  13. };
  14. enum LightIds {
  15. ENUMS(CHANNEL_LIGHTS, 16),
  16. NUM_LIGHTS
  17. };
  18. int channels = -1;
  19. int automaticChannels = 0;
  20. Merge() {
  21. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  22. for (int i = 0; i < 16; i++)
  23. configInput(MONO_INPUTS + i, string::f("Channel %d", i + 1));
  24. configOutput(POLY_OUTPUT, "Polyphonic");
  25. onReset();
  26. }
  27. void onReset() override {
  28. channels = -1;
  29. }
  30. void process(const ProcessArgs& args) override {
  31. int lastChannel = -1;
  32. for (int c = 0; c < 16; c++) {
  33. float v = 0.f;
  34. if (inputs[MONO_INPUTS + c].isConnected()) {
  35. lastChannel = c;
  36. v = inputs[MONO_INPUTS + c].getVoltage();
  37. }
  38. outputs[POLY_OUTPUT].setVoltage(v, c);
  39. }
  40. automaticChannels = lastChannel + 1;
  41. // In order to allow 0 channels, modify `channels` directly instead of using `setChannels()`
  42. outputs[POLY_OUTPUT].channels = (channels >= 0) ? channels : automaticChannels;
  43. }
  44. json_t* dataToJson() override {
  45. json_t* rootJ = json_object();
  46. json_object_set_new(rootJ, "channels", json_integer(channels));
  47. return rootJ;
  48. }
  49. void dataFromJson(json_t* rootJ) override {
  50. json_t* channelsJ = json_object_get(rootJ, "channels");
  51. if (channelsJ)
  52. channels = json_integer_value(channelsJ);
  53. }
  54. };
  55. struct MergeChannelDisplay : ChannelDisplay {
  56. Merge* module;
  57. void step() override {
  58. int channels = 16;
  59. if (module) {
  60. channels = module->channels;
  61. if (channels < 0)
  62. channels = module->automaticChannels;
  63. }
  64. text = string::f("%d", channels);
  65. }
  66. };
  67. struct MergeWidget : ModuleWidget {
  68. MergeWidget(Merge* module) {
  69. setModule(module);
  70. setPanel(createPanel(asset::plugin(pluginInstance, "res/Merge.svg"), asset::plugin(pluginInstance, "res/Merge-dark.svg")));
  71. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, 0)));
  72. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  73. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  74. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  75. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 41.995)), module, Merge::MONO_INPUTS + 0));
  76. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 52.155)), module, Merge::MONO_INPUTS + 1));
  77. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 62.315)), module, Merge::MONO_INPUTS + 2));
  78. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 72.475)), module, Merge::MONO_INPUTS + 3));
  79. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 82.635)), module, Merge::MONO_INPUTS + 4));
  80. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 92.795)), module, Merge::MONO_INPUTS + 5));
  81. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 102.955)), module, Merge::MONO_INPUTS + 6));
  82. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 113.115)), module, Merge::MONO_INPUTS + 7));
  83. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 41.995)), module, Merge::MONO_INPUTS + 8));
  84. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 52.155)), module, Merge::MONO_INPUTS + 9));
  85. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 62.315)), module, Merge::MONO_INPUTS + 10));
  86. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 72.475)), module, Merge::MONO_INPUTS + 11));
  87. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 82.635)), module, Merge::MONO_INPUTS + 12));
  88. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 92.795)), module, Merge::MONO_INPUTS + 13));
  89. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 102.955)), module, Merge::MONO_INPUTS + 14));
  90. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.119, 113.115)), module, Merge::MONO_INPUTS + 15));
  91. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.281, 21.967)), module, Merge::POLY_OUTPUT));
  92. MergeChannelDisplay* display = createWidget<MergeChannelDisplay>(mm2px(Vec(14.02, 18.611)));
  93. display->box.size = mm2px(Vec(8.197, 8.197));
  94. display->module = module;
  95. addChild(display);
  96. }
  97. void appendContextMenu(Menu* menu) override {
  98. Merge* module = dynamic_cast<Merge*>(this->module);
  99. menu->addChild(new MenuSeparator);
  100. std::vector<std::string> channelLabels;
  101. channelLabels.push_back(string::f("Automatic (%d)", module->automaticChannels));
  102. for (int i = 0; i <= 16; i++) {
  103. channelLabels.push_back(string::f("%d", i));
  104. }
  105. menu->addChild(createIndexSubmenuItem("Channels", channelLabels,
  106. [=]() {return module->channels + 1;},
  107. [=](int i) {module->channels = i - 1;}
  108. ));
  109. }
  110. };
  111. Model* modelMerge = createModel<Merge, MergeWidget>("Merge");