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.

2273 lines
72KB

  1. #include "midi.hpp"
  2. #include "dsp/filter.hpp"
  3. #include "dsp/digital.hpp"
  4. #include "moDllz.hpp"
  5. #include <list>
  6. namespace rack_plugin_moDllz {
  7. /*
  8. * MIDIPolyInterface converts midi note on/off events, velocity , pitch wheel and mod wheel to CV
  9. * with 16 Midi Note Buttons with individual vel & gate
  10. */
  11. struct MidiNoteData {
  12. uint8_t velocity = 0;
  13. uint8_t aftertouch = 0;
  14. };
  15. struct MIDIPolyInterface : Module {
  16. static const int numPads = 16;
  17. enum ParamIds {
  18. ENUMS(KEYBUTTON_PARAM, 16),
  19. ENUMS(SEQSEND_PARAM, 16),
  20. LEARNPAD_PARAM,
  21. LOCKPAD_PARAM,
  22. SEQPAD_PARAM,
  23. PADXLOCK_PARAM,
  24. DRIFT_PARAM,
  25. POLYMODE_PARAM,
  26. MONOPITCH_PARAM,
  27. ARCADEON_PARAM,
  28. ARPEGON_PARAM,
  29. ARPEGRATIO_PARAM,
  30. ARPEGOCT_PARAM,
  31. ARPEGOCTALT_PARAM,
  32. MONORETRIG_PARAM,
  33. HOLD_PARAM,
  34. SEQSPEED_PARAM,
  35. SEQCLOCKRATIO_PARAM,
  36. SEQFIRST_PARAM,
  37. SEQSTEPS_PARAM,
  38. SEQRUN_PARAM,
  39. SEQGATERUN_PARAM,
  40. SEQRETRIG_PARAM,
  41. SEQRESET_PARAM,
  42. SEQRUNRESET_PARAM,
  43. SEQRUNGATE_PARAM,
  44. SEQCLOCKSRC_PARAM,
  45. SEQARPSWING_PARAM,
  46. SWINGTRI_PARAM,
  47. SEQOCT_PARAM,
  48. SEQOCTALT_PARAM,
  49. SEQSWING_PARAM,
  50. ARPSWING_PARAM,
  51. SEQTRANUP_PARAM,
  52. SEQTRANDWN_PARAM,
  53. POLYTRANUP_PARAM,
  54. POLYTRANDWN_PARAM,
  55. POLYUNISON_PARAM,
  56. LOCKEDPITCH_PARAM,
  57. LOCKEDRETRIG_PARAM,
  58. PLAYXLOCKED_PARAM,
  59. DISPLAYNOTENUM_PARAM,
  60. RESETMIDI_PARAM,
  61. TRIMPOLYSHIFT_PARAM,
  62. TRIMSEQSHIFT_PARAM,
  63. MUTESEQ_PARAM,
  64. MUTEMONO_PARAM,
  65. MUTELOCKED_PARAM,
  66. MUTEPOLYA_PARAM,
  67. MUTEPOLYB_PARAM,
  68. NUM_PARAMS
  69. };
  70. enum InputIds {
  71. POLYUNISON_INPUT,
  72. POLYSHIFT_INPUT,
  73. CLOCK_INPUT,
  74. SEQSPEED_INPUT,
  75. SEQRATIO_INPUT,
  76. SEQSTEPS_INPUT,
  77. SEQFIRST_INPUT,
  78. SEQRUN_INPUT,
  79. SEQRESET_INPUT,
  80. SEQSWING_INPUT,
  81. SEQSHIFT_INPUT,
  82. ARPEGRATIO_INPUT,
  83. ARPMODE_INPUT,
  84. NUM_INPUTS
  85. };
  86. enum OutputIds {
  87. ENUMS(PITCH_OUTPUT,16),
  88. ENUMS(VEL_OUTPUT,16),
  89. ENUMS(GATE_OUTPUT,16),
  90. SEQPITCH_OUTPUT,
  91. SEQVEL_OUTPUT,
  92. SEQGATE_OUTPUT,
  93. LOCKEDPITCH_OUTPUT,
  94. LOCKEDVEL_OUTPUT,
  95. LOCKEDGATE_OUTPUT,
  96. MONOPITCH_OUTPUT,
  97. MONOVEL_OUTPUT,
  98. MONOGATE_OUTPUT,
  99. PBEND_OUTPUT,
  100. MOD_OUTPUT,
  101. PRESSURE_OUTPUT,
  102. SUSTAIN_OUTPUT,
  103. SEQSTART_OUTPUT,
  104. SEQSTOP_OUTPUT,
  105. SEQSTARTSTOP_OUTPUT,
  106. SEQCLOCK_OUTPUT,
  107. NUM_OUTPUTS
  108. };
  109. enum LightIds {
  110. ENUMS(SEQ_LIGHT,16),
  111. RESETMIDI_LIGHT,
  112. PLOCK_LIGHT,
  113. PLEARN_LIGHT,
  114. PXLOCK_LIGHT,
  115. PSEQ_LIGHT,
  116. SEQRUNNING_LIGHT,
  117. SEQRESET_LIGHT,
  118. ENUMS(SEQOCT_LIGHT,5),
  119. ENUMS(ARPOCT_LIGHT,5),
  120. ARCADEON_LIGHT,
  121. ARPEGON_LIGHT,
  122. MUTESEQ_LIGHT,
  123. MUTEMONO_LIGHT,
  124. MUTELOCKED_LIGHT,
  125. MUTEPOLY_LIGHT,
  126. MIDIBEAT_LIGHT,
  127. NUM_LIGHTS
  128. };
  129. MidiInputQueue midiInput;
  130. uint8_t mod = 0;
  131. ExponentialFilter modFilter;
  132. uint16_t pitch = 8192;
  133. ExponentialFilter pitchFilter;
  134. uint8_t sustain = 0;
  135. ExponentialFilter sustainFilter;
  136. uint8_t pressure = 0;
  137. ExponentialFilter pressureFilter;
  138. MidiNoteData noteData[128];
  139. enum buttonmodes{
  140. POLY_MODE,
  141. SEQ_MODE,
  142. LOCKED_MODE,
  143. XLOCK_MODE
  144. };
  145. struct noteButton{
  146. int key = 0;
  147. int vel = 0;
  148. float drift = 0.0f;
  149. bool gate = false;
  150. bool button = false;
  151. bool newkey = true;
  152. int mode = 0;
  153. bool learn = false;
  154. int velseq = 127; //lastvel for seq
  155. int stamp = 0;
  156. bool gateseq = false;
  157. bool polyretrig = false;
  158. };
  159. noteButton noteButtons[numPads];
  160. std::list<int> noteBuffer; //buffered notes over polyphony
  161. int polyIndex = 0;
  162. int polyTopIndex = numPads-1;
  163. int polymode = 0;
  164. int lastpolyIndex = 0;
  165. int polyMaxVoices = 8;
  166. int stampIx = 0;
  167. int playingVoices = 0;
  168. int polyTransParam = 0;
  169. float arpPhase = 0.0f;
  170. int arpegStatus = 0; //for Display : Mode / OutMono active
  171. int arpegMode = 0;
  172. bool arpegStep = false;
  173. bool arpSwingDwn = true;
  174. int arpclockRatio = 0;
  175. int arpegIx = 0;
  176. int arpegFrame = 0;
  177. int arpOctIx = 0;
  178. bool arpegStarted = false;
  179. int arpegCycle = 0;
  180. int arpOctValue = 0;
  181. bool syncArpPhase = false;
  182. int arpDisplayIx = -1;
  183. const int octaveShift[7][5] =
  184. { {0,-1,-2,-1, 8},
  185. {0,-1,-2, 8, 8},
  186. {0,-1, 8, 8, 8},
  187. {0, 8, 8, 8, 8},
  188. {0, 1, 8, 8, 8},
  189. {0, 1, 2, 8, 8},
  190. {0, 1, 2, 1, 8}
  191. };
  192. int liveMono = 0;
  193. int lockedMono = 0;
  194. int lastMono = -1;
  195. int lastLocked = -1;
  196. bool pedal = false;
  197. bool sustainhold = true;
  198. float drift[numPads] = {0.0f};
  199. bool padSetLearn = false;
  200. int padSetMode = 0;
  201. float seqPhase = 0.0f;
  202. bool seqSwingDwn = true;
  203. bool seqrunning = false;
  204. bool seqResetNext = false;
  205. int seqSteps = 16;
  206. int seqOffset = 0;
  207. int seqStep = 0;
  208. int seqi = 0;
  209. int seqiWoct = 0;
  210. int seqOctIx = 0;
  211. int seqOctValue = 3;
  212. int seqTransParam = 0;
  213. int seqSampleCount = 0;
  214. int arpSampleCount = 0;
  215. int ClockSeqSamples = 1;
  216. int ClockArpSamples = 1;
  217. const float ClockRatios[13] ={0.50f, 2.f/3.f,0.75f, 1.0f ,4.f/3.f,1.5f, 2.0f, 8.f/3.f, 3.0f, 4.0f, 6.0f, 8.0f,12.0f};
  218. const bool swingTriplet[13] = {true,true,false,true,true,false,true,true,false,true,false,true,false};
  219. int clockSource = 0;
  220. int seqclockRatio = 1;
  221. std::string mainDisplay[4] = {""};
  222. bool dispNotenumber = false;
  223. SchmittTrigger resetMidiTrigger;
  224. SchmittTrigger extClockTrigger;
  225. SchmittTrigger seqRunTrigger;
  226. SchmittTrigger seqResetTrigger;
  227. SchmittTrigger setLockTrigger;
  228. SchmittTrigger setLearnTrigger;
  229. SchmittTrigger setSeqTrigger;
  230. SchmittTrigger setPadTrigger;
  231. SchmittTrigger setArcadeTrigger;
  232. SchmittTrigger setArpegTrigger;
  233. SchmittTrigger octUpTrigger;
  234. SchmittTrigger octDwnTrigger;
  235. SchmittTrigger seqTransUpTrigger;
  236. SchmittTrigger seqTransDwnTrigger;
  237. SchmittTrigger polyTransUpTrigger;
  238. SchmittTrigger polyTransDwnTrigger;
  239. SchmittTrigger muteSeqTrigger;
  240. SchmittTrigger muteMonoTrigger;
  241. SchmittTrigger muteLockedTrigger;
  242. SchmittTrigger mutePolyATrigger;
  243. SchmittTrigger mutePolyBTrigger;
  244. bool muteSeq = false;
  245. bool muteMono = false;
  246. bool muteLocked = false;
  247. bool mutePoly = false;
  248. PulseGenerator gatePulse;
  249. PulseGenerator keyPulse;
  250. PulseGenerator monoPulse;
  251. PulseGenerator lockedPulse;
  252. PulseGenerator clockPulse;
  253. PulseGenerator startPulse;
  254. PulseGenerator stopPulse;
  255. bool clkMIDItick = false;
  256. bool MIDIstart = false;
  257. bool MIDIstop = false;
  258. bool MIDIcont = false;
  259. bool stopped = true;
  260. bool arpMIDItick = false;
  261. bool seqMIDItick = false;
  262. int seqTickCount = 0;
  263. int arpTickCount = 0;
  264. int sampleFrames = 0;
  265. int displayedBPM = 0;
  266. float BPMrate = 0.0f;
  267. bool BPMdecimals = false;
  268. bool firstBPM = true; ///to hold if no clock ...and skip first BPM calc...
  269. bool extBPM = false;
  270. ///////////////
  271. MIDIPolyInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  272. onReset();
  273. }
  274. ~MIDIPolyInterface() {
  275. };
  276. void doSequencer();
  277. void step() override;
  278. void processMessage(MidiMessage msg);
  279. void processCC(MidiMessage msg);
  280. void processSystem(MidiMessage msg);
  281. void pressNote(int note, int vel);
  282. void releaseNote(int note);
  283. void releasePedalNotes();
  284. void setPolyIndex(int note);
  285. void initPolyIndex();
  286. void recoverBufferedNotes();
  287. void getBPM();
  288. float minmaxFit(float val, float minv, float maxv);
  289. void MidiPanic();
  290. void onSampleRateChange() override{
  291. onReset();
  292. }
  293. void onReset() override {
  294. // resetMidi();
  295. for (int i = 0; i < numPads; i++)
  296. {
  297. noteButtons[i].key= 48 + i;
  298. if (i < 8 ) noteButtons[i].mode = POLY_MODE;
  299. else if(i < 12) noteButtons[i].mode = SEQ_MODE;
  300. else noteButtons[i].mode = LOCKED_MODE;
  301. //// else noteButtons[i].mode = XLOCK_MODE;
  302. }
  303. polyIndex = 0;
  304. polyTopIndex = 7;;
  305. lastpolyIndex = 0;
  306. seqTransParam = 0;
  307. for (int i = 0; i < NUM_OUTPUTS; i++){
  308. outputs[i].value= 0.0f;
  309. }
  310. params[SEQRESET_PARAM].value = 0.0f;
  311. sustainFilter.lambda = 100.f * engineGetSampleTime();
  312. modFilter.lambda = 100.f * engineGetSampleTime();
  313. pressureFilter.lambda = 100.f * engineGetSampleTime();
  314. pitchFilter.lambda = 100.f * engineGetSampleTime();
  315. }
  316. json_t *toJson() override {
  317. json_t *rootJ = json_object();
  318. json_object_set_new(rootJ, "midi", midiInput.toJson());
  319. for (int i = 0; i < numPads; i++) {
  320. json_object_set_new(rootJ, ("key" + std::to_string(i)).c_str(), json_integer(noteButtons[i].key));
  321. json_object_set_new(rootJ, ("mode" + std::to_string(i)).c_str(), json_integer(noteButtons[i].mode));
  322. }
  323. json_object_set_new(rootJ, "seqtransp", json_integer(seqTransParam));
  324. json_object_set_new(rootJ, "polytransp", json_integer(polyTransParam));
  325. json_object_set_new(rootJ, "arpegmode", json_integer(arpegMode));
  326. json_object_set_new(rootJ, "seqrunning", json_boolean(seqrunning));
  327. return rootJ;
  328. }
  329. void fromJson(json_t *rootJ) override {
  330. json_t *midiJ = json_object_get(rootJ, "midi");
  331. if (midiJ)
  332. midiInput.fromJson(midiJ);
  333. for (int i = 0; i < numPads; i++) {
  334. json_t *keyJ = json_object_get(rootJ,("key" + std::to_string(i)).c_str());
  335. if (keyJ)
  336. noteButtons[i].key = json_integer_value(keyJ);
  337. json_t *modeJ = json_object_get(rootJ,("mode" + std::to_string(i)).c_str());
  338. if (modeJ)
  339. noteButtons[i].mode = json_integer_value(modeJ);
  340. noteButtons[i].learn = false;
  341. }
  342. json_t *seqtranspJ = json_object_get(rootJ,("seqtransp"));
  343. if (seqtranspJ)
  344. seqTransParam = json_integer_value(seqtranspJ);
  345. json_t *polytranspJ = json_object_get(rootJ,("polytransp"));
  346. if (polytranspJ)
  347. polyTransParam = json_integer_value(polytranspJ);
  348. json_t *arpegmodeJ = json_object_get(rootJ,("arpegmode"));
  349. if (arpegmodeJ)
  350. arpegMode = json_integer_value(arpegmodeJ);
  351. json_t *seqrunningJ = json_object_get(rootJ,("seqrunning"));
  352. if (seqrunningJ)
  353. seqrunning = json_is_true(seqrunningJ);
  354. padSetMode = POLY_MODE;
  355. padSetLearn = false;
  356. ///midiInput.rtMidiIn->ignoreTypes(true,false,false);
  357. MidiPanic();
  358. initPolyIndex();
  359. }
  360. };
  361. void MIDIPolyInterface::initPolyIndex(){
  362. polyTopIndex = -1;
  363. int iPoly = 0;
  364. polyMaxVoices = 0;
  365. for (int i = 0 ; i < numPads; i++){
  366. if (noteButtons[i].mode == POLY_MODE){
  367. iPoly ++;
  368. polyMaxVoices = iPoly;
  369. polyTopIndex = i;
  370. }
  371. }
  372. polyIndex = polyTopIndex;
  373. noteBuffer.clear();
  374. }
  375. void MIDIPolyInterface::pressNote(int note, int vel) {
  376. stampIx ++ ; // update note press stamp for mono "last"
  377. if (playingVoices == polyMaxVoices) keyPulse.trigger(1e-3);
  378. if (params[MONORETRIG_PARAM].value > 0.5f) monoPulse.trigger(1e-3);
  379. if (params[LOCKEDRETRIG_PARAM].value > 0.5f) lockedPulse.trigger(1e-3);
  380. bool (Xlockedmatch) = false;
  381. for (int i = 0; i < numPads; i++){
  382. noteButtons[i].polyretrig = false;
  383. if (noteButtons[i].learn) {
  384. noteButtons[i].key= note;
  385. noteButtons[i].learn = false;
  386. }
  387. /////////play every matching locked note...
  388. if ((note == noteButtons[i].key) && (noteButtons[i].mode > 1)){
  389. noteButtons[i].gate = true;
  390. noteButtons[i].newkey = true; //same key but true to display velocity
  391. noteButtons[i].vel = vel;
  392. noteButtons[i].velseq = vel;
  393. noteButtons[i].stamp = stampIx;
  394. //
  395. if (noteButtons[i].mode == XLOCK_MODE) Xlockedmatch = true;
  396. }
  397. }
  398. //if (params[PLAYXLOCKED_PARAM].value < 0.5f)
  399. if (Xlockedmatch) return;
  400. ///////////////////////
  401. if (polyIndex > -1){ //polyIndex -1 if all notes are locked or seq
  402. setPolyIndex(note);
  403. ////////////////////////////////////////
  404. /// if gate is on set retrigg
  405. noteButtons[polyIndex].polyretrig = noteButtons[polyIndex].gate;
  406. noteButtons[polyIndex].stamp = stampIx;
  407. noteButtons[polyIndex].key = note;
  408. noteButtons[polyIndex].vel = vel;
  409. noteButtons[polyIndex].velseq = vel;
  410. noteButtons[polyIndex].newkey = true;
  411. noteButtons[polyIndex].gate = true;
  412. }
  413. return;
  414. }
  415. void MIDIPolyInterface::releaseNote(int note) {
  416. // auto it = std::find(noteBuffer.begin(), noteBuffer.end(), note);
  417. //if (it != noteBuffer.end()) noteBuffer.erase(it);
  418. noteBuffer.remove(note);
  419. if ((params[MONORETRIG_PARAM].value > 0.5f) && (params[MONOPITCH_PARAM].value != 1.0f)) monoPulse.trigger(1e-3);
  420. if ((params[LOCKEDRETRIG_PARAM].value > 0.5f) && (params[LOCKEDPITCH_PARAM].value != 1.0f)) lockedPulse.trigger(1e-3);
  421. for (int i = 0; i < numPads; i++)
  422. {
  423. if ((note == noteButtons[i].key) && (noteButtons[i].vel > 0)){
  424. // polyIndex = i;
  425. if (!noteButtons[i].button) noteButtons[i].vel = 0;
  426. noteButtons[i].gate = pedal && sustainhold;
  427. if ((noteButtons[i].mode == POLY_MODE) && (!noteButtons[i].gate) && (!noteBuffer.empty())){
  428. //recover if buffered over number of voices
  429. noteButtons[i].key = noteBuffer.front();
  430. noteBuffer.pop_front();
  431. noteButtons[i].gate = true;
  432. noteButtons[i].vel = noteButtons[i].velseq;
  433. }
  434. }
  435. }
  436. return;
  437. }
  438. void MIDIPolyInterface::releasePedalNotes() {
  439. // gatePulse.trigger(1e-3);
  440. for (int i = 0; i < numPads; i++)
  441. {
  442. if (noteButtons[i].vel == 0){
  443. if (!noteBuffer.empty()){//recover if buffered over number of voices
  444. noteButtons[i].key = noteBuffer.front();
  445. noteButtons[i].vel = noteButtons[i].velseq;
  446. noteBuffer.pop_front();
  447. }else{
  448. noteButtons[i].gate = false;
  449. }
  450. }
  451. }
  452. return;
  453. }
  454. ///////////////////////////////////////////// SET POLY INDEX /////////////////////////////////////////////
  455. void MIDIPolyInterface::setPolyIndex(int note){
  456. polymode = static_cast<int>(params[POLYMODE_PARAM].value);
  457. if (polymode < 1) polyIndex ++;
  458. else if (pedal && sustainhold){///check if note is held to recycle it....
  459. for (int i = 0; i < numPads; i ++){
  460. if ((noteButtons[i].mode == POLY_MODE) && (noteButtons[i].gate) && (noteButtons[i].key == note)){
  461. // ///note is already on....
  462. lastpolyIndex = i;
  463. polyIndex = i;
  464. return;
  465. }
  466. }
  467. }else if (polymode > 1) polyIndex = 0;
  468. int ii = polyIndex;
  469. for (int i = 0; i < (polyTopIndex + 1); i ++){
  470. if (ii > polyTopIndex) ii = 0;
  471. //if (!(noteButtons[ii].locked)){
  472. if (noteButtons[ii].mode == POLY_MODE){
  473. if (!noteButtons[ii].gate){
  474. lastpolyIndex = ii;
  475. polyIndex = ii;
  476. return;
  477. }
  478. }
  479. ii ++;
  480. }
  481. //////////scan to steal oldest note.......
  482. lastpolyIndex ++;
  483. ii = lastpolyIndex;
  484. for (int i = 0; i < (polyTopIndex + 1); i ++){
  485. if (ii > polyTopIndex) ii = 0;
  486. //if (!(noteButtons[ii].locked)){
  487. if (noteButtons[ii].mode == POLY_MODE){
  488. lastpolyIndex = ii;
  489. polyIndex = ii;
  490. /// pulse for reTrigger
  491. //noteButtons[ii].polyretrig = false;
  492. ///// save to Buffer /////
  493. // int notebffr;
  494. // notebffr = noteButtons[ii].key;
  495. if (noteButtons[ii].vel > 0) noteBuffer.push_front(noteButtons[ii].key); ///////////////
  496. return;
  497. }
  498. ii ++;
  499. }
  500. }
  501. /////////////////////////////// END SET POLY INDEX //////////////////////////////////////////////
  502. ///////////////////////////////////////////////////////////////////
  503. // MMM MMM III DDDDDDDD III
  504. // MMMM MMMM III DDD DDD III
  505. // MMMMM MMMMM III DDD DDD III
  506. // MMMMMM MMMMMM III DDD DDD III
  507. // MMM MMMMM MMM III DDD DDD III
  508. // MMM MMM MMM III DDD DDD III
  509. // MMM M MMM III DDDDDDDD III
  510. //////////////////////////////////////////////////////////////////
  511. void MIDIPolyInterface::processMessage(MidiMessage msg) {
  512. if (msg.status() == 0xf) {
  513. ///clock
  514. processSystem(msg);
  515. return;
  516. }
  517. //if ((midiInput.channel < 0) || (midiInput.channel == msg.channel())){
  518. switch (msg.status()) {
  519. case 0x8: {
  520. releaseNote(msg.data1 & 0x7f);
  521. }
  522. break;
  523. case 0x9: {// note on
  524. if (msg.data2 > 0) {
  525. pressNote((msg.data1 & 0x7f), msg.data2);
  526. } else {
  527. releaseNote(msg.data1 & 0x7f);
  528. }
  529. }
  530. break;
  531. case 0xb: {
  532. processCC(msg);
  533. }
  534. break;
  535. // pitch wheel
  536. case 0xe: {
  537. pitch = msg.data2 * 128 + msg.data1;
  538. }
  539. break;
  540. // channel aftertouch
  541. case 0xd: {
  542. pressure = msg.data1;
  543. }
  544. break;
  545. default: break;
  546. }
  547. //}
  548. }
  549. void MIDIPolyInterface::processCC(MidiMessage msg) {
  550. switch (msg.data1) {
  551. // mod
  552. case 0x01: {
  553. mod = msg.data2;
  554. } break;
  555. // sustain
  556. case 0x40: {
  557. sustain = msg.data2;
  558. if (sustain >= 64) {
  559. pedal = sustainhold;
  560. }else {
  561. pedal = false;
  562. if (sustainhold) releasePedalNotes();
  563. }
  564. } break;
  565. default: break;
  566. }
  567. }
  568. void MIDIPolyInterface::processSystem(MidiMessage msg) {
  569. switch (msg.channel()) {
  570. case 0x8: {
  571. // debug("timing clock");
  572. clkMIDItick = true;
  573. seqMIDItick = true;
  574. arpMIDItick = true;
  575. } break;
  576. case 0xa: {
  577. // debug("start");
  578. MIDIstart = true;
  579. } break;
  580. case 0xb: {
  581. // debug("continue");
  582. MIDIcont = true;
  583. } break;
  584. case 0xc: {
  585. // debug("stop");
  586. MIDIstop = true;
  587. } break;
  588. default: break;
  589. }
  590. }
  591. void MIDIPolyInterface::MidiPanic() {
  592. pitch = 8192;
  593. outputs[PBEND_OUTPUT].value = 0.0f;
  594. mod = 0;
  595. outputs[MOD_OUTPUT].value = 0.0f;
  596. pressure = 0;
  597. outputs[PRESSURE_OUTPUT].value = 0.0f;
  598. sustain = 0;
  599. outputs[SUSTAIN_OUTPUT].value = 0.0f;
  600. pedal = false;
  601. for (int i = 0; i < numPads; i++)
  602. {
  603. noteButtons[i].vel = 0;
  604. noteButtons[i].gate = false;
  605. noteButtons[i].button = false;
  606. }
  607. noteBuffer.clear();
  608. }
  609. /////////////////////////////
  610. ////////////////////////////////// DISPLAY
  611. //////////////////////////////////////////
  612. void MIDIPolyInterface::getBPM(){
  613. if (firstBPM){
  614. firstBPM = false;
  615. sampleFrames = 0;
  616. return;
  617. }
  618. float fBPM = engineGetSampleRate() * 600.0f / static_cast<float>(sampleFrames); // / ;
  619. sampleFrames = 0;
  620. displayedBPM = static_cast<int>(fBPM + 0.5f);
  621. }
  622. float MIDIPolyInterface::minmaxFit(float val, float minv, float maxv){
  623. if (val < minv) val = minv;
  624. else if (val > maxv) val = maxv;
  625. return val;
  626. }
  627. /////////////////// //// //// //// //////////////////////
  628. ///////////////// /////////////// ///////// //////////// ////// ////////////////////
  629. ///////////////// //////// ///////// //////// /////////////////////
  630. /////////////////////// /////// ///////// //////////// ////////////////////////////
  631. ////////////// ///////// ///////// //// ////////////////////////////
  632. void MIDIPolyInterface::step() {
  633. //// mono modes and indexes
  634. int liveMonoMode = static_cast <int>(params[MONOPITCH_PARAM].value);
  635. int liveIx = 128 - liveMonoMode * 65; //first index -2 for Upper,(63 not used for Last), 128 for Lower
  636. int liveMonoIx = 0;
  637. int lockedMonoMode = static_cast <int>(params[LOCKEDPITCH_PARAM].value);
  638. int lockedIx = 128 - lockedMonoMode * 65; //first index -2 for Upper,(63 not used for Last), 128 for Lower
  639. int lockedMonoIx = 0;
  640. ////
  641. clockSource = static_cast<int>(params[SEQCLOCKSRC_PARAM].value);
  642. if (clockSource == 1){
  643. if (inputs[SEQSPEED_INPUT].active){
  644. BPMdecimals = true;
  645. float vcBPMtime = minmaxFit(inputs[SEQSPEED_INPUT].value,-10.0f,10.0f) * 24.0f;
  646. BPMrate = minmaxFit(params[SEQSPEED_PARAM].value + vcBPMtime, 12.0f, 360.0f);
  647. } else{
  648. BPMrate = params[SEQSPEED_PARAM].value;
  649. BPMdecimals = false;
  650. }
  651. displayedBPM = static_cast<int>(BPMrate * 100.f + 0.5f);
  652. }
  653. ////////// MIDI MESSAGE ////////
  654. MidiMessage msg;
  655. while (midiInput.shift(&msg)) {
  656. processMessage(msg);
  657. }
  658. bool analogdrift = (params[DRIFT_PARAM].value > 0.0001f);
  659. bool newdrift = false;
  660. if (analogdrift){
  661. static int framedrift = 0;
  662. if (framedrift > engineGetSampleRate())
  663. {
  664. newdrift = true;
  665. framedrift = 4 * rand() % static_cast<int>(engineGetSampleRate()/2.0f);
  666. }else{
  667. newdrift = false;
  668. framedrift++;
  669. }
  670. }
  671. //////////////////////////////
  672. playingVoices = 0;
  673. bool monogate = false;
  674. // bool retrigLive = false;
  675. bool lockedgate = false;
  676. // bool retrigLocked = false;
  677. static int lockedM = 0;
  678. static int liveM = 0;
  679. for (int i = 0; i < numPads; i++)
  680. {
  681. if ((!noteButtons[i].button) && (params[KEYBUTTON_PARAM + i].value > 0.5f)){ ///button ON
  682. if (noteButtons[i].mode == 0) noteButtons[i].polyretrig = noteButtons[i].gate;
  683. noteButtons[i].vel = 127;
  684. noteButtons[i].button = true;
  685. //noteButtons[i].monoretrig = true;
  686. /// update note press stamp for mono "last"
  687. stampIx ++;
  688. noteButtons[i].stamp = stampIx;
  689. //if ((noteButtons[i].mode <2)&&((params[MONORETRIG_PARAM].value > 0.5f)||(params[LOCKEDRETRIG_PARAM].value > 0.5f))){
  690. if (noteButtons[i].mode != SEQ_MODE) {
  691. keyPulse.trigger(1e-3);
  692. monoPulse.trigger(1e-3);
  693. lockedPulse.trigger(1e-3);
  694. }
  695. ///////////// SET BUTTON MODE
  696. if (padSetMode>0) {
  697. //noteButtons[i].locked = !noteButtons[i].locked;
  698. if (noteButtons[i].mode != padSetMode) noteButtons[i].mode = padSetMode;
  699. else noteButtons[i].mode = POLY_MODE;
  700. initPolyIndex();
  701. }else if ((padSetLearn) && (noteButtons[i].mode >0)) ///learn if pad locked or Seq
  702. noteButtons[i].learn = !noteButtons[i].learn;
  703. ////////////////////////////////////////////
  704. //if (!noteButtons[i].gate) noteButtons[i].vel = 64;
  705. } else if ((noteButtons[i].button) && (params[KEYBUTTON_PARAM + i].value < 0.5f)){///button off
  706. if ((noteButtons[i].mode == POLY_MODE) && (liveMonoMode != 1)) monoPulse.trigger(1e-3);
  707. else if ((noteButtons[i].mode > SEQ_MODE) && (lockedMonoMode != 1)) lockedPulse.trigger(1e-3);
  708. noteButtons[i].button = false;
  709. if (!noteButtons[i].gate) noteButtons[i].vel = 0;
  710. }
  711. bool thisgate = noteButtons[i].gate || noteButtons[i].button;
  712. //// retrigger ...
  713. bool outgate = thisgate;
  714. if (noteButtons[i].polyretrig) outgate = !keyPulse.process(engineGetSampleTime());
  715. outputs[GATE_OUTPUT + i].value = !mutePoly && outgate ? 10.0f : 0.0f;
  716. if (thisgate){
  717. outputs[VEL_OUTPUT + i].value = noteButtons[i].velseq / 127.0f * 10.0f; //(velocity from seq 'cause it doesn't update to zero)
  718. if (!padSetLearn) noteButtons[i].learn = false;
  719. // get mono values
  720. if (noteButtons[i].mode == POLY_MODE){
  721. playingVoices ++;
  722. switch (liveMonoMode){
  723. case 0:{
  724. //// get lowest pressed note
  725. if (noteButtons[i].key < liveIx) {
  726. liveIx = noteButtons[i].key;
  727. liveM = i;
  728. monogate = true;
  729. }
  730. }break;
  731. case 1:{
  732. if (noteButtons[i].stamp > liveMonoIx ) {
  733. liveMonoIx = noteButtons[i].stamp;
  734. liveM = i;
  735. monogate = true;
  736. }
  737. }break;
  738. default:{
  739. //// get highest pressed note
  740. if (noteButtons[i].key > liveIx) {
  741. liveIx = noteButtons[i].key;
  742. liveM = i;
  743. monogate = true;
  744. }
  745. }break;
  746. }
  747. }else if ((noteButtons[i].mode == LOCKED_MODE) || ((noteButtons[i].mode == XLOCK_MODE)&&(params[PLAYXLOCKED_PARAM].value>0.5))){
  748. switch (lockedMonoMode){
  749. case 0:{
  750. //// get lowest pressed note
  751. if (noteButtons[i].key < lockedIx) {
  752. lockedIx = noteButtons[i].key;
  753. lockedM = i;
  754. lockedgate = true;
  755. }
  756. }break;
  757. case 1:{
  758. if (noteButtons[i].stamp > lockedMonoIx ) {
  759. lockedMonoIx = noteButtons[i].stamp;
  760. lockedM= i;
  761. lockedgate = true;
  762. }
  763. }break;
  764. default:{
  765. //// get highest pressed note
  766. if (noteButtons[i].key > lockedIx) {
  767. lockedIx = noteButtons[i].key;
  768. lockedM = i;
  769. lockedgate = true;
  770. }
  771. }break;
  772. }
  773. }
  774. ///////// POLY PITCH OUTPUT///////////////////////
  775. if (analogdrift){
  776. static int bounced[numPads] = {0};
  777. float dlimit = (0.1f + params[DRIFT_PARAM].value )/ 26.4f;
  778. const float driftfactor = 1e-9f;
  779. if (newdrift) {
  780. bounced[i] = 0;
  781. int randrange = static_cast<int>(1.0f + params[DRIFT_PARAM].value) * 300;
  782. drift[i] = (static_cast<float>(rand() % randrange * 2 - randrange)) * driftfactor * ( 0.5f + params[DRIFT_PARAM].value);
  783. } //
  784. noteButtons[i].drift += drift[i];
  785. if ((bounced[i] < 1) && (noteButtons[i].drift > dlimit )) {
  786. drift[i] = -drift[i];
  787. bounced[i] = 1;
  788. }else if ((bounced[i] > -1) && (noteButtons[i].drift < - dlimit )) {
  789. drift[i] = -drift[i];
  790. bounced[i] = -1;
  791. }
  792. }else noteButtons[i].drift = 0.0f; // no analog drift
  793. float noteUnison = 0.0f;
  794. if (inputs[POLYUNISON_INPUT].active)
  795. noteUnison = (minmaxFit(inputs[POLYUNISON_INPUT].value * 0.1f ,-10.0f,10.f)) * params[POLYUNISON_PARAM].value * (noteButtons[liveMono].key - noteButtons[i].key);
  796. else noteUnison = params[POLYUNISON_PARAM].value * (noteButtons[liveMono].key - noteButtons[i].key);
  797. outputs[PITCH_OUTPUT + i].value = noteButtons[i].drift + (inputs[POLYSHIFT_INPUT].value/48.0f * params[TRIMPOLYSHIFT_PARAM].value) + (polyTransParam + noteButtons[i].key + noteUnison - 60) / 12.0f; //
  798. //////////////////////////////////////////////////
  799. }
  800. if (seqrunning) lights[SEQ_LIGHT + i].value = (seqStep == i) ? 1.0f : 0.0f;
  801. } //// end for i to numPads
  802. lockedMono = lockedM;
  803. liveMono = liveM;
  804. sustainhold = params[HOLD_PARAM].value > 0.5f;
  805. // Output Live Mono note
  806. // bool monogate = (noteButtons[liveMono].gate || noteButtons[liveMono].button);
  807. if (outputs[MONOPITCH_OUTPUT].active) {
  808. //////////////////////////////////////
  809. ///////////////////////////////// ///
  810. /// A R C A D E // S C A N /// //
  811. /////////////////////////////// ////
  812. ////////////////////////////// // ////
  813. ///// A R P E G G I A T O R //////////
  814. if (arpegMode > 0) {
  815. int updArpClockRatio = 0;
  816. if (inputs[ARPEGRATIO_INPUT].active)
  817. updArpClockRatio = static_cast<int>(minmaxFit(inputs[ARPEGRATIO_INPUT].value + params[ARPEGRATIO_PARAM].value, 0.0f, 11.0f));
  818. else
  819. updArpClockRatio = static_cast<int>(params[ARPEGRATIO_PARAM].value);
  820. if (monogate){
  821. if (!arpegStarted) {
  822. arpegStarted = true;
  823. arpegIx = liveMono;
  824. arpegCycle = 0;
  825. arpOctIx = 0;
  826. arpSampleCount = 0;
  827. arpPhase = 0.0f;
  828. arpTickCount = 0;
  829. /////////////////////////////////
  830. syncArpPhase = seqrunning;///// SYNC with seq if running
  831. /////////////////////////////////
  832. }
  833. if (arpegMode > 1){/////// ARCADE / / / / / / /
  834. arpegFrame ++;
  835. if (arpegFrame > (engineGetSampleRate() / 60.0f)){
  836. arpegStep = true;
  837. arpegFrame = 0;
  838. }
  839. }else {//if (!seqrunning){ /// set clocks if sequence is not running.....
  840. float arpswingPhase;
  841. float swingknob = params[SEQARPSWING_PARAM].value / 40.0f;
  842. bool swingThis ((params[ARPSWING_PARAM].value > 0.5f) && ((swingTriplet[arpclockRatio]) || (params[SWINGTRI_PARAM].value > 0.5f)));
  843. if (clockSource < 2) {
  844. if (clockSource == 1) ClockArpSamples = static_cast<int>(engineGetSampleRate() * 60.0f/BPMrate / ClockRatios[arpclockRatio] + 0.5f);
  845. arpPhase = static_cast<float>(arpSampleCount)/static_cast<float>(ClockArpSamples);
  846. arpSampleCount++;
  847. if (swingThis){
  848. if (arpSwingDwn) arpswingPhase = 1.0f + swingknob;
  849. else arpswingPhase = 1.0f - swingknob;
  850. } else arpswingPhase = 1.0f;
  851. if (arpPhase >= arpswingPhase) {
  852. arpPhase = 0.0f;
  853. arpSwingDwn = !arpSwingDwn;
  854. arpegStep = true;
  855. arpSampleCount = 0;
  856. }
  857. }else{
  858. int arpMidiPhase;
  859. int swingtick = static_cast<int>(swingknob * (24/ClockRatios[seqclockRatio]));
  860. if (arpMIDItick){
  861. arpMIDItick = false;
  862. arpTickCount ++; /// arpeggiator sync with sequencer
  863. if (swingThis){
  864. if (arpSwingDwn) arpMidiPhase = 24/ClockRatios[arpclockRatio] + swingtick;
  865. else arpMidiPhase = 24/ClockRatios[arpclockRatio] - swingtick;
  866. } else arpMidiPhase = 24/ClockRatios[arpclockRatio];
  867. if (arpTickCount >= arpMidiPhase) {
  868. arpTickCount = 0;
  869. arpSwingDwn = !arpSwingDwn;
  870. arpegStep = true;
  871. }
  872. }
  873. }
  874. }// END IF MODE ARP
  875. /// first gate --> set up indexes
  876. }else{ ////////// GATE OFF //arpeg ON no gate (all notes off) reset..
  877. arpegStarted = false;
  878. //if (!seqrunning) {
  879. arpSampleCount = 0;
  880. arpPhase = 0.0f;
  881. arpSwingDwn = true;
  882. // }
  883. }
  884. bool notesFirst = (params[ARPEGOCTALT_PARAM].value > 0.5f);
  885. if ((arpegStep) && (monogate)){
  886. if (arpclockRatio != updArpClockRatio){
  887. arpclockRatio = updArpClockRatio;
  888. arpPhase = 0.0f;
  889. arpSwingDwn = true;
  890. arpSampleCount = 0;
  891. }///update ratio....
  892. int arpOctaveKnob = static_cast<int>(params[ARPEGOCT_PARAM].value);
  893. for (int i = 0 ; i < 5; i++){
  894. lights[ARPOCT_LIGHT + i].value = 0.0f;
  895. }
  896. arpegStep=false;
  897. if (notesFirst) {
  898. ////////// NOTE to arp and CYCLE FLAG
  899. arpegIx ++;
  900. if (arpegIx > polyTopIndex) arpegIx = 0;
  901. for (int i = 0; i <= polyTopIndex; i++){
  902. if ((noteButtons[arpegIx].mode == POLY_MODE) && ((noteButtons[arpegIx].gate) || (noteButtons[arpegIx].button))) {
  903. arpegCycle++;
  904. if (arpegCycle >= playingVoices){
  905. arpegCycle = 0;
  906. arpOctValue = arpOctaveKnob;
  907. if (octaveShift[arpOctValue][arpOctIx + 1] > 2){
  908. arpOctIx = 0;
  909. } else {
  910. arpOctIx ++;
  911. }
  912. }
  913. break;
  914. }
  915. arpegIx ++;
  916. if (arpegIx > polyTopIndex) arpegIx = 0;
  917. }
  918. ///////////
  919. }else {
  920. arpOctValue = arpOctaveKnob;
  921. if (octaveShift[arpOctValue][arpOctIx + 1] > 2) {
  922. arpegIx ++;
  923. arpOctIx= 0;
  924. for (int i = 0; i <= polyTopIndex; i++){
  925. if ((noteButtons[arpegIx].mode == POLY_MODE) && ((noteButtons[arpegIx].gate) || (noteButtons[arpegIx].button))) {
  926. break;
  927. }
  928. arpegIx ++;
  929. if (arpegIx > polyTopIndex) arpegIx = 0;
  930. }
  931. } else {
  932. arpOctIx ++;
  933. }
  934. }
  935. lights[ARPOCT_LIGHT + 2 + octaveShift[arpOctValue][arpOctIx]].value = 1.0f;
  936. arpDisplayIx = arpegIx;
  937. }else if (!monogate){
  938. ///keysUp...update arp ratio
  939. arpclockRatio = updArpClockRatio;
  940. arpDisplayIx = -1;
  941. for (int i = 0 ; i < 5; i++){
  942. lights[ARPOCT_LIGHT + i].value = 0.0f;
  943. }
  944. }
  945. outputs[MONOPITCH_OUTPUT].value = octaveShift[arpOctValue][arpOctIx] + (noteButtons[arpegIx].key - 60) / 12.0f;
  946. }else{
  947. /// Normal Mono /////////////
  948. outputs[MONOPITCH_OUTPUT].value = noteButtons[liveMono].drift + (noteButtons[liveMono].key - 60) / 12.0f;
  949. }
  950. } /// end if output active
  951. outputs[MONOVEL_OUTPUT].value = noteButtons[liveMono].vel / 127.0f * 10.0f;
  952. bool monoRtgGate = monogate;
  953. if ((params[MONORETRIG_PARAM].value > 0.5f) && (noteButtons[liveMono].key != lastMono)){///if retrig
  954. monoRtgGate = !monoPulse.process(engineGetSampleTime());
  955. if (monoRtgGate) lastMono = noteButtons[liveMono].key;
  956. }
  957. outputs[MONOGATE_OUTPUT].value = !muteMono && monoRtgGate ? 10.0f : 0.0f;
  958. //////////////////////////////////////
  959. //////////////////////////////////////////////////////////////////////////
  960. // Output locked Mono note
  961. outputs[LOCKEDVEL_OUTPUT].value = noteButtons[lockedMono].vel / 127.0f * 10.0f;
  962. outputs[LOCKEDPITCH_OUTPUT].value = noteButtons[lockedMono].drift + (noteButtons[lockedMono].key - 60) / 12.0f;
  963. bool lockedRtgGate = lockedgate;
  964. if ((params[LOCKEDRETRIG_PARAM].value > 0.5f) && (noteButtons[lockedMono].key != lastLocked)) {
  965. lockedRtgGate = !lockedPulse.process(engineGetSampleTime());
  966. if (lockedRtgGate) lastLocked = noteButtons[lockedMono].key; ///set new lastLive
  967. }
  968. outputs[LOCKEDGATE_OUTPUT].value = !muteLocked && lockedRtgGate ? 10.0f : 0.0f;
  969. if (pitch < 8192){
  970. outputs[PBEND_OUTPUT].value = pitchFilter.process(rescale(pitch, 0, 8192, -5.f, 0.f));
  971. } else {
  972. outputs[PBEND_OUTPUT].value = pitchFilter.process(rescale(pitch, 8192, 16383, 0.f, 5.f));
  973. }
  974. outputs[MOD_OUTPUT].value = modFilter.process(rescale(mod, 0, 127, 0.f, 10.f));
  975. outputs[SUSTAIN_OUTPUT].value = sustainFilter.process(rescale(sustain, 0, 127, 0.f, 10.f));
  976. outputs[PRESSURE_OUTPUT].value = pressureFilter.process(rescale(pressure, 0, 127, 0.f, 10.f));
  977. //////////////////// S E Q U E N C E R ////////////////////////////
  978. doSequencer(); /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ //////
  979. //////////////////// S E Q U E N C E R ////////////////////////////
  980. ///// RESET MIDI LIGHT
  981. if (resetMidiTrigger.process(params[RESETMIDI_PARAM].value)) {
  982. lights[RESETMIDI_LIGHT].value= 1.0f;
  983. MidiPanic();
  984. return;
  985. }
  986. if (lights[RESETMIDI_LIGHT].value > 0.0001f)
  987. lights[RESETMIDI_LIGHT].value -= 0.0001f ; // fade out light
  988. bool pulseClk = clockPulse.process(1.0f / engineGetSampleRate());
  989. outputs[SEQCLOCK_OUTPUT].value = pulseClk ? 10.0f : 0.0f;
  990. bool pulseStart = startPulse.process(1.0f / engineGetSampleRate());
  991. outputs[SEQSTART_OUTPUT].value = pulseStart ? 10.0f : 0.0f;
  992. bool pulseStop = stopPulse.process(1.0f / engineGetSampleRate());
  993. outputs[SEQSTOP_OUTPUT].value = pulseStop ? 10.0f : 0.0f;
  994. outputs[SEQSTARTSTOP_OUTPUT].value = (pulseStop || pulseStart) ? 10.0f : 0.0f;
  995. ////// TRIGGER BUTTONS....
  996. if (setSeqTrigger.process(params[SEQPAD_PARAM].value)){
  997. padSetMode = (padSetMode != SEQ_MODE)? SEQ_MODE:POLY_MODE;
  998. lights[PSEQ_LIGHT].value = (padSetMode==SEQ_MODE) ? 1.0f : 0.0f;
  999. lights[PLOCK_LIGHT].value = 0.f;
  1000. lights[PXLOCK_LIGHT].value = 0.f;
  1001. padSetLearn = false;
  1002. lights[PLEARN_LIGHT].value = 0.f;
  1003. for (int i = 0; i < numPads; i++) noteButtons[i].learn = false;
  1004. }
  1005. if (setLockTrigger.process(params[LOCKPAD_PARAM].value)){
  1006. padSetMode = (padSetMode != LOCKED_MODE) ? LOCKED_MODE:POLY_MODE;
  1007. lights[PLOCK_LIGHT].value = (padSetMode==LOCKED_MODE) ? 1.0f : 0.0f;
  1008. lights[PSEQ_LIGHT].value = 0.f;
  1009. lights[PXLOCK_LIGHT].value = 0.f;
  1010. padSetLearn = false;
  1011. lights[PLEARN_LIGHT].value = 0.f;
  1012. for (int i = 0; i < numPads; i++) noteButtons[i].learn = false;
  1013. }
  1014. if (setPadTrigger.process(params[PADXLOCK_PARAM].value)){
  1015. padSetMode = (padSetMode != XLOCK_MODE)? XLOCK_MODE:POLY_MODE;
  1016. lights[PXLOCK_LIGHT].value = (padSetMode==XLOCK_MODE) ? 1.0f : 0.0f;
  1017. lights[PLOCK_LIGHT].value = 0.f;
  1018. lights[PSEQ_LIGHT].value = 0.f;
  1019. padSetLearn = false;
  1020. lights[PLEARN_LIGHT].value = 0.f;
  1021. for (int i = 0; i < numPads; i++) noteButtons[i].learn = false;
  1022. }
  1023. if (setLearnTrigger.process(params[LEARNPAD_PARAM].value)){
  1024. padSetLearn = !padSetLearn;
  1025. lights[PLEARN_LIGHT].value = padSetLearn ? 1.0f : 0.0f;
  1026. padSetMode = POLY_MODE;
  1027. lights[PLOCK_LIGHT].value = 0.f;
  1028. lights[PSEQ_LIGHT].value = 0.f;
  1029. lights[PXLOCK_LIGHT].value = 0.f;
  1030. if (!padSetLearn){///turn off learn on buttons
  1031. for (int i = 0; i < numPads; i++) noteButtons[i].learn = false;
  1032. }
  1033. }
  1034. if (inputs[ARPMODE_INPUT].active) {
  1035. arpegMode = static_cast<int>(minmaxFit(inputs[ARPMODE_INPUT].value * 0.3, 0.0f, 2.0f));
  1036. arpegStatus = ((outputs[MONOPITCH_OUTPUT].active)? 0 : 3 ) + arpegMode;
  1037. lights[ARPEGON_LIGHT].value = (arpegMode==1) ? 1.0f : 0.0f;
  1038. lights[ARCADEON_LIGHT].value = (arpegMode==2) ? 1.0f : 0.0f;
  1039. }else{
  1040. if (setArpegTrigger.process(params[ARPEGON_PARAM].value)){
  1041. arpegMode = (arpegMode != 1)? 1:0;
  1042. arpegStatus = ((outputs[MONOPITCH_OUTPUT].active)? 0 : 3 ) + arpegMode;
  1043. lights[ARPEGON_LIGHT].value = (arpegMode==1) ? 1.0f : 0.0f;
  1044. lights[ARCADEON_LIGHT].value = (arpegMode==2) ? 1.0f : 0.0f;
  1045. }
  1046. if (setArcadeTrigger.process(params[ARCADEON_PARAM].value)){
  1047. arpegMode = (arpegMode != 2)? 2:0;
  1048. arpegStatus = ((outputs[MONOPITCH_OUTPUT].active)? 0 : 3 ) + arpegMode;
  1049. lights[ARPEGON_LIGHT].value = (arpegMode==1) ? 1.0f : 0.0f;
  1050. lights[ARCADEON_LIGHT].value = (arpegMode==2) ? 1.0f : 0.0f;
  1051. }
  1052. }
  1053. if (muteSeqTrigger.process(params[MUTESEQ_PARAM].value)){
  1054. muteSeq = !muteSeq;
  1055. lights[MUTESEQ_LIGHT].value = (muteSeq) ? 1.0f : 0.0f;
  1056. }
  1057. if (muteMonoTrigger.process(params[MUTEMONO_PARAM].value)){
  1058. muteMono = !muteMono;
  1059. lights[MUTEMONO_LIGHT].value = (muteMono) ? 1.0f : 0.0f;
  1060. }
  1061. if (muteLockedTrigger.process(params[MUTELOCKED_PARAM].value)){
  1062. muteLocked = !muteLocked;
  1063. lights[MUTELOCKED_LIGHT].value = (muteLocked) ? 1.0f : 0.0f;
  1064. }
  1065. if (mutePolyATrigger.process(params[MUTEPOLYA_PARAM].value)){
  1066. mutePoly = !mutePoly;
  1067. lights[MUTEPOLY_LIGHT].value = (mutePoly) ? 1.0f : 0.0f;
  1068. }
  1069. if (mutePolyBTrigger.process(params[MUTEPOLYB_PARAM].value)){
  1070. mutePoly = !mutePoly;
  1071. lights[MUTEPOLY_LIGHT].value = (mutePoly) ? 1.0f : 0.0f;
  1072. }
  1073. if (polyTransUpTrigger.process(params[POLYTRANUP_PARAM].value)){
  1074. if (padSetLearn){
  1075. for (int i = 0; i < numPads; i++)
  1076. {
  1077. if ((noteButtons[i].learn) && (noteButtons[i].key<127)) noteButtons[i].key ++;
  1078. }
  1079. }else if (polyTransParam < 48) polyTransParam ++;
  1080. }
  1081. if (polyTransDwnTrigger.process(params[POLYTRANDWN_PARAM].value)){
  1082. if (padSetLearn){
  1083. for (int i = 0; i < numPads; i++)
  1084. {
  1085. if ((noteButtons[i].learn) && (noteButtons[i].key > 0)) noteButtons[i].key --;
  1086. }
  1087. }else if (polyTransParam > -48) polyTransParam --;
  1088. }
  1089. if ((seqTransUpTrigger.process(params[SEQTRANUP_PARAM].value)) && (seqTransParam < 48)) seqTransParam ++;
  1090. if ((seqTransDwnTrigger.process(params[SEQTRANDWN_PARAM].value)) && (seqTransParam > -48)) seqTransParam --;
  1091. //if (dispNotenumber != (params[DISPLAYNOTENUM_PARAM].value > 0.5f))
  1092. dispNotenumber = (params[DISPLAYNOTENUM_PARAM].value > 0.5f);
  1093. }
  1094. /////////////////////// * * * ///////////////////////////////////////////////// * * *
  1095. // * * * E N D O F S T E P * * *
  1096. /////////////////////// * * * ///////////////////////////////////////////////// * * *
  1097. void MIDIPolyInterface::doSequencer(){
  1098. /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ //////
  1099. /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ ////// /////// SEQ //////
  1100. //////// GET RATIO STEP OFFSET with CVs ....
  1101. int updSeqClockRatio = 0;
  1102. if (inputs[SEQRATIO_INPUT].active)
  1103. updSeqClockRatio = static_cast<int>(minmaxFit(inputs[SEQRATIO_INPUT].value + params[SEQCLOCKRATIO_PARAM].value, 0.0f, 11.0f));
  1104. else
  1105. updSeqClockRatio = static_cast<int>(params[SEQCLOCKRATIO_PARAM].value);
  1106. if (updSeqClockRatio != seqclockRatio){
  1107. seqclockRatio = updSeqClockRatio;
  1108. syncArpPhase = true;
  1109. }
  1110. int updSeqFirst = 0;
  1111. if (inputs[SEQFIRST_INPUT].active)
  1112. updSeqFirst = static_cast<int>(minmaxFit(inputs[SEQFIRST_INPUT].value * 1.55f + params[SEQFIRST_PARAM].value, 0.0f, 15.0f));
  1113. else
  1114. updSeqFirst = static_cast<int>(params[SEQFIRST_PARAM].value);
  1115. if (updSeqFirst != seqOffset)
  1116. {
  1117. seqOffset = updSeqFirst;
  1118. seqStep = seqOffset;
  1119. }
  1120. if (inputs[SEQSTEPS_INPUT].active) {
  1121. seqSteps = static_cast <int> (minmaxFit((inputs[SEQSTEPS_INPUT].value * 1.55f + params[SEQSTEPS_PARAM].value), 1.0f,16.0f));
  1122. }else{
  1123. seqSteps = static_cast <int> (params[SEQSTEPS_PARAM].value);
  1124. }
  1125. ///////////////////////////////////////////////
  1126. bool seqResetNow = false;
  1127. if ((params[SEQGATERUN_PARAM].value > 0.5f) && (inputs[SEQRUN_INPUT].active)) {
  1128. if ((!seqrunning) && (inputs[SEQRUN_INPUT].value > 3.f)){
  1129. seqrunning = true;
  1130. if (params[SEQRUNRESET_PARAM].value > 0.5f) seqResetNow = true;
  1131. } else if ((seqrunning) && (inputs[SEQRUN_INPUT].value < 2.f)){
  1132. seqrunning = false;
  1133. }
  1134. } else { /// trigger selected for run or disconnected gate input...
  1135. if (seqRunTrigger.process(params[SEQRUN_PARAM].value + inputs[SEQRUN_INPUT].value)) {
  1136. if (params[SEQRUNRESET_PARAM].value > 0.5f){// if linked run > reset
  1137. if (!seqrunning){
  1138. seqrunning = true;
  1139. seqResetNow = true;
  1140. } else {
  1141. seqrunning = false;
  1142. }
  1143. }else{ // reset not linked...regular toggle
  1144. seqrunning = !seqrunning;
  1145. }
  1146. }
  1147. }
  1148. if (clockSource == 2){
  1149. static int MIDIframe = 0;
  1150. if (extBPM && (sampleFrames < (3 * static_cast<int>(engineGetSampleRate()))))
  1151. sampleFrames ++;
  1152. else////// 3 seconds without a tick......(20 bmp min)
  1153. {
  1154. extBPM = false;
  1155. firstBPM = true;
  1156. displayedBPM = 0;
  1157. // MIDIframe = 0;
  1158. }
  1159. if (clkMIDItick){
  1160. MIDIframe++;
  1161. lights[MIDIBEAT_LIGHT].value = 0.f;
  1162. if (MIDIframe >= 24)
  1163. {
  1164. extBPM = true;
  1165. MIDIframe = 0;
  1166. lights[MIDIBEAT_LIGHT].value = 1.f;
  1167. getBPM();
  1168. }
  1169. clkMIDItick = false;
  1170. }
  1171. if(!inputs[SEQRUN_INPUT].active){
  1172. if (MIDIstart){
  1173. seqrunning = true;
  1174. seqTickCount = 0;
  1175. arpTickCount = 0;
  1176. MIDIstart = false;
  1177. seqResetNow = true;
  1178. }
  1179. if (MIDIcont){
  1180. seqrunning = true;
  1181. seqTickCount = 0;
  1182. arpTickCount = 0;
  1183. MIDIcont = false;
  1184. }
  1185. if (MIDIstop){
  1186. seqrunning = false;
  1187. MIDIstop = false;
  1188. }
  1189. }
  1190. }else if (clockSource == 0) {
  1191. if (extBPM && (inputs[CLOCK_INPUT].active) && (sampleFrames < (3 * static_cast<int>(engineGetSampleRate()))))
  1192. sampleFrames ++;
  1193. else////// 3 seconds without a tick......(20 bmp min)
  1194. {
  1195. extBPM = false;
  1196. firstBPM = true;
  1197. displayedBPM = 0;
  1198. }
  1199. if (extClockTrigger.process(inputs[CLOCK_INPUT].value)) {
  1200. ///// EXTERNAL CLOCK
  1201. extBPM = true;
  1202. ClockSeqSamples = static_cast<int>(static_cast<float>(sampleFrames) / ClockRatios[seqclockRatio]+0.5f);
  1203. ClockArpSamples = static_cast<int>(static_cast<float>(sampleFrames) / ClockRatios[arpclockRatio]+0.5f);
  1204. getBPM();
  1205. }
  1206. }
  1207. // Reset manual
  1208. if ((seqResetTrigger.process(params[SEQRESET_PARAM].value)) || ((inputs[SEQRESET_INPUT].active) && (seqResetTrigger.process(inputs[SEQRESET_INPUT].value)))) {
  1209. lights[SEQRESET_LIGHT].value = 1.0f;
  1210. seqOctIx = 0;
  1211. if (seqrunning) {
  1212. seqResetNext = true;
  1213. }else {
  1214. seqResetNow = true;
  1215. }
  1216. }
  1217. ///
  1218. if (seqResetNow){
  1219. seqPhase = 0.0f;
  1220. seqi = 0;
  1221. seqiWoct = 0;
  1222. seqStep = seqOffset;
  1223. seqOctIx = 0;
  1224. seqSwingDwn = true;
  1225. arpSwingDwn = true;
  1226. arpPhase = 0.0f;
  1227. seqTickCount = 0;
  1228. arpTickCount = 0;
  1229. }
  1230. ////// seq run // // // // // // // // //
  1231. bool nextStep = false;
  1232. if (seqrunning) {
  1233. int seqOctaveKnob = static_cast<int> (params[SEQOCT_PARAM].value);
  1234. if (stopped){
  1235. stopped = false;
  1236. startPulse.trigger(1e-3);
  1237. clockPulse.trigger(1e-3);
  1238. seqOctValue = seqOctaveKnob;
  1239. seqSampleCount = 0;
  1240. seqPhase = 0.0f;
  1241. seqSwingDwn = true;
  1242. arpSampleCount = 0;
  1243. arpPhase = 0.0f;
  1244. arpSwingDwn = true;
  1245. seqTickCount = 0;
  1246. arpTickCount = 0;
  1247. }
  1248. float swingknob = params[SEQARPSWING_PARAM].value / 40.0f;
  1249. float seqswingPhase;
  1250. int swingtick;
  1251. int swingMidiPhase;
  1252. bool notesFirst = (params[SEQOCTALT_PARAM].value > 0.5f);
  1253. bool DontSwing = true;
  1254. if ((params[SEQSWING_PARAM].value > 0.5f) && ((swingTriplet[seqclockRatio]) || (params[SWINGTRI_PARAM].value > 0.5f))){
  1255. int lastStepByOct = seqSteps * (1 + std::abs(seqOctValue-3));
  1256. ///if steps is Odd Don't swing last step..if Octaves first last Step is seqSteps * Octave cycles....if notes first last step is seqSteps...
  1257. DontSwing = (((seqSteps % 2 == 1) && (notesFirst) && ((seqStep - seqOffset) == (seqSteps - 1))) ||
  1258. ((lastStepByOct % 2 == 1) && (!notesFirst) && (seqiWoct == (lastStepByOct - 1))));
  1259. }
  1260. if (clockSource < 2) {
  1261. if (clockSource == 1) ClockSeqSamples = static_cast<int>(engineGetSampleRate() * 60.0f/BPMrate / ClockRatios[seqclockRatio] + 0.5f);
  1262. seqPhase = static_cast<float>(seqSampleCount)/static_cast<float>(ClockSeqSamples);
  1263. seqSampleCount++;
  1264. if (DontSwing) {
  1265. seqswingPhase = 1.0f;
  1266. }else{
  1267. if (seqSwingDwn){
  1268. seqswingPhase = 1.0f + swingknob;
  1269. }else{
  1270. seqswingPhase = 1.0f - swingknob;
  1271. }
  1272. }
  1273. if (seqPhase >= seqswingPhase) {
  1274. seqPhase = 0.0f;
  1275. seqSwingDwn = !seqSwingDwn;
  1276. nextStep = true;
  1277. seqSampleCount = 0;
  1278. if (DontSwing) seqSwingDwn = true;
  1279. }
  1280. }else{
  1281. swingtick = static_cast<int>(swingknob * (24/ClockRatios[seqclockRatio]));
  1282. if (seqMIDItick){
  1283. seqMIDItick = false;
  1284. seqTickCount ++;
  1285. if (DontSwing) {
  1286. swingMidiPhase = 24/ClockRatios[seqclockRatio];
  1287. }else{
  1288. if (seqSwingDwn){
  1289. swingMidiPhase = 24/ClockRatios[seqclockRatio] + swingtick;
  1290. }else{
  1291. swingMidiPhase = 24/ClockRatios[seqclockRatio] - swingtick;
  1292. }
  1293. }
  1294. if (seqTickCount >= swingMidiPhase){
  1295. seqTickCount = 0;
  1296. seqSwingDwn = !seqSwingDwn;
  1297. nextStep = true;
  1298. if (DontSwing) seqSwingDwn = true;
  1299. }
  1300. }
  1301. }
  1302. bool gateOut;
  1303. bool pulseTrig = gatePulse.process(1.0f / engineGetSampleRate());
  1304. gateOut = (noteButtons[seqStep].velseq > 0) && (!(pulseTrig && (params[SEQRETRIG_PARAM].value > 0.5f)));
  1305. //// if note goes out to seq...(if not the outputs hold the last played value)
  1306. if (params[SEQSEND_PARAM + seqStep].value > 0.5f){
  1307. outputs[SEQPITCH_OUTPUT].value = noteButtons[seqStep].drift + octaveShift[seqOctValue][seqOctIx] + (inputs[SEQSHIFT_INPUT].value * params[TRIMSEQSHIFT_PARAM].value /48.0f ) + (seqTransParam + noteButtons[seqStep].key - 60) / 12.0f;
  1308. outputs[SEQVEL_OUTPUT].value = noteButtons[seqStep].velseq / 127.0f * 10.0f;
  1309. outputs[SEQGATE_OUTPUT].value = !muteSeq && gateOut ? 10.0f : 0.0f;
  1310. ///if individual gate / vel
  1311. if (params[SEQSEND_PARAM + seqStep].value > 1.5f){
  1312. noteButtons[seqStep].gateseq = true;
  1313. // outputs[PITCH_OUTPUT + seqStep].value = noteButtons[seqStep].drift + octaveShift[seqOctValue][seqOctIx] + (seqTransParam + noteButtons[seqStep].key - 60) / 12.0f;
  1314. outputs[VEL_OUTPUT + seqStep].value = noteButtons[seqStep].velseq / 127.0f * 10.0f;
  1315. outputs[GATE_OUTPUT + seqStep].value = !muteSeq && gateOut ? 10.0f : 0.0f;
  1316. }
  1317. }else{
  1318. outputs[SEQGATE_OUTPUT].value = 0.0f;
  1319. }
  1320. if (nextStep) {
  1321. // restore gates and vel from individual outputs...
  1322. if (params[SEQSEND_PARAM + seqStep].value > 1.5f){
  1323. noteButtons[seqStep].gateseq = false;
  1324. // outputs[PITCH_OUTPUT + seqStep].value = noteButtons[seqStep].drift + (noteButtons[seqStep].key - 60) / 12.0f;
  1325. outputs[VEL_OUTPUT + seqStep].value = noteButtons[seqStep].vel / 127.0f * 10.0f;
  1326. outputs[GATE_OUTPUT + seqStep].value = noteButtons[seqStep].gate ? 10.0f : 0.0f;
  1327. }
  1328. for (int i = 0 ; i < 5; i++){
  1329. lights[SEQOCT_LIGHT + i].value = 0.0f;
  1330. }
  1331. if ((syncArpPhase) && (seqSwingDwn)) {
  1332. arpSampleCount = 0;
  1333. arpPhase = 0.0f;
  1334. arpSwingDwn = true;
  1335. syncArpPhase = false;
  1336. arpTickCount = 0;
  1337. }
  1338. clockPulse.trigger(1e-3);
  1339. gatePulse.trigger(1e-3);
  1340. ////////////////////////
  1341. if (seqResetNext){ ///if reset while running
  1342. seqResetNext = false;
  1343. seqPhase = 0.0f;
  1344. seqi = 0;
  1345. seqiWoct = 0;
  1346. seqOctIx = 0;
  1347. seqStep = seqOffset;
  1348. seqSwingDwn = true;
  1349. arpPhase = 0.0f;
  1350. arpSwingDwn = true;
  1351. seqTickCount = 0;
  1352. arpTickCount = 0;
  1353. seqSampleCount = 0;
  1354. arpSampleCount = 0; /// SYNC THE ARPEGG
  1355. }else{
  1356. seqiWoct ++;
  1357. if (notesFirst) {
  1358. ////// ADVANCE STEP ///////
  1359. seqi ++;
  1360. if ( seqi > (seqSteps - 1)) { ///seq Cycle ... change octave ?
  1361. seqOctValue = seqOctaveKnob;
  1362. if (octaveShift[seqOctValue][seqOctIx + 1] > 2) {
  1363. seqOctIx= 0;
  1364. seqiWoct = 0;
  1365. }else{
  1366. seqOctIx ++;
  1367. }
  1368. seqi = 0;// next cycle
  1369. }
  1370. }else{
  1371. if (octaveShift[seqOctValue][seqOctIx + 1] > 2) {
  1372. seqOctValue = seqOctaveKnob;
  1373. seqOctIx = 0;
  1374. seqi ++;
  1375. if ( seqi > (seqSteps - 1)) {
  1376. seqi = 0;// next cycle
  1377. seqiWoct = 0;
  1378. }
  1379. }else{
  1380. seqOctIx ++;
  1381. }
  1382. }
  1383. seqStep = ((seqi % seqSteps) + seqOffset) % numPads;
  1384. }
  1385. lights[SEQOCT_LIGHT + 2 + octaveShift[seqOctValue][seqOctIx]].value = 1.0f;
  1386. lights[SEQRUNNING_LIGHT].value = 1.f;
  1387. }
  1388. } else { ///stopped shut down gate....
  1389. if (!stopped){
  1390. lights[SEQRUNNING_LIGHT].value = 0.f;
  1391. noteButtons[seqStep].gateseq = false;
  1392. stopped = true;
  1393. stopPulse.trigger(1e-3);
  1394. //seqOctIx = 0;
  1395. //seqi = 0;
  1396. //seqiWoct = 0;
  1397. for (int i = 0 ; i < 5; i++){
  1398. lights[SEQOCT_LIGHT + i].value = 0.0f;
  1399. }
  1400. outputs[SEQGATE_OUTPUT].value = 0.0f;
  1401. }
  1402. }
  1403. if (lights[SEQRESET_LIGHT].value > 0.0001f)
  1404. lights[SEQRESET_LIGHT].value -= 0.0001f;
  1405. /////// SEQ ////// ------- E N D --------- ------- E N D --------- ------- E N D --------- /////// SEQ //////
  1406. return;
  1407. }
  1408. ///////////BUTTONS' DISPLAY
  1409. struct NoteDisplay : TransparentWidget {
  1410. MIDIPolyInterface::noteButton *nButton = new MIDIPolyInterface::noteButton();
  1411. NoteDisplay() {
  1412. font = Font::load(FONT_FILE);
  1413. }
  1414. float dfontsize = 12.0f;
  1415. int key = 0;
  1416. int vel = 0;
  1417. bool gate = false;
  1418. bool gateseq = false;
  1419. bool newkey = false;
  1420. int frame = 0;
  1421. int framevel = 0;
  1422. bool showvel = true;
  1423. int polyi = 0;
  1424. int *polyIndex = &polyi;
  1425. int id = 0;
  1426. int mode = 0;
  1427. bool learn = false;
  1428. bool notenumber = false;
  1429. bool *dispNotenumber = &notenumber;
  1430. int arpI = 0;
  1431. int *arpIx = &arpI;
  1432. bool arp = false;
  1433. std::shared_ptr<Font> font;
  1434. std::string to_display;
  1435. std::string displayNoteName(int key, bool notenumber);
  1436. void draw(NVGcontext *vg) {
  1437. frame ++;
  1438. if (frame > 5){
  1439. frame = 0;
  1440. newkey = nButton->newkey;
  1441. key = nButton->key;
  1442. vel = nButton->vel;
  1443. gate = nButton->gate;
  1444. gateseq = nButton->gateseq;
  1445. mode = nButton->mode;
  1446. learn = nButton->learn;
  1447. arpI = *arpIx;///-1 if no arp
  1448. polyi = *polyIndex;
  1449. notenumber = *dispNotenumber;
  1450. }
  1451. int rrr,ggg,bbb,aaa;
  1452. if (learn) {
  1453. rrr=0xff; ggg=0xff; bbb=0x00;
  1454. aaa=128;
  1455. } else { switch (mode) {
  1456. case 0:{/// Poly
  1457. rrr=0xff; ggg=0xff; bbb=0xff;
  1458. aaa= vel;
  1459. }break;
  1460. case 1:{/// Seq
  1461. rrr=0x00; ggg=0x99; bbb=0xff;
  1462. aaa= 64 + vel * 1.5f;
  1463. }break;
  1464. case 2:{/// Lock
  1465. rrr=0xff; ggg=0x00; bbb=0x00;
  1466. aaa= 64 + vel * 1.5f;
  1467. }break;
  1468. default:{/// xLock
  1469. rrr=0xff; ggg=0x80; bbb=0x00;
  1470. aaa= 64 + vel * 1.5f;
  1471. }break;
  1472. }
  1473. }
  1474. NVGcolor backgroundColor = nvgRGBA(rrr*0.6f, ggg*0.6f, bbb*0.6f, aaa);
  1475. nvgBeginPath(vg);
  1476. nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 6.0f);
  1477. nvgFillColor(vg, backgroundColor);
  1478. nvgFill(vg);
  1479. if (newkey) {
  1480. showvel = true;
  1481. framevel = 0;
  1482. // module->noteButtons[id].newkey = false;
  1483. nButton->newkey = false;
  1484. }else{
  1485. to_display = displayNoteName(key, notenumber);
  1486. }
  1487. if (learn) {
  1488. NVGcolor borderColor = nvgRGB(rrr, ggg, bbb);
  1489. nvgStrokeWidth(vg, 2.0f);
  1490. nvgStrokeColor(vg, borderColor);
  1491. nvgStroke(vg);
  1492. } else if (gate || gateseq){
  1493. if (showvel) {
  1494. if (++framevel <= 20) {
  1495. to_display = "v" + std::to_string(vel);
  1496. } else {
  1497. showvel = false;
  1498. framevel = 0;
  1499. }
  1500. }
  1501. NVGcolor borderColor = nvgRGB(rrr, ggg, bbb);
  1502. nvgStrokeWidth(vg, 2.0f);
  1503. nvgStrokeColor(vg, borderColor);
  1504. nvgStroke(vg);
  1505. }
  1506. if (arpI == id)
  1507. { ///arp led
  1508. NVGcolor ledColor = nvgRGB(0xff, 0xff, 0xff);
  1509. nvgBeginPath(vg);
  1510. nvgRect(vg, 4 , 8, 2, 2);
  1511. nvgFillColor(vg, ledColor);
  1512. nvgFill(vg);
  1513. // nButton->arp = false;
  1514. }
  1515. if (polyi == id)
  1516. { ///led
  1517. NVGcolor ledColor = nvgRGB(0xff, 0xff, 0xff);
  1518. nvgBeginPath(vg);
  1519. nvgRect(vg, 4 , 4, 2, 2);
  1520. nvgFillColor(vg, ledColor);
  1521. nvgFill(vg);
  1522. }
  1523. nvgFontSize(vg, dfontsize);
  1524. nvgFontFaceId(vg, font->handle);
  1525. //nvgTextLetterSpacing(vg, 2.0f);
  1526. NVGcolor textColor = nvgRGB(rrr, ggg, bbb);
  1527. nvgFillColor(vg, textColor);
  1528. // nvgTextLetterSpacing(vg, 3.0f);
  1529. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  1530. //Vec textPos = Vec(47 - 14 * to_display.length(), 18.0f);
  1531. //Vec textPos = Vec(5.0f, 20.0f);
  1532. nvgTextBox(vg, 0.0f, 19.f, 48.0f ,to_display.c_str(), NULL);
  1533. }
  1534. };
  1535. /////////// MIDI NOTES to Text
  1536. std::string NoteDisplay::displayNoteName(int value, bool notenumber)
  1537. {
  1538. std::string notename[12] = {"C","C#","D","Eb","E","F","F#","G","Ab","A","Bb","B"};
  1539. if (notenumber){
  1540. return "n"+ std::to_string(value);
  1541. }else{
  1542. int octaveint = (value / 12) - 2;
  1543. return notename[value % 12] + std::to_string(octaveint);
  1544. }
  1545. }
  1546. ///// MAIN DISPLAY //////
  1547. struct digiDisplay : TransparentWidget {
  1548. digiDisplay() {
  1549. font = Font::load(FONT_FILE);
  1550. }
  1551. int initpointer = 0;
  1552. bool initpointerb = false;
  1553. float mdfontSize = 10.f;
  1554. std::shared_ptr<Font> font;
  1555. std::string seqDisplayedTr;
  1556. std::string polyDisplayedTr;
  1557. const std::string stringClockRatios[13] ={"1/2", "1/4d","1/2t", "1/4", "1/8d", "1/4t","1/8","1/16d","1/8t","1/16","1/16t","1/32","1/32t"};
  1558. std::string clockDisplay = "";
  1559. std::string seqDisplay = "";
  1560. std::string arpegDisplay = "";
  1561. std::string voicesDisplay = "";
  1562. bool *BPMdecimalsP = &initpointerb;
  1563. int *clockSourceP = &initpointer;
  1564. int *displayedBPMP = &initpointer;
  1565. int *seqclockRatioP = &initpointer;
  1566. int *seqStepsP = &initpointer;
  1567. int *seqOffsetP = &initpointer;
  1568. int *arpclockRatioP = &initpointer;
  1569. int *arpegStatusP = &initpointer;
  1570. int *polyMaxVoicesP = &initpointer;
  1571. int *playingVoicesP = &initpointer;
  1572. int *seqtransP = &initpointer;
  1573. int *polytransP = &initpointer;
  1574. float thirdlineoff = 0.0f;
  1575. bool thirdline = false;
  1576. int frame = 0;
  1577. void draw(NVGcontext* vg)
  1578. {
  1579. if (frame ++ > 5 )
  1580. {
  1581. switch (*arpegStatusP){
  1582. case 0:{
  1583. arpegDisplay = "";
  1584. thirdline = false;
  1585. }break;
  1586. case 1:{
  1587. arpegDisplay = "Arpeggiator: " + stringClockRatios[*arpclockRatioP];
  1588. thirdline = true;
  1589. }break;
  1590. case 2:{
  1591. arpegDisplay = "Arpeggiator: Arcade";
  1592. thirdline = true;
  1593. }break;
  1594. case 3:{
  1595. arpegDisplay = "";
  1596. thirdline = false;
  1597. }break;
  1598. default:{
  1599. arpegDisplay = "Arpeg.connect mono out";
  1600. thirdline = true;
  1601. }break;
  1602. }
  1603. switch (*clockSourceP){
  1604. case 0:{
  1605. int BPMint = static_cast<int>(*displayedBPMP / 10.f);
  1606. int BPMdec = static_cast<int>(*displayedBPMP) % 10;
  1607. if (*displayedBPMP < 1){
  1608. clockDisplay = "EXT ...no clock...";
  1609. } else {
  1610. clockDisplay = "EXT " + std::to_string(BPMint) + "." + std::to_string(BPMdec) +" bpm "+ stringClockRatios[*seqclockRatioP];
  1611. }
  1612. }break;
  1613. case 1:{
  1614. int BPMint = static_cast<int>(*displayedBPMP / 100.f);
  1615. if (*BPMdecimalsP){
  1616. int BPMdec = static_cast<int>(*displayedBPMP) % 100;
  1617. clockDisplay = "INT " + std::to_string(BPMint) + "." + std::to_string(BPMdec) +" bpm "+ stringClockRatios[*seqclockRatioP];
  1618. } else{
  1619. clockDisplay = "INT " + std::to_string(BPMint) + " bpm "+ stringClockRatios[*seqclockRatioP];
  1620. }
  1621. }break;
  1622. case 2:{
  1623. int BPMint = static_cast<int>(*displayedBPMP / 10.f);
  1624. int BPMdec = static_cast<int>(*displayedBPMP) % 10;
  1625. if (*displayedBPMP < 1){
  1626. clockDisplay = "MIDI ...no clock...";
  1627. } else {
  1628. clockDisplay = "MIDI " + std::to_string(BPMint) + "." + std::to_string(BPMdec) +" bpm "+ stringClockRatios[*seqclockRatioP];
  1629. }
  1630. }break;
  1631. }
  1632. seqDisplay = "Steps: " + std::to_string(*seqStepsP) + " First: " + std::to_string(*seqOffsetP + 1);
  1633. voicesDisplay = std::to_string(*playingVoicesP)+"/"+std::to_string(*polyMaxVoicesP);
  1634. seqDisplayedTr = std::to_string(*seqtransP);
  1635. polyDisplayedTr = std::to_string(*polytransP);
  1636. frame = 0;
  1637. }
  1638. nvgFillColor(vg, nvgRGBA(0xFF,0xFF,0xFF,0xFF));
  1639. nvgFontSize(vg, mdfontSize);
  1640. nvgFontFaceId(vg, font->handle);
  1641. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  1642. if (thirdline) {
  1643. nvgTextBox(vg, 0.0f, 9.f + mdfontSize * 3.f, box.size.x, arpegDisplay.c_str(), NULL);
  1644. thirdlineoff = 0.0f;
  1645. } else {thirdlineoff = 6.f;}
  1646. nvgTextBox(vg, 0.0f, 3.f + mdfontSize + thirdlineoff, box.size.x, clockDisplay.c_str(), NULL);
  1647. nvgTextBox(vg, 0.0f, 6.f + mdfontSize * 2.f + thirdlineoff, box.size.x, seqDisplay.c_str(), NULL);
  1648. nvgTextBox(vg, 87.0f, -21.0f, 48.f, voicesDisplay.c_str(), NULL);//PolyVoices Display
  1649. nvgTextBox(vg, 240.0f, -21.0f,30.0f, polyDisplayedTr.c_str(), NULL);//VoicesTransp Display
  1650. nvgTextBox(vg, -7.0f, 284.0f,30.0f, seqDisplayedTr.c_str(), NULL);//SeqTransp Display
  1651. }
  1652. };
  1653. struct SelectorKnob : moDllzSelector32 {
  1654. SelectorKnob() {
  1655. minAngle = -0.88*M_PI;
  1656. maxAngle = 1.0f*M_PI;
  1657. }
  1658. // void onAction(EventAction &e) override {
  1659. // }
  1660. };
  1661. struct RatioKnob : moDllzSmSelector {
  1662. RatioKnob() {
  1663. // box.size ={36,36};
  1664. minAngle = -0.871*M_PI;
  1665. maxAngle = 1.0*M_PI;
  1666. }
  1667. };
  1668. struct SelectorOct : moDllzSelector32 {//Oct
  1669. SelectorOct() {
  1670. // box.size ={32,32};
  1671. minAngle = -0.44f*M_PI;
  1672. maxAngle = 0.44f*M_PI;
  1673. }
  1674. };
  1675. struct Knob26 : moDllzKnob26 {///Unison
  1676. Knob26() {
  1677. //snap = true;
  1678. minAngle = -0.75*M_PI;
  1679. maxAngle = 0.75*M_PI;
  1680. }
  1681. };
  1682. struct Knob26Snap : moDllzKnob26 {///swing
  1683. Knob26Snap() {
  1684. //box.size ={26,26};
  1685. snap = true;
  1686. minAngle = -0.75*M_PI;
  1687. maxAngle = 0.75*M_PI;
  1688. }
  1689. };
  1690. struct KnobSnap : moDllzKnobM {//BPM
  1691. KnobSnap() {
  1692. snap = true;
  1693. minAngle = -0.836*M_PI;
  1694. maxAngle = 1.0*M_PI;
  1695. }
  1696. };
  1697. struct TangerineLight : GrayModuleLightWidget {
  1698. TangerineLight() {
  1699. addBaseColor(nvgRGB(0xff, 0x80, 0x00));
  1700. }
  1701. };
  1702. struct WhiteYLight : GrayModuleLightWidget {
  1703. WhiteYLight() {
  1704. addBaseColor(nvgRGB(0xee, 0xee, 0x88));
  1705. }
  1706. };
  1707. /////////////////////////////////////////////// WIDGET ///////////////////////////////////////////////
  1708. struct MIDIPolyWidget : ModuleWidget
  1709. {
  1710. MIDIPolyWidget(MIDIPolyInterface *module): ModuleWidget(module){
  1711. setPanel(SVG::load(assetPlugin(plugin, "res/MIDIPoly.svg")));
  1712. //Screws
  1713. addChild(Widget::create<ScrewBlack>(Vec(0, 0)));
  1714. addChild(Widget::create<ScrewBlack>(Vec(135, 0)));
  1715. addChild(Widget::create<ScrewBlack>(Vec(435, 0)));
  1716. addChild(Widget::create<ScrewBlack>(Vec(585, 0)));
  1717. addChild(Widget::create<ScrewBlack>(Vec(0, 365)));
  1718. addChild(Widget::create<ScrewBlack>(Vec(135, 365)));
  1719. addChild(Widget::create<ScrewBlack>(Vec(435, 365)));
  1720. addChild(Widget::create<ScrewBlack>(Vec(585, 365)));
  1721. float xPos = 8.f;//61;
  1722. float yPos = 18.f;
  1723. MidiWidget *midiWidget = Widget::create<MidiWidget>(Vec(xPos,yPos));
  1724. midiWidget->box.size = Vec(128.f,36.f);
  1725. midiWidget->midiIO = &module->midiInput;
  1726. midiWidget->driverChoice->box.size.y = 12.f;
  1727. midiWidget->deviceChoice->box.size.y = 12.f;
  1728. midiWidget->channelChoice->box.size.y = 12.f;
  1729. midiWidget->driverChoice->box.pos = Vec(0.f, 0.f);
  1730. midiWidget->deviceChoice->box.pos = Vec(0.f, 12.f);
  1731. midiWidget->channelChoice->box.pos = Vec(0.f, 24.f);
  1732. midiWidget->driverSeparator->box.pos = Vec(0.f, 12.f);
  1733. midiWidget->deviceSeparator->box.pos = Vec(0.f, 24.f);
  1734. midiWidget->driverChoice->font = Font::load(mFONT_FILE);
  1735. midiWidget->deviceChoice->font = Font::load(mFONT_FILE);
  1736. midiWidget->channelChoice->font = Font::load(mFONT_FILE);
  1737. midiWidget->driverChoice->textOffset = Vec(2.f,10.f);
  1738. midiWidget->deviceChoice->textOffset = Vec(2.f,10.f);
  1739. midiWidget->channelChoice->textOffset = Vec(2.f,10.f);
  1740. midiWidget->driverChoice->color = nvgRGB(0xdd, 0xdd, 0xdd);
  1741. midiWidget->deviceChoice->color = nvgRGB(0xdd, 0xdd, 0xdd);
  1742. midiWidget->channelChoice->color = nvgRGB(0xdd, 0xdd, 0xdd);
  1743. addChild(midiWidget);
  1744. xPos = 98.f;
  1745. yPos = 42.f;
  1746. addParam(ParamWidget::create<moDllzMidiPanic>(Vec(xPos, yPos), module, MIDIPolyInterface::RESETMIDI_PARAM, 0.0f, 1.0f, 0.0f));
  1747. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos + 3.f, yPos + 4.f), module, MIDIPolyInterface::RESETMIDI_LIGHT));
  1748. yPos = 20.f;
  1749. // PolyMode
  1750. xPos = 205.f;
  1751. addParam(ParamWidget::create<moDllzSwitchT>(Vec(xPos,yPos), module, MIDIPolyInterface::POLYMODE_PARAM, 0.0f, 2.0f, 1.0f));
  1752. //Shift
  1753. xPos = 252.f;
  1754. addInput(Port::create<moDllzPort>(Vec(xPos,yPos - 0.5f), Port::INPUT, module, MIDIPolyInterface::POLYSHIFT_INPUT));
  1755. xPos = 277.f;
  1756. addParam(ParamWidget::create<TTrimSnap>(Vec(xPos,yPos + 4.f), module, MIDIPolyInterface::TRIMPOLYSHIFT_PARAM, 0.0f, 48.0f, 9.6f));
  1757. // Poly Transp ...
  1758. xPos = 333.f;
  1759. addParam(ParamWidget::create<moDllzPulseUp>(Vec(xPos,yPos), module, MIDIPolyInterface::POLYTRANUP_PARAM, 0.0f, 1.0f, 0.0f));
  1760. addParam(ParamWidget::create<moDllzPulseDwn>(Vec(xPos,yPos + 11.f), module, MIDIPolyInterface::POLYTRANDWN_PARAM, 0.0f, 1.0f, 0.0f));
  1761. addChild(ModuleLightWidget::create<TinyLight<YellowLight>>(Vec(xPos + 8.f, yPos + 25.f), module, MIDIPolyInterface::PLEARN_LIGHT));
  1762. //Unison Drift
  1763. xPos = 351.f;
  1764. addInput(Port::create<moDllzPort>(Vec(xPos, yPos+7.5f), Port::INPUT, module, MIDIPolyInterface::POLYUNISON_INPUT));
  1765. xPos = 379.f;
  1766. addParam(ParamWidget::create<moDllzKnob32>(Vec(xPos ,yPos), module, MIDIPolyInterface::POLYUNISON_PARAM, 0.0f, 2.0f, 0.0f) );
  1767. xPos = 433.f;
  1768. addParam(ParamWidget::create<Knob26>(Vec(xPos-1,yPos-2), module, MIDIPolyInterface::DRIFT_PARAM, 0.0f, 0.1f, 0.0f));
  1769. //Midi Numbers / notes
  1770. xPos = 472.f;
  1771. addParam(ParamWidget::create<moDllzSwitch>(Vec(xPos,yPos+10), module, MIDIPolyInterface::DISPLAYNOTENUM_PARAM, 0.0f, 1.0f, 0.0f));
  1772. xPos = 509;
  1773. // seq xLock
  1774. yPos = 21;
  1775. addParam(ParamWidget::create<moDllzClearButton>(Vec(xPos, yPos), module, MIDIPolyInterface::SEQPAD_PARAM, 0.0f, 1.0f, 0.0f));
  1776. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(xPos+28, yPos + 3), module, MIDIPolyInterface::PSEQ_LIGHT));
  1777. yPos = 37;
  1778. addParam(ParamWidget::create<moDllzClearButton>(Vec(xPos, yPos), module, MIDIPolyInterface::PADXLOCK_PARAM, 0.0f, 1.0f, 0.0f));
  1779. addChild(ModuleLightWidget::create<SmallLight<TangerineLight>>(Vec(xPos+28, yPos + 3), module, MIDIPolyInterface::PXLOCK_LIGHT));
  1780. xPos = 550;
  1781. // Lock Learn
  1782. yPos = 21;
  1783. addParam(ParamWidget::create<moDllzClearButton>(Vec(xPos, yPos), module, MIDIPolyInterface::LEARNPAD_PARAM, 0.0f, 1.0f, 0.0f));
  1784. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(xPos+28, yPos + 3), module, MIDIPolyInterface::PLEARN_LIGHT));
  1785. yPos = 37;
  1786. addParam(ParamWidget::create<moDllzClearButton>(Vec(xPos, yPos), module, MIDIPolyInterface::LOCKPAD_PARAM, 0.0f, 1.0f, 0.0f));
  1787. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+28, yPos + 3), module, MIDIPolyInterface::PLOCK_LIGHT));
  1788. //////// Note Buttons X 16 ///////////
  1789. yPos = 66;
  1790. xPos = 272;
  1791. for (int i = 0; i < MIDIPolyInterface::numPads; i++)
  1792. {
  1793. addParam(ParamWidget::create<moDllzMoButton>(Vec(xPos, yPos), module, MIDIPolyInterface::KEYBUTTON_PARAM + i, 0.0f, 1.0f, 0.0f));
  1794. {
  1795. NoteDisplay *notedisplay = new NoteDisplay();
  1796. notedisplay->box.pos = Vec(xPos,yPos);
  1797. notedisplay->box.size = Vec(48, 27);
  1798. notedisplay->id = i;
  1799. notedisplay->polyIndex = &(module->polyIndex);
  1800. notedisplay->arpIx = &(module->arpDisplayIx);
  1801. notedisplay->dispNotenumber = &(module->dispNotenumber);
  1802. notedisplay->nButton = &(module->noteButtons[i]);
  1803. addChild(notedisplay);
  1804. }
  1805. addParam(ParamWidget::create<moDllzSwitchLedHT>(Vec(xPos + 54 ,yPos + 11), module, MIDIPolyInterface::SEQSEND_PARAM + i, 0.0f, 2.0f, 0.0f));
  1806. addChild(ModuleLightWidget::create<TinyLight<BlueLight>>(Vec(xPos + 64.2, yPos + 4), module, MIDIPolyInterface::SEQ_LIGHT + i));
  1807. addOutput(Port::create<moDllzPortDark>(Vec(xPos + 81, yPos + 3.5f), Port::OUTPUT, module, MIDIPolyInterface::PITCH_OUTPUT + i));
  1808. addOutput(Port::create<moDllzPortDark>(Vec(xPos + 105, yPos + 3.5f), Port::OUTPUT, module, MIDIPolyInterface::VEL_OUTPUT + i));
  1809. addOutput(Port::create<moDllzPortDark>(Vec(xPos + 129, yPos + 3.5f), Port::OUTPUT, module, MIDIPolyInterface::GATE_OUTPUT + i));
  1810. yPos += 31;
  1811. if (yPos > 300){
  1812. yPos = 66;
  1813. xPos += 165;
  1814. }
  1815. }
  1816. ////SEQ////
  1817. yPos = 125;
  1818. //Seq SPEED and Ratio knobs
  1819. xPos = 79;
  1820. addParam(ParamWidget::create<KnobSnap>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQSPEED_PARAM, 20.0f, 240.0f, 120.0f));
  1821. xPos = 146;
  1822. addParam(ParamWidget::create<RatioKnob>(Vec(xPos,yPos+2), module, MIDIPolyInterface::SEQCLOCKRATIO_PARAM, 0.0f, 12.0f, 3.0f));
  1823. yPos = 167.5f;
  1824. //Seq SPEED and Ratio inputs
  1825. xPos = 71.5f;
  1826. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, MIDIPolyInterface::SEQSPEED_INPUT));
  1827. xPos = 134.5f;
  1828. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, MIDIPolyInterface::SEQRATIO_INPUT));
  1829. xPos = 89;
  1830. // STEP FIRST KNOBS
  1831. yPos = 207;
  1832. addParam(ParamWidget::create<SelectorKnob>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQSTEPS_PARAM, 1.0f, 16.0f, 16.0f));
  1833. yPos = 266;
  1834. addParam(ParamWidget::create<SelectorKnob>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQFIRST_PARAM, 0.0f, 15.0f, 0.0f));
  1835. xPos = 67.5f;
  1836. // STEP FIRST > > > > > > > > INPUTS
  1837. yPos = 226.5f;
  1838. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, MIDIPolyInterface::SEQSTEPS_INPUT));
  1839. yPos = 285.5f;
  1840. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, MIDIPolyInterface::SEQFIRST_INPUT));
  1841. yPos = 262;
  1842. // Swing..... swing Triplets
  1843. xPos = 134;
  1844. addParam(ParamWidget::create<Knob26Snap>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQARPSWING_PARAM, -20.0, 20.0f, 0.0f));
  1845. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos+31,yPos+9), module, MIDIPolyInterface::SEQSWING_PARAM, 0.0f, 1.0f, 0.0f));
  1846. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos+48,yPos+9), module, MIDIPolyInterface::ARPSWING_PARAM, 0.0f, 1.0f, 0.0f));
  1847. addParam(ParamWidget::create<moDllzSwitchLedH>(Vec(xPos+20,yPos+37), module, MIDIPolyInterface::SWINGTRI_PARAM, 0.0f, 1.0f, 0.0f));
  1848. ///SEQ OCT
  1849. yPos = 210;
  1850. xPos = 148;
  1851. addParam(ParamWidget::create<moDllzSmSelector>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQOCT_PARAM, 0.0f, 6.0f, 3.0f));
  1852. ///ARPEG OCT
  1853. xPos = 213;
  1854. addParam(ParamWidget::create<moDllzSmSelector>(Vec(xPos,yPos), module, MIDIPolyInterface::ARPEGOCT_PARAM, 0.0f, 6.0f, 3.0f));
  1855. ///// oct lights
  1856. yPos=248;
  1857. xPos=145;
  1858. for (int i = 0 ; i < 5 ; i++){
  1859. addChild(ModuleLightWidget::create<TinyLight<BlueLight>>(Vec(xPos + (10 * i), yPos), module, MIDIPolyInterface::SEQOCT_LIGHT + i));
  1860. }
  1861. xPos=211;
  1862. for (int i = 0 ; i < 5 ; i++){
  1863. addChild(ModuleLightWidget::create<TinyLight<WhiteYLight>>(Vec(xPos + (10 * i), yPos), module, MIDIPolyInterface::ARPOCT_LIGHT + i));
  1864. }
  1865. yPos = 197;
  1866. xPos = 156;
  1867. addParam(ParamWidget::create<moDllzSwitchH>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQOCTALT_PARAM, 0.0f, 1.0f, 0.0f));
  1868. xPos = 222;
  1869. addParam(ParamWidget::create<moDllzSwitchH>(Vec(xPos,yPos), module, MIDIPolyInterface::ARPEGOCTALT_PARAM, 0.0f, 1.0f, 1.0f));
  1870. //ARPEGG ............. RATIO . . . . . . .
  1871. xPos = 215;
  1872. yPos = 127;
  1873. addParam(ParamWidget::create<RatioKnob>(Vec(xPos,yPos), module, MIDIPolyInterface::ARPEGRATIO_PARAM, 0.0f, 12.0f, 6.0f));
  1874. xPos = 203.5f;
  1875. yPos = 167.5f;
  1876. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, MIDIPolyInterface::ARPEGRATIO_INPUT));
  1877. //// ARP ARC INPUT
  1878. xPos = 217.5f;
  1879. yPos = 288.5f;
  1880. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, MIDIPolyInterface::ARPMODE_INPUT));
  1881. xPos = 240;
  1882. yPos = 259;
  1883. addParam(ParamWidget::create<moDllzRoundButton>(Vec(xPos, yPos), module, MIDIPolyInterface::ARCADEON_PARAM, 0.0f, 1.0f, 0.0f));
  1884. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+3.75f, yPos + 3.75f), module, MIDIPolyInterface::ARCADEON_LIGHT));
  1885. yPos += 18;
  1886. addParam(ParamWidget::create<moDllzRoundButton>(Vec(xPos, yPos), module, MIDIPolyInterface::ARPEGON_PARAM, 0.0f, 1.0f, 0.0f));
  1887. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(xPos+3.75f, yPos + 3.75f), module, MIDIPolyInterface::ARPEGON_LIGHT));
  1888. ////// LEFT COL
  1889. /// Clock IN
  1890. xPos= 9.5f;
  1891. yPos = 58.5f;
  1892. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, MIDIPolyInterface::CLOCK_INPUT));
  1893. xPos = 18;
  1894. yPos = 84;
  1895. addParam(ParamWidget::create<moDllzSwitchTH>(Vec(xPos, yPos), module, MIDIPolyInterface:: SEQCLOCKSRC_PARAM, 0.0f, 2.0f, 1.0f));
  1896. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(xPos+31.f, yPos+2.f), module, MIDIPolyInterface::MIDIBEAT_LIGHT));
  1897. // SEQ START gate
  1898. xPos = 21.5;
  1899. yPos = 118;
  1900. addParam(ParamWidget::create<moDllzSwitchH>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQGATERUN_PARAM, 0.0f, 1.0f, 0.0f));
  1901. xPos = 13;
  1902. yPos += 60;
  1903. //Link Run Reset
  1904. addParam(ParamWidget::create<moDllzSwitchLedH>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQRUNRESET_PARAM, 0.0f, 1.0f, 0.0f));
  1905. ///seq Run Reset Inputs
  1906. xPos = 9.5f;
  1907. yPos = 134.5;
  1908. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, MIDIPolyInterface::SEQRUN_INPUT));
  1909. yPos += 60;
  1910. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, MIDIPolyInterface::SEQRESET_INPUT));
  1911. ///seq Run Reset BUTTONS
  1912. xPos += 30;
  1913. yPos = 140;
  1914. addParam(ParamWidget::create<moDllzRoundButton>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQRUN_PARAM, 0.0f, 1.0f, 0.0f));
  1915. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(xPos+3.75f,yPos+3.75f), module, MIDIPolyInterface::SEQRUNNING_LIGHT));
  1916. yPos += 60;
  1917. addParam(ParamWidget::create<moDllzRoundButton>(Vec(xPos,yPos), module, MIDIPolyInterface::SEQRESET_PARAM, 0.0f, 1.0f, 0.0f));
  1918. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(xPos+3.75f,yPos+3.75f), module, MIDIPolyInterface::SEQRESET_LIGHT));
  1919. xPos = 9.5f;
  1920. // START STOP CLOCK OUTS
  1921. yPos = 241.5f;
  1922. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQSTART_OUTPUT));
  1923. addOutput(Port::create<moDllzPort>(Vec(xPos+23, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQSTOP_OUTPUT));
  1924. yPos += 40;
  1925. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQSTARTSTOP_OUTPUT));
  1926. addOutput(Port::create<moDllzPort>(Vec(xPos+23, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQCLOCK_OUTPUT));
  1927. // Transp ...
  1928. yPos = 328;
  1929. xPos = 8.5f;
  1930. addInput(Port::create<moDllzPort>(Vec(xPos, yPos-4.5f), Port::INPUT, module, MIDIPolyInterface::SEQSHIFT_INPUT));
  1931. xPos = 33;
  1932. addParam(ParamWidget::create<TTrimSnap>(Vec(xPos,yPos), module, MIDIPolyInterface::TRIMSEQSHIFT_PARAM, 0.0f, 48.0f, 9.6f));
  1933. xPos = 87;
  1934. addParam(ParamWidget::create<moDllzPulseUp>(Vec(xPos,yPos-3), module, MIDIPolyInterface::SEQTRANUP_PARAM, 0.0f, 1.0f, 0.0f));
  1935. addParam(ParamWidget::create<moDllzPulseDwn>(Vec(xPos,yPos+8), module, MIDIPolyInterface::SEQTRANDWN_PARAM, 0.0f, 1.0f, 0.0f));
  1936. yPos = 327.5;
  1937. // SEQ OUTS
  1938. xPos = 99.5f;
  1939. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQPITCH_OUTPUT));
  1940. xPos += 24;
  1941. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQVEL_OUTPUT));
  1942. xPos += 24;
  1943. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::SEQGATE_OUTPUT));
  1944. xPos += 27.5f;
  1945. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos,yPos+8.5f), module, MIDIPolyInterface::SEQRETRIG_PARAM, 0.0f, 1.0f, 1.0f));
  1946. //// MIDI OUTS
  1947. xPos = 202;
  1948. addParam(ParamWidget::create<moDllzSwitchT>(Vec(xPos,yPos-2.5f), module, MIDIPolyInterface::MONOPITCH_PARAM, 0.0f, 2.0f, 1.0f));
  1949. xPos = 234.5f;
  1950. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::MONOPITCH_OUTPUT));
  1951. xPos += 24;
  1952. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::MONOVEL_OUTPUT));
  1953. xPos += 24;
  1954. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::MONOGATE_OUTPUT));
  1955. xPos += 27.5f;
  1956. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos,yPos+8.5f), module, MIDIPolyInterface::MONORETRIG_PARAM, 0.0f, 1.0f, 0.0f));
  1957. xPos += 14.5;
  1958. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::PBEND_OUTPUT));
  1959. xPos += 24;
  1960. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::MOD_OUTPUT));
  1961. xPos += 24;
  1962. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::PRESSURE_OUTPUT));
  1963. xPos += 24;
  1964. addOutput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::OUTPUT, module, MIDIPolyInterface::SUSTAIN_OUTPUT));
  1965. xPos += 27.5f;
  1966. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos,yPos+8.5f), module, MIDIPolyInterface::HOLD_PARAM, 0.0f, 1.0f, 1.0f));
  1967. ///LOCKED OUTS
  1968. xPos= 451;
  1969. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos,yPos+8.5f), module, MIDIPolyInterface::PLAYXLOCKED_PARAM, 0.0f, 1.0f, 1.0f));
  1970. xPos += 18;
  1971. addParam(ParamWidget::create<moDllzSwitchT>(Vec(xPos,yPos-2.5f), module, MIDIPolyInterface::LOCKEDPITCH_PARAM, 0.0f, 2.0f, 0.0f));
  1972. xPos = 500.5f;
  1973. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::LOCKEDPITCH_OUTPUT));
  1974. xPos += 24;
  1975. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::LOCKEDVEL_OUTPUT));
  1976. xPos += 24;
  1977. addOutput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::OUTPUT, module, MIDIPolyInterface::LOCKEDGATE_OUTPUT));
  1978. xPos += 27.5f;
  1979. addParam(ParamWidget::create<moDllzSwitchLed>(Vec(xPos,yPos+10.5f), module, MIDIPolyInterface::LOCKEDRETRIG_PARAM, 0.0f, 1.0f, 0.0f));
  1980. ///mute buttons
  1981. yPos=318;
  1982. xPos=102;
  1983. addParam(ParamWidget::create<moDllzMuteG>(Vec(xPos,yPos), module, MIDIPolyInterface::MUTESEQ_PARAM, 0.0f, 1.0f, 0.0f));
  1984. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+57.5f, yPos+3), module, MIDIPolyInterface::MUTESEQ_LIGHT));
  1985. xPos=237;
  1986. addParam(ParamWidget::create<moDllzMuteG>(Vec(xPos,yPos), module, MIDIPolyInterface::MUTEMONO_PARAM, 0.0f, 1.0f, 0.0f));
  1987. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+57.5f, yPos+3), module, MIDIPolyInterface::MUTEMONO_LIGHT));
  1988. xPos=503;
  1989. addParam(ParamWidget::create<moDllzMuteG>(Vec(xPos,yPos), module, MIDIPolyInterface::MUTELOCKED_PARAM, 0.0f, 1.0f, 0.0f));
  1990. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(xPos+57.5f, yPos+3), module, MIDIPolyInterface::MUTELOCKED_LIGHT));
  1991. yPos=56;
  1992. xPos=401;
  1993. addParam(ParamWidget::create<moDllzMuteGP>(Vec(xPos,yPos), module, MIDIPolyInterface::MUTEPOLYA_PARAM, 0.0f, 1.0f, 0.0f));
  1994. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos+20, yPos+4), module, MIDIPolyInterface::MUTEPOLY_LIGHT));
  1995. xPos=566;
  1996. addParam(ParamWidget::create<moDllzMuteGP>(Vec(xPos,yPos), module, MIDIPolyInterface::MUTEPOLYB_PARAM, 0.0f, 1.0f, 0.0f));
  1997. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos+20, yPos+4), module, MIDIPolyInterface::MUTEPOLY_LIGHT));
  1998. {
  1999. digiDisplay *mainDisplay = new digiDisplay();
  2000. mainDisplay->box.pos = Vec(63, 57);
  2001. mainDisplay->box.size = {198, 44};
  2002. mainDisplay->clockSourceP = &(module->clockSource);
  2003. mainDisplay->BPMdecimalsP = &(module->BPMdecimals);
  2004. mainDisplay->displayedBPMP = &(module->displayedBPM);
  2005. mainDisplay->seqclockRatioP = &(module->seqclockRatio);
  2006. mainDisplay->seqStepsP = &(module->seqSteps);
  2007. mainDisplay->seqOffsetP = &(module->seqOffset);
  2008. mainDisplay->polyMaxVoicesP = &(module->polyMaxVoices);
  2009. mainDisplay->playingVoicesP = &(module->playingVoices);
  2010. mainDisplay->arpegStatusP = &(module->arpegStatus);
  2011. mainDisplay->arpclockRatioP = &(module->arpclockRatio);
  2012. mainDisplay->seqtransP = &(module->seqTransParam);
  2013. mainDisplay->polytransP = &(module->polyTransParam);
  2014. addChild(mainDisplay);
  2015. }
  2016. }
  2017. };
  2018. //void MIDIPolyWidget::step() {
  2019. // ModuleWidget::step();
  2020. //}
  2021. } // namespace rack_plugin_moDllz
  2022. using namespace rack_plugin_moDllz;
  2023. RACK_PLUGIN_MODEL_INIT(moDllz, MIDIPoly) {
  2024. Model *modelMIDIPoly = Model::create<MIDIPolyInterface, MIDIPolyWidget>("moDllz", "MIDIPoly16", "MIDI Poly 16", MIDI_TAG, ARPEGGIATOR_TAG, SEQUENCER_TAG, CONTROLLER_TAG, MULTIPLE_TAG, EXTERNAL_TAG);
  2025. return modelMIDIPoly;
  2026. }