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.

598 lines
16KB

  1. #include "plugin.hpp"
  2. #include <algorithm>
  3. namespace rack {
  4. namespace core {
  5. struct MIDI_CV : Module {
  6. enum ParamIds {
  7. NUM_PARAMS
  8. };
  9. enum InputIds {
  10. NUM_INPUTS
  11. };
  12. enum OutputIds {
  13. CV_OUTPUT,
  14. GATE_OUTPUT,
  15. VELOCITY_OUTPUT,
  16. AFTERTOUCH_OUTPUT,
  17. PITCH_OUTPUT,
  18. MOD_OUTPUT,
  19. RETRIGGER_OUTPUT,
  20. CLOCK_OUTPUT,
  21. CLOCK_DIV_OUTPUT,
  22. START_OUTPUT,
  23. STOP_OUTPUT,
  24. CONTINUE_OUTPUT,
  25. NUM_OUTPUTS
  26. };
  27. enum LightIds {
  28. NUM_LIGHTS
  29. };
  30. midi::InputQueue midiInput;
  31. int channels;
  32. enum PolyMode {
  33. ROTATE_MODE,
  34. REUSE_MODE,
  35. RESET_MODE,
  36. MPE_MODE,
  37. NUM_POLY_MODES
  38. };
  39. PolyMode polyMode;
  40. uint32_t clock = 0;
  41. int clockDivision;
  42. bool pedal;
  43. // Indexed by channel
  44. uint8_t notes[16];
  45. bool gates[16];
  46. uint8_t velocities[16];
  47. uint8_t aftertouches[16];
  48. std::vector<uint8_t> heldNotes;
  49. int rotateIndex;
  50. // 16 channels for MPE. When MPE is disabled, only the first channel is used.
  51. uint16_t pitches[16];
  52. uint8_t mods[16];
  53. dsp::ExponentialFilter pitchFilters[16];
  54. dsp::ExponentialFilter modFilters[16];
  55. dsp::PulseGenerator clockPulse;
  56. dsp::PulseGenerator clockDividerPulse;
  57. dsp::PulseGenerator retriggerPulses[16];
  58. dsp::PulseGenerator startPulse;
  59. dsp::PulseGenerator stopPulse;
  60. dsp::PulseGenerator continuePulse;
  61. MIDI_CV() {
  62. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  63. heldNotes.reserve(128);
  64. for (int c = 0; c < 16; c++) {
  65. pitchFilters[c].setTau(1 / 30.f);
  66. modFilters[c].setTau(1 / 30.f);
  67. }
  68. onReset();
  69. }
  70. void onReset() override {
  71. channels = 1;
  72. polyMode = ROTATE_MODE;
  73. clockDivision = 24;
  74. panic();
  75. midiInput.reset();
  76. }
  77. /** Resets performance state */
  78. void panic() {
  79. pedal = false;
  80. for (int c = 0; c < 16; c++) {
  81. notes[c] = 60;
  82. gates[c] = false;
  83. velocities[c] = 0;
  84. aftertouches[c] = 0;
  85. pitches[c] = 8192;
  86. mods[c] = 0;
  87. pitchFilters[c].reset();
  88. modFilters[c].reset();
  89. }
  90. pedal = false;
  91. rotateIndex = -1;
  92. heldNotes.clear();
  93. }
  94. void process(const ProcessArgs& args) override {
  95. midi::Message msg;
  96. while (midiInput.shift(&msg)) {
  97. processMessage(msg);
  98. }
  99. outputs[CV_OUTPUT].setChannels(channels);
  100. outputs[GATE_OUTPUT].setChannels(channels);
  101. outputs[VELOCITY_OUTPUT].setChannels(channels);
  102. outputs[AFTERTOUCH_OUTPUT].setChannels(channels);
  103. outputs[RETRIGGER_OUTPUT].setChannels(channels);
  104. for (int c = 0; c < channels; c++) {
  105. outputs[CV_OUTPUT].setVoltage((notes[c] - 60.f) / 12.f, c);
  106. outputs[GATE_OUTPUT].setVoltage(gates[c] ? 10.f : 0.f, c);
  107. outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[c], 0, 127, 0.f, 10.f), c);
  108. outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[c], 0, 127, 0.f, 10.f), c);
  109. outputs[RETRIGGER_OUTPUT].setVoltage(retriggerPulses[c].process(args.sampleTime) ? 10.f : 0.f, c);
  110. }
  111. if (polyMode == MPE_MODE) {
  112. for (int c = 0; c < channels; c++) {
  113. outputs[PITCH_OUTPUT].setChannels(channels);
  114. outputs[MOD_OUTPUT].setChannels(channels);
  115. outputs[PITCH_OUTPUT].setVoltage(pitchFilters[c].process(args.sampleTime, rescale(pitches[c], 0, 1 << 14, -5.f, 5.f)), c);
  116. outputs[MOD_OUTPUT].setVoltage(modFilters[c].process(args.sampleTime, rescale(mods[c], 0, 127, 0.f, 10.f)), c);
  117. }
  118. }
  119. else {
  120. outputs[PITCH_OUTPUT].setChannels(1);
  121. outputs[MOD_OUTPUT].setChannels(1);
  122. outputs[PITCH_OUTPUT].setVoltage(pitchFilters[0].process(args.sampleTime, rescale(pitches[0], 0, 1 << 14, -5.f, 5.f)));
  123. outputs[MOD_OUTPUT].setVoltage(modFilters[0].process(args.sampleTime, rescale(mods[0], 0, 127, 0.f, 10.f)));
  124. }
  125. outputs[CLOCK_OUTPUT].setVoltage(clockPulse.process(args.sampleTime) ? 10.f : 0.f);
  126. outputs[CLOCK_DIV_OUTPUT].setVoltage(clockDividerPulse.process(args.sampleTime) ? 10.f : 0.f);
  127. outputs[START_OUTPUT].setVoltage(startPulse.process(args.sampleTime) ? 10.f : 0.f);
  128. outputs[STOP_OUTPUT].setVoltage(stopPulse.process(args.sampleTime) ? 10.f : 0.f);
  129. outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(args.sampleTime) ? 10.f : 0.f);
  130. }
  131. void processMessage(midi::Message msg) {
  132. // DEBUG("MIDI: %01x %01x %02x %02x", msg.getStatus(), msg.getChannel(), msg.getNote(), msg.getValue());
  133. switch (msg.getStatus()) {
  134. // note off
  135. case 0x8: {
  136. releaseNote(msg.getNote());
  137. } break;
  138. // note on
  139. case 0x9: {
  140. if (msg.getValue() > 0) {
  141. int c = msg.getChannel();
  142. pressNote(msg.getNote(), &c);
  143. velocities[c] = msg.getValue();
  144. }
  145. else {
  146. // For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released.
  147. releaseNote(msg.getNote());
  148. }
  149. } break;
  150. // key pressure
  151. case 0xa: {
  152. // Set the aftertouches with the same note
  153. // TODO Should we handle the MPE case differently?
  154. for (int c = 0; c < 16; c++) {
  155. if (notes[c] == msg.getNote())
  156. aftertouches[c] = msg.getValue();
  157. }
  158. } break;
  159. // cc
  160. case 0xb: {
  161. processCC(msg);
  162. } break;
  163. // channel pressure
  164. case 0xd: {
  165. if (polyMode == MPE_MODE) {
  166. // Set the channel aftertouch
  167. aftertouches[msg.getChannel()] = msg.getNote();
  168. }
  169. else {
  170. // Set all aftertouches
  171. for (int c = 0; c < 16; c++) {
  172. aftertouches[c] = msg.getNote();
  173. }
  174. }
  175. } break;
  176. // pitch wheel
  177. case 0xe: {
  178. int c = (polyMode == MPE_MODE) ? msg.getChannel() : 0;
  179. pitches[c] = ((uint16_t) msg.getValue() << 7) | msg.getNote();
  180. } break;
  181. case 0xf: {
  182. processSystem(msg);
  183. } break;
  184. default: break;
  185. }
  186. }
  187. void processCC(midi::Message msg) {
  188. switch (msg.getNote()) {
  189. // mod
  190. case 0x01: {
  191. int c = (polyMode == MPE_MODE) ? msg.getChannel() : 0;
  192. mods[c] = msg.getValue();
  193. } break;
  194. // sustain
  195. case 0x40: {
  196. if (msg.getValue() >= 64)
  197. pressPedal();
  198. else
  199. releasePedal();
  200. } break;
  201. default: break;
  202. }
  203. }
  204. void processSystem(midi::Message msg) {
  205. switch (msg.getChannel()) {
  206. // Timing
  207. case 0x8: {
  208. clockPulse.trigger(1e-3);
  209. if (clock % clockDivision == 0) {
  210. clockDividerPulse.trigger(1e-3);
  211. }
  212. clock++;
  213. } break;
  214. // Start
  215. case 0xa: {
  216. startPulse.trigger(1e-3);
  217. clock = 0;
  218. } break;
  219. // Continue
  220. case 0xb: {
  221. continuePulse.trigger(1e-3);
  222. } break;
  223. // Stop
  224. case 0xc: {
  225. stopPulse.trigger(1e-3);
  226. clock = 0;
  227. } break;
  228. default: break;
  229. }
  230. }
  231. int assignChannel(uint8_t note) {
  232. if (channels == 1)
  233. return 0;
  234. switch (polyMode) {
  235. case REUSE_MODE: {
  236. // Find channel with the same note
  237. for (int c = 0; c < channels; c++) {
  238. if (notes[c] == note)
  239. return c;
  240. }
  241. } // fallthrough
  242. case ROTATE_MODE: {
  243. // Find next available channel
  244. for (int i = 0; i < channels; i++) {
  245. rotateIndex++;
  246. if (rotateIndex >= channels)
  247. rotateIndex = 0;
  248. if (!gates[rotateIndex])
  249. return rotateIndex;
  250. }
  251. // No notes are available. Advance rotateIndex once more.
  252. rotateIndex++;
  253. if (rotateIndex >= channels)
  254. rotateIndex = 0;
  255. return rotateIndex;
  256. } break;
  257. case RESET_MODE: {
  258. for (int c = 0; c < channels; c++) {
  259. if (!gates[c])
  260. return c;
  261. }
  262. return channels - 1;
  263. } break;
  264. case MPE_MODE: {
  265. // This case is handled by querying the MIDI message channel.
  266. return 0;
  267. } break;
  268. default: return 0;
  269. }
  270. }
  271. void pressNote(uint8_t note, int* channel) {
  272. // Remove existing similar note
  273. auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
  274. if (it != heldNotes.end())
  275. heldNotes.erase(it);
  276. // Push note
  277. heldNotes.push_back(note);
  278. // Determine actual channel
  279. if (polyMode == MPE_MODE) {
  280. // Channel is already decided for us
  281. }
  282. else {
  283. *channel = assignChannel(note);
  284. }
  285. // Set note
  286. notes[*channel] = note;
  287. gates[*channel] = true;
  288. retriggerPulses[*channel].trigger(1e-3);
  289. }
  290. void releaseNote(uint8_t note) {
  291. // Remove the note
  292. auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
  293. if (it != heldNotes.end())
  294. heldNotes.erase(it);
  295. // Hold note if pedal is pressed
  296. if (pedal)
  297. return;
  298. // Turn off gate of all channels with note
  299. for (int c = 0; c < channels; c++) {
  300. if (notes[c] == note) {
  301. gates[c] = false;
  302. }
  303. }
  304. // Set last note if monophonic
  305. if (channels == 1) {
  306. if (note == notes[0] && !heldNotes.empty()) {
  307. uint8_t lastNote = heldNotes.back();
  308. notes[0] = lastNote;
  309. gates[0] = true;
  310. return;
  311. }
  312. }
  313. }
  314. void pressPedal() {
  315. if (pedal)
  316. return;
  317. pedal = true;
  318. }
  319. void releasePedal() {
  320. if (!pedal)
  321. return;
  322. pedal = false;
  323. // Set last note if monophonic
  324. if (channels == 1) {
  325. if (!heldNotes.empty()) {
  326. uint8_t lastNote = heldNotes.back();
  327. notes[0] = lastNote;
  328. }
  329. }
  330. // Clear notes that are not held if polyphonic
  331. else {
  332. for (int c = 0; c < channels; c++) {
  333. if (!gates[c])
  334. continue;
  335. gates[c] = false;
  336. for (uint8_t note : heldNotes) {
  337. if (notes[c] == note) {
  338. gates[c] = true;
  339. break;
  340. }
  341. }
  342. }
  343. }
  344. }
  345. void setChannels(int channels) {
  346. if (channels == this->channels)
  347. return;
  348. this->channels = channels;
  349. panic();
  350. }
  351. void setPolyMode(PolyMode polyMode) {
  352. if (polyMode == this->polyMode)
  353. return;
  354. this->polyMode = polyMode;
  355. panic();
  356. }
  357. json_t* dataToJson() override {
  358. json_t* rootJ = json_object();
  359. json_object_set_new(rootJ, "channels", json_integer(channels));
  360. json_object_set_new(rootJ, "polyMode", json_integer(polyMode));
  361. json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision));
  362. // Saving/restoring pitch and mod doesn't make much sense for MPE.
  363. if (polyMode != MPE_MODE) {
  364. json_object_set_new(rootJ, "lastPitch", json_integer(pitches[0]));
  365. json_object_set_new(rootJ, "lastMod", json_integer(mods[0]));
  366. }
  367. json_object_set_new(rootJ, "midi", midiInput.toJson());
  368. return rootJ;
  369. }
  370. void dataFromJson(json_t* rootJ) override {
  371. json_t* channelsJ = json_object_get(rootJ, "channels");
  372. if (channelsJ)
  373. setChannels(json_integer_value(channelsJ));
  374. json_t* polyModeJ = json_object_get(rootJ, "polyMode");
  375. if (polyModeJ)
  376. polyMode = (PolyMode) json_integer_value(polyModeJ);
  377. json_t* clockDivisionJ = json_object_get(rootJ, "clockDivision");
  378. if (clockDivisionJ)
  379. clockDivision = json_integer_value(clockDivisionJ);
  380. json_t* lastPitchJ = json_object_get(rootJ, "lastPitch");
  381. if (lastPitchJ)
  382. pitches[0] = json_integer_value(lastPitchJ);
  383. json_t* lastModJ = json_object_get(rootJ, "lastMod");
  384. if (lastModJ)
  385. mods[0] = json_integer_value(lastModJ);
  386. json_t* midiJ = json_object_get(rootJ, "midi");
  387. if (midiJ)
  388. midiInput.fromJson(midiJ);
  389. }
  390. };
  391. struct ClockDivisionValueItem : MenuItem {
  392. MIDI_CV* module;
  393. int clockDivision;
  394. void onAction(const event::Action& e) override {
  395. module->clockDivision = clockDivision;
  396. }
  397. };
  398. struct ClockDivisionItem : MenuItem {
  399. MIDI_CV* module;
  400. Menu* createChildMenu() override {
  401. Menu* menu = new Menu;
  402. std::vector<int> divisions = {24 * 4, 24 * 2, 24, 24 / 2, 24 / 4, 24 / 8, 2, 1};
  403. std::vector<std::string> divisionNames = {"Whole", "Half", "Quarter", "8th", "16th", "32nd", "12 PPQN", "24 PPQN"};
  404. for (size_t i = 0; i < divisions.size(); i++) {
  405. ClockDivisionValueItem* item = new ClockDivisionValueItem;
  406. item->text = divisionNames[i];
  407. item->rightText = CHECKMARK(module->clockDivision == divisions[i]);
  408. item->module = module;
  409. item->clockDivision = divisions[i];
  410. menu->addChild(item);
  411. }
  412. return menu;
  413. }
  414. };
  415. struct ChannelValueItem : MenuItem {
  416. MIDI_CV* module;
  417. int channels;
  418. void onAction(const event::Action& e) override {
  419. module->setChannels(channels);
  420. }
  421. };
  422. struct ChannelItem : MenuItem {
  423. MIDI_CV* module;
  424. Menu* createChildMenu() override {
  425. Menu* menu = new Menu;
  426. for (int channels = 1; channels <= 16; channels++) {
  427. ChannelValueItem* item = new ChannelValueItem;
  428. if (channels == 1)
  429. item->text = "Monophonic";
  430. else
  431. item->text = string::f("%d", channels);
  432. item->rightText = CHECKMARK(module->channels == channels);
  433. item->module = module;
  434. item->channels = channels;
  435. menu->addChild(item);
  436. }
  437. return menu;
  438. }
  439. };
  440. struct PolyModeValueItem : MenuItem {
  441. MIDI_CV* module;
  442. MIDI_CV::PolyMode polyMode;
  443. void onAction(const event::Action& e) override {
  444. module->setPolyMode(polyMode);
  445. }
  446. };
  447. struct PolyModeItem : MenuItem {
  448. MIDI_CV* module;
  449. Menu* createChildMenu() override {
  450. Menu* menu = new Menu;
  451. std::vector<std::string> polyModeNames = {
  452. "Rotate",
  453. "Reuse",
  454. "Reset",
  455. "MPE",
  456. };
  457. for (int i = 0; i < MIDI_CV::NUM_POLY_MODES; i++) {
  458. MIDI_CV::PolyMode polyMode = (MIDI_CV::PolyMode) i;
  459. PolyModeValueItem* item = new PolyModeValueItem;
  460. item->text = polyModeNames[i];
  461. item->rightText = CHECKMARK(module->polyMode == polyMode);
  462. item->module = module;
  463. item->polyMode = polyMode;
  464. menu->addChild(item);
  465. }
  466. return menu;
  467. }
  468. };
  469. struct MIDI_CVPanicItem : MenuItem {
  470. MIDI_CV* module;
  471. void onAction(const event::Action& e) override {
  472. module->panic();
  473. }
  474. };
  475. struct MIDI_CVWidget : ModuleWidget {
  476. MIDI_CVWidget(MIDI_CV* module) {
  477. setModule(module);
  478. setPanel(APP->window->loadSvg(asset::system("res/Core/MIDI-CV.svg")));
  479. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  480. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  481. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  482. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  483. addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 60.1445)), module, MIDI_CV::CV_OUTPUT));
  484. addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 60.1445)), module, MIDI_CV::GATE_OUTPUT));
  485. addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 60.1445)), module, MIDI_CV::VELOCITY_OUTPUT));
  486. addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 76.1449)), module, MIDI_CV::AFTERTOUCH_OUTPUT));
  487. addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 76.1449)), module, MIDI_CV::PITCH_OUTPUT));
  488. addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 76.1449)), module, MIDI_CV::MOD_OUTPUT));
  489. addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 92.1439)), module, MIDI_CV::CLOCK_OUTPUT));
  490. addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 92.1439)), module, MIDI_CV::CLOCK_DIV_OUTPUT));
  491. addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 92.1439)), module, MIDI_CV::RETRIGGER_OUTPUT));
  492. addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 108.144)), module, MIDI_CV::START_OUTPUT));
  493. addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 108.144)), module, MIDI_CV::STOP_OUTPUT));
  494. addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 108.144)), module, MIDI_CV::CONTINUE_OUTPUT));
  495. MidiWidget* midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.41891, 14.8373)));
  496. midiWidget->box.size = mm2px(Vec(33.840, 28));
  497. midiWidget->setMidiPort(module ? &module->midiInput : NULL);
  498. addChild(midiWidget);
  499. }
  500. void appendContextMenu(Menu* menu) override {
  501. MIDI_CV* module = dynamic_cast<MIDI_CV*>(this->module);
  502. menu->addChild(new MenuEntry);
  503. ClockDivisionItem* clockDivisionItem = new ClockDivisionItem;
  504. clockDivisionItem->text = "CLK/N divider";
  505. clockDivisionItem->rightText = RIGHT_ARROW;
  506. clockDivisionItem->module = module;
  507. menu->addChild(clockDivisionItem);
  508. ChannelItem* channelItem = new ChannelItem;
  509. channelItem->text = "Polyphony channels";
  510. channelItem->rightText = string::f("%d", module->channels) + " " + RIGHT_ARROW;
  511. channelItem->module = module;
  512. menu->addChild(channelItem);
  513. PolyModeItem* polyModeItem = new PolyModeItem;
  514. polyModeItem->text = "Polyphony mode";
  515. polyModeItem->rightText = RIGHT_ARROW;
  516. polyModeItem->module = module;
  517. menu->addChild(polyModeItem);
  518. MIDI_CVPanicItem* panicItem = new MIDI_CVPanicItem;
  519. panicItem->text = "Panic";
  520. panicItem->module = module;
  521. menu->addChild(panicItem);
  522. }
  523. };
  524. // Use legacy slug for compatibility
  525. Model* modelMIDI_CV = createModel<MIDI_CV, MIDI_CVWidget>("MIDIToCVInterface");
  526. } // namespace core
  527. } // namespace rack