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.

162 lines
6.6KB

  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;
  20. Merge() {
  21. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  22. lightDivider.setDivision(512);
  23. onReset();
  24. }
  25. void onReset() override {
  26. channels = -1;
  27. }
  28. void process(const ProcessArgs& args) override {
  29. int lastChannel = -1;
  30. for (int c = 0; c < 16; c++) {
  31. float v = 0.f;
  32. if (inputs[MONO_INPUTS + c].isConnected()) {
  33. lastChannel = c;
  34. v = inputs[MONO_INPUTS + c].getVoltage();
  35. }
  36. outputs[POLY_OUTPUT].setVoltage(v, c);
  37. }
  38. // In order to allow 0 channels, modify channels directly instead of using `setChannels()`
  39. outputs[POLY_OUTPUT].channels = (channels >= 0) ? channels : (lastChannel + 1);
  40. // Set channel lights infrequently
  41. if (lightDivider.process()) {
  42. for (int c = 0; c < 16; c++) {
  43. bool active = (c < outputs[POLY_OUTPUT].getChannels());
  44. lights[CHANNEL_LIGHTS + c].setBrightness(active);
  45. }
  46. }
  47. }
  48. json_t* dataToJson() override {
  49. json_t* rootJ = json_object();
  50. json_object_set_new(rootJ, "channels", json_integer(channels));
  51. return rootJ;
  52. }
  53. void dataFromJson(json_t* rootJ) override {
  54. json_t* channelsJ = json_object_get(rootJ, "channels");
  55. if (channelsJ)
  56. channels = json_integer_value(channelsJ);
  57. }
  58. };
  59. struct MergeChannelItem : MenuItem {
  60. Merge* module;
  61. int channels;
  62. void onAction(const event::Action& e) override {
  63. module->channels = channels;
  64. }
  65. };
  66. struct MergeChannelsItem : MenuItem {
  67. Merge* module;
  68. Menu* createChildMenu() override {
  69. Menu* menu = new Menu;
  70. for (int channels = -1; channels <= 16; channels++) {
  71. MergeChannelItem* item = new MergeChannelItem;
  72. if (channels < 0)
  73. item->text = "Automatic";
  74. else
  75. item->text = string::f("%d", channels);
  76. item->rightText = CHECKMARK(module->channels == channels);
  77. item->module = module;
  78. item->channels = channels;
  79. menu->addChild(item);
  80. }
  81. return menu;
  82. }
  83. };
  84. struct MergeWidget : ModuleWidget {
  85. MergeWidget(Merge* module) {
  86. setModule(module);
  87. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Merge.svg")));
  88. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  89. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  90. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  91. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  92. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.771, 37.02)), module, Merge::MONO_INPUTS + 0));
  93. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.771, 48.02)), module, Merge::MONO_INPUTS + 1));
  94. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.77, 59.02)), module, Merge::MONO_INPUTS + 2));
  95. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.77, 70.02)), module, Merge::MONO_INPUTS + 3));
  96. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.77, 81.02)), module, Merge::MONO_INPUTS + 4));
  97. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.77, 92.02)), module, Merge::MONO_INPUTS + 5));
  98. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.771, 103.02)), module, Merge::MONO_INPUTS + 6));
  99. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.771, 114.02)), module, Merge::MONO_INPUTS + 7));
  100. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.275, 37.02)), module, Merge::MONO_INPUTS + 8));
  101. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.275, 48.02)), module, Merge::MONO_INPUTS + 9));
  102. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.274, 59.02)), module, Merge::MONO_INPUTS + 10));
  103. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.274, 70.02)), module, Merge::MONO_INPUTS + 11));
  104. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.274, 81.02)), module, Merge::MONO_INPUTS + 12));
  105. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.274, 92.02)), module, Merge::MONO_INPUTS + 13));
  106. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.275, 103.02)), module, Merge::MONO_INPUTS + 14));
  107. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.275, 114.02)), module, Merge::MONO_INPUTS + 15));
  108. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(6.77, 21.347)), module, Merge::POLY_OUTPUT));
  109. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(15.276, 17.775)), module, Merge::CHANNEL_LIGHTS + 0));
  110. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(17.275, 17.775)), module, Merge::CHANNEL_LIGHTS + 1));
  111. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(19.275, 17.775)), module, Merge::CHANNEL_LIGHTS + 2));
  112. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(21.275, 17.775)), module, Merge::CHANNEL_LIGHTS + 3));
  113. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(15.276, 19.775)), module, Merge::CHANNEL_LIGHTS + 4));
  114. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(17.275, 19.775)), module, Merge::CHANNEL_LIGHTS + 5));
  115. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(19.275, 19.775)), module, Merge::CHANNEL_LIGHTS + 6));
  116. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(21.275, 19.775)), module, Merge::CHANNEL_LIGHTS + 7));
  117. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(15.276, 21.775)), module, Merge::CHANNEL_LIGHTS + 8));
  118. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(17.275, 21.775)), module, Merge::CHANNEL_LIGHTS + 9));
  119. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(19.275, 21.775)), module, Merge::CHANNEL_LIGHTS + 10));
  120. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(21.276, 21.775)), module, Merge::CHANNEL_LIGHTS + 11));
  121. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(15.276, 23.775)), module, Merge::CHANNEL_LIGHTS + 12));
  122. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(17.275, 23.775)), module, Merge::CHANNEL_LIGHTS + 13));
  123. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(19.275, 23.775)), module, Merge::CHANNEL_LIGHTS + 14));
  124. addChild(createLightCentered<TinyLight<BlueLight>>(mm2px(Vec(21.276, 23.775)), module, Merge::CHANNEL_LIGHTS + 15));
  125. }
  126. void appendContextMenu(Menu* menu) override {
  127. Merge* module = dynamic_cast<Merge*>(this->module);
  128. menu->addChild(new MenuEntry);
  129. MergeChannelsItem* channelsItem = new MergeChannelsItem;
  130. channelsItem->text = "Channels";
  131. channelsItem->rightText = RIGHT_ARROW;
  132. channelsItem->module = module;
  133. menu->addChild(channelsItem);
  134. }
  135. };
  136. Model* modelMerge = createModel<Merge, MergeWidget>("Merge");