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.

1050 lines
25KB

  1. #include "AH.hpp"
  2. #include "Core.hpp"
  3. #include "UI.hpp"
  4. #include "componentlibrary.hpp"
  5. #include "dsp/digital.hpp"
  6. #include <iostream>
  7. namespace rack_plugin_AmalgamatedHarmonics {
  8. struct Pattern {
  9. int length = 0;
  10. int trans = 0;
  11. int scale = 0;
  12. int count = 0;
  13. int MAJOR[7] = {0,2,4,5,7,9,11};
  14. int MINOR[7] = {0,2,3,5,7,8,10};
  15. virtual std::string getName() = 0;
  16. virtual void initialise(int l, int sc, int tr, bool freeRun) {
  17. length = l;
  18. trans = tr;
  19. scale = sc;
  20. count = 0;
  21. };
  22. virtual void advance() {
  23. count++;
  24. };
  25. virtual int getOffset() = 0;
  26. virtual bool isPatternFinished() = 0;
  27. int getMajor(int count) {
  28. int i = abs(count);
  29. int sign = (count < 0) ? -1 : (count > 0);
  30. return sign * ((i / 7) * 12 + MAJOR[i % 7]);
  31. }
  32. int getMinor(int count) {
  33. int i = abs(count);
  34. int sign = (count < 0) ? -1 : (count > 0);
  35. return sign * ((i / 7) * 12 + MINOR[i % 7]);
  36. }
  37. };
  38. struct UpPattern : Pattern {
  39. std::string getName() override {
  40. return "Up";
  41. };
  42. void initialise(int l, int sc, int tr, bool fr) override {
  43. Pattern::initialise(l,sc,tr,fr);
  44. }
  45. int getOffset() override {
  46. switch(scale) {
  47. case 0: return count * trans; break;
  48. case 1: return getMajor(count * trans); break;
  49. case 2: return getMinor(count * trans); break;
  50. default:
  51. return count * trans; break;
  52. }
  53. }
  54. bool isPatternFinished() override {
  55. return(count == length);
  56. }
  57. };
  58. struct DownPattern : Pattern {
  59. int currSt = 0;
  60. std::string getName() override {
  61. return "Down";
  62. };
  63. void initialise(int l, int sc, int tr, bool fr) override {
  64. Pattern::initialise(l,sc,tr,fr);
  65. currSt = length - 1;
  66. }
  67. void advance() override {
  68. Pattern::advance();
  69. currSt--;
  70. }
  71. int getOffset() override {
  72. switch(scale) {
  73. case 0: return currSt * trans; break;
  74. case 1: return getMajor(currSt * trans); break;
  75. case 2: return getMinor(currSt * trans); break;
  76. default:
  77. return currSt * trans; break;
  78. }
  79. }
  80. bool isPatternFinished() override {
  81. return (currSt < 0);
  82. }
  83. };
  84. struct UpDownPattern : Pattern {
  85. int mag = 0;
  86. int end = 0;
  87. std::string getName() override {
  88. return "UpDown";
  89. };
  90. void initialise(int l, int sc, int tr, bool fr) override {
  91. Pattern::initialise(l,sc,tr,fr);
  92. mag = l - 1;
  93. if (fr) {
  94. end = 2 * l - 2;
  95. } else {
  96. end = 2 * l - 1;
  97. }
  98. if (end < 1) {
  99. end = 1;
  100. }
  101. }
  102. int getOffset() override {
  103. int note = (mag - abs(mag - count));
  104. switch(scale) {
  105. case 0: return note * trans; break;
  106. case 1: return getMajor(note * trans); break;
  107. case 2: return getMinor(note * trans); break;
  108. default:
  109. return note * trans; break;
  110. }
  111. }
  112. bool isPatternFinished() override {
  113. return(count == end);
  114. }
  115. };
  116. struct DownUpPattern : Pattern {
  117. int mag = 0;
  118. int end = 0;
  119. std::string getName() override {
  120. return "DownUp";
  121. };
  122. void initialise(int l, int sc, int tr, bool fr) override {
  123. Pattern::initialise(l,sc,tr,fr);
  124. mag = l - 1;
  125. if (fr) {
  126. end = 2 * l - 2;
  127. } else {
  128. end = 2 * l - 1;
  129. }
  130. if (end < 1) {
  131. end = 1;
  132. }
  133. }
  134. int getOffset() override {
  135. int note = -(mag - abs(mag - count));
  136. switch(scale) {
  137. case 0: return note * trans; break;
  138. case 1: return getMajor(note * trans); break;
  139. case 2: return getMinor(note * trans); break;
  140. default:
  141. return note * trans; break;
  142. }
  143. }
  144. bool isPatternFinished() override {
  145. return(count == end);
  146. }
  147. };
  148. struct NotePattern : Pattern {
  149. std::vector<int> notes;
  150. void initialise(int l, int sc, int tr, bool fr) override {
  151. Pattern::initialise(l,sc,tr,fr);
  152. }
  153. int getOffset() override {
  154. return getNote(count);
  155. }
  156. bool isPatternFinished() override {
  157. return (count == (int)notes.size());
  158. }
  159. int getNote(int i) {
  160. return notes[i];
  161. }
  162. };
  163. struct RezPattern : NotePattern {
  164. std::string getName() override {
  165. return "Rez";
  166. };
  167. RezPattern() {
  168. notes.clear();
  169. notes.push_back(0);
  170. notes.push_back(12);
  171. notes.push_back(0);
  172. notes.push_back(0);
  173. notes.push_back(8);
  174. notes.push_back(0);
  175. notes.push_back(0);
  176. notes.push_back(3);
  177. notes.push_back(0);
  178. notes.push_back(0);
  179. notes.push_back(3);
  180. notes.push_back(0);
  181. notes.push_back(3);
  182. notes.push_back(0);
  183. notes.push_back(8);
  184. notes.push_back(0);
  185. }
  186. };
  187. struct OnTheRunPattern : NotePattern {
  188. std::string getName() override {
  189. return "On The Run";
  190. };
  191. OnTheRunPattern() {
  192. notes.clear();
  193. notes.push_back(0);
  194. notes.push_back(4);
  195. notes.push_back(6);
  196. notes.push_back(4);
  197. notes.push_back(9);
  198. notes.push_back(11);
  199. notes.push_back(13);
  200. notes.push_back(11);
  201. }
  202. };
  203. struct Arpeggio {
  204. virtual std::string getName() = 0;
  205. virtual void initialise(int nPitches, bool fr) = 0;
  206. virtual void advance() = 0;
  207. virtual int getPitch() = 0;
  208. virtual bool isArpeggioFinished() = 0;
  209. };
  210. struct RightArp : Arpeggio {
  211. int index = 0;
  212. int nPitches = 0;
  213. std::string getName() override {
  214. return "Right";
  215. };
  216. void initialise(int np, bool fr) override {
  217. index = 0;
  218. nPitches = np;
  219. }
  220. void advance() override {
  221. index++;
  222. }
  223. int getPitch() override {
  224. return index;
  225. }
  226. bool isArpeggioFinished() override {
  227. return (index == nPitches);
  228. }
  229. };
  230. struct LeftArp : Arpeggio {
  231. int index = 0;
  232. int nPitches = 0;
  233. std::string getName() override {
  234. return "Left";
  235. };
  236. void initialise(int np, bool fr) override {
  237. nPitches = np;
  238. index = nPitches - 1;
  239. }
  240. void advance() override {
  241. index--;
  242. }
  243. int getPitch() override {
  244. return index;
  245. }
  246. bool isArpeggioFinished() override {
  247. return (index < 0);
  248. }
  249. };
  250. struct RightLeftArp : Arpeggio {
  251. int currSt = 0;
  252. int mag = 0;
  253. int end = 0;
  254. std::string getName() override {
  255. return "RightLeft";
  256. };
  257. void initialise(int l, bool fr) override {
  258. mag = l - 1;
  259. if (fr) {
  260. end = 2 * l - 2;
  261. } else {
  262. end = 2 * l - 1;
  263. }
  264. if (end < 1) {
  265. end = 1;
  266. }
  267. currSt = 0;
  268. }
  269. void advance() override {
  270. currSt++;
  271. }
  272. int getPitch() override {
  273. return mag - abs(mag - currSt);
  274. }
  275. bool isArpeggioFinished() override {
  276. return(currSt == end);
  277. }
  278. };
  279. struct LeftRightArp : Arpeggio {
  280. int currSt = 0;
  281. int mag = 0;
  282. int end = 0;
  283. std::string getName() override {
  284. return "LeftRight";
  285. };
  286. void initialise(int l, bool fr) override {
  287. mag = l - 1;
  288. if (fr) {
  289. end = 2 * l - 2;
  290. } else {
  291. end = 2 * l - 1;
  292. }
  293. if (end < 1) {
  294. end = 1;
  295. }
  296. currSt = 0;
  297. }
  298. void advance() override {
  299. currSt++;
  300. }
  301. int getPitch() override {
  302. return abs(mag - currSt);
  303. }
  304. bool isArpeggioFinished() override {
  305. return(currSt == end);
  306. }
  307. };
  308. struct Arpeggiator2 : AHModule {
  309. const static int MAX_STEPS = 16;
  310. const static int MAX_DIST = 12; //Octave
  311. const static int NUM_PITCHES = 6;
  312. enum ParamIds {
  313. LOCK_PARAM,
  314. TRIGGER_PARAM,
  315. PATT_PARAM,
  316. ARP_PARAM,
  317. LENGTH_PARAM,
  318. TRANS_PARAM,
  319. SCALE_PARAM,
  320. NUM_PARAMS
  321. };
  322. enum InputIds {
  323. CLOCK_INPUT,
  324. TRIG_INPUT,
  325. ENUMS(PITCH_INPUT,6),
  326. PATT_INPUT,
  327. ARP_INPUT,
  328. LENGTH_INPUT,
  329. TRANS_INPUT,
  330. NUM_INPUTS
  331. };
  332. enum OutputIds {
  333. OUT_OUTPUT,
  334. GATE_OUTPUT,
  335. EOC_OUTPUT,
  336. EOS_OUTPUT,
  337. NUM_OUTPUTS
  338. };
  339. enum LightIds {
  340. LOCK_LIGHT,
  341. NUM_LIGHTS
  342. };
  343. Arpeggiator2() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  344. reset();
  345. id = rand();
  346. debugFlag = false;
  347. }
  348. void step() override;
  349. void reset() override {
  350. newSequence = 0;
  351. newCycle = 0;
  352. isRunning = false;
  353. freeRunning = false;
  354. }
  355. json_t *toJson() override {
  356. json_t *rootJ = json_object();
  357. // gateMode
  358. json_t *gateModeJ = json_integer((int) gateMode);
  359. json_object_set_new(rootJ, "gateMode", gateModeJ);
  360. return rootJ;
  361. }
  362. void fromJson(json_t *rootJ) override {
  363. // gateMode
  364. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  365. if (gateModeJ) {
  366. gateMode = (GateMode)json_integer_value(gateModeJ);
  367. }
  368. }
  369. enum GateMode {
  370. TRIGGER,
  371. RETRIGGER,
  372. CONTINUOUS,
  373. };
  374. GateMode gateMode = TRIGGER;
  375. SchmittTrigger clockTrigger; // for clock
  376. SchmittTrigger trigTrigger; // for step trigger
  377. SchmittTrigger lockTrigger;
  378. SchmittTrigger buttonTrigger;
  379. PulseGenerator triggerPulse;
  380. PulseGenerator gatePulse;
  381. PulseGenerator eosPulse;
  382. PulseGenerator eocPulse;
  383. bool locked = false;
  384. float outVolts = 0;
  385. bool isRunning = false;
  386. bool freeRunning = false;
  387. int error = 0;
  388. int newSequence = 0;
  389. int newCycle = 0;
  390. const static int LAUNCH = 1;
  391. const static int COUNTDOWN = 3;
  392. int inputPat = 0;
  393. int inputArp = 0;
  394. int inputLen = 0;
  395. int inputTrans = 0;
  396. int inputScale = 0;
  397. int poll = 5000;
  398. int pattern = 0;
  399. int arp = 0;
  400. int length = 0;
  401. float trans = 0;
  402. float scale = 0;
  403. float semiTone = 1.0 / 12.0;
  404. UpPattern patt_up;
  405. DownPattern patt_down;
  406. UpDownPattern patt_updown;
  407. DownUpPattern patt_downup;
  408. RezPattern patt_rez;
  409. OnTheRunPattern patt_ontherun;
  410. UpPattern ui_patt_up;
  411. DownPattern ui_patt_down;
  412. UpDownPattern ui_patt_updown;
  413. DownUpPattern ui_patt_downup;
  414. RezPattern ui_patt_rez;
  415. OnTheRunPattern ui_patt_ontherun;
  416. RightArp arp_right;
  417. LeftArp arp_left;
  418. RightLeftArp arp_rightleft;
  419. LeftRightArp arp_leftright;
  420. RightArp ui_arp_right;
  421. LeftArp ui_arp_left;
  422. RightLeftArp ui_arp_rightleft;
  423. LeftRightArp ui_arp_leftright;
  424. Pattern *currPatt = &patt_up;
  425. Arpeggio *currArp = &arp_right;
  426. Pattern *uiPatt = &patt_up;
  427. Arpeggio *uiArp = &arp_right;
  428. float pitches[6];
  429. int nPitches = 0;
  430. int id = 0;
  431. };
  432. void Arpeggiator2::step() {
  433. AHModule::step();
  434. // Wait a few steps for the inputs to flow through Rack
  435. if (stepX < 10) {
  436. return;
  437. }
  438. // Get inputs from Rack
  439. float clockInput = inputs[CLOCK_INPUT].value;
  440. bool clockActive = inputs[CLOCK_INPUT].active;
  441. float trigInput = inputs[TRIG_INPUT].value;
  442. bool trigActive = inputs[TRIG_INPUT].active;
  443. float lockInput = params[LOCK_PARAM].value;
  444. float buttonInput = params[TRIGGER_PARAM].value;
  445. // Read param section
  446. if (inputs[PATT_INPUT].active) {
  447. inputPat = inputs[PATT_INPUT].value;
  448. } else {
  449. inputPat = params[PATT_PARAM].value;
  450. }
  451. if (inputs[ARP_INPUT].active) {
  452. inputArp = inputs[ARP_INPUT].value;
  453. } else {
  454. inputArp = params[ARP_PARAM].value;
  455. }
  456. if (inputs[LENGTH_INPUT].active) {
  457. inputLen = inputs[LENGTH_INPUT].value;
  458. } else {
  459. inputLen = params[LENGTH_PARAM].value;
  460. }
  461. if (inputs[TRANS_INPUT].active) {
  462. inputTrans = inputs[TRANS_INPUT].value;
  463. } else {
  464. inputTrans = params[TRANS_PARAM].value;
  465. }
  466. inputScale = params[SCALE_PARAM].value;
  467. // Process inputs
  468. bool clockStatus = clockTrigger.process(clockInput);
  469. bool triggerStatus = trigTrigger.process(trigInput);
  470. bool lockStatus = lockTrigger.process(lockInput);
  471. bool buttonStatus = buttonTrigger.process(buttonInput);
  472. // Read input pitches and assign to pitch array
  473. int nValidPitches = 0;
  474. float inputPitches[NUM_PITCHES];
  475. for (int p = 0; p < NUM_PITCHES; p++) {
  476. int index = PITCH_INPUT + p;
  477. if (inputs[index].active) {
  478. inputPitches[nValidPitches] = inputs[index].value;
  479. nValidPitches++;
  480. } else {
  481. inputPitches[nValidPitches] = 0.0;
  482. }
  483. }
  484. // if (debugEnabled()) {
  485. // for (int p = 0; p < nValidPitches; p++) {
  486. // std::cout << inputPitches[p] << std::endl;
  487. // }
  488. // }
  489. // Always play something
  490. if (nValidPitches == 0) {
  491. if (debugEnabled()) { std::cout << stepX << " " << id << " No inputs, assume single 0V pitch" << std::endl; }
  492. nValidPitches = 1;
  493. }
  494. // Need to understand why this happens
  495. if (inputLen == 0) {
  496. if (debugEnabled()) { std::cout << stepX << " " << id << " InputLen == 0, aborting" << std::endl; }
  497. return; // No inputs, no music
  498. }
  499. // If there is no clock input, then force that we are not running
  500. if (!clockActive) {
  501. isRunning = false;
  502. }
  503. // Has the trigger input been fired
  504. if (triggerStatus) {
  505. triggerPulse.trigger(5e-5);
  506. if (debugEnabled()) { std::cout << stepX << " " << id << " Triggered" << std::endl; }
  507. }
  508. // Update the trigger pulse and determine if it is still high
  509. bool triggerHigh = triggerPulse.process(delta);
  510. if (debugEnabled()) {
  511. if (triggerHigh) {
  512. std::cout << stepX << " " << id << " Trigger is high" << std::endl;
  513. }
  514. }
  515. // Update lock
  516. if (lockStatus) {
  517. if (debugEnabled()) { std::cout << "Toggling lock: " << locked << std::endl; }
  518. locked = !locked;
  519. }
  520. if (newSequence) {
  521. newSequence--;
  522. if (debugEnabled()) { std::cout << stepX << " " << id << " Countdown newSequence: " << newSequence << std::endl; }
  523. }
  524. if (newCycle) {
  525. newCycle--;
  526. if (debugEnabled()) { std::cout << stepX << " " << id << " Countdown newCycle: " << newCycle << std::endl; }
  527. }
  528. // OK so the problem here might be that the clock gate is still high right after the trigger gate fired on the previous step
  529. // So we need to wait a while for the clock gate to go low
  530. // Has the clock input been fired
  531. bool isClocked = false;
  532. if (clockStatus && !triggerHigh) {
  533. if (debugEnabled()) { std::cout << stepX << " " << id << " Clocked" << std::endl; }
  534. isClocked = true;
  535. }
  536. // Has the trigger input been fired, either on the input or button
  537. if (triggerStatus || buttonStatus) {
  538. if (debugEnabled()) { std::cout << stepX << " " << id << " Start countdown " << clockActive <<std::endl; }
  539. if (clockActive) {
  540. newSequence = COUNTDOWN;
  541. newCycle = COUNTDOWN;
  542. }
  543. }
  544. // So this is where the free-running could be triggered
  545. if (isClocked && !isRunning) { // Must have a clock and not be already running
  546. if (!trigActive) { // If nothing plugged into the TRIG input
  547. if (debugEnabled()) { std::cout << stepX << " " << id << " Free running sequence; starting" << std::endl; }
  548. freeRunning = true; // We're free-running
  549. newSequence = COUNTDOWN;
  550. newCycle = LAUNCH;
  551. } else {
  552. if (debugEnabled()) { std::cout << stepX << " " << id << " Triggered sequence; wait for trigger" << std::endl; }
  553. freeRunning = false;
  554. }
  555. }
  556. // Detect cable being plugged in when free-running, stop free-running
  557. if (freeRunning && trigActive && isRunning) {
  558. if (debugEnabled()) { std::cout << stepX << " " << id << " TRIG input re-connected" << std::endl; }
  559. freeRunning = false;
  560. }
  561. // Reached the end of the cycle
  562. if (isRunning && isClocked && currArp->isArpeggioFinished()) {
  563. // Completed 1 step
  564. currPatt->advance();
  565. // Pulse the EOC gate
  566. eocPulse.trigger(Core::TRIGGER);
  567. if (debugEnabled()) { std::cout << stepX << " " << id << " Finished Cycle" << std::endl; }
  568. // Reached the end of the sequence
  569. if (isRunning && currPatt->isPatternFinished()) {
  570. // Free running, so start new seqeuence & cycle
  571. if (freeRunning) {
  572. newCycle = COUNTDOWN;
  573. newSequence = COUNTDOWN;
  574. }
  575. isRunning = false;
  576. // Pulse the EOS gate
  577. eosPulse.trigger(Core::TRIGGER);
  578. if (debugEnabled()) { std::cout << stepX << " " << id << " Finished Sequence, flag: " << isRunning << std::endl; }
  579. } else {
  580. newCycle = LAUNCH;
  581. if (debugEnabled()) { std::cout << stepX << " " << id << " Flagging new cycle" << std::endl; }
  582. }
  583. }
  584. // If we have been triggered, start a new sequence
  585. if (newSequence == LAUNCH) {
  586. // At the first step of the sequence
  587. // So this is where we tweak the sequence parameters
  588. if (!locked) {
  589. pattern = inputPat;
  590. length = inputLen;
  591. trans = inputTrans;
  592. scale = inputScale;
  593. switch(pattern) {
  594. case 0: currPatt = &patt_up; break;
  595. case 1: currPatt = &patt_down; break;
  596. case 2: currPatt = &patt_updown; break;
  597. case 3: currPatt = &patt_downup; break;
  598. case 4: currPatt = &patt_rez; break;
  599. case 5: currPatt = &patt_ontherun; break;
  600. default: currPatt = &patt_up; break;
  601. };
  602. }
  603. if (debugEnabled()) { std::cout << stepX << " " << id << " Initiatise new Sequence: Pattern: " << currPatt->getName() <<
  604. " Length: " << inputLen <<
  605. " Locked: " << locked << std::endl; }
  606. currPatt->initialise(length, scale, trans, freeRunning);
  607. // We're running now
  608. isRunning = true;
  609. }
  610. // Starting a new cycle
  611. if (newCycle == LAUNCH) {
  612. /// Reset the cycle counters
  613. if (!locked) {
  614. arp = inputArp;
  615. switch(arp) {
  616. case 0: currArp = &arp_right; break;
  617. case 1: currArp = &arp_left; break;
  618. case 2: currArp = &arp_rightleft; break;
  619. case 3: currArp = &arp_leftright; break;
  620. default: currArp = &arp_right; break;
  621. };
  622. // Copy pitches
  623. for (int p = 0; p < nValidPitches; p++) {
  624. pitches[p] = inputPitches[p];
  625. }
  626. nPitches = nValidPitches;
  627. }
  628. if (debugEnabled()) { std::cout << stepX << " " << id << " Initiatise new Cycle: " << nPitches << " " << currArp->getName() << std::endl; }
  629. currArp->initialise(nPitches, freeRunning);
  630. }
  631. // Advance the sequence
  632. // Are we starting a sequence or are running and have been clocked; if so advance the sequence
  633. // Only advance from the clock
  634. if (isRunning && (isClocked || newCycle == LAUNCH)) {
  635. if (debugEnabled()) { std::cout << stepX << " " << id << " Advance Cycle: " << currArp->getPitch() << std::endl; }
  636. if (debugEnabled()) { std::cout << stepX << " " << id << " Advance Cycle: " << pitches[currArp->getPitch()] << " " << (float)currPatt->getOffset() << std::endl; }
  637. // Finally set the out voltage
  638. outVolts = clamp(pitches[currArp->getPitch()] + semiTone * (float)currPatt->getOffset(), -10.0f, 10.0f);
  639. if (debugEnabled()) { std::cout << stepX << " " << id << " Output V = " << outVolts << std::endl; }
  640. // Update counters
  641. currArp->advance();
  642. // Pulse the output gate
  643. gatePulse.trigger(Core::TRIGGER);
  644. }
  645. // Update UI
  646. switch(inputPat) {
  647. case 0: uiPatt = &ui_patt_up; break;
  648. case 1: uiPatt = &ui_patt_down; break;
  649. case 2: uiPatt = &ui_patt_updown; break;
  650. case 3: uiPatt = &ui_patt_downup; break;
  651. case 4: uiPatt = &ui_patt_rez; break;
  652. case 5: uiPatt = &ui_patt_ontherun; break;
  653. default: uiPatt = &ui_patt_up; break;
  654. };
  655. uiPatt->initialise(inputLen, inputScale, inputTrans, freeRunning);
  656. switch(inputArp) {
  657. case 0: uiArp = &ui_arp_right; break;
  658. case 1: uiArp = &ui_arp_left; break;
  659. case 2: uiArp = &ui_arp_rightleft; break;
  660. case 3: uiArp = &ui_arp_leftright; break;
  661. default: uiArp = &ui_arp_right; break;
  662. };
  663. uiArp->initialise(nPitches, freeRunning);
  664. // Set the value
  665. lights[LOCK_LIGHT].value = locked ? 1.0 : 0.0;
  666. outputs[OUT_OUTPUT].value = outVolts;
  667. bool gPulse = gatePulse.process(delta);
  668. bool sPulse = eosPulse.process(delta);
  669. bool cPulse = eocPulse.process(delta);
  670. bool gatesOn = isRunning;
  671. if (gateMode == TRIGGER) {
  672. gatesOn = gatesOn && gPulse;
  673. } else if (gateMode == RETRIGGER) {
  674. gatesOn = gatesOn && !gPulse;
  675. }
  676. outputs[GATE_OUTPUT].value = gatesOn ? 10.0 : 0.0;
  677. outputs[EOS_OUTPUT].value = sPulse ? 10.0 : 0.0;
  678. outputs[EOC_OUTPUT].value = cPulse ? 10.0 : 0.0;
  679. }
  680. struct Arpeggiator2Display : TransparentWidget {
  681. Arpeggiator2 *module;
  682. int frame = 0;
  683. std::shared_ptr<Font> font;
  684. Arpeggiator2Display() {
  685. font = Font::load(assetPlugin(plugin, "res/EurostileBold.ttf"));
  686. }
  687. void draw(NVGcontext *vg) override {
  688. Vec pos = Vec(0, 15);
  689. nvgFontSize(vg, 16);
  690. nvgFontFaceId(vg, font->handle);
  691. nvgTextLetterSpacing(vg, -1);
  692. nvgFillColor(vg, nvgRGBA(255, 0, 0, 0xff));
  693. char text[128];
  694. if (module->inputLen == 0) {
  695. snprintf(text, sizeof(text), "Error: inputLen == 0");
  696. nvgText(vg, pos.x + 10, pos.y + 5, text, NULL);
  697. } else {
  698. snprintf(text, sizeof(text), "Pattern: %s", module->uiPatt->getName().c_str());
  699. nvgText(vg, pos.x + 10, pos.y + 5, text, NULL);
  700. snprintf(text, sizeof(text), "Length: %d", module->uiPatt->length);
  701. nvgText(vg, pos.x + 10, pos.y + 25, text, NULL);
  702. switch(module->uiPatt->scale) {
  703. case 0: snprintf(text, sizeof(text), "Transpose: %d s.t.", module->uiPatt->trans); break;
  704. case 1: snprintf(text, sizeof(text), "Transpose: %d Maj. int.", module->uiPatt->trans); break;
  705. case 2: snprintf(text, sizeof(text), "Transpose: %d Min. int.", module->uiPatt->trans); break;
  706. default: snprintf(text, sizeof(text), "Error..."); break;
  707. }
  708. nvgText(vg, pos.x + 10, pos.y + 45, text, NULL);
  709. snprintf(text, sizeof(text), "Arpeggio: %s", module->uiArp->getName().c_str());
  710. nvgText(vg, pos.x + 10, pos.y + 65, text, NULL);
  711. }
  712. }
  713. };
  714. struct Arpeggiator2Widget : ModuleWidget {
  715. Arpeggiator2Widget(Arpeggiator2 *module);
  716. Menu *createContextMenu() override;
  717. };
  718. Arpeggiator2Widget::Arpeggiator2Widget(Arpeggiator2 *module) : ModuleWidget(module) {
  719. UI ui;
  720. box.size = Vec(240, 380);
  721. {
  722. SVGPanel *panel = new SVGPanel();
  723. panel->box.size = box.size;
  724. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Arpeggiator2.svg")));
  725. addChild(panel);
  726. }
  727. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  728. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  729. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  730. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  731. {
  732. Arpeggiator2Display *display = new Arpeggiator2Display();
  733. display->module = module;
  734. display->box.pos = Vec(10, 95);
  735. display->box.size = Vec(100, 140);
  736. addChild(display);
  737. }
  738. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 0, false, false), Port::OUTPUT, module, Arpeggiator2::OUT_OUTPUT));
  739. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 1, 0, false, false), Port::OUTPUT, module, Arpeggiator2::GATE_OUTPUT));
  740. addParam(ParamWidget::create<AHButton>(ui.getPosition(UI::BUTTON, 2, 0, false, false), module, Arpeggiator2::LOCK_PARAM, 0.0, 1.0, 0.0));
  741. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(ui.getPosition(UI::LIGHT, 2, 0, false, false), module, Arpeggiator2::LOCK_LIGHT));
  742. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 3, 0, false, false), Port::OUTPUT, module, Arpeggiator2::EOC_OUTPUT));
  743. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 4, 0, false, false), Port::OUTPUT, module, Arpeggiator2::EOS_OUTPUT));
  744. addParam(ParamWidget::create<BefacoPush>(Vec(195, 148), module, Arpeggiator2::TRIGGER_PARAM, 0.0, 1.0, 0.0));
  745. for (int i = 0; i < Arpeggiator2::NUM_PITCHES; i++) {
  746. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, i, 5, true, false), Port::INPUT, module, Arpeggiator2::PITCH_INPUT + i));
  747. }
  748. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 4, 4, true, false), Port::INPUT, module, Arpeggiator2::ARP_INPUT));
  749. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 5, 4, true, false), module, Arpeggiator2::ARP_PARAM, 0.0, 3.0, 0.0));
  750. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 4, true, false), Port::INPUT, module, Arpeggiator2::TRIG_INPUT));
  751. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 1, 4, true, false), Port::INPUT, module, Arpeggiator2::CLOCK_INPUT));
  752. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 3, 4, true, false), module, Arpeggiator2::SCALE_PARAM, 0, 2, 0));
  753. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 3, true, false), Port::INPUT, module, Arpeggiator2::PATT_INPUT));
  754. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 1, 3, true, false), module, Arpeggiator2::PATT_PARAM, 0.0, 5.0, 0.0));
  755. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 2, 3, true, false), Port::INPUT, module, Arpeggiator2::TRANS_INPUT));
  756. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 3, 3, true, false), module, Arpeggiator2::TRANS_PARAM, -24, 24, 0));
  757. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 4, 3, true, false), Port::INPUT, module, Arpeggiator2::LENGTH_INPUT));
  758. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 5, 3, true, false), module, Arpeggiator2::LENGTH_PARAM, 1.0, 16.0, 1.0));
  759. }
  760. struct ArpGateModeItem : MenuItem {
  761. Arpeggiator2 *arp;
  762. Arpeggiator2::GateMode gateMode;
  763. void onAction(EventAction &e) override {
  764. arp->gateMode = gateMode;
  765. }
  766. void step() override {
  767. rightText = (arp->gateMode == gateMode) ? "✔" : "";
  768. }
  769. };
  770. Menu *Arpeggiator2Widget::createContextMenu() {
  771. Menu *menu = ModuleWidget::createContextMenu();
  772. MenuLabel *spacerLabel = new MenuLabel();
  773. menu->addChild(spacerLabel);
  774. Arpeggiator2 *arp = dynamic_cast<Arpeggiator2*>(module);
  775. assert(arp);
  776. MenuLabel *modeLabel = new MenuLabel();
  777. modeLabel->text = "Gate Mode";
  778. menu->addChild(modeLabel);
  779. ArpGateModeItem *triggerItem = new ArpGateModeItem();
  780. triggerItem->text = "Trigger";
  781. triggerItem->arp = arp;
  782. triggerItem->gateMode = Arpeggiator2::TRIGGER;
  783. menu->addChild(triggerItem);
  784. ArpGateModeItem *retriggerItem = new ArpGateModeItem();
  785. retriggerItem->text = "Retrigger";
  786. retriggerItem->arp = arp;
  787. retriggerItem->gateMode = Arpeggiator2::RETRIGGER;
  788. menu->addChild(retriggerItem);
  789. ArpGateModeItem *continuousItem = new ArpGateModeItem();
  790. continuousItem->text = "Continuous";
  791. continuousItem->arp = arp;
  792. continuousItem->gateMode = Arpeggiator2::CONTINUOUS;
  793. menu->addChild(continuousItem);
  794. return menu;
  795. }
  796. } // namespace rack_plugin_AmalgamatedHarmonics
  797. using namespace rack_plugin_AmalgamatedHarmonics;
  798. RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Arpeggiator2) {
  799. Model *modelArpeggiator2 = Model::create<Arpeggiator2, Arpeggiator2Widget>( "Amalgamated Harmonics", "Arpeggiator2", "Arpeggiator MkII", ARPEGGIATOR_TAG);
  800. return modelArpeggiator2;
  801. }