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.

621 lines
13KB

  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 Arpeggio {
  9. virtual std::string getName() = 0;
  10. virtual void initialise(int nPitches, int offset) = 0;
  11. virtual void advance() = 0;
  12. virtual int getPitch() = 0;
  13. virtual bool isArpeggioFinished() = 0;
  14. // For RL and LR arps we have the following logic
  15. // Convert from npitch (1-6) to index (0 -> 9), but do no repeat first note
  16. // 1,2,3,4,5,6 (6) ->
  17. // 0 (1)
  18. // 1 (2)
  19. // 2 (3)
  20. // 3 (4)
  21. // 4 (5)
  22. // 5 (6)
  23. // 6 (5)
  24. // 7 (3)
  25. // 8 (2)
  26. // 9 (END, do not repeat 1)
  27. };
  28. struct RightArp : Arpeggio {
  29. int index = 0;
  30. int nPitches = 0;
  31. std::string getName() override {
  32. return "Right";
  33. };
  34. void initialise(int np, int offset) override {
  35. if (offset != 0) {
  36. index = offset % np;
  37. } else {
  38. index = 0;
  39. }
  40. nPitches = np;
  41. // std::cout << nPitches << " " << offset << " " << index << std::endl;
  42. }
  43. void advance() override {
  44. index++;
  45. }
  46. int getPitch() override {
  47. return index;
  48. }
  49. bool isArpeggioFinished() override {
  50. return (index >= nPitches - 1);
  51. }
  52. };
  53. struct LeftArp : Arpeggio {
  54. int index = 0;
  55. int nPitches = 0;
  56. std::string getName() override {
  57. return "Left";
  58. };
  59. void initialise(int np, int offset) override {
  60. if (offset != 0) {
  61. offset = offset % np;
  62. index = np - offset - 1;
  63. } else {
  64. index = np - 1;
  65. }
  66. nPitches = np;
  67. // std::cout << nPitches << " " << offset << " " << index << std::endl;
  68. }
  69. void advance() override {
  70. index--;
  71. }
  72. int getPitch() override {
  73. return index;
  74. }
  75. bool isArpeggioFinished() override {
  76. return (index == 0);
  77. }
  78. };
  79. struct RightLeftArp : Arpeggio {
  80. int currSt = 0;
  81. int mag = 0; // index of last pitch
  82. int end = 0; // index of end of arp
  83. int nPitches = 0;
  84. std::string getName() override {
  85. return "RightLeft";
  86. };
  87. void initialise(int np, int offset) override {
  88. nPitches = np;
  89. mag = np - 1;
  90. end = 2 * mag - 1;
  91. if (end < 1) {
  92. end = 1;
  93. }
  94. currSt = offset;
  95. if (end < currSt) {
  96. end = currSt;
  97. } else {
  98. if (offset > 0) {
  99. end++;
  100. }
  101. }
  102. }
  103. void advance() override {
  104. currSt++;
  105. }
  106. int getPitch() override {
  107. int p = abs((mag - abs(mag - currSt)) % nPitches);
  108. return p;
  109. }
  110. bool isArpeggioFinished() override {
  111. return(currSt == end);
  112. }
  113. };
  114. struct LeftRightArp : Arpeggio {
  115. int currSt = 0;
  116. int mag = 0;
  117. int end = 0;
  118. int nPitches = 0;
  119. std::string getName() override {
  120. return "LeftRight";
  121. };
  122. void initialise(int np, int offset) override {
  123. nPitches = np;
  124. mag = np - 1;
  125. end = 2 * mag - 1;
  126. if (end < 1) {
  127. end = 1;
  128. }
  129. currSt = offset;
  130. if (end < currSt) {
  131. end = currSt;
  132. } else {
  133. if (offset > 0) {
  134. end++;
  135. }
  136. }
  137. }
  138. void advance() override {
  139. currSt++;
  140. }
  141. int getPitch() override {
  142. int p = abs(abs(mag - currSt) % nPitches);
  143. return p;
  144. }
  145. bool isArpeggioFinished() override {
  146. return(currSt == end);
  147. }
  148. };
  149. struct Arp31 : AHModule {
  150. const static int MAX_STEPS = 16;
  151. const static int MAX_DIST = 12; //Octave
  152. const static int NUM_PITCHES = 6;
  153. enum ParamIds {
  154. ARP_PARAM,
  155. OFFSET_PARAM,
  156. NUM_PARAMS
  157. };
  158. enum InputIds {
  159. CLOCK_INPUT,
  160. ENUMS(PITCH_INPUT,6),
  161. ARP_INPUT,
  162. NUM_INPUTS
  163. };
  164. enum OutputIds {
  165. OUT_OUTPUT,
  166. GATE_OUTPUT,
  167. EOC_OUTPUT,
  168. NUM_OUTPUTS
  169. };
  170. enum LightIds {
  171. ENUMS(CURR_LIGHT,6),
  172. NUM_LIGHTS
  173. };
  174. Arp31() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  175. reset();
  176. id = rand();
  177. debugFlag = false;
  178. }
  179. void step() override;
  180. void reset() override {
  181. isRunning = false;
  182. }
  183. json_t *toJson() override {
  184. json_t *rootJ = json_object();
  185. // gateMode
  186. json_t *gateModeJ = json_integer((int) gateMode);
  187. json_object_set_new(rootJ, "gateMode", gateModeJ);
  188. return rootJ;
  189. }
  190. void fromJson(json_t *rootJ) override {
  191. // gateMode
  192. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  193. if (gateModeJ) {
  194. gateMode = (GateMode)json_integer_value(gateModeJ);
  195. }
  196. }
  197. enum GateMode {
  198. TRIGGER,
  199. RETRIGGER,
  200. CONTINUOUS,
  201. };
  202. GateMode gateMode = TRIGGER;
  203. SchmittTrigger clockTrigger; // for clock
  204. PulseGenerator gatePulse;
  205. PulseGenerator eocPulse;
  206. bool locked = false;
  207. float outVolts = 0;
  208. bool isRunning = false;
  209. int error = 0;
  210. int inputArp = 0;
  211. int arp = 0;
  212. int poll = 5000;
  213. float semiTone = 1.0 / 12.0;
  214. RightArp arp_right;
  215. LeftArp arp_left;
  216. RightLeftArp arp_rightleft;
  217. LeftRightArp arp_leftright;
  218. RightArp ui_arp_right;
  219. LeftArp ui_arp_left;
  220. RightLeftArp ui_arp_rightleft;
  221. LeftRightArp ui_arp_leftright;
  222. Arpeggio *currArp = &arp_right;
  223. Arpeggio *uiArp = &arp_right;
  224. float pitches[6];
  225. int pitchIndex[NUM_PITCHES];
  226. int nPitches = 0;
  227. int id = 0;
  228. int currLight = 0;
  229. };
  230. void Arp31::step() {
  231. AHModule::step();
  232. // Wait a few steps for the inputs to flow through Rack
  233. if (stepX < 10) {
  234. return;
  235. }
  236. // Get inputs from Rack
  237. float clockInput = inputs[CLOCK_INPUT].value;
  238. bool clockActive = inputs[CLOCK_INPUT].active;
  239. if (inputs[ARP_INPUT].active) {
  240. inputArp = inputs[ARP_INPUT].value;
  241. } else {
  242. inputArp = params[ARP_PARAM].value;
  243. }
  244. int offset = params[OFFSET_PARAM].value;
  245. // Process inputs
  246. bool clockStatus = clockTrigger.process(clockInput);
  247. // If there is no clock input, then force that we are not running
  248. if (!clockActive) {
  249. isRunning = false;
  250. }
  251. bool restart = false;
  252. int oldLight = 0;
  253. // Have we been clocked?
  254. if (clockStatus) {
  255. // If we are already running, process cycle
  256. if (isRunning) {
  257. if (debugEnabled()) { std::cout << stepX << " " << id << " Advance Cycle: " << currArp->getPitch() << " " << pitches[currArp->getPitch()] << std::endl; }
  258. // Reached the end of the pattern?
  259. if (currArp->isArpeggioFinished()) {
  260. // Pulse the EOC gate
  261. eocPulse.trigger(Core::TRIGGER);
  262. if (debugEnabled()) { std::cout << stepX << " " << id << " Finished Cycle" << std::endl; }
  263. restart = true;
  264. }
  265. // Finally set the out voltage
  266. int i = currArp->getPitch();
  267. outVolts = clamp(pitches[i], -10.0f, 10.0f);
  268. oldLight = currLight;
  269. currLight = pitchIndex[i];
  270. if (debugEnabled()) { std::cout << stepX << " " << id << " Index: " << i << " V: " << outVolts << " Light: " << currLight << std::endl; }
  271. // Pulse the output gate
  272. gatePulse.trigger(Core::TRIGGER);
  273. // Completed 1 step
  274. currArp->advance();
  275. } else {
  276. // Start a cycle
  277. restart = true;
  278. }
  279. }
  280. // If we have been triggered, start a new sequence
  281. if (restart) {
  282. // Read input pitches and assign to pitch array
  283. int nValidPitches = 0;
  284. float inputPitches[NUM_PITCHES];
  285. for (int p = 0; p < NUM_PITCHES; p++) {
  286. int index = PITCH_INPUT + p;
  287. if (inputs[index].active) {
  288. inputPitches[nValidPitches] = inputs[index].value;
  289. pitchIndex[nValidPitches] = p;
  290. nValidPitches++;
  291. } else {
  292. inputPitches[nValidPitches] = 0.0;
  293. pitchIndex[nValidPitches] = 0;
  294. }
  295. }
  296. // if (debugEnabled()) {
  297. // for (int p = 0; p < nValidPitches; p++) {
  298. // std::cout << inputPitches[p] << std::endl;
  299. // }
  300. // }
  301. // Always play something
  302. if (nValidPitches == 0) {
  303. if (debugEnabled()) { std::cout << stepX << " " << id << " No inputs, assume single 0V pitch" << std::endl; }
  304. inputPitches[0] = 0.0;
  305. pitchIndex[0] = 0;
  306. nValidPitches = 1;
  307. }
  308. // At the first step of the cycle
  309. // So this is where we tweak the cycle parameters
  310. arp = inputArp;
  311. switch(arp) {
  312. case 0: currArp = &arp_right; break;
  313. case 1: currArp = &arp_left; break;
  314. case 2: currArp = &arp_rightleft; break;
  315. case 3: currArp = &arp_leftright; break;
  316. default: currArp = &arp_right; break;
  317. };
  318. // Copy pitches
  319. for (int p = 0; p < nValidPitches; p++) {
  320. pitches[p] = inputPitches[p];
  321. }
  322. nPitches = nValidPitches;
  323. if (debugEnabled()) { std::cout << stepX << " " << id << " Initiatise new Cycle: Pattern: " << currArp->getName() << " nPitches: " << nPitches << std::endl; }
  324. currArp->initialise(nPitches, offset);
  325. // Start
  326. isRunning = true;
  327. }
  328. // Update UI
  329. switch(inputArp) {
  330. case 0: uiArp = &ui_arp_right; break;
  331. case 1: uiArp = &ui_arp_left; break;
  332. case 2: uiArp = &ui_arp_rightleft; break;
  333. case 3: uiArp = &ui_arp_leftright; break;
  334. default: uiArp = &ui_arp_right; break;
  335. };
  336. // uiArp->initialise(nValidPitches, 1);
  337. // Set the value
  338. outputs[OUT_OUTPUT].value = outVolts;
  339. // Set the light
  340. lights[CURR_LIGHT + oldLight].value = 0.0;
  341. lights[CURR_LIGHT + currLight].value = 1.0;
  342. bool gPulse = gatePulse.process(delta);
  343. bool cPulse = eocPulse.process(delta);
  344. bool gatesOn = isRunning;
  345. if (gateMode == TRIGGER) {
  346. gatesOn = gatesOn && gPulse;
  347. } else if (gateMode == RETRIGGER) {
  348. gatesOn = gatesOn && !gPulse;
  349. }
  350. outputs[GATE_OUTPUT].value = gatesOn ? 10.0 : 0.0;
  351. outputs[EOC_OUTPUT].value = cPulse ? 10.0 : 0.0;
  352. }
  353. struct Arp31Display : TransparentWidget {
  354. Arp31 *module;
  355. int frame = 0;
  356. std::shared_ptr<Font> font;
  357. Arp31Display() {
  358. font = Font::load(assetPlugin(plugin, "res/EurostileBold.ttf"));
  359. }
  360. void draw(NVGcontext *vg) override {
  361. Vec pos = Vec(0, 15);
  362. nvgFontSize(vg, 16);
  363. nvgFontFaceId(vg, font->handle);
  364. nvgTextLetterSpacing(vg, -1);
  365. nvgFillColor(vg, nvgRGBA(255, 0, 0, 0xff));
  366. char text[128];
  367. snprintf(text, sizeof(text), "%s", module->uiArp->getName().c_str());
  368. nvgText(vg, pos.x + 10, pos.y + 65, text, NULL);
  369. }
  370. };
  371. struct Arp31Widget : ModuleWidget {
  372. Arp31Widget(Arp31 *module);
  373. Menu *createContextMenu() override;
  374. };
  375. Arp31Widget::Arp31Widget(Arp31 *module) : ModuleWidget(module) {
  376. UI ui;
  377. box.size = Vec(135, 380);
  378. {
  379. SVGPanel *panel = new SVGPanel();
  380. panel->box.size = box.size;
  381. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Arp31c.svg")));
  382. addChild(panel);
  383. }
  384. {
  385. Arp31Display *display = new Arp31Display();
  386. display->module = module;
  387. display->box.pos = Vec(40, 100);
  388. display->box.size = Vec(100, 70);
  389. addChild(display);
  390. }
  391. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 5, true, false), Port::OUTPUT, module, Arp31::OUT_OUTPUT));
  392. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 1, 5, true, false), Port::OUTPUT, module, Arp31::GATE_OUTPUT));
  393. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 2, 5, true, false), Port::OUTPUT, module, Arp31::EOC_OUTPUT));
  394. for (int i = 0; i < 3; i++) {
  395. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, i, 0, true, false), Port::INPUT, module, Arp31::PITCH_INPUT + i));
  396. Vec v = ui.getPosition(UI::LIGHT, i, 1, true, false);
  397. v.x = v.x + 2;
  398. v.y = 75;
  399. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(v, module, Arp31::CURR_LIGHT + i));
  400. }
  401. for (int i = 3; i < 6; i++) {
  402. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, i - 3, 1, true, false), Port::INPUT, module, Arp31::PITCH_INPUT + i));
  403. Vec v = ui.getPosition(UI::LIGHT, i - 3, 2, true, false);
  404. v.x = v.x + 2;
  405. v.y = 131;
  406. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(v, module, Arp31::CURR_LIGHT + i));
  407. }
  408. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 4, true, false), Port::INPUT, module, Arp31::CLOCK_INPUT));
  409. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 1, 4, true, false), module, Arp31::OFFSET_PARAM, 0.0, 10.0, 0.0));
  410. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, 0, 2, true, false), module, Arp31::ARP_PARAM, 0.0, 3.0, 0.0));
  411. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 0, 3, true, false), Port::INPUT, module, Arp31::ARP_INPUT));
  412. }
  413. struct ArpGateModeItem : MenuItem {
  414. Arp31 *arp;
  415. Arp31::GateMode gateMode;
  416. void onAction(EventAction &e) override {
  417. arp->gateMode = gateMode;
  418. }
  419. void step() override {
  420. rightText = (arp->gateMode == gateMode) ? "✔" : "";
  421. }
  422. };
  423. Menu *Arp31Widget::createContextMenu() {
  424. Menu *menu = ModuleWidget::createContextMenu();
  425. MenuLabel *spacerLabel = new MenuLabel();
  426. menu->addChild(spacerLabel);
  427. Arp31 *arp = dynamic_cast<Arp31*>(module);
  428. assert(arp);
  429. MenuLabel *modeLabel = new MenuLabel();
  430. modeLabel->text = "Gate Mode";
  431. menu->addChild(modeLabel);
  432. ArpGateModeItem *triggerItem = new ArpGateModeItem();
  433. triggerItem->text = "Trigger";
  434. triggerItem->arp = arp;
  435. triggerItem->gateMode = Arp31::TRIGGER;
  436. menu->addChild(triggerItem);
  437. ArpGateModeItem *retriggerItem = new ArpGateModeItem();
  438. retriggerItem->text = "Retrigger";
  439. retriggerItem->arp = arp;
  440. retriggerItem->gateMode = Arp31::RETRIGGER;
  441. menu->addChild(retriggerItem);
  442. ArpGateModeItem *continuousItem = new ArpGateModeItem();
  443. continuousItem->text = "Continuous";
  444. continuousItem->arp = arp;
  445. continuousItem->gateMode = Arp31::CONTINUOUS;
  446. menu->addChild(continuousItem);
  447. return menu;
  448. }
  449. } // namespace rack_plugin_AmalgamatedHarmonics
  450. using namespace rack_plugin_AmalgamatedHarmonics;
  451. RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Arp31) {
  452. Model *modelArp31 = Model::create<Arp31, Arp31Widget>( "Amalgamated Harmonics", "Arp31", "Arp 3.1 - Chord", ARPEGGIATOR_TAG);
  453. return modelArp31;
  454. }