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.

172 lines
5.4KB

  1. #include "Core.hpp"
  2. #include "midi.hpp"
  3. #include "dsp/filter.hpp"
  4. struct MIDICCToCVInterface : Module {
  5. enum ParamIds {
  6. NUM_PARAMS
  7. };
  8. enum InputIds {
  9. NUM_INPUTS
  10. };
  11. enum OutputIds {
  12. ENUMS(CC_OUTPUT, 16),
  13. NUM_OUTPUTS
  14. };
  15. enum LightIds {
  16. NUM_LIGHTS
  17. };
  18. MidiInputQueue midiInput;
  19. uint8_t cvs[16];
  20. ExponentialFilter ccFilters[16];
  21. int learningId = -1;
  22. uint8_t learnedCcs[16] = {};
  23. MIDICCToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  24. onReset();
  25. }
  26. void onReset() override {
  27. for (int i = 0; i < 16; i++) {
  28. cvs[i] = 0;
  29. learnedCcs[i] = i;
  30. }
  31. learningId = -1;
  32. }
  33. void step() override {
  34. MidiMessage msg;
  35. while (midiInput.shift(&msg)) {
  36. processMessage(msg);
  37. }
  38. float lambda = 100.f * engineGetSampleTime();
  39. for (int i = 0; i < 16; i++) {
  40. float value = rescale(cvs[i], 0, 127, 0.f, 10.f);
  41. ccFilters[i].lambda = lambda;
  42. outputs[CC_OUTPUT + i].value = ccFilters[i].process(value);
  43. }
  44. }
  45. void processMessage(MidiMessage msg) {
  46. switch (msg.status()) {
  47. // cc
  48. case 0xb: {
  49. uint8_t cc = msg.note();
  50. // Learn
  51. if (learningId >= 0) {
  52. learnedCcs[learningId] = cc;
  53. learningId = -1;
  54. }
  55. // Set CV
  56. for (int i = 0; i < 16; i++) {
  57. if (learnedCcs[i] == cc) {
  58. cvs[i] = msg.value();
  59. }
  60. }
  61. } break;
  62. default: break;
  63. }
  64. }
  65. json_t *toJson() override {
  66. json_t *rootJ = json_object();
  67. json_object_set_new(rootJ, "midi", midiInput.toJson());
  68. return rootJ;
  69. }
  70. void fromJson(json_t *rootJ) override {
  71. json_t *midiJ = json_object_get(rootJ, "midi");
  72. midiInput.fromJson(midiJ);
  73. }
  74. };
  75. struct MidiCcChoice : GridChoice {
  76. MIDICCToCVInterface *module;
  77. int id;
  78. MidiCcChoice() {
  79. box.size.y = mm2px(6.666);
  80. textOffset.y -= 4;
  81. }
  82. void setId(int id) override {
  83. this->id = id;
  84. }
  85. void step() override {
  86. if (module->learningId == id) {
  87. text = "LRN";
  88. color.a = 0.5;
  89. }
  90. else {
  91. text = stringf("%d", module->learnedCcs[id]);
  92. color.a = 1.0;
  93. if (gFocusedWidget == this)
  94. gFocusedWidget = NULL;
  95. }
  96. }
  97. void onFocus(EventFocus &e) override {
  98. e.consumed = true;
  99. module->learningId = id;
  100. }
  101. void onDefocus(EventDefocus &e) override {
  102. module->learningId = -1;
  103. }
  104. };
  105. struct MidiCcWidget : Grid16MidiWidget {
  106. MIDICCToCVInterface *module;
  107. GridChoice *createGridChoice() override {
  108. MidiCcChoice *gridChoice = new MidiCcChoice();
  109. gridChoice->module = module;
  110. return gridChoice;
  111. }
  112. };
  113. struct MIDICCToCVInterfaceWidget : ModuleWidget {
  114. MIDICCToCVInterfaceWidget(MIDICCToCVInterface *module) : ModuleWidget(module) {
  115. setPanel(SVG::load(assetGlobal("res/Core/MIDICCToCVInterface.svg")));
  116. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  117. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  118. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  119. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  120. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 73.344704)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 0));
  121. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 73.344704)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 1));
  122. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094982, 73.344704)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 2));
  123. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 73.344704)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 3));
  124. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.8943355, 84.945023)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 4));
  125. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.49466, 84.945023)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 5));
  126. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094982, 84.945023)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 6));
  127. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 84.945023)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 7));
  128. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.8943343, 96.543976)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 8));
  129. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 96.543976)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 9));
  130. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.09498, 96.543976)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 10));
  131. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 96.543976)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 11));
  132. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 12));
  133. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.49466, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 13));
  134. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 14));
  135. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 15));
  136. MidiCcWidget *midiWidget = Widget::create<MidiCcWidget>(mm2px(Vec(3.399621, 14.837339)));
  137. midiWidget->module = module;
  138. midiWidget->box.size = mm2px(Vec(44, 54.667));
  139. midiWidget->midiIO = &module->midiInput;
  140. midiWidget->createGridChoices();
  141. addChild(midiWidget);
  142. }
  143. };
  144. Model *modelMIDICCToCVInterface = Model::create<MIDICCToCVInterface, MIDICCToCVInterfaceWidget>("Core", "MIDICCToCVInterface", "MIDI-CC", MIDI_TAG, EXTERNAL_TAG);