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.

138 lines
4.7KB

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