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.

579 lines
15KB

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