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.

1489 lines
41KB

  1. #include "midi.hpp"
  2. #include "dsp/filter.hpp"
  3. #include "dsp/digital.hpp"
  4. #include "moDllz.hpp"
  5. #include <algorithm> // std::find
  6. #include <vector> // std::vector
  7. namespace rack_plugin_moDllz {
  8. struct MIDI8MPE : Module {
  9. enum ParamIds {
  10. RESETMIDI_PARAM,
  11. LCURSOR_PARAM,
  12. RCURSOR_PARAM,
  13. PLUSONE_PARAM,
  14. MINUSONE_PARAM,
  15. LEARNCCA_PARAM,
  16. LEARNCCB_PARAM,
  17. LEARNCCC_PARAM,
  18. LEARNCCD_PARAM,
  19. LEARNCCE_PARAM,
  20. LEARNCCF_PARAM,
  21. SUSTHOLD_PARAM,
  22. NUM_PARAMS
  23. };
  24. enum InputIds {
  25. NUM_INPUTS
  26. };
  27. enum OutputIds {
  28. ENUMS(X_OUTPUT, 8),
  29. ENUMS(Y_OUTPUT, 8),
  30. ENUMS(Z_OUTPUT, 8),
  31. ENUMS(VEL_OUTPUT, 8),
  32. ENUMS(GATE_OUTPUT, 8),
  33. MMA_OUTPUT,
  34. MMB_OUTPUT,
  35. MMC_OUTPUT,
  36. MMD_OUTPUT,
  37. MME_OUTPUT,
  38. MMF_OUTPUT,
  39. NUM_OUTPUTS
  40. };
  41. enum LightIds {
  42. RESETMIDI_LIGHT,
  43. ENUMS(CH_LIGHT, 8),
  44. SUSTHOLD_LIGHT,
  45. NUM_LIGHTS
  46. };
  47. MidiInputQueue midiInput;
  48. enum PolyMode {
  49. MPE_MODE,
  50. ROTATE_MODE,
  51. REUSE_MODE,
  52. RESET_MODE,
  53. REASSIGN_MODE,
  54. UNISON_MODE,
  55. NUM_MODES
  56. };
  57. PolyMode polyMode = ROTATE_MODE;
  58. bool holdGates = true;
  59. struct NoteData {
  60. uint8_t velocity = 0;
  61. uint8_t aftertouch = 0;
  62. };
  63. NoteData noteData[128];
  64. // cachedNotes : UNISON_MODE and REASSIGN_MODE cache all played notes. The other polyModes cache stolen notes (after the 4th one).
  65. std::vector<uint8_t> cachedNotes;
  66. std::vector<uint8_t> cachedMPE[8];
  67. uint8_t notes[8] = {0};
  68. uint8_t vels[8] = {0};
  69. int16_t mpex[8] = {0};
  70. uint16_t mpey[8] = {0};
  71. uint16_t mpez[8] = {0};
  72. uint8_t mpeyLB[8] = {0};
  73. uint8_t mpezLB[8] = {0};
  74. uint8_t mpePlusLB[8] = {0};
  75. bool gates[8] = {false};
  76. uint8_t Maft = 0;
  77. int midiCCs[6] = {128,1,129,11,7,64};
  78. uint8_t midiCCsVal[6] = {0};
  79. uint16_t Mpit = 8192;
  80. float xpitch[8] = {0.f};
  81. // gates set to TRUE by pedal and current gate. FALSE by pedal.
  82. bool pedalgates[8] = {false};
  83. bool pedal = false;
  84. int rotateIndex = 0;
  85. int stealIndex = 0;
  86. int numVo = 8;
  87. int polyModeIx = 1;
  88. int pbMain = 12;
  89. int pbMPE = 96;
  90. int mpeYcc = 74; //cc74 (default MPE Y)
  91. int mpeZcc = 128; //128 = ChannelAfterTouch (default MPE Z)
  92. int MPEmode = 0; // Index of different MPE modes...(User and HakenPlus for now)
  93. int savedMidiCh = -1;//to reset channel from MPE all channels
  94. int MPEmasterCh = 0;// 0 ~ 15
  95. int MPEfirstCh = 1;// 0 ~ 15
  96. int displayYcc = 74;
  97. int displayZcc = 128;
  98. int learnIx = 0;
  99. int cursorIx = 0;
  100. int cursorI = 0;
  101. int selectedmidich = 0;
  102. int cursorPoly[9] = {0,1,3,7,8,9,10,11,12};
  103. int cursorMPE[12] = {0,2,3,4,5,6,7,8,9,10,11,12};
  104. int cursorMPEsub[10] = {0,2,3,4,7,8,9,10,11,12};
  105. float dummy = 0.f;
  106. float *dataKnob = &dummy;
  107. int frameData = 100000;
  108. ExponentialFilter MPExFilter[8];
  109. ExponentialFilter MPEyFilter[8];
  110. ExponentialFilter MPEzFilter[8];
  111. ExponentialFilter MCCsFilter[6];
  112. ExponentialFilter MpitFilter;
  113. // retrigger for stolen notes (when gates already open)
  114. PulseGenerator reTrigger[8];
  115. SchmittTrigger resetMidiTrigger;
  116. SchmittTrigger PlusOneTrigger;
  117. SchmittTrigger MinusOneTrigger;
  118. SchmittTrigger LcursorTrigger;
  119. SchmittTrigger RcursorTrigger;
  120. SchmittTrigger learnCCsTrigger[6];
  121. MIDI8MPE() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  122. onReset();
  123. }
  124. json_t *toJson() override {
  125. json_t *rootJ = json_object();
  126. json_object_set_new(rootJ, "midi", midiInput.toJson());
  127. json_object_set_new(rootJ, "polyMode", json_integer(polyMode));
  128. json_object_set_new(rootJ, "pbMain", json_integer(pbMain));
  129. json_object_set_new(rootJ, "pbMPE", json_integer(pbMPE));
  130. json_object_set_new(rootJ, "numVo", json_integer(numVo));
  131. json_object_set_new(rootJ, "MPEmasterCh", json_integer(MPEmasterCh));
  132. json_object_set_new(rootJ, "MPEfirstCh", json_integer(MPEfirstCh));
  133. json_object_set_new(rootJ, "midiAcc", json_integer(midiCCs[0]));
  134. json_object_set_new(rootJ, "midiBcc", json_integer(midiCCs[1]));
  135. json_object_set_new(rootJ, "midiCcc", json_integer(midiCCs[2]));
  136. json_object_set_new(rootJ, "midiDcc", json_integer(midiCCs[3]));
  137. json_object_set_new(rootJ, "midiEcc", json_integer(midiCCs[4]));
  138. json_object_set_new(rootJ, "midiFcc", json_integer(midiCCs[5]));
  139. json_object_set_new(rootJ, "mpeYcc", json_integer(mpeYcc));
  140. json_object_set_new(rootJ, "mpeZcc", json_integer(mpeZcc));
  141. json_object_set_new(rootJ, "MPEmode", json_integer(MPEmode));
  142. return rootJ;
  143. }
  144. void fromJson(json_t *rootJ) override {
  145. json_t *midiJ = json_object_get(rootJ, "midi");
  146. if (midiJ)
  147. midiInput.fromJson(midiJ);
  148. json_t *polyModeJ = json_object_get(rootJ, "polyMode");
  149. if (polyModeJ)
  150. polyMode = (PolyMode) json_integer_value(polyModeJ);
  151. polyModeIx = polyMode;
  152. json_t *pbMainJ = json_object_get(rootJ, "pbMain");
  153. if (pbMainJ)
  154. pbMain = json_integer_value(pbMainJ);
  155. json_t *pbMPEJ = json_object_get(rootJ, "pbMPE");
  156. if (pbMPEJ)
  157. pbMPE = json_integer_value(pbMPEJ);
  158. json_t *numVoJ = json_object_get(rootJ, "numVo");
  159. if (numVoJ)
  160. numVo = json_integer_value(numVoJ);
  161. json_t *MPEmasterChJ = json_object_get(rootJ, "MPEmasterCh");
  162. if (MPEmasterChJ)
  163. MPEmasterCh = json_integer_value(MPEmasterChJ);
  164. json_t *MPEfirstChJ = json_object_get(rootJ, "MPEfirstCh");
  165. if (MPEfirstChJ)
  166. MPEfirstCh = json_integer_value(MPEfirstChJ);
  167. json_t *midiAccJ = json_object_get(rootJ, "midiAcc");
  168. if (midiAccJ)
  169. midiCCs[0] = json_integer_value(midiAccJ);
  170. json_t *midiBccJ = json_object_get(rootJ, "midiBcc");
  171. if (midiBccJ)
  172. midiCCs[1] = json_integer_value(midiBccJ);
  173. json_t *midiCccJ = json_object_get(rootJ, "midiCcc");
  174. if (midiCccJ)
  175. midiCCs[2] = json_integer_value(midiCccJ);
  176. json_t *midiDccJ = json_object_get(rootJ, "midiDcc");
  177. if (midiDccJ)
  178. midiCCs[3] = json_integer_value(midiDccJ);
  179. json_t *midiEccJ = json_object_get(rootJ, "midiEcc");
  180. if (midiEccJ)
  181. midiCCs[4] = json_integer_value(midiEccJ);
  182. json_t *midiFccJ = json_object_get(rootJ, "midiFcc");
  183. if (midiFccJ)
  184. midiCCs[5] = json_integer_value(midiFccJ);
  185. json_t *mpeYccJ = json_object_get(rootJ, "mpeYcc");
  186. if (mpeYccJ)
  187. mpeYcc = json_integer_value(mpeYccJ);
  188. json_t *mpeZccJ = json_object_get(rootJ, "mpeZcc");
  189. if (mpeZccJ)
  190. mpeZcc = json_integer_value(mpeZccJ);
  191. json_t *MPEmodeJ = json_object_get(rootJ, "MPEmode");
  192. if (MPEmodeJ)
  193. MPEmode = json_integer_value(MPEmodeJ);
  194. if (polyModeIx > 0){
  195. displayYcc = 129;
  196. displayZcc = 130;
  197. }else if (MPEmode > 0){
  198. displayYcc = 131;
  199. displayZcc = 132;
  200. }else {
  201. displayYcc = mpeYcc;
  202. displayZcc = mpeZcc;
  203. }
  204. }
  205. ///////////////////////////ON RESET
  206. void onReset() override {
  207. for (int i = 0; i < 8; i++) {
  208. notes[i] = 60;
  209. gates[i] = false;
  210. pedalgates[i] = false;
  211. mpey[i] = 0.f;
  212. }
  213. rotateIndex = -1;
  214. cachedNotes.clear();
  215. float lambdaf = 100.f * engineGetSampleTime();
  216. if (polyMode == MPE_MODE) {
  217. midiInput.channel = -1;
  218. for (int i = 0; i < 8; i++) {
  219. mpex[i] = 0.f;
  220. mpez[i] = 0.f;
  221. cachedMPE[i].clear();
  222. MPExFilter[i].lambda = lambdaf;
  223. MPEyFilter[i].lambda = lambdaf;
  224. MPEzFilter[i].lambda = lambdaf;
  225. }
  226. if (MPEmode > 0){// Haken MPE Plus
  227. displayYcc = 131;
  228. displayZcc = 132;
  229. }else{
  230. displayYcc = mpeYcc;
  231. displayZcc = mpeZcc;
  232. }
  233. } else {
  234. displayYcc = 129;
  235. displayZcc = 130;
  236. }
  237. learnIx = 0;
  238. MpitFilter.lambda = lambdaf;
  239. for (int i=0; i < 6; i++){
  240. MCCsFilter[i].lambda = lambdaf;
  241. }
  242. MpitFilter.lambda = lambdaf;
  243. }
  244. ////////////////////////////////////////////////////
  245. int getPolyIndex(int nowIndex) {
  246. for (int i = 0; i < numVo; i++) {
  247. nowIndex++;
  248. if (nowIndex > (numVo - 1))
  249. nowIndex = 0;
  250. if (!(gates[nowIndex] || pedalgates[nowIndex])) {
  251. stealIndex = nowIndex;
  252. return nowIndex;
  253. }
  254. }
  255. // All taken = steal (stealIndex always rotates)
  256. stealIndex++;
  257. if (stealIndex > (numVo - 1))
  258. stealIndex = 0;
  259. ///if ((polyMode > MPE_MODE) && (polyMode < REASSIGN_MODE) && (gates[stealIndex]))
  260. /// cannot reach here if polyMode == MPE mode ...no need to check
  261. if ((polyMode < REASSIGN_MODE) && (gates[stealIndex]))
  262. cachedNotes.push_back(notes[stealIndex]);
  263. return stealIndex;
  264. }
  265. void pressNote(uint8_t channel, uint8_t note, uint8_t vel) {
  266. // Set notes and gates
  267. switch (polyMode) {
  268. case MPE_MODE: {
  269. //////if gate push note to mpe_buffer for legato/////
  270. rotateIndex = channel - MPEfirstCh;
  271. if ((rotateIndex < 0) || (rotateIndex > 7)) return;
  272. if (gates[rotateIndex]) cachedMPE[rotateIndex].push_back(notes[rotateIndex]);
  273. } break;
  274. case ROTATE_MODE: {
  275. rotateIndex = getPolyIndex(rotateIndex);
  276. } break;
  277. case REUSE_MODE: {
  278. bool reuse = false;
  279. for (int i = 0; i < numVo; i++) {
  280. if (notes[i] == note) {
  281. rotateIndex = i;
  282. reuse = true;
  283. break;
  284. }
  285. }
  286. if (!reuse)
  287. rotateIndex = getPolyIndex(rotateIndex);
  288. } break;
  289. case RESET_MODE: {
  290. rotateIndex = getPolyIndex(-1);
  291. } break;
  292. case REASSIGN_MODE: {
  293. cachedNotes.push_back(note);
  294. rotateIndex = getPolyIndex(-1);
  295. } break;
  296. case UNISON_MODE: {
  297. cachedNotes.push_back(note);
  298. for (int i = 0; i < numVo; i++) {
  299. notes[i] = note;
  300. vels[i] = vel;
  301. gates[i] = true;
  302. pedalgates[i] = pedal;
  303. reTrigger[i].trigger(1e-3);
  304. }
  305. return;
  306. } break;
  307. default: break;
  308. }
  309. // Set notes and gates
  310. if (gates[rotateIndex] || pedalgates[rotateIndex])
  311. reTrigger[rotateIndex].trigger(1e-3);
  312. notes[rotateIndex] = note;
  313. vels[rotateIndex] = vel;
  314. gates[rotateIndex] = true;
  315. pedalgates[rotateIndex] = pedal;
  316. }
  317. void releaseNote(uint8_t channel, uint8_t note, uint8_t vel) {
  318. if (polyMode > MPE_MODE) {
  319. // Remove the note
  320. auto it = std::find(cachedNotes.begin(), cachedNotes.end(), note);
  321. if (it != cachedNotes.end())
  322. cachedNotes.erase(it);
  323. }else{
  324. int i = channel - MPEfirstCh;
  325. if ((i < 0) || (i > 7)) return;
  326. auto it = std::find(cachedMPE[i].begin(), cachedMPE[i].end(), note);
  327. if (it != cachedMPE[i].end())
  328. cachedMPE[i].erase(it);
  329. }
  330. switch (polyMode) {
  331. case MPE_MODE: {
  332. int i = channel - MPEfirstCh;
  333. if (note == notes[i]) {
  334. if (pedalgates[i]) {
  335. gates[i] = false;
  336. }
  337. /// check for cachednotes on MPE buffers [8]...
  338. else if (!cachedMPE[i].empty()) {
  339. notes[i] = cachedMPE[i].back();
  340. cachedMPE[i].pop_back();
  341. }
  342. else {
  343. gates[i] = false;
  344. }
  345. if (vel < 128) // 128 = from NoteOn ZeroVel
  346. vels[i] = vel;///Rel Vel
  347. }
  348. } break;
  349. case REASSIGN_MODE: {
  350. if (vel > 128) vel = 64;
  351. for (int i = 0; i < numVo; i++) {
  352. if (i < (int) cachedNotes.size()) {
  353. if (!pedalgates[i])
  354. notes[i] = cachedNotes[i];
  355. pedalgates[i] = pedal;
  356. }
  357. else {
  358. gates[i] = false;
  359. mpey[i] = vel * 128;
  360. }
  361. }
  362. } break;
  363. case UNISON_MODE: {
  364. if (vel > 128) vel = 64;
  365. if (!cachedNotes.empty()) {
  366. uint8_t backnote = cachedNotes.back();
  367. for (int i = 0; i < numVo; i++) {
  368. notes[i] = backnote;
  369. gates[i] = true;
  370. mpey[i] = vel * 128;
  371. }
  372. }
  373. else {
  374. for (int i = 0; i < numVo; i++) {
  375. gates[i] = false;
  376. mpey[i] = vel * 128;
  377. }
  378. }
  379. } break;
  380. // default ROTATE_MODE REUSE_MODE RESET_MODE
  381. default: {
  382. for (int i = 0; i < numVo; i++) {
  383. if (notes[i] == note) {
  384. if (pedalgates[i]) {
  385. gates[i] = false;
  386. }
  387. else if (!cachedNotes.empty()) {
  388. notes[i] = cachedNotes.back();
  389. cachedNotes.pop_back();
  390. }
  391. else {
  392. gates[i] = false;
  393. }
  394. if (vel < 128) // 128 = from NoteOn ZeroVel
  395. mpey[i] = vel * 128;
  396. else//Fixed RelVel
  397. mpey[i] = 8192;
  398. }
  399. }
  400. } break;
  401. }
  402. }
  403. void pressPedal() {
  404. pedal = true;
  405. lights[SUSTHOLD_LIGHT].value = params[SUSTHOLD_PARAM].value;
  406. if (polyMode == MPE_MODE) {
  407. for (int i = 0; i < 8; i++) {
  408. pedalgates[i] = gates[i];
  409. }
  410. }else {
  411. for (int i = 0; i < numVo; i++) {
  412. pedalgates[i] = gates[i];
  413. }
  414. }
  415. }
  416. void releasePedal() {
  417. pedal = false;
  418. lights[SUSTHOLD_LIGHT].value = 0.f;
  419. // When pedal is off, recover notes for pressed keys (if any) after they were already being "cycled" out by pedal-sustained notes.
  420. if (polyMode == MPE_MODE) {
  421. for (int i = 0; i < 8; i++) {
  422. pedalgates[i] = false;
  423. if (!cachedMPE[i].empty()) {
  424. notes[i] = cachedMPE[i].back();
  425. cachedMPE[i].pop_back();
  426. gates[i] = true;
  427. }
  428. }
  429. }else{
  430. for (int i = 0; i < numVo; i++) {
  431. pedalgates[i] = false;
  432. if (!cachedNotes.empty()) {
  433. if (polyMode < REASSIGN_MODE){
  434. notes[i] = cachedNotes.back();
  435. cachedNotes.pop_back();
  436. gates[i] = true;
  437. }
  438. }
  439. }
  440. if (polyMode == REASSIGN_MODE) {
  441. for (int i = 0; i < numVo; i++) {
  442. if (i < (int) cachedNotes.size()) {
  443. notes[i] = cachedNotes[i];
  444. gates[i] = true;
  445. }
  446. else {
  447. gates[i] = false;
  448. }
  449. }
  450. }
  451. }
  452. }
  453. void onSampleRateChange() override {
  454. onReset();
  455. }
  456. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  457. ///////////////////////
  458. ////// STEP START
  459. ///////////////////////
  460. void step() override {
  461. MidiMessage msg;
  462. while (midiInput.shift(&msg)) {
  463. processMessage(msg);
  464. }
  465. float pbVo = 0.f;
  466. if (Mpit < 8192){
  467. pbVo = MpitFilter.process(rescale(Mpit, 0, 8192, -5.f, 0.f));
  468. } else {
  469. pbVo = MpitFilter.process(rescale(Mpit, 8192, 16383, 0.f, 5.f));
  470. }
  471. // outputs[MMA_OUTPUT].value = pbVo;
  472. bool sustainHold = (params[SUSTHOLD_PARAM].value > .5 );
  473. if (polyMode > PolyMode::MPE_MODE){
  474. for (int i = 0; i < numVo; i++) {
  475. float lastGate = ((gates[i] || (sustainHold && pedalgates[i])) && (!(reTrigger[i].process(engineGetSampleTime()))))? 10.f : 0.f;
  476. outputs[GATE_OUTPUT + i].value = lastGate;
  477. outputs[X_OUTPUT + i].value = ((notes[i] - 60) / 12.f) + (pbVo * static_cast<float>(pbMain) / 60.f);
  478. outputs[VEL_OUTPUT + i].value = rescale(vels[i], 0, 127, 0.f, 10.f);
  479. outputs[Y_OUTPUT + i].value = rescale(mpey[i], 0, 16383, 0.f, 10.f);
  480. outputs[Z_OUTPUT + i].value = rescale(noteData[notes[i]].aftertouch, 0, 127, 0.f, 10.f);
  481. lights[CH_LIGHT + i].value = ((i == rotateIndex)? 0.2f : 0.f) + (lastGate * .08f);
  482. }
  483. } else {/// MPE MODE!!!
  484. for (int i = 0; i < 8; i++) {
  485. float lastGate = ((gates[i] || (sustainHold && pedalgates[i])) && (!(reTrigger[i].process(engineGetSampleTime())))) ? 10.f : 0.f;
  486. outputs[GATE_OUTPUT + i].value = lastGate ;
  487. if ( mpex[i] < 0){
  488. xpitch[i] = (MPExFilter[i].process(rescale(mpex[i], -8192 , 0, -5.f, 0.f))) * pbMPE / 60.f;
  489. } else {
  490. xpitch[i] = (MPExFilter[i].process(rescale(mpex[i], 0, 8191, 0.f, 5.f))) * pbMPE / 60.f;
  491. }
  492. outputs[X_OUTPUT + i].value = xpitch[i] + ((notes[i] - 60) / 12.f) + (pbVo * static_cast<float>(pbMain) / 60.f);
  493. outputs[VEL_OUTPUT + i].value = rescale(vels[i], 0, 127, 0.f, 10.f);
  494. outputs[Y_OUTPUT + i].value = MPEyFilter[i].process(rescale(mpey[i], 0, 16383, 0.f, 10.f));
  495. outputs[Z_OUTPUT + i].value = MPEzFilter[i].process(rescale(mpez[i], 0, 16383, 0.f, 10.f));
  496. lights[CH_LIGHT + i].value = ((i == rotateIndex)? 0.2f : 0.f) + (lastGate * .08f);
  497. }
  498. }
  499. for (int i = 0; i < 6; i++){
  500. if (midiCCs[i] == 128)
  501. outputs[MMA_OUTPUT + i].value = pbVo;
  502. else if (midiCCs[i] == 129)
  503. outputs[MMA_OUTPUT + i].value = MCCsFilter[i].process(rescale(Maft, 0, 127, 0.f, 10.f));
  504. else
  505. outputs[MMA_OUTPUT + i].value = MCCsFilter[i].process(rescale(midiCCsVal[i], 0, 127, 0.f, 10.f));
  506. }
  507. //// PANEL KNOB AND BUTTONS
  508. float f_dataKnob = *dataKnob;
  509. if ( f_dataKnob > 0.07f){
  510. int knobInterval = static_cast<int>(0.05 * static_cast<float>(engineGetSampleRate()) / f_dataKnob);
  511. if (frameData ++ > knobInterval){
  512. frameData = 0;
  513. dataPlus();
  514. }
  515. }else if(f_dataKnob < -0.07f){
  516. int knobInterval = static_cast<int>(0.05 * static_cast<float>(engineGetSampleRate()) / -f_dataKnob);
  517. if (frameData ++ > knobInterval){
  518. frameData = 0;
  519. dataMinus();
  520. }
  521. }
  522. if (PlusOneTrigger.process(params[PLUSONE_PARAM].value)) {
  523. dataPlus();
  524. return;
  525. }
  526. if (MinusOneTrigger.process(params[MINUSONE_PARAM].value)) {
  527. dataMinus();
  528. return;
  529. }
  530. if (LcursorTrigger.process(params[LCURSOR_PARAM].value)) {
  531. if (polyMode == MPE_MODE){
  532. if (MPEmode > 0){
  533. if (cursorI > 0) cursorI --;
  534. else cursorI = 9;
  535. cursorIx = cursorMPEsub[cursorI];
  536. }else{
  537. if (cursorI > 0) cursorI --;
  538. else cursorI = 11;
  539. cursorIx = cursorMPE[cursorI];
  540. }
  541. }else{
  542. if (cursorI > 0) cursorI --;
  543. else cursorI = 8;
  544. cursorIx = cursorPoly[cursorI];
  545. }
  546. learnIx = 0;
  547. return;
  548. }
  549. if (RcursorTrigger.process(params[RCURSOR_PARAM].value)) {
  550. if (polyMode == MPE_MODE){
  551. if (MPEmode > 0){
  552. if (cursorI < 9) cursorI ++;
  553. else cursorI = 0;
  554. cursorIx = cursorMPEsub[cursorI];
  555. }else{
  556. if (cursorI < 11) cursorI ++;
  557. else cursorI = 0;
  558. cursorIx = cursorMPE[cursorI];
  559. }
  560. }else{
  561. if (cursorI < 8) cursorI ++;
  562. else cursorI = 0;
  563. cursorIx = cursorPoly[cursorI];
  564. }
  565. learnIx = 0;
  566. return;
  567. }
  568. for (int i = 0; i < 6; i++){
  569. if (learnCCsTrigger[i].process(params[LEARNCCA_PARAM + i].value)) {
  570. if (learnIx == i + 1)
  571. learnIx = 0;
  572. else{
  573. learnIx = i + 1;
  574. //cursorIx = i + 7;
  575. }
  576. return;
  577. }
  578. }
  579. ///// RESET MIDI
  580. if (resetMidiTrigger.process(params[RESETMIDI_PARAM].value)) {
  581. lights[RESETMIDI_LIGHT].value= 1.0f;
  582. onReset();
  583. return;
  584. }
  585. if (lights[RESETMIDI_LIGHT].value > 0.0001f){
  586. lights[RESETMIDI_LIGHT].value -= 0.0001f ; // fade out light
  587. }
  588. }
  589. ///////////////////////
  590. ////// STEP END
  591. ///////////////////////
  592. void dataPlus(){
  593. switch (cursorIx){
  594. case 0: {
  595. if (polyMode == MPE_MODE){
  596. if (MPEmode < 1){
  597. MPEmode ++;
  598. onReset();
  599. }else{//last MPE submode... go to Poly
  600. polyMode = (PolyMode) (1);
  601. onReset();
  602. midiInput.channel = savedMidiCh;//restore channel
  603. }
  604. }else if (polyMode < UNISON_MODE) {
  605. polyMode = (PolyMode) (polyMode + 1);
  606. onReset();
  607. }else {
  608. polyMode = MPE_MODE;
  609. MPEmode = 0; // no MPE submode...
  610. savedMidiCh = midiInput.channel;// save Poly MIDI channel
  611. onReset();
  612. }
  613. polyModeIx = polyMode;
  614. }break;
  615. case 1: {
  616. if (numVo < 8) numVo ++;
  617. //else numVo = 2;
  618. onReset();
  619. }break;
  620. case 2: {
  621. if (MPEfirstCh < 8){
  622. MPEfirstCh ++;
  623. MPEmasterCh = MPEfirstCh - 1;
  624. }else{
  625. MPEfirstCh = 0;
  626. MPEmasterCh = 15;
  627. }
  628. onReset();
  629. }break;
  630. case 3: {
  631. if (pbMain < 96) pbMain ++;
  632. }break;
  633. case 4: {
  634. if (pbMPE < 96) pbMPE ++;
  635. }break;
  636. case 5: {
  637. if (mpeYcc <128)
  638. mpeYcc ++;
  639. else
  640. mpeYcc = 0;
  641. displayYcc = mpeYcc;
  642. }break;
  643. case 6: {
  644. if (mpeZcc <128)
  645. mpeZcc ++;
  646. else
  647. mpeZcc = 0;
  648. displayZcc = mpeZcc;
  649. }break;
  650. default: {
  651. if (midiCCs[cursorIx - 7] < 129)
  652. midiCCs[cursorIx - 7] ++;
  653. else
  654. midiCCs[cursorIx - 7] = 0;
  655. }break;
  656. }
  657. learnIx = 0;;
  658. return;
  659. }
  660. void dataMinus(){
  661. switch (cursorIx){
  662. case 0: {
  663. if (polyMode > MPE_MODE) {
  664. polyMode = (PolyMode) (polyMode - 1);
  665. MPEmode = 1;
  666. savedMidiCh = midiInput.channel;
  667. onReset();
  668. }else if (MPEmode > 0){
  669. MPEmode --;
  670. onReset();
  671. }else {//last MPE submode... go to Poly
  672. polyMode = UNISON_MODE;
  673. onReset();
  674. midiInput.channel = savedMidiCh;//restore channel
  675. }
  676. polyModeIx = polyMode;
  677. }break;
  678. case 1: {
  679. if (numVo > 2) numVo --;
  680. //else numVo = 8;
  681. onReset();
  682. }break;
  683. case 2:{
  684. if (MPEfirstCh > 1){
  685. MPEfirstCh -- ;
  686. MPEmasterCh = MPEfirstCh - 1;
  687. }else if (MPEfirstCh == 1){
  688. MPEfirstCh = 0;
  689. MPEmasterCh = 15;
  690. }else {
  691. MPEfirstCh = 8;
  692. MPEmasterCh = 7;
  693. }
  694. onReset();
  695. }break;
  696. case 3: {
  697. if (pbMain > 0) pbMain --;
  698. }break;
  699. case 4: {
  700. if (pbMPE > 0) pbMPE --;
  701. }break;
  702. case 5: {
  703. if (mpeYcc > 0)
  704. mpeYcc --;
  705. else
  706. mpeYcc = 128;
  707. displayYcc = mpeYcc;
  708. }break;
  709. case 6: {
  710. if (mpeZcc > 0)
  711. mpeZcc --;
  712. else
  713. mpeZcc = 128;
  714. displayZcc = mpeZcc;
  715. }break;
  716. default: {
  717. if (midiCCs[cursorIx - 7] > 0)
  718. midiCCs[cursorIx - 7] --;
  719. else
  720. midiCCs[cursorIx - 7] = 129;
  721. }break;
  722. }
  723. learnIx = 0;
  724. return;
  725. }
  726. void processMessage(MidiMessage msg) {
  727. switch (msg.status()) {
  728. // note off
  729. case 0x8: {
  730. if ((polyMode == MPE_MODE) && (msg.channel() == MPEmasterCh)) return;
  731. releaseNote(msg.channel(), msg.note(), msg.value());
  732. } break;
  733. // note on
  734. case 0x9: {
  735. if ((polyMode == MPE_MODE) && (msg.channel() == MPEmasterCh)) return;
  736. if (msg.value() > 0) {
  737. //noteData[msg.note()].velocity = msg.value();
  738. pressNote(msg.channel(), msg.note(), msg.value());
  739. }
  740. else {
  741. releaseNote(msg.channel(), msg.note(), 128);//128 to bypass Release vel on Vel Outputs
  742. }
  743. } break;
  744. // note (poly) aftertouch
  745. case 0xa: {
  746. if (polyMode == MPE_MODE) return;
  747. noteData[msg.note()].aftertouch = msg.value();
  748. } break;
  749. // channel aftertouch
  750. case 0xd: {
  751. if (learnIx > 0) {// learn enabled ???
  752. midiCCs[learnIx - 1] = 129;
  753. learnIx = 0;
  754. return;
  755. }////////////////////////////////////////
  756. else if (polyMode == MPE_MODE){
  757. if (msg.channel() == MPEmasterCh){
  758. Maft = msg.data1;
  759. }else if (MPEmode == 1){
  760. mpez[msg.channel() - MPEfirstCh] = msg.data1 * 128 + mpePlusLB[msg.channel() - MPEfirstCh];
  761. mpePlusLB[msg.channel() - MPEfirstCh] = 0;
  762. }else {
  763. if (mpeZcc == 128)
  764. mpez[msg.channel() - MPEfirstCh] = msg.data1 * 128;
  765. if (mpeYcc == 128)
  766. mpey[msg.channel() - MPEfirstCh] = msg.data1 * 128;
  767. }
  768. }else{
  769. Maft = msg.data1;
  770. }
  771. } break;
  772. // pitch Bend
  773. case 0xe:{
  774. if (learnIx > 0) {// learn enabled ???
  775. midiCCs[learnIx - 1] = 128;
  776. learnIx = 0;
  777. return;
  778. }////////////////////////////////////////
  779. else if (polyMode == MPE_MODE){
  780. if (msg.channel() == MPEmasterCh){
  781. Mpit = msg.data2 * 128 + msg.data1;
  782. }else{
  783. mpex[msg.channel() - MPEfirstCh] = msg.data2 * 128 + msg.data1 - 8192;
  784. }
  785. }else{
  786. Mpit = msg.data2 * 128 + msg.data1; //14bit Pitch Bend
  787. }
  788. } break;
  789. // cc
  790. case 0xb: {
  791. ///////// LEARN CC ???
  792. if (learnIx > 0) {
  793. midiCCs[learnIx - 1] = msg.note();
  794. learnIx = 0;
  795. return;
  796. }else if (polyMode == MPE_MODE){
  797. if (msg.channel() == MPEmasterCh){
  798. processCC(msg);
  799. }else if (MPEmode == 1){ //Continuum
  800. if (msg.note() == 87){
  801. mpePlusLB[msg.channel() - MPEfirstCh] = msg.data2;
  802. }else if (msg.note() == 74){
  803. mpey[msg.channel() - MPEfirstCh] = msg.data2 * 128 + mpePlusLB[msg.channel() - MPEfirstCh];
  804. mpePlusLB[msg.channel() - MPEfirstCh] = 0;
  805. }
  806. }else if (msg.note() == mpeYcc){
  807. //cc74 0x4a default
  808. mpey[msg.channel() - MPEfirstCh] = msg.data2 * 128;
  809. }else if (msg.note() == mpeZcc){
  810. mpez[msg.channel() - MPEfirstCh] = msg.data2 * 128;
  811. }
  812. }else{
  813. processCC(msg);
  814. }
  815. } break;
  816. default: break;
  817. }
  818. }
  819. void processCC(MidiMessage msg) {
  820. if (msg.note() == 0x40) { //internal sust pedal
  821. if (msg.value() >= 64)
  822. pressPedal();
  823. else
  824. releasePedal();
  825. }
  826. for (int i = 0; i < 6; i++){
  827. if (midiCCs[i] == msg.note()){
  828. midiCCsVal[i] = msg.value();
  829. return;
  830. }
  831. }
  832. }
  833. void MidiPanic() {
  834. onReset();
  835. pedal = false;
  836. lights[SUSTHOLD_LIGHT].value = 0.f;
  837. for (int i = 0; i < 8; i++){
  838. notes[i] = 0;
  839. vels[i] = 0;
  840. mpex[i] = 0;
  841. mpey[i] = 0;
  842. mpez[i] = 0;
  843. gates[i] = false;
  844. xpitch[i] = {0.f};
  845. }
  846. for (int i = 0; i < NUM_OUTPUTS; i++) {
  847. outputs[i].value = 0.f;
  848. }
  849. }
  850. };
  851. // Main Display
  852. struct PolyModeDisplay : TransparentWidget {
  853. PolyModeDisplay(){
  854. font = Font::load(mFONT_FILE);
  855. }
  856. int pointerinit = 0;
  857. float mdfontSize = 12.f;
  858. std::string sMode ="";
  859. std::string sVo ="";
  860. std::string sPBM ="";
  861. std::string sPBMPE ="";
  862. std::string sMPEmidiCh = "";
  863. std::string yyDisplay = "";
  864. std::string zzDisplay = "";
  865. std::shared_ptr<Font> font;
  866. std::string polyModeStr[6] = {
  867. "M. P. E.",
  868. "C Y C L E",
  869. "R E U S E",
  870. "R E S E T",
  871. "R E A S S I G N",
  872. "U N I S O N",
  873. };
  874. int drawFrame = 0;
  875. int *p_polyMode = &pointerinit;
  876. int polyModeI = -1;
  877. int *p_numVo = &pointerinit;
  878. int numVoI = -1;
  879. int *p_pbMain = &pointerinit;
  880. int pbMainI = -1;
  881. int *p_pbMPE = &pointerinit;
  882. int pbMPEI = -1;
  883. int *p_MPEmasterCh = &pointerinit;
  884. int MPEmasterChI = -1;
  885. int *p_MPEfirstCh = &pointerinit;
  886. int MPEfirstChI = -1;
  887. int *p_MPEmode = &pointerinit;
  888. int MPEmodeI;
  889. int *p_YccNumber = &pointerinit;
  890. int YccNumber = -1;
  891. int *p_ZccNumber = &pointerinit;
  892. int ZccNumber = -1;
  893. int *p_cursorIx = &pointerinit;
  894. int cursorIxI = 0;
  895. int flashFocus = 0;
  896. void draw(NVGcontext* vg) {
  897. if (drawFrame ++ > 5){
  898. drawFrame = 0;
  899. if (MPEmodeI != *p_MPEmode){
  900. MPEmodeI = *p_MPEmode;
  901. //if (MPEmodeI > 1) sMode = "M. P. E. w RelVel";///
  902. if (MPEmodeI == 1) sMode = "M. P. E. Plus";/// Continuum Hi Res YZ
  903. else sMode = polyModeStr[polyModeI];
  904. }
  905. if (polyModeI != *p_polyMode) {
  906. polyModeI = *p_polyMode;
  907. if (polyModeI < 1) {
  908. if (MPEmodeI == 1) sMode = "M. P. E. Plus";/// Continuum Hi Res YZ
  909. else sMode = polyModeStr[polyModeI];
  910. }else{
  911. sMode = polyModeStr[polyModeI];
  912. }
  913. }
  914. if (numVoI != *p_numVo){
  915. numVoI = *p_numVo;
  916. sVo = "Poly "+ std::to_string(numVoI) +" Vo outs";
  917. }
  918. if (pbMainI != *p_pbMain){
  919. pbMainI = *p_pbMain;
  920. sPBM = "PBend:" + std::to_string(pbMainI);
  921. }
  922. if (pbMPEI != *p_pbMPE){
  923. pbMPEI = *p_pbMPE;
  924. sPBMPE = " CH PBend:" + std::to_string(pbMPEI);
  925. }
  926. if ((MPEmasterChI != *p_MPEmasterCh) || (MPEfirstChI != *p_MPEfirstCh)){
  927. MPEmasterChI = *p_MPEmasterCh;
  928. MPEfirstChI = *p_MPEfirstCh;
  929. sMPEmidiCh = "channels M:" + std::to_string(MPEmasterChI + 1) + " Vo:" + std::to_string(MPEfirstChI + 1) + "++";
  930. }
  931. if (YccNumber != *p_YccNumber){
  932. YccNumber = *p_YccNumber;
  933. switch (YccNumber) {
  934. case 129 :{//(locked) Rel Vel
  935. yyDisplay = "rVel";
  936. }break;
  937. case 131 :{//HiRes MPE Y
  938. yyDisplay = "cc74+";
  939. }break;
  940. default :{
  941. yyDisplay = "cc" + std::to_string(YccNumber);
  942. }
  943. }
  944. }
  945. if (ZccNumber != *p_ZccNumber){
  946. ZccNumber = *p_ZccNumber;
  947. switch (ZccNumber) {
  948. case 128 :{
  949. zzDisplay = "chnAT";
  950. }break;
  951. case 130 :{//(locked) note AfterT
  952. zzDisplay = "nteAT";
  953. }break;
  954. case 132 :{//HiRes MPE Z
  955. zzDisplay = "chAT+";
  956. }break;
  957. default :{
  958. zzDisplay = "cc" + std::to_string(ZccNumber);
  959. }
  960. }
  961. }
  962. if (cursorIxI != *p_cursorIx){
  963. cursorIxI = *p_cursorIx;
  964. flashFocus = 64;
  965. }
  966. }
  967. nvgFontSize(vg, mdfontSize);
  968. nvgFontFaceId(vg, font->handle);
  969. nvgFillColor(vg, nvgRGB(0xcc, 0xcc, 0xcc));//Text
  970. //nvgGlobalCompositeOperation(vg, NVG_SOURCE_OUT);
  971. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  972. nvgTextBox(vg, 4.f, 11.0f,124.f, sMode.c_str(), NULL);
  973. nvgTextBox(vg, 50.f, 52.f, 31.f, yyDisplay.c_str(), NULL);// YY
  974. nvgTextBox(vg, 82.f, 52.f, 31.f, zzDisplay.c_str(), NULL);// ZZ
  975. if (polyModeI < 1){
  976. nvgTextBox(vg, 4.f, 24.f,124.f, sMPEmidiCh.c_str(), NULL);// MPE Channels
  977. nvgTextAlign(vg, NVG_ALIGN_LEFT);
  978. nvgTextBox(vg, 58.f, 37.f,66.f, sPBMPE.c_str(), NULL);//MPE PitchBend
  979. } else {
  980. nvgTextBox(vg, 4.f, 24.f,124.f, sVo.c_str(), NULL);
  981. }
  982. nvgTextAlign(vg, NVG_ALIGN_LEFT);
  983. nvgTextBox(vg, 4.f, 37.0f, 50.f, sPBM.c_str(), NULL);
  984. nvgGlobalCompositeBlendFunc(vg, NVG_ONE , NVG_ONE);
  985. nvgBeginPath(vg);
  986. switch (cursorIxI){
  987. case 0:{ // PolyMode
  988. nvgRoundedRect(vg, 1.f, 1.f, 130.f, 12.f, 3.f);
  989. }break;
  990. case 1:{ //numVoices Poly
  991. nvgRoundedRect(vg, 1.f, 14.f, 130.f, 12.f, 3.f);
  992. }break;
  993. case 2:{ //MPE channels
  994. nvgRoundedRect(vg, 1.f, 14.f, 130.f, 12.f, 3.f);
  995. }break;
  996. case 3:{//mainPB
  997. nvgRoundedRect(vg, 1.f, 27.f, 52.f, 12.f, 3.f);
  998. }break;
  999. case 4:{//mpePB
  1000. nvgRoundedRect(vg, 54.f, 27.f, 77.f, 12.f, 3.f);
  1001. }break;
  1002. case 5:{//YY
  1003. nvgRoundedRect(vg, 50.f, 42.f, 31, 13.f, 3.f);
  1004. }break;
  1005. case 6:{//ZZ
  1006. nvgRoundedRect(vg, 82.f, 42.f, 31, 13.f, 3.f);
  1007. }break;
  1008. }
  1009. if (flashFocus > 0)
  1010. flashFocus -= 2;
  1011. int rgbint = 0x55 + flashFocus;
  1012. nvgFillColor(vg, nvgRGB(rgbint,rgbint,rgbint)); //SELECTED
  1013. nvgFill(vg);
  1014. }
  1015. };
  1016. struct MidiccDisplay : TransparentWidget {
  1017. MidiccDisplay(){
  1018. font = Font::load(mFONT_FILE);
  1019. }
  1020. float mdfontSize = 12.f;
  1021. std::string sDisplay = "";
  1022. int pointerinit = 0;
  1023. int *p_cursor = &pointerinit;
  1024. int cursorI = -1;
  1025. int displayID = 0;//set on each instance
  1026. int *p_ccNumber = &pointerinit;
  1027. int ccNumber = -1;
  1028. bool learnOn = false;
  1029. bool learnChanged = false;
  1030. int *p_learnIx = &pointerinit;
  1031. int flashFocus = 0;
  1032. int displayFrames = 0;
  1033. std::shared_ptr<Font> font;
  1034. void draw(NVGcontext* vg) {
  1035. if(displayFrames ++ > 5){
  1036. displayFrames = 0;
  1037. learnOn = (displayID - 6 == *p_learnIx);
  1038. if (learnOn){
  1039. learnChanged = true;
  1040. sDisplay = "LRN";
  1041. }else if ((ccNumber != *p_ccNumber) || (learnChanged)){
  1042. learnChanged = false;
  1043. ccNumber = *p_ccNumber;
  1044. switch (ccNumber) {
  1045. case 128 :{
  1046. sDisplay = "PBnd";
  1047. }break;
  1048. case 129 :{
  1049. sDisplay = "chAT";
  1050. }break;
  1051. case 1 :{
  1052. sDisplay = "Mod";
  1053. }break;
  1054. case 2 :{
  1055. sDisplay = "BrC";
  1056. }break;
  1057. case 7 :{
  1058. sDisplay = "Vol";
  1059. }break;
  1060. case 10 :{
  1061. sDisplay = "Pan";
  1062. }break;
  1063. case 11 :{
  1064. sDisplay = "Expr";
  1065. }break;
  1066. case 64 :{
  1067. sDisplay = "Sust";
  1068. }break;
  1069. default :{
  1070. sDisplay = "c" + std::to_string(ccNumber);
  1071. }
  1072. }
  1073. }
  1074. }
  1075. if (learnOn) {
  1076. nvgBeginPath(vg);
  1077. nvgRoundedRect(vg, 0.f, 0.f, box.size.x, box.size.y,3.f);
  1078. nvgStrokeColor(vg, nvgRGB(0xdd, 0x0, 0x0));
  1079. nvgStroke(vg);
  1080. nvgRoundedRect(vg, 0.f, 0.f, box.size.x, box.size.y,3.f);
  1081. nvgFillColor(vg, nvgRGBA(0xcc, 0x0, 0x0,0x64));
  1082. nvgFill(vg);
  1083. ///text color
  1084. nvgFillColor(vg, nvgRGB(0xff, 0x00, 0x00));//LEARN
  1085. }else{
  1086. ///text color
  1087. nvgFillColor(vg, nvgRGB(0xcc, 0xcc, 0xcc));
  1088. }
  1089. nvgFontSize(vg, mdfontSize);
  1090. nvgFontFaceId(vg, font->handle);
  1091. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  1092. nvgTextBox(vg, 0.f, 10.f,box.size.x, sDisplay.c_str(), NULL);
  1093. if (cursorI != *p_cursor){
  1094. cursorI = *p_cursor;
  1095. if (*p_cursor == displayID)
  1096. flashFocus = 64;
  1097. }
  1098. if ((displayID == cursorI) && (!learnOn)){
  1099. nvgGlobalCompositeBlendFunc(vg, NVG_ONE , NVG_ONE);
  1100. nvgBeginPath(vg);
  1101. nvgRoundedRect(vg, 0.f, 0.f, box.size.x, box.size.y,3.f);
  1102. // nvgStrokeColor(vg, nvgRGB(0x66, 0x66, 0x66));
  1103. // nvgStroke(vg);
  1104. if (flashFocus > 0)
  1105. flashFocus -= 2;
  1106. int rgbint = 0x55 + flashFocus;
  1107. nvgFillColor(vg, nvgRGB(rgbint,rgbint,rgbint)); //SELECTED
  1108. nvgFill(vg);
  1109. }
  1110. }
  1111. };
  1112. struct BlockChannel : OpaqueWidget {
  1113. int *p_polyMode;
  1114. void draw(NVGcontext* vg) {
  1115. if ( *p_polyMode > 0) {
  1116. box.size = Vec(0.f,0.f);
  1117. }else{
  1118. box.size = Vec(94.f,13.f);
  1119. NVGcolor ledColor = nvgRGBA(0x00, 0x00, 0x00,0xaa);
  1120. nvgBeginPath(vg);
  1121. nvgRoundedRect(vg, 0.f, 0.f, 94.f, 13.f,3.f);
  1122. nvgFillColor(vg, ledColor);
  1123. nvgFill(vg);
  1124. }
  1125. }
  1126. };
  1127. ///MIDIlearnMCC
  1128. struct learnMccButton : SVGSwitch, MomentarySwitch {
  1129. learnMccButton() {
  1130. box.size = Vec(26, 13);
  1131. addFrame(SVG::load(assetPlugin(plugin, "res/learnMcc_0.svg")));
  1132. addFrame(SVG::load(assetPlugin(plugin, "res/learnMcc_1.svg")));
  1133. }
  1134. };
  1135. struct springDataKnob : SVGKnob {
  1136. int *p_frameData;
  1137. springDataKnob() {
  1138. minAngle = -0.75*M_PI;
  1139. maxAngle = 0.75*M_PI;
  1140. setSVG(SVG::load(assetPlugin(plugin, "res/dataKnob.svg")));
  1141. shadow->opacity = 0.f;
  1142. }
  1143. void onMouseUp(EventMouseUp &e){
  1144. this->value = 0.f;
  1145. *p_frameData = 100000; //reset frame Counter to start (over sampleRate counter)
  1146. }
  1147. };
  1148. struct TranspOffRedLight : TranspOffLight {
  1149. TranspOffRedLight() {
  1150. addBaseColor(nvgRGBA(0xff, 0x00, 0x00, 0x88));//borderColor = nvgRGBA(0, 0, 0, 0x60);
  1151. }
  1152. };
  1153. struct MIDI8MPEWidget : ModuleWidget {
  1154. MIDI8MPEWidget(MIDI8MPE *module) : ModuleWidget(module) {
  1155. setPanel(SVG::load(assetPlugin(plugin,"res/MIDI8MPE.svg")));
  1156. //Screws
  1157. addChild(Widget::create<ScrewBlack>(Vec(0, 0)));
  1158. addChild(Widget::create<ScrewBlack>(Vec(180, 0)));
  1159. addChild(Widget::create<ScrewBlack>(Vec(0, 365)));
  1160. addChild(Widget::create<ScrewBlack>(Vec(180, 365)));
  1161. float xPos = 8.f;//61;
  1162. float yPos = 18.f;
  1163. {
  1164. MidiWidget *midiWidget = Widget::create<MidiWidget>(Vec(xPos,yPos));
  1165. midiWidget->box.size = Vec(132.f,41.f);
  1166. midiWidget->midiIO = &module->midiInput;
  1167. midiWidget->driverChoice->box.size.y = 12.f;
  1168. midiWidget->deviceChoice->box.size.y = 12.f;
  1169. midiWidget->channelChoice->box.size.y = 12.f;
  1170. midiWidget->driverChoice->box.pos = Vec(0.f, 2.f);
  1171. midiWidget->deviceChoice->box.pos = Vec(0.f, 15.f);
  1172. midiWidget->channelChoice->box.pos = Vec(0.f, 28.f);
  1173. midiWidget->driverSeparator->box.pos = Vec(0.f, 15.f);
  1174. midiWidget->deviceSeparator->box.pos = Vec(0.f, 28.f);
  1175. midiWidget->driverChoice->font = Font::load(mFONT_FILE);
  1176. midiWidget->deviceChoice->font = Font::load(mFONT_FILE);
  1177. midiWidget->channelChoice->font = Font::load(mFONT_FILE);
  1178. midiWidget->driverChoice->textOffset = Vec(2.f,10.f);
  1179. midiWidget->deviceChoice->textOffset = Vec(2.f,10.f);
  1180. midiWidget->channelChoice->textOffset = Vec(2.f,10.f);
  1181. midiWidget->driverChoice->color = nvgRGB(0xcc, 0xcc, 0xcc);
  1182. midiWidget->deviceChoice->color = nvgRGB(0xcc, 0xcc, 0xcc);
  1183. midiWidget->channelChoice->color = nvgRGB(0xcc, 0xcc, 0xcc);
  1184. addChild(midiWidget);
  1185. }
  1186. BlockChannel *blockChannel = Widget::create<BlockChannel>(Vec(8.f,46.f));
  1187. blockChannel->p_polyMode = &(module->polyModeIx);
  1188. addChild(blockChannel);
  1189. xPos = 102.f;
  1190. yPos = 47.f;
  1191. addParam(ParamWidget::create<moDllzMidiPanic>(Vec(xPos, yPos), module, MIDI8MPE::RESETMIDI_PARAM, 0.0f, 1.0f, 0.0f));
  1192. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+3.f, yPos+3.f), module, MIDI8MPE::RESETMIDI_LIGHT));
  1193. xPos = 8.f;
  1194. yPos = 62.f;
  1195. {
  1196. PolyModeDisplay *polyModeDisplay = new PolyModeDisplay();
  1197. polyModeDisplay->box.pos = Vec(xPos, yPos);
  1198. polyModeDisplay->box.size = {132.f, 54.f};
  1199. polyModeDisplay->p_polyMode = &(module->polyModeIx);
  1200. polyModeDisplay->p_MPEmode = &(module->MPEmode);
  1201. polyModeDisplay->p_numVo = &(module->numVo);
  1202. polyModeDisplay->p_pbMain = &(module->pbMain);
  1203. polyModeDisplay->p_pbMPE = &(module->pbMPE);
  1204. polyModeDisplay->p_MPEmasterCh = &(module->MPEmasterCh);
  1205. polyModeDisplay->p_MPEfirstCh = &(module->MPEfirstCh);
  1206. polyModeDisplay->p_YccNumber = &(module->displayYcc);
  1207. polyModeDisplay->p_ZccNumber = &(module->displayZcc);
  1208. polyModeDisplay->p_cursorIx = &(module->cursorIx);
  1209. addChild(polyModeDisplay);
  1210. }
  1211. yPos = 20.f;
  1212. xPos = 145.f;
  1213. addParam(ParamWidget::create<minusButton>(Vec(xPos, yPos), module, MIDI8MPE::MINUSONE_PARAM, 0.0f, 1.0f, 0.0f));
  1214. xPos = 169.f;
  1215. addParam(ParamWidget::create<plusButton>(Vec(xPos, yPos), module, MIDI8MPE::PLUSONE_PARAM, 0.0f, 1.0f, 0.0f));
  1216. xPos = 147.f;
  1217. yPos = 40.f;
  1218. ////DATA KNOB
  1219. { springDataKnob *sDataKnob = new springDataKnob();
  1220. sDataKnob->box.pos = Vec(xPos, yPos);
  1221. sDataKnob->box.size = {36.f, 36.f};
  1222. sDataKnob->minValue = -1.f;
  1223. sDataKnob->maxValue = 1.f;
  1224. sDataKnob->defaultValue = 0.f;
  1225. sDataKnob->p_frameData = &(module->frameData);
  1226. module->dataKnob = &(sDataKnob->value);
  1227. addChild(sDataKnob);
  1228. }
  1229. yPos = 85.f;
  1230. xPos = 145.5f;
  1231. addParam(ParamWidget::create<moDllzcursorL>(Vec(xPos, yPos), module, MIDI8MPE::LCURSOR_PARAM, 0.0f, 1.0f, 0.0f));
  1232. xPos = 165.5f;
  1233. addParam(ParamWidget::create<moDllzcursorR>(Vec(xPos, yPos), module, MIDI8MPE::RCURSOR_PARAM, 0.0f, 1.0f, 0.0f));
  1234. // yPos = 104.f;
  1235. // xPos = 59.f;
  1236. // {
  1237. // MidiccDisplay *mpeYDisplay = new MidiccDisplay();
  1238. // mpeYDisplay->box.pos = Vec(xPos, yPos);
  1239. // mpeYDisplay->box.size = {29.5f, 13.f};
  1240. // mpeYDisplay->displayID = 5;
  1241. // mpeYDisplay->p_cursor = &(module->cursorIx);
  1242. // mpeYDisplay->p_ccNumber = &(module->displayYcc);
  1243. // mpeYDisplay->p_learnOn = &(module->learnYcc);
  1244. // addChild(mpeYDisplay);
  1245. // }
  1246. //
  1247. // addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCY_PARAM, 0.0, 1.0, 0.0));
  1248. // xPos = 89.5f;
  1249. // {
  1250. // MidiccDisplay *mpeZDisplay = new MidiccDisplay();
  1251. // mpeZDisplay->box.pos = Vec(xPos, yPos);
  1252. // mpeZDisplay->box.size = {29.5f, 13.f};
  1253. // mpeZDisplay->displayID = 6;
  1254. // mpeZDisplay->p_cursor = &(module->cursorIx);
  1255. // mpeZDisplay->p_ccNumber = &(module->displayZcc);
  1256. // mpeZDisplay->p_learnOn = &(module->learnZcc);
  1257. // addChild(mpeZDisplay);
  1258. // }
  1259. // addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCZ_PARAM, 0.0, 1.0, 0.0));
  1260. yPos = 118.f;
  1261. float const xOffset = 32.f;
  1262. for (int i = 0; i < 8; i++){
  1263. xPos = 30.f;
  1264. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos-7.f, yPos+10.f), module, MIDI8MPE::CH_LIGHT + i));
  1265. addOutput(Port::create<moDllzPortDark>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::X_OUTPUT + i));
  1266. xPos += xOffset;
  1267. addOutput(Port::create<moDllzPortDark>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::Y_OUTPUT + i));
  1268. xPos += xOffset;
  1269. addOutput(Port::create<moDllzPortDark>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::Z_OUTPUT + i));
  1270. xPos += xOffset;
  1271. addOutput(Port::create<moDllzPortDark>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::VEL_OUTPUT + i));
  1272. xPos += xOffset;
  1273. addOutput(Port::create<moDllzPortDark>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::GATE_OUTPUT + i));
  1274. yPos += 25.f;
  1275. }
  1276. yPos = 336.f;
  1277. xPos = 10.5f;
  1278. for ( int i = 0; i < 6; i++){
  1279. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDI8MPE::MMA_OUTPUT + i));
  1280. xPos += 27.f;
  1281. }
  1282. yPos = 322.f;
  1283. xPos = 9.f;
  1284. {
  1285. MidiccDisplay *MccADisplay = new MidiccDisplay();
  1286. MccADisplay->box.pos = Vec(xPos, yPos);
  1287. MccADisplay->box.size = {26.f, 13.f};
  1288. MccADisplay->displayID = 7;
  1289. MccADisplay->p_cursor = &(module->cursorIx);
  1290. MccADisplay->p_ccNumber = &(module->midiCCs[0]);
  1291. MccADisplay->p_learnIx = &(module->learnIx);
  1292. addChild(MccADisplay);
  1293. }
  1294. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCA_PARAM, 0.0, 1.0, 0.0));
  1295. xPos += 27.f;
  1296. {
  1297. MidiccDisplay *MccBDisplay = new MidiccDisplay();
  1298. MccBDisplay->box.pos = Vec(xPos, yPos);
  1299. MccBDisplay->box.size = {26.f, 13.f};
  1300. MccBDisplay->displayID = 8;
  1301. MccBDisplay->p_cursor = &(module->cursorIx);
  1302. MccBDisplay->p_ccNumber = &(module->midiCCs[1]);
  1303. MccBDisplay->p_learnIx = &(module->learnIx);
  1304. addChild(MccBDisplay);
  1305. }
  1306. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCB_PARAM, 0.0, 1.0, 0.0));
  1307. xPos += 27.f;
  1308. {
  1309. MidiccDisplay *MccCDisplay = new MidiccDisplay();
  1310. MccCDisplay->box.pos = Vec(xPos, yPos);
  1311. MccCDisplay->box.size = {26.f, 13.f};
  1312. MccCDisplay->displayID = 9;
  1313. MccCDisplay->p_cursor = &(module->cursorIx);
  1314. MccCDisplay->p_ccNumber = &(module->midiCCs[2]);
  1315. MccCDisplay->p_learnIx = &(module->learnIx);
  1316. addChild(MccCDisplay);
  1317. }
  1318. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCC_PARAM, 0.0, 1.0, 0.0));
  1319. xPos += 27.f;
  1320. {
  1321. MidiccDisplay *MccDDisplay = new MidiccDisplay();
  1322. MccDDisplay->box.pos = Vec(xPos, yPos);
  1323. MccDDisplay->box.size = {26.f, 13.f};
  1324. MccDDisplay->displayID = 10;
  1325. MccDDisplay->p_cursor = &(module->cursorIx);
  1326. MccDDisplay->p_ccNumber = &(module->midiCCs[3]);
  1327. MccDDisplay->p_learnIx = &(module->learnIx);
  1328. addChild(MccDDisplay);
  1329. }
  1330. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCD_PARAM, 0.0, 1.0, 0.0));
  1331. xPos += 27.f;
  1332. {
  1333. MidiccDisplay *MccEDisplay = new MidiccDisplay();
  1334. MccEDisplay->box.pos = Vec(xPos, yPos);
  1335. MccEDisplay->box.size = {26.f, 13.f};
  1336. MccEDisplay->displayID = 11;
  1337. MccEDisplay->p_cursor = &(module->cursorIx);
  1338. MccEDisplay->p_ccNumber = &(module->midiCCs[4]);
  1339. MccEDisplay->p_learnIx = &(module->learnIx);
  1340. addChild(MccEDisplay);
  1341. }
  1342. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCE_PARAM, 0.0, 1.0, 0.0));
  1343. xPos += 27.f;
  1344. {
  1345. MidiccDisplay *MccFDisplay = new MidiccDisplay();
  1346. MccFDisplay->box.pos = Vec(xPos, yPos);
  1347. MccFDisplay->box.size = {26.f, 13.f};
  1348. MccFDisplay->displayID = 12;
  1349. MccFDisplay->p_cursor = &(module->cursorIx);
  1350. MccFDisplay->p_ccNumber = &(module->midiCCs[5]);
  1351. MccFDisplay->p_learnIx = &(module->learnIx);
  1352. addChild(MccFDisplay);
  1353. }
  1354. addParam(ParamWidget::create<learnMccButton>(Vec(xPos, yPos), module, MIDI8MPE::LEARNCCF_PARAM, 0.0, 1.0, 0.0));
  1355. ///Sustain hold notes
  1356. xPos = 173.f;
  1357. yPos = 338.f;
  1358. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos, yPos), module, MIDI8MPE::SUSTHOLD_PARAM, 0.0, 1.0, 1.0));
  1359. addChild(ModuleLightWidget::create<TranspOffRedLight>(Vec(xPos, yPos), module, MIDI8MPE::SUSTHOLD_LIGHT));
  1360. // {
  1361. // testDisplay *mDisplay = new testDisplay();
  1362. // mDisplay->box.pos = Vec(0.0f, 360.0f);
  1363. // mDisplay->box.size = {165.0f, 20.0f};
  1364. // mDisplay->valP = module->dataKnob;
  1365. // addChild(mDisplay);
  1366. // }
  1367. }
  1368. };
  1369. } // namespace rack_plugin_moDllz
  1370. using namespace rack_plugin_moDllz;
  1371. RACK_PLUGIN_MODEL_INIT(moDllz, MIDI8MPE) {
  1372. Model *modelMIDI8MPE = Model::create<MIDI8MPE, MIDI8MPEWidget>("moDllz", "MIDI8MPE", "MIDI 8cv MPE", MIDI_TAG, EXTERNAL_TAG, MULTIPLE_TAG);
  1373. return modelMIDI8MPE;
  1374. }