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.

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