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.

228 lines
6.8KB

  1. #include "Core.hpp"
  2. #include "midi.hpp"
  3. #include <algorithm>
  4. struct QuadMIDIToCVInterface : Module {
  5. enum ParamIds {
  6. NUM_PARAMS
  7. };
  8. enum InputIds {
  9. NUM_INPUTS
  10. };
  11. enum OutputIds {
  12. ENUMS(CV_OUTPUT, 4),
  13. ENUMS(GATE_OUTPUT, 4),
  14. ENUMS(VELOCITY_OUTPUT, 4),
  15. ENUMS(AFTERTOUCH_OUTPUT, 4),
  16. NUM_OUTPUTS
  17. };
  18. enum LightIds {
  19. NUM_LIGHTS
  20. };
  21. MidiInputQueue midiInput;
  22. enum PolyMode {
  23. ROTATE_MODE,
  24. RESET_MODE,
  25. REASSIGN_MODE,
  26. UNISON_MODE,
  27. NUM_MODES
  28. };
  29. PolyMode polyMode = ROTATE_MODE;
  30. struct NoteData {
  31. uint8_t velocity = 0;
  32. uint8_t aftertouch = 0;
  33. };
  34. NoteData noteData[128];
  35. std::vector<uint8_t> heldNotes;
  36. uint8_t notes[4];
  37. bool gates[4];
  38. bool pedal;
  39. QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), heldNotes(128) {
  40. onReset();
  41. }
  42. json_t *toJson() override {
  43. json_t *rootJ = json_object();
  44. json_object_set_new(rootJ, "midi", midiInput.toJson());
  45. json_object_set_new(rootJ, "polyMode", json_integer(polyMode));
  46. return rootJ;
  47. }
  48. void fromJson(json_t *rootJ) override {
  49. json_t *midiJ = json_object_get(rootJ, "midi");
  50. if (midiJ)
  51. midiInput.fromJson(midiJ);
  52. json_t *polyModeJ = json_object_get(rootJ, "polyMode");
  53. if (polyModeJ)
  54. polyMode = (PolyMode) json_integer_value(polyModeJ);
  55. }
  56. void onReset() override {
  57. for (int i = 0; i < 4; i++) {
  58. notes[i] = 60;
  59. gates[i] = false;
  60. }
  61. pedal = false;
  62. }
  63. void pressNote(uint8_t note) {
  64. // Remove existing similar note
  65. auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
  66. if (it != heldNotes.end())
  67. heldNotes.erase(it);
  68. // Push note
  69. heldNotes.push_back(note);
  70. // Set notes and gates
  71. switch (polyMode) {
  72. case ROTATE_MODE: {
  73. } break;
  74. case RESET_MODE: {
  75. } break;
  76. case REASSIGN_MODE: {
  77. } break;
  78. case UNISON_MODE: {
  79. } break;
  80. default: break;
  81. }
  82. }
  83. void releaseNote(uint8_t note) {
  84. // Remove the note
  85. auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
  86. if (it != heldNotes.end())
  87. heldNotes.erase(it);
  88. // Hold note if pedal is pressed
  89. // if (pedal)
  90. // return;
  91. // // Set last note
  92. // if (!heldNotes.empty()) {
  93. // auto it2 = heldNotes.end();
  94. // it2--;
  95. // lastNote = *it2;
  96. // gate = true;
  97. // }
  98. // else {
  99. // gate = false;
  100. // }
  101. }
  102. void pressPedal() {
  103. pedal = true;
  104. }
  105. void releasePedal() {
  106. pedal = false;
  107. releaseNote(255);
  108. }
  109. void step() override {
  110. MidiMessage msg;
  111. while (midiInput.shift(&msg)) {
  112. processMessage(msg);
  113. }
  114. for (int i = 0; i < 4; i++) {
  115. uint8_t lastNote = notes[i];
  116. outputs[CV_OUTPUT + i].value = (lastNote - 60) / 12.f;
  117. outputs[GATE_OUTPUT + i].value = gates[i] ? 10.f : 0.f;
  118. outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f);
  119. outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f);
  120. }
  121. }
  122. void processMessage(MidiMessage msg) {
  123. switch (msg.status()) {
  124. // note off
  125. case 0x8: {
  126. // releaseNote(msg.data1);
  127. } break;
  128. // note on
  129. case 0x9: {
  130. if (msg.data2 > 0) {
  131. uint8_t note = msg.data1 & 0x7f;
  132. noteData[note].velocity = msg.data2;
  133. // pressNote(msg.data1);
  134. }
  135. else {
  136. // For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released.
  137. // releaseNote(msg.data1);
  138. }
  139. } break;
  140. // channel aftertouch
  141. case 0xa: {
  142. uint8_t note = msg.data1 & 0x7f;
  143. noteData[note].aftertouch = msg.data2;
  144. } break;
  145. // cc
  146. case 0xb: {
  147. processCC(msg);
  148. } break;
  149. default: break;
  150. }
  151. }
  152. void processCC(MidiMessage msg) {
  153. switch (msg.data1) {
  154. // sustain
  155. case 0x40: {
  156. if (msg.data2 >= 64)
  157. pressPedal();
  158. else
  159. releasePedal();
  160. } break;
  161. default: break;
  162. }
  163. }
  164. };
  165. struct QuadMIDIToCVInterfaceWidget : ModuleWidget {
  166. QuadMIDIToCVInterfaceWidget(QuadMIDIToCVInterface *module) : ModuleWidget(module) {
  167. setPanel(SVG::load(assetGlobal("res/Core/QuadMIDIToCVInterface.svg")));
  168. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  169. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  170. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  171. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  172. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 0));
  173. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 0));
  174. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094986, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 0));
  175. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693935, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 0));
  176. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 1));
  177. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 1));
  178. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094986, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 1));
  179. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693935, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 1));
  180. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 2));
  181. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 2));
  182. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094986, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 2));
  183. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693935, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 2));
  184. addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 3));
  185. addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 3));
  186. addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094986, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 3));
  187. addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693935, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 3));
  188. MidiWidget *midiWidget = Widget::create<MidiWidget>(mm2px(Vec(3.4009969, 14.837336)));
  189. midiWidget->box.size = mm2px(Vec(44, 28));
  190. midiWidget->midiIO = &module->midiInput;
  191. addChild(midiWidget);
  192. }
  193. };
  194. Model *modelQuadMIDIToCVInterface = Model::create<QuadMIDIToCVInterface, QuadMIDIToCVInterfaceWidget>("Core", "QuadMIDIToCVInterface", "MIDI-4", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG);