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.

1421 lines
54KB

  1. #include "global_pre.hpp"
  2. #include "Bidoo.hpp"
  3. #include "dsp/digital.hpp"
  4. #include "BidooComponents.hpp"
  5. #include "global_ui.hpp"
  6. #include <ctime>
  7. #include <iostream>
  8. #include <vector>
  9. #include <random>
  10. #include <algorithm>
  11. using namespace std;
  12. namespace rack_plugin_Bidoo {
  13. struct StepPlus {
  14. int index = 0;
  15. int number = 0;
  16. bool skip = false;
  17. bool skipParam = false;
  18. bool slide = false;
  19. int pulses = 1;
  20. int pulsesParam = 1;
  21. float pitch = 3.0f;
  22. int type = 2;
  23. float gateProb = 1.0f;
  24. float pitchRnd = 0.0f;
  25. float accent = 0.0f;
  26. float rndAccent = 0.0f;
  27. };
  28. struct PatternPlus {
  29. int playMode = 0;
  30. int countMode = 0;
  31. int numberOfSteps = 8;
  32. int numberOfStepsParam = 8;
  33. int rootNote = 0;
  34. int rootNoteParam = 0;
  35. int scale = 0;
  36. int scaleParam = 0;
  37. float gateTime = 0.5f;
  38. float slideTime = 0.2f;
  39. float sensitivity = 1.0f;
  40. int currentStep = 0;
  41. int currentPulse = 0;
  42. bool forward = true;
  43. std::vector<StepPlus> steps {16};
  44. void Update(int playMode, int countMode, int numberOfSteps, int numberOfStepsParam, int rootNote, int scale,
  45. float gateTime, float slideTime, float sensitivity, std::vector<char> skips, std::vector<char> slides,
  46. std::vector<Param> pulses, std::vector<Param> pitches, std::vector<Param> types, std::vector<Param> probGates,
  47. std::vector<Param> rndPitches, std::vector<Param> accents, std::vector<Param> rndAccents)
  48. {
  49. this->playMode = playMode;
  50. this->countMode = countMode;
  51. this->numberOfSteps = numberOfSteps;
  52. this->numberOfStepsParam = numberOfStepsParam;
  53. this->rootNote = rootNote;
  54. this->scale = scale;
  55. this->rootNoteParam = rootNote;
  56. this->scaleParam = scale;
  57. this->gateTime = gateTime;
  58. this->slideTime = slideTime;
  59. this->sensitivity = sensitivity;
  60. int pCount = 0;
  61. for (int i = 0; i < 16; i++) {
  62. steps[i].index = i%8;
  63. steps[i].number = i;
  64. if (((countMode == 0) && (i < numberOfSteps)) || ((countMode == 1) && (pCount < numberOfSteps))) {
  65. steps[i].skip = (skips[i%8] == 't');
  66. } else {
  67. steps[i].skip = true;
  68. }
  69. steps[i].skipParam = (skips[i%8] == 't');
  70. steps[i].slide = (slides[i%8] == 't');
  71. if ((countMode == 1) && ((pCount + (int)pulses[i%8].value) >= numberOfSteps)) {
  72. steps[i].pulses = max(numberOfSteps - pCount, 0);
  73. } else {
  74. steps[i].pulses = (int)pulses[i%8].value;
  75. }
  76. steps[i].pulsesParam = (int)pulses[i%8].value;
  77. pCount = pCount + steps[i].pulses;
  78. steps[i].pitch = pitches[i%8].value;
  79. steps[i].type = (int)types[i%8].value;
  80. steps[i].gateProb = probGates[i%8].value;
  81. steps[i].pitchRnd = rndPitches[i%8].value;
  82. steps[i].accent = accents[i%8].value;
  83. steps[i].rndAccent = rndAccents[i%8].value;
  84. }
  85. }
  86. std::tuple<int, int> GetNextStep(bool reset)
  87. {
  88. if (reset) {
  89. if (playMode != 1) {
  90. currentStep = GetFirstStep();
  91. } else {
  92. currentStep = GetLastStep();
  93. }
  94. currentPulse = 0;
  95. return std::make_tuple(currentStep,currentPulse);
  96. } else {
  97. if (currentPulse < steps[currentStep].pulses - 1) {
  98. currentPulse++;
  99. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  100. } else {
  101. if (playMode == 0) {
  102. currentStep = GetNextStepForward(currentStep);
  103. currentPulse = 0;
  104. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  105. } else if (playMode == 1) {
  106. currentStep = GetNextStepBackward(currentStep);
  107. currentPulse = 0;
  108. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  109. } else if (playMode == 2) {
  110. if (currentStep == GetLastStep()) {
  111. forward = false;
  112. }
  113. if (currentStep == GetFirstStep()) {
  114. forward = true;
  115. }
  116. if (forward) {
  117. currentStep = GetNextStepForward(currentStep);
  118. } else {
  119. currentStep = GetNextStepBackward(currentStep);
  120. }
  121. currentPulse = 0;
  122. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  123. } else if (playMode == 3) {
  124. std::vector<StepPlus> tmp (steps.size());
  125. auto it = std::copy_if (steps.begin(), steps.end(), tmp.begin(), [](StepPlus i){return !(i.skip);} );
  126. tmp.resize(std::distance(tmp.begin(),it)); // shrink container to new size
  127. StepPlus tmpStep = *select_randomly(tmp.begin(), tmp.end());
  128. currentPulse = 0;
  129. currentStep = tmpStep.number;
  130. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  131. } else if (playMode == 4) {
  132. int next = GetNextStepForward(currentStep);
  133. int prev = GetNextStepBackward(currentStep);
  134. vector<StepPlus> subPattern;
  135. subPattern.push_back(steps[prev]);
  136. subPattern.push_back(steps[next]);
  137. StepPlus choice = *select_randomly(subPattern.begin(), subPattern.end());
  138. currentPulse = 0;
  139. currentStep = choice.number;
  140. return std::make_tuple(steps[currentStep%16].index,currentPulse);
  141. } else {
  142. return std::make_tuple(0,0);
  143. }
  144. }
  145. }
  146. }
  147. StepPlus CurrentStep() {
  148. return this->steps[currentStep];
  149. }
  150. int GetFirstStep()
  151. {
  152. for (int i = 0; i < 16; i++) {
  153. if (!steps[i].skip) {
  154. return i;
  155. }
  156. }
  157. return 0;
  158. }
  159. int GetLastStep()
  160. {
  161. for (int i = 15; i >= 0 ; i--) {
  162. if (!steps[i].skip) {
  163. return i;
  164. }
  165. }
  166. return 15;
  167. }
  168. int GetNextStepForward(int pos)
  169. {
  170. for (int i = pos + 1; i < pos + 16; i++) {
  171. if (!steps[i%16].skip) {
  172. return i%16;
  173. }
  174. }
  175. return pos;
  176. }
  177. int GetNextStepBackward(int pos)
  178. {
  179. for (int i = pos - 1; i > pos - 16; i--) {
  180. if (!steps[i%16 + (i<0?16:0)].skip) {
  181. return i%16 + (i<0?16:0);
  182. }
  183. }
  184. return pos;
  185. }
  186. template<typename Iter, typename RandomGenerator> Iter select_randomly(Iter start, Iter end, RandomGenerator& g) {
  187. std::uniform_int_distribution<> dis(0, std::distance(start, end) - 1);
  188. std::advance(start, dis(g));
  189. return start;
  190. }
  191. template<typename Iter> Iter select_randomly(Iter start, Iter end) {
  192. static std::random_device rd;
  193. static std::mt19937 gen(rd());
  194. return select_randomly(start, end, gen);
  195. }
  196. };
  197. struct BORDL : Module {
  198. enum ParamIds {
  199. CLOCK_PARAM,
  200. RUN_PARAM,
  201. RESET_PARAM,
  202. STEPS_PARAM,
  203. SLIDE_TIME_PARAM,
  204. GATE_TIME_PARAM,
  205. ROOT_NOTE_PARAM,
  206. SCALE_PARAM,
  207. PLAY_MODE_PARAM,
  208. COUNT_MODE_PARAM,
  209. PATTERN_PARAM,
  210. SENSITIVITY_PARAM,
  211. TRIG_COUNT_PARAM = SENSITIVITY_PARAM + 8,
  212. TRIG_TYPE_PARAM = TRIG_COUNT_PARAM + 8,
  213. TRIG_PITCH_PARAM = TRIG_TYPE_PARAM + 8,
  214. TRIG_SLIDE_PARAM = TRIG_PITCH_PARAM + 8,
  215. TRIG_SKIP_PARAM = TRIG_SLIDE_PARAM + 8,
  216. TRIG_GATEPROB_PARAM = TRIG_SKIP_PARAM + 8,
  217. TRIG_PITCHRND_PARAM = TRIG_GATEPROB_PARAM + 8,
  218. TRIG_ACCENT_PARAM = TRIG_PITCHRND_PARAM + 8,
  219. TRIG_RNDACCENT_PARAM = TRIG_ACCENT_PARAM + 8,
  220. NUM_PARAMS = TRIG_RNDACCENT_PARAM + 8
  221. };
  222. enum InputIds {
  223. CLOCK_INPUT,
  224. EXT_CLOCK_INPUT,
  225. RESET_INPUT,
  226. STEPS_INPUT,
  227. SLIDE_TIME_INPUT,
  228. GATE_TIME_INPUT,
  229. ROOT_NOTE_INPUT,
  230. SCALE_INPUT,
  231. EXTGATE1_INPUT,
  232. EXTGATE2_INPUT,
  233. PATTERN_INPUT,
  234. NUM_INPUTS
  235. };
  236. enum OutputIds {
  237. GATE_OUTPUT,
  238. PITCH_OUTPUT,
  239. ACC_OUTPUT,
  240. NUM_OUTPUTS
  241. };
  242. enum LightIds {
  243. RUNNING_LIGHT,
  244. RESET_LIGHT,
  245. GATE_LIGHT,
  246. STEPS_LIGHTS = GATE_LIGHT + 8,
  247. SLIDES_LIGHTS = STEPS_LIGHTS + 8,
  248. SKIPS_LIGHTS = SLIDES_LIGHTS + 8,
  249. NUM_LIGHTS = SKIPS_LIGHTS + 8
  250. };
  251. //copied from http://www.grantmuller.com/MidiReference/doc/midiReference/ScaleReference.html
  252. int SCALE_AEOLIAN [7] = {0, 2, 3, 5, 7, 8, 10};
  253. int SCALE_BLUES [9] = {0, 2, 3, 4, 5, 7, 9, 10, 11};
  254. int SCALE_CHROMATIC [12]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
  255. int SCALE_DIATONIC_MINOR [7] = {0, 2, 3, 5, 7, 8, 10};
  256. int SCALE_DORIAN [7] = {0, 2, 3, 5, 7, 9, 10};
  257. int SCALE_HARMONIC_MINOR [7] = {0, 2, 3, 5, 7, 8, 11};
  258. int SCALE_INDIAN [7] = {0, 1, 1, 4, 5, 8, 10};
  259. int SCALE_LOCRIAN [7] = {0, 1, 3, 5, 6, 8, 10};
  260. int SCALE_LYDIAN [7] = {0, 2, 4, 6, 7, 9, 10};
  261. int SCALE_MAJOR [7] = {0, 2, 4, 5, 7, 9, 11};
  262. int SCALE_MELODIC_MINOR [9] = {0, 2, 3, 5, 7, 8, 9, 10, 11};
  263. int SCALE_MINOR [7] = {0, 2, 3, 5, 7, 8, 10};
  264. int SCALE_MIXOLYDIAN [7] = {0, 2, 4, 5, 7, 9, 10};
  265. int SCALE_NATURAL_MINOR [7] = {0, 2, 3, 5, 7, 8, 10};
  266. int SCALE_PENTATONIC [5] = {0, 2, 4, 7, 9};
  267. int SCALE_PHRYGIAN [7] = {0, 1, 3, 5, 7, 8, 10};
  268. int SCALE_TURKISH [7] = {0, 1, 3, 5, 7, 10, 11};
  269. enum Notes {
  270. NOTE_C,
  271. NOTE_C_SHARP,
  272. NOTE_D,
  273. NOTE_D_SHARP,
  274. NOTE_E,
  275. NOTE_F,
  276. NOTE_F_SHARP,
  277. NOTE_G,
  278. NOTE_G_SHARP,
  279. NOTE_A,
  280. NOTE_A_SHARP,
  281. NOTE_B,
  282. NUM_NOTES
  283. };
  284. enum Scales {
  285. AEOLIAN,
  286. BLUES,
  287. CHROMATIC,
  288. DIATONIC_MINOR,
  289. DORIAN,
  290. HARMONIC_MINOR,
  291. INDIAN,
  292. LOCRIAN,
  293. LYDIAN,
  294. MAJOR,
  295. MELODIC_MINOR,
  296. MINOR,
  297. MIXOLYDIAN,
  298. NATURAL_MINOR,
  299. PENTATONIC,
  300. PHRYGIAN,
  301. TURKISH,
  302. NONE,
  303. NUM_SCALES
  304. };
  305. bool running = true;
  306. SchmittTrigger clockTrigger;
  307. SchmittTrigger runningTrigger;
  308. SchmittTrigger resetTrigger;
  309. SchmittTrigger slideTriggers[8];
  310. SchmittTrigger skipTriggers[8];
  311. SchmittTrigger playModeTrigger;
  312. SchmittTrigger countModeTrigger;
  313. SchmittTrigger PatternTrigger;
  314. float phase = 0.0f;
  315. int index = 0;
  316. int prevIndex = 0;
  317. bool reStart = true;
  318. int pulse = 0;
  319. int rootNote = 0;
  320. int curScaleVal = 0;
  321. float pitch = 0.0f;
  322. float previousPitch = 0.0f;
  323. clock_t tCurrent;
  324. clock_t tLastTrig;
  325. clock_t tPreviousTrig;
  326. std::vector<char> slideState = {'f','f','f','f','f','f','f','f'};
  327. std::vector<char> skipState = {'f','f','f','f','f','f','f','f'};
  328. int playMode = 0; // 0 forward, 1 backward, 2 pingpong, 3 random, 4 brownian
  329. int countMode = 0; // 0 steps, 1 pulses
  330. int numSteps = 8;
  331. int selectedPattern = 0;
  332. int playedPattern = 0;
  333. bool pitchMode = false;
  334. bool pitchQuantizeMode = true;
  335. bool updateFlag = false;
  336. bool probGate = true;
  337. float rndPitch = 0.0f;
  338. float accent = 5.0f;
  339. bool loadedFromJson = false;
  340. int copyPattern = -1;
  341. PatternPlus patterns[16];
  342. BORDL() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  343. }
  344. void UpdatePattern() {
  345. std::vector<Param> pulses(&params[TRIG_COUNT_PARAM],&params[TRIG_COUNT_PARAM + 8]);
  346. std::vector<Param> pitches(&params[TRIG_PITCH_PARAM],&params[TRIG_PITCH_PARAM + 8]);
  347. std::vector<Param> types(&params[TRIG_TYPE_PARAM],&params[TRIG_TYPE_PARAM + 8]);
  348. std::vector<Param> probGates(&params[TRIG_GATEPROB_PARAM],&params[TRIG_GATEPROB_PARAM + 8]);
  349. std::vector<Param> rndPitches(&params[TRIG_PITCHRND_PARAM],&params[TRIG_PITCHRND_PARAM + 8]);
  350. std::vector<Param> accents(&params[TRIG_ACCENT_PARAM],&params[TRIG_ACCENT_PARAM + 8]);
  351. std::vector<Param> rndAccents(&params[TRIG_RNDACCENT_PARAM],&params[TRIG_RNDACCENT_PARAM + 8]);
  352. patterns[selectedPattern].Update(playMode, countMode, numSteps, roundf(params[STEPS_PARAM].value), roundf(params[ROOT_NOTE_PARAM].value),
  353. roundf(params[SCALE_PARAM].value), params[GATE_TIME_PARAM].value, params[SLIDE_TIME_PARAM].value, params[SENSITIVITY_PARAM].value ,
  354. skipState, slideState, pulses, pitches, types, probGates, rndPitches, accents, rndAccents);
  355. }
  356. void step() override;
  357. // persistence, random & init
  358. json_t *toJson() override {
  359. json_t *rootJ = json_object();
  360. json_object_set_new(rootJ, "running", json_boolean(running));
  361. json_object_set_new(rootJ, "playMode", json_integer(playMode));
  362. json_object_set_new(rootJ, "countMode", json_integer(countMode));
  363. json_object_set_new(rootJ, "pitchMode", json_boolean(pitchMode));
  364. json_object_set_new(rootJ, "pitchQuantizeMode", json_boolean(pitchQuantizeMode));
  365. json_object_set_new(rootJ, "selectedPattern", json_integer(selectedPattern));
  366. json_object_set_new(rootJ, "playedPattern", json_integer(playedPattern));
  367. json_t *trigsJ = json_array();
  368. for (int i = 0; i < 8; i++) {
  369. json_t *trigJ = json_array();
  370. json_t *trigJSlide = json_boolean(slideState[i] == 't');
  371. json_array_append_new(trigJ, trigJSlide);
  372. json_t *trigJSkip = json_boolean(skipState[i] == 't');
  373. json_array_append_new(trigJ, trigJSkip);
  374. json_array_append_new(trigsJ, trigJ);
  375. }
  376. json_object_set_new(rootJ, "trigs", trigsJ);
  377. for (int i = 0; i<16; i++) {
  378. json_t *patternJ = json_object();
  379. json_object_set_new(patternJ, "playMode", json_integer(patterns[i].playMode));
  380. json_object_set_new(patternJ, "countMode", json_integer(patterns[i].countMode));
  381. json_object_set_new(patternJ, "numSteps", json_integer(patterns[i].numberOfStepsParam));
  382. json_object_set_new(patternJ, "rootNote", json_integer(patterns[i].rootNote));
  383. json_object_set_new(patternJ, "scale", json_integer(patterns[i].scale));
  384. json_object_set_new(patternJ, "gateTime", json_real(patterns[i].gateTime));
  385. json_object_set_new(patternJ, "slideTime", json_real(patterns[i].slideTime));
  386. json_object_set_new(patternJ, "sensitivity", json_real(patterns[i].sensitivity));
  387. for (int j = 0; j < 16; j++) {
  388. json_t *stepJ = json_object();
  389. json_object_set_new(stepJ, "index", json_integer(patterns[i].steps[j].index));
  390. json_object_set_new(stepJ, "number", json_integer(patterns[i].steps[j].number));
  391. json_object_set_new(stepJ, "skip", json_integer((int)patterns[i].steps[j].skip));
  392. json_object_set_new(stepJ, "skipParam", json_integer((int)patterns[i].steps[j].skipParam));
  393. json_object_set_new(stepJ, "slide", json_integer((int)patterns[i].steps[j].slide));
  394. json_object_set_new(stepJ, "pulses", json_integer(patterns[i].steps[j].pulses));
  395. json_object_set_new(stepJ, "pulsesParam", json_integer(patterns[i].steps[j].pulsesParam));
  396. json_object_set_new(stepJ, "pitch", json_real(patterns[i].steps[j].pitch));
  397. json_object_set_new(stepJ, "type", json_integer(patterns[i].steps[j].type));
  398. json_object_set_new(stepJ, "gateProb", json_real(patterns[i].steps[j].gateProb));
  399. json_object_set_new(stepJ, "pitchRnd", json_real(patterns[i].steps[j].pitchRnd));
  400. json_object_set_new(stepJ, "accent", json_real(patterns[i].steps[j].accent));
  401. json_object_set_new(stepJ, "rndAccent", json_real(patterns[i].steps[j].rndAccent));
  402. json_object_set_new(patternJ, ("step" + to_string(j)).c_str() , stepJ);
  403. }
  404. json_object_set_new(rootJ, ("pattern" + to_string(i)).c_str(), patternJ);
  405. }
  406. return rootJ;
  407. }
  408. void fromJson(json_t *rootJ) override {
  409. json_t *runningJ = json_object_get(rootJ, "running");
  410. if (runningJ)
  411. running = json_is_true(runningJ);
  412. json_t *playModeJ = json_object_get(rootJ, "playMode");
  413. if (playModeJ)
  414. playMode = json_integer_value(playModeJ);
  415. json_t *countModeJ = json_object_get(rootJ, "countMode");
  416. if (countModeJ)
  417. countMode = json_integer_value(countModeJ);
  418. json_t *selectedPatternJ = json_object_get(rootJ, "selectedPattern");
  419. if (selectedPatternJ)
  420. selectedPattern = json_integer_value(selectedPatternJ);
  421. json_t *playedPatternJ = json_object_get(rootJ, "playedPattern");
  422. if (playedPatternJ)
  423. playedPattern = json_integer_value(playedPatternJ);
  424. json_t *pitchModeJ = json_object_get(rootJ, "pitchMode");
  425. if (pitchModeJ)
  426. pitchMode = json_is_true(pitchModeJ);
  427. json_t *pitchQuantizeModeJ = json_object_get(rootJ, "pitchQuantizeMode");
  428. if (pitchQuantizeModeJ)
  429. pitchQuantizeMode = json_is_true(pitchQuantizeModeJ);
  430. json_t *trigsJ = json_object_get(rootJ, "trigs");
  431. if (trigsJ) {
  432. for (int i = 0; i < 8; i++) {
  433. json_t *trigJ = json_array_get(trigsJ, i);
  434. if (trigJ)
  435. {
  436. slideState[i] = json_is_true(json_array_get(trigJ, 0)) ? 't' : 'f';
  437. skipState[i] = json_is_true(json_array_get(trigJ, 1)) ? 't' : 'f';
  438. }
  439. }
  440. }
  441. for (int i=0; i<16;i++) {
  442. json_t *patternJ = json_object_get(rootJ, ("pattern" + to_string(i)).c_str());
  443. if (patternJ){
  444. json_t *playModeJ = json_object_get(patternJ, "playMode");
  445. if (playModeJ)
  446. patterns[i].playMode = json_integer_value(playModeJ);
  447. json_t *countModeJ = json_object_get(patternJ, "countMode");
  448. if (countModeJ)
  449. patterns[i].countMode = json_integer_value(countModeJ);
  450. json_t *numStepsJ = json_object_get(patternJ, "numSteps");
  451. if (numStepsJ)
  452. patterns[i].numberOfStepsParam = json_integer_value(numStepsJ);
  453. json_t *rootNoteJ = json_object_get(patternJ, "rootNote");
  454. if (rootNoteJ)
  455. patterns[i].rootNote = json_integer_value(rootNoteJ);
  456. json_t *scaleJ = json_object_get(patternJ, "scale");
  457. if (scaleJ)
  458. patterns[i].scale = json_integer_value(scaleJ);
  459. json_t *gateTimeJ = json_object_get(patternJ, "gateTime");
  460. if (gateTimeJ)
  461. patterns[i].gateTime = json_real_value(gateTimeJ);
  462. json_t *slideTimeJ = json_object_get(patternJ, "slideTime");
  463. if (slideTimeJ)
  464. patterns[i].slideTime = json_real_value(slideTimeJ);
  465. json_t *sensitivityJ = json_object_get(patternJ, "sensitivity");
  466. if (sensitivityJ)
  467. patterns[i].sensitivity = json_real_value(sensitivityJ);
  468. for (int j = 0; j < 16; j++) {
  469. json_t *stepJ = json_object_get(patternJ, ("step" + to_string(j)).c_str());
  470. if (stepJ) {
  471. json_t *indexJ= json_object_get(stepJ, "index");
  472. if (indexJ)
  473. patterns[i].steps[j].index = json_integer_value(indexJ);
  474. json_t *numberJ= json_object_get(stepJ, "numer");
  475. if (numberJ)
  476. patterns[i].steps[j].number = json_integer_value(numberJ);
  477. json_t *skipJ= json_object_get(stepJ, "skip");
  478. if (skipJ)
  479. patterns[i].steps[j].skip = !!json_integer_value(skipJ);
  480. json_t *skipParamJ= json_object_get(stepJ, "skipParam");
  481. if (skipParamJ)
  482. patterns[i].steps[j].skipParam = !!json_integer_value(skipParamJ);
  483. json_t *slideJ= json_object_get(stepJ, "slide");
  484. if (slideJ)
  485. patterns[i].steps[j].slide = !!json_integer_value(slideJ);
  486. json_t *pulsesJ= json_object_get(stepJ, "pulses");
  487. if (pulsesJ)
  488. patterns[i].steps[j].pulses = json_integer_value(pulsesJ);
  489. json_t *pulsesParamJ= json_object_get(stepJ, "pulsesParam");
  490. if (pulsesParamJ)
  491. patterns[i].steps[j].pulsesParam = json_integer_value(pulsesParamJ);
  492. json_t *pitchJ= json_object_get(stepJ, "pitch");
  493. if (pitchJ)
  494. patterns[i].steps[j].pitch = json_real_value(pitchJ);
  495. json_t *typeJ= json_object_get(stepJ, "type");
  496. if (typeJ)
  497. patterns[i].steps[j].type = json_integer_value(typeJ);
  498. json_t *probGateJ= json_object_get(stepJ, "gateProb");
  499. if (probGateJ)
  500. patterns[i].steps[j].gateProb = json_real_value(probGateJ);
  501. json_t *rndPitchJ= json_object_get(stepJ, "pitchRnd");
  502. if (rndPitchJ)
  503. patterns[i].steps[j].pitchRnd = json_real_value(rndPitchJ);
  504. json_t *accentJ= json_object_get(stepJ, "accent");
  505. if (accentJ)
  506. patterns[i].steps[j].accent = json_real_value(accentJ);
  507. json_t *rndAccentJ= json_object_get(stepJ, "rndAccent");
  508. if (rndAccentJ)
  509. patterns[i].steps[j].rndAccent = json_real_value(rndAccentJ);
  510. }
  511. }
  512. }
  513. }
  514. updateFlag = true;
  515. loadedFromJson = true;
  516. }
  517. void randomize() override {
  518. randomizeSlidesSkips();
  519. }
  520. void randomizeSlidesSkips() {
  521. for (int i = 0; i < 8; i++) {
  522. slideState[i] = (randomUniform() > 0.8f) ? 't' : 'f';
  523. skipState[i] = (randomUniform() > 0.85f) ? 't' : 'f';
  524. }
  525. }
  526. void reset() override {
  527. for (int i = 0; i < 8; i++) {
  528. slideState[i] = 'f';
  529. skipState[i] = 'f';
  530. }
  531. }
  532. // Quantization inspired from https://github.com/jeremywen/JW-Modules
  533. float getOneRandomNoteInScale(){
  534. rootNote = clamp(patterns[playedPattern].rootNote + inputs[ROOT_NOTE_INPUT].value, 0.0f, NUM_NOTES-1.0f);
  535. curScaleVal = clamp(patterns[playedPattern].scale + inputs[SCALE_INPUT].value, 0.0f, NUM_SCALES-1.0f);
  536. int *curScaleArr;
  537. int notesInScale = 0;
  538. switch(curScaleVal){
  539. case AEOLIAN: curScaleArr = SCALE_AEOLIAN; notesInScale=LENGTHOF(SCALE_AEOLIAN); break;
  540. case BLUES: curScaleArr = SCALE_BLUES; notesInScale=LENGTHOF(SCALE_BLUES); break;
  541. case CHROMATIC: curScaleArr = SCALE_CHROMATIC; notesInScale=LENGTHOF(SCALE_CHROMATIC); break;
  542. case DIATONIC_MINOR: curScaleArr = SCALE_DIATONIC_MINOR;notesInScale=LENGTHOF(SCALE_DIATONIC_MINOR); break;
  543. case DORIAN: curScaleArr = SCALE_DORIAN; notesInScale=LENGTHOF(SCALE_DORIAN); break;
  544. case HARMONIC_MINOR: curScaleArr = SCALE_HARMONIC_MINOR;notesInScale=LENGTHOF(SCALE_HARMONIC_MINOR); break;
  545. case INDIAN: curScaleArr = SCALE_INDIAN; notesInScale=LENGTHOF(SCALE_INDIAN); break;
  546. case LOCRIAN: curScaleArr = SCALE_LOCRIAN; notesInScale=LENGTHOF(SCALE_LOCRIAN); break;
  547. case LYDIAN: curScaleArr = SCALE_LYDIAN; notesInScale=LENGTHOF(SCALE_LYDIAN); break;
  548. case MAJOR: curScaleArr = SCALE_MAJOR; notesInScale=LENGTHOF(SCALE_MAJOR); break;
  549. case MELODIC_MINOR: curScaleArr = SCALE_MELODIC_MINOR; notesInScale=LENGTHOF(SCALE_MELODIC_MINOR); break;
  550. case MINOR: curScaleArr = SCALE_MINOR; notesInScale=LENGTHOF(SCALE_MINOR); break;
  551. case MIXOLYDIAN: curScaleArr = SCALE_MIXOLYDIAN; notesInScale=LENGTHOF(SCALE_MIXOLYDIAN); break;
  552. case NATURAL_MINOR: curScaleArr = SCALE_NATURAL_MINOR; notesInScale=LENGTHOF(SCALE_NATURAL_MINOR); break;
  553. case PENTATONIC: curScaleArr = SCALE_PENTATONIC; notesInScale=LENGTHOF(SCALE_PENTATONIC); break;
  554. case PHRYGIAN: curScaleArr = SCALE_PHRYGIAN; notesInScale=LENGTHOF(SCALE_PHRYGIAN); break;
  555. case TURKISH: curScaleArr = SCALE_TURKISH; notesInScale=LENGTHOF(SCALE_TURKISH); break;
  556. }
  557. if(curScaleVal == NONE){
  558. return randomUniform() * 6.0f;
  559. } else {
  560. float voltsOut = 0.0f;
  561. int rndOctaveInVolts = int(5 * randomUniform());
  562. voltsOut += rndOctaveInVolts;
  563. voltsOut += rootNote / 12.0f;
  564. voltsOut += curScaleArr[int(notesInScale * randomUniform())] / 12.0f;
  565. return voltsOut;
  566. }
  567. }
  568. float closestVoltageInScale(float voltsIn){
  569. rootNote = clamp(patterns[playedPattern].rootNote + inputs[ROOT_NOTE_INPUT].value, 0.0f, BORDL::NUM_NOTES-1.0f);
  570. curScaleVal = clamp(patterns[playedPattern].scale + inputs[SCALE_INPUT].value, 0.0f, BORDL::NUM_SCALES-1.0f);
  571. int *curScaleArr;
  572. int notesInScale = 0;
  573. switch(curScaleVal){
  574. case AEOLIAN: curScaleArr = SCALE_AEOLIAN; notesInScale=LENGTHOF(SCALE_AEOLIAN); break;
  575. case BLUES: curScaleArr = SCALE_BLUES; notesInScale=LENGTHOF(SCALE_BLUES); break;
  576. case CHROMATIC: curScaleArr = SCALE_CHROMATIC; notesInScale=LENGTHOF(SCALE_CHROMATIC); break;
  577. case DIATONIC_MINOR: curScaleArr = SCALE_DIATONIC_MINOR;notesInScale=LENGTHOF(SCALE_DIATONIC_MINOR); break;
  578. case DORIAN: curScaleArr = SCALE_DORIAN; notesInScale=LENGTHOF(SCALE_DORIAN); break;
  579. case HARMONIC_MINOR: curScaleArr = SCALE_HARMONIC_MINOR;notesInScale=LENGTHOF(SCALE_HARMONIC_MINOR); break;
  580. case INDIAN: curScaleArr = SCALE_INDIAN; notesInScale=LENGTHOF(SCALE_INDIAN); break;
  581. case LOCRIAN: curScaleArr = SCALE_LOCRIAN; notesInScale=LENGTHOF(SCALE_LOCRIAN); break;
  582. case LYDIAN: curScaleArr = SCALE_LYDIAN; notesInScale=LENGTHOF(SCALE_LYDIAN); break;
  583. case MAJOR: curScaleArr = SCALE_MAJOR; notesInScale=LENGTHOF(SCALE_MAJOR); break;
  584. case MELODIC_MINOR: curScaleArr = SCALE_MELODIC_MINOR; notesInScale=LENGTHOF(SCALE_MELODIC_MINOR); break;
  585. case MINOR: curScaleArr = SCALE_MINOR; notesInScale=LENGTHOF(SCALE_MINOR); break;
  586. case MIXOLYDIAN: curScaleArr = SCALE_MIXOLYDIAN; notesInScale=LENGTHOF(SCALE_MIXOLYDIAN); break;
  587. case NATURAL_MINOR: curScaleArr = SCALE_NATURAL_MINOR; notesInScale=LENGTHOF(SCALE_NATURAL_MINOR); break;
  588. case PENTATONIC: curScaleArr = SCALE_PENTATONIC; notesInScale=LENGTHOF(SCALE_PENTATONIC); break;
  589. case PHRYGIAN: curScaleArr = SCALE_PHRYGIAN; notesInScale=LENGTHOF(SCALE_PHRYGIAN); break;
  590. case TURKISH: curScaleArr = SCALE_TURKISH; notesInScale=LENGTHOF(SCALE_TURKISH); break;
  591. case NONE: return voltsIn;
  592. }
  593. float closestVal = 10.0f;
  594. float closestDist = 10.0f;
  595. int octaveInVolts = int(voltsIn);
  596. for (int i = 0; i < notesInScale; i++) {
  597. float scaleNoteInVolts = octaveInVolts + (((pitchQuantizeMode ? rootNote : 0.0f) + curScaleArr[i]) / 12.0f);
  598. float distAway = fabs(voltsIn - scaleNoteInVolts);
  599. if(distAway < closestDist){
  600. closestVal = scaleNoteInVolts;
  601. closestDist = distAway;
  602. }
  603. }
  604. closestVal += pitchQuantizeMode ? 0.0f : (rootNote / 12.0f);
  605. return closestVal;
  606. }
  607. };
  608. void BORDL::step() {
  609. const float lightLambda = 0.075f;
  610. // Run
  611. if (runningTrigger.process(params[RUN_PARAM].value)) {
  612. running = !running;
  613. }
  614. lights[RUNNING_LIGHT].value = running ? 1.0f : 0.0f;
  615. bool nextStep = false;
  616. // Phase calculation
  617. if (running) {
  618. if (inputs[EXT_CLOCK_INPUT].active) {
  619. tCurrent = clock();
  620. float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  621. if (tLastTrig && tPreviousTrig) {
  622. phase = float(tCurrent - tLastTrig) / float(tLastTrig - tPreviousTrig);
  623. }
  624. else {
  625. phase += clockTime / engineGetSampleRate();
  626. }
  627. // External clock
  628. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) {
  629. tPreviousTrig = tLastTrig;
  630. tLastTrig = clock();
  631. phase = 0.0f;
  632. nextStep = true;
  633. }
  634. }
  635. else {
  636. // Internal clock
  637. float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  638. phase += clockTime / engineGetSampleRate();
  639. if (phase >= 1.0f) {
  640. phase--;
  641. nextStep = true;
  642. }
  643. }
  644. }
  645. // Reset
  646. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
  647. phase = 0.0f;
  648. reStart = true;
  649. nextStep = true;
  650. lights[RESET_LIGHT].value = 1.0f;
  651. }
  652. //patternNumber
  653. playedPattern = clamp((inputs[PATTERN_INPUT].active ? rescale(inputs[PATTERN_INPUT].value,0.0f,10.0f,1.0f,16.1f) : params[PATTERN_PARAM].value) - 1.0f, 0.0f, 15.0f);
  654. // Update Pattern
  655. if ((updateFlag) || (!loadedFromJson)) {
  656. // Trigs Update
  657. for (int i = 0; i < 8; i++) {
  658. if (slideTriggers[i].process(params[TRIG_SLIDE_PARAM + i].value)) {
  659. slideState[i] = slideState[i] == 't' ? 'f' : 't';
  660. }
  661. if (skipTriggers[i].process(params[TRIG_SKIP_PARAM + i].value)) {
  662. skipState[i] = skipState[i] == 't' ? 'f' : 't';
  663. }
  664. }
  665. // playMode
  666. if (playModeTrigger.process(params[PLAY_MODE_PARAM].value)) {
  667. playMode = (((int)playMode + 1) % 5);
  668. }
  669. // countMode
  670. if (countModeTrigger.process(params[COUNT_MODE_PARAM].value)) {
  671. countMode = (((int)countMode + 1) % 2);
  672. }
  673. // numSteps
  674. numSteps = clamp(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 16.0f);
  675. UpdatePattern();
  676. if (!loadedFromJson) {
  677. loadedFromJson = true;
  678. updateFlag = true;
  679. }
  680. }
  681. // Steps && Pulses Management
  682. if (nextStep) {
  683. // Advance step
  684. previousPitch = closestVoltageInScale(patterns[playedPattern].CurrentStep().pitch);
  685. prevIndex = index;
  686. auto nextT = patterns[playedPattern].GetNextStep(reStart);
  687. index = std::get<0>(nextT);
  688. pulse = std::get<1>(nextT);
  689. if (reStart) { reStart = false; }
  690. lights[STEPS_LIGHTS+index%8].value = 1.0f;
  691. probGate = index != prevIndex ? randomUniform() <= params[TRIG_GATEPROB_PARAM+index%8].value : probGate;
  692. rndPitch = index != prevIndex ? rescale(randomUniform(),0.0f,1.0f,params[TRIG_PITCHRND_PARAM+index%8].value*-5.0f,params[TRIG_PITCHRND_PARAM+index%8].value*5.0f) : rndPitch;
  693. accent = index != prevIndex ? clamp(params[TRIG_ACCENT_PARAM+index%8].value + rescale(randomUniform(),0.0f,1.0f,params[TRIG_RNDACCENT_PARAM+index%8].value*-5.0f,params[TRIG_RNDACCENT_PARAM+index%8].value*5.0f),0.0f,10.0f) : accent;
  694. }
  695. // Lights
  696. for (int i = 0; i < 8; i++) {
  697. lights[STEPS_LIGHTS + i].value -= lights[STEPS_LIGHTS + i].value / lightLambda / engineGetSampleRate();
  698. lights[SLIDES_LIGHTS + i].value = slideState[i] == 't' ? 1.0f - lights[STEPS_LIGHTS + i].value : lights[STEPS_LIGHTS + i].value;
  699. lights[SKIPS_LIGHTS + i].value = skipState[i]== 't' ? 1.0f - lights[STEPS_LIGHTS + i].value : lights[STEPS_LIGHTS + i].value;
  700. }
  701. lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / lightLambda / engineGetSampleRate();
  702. // Caclulate Outputs
  703. bool gateOn = running && (!patterns[playedPattern].CurrentStep().skip);
  704. float gateValue = 0.0f;
  705. if (gateOn){
  706. if (patterns[playedPattern].CurrentStep().type == 0) {
  707. gateOn = false;
  708. }
  709. else if (((patterns[playedPattern].CurrentStep().type == 1) && (pulse == 0))
  710. || (patterns[playedPattern].CurrentStep().type == 2)
  711. || ((patterns[playedPattern].CurrentStep().type == 3) && (pulse == patterns[playedPattern].CurrentStep().pulses))) {
  712. float gateCoeff = clamp(patterns[playedPattern].gateTime - 0.02f + inputs[GATE_TIME_INPUT].value /10.0f, 0.0f, 0.99f);
  713. gateOn = phase < gateCoeff;
  714. gateValue = 10.0f;
  715. }
  716. else if (patterns[playedPattern].CurrentStep().type == 3) {
  717. gateOn = true;
  718. gateValue = 10.0f;
  719. }
  720. else if (patterns[playedPattern].CurrentStep().type == 4) {
  721. gateOn = true;
  722. gateValue = inputs[EXTGATE1_INPUT].value;
  723. }
  724. else if (patterns[playedPattern].CurrentStep().type == 5) {
  725. gateOn = true;
  726. gateValue = inputs[EXTGATE2_INPUT].value;
  727. }
  728. else {
  729. gateOn = false;
  730. gateValue = 0.0f;
  731. }
  732. }
  733. //pitch management
  734. pitch = closestVoltageInScale(clamp(patterns[playedPattern].CurrentStep().pitch + rndPitch,0.0f,10.0f) * patterns[playedPattern].sensitivity);
  735. if (patterns[playedPattern].CurrentStep().slide) {
  736. if (pulse == 0) {
  737. float slideCoeff = clamp(patterns[playedPattern].slideTime - 0.01f + inputs[SLIDE_TIME_INPUT].value /10.0f, -0.1f, 0.99f);
  738. pitch = pitch - (1.0f - powf(phase, slideCoeff)) * (pitch - previousPitch);
  739. }
  740. }
  741. // Update Outputs
  742. outputs[GATE_OUTPUT].value = gateOn ? (probGate ? gateValue : 0.0f) : 0.0f;
  743. outputs[PITCH_OUTPUT].value = pitchMode ? pitch : (gateOn ? pitch : 0.0f);
  744. outputs[ACC_OUTPUT].value = gateOn ? (probGate ? accent : 0.0f) : 0.0f;
  745. }
  746. struct BORDLDisplay : TransparentWidget {
  747. BORDL *module;
  748. int frame = 0;
  749. shared_ptr<Font> font;
  750. string note, scale, steps, playMode, selectedPattern, playedPattern;
  751. BORDLDisplay() {
  752. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  753. }
  754. void drawMessage(NVGcontext *vg, Vec pos, string note, string playMode, string selectedPattern, string playedPattern, string steps, string scale) {
  755. nvgFontSize(vg, 18.0f);
  756. nvgFontFaceId(vg, font->handle);
  757. nvgTextLetterSpacing(vg, -2.0f);
  758. nvgFillColor(vg, YELLOW_BIDOO);
  759. nvgText(vg, pos.x + 4.0f, pos.y + 8.0f, playMode.c_str(), NULL);
  760. nvgFontSize(vg, 14.0f);
  761. nvgFillColor(vg, YELLOW_BIDOO);
  762. nvgText(vg, pos.x + 91.0f, pos.y + 7.0f, selectedPattern.c_str(), NULL);
  763. nvgText(vg, pos.x + 31.0f, pos.y + 7.0f, steps.c_str(), NULL);
  764. nvgText(vg, pos.x + 3.0f, pos.y + 23.0f, note.c_str(), NULL);
  765. nvgText(vg, pos.x + 25.0f, pos.y + 23.0f, scale.c_str(), NULL);
  766. nvgFillColor(vg, YELLOW_BIDOO);
  767. nvgText(vg, pos.x + 116.0f, pos.y + 7.0f, playedPattern.c_str(), NULL);
  768. }
  769. string displayRootNote(int value) {
  770. switch(value){
  771. case BORDL::NOTE_C: return "C";
  772. case BORDL::NOTE_C_SHARP: return "C#";
  773. case BORDL::NOTE_D: return "D";
  774. case BORDL::NOTE_D_SHARP: return "D#";
  775. case BORDL::NOTE_E: return "E";
  776. case BORDL::NOTE_F: return "F";
  777. case BORDL::NOTE_F_SHARP: return "F#";
  778. case BORDL::NOTE_G: return "G";
  779. case BORDL::NOTE_G_SHARP: return "G#";
  780. case BORDL::NOTE_A: return "A";
  781. case BORDL::NOTE_A_SHARP: return "A#";
  782. case BORDL::NOTE_B: return "B";
  783. default: return "";
  784. }
  785. }
  786. string displayScale(int value) {
  787. switch(value){
  788. case BORDL::AEOLIAN: return "Aeolian";
  789. case BORDL::BLUES: return "Blues";
  790. case BORDL::CHROMATIC: return "Chromatic";
  791. case BORDL::DIATONIC_MINOR: return "Diatonic Minor";
  792. case BORDL::DORIAN: return "Dorian";
  793. case BORDL::HARMONIC_MINOR: return "Harmonic Minor";
  794. case BORDL::INDIAN: return "Indian";
  795. case BORDL::LOCRIAN: return "Locrian";
  796. case BORDL::LYDIAN: return "Lydian";
  797. case BORDL::MAJOR: return "Major";
  798. case BORDL::MELODIC_MINOR: return "Melodic Minor";
  799. case BORDL::MINOR: return "Minor";
  800. case BORDL::MIXOLYDIAN: return "Mixolydian";
  801. case BORDL::NATURAL_MINOR: return "Natural Minor";
  802. case BORDL::PENTATONIC: return "Pentatonic";
  803. case BORDL::PHRYGIAN: return "Phrygian";
  804. case BORDL::TURKISH: return "Turkish";
  805. case BORDL::NONE: return "None";
  806. default: return "";
  807. }
  808. }
  809. string displayPlayMode(int value) {
  810. switch(value){
  811. case 0: return "►";
  812. case 1: return "◄";
  813. case 2: return "►◄";
  814. case 3: return "►*";
  815. case 4: return "►?";
  816. default: return "";
  817. }
  818. }
  819. void draw(NVGcontext *vg) override {
  820. if (++frame >= 4) {
  821. frame = 0;
  822. note = displayRootNote(module->patterns[module->selectedPattern].rootNote);
  823. steps = (module->patterns[module->selectedPattern].countMode == 0 ? "steps:" : "pulses:" ) + to_string(module->patterns[module->selectedPattern].numberOfStepsParam);
  824. playMode = displayPlayMode(module->patterns[module->selectedPattern].playMode);
  825. scale = displayScale(module->patterns[module->selectedPattern].scale);
  826. selectedPattern = "P" + to_string(module->selectedPattern + 1);
  827. playedPattern = "P" + to_string(module->playedPattern + 1);
  828. }
  829. drawMessage(vg, Vec(0.0f, 20.0f), note, playMode, selectedPattern, playedPattern, steps, scale);
  830. }
  831. };
  832. struct BORDLGateDisplay : TransparentWidget {
  833. BORDL *module;
  834. shared_ptr<Font> font;
  835. int index;
  836. BORDLGateDisplay() {
  837. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  838. }
  839. void drawGate(NVGcontext *vg, Vec pos) {
  840. int gateType = (int)module->params[BORDL::TRIG_TYPE_PARAM+index].value;
  841. nvgStrokeWidth(vg, 1.0f);
  842. nvgStrokeColor(vg, YELLOW_BIDOO);
  843. nvgFillColor(vg, YELLOW_BIDOO);
  844. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  845. nvgFontSize(vg, 16.0f);
  846. nvgFontFaceId(vg, font->handle);
  847. nvgTextLetterSpacing(vg, -2.0f);
  848. if (gateType == 0) {
  849. nvgBeginPath(vg);
  850. nvgRoundedRect(vg,pos.x,pos.y,22.0f,6.0f,0.0f);
  851. nvgClosePath(vg);
  852. nvgStroke(vg);
  853. }
  854. else if (gateType == 1) {
  855. nvgBeginPath(vg);
  856. nvgRoundedRect(vg,pos.x,pos.y,22.0f,6.0f,0.0f);
  857. nvgClosePath(vg);
  858. nvgStroke(vg);
  859. nvgBeginPath(vg);
  860. nvgRoundedRect(vg,pos.x,pos.y,6.0f,6.0f,0.0f);
  861. nvgClosePath(vg);
  862. nvgStroke(vg);
  863. nvgFill(vg);
  864. }
  865. else if (gateType == 2) {
  866. nvgBeginPath(vg);
  867. nvgRoundedRect(vg,pos.x,pos.y,6.0f,6.0f,0.0f);
  868. nvgRoundedRect(vg,pos.x+8.0f,pos.y,6.0f,6.0f,0.0f);
  869. nvgRoundedRect(vg,pos.x+16.0f,pos.y,6.0f,6.0f,0.0f);
  870. nvgClosePath(vg);
  871. nvgStroke(vg);
  872. nvgFill(vg);
  873. }
  874. else if (gateType == 3) {
  875. nvgBeginPath(vg);
  876. nvgRoundedRect(vg,pos.x,pos.y,22.0f,6.0f,0.0f);
  877. nvgClosePath(vg);
  878. nvgStroke(vg);
  879. nvgFill(vg);
  880. }
  881. else if (gateType == 4) {
  882. nvgText(vg, pos.x+11.0f, pos.y+8.0f, "G1", NULL);
  883. }
  884. else if (gateType == 5) {
  885. nvgText(vg, pos.x+11.0f, pos.y+8.0f, "G2", NULL);
  886. }
  887. }
  888. void draw(NVGcontext *vg) override {
  889. drawGate(vg, Vec(0.0f, 0.0f));
  890. }
  891. };
  892. struct BORDLPulseDisplay : TransparentWidget {
  893. BORDL *module;
  894. shared_ptr<Font> font;
  895. int index;
  896. BORDLPulseDisplay() {
  897. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  898. }
  899. void drawPulse(NVGcontext *vg, Vec pos) {
  900. nvgStrokeWidth(vg, 1.0f);
  901. nvgStrokeColor(vg, YELLOW_BIDOO);
  902. nvgFillColor(vg, YELLOW_BIDOO);
  903. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  904. nvgFontSize(vg, 16.0f);
  905. nvgFontFaceId(vg, font->handle);
  906. nvgTextLetterSpacing(vg, -2.0f);
  907. char tCount[128],tProb[128];
  908. snprintf(tCount, sizeof(tCount), "%1i", (int)module->params[BORDL::TRIG_COUNT_PARAM+index].value);
  909. snprintf(tProb, sizeof(tProb), "%1i%%", (int)(module->params[BORDL::TRIG_GATEPROB_PARAM+index].value*100.0f));
  910. nvgText(vg, pos.x, pos.y, tCount, NULL);
  911. nvgFontSize(vg, 12.0f);
  912. nvgText(vg, pos.x, pos.y+12.0f, tProb, NULL);
  913. }
  914. void draw(NVGcontext *vg) override {
  915. drawPulse(vg, Vec(0.0f, 0.0f));
  916. }
  917. };
  918. struct BORDLPitchDisplay : TransparentWidget {
  919. BORDL *module;
  920. shared_ptr<Font> font;
  921. int index;
  922. BORDLPitchDisplay() {
  923. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  924. }
  925. void drawPitch(NVGcontext *vg, Vec pos) {
  926. nvgStrokeWidth(vg, 1.0f);
  927. nvgStrokeColor(vg, YELLOW_BIDOO);
  928. nvgFillColor(vg, YELLOW_BIDOO);
  929. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  930. nvgFontSize(vg, 14.0f);
  931. nvgFontFaceId(vg, font->handle);
  932. nvgTextLetterSpacing(vg, -2.0f);
  933. char tPitch[128],tPitchRnd[128],tAcc[128],tAccRnd[128];
  934. snprintf(tPitch, sizeof(tPitch), "%1.2f", module->closestVoltageInScale(module->params[BORDL::TRIG_PITCH_PARAM+index].value));
  935. snprintf(tPitchRnd, sizeof(tPitchRnd), "%1i%%", (int)(module->params[BORDL::TRIG_PITCHRND_PARAM+index].value*100));
  936. snprintf(tAcc, sizeof(tAcc), "%1.2f", module->params[BORDL::TRIG_ACCENT_PARAM+index].value);
  937. snprintf(tAccRnd, sizeof(tAccRnd), "%1i%%", (int)(module->params[BORDL::TRIG_RNDACCENT_PARAM+index].value*100));
  938. nvgText(vg, pos.x, pos.y-9.0f, tPitch, NULL);
  939. nvgText(vg, pos.x, pos.y+15.0f, tAcc, NULL);
  940. nvgFontSize(vg, 12.0f);
  941. nvgText(vg, pos.x, pos.y+2.0f, tPitchRnd, NULL);
  942. nvgText(vg, pos.x, pos.y+25.0f, tAccRnd, NULL);
  943. }
  944. void draw(NVGcontext *vg) override {
  945. drawPitch(vg, Vec(0.0f, 0.0f));
  946. }
  947. };
  948. struct BORDLWidget : ModuleWidget {
  949. ParamWidget *stepsParam, *scaleParam, *rootNoteParam, *sensitivityParam,
  950. *gateTimeParam, *slideTimeParam, *playModeParam, *countModeParam, *patternParam,
  951. *pitchParams[8], *pulseParams[8], *typeParams[8], *slideParams[8], *skipParams[8],
  952. *pitchRndParams[8], *pulseProbParams[8], *accentParams[8], *rndAccentParams[8];
  953. BORDLWidget(BORDL *module);
  954. Menu *createContextMenu() override;
  955. };
  956. struct BORDLPatternRoundBlackSnapKnob : RoundBlackSnapKnob {
  957. void onChange(EventChange &e) override {
  958. RoundBlackSnapKnob::onChange(e);
  959. BORDL *module = dynamic_cast<BORDL*>(this->module);
  960. BORDLWidget *parent = dynamic_cast<BORDLWidget*>(this->parent);
  961. int target = clamp(value - 1.0f, 0.0f, 15.0f);
  962. if (module && parent && (target != module->selectedPattern) && module->updateFlag)
  963. {
  964. module->updateFlag = false;
  965. module->selectedPattern = value - 1;
  966. parent->stepsParam->setValue(module->patterns[target].numberOfStepsParam);
  967. parent->rootNoteParam->setValue(module->patterns[target].rootNote);
  968. parent->scaleParam->setValue(module->patterns[target].scale);
  969. parent->gateTimeParam->setValue(module->patterns[target].gateTime);
  970. parent->slideTimeParam->setValue(module->patterns[target].slideTime);
  971. parent->sensitivityParam->setValue(module->patterns[target].sensitivity);
  972. module->playMode = module->patterns[module->selectedPattern].playMode;
  973. module->countMode = module->patterns[module->selectedPattern].countMode;
  974. for (int i = 0; i < 8; i++) {
  975. parent->pitchParams[i]->setValue(module->patterns[target].steps[i].pitch);
  976. parent->pulseParams[i]->setValue(module->patterns[target].steps[i].pulsesParam);
  977. parent->typeParams[i]->setValue(module->patterns[target].steps[i].type);
  978. module->skipState[i] = module->patterns[target].steps[i].skipParam ? 't' : 'f';
  979. module->slideState[i] = module->patterns[target].steps[i].slide ? 't' : 'f';
  980. parent->pulseProbParams[i]->setValue(module->patterns[target].steps[i].gateProb);
  981. parent->pitchRndParams[i]->setValue(module->patterns[target].steps[i].pitchRnd);
  982. parent->accentParams[i]->setValue(module->patterns[target].steps[i].accent);
  983. parent->rndAccentParams[i]->setValue(module->patterns[target].steps[i].rndAccent);
  984. }
  985. module->updateFlag = true;
  986. }
  987. }
  988. };
  989. BORDLWidget::BORDLWidget(BORDL *module) : ModuleWidget(module) {
  990. setPanel(SVG::load(assetPlugin(plugin, "res/BORDL.svg")));
  991. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  992. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  993. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  994. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  995. {
  996. BORDLDisplay *display = new BORDLDisplay();
  997. display->module = module;
  998. display->box.pos = Vec(20.0f, 253.0f);
  999. display->box.size = Vec(250.0f, 60.0f);
  1000. addChild(display);
  1001. }
  1002. addParam(ParamWidget::create<RoundBlackKnob>(Vec(17.0f, 52.0f), module, BORDL::CLOCK_PARAM, -2.0f, 6.0f, 2.0f));
  1003. addParam(ParamWidget::create<LEDButton>(Vec(61.0f, 56.0f), module, BORDL::RUN_PARAM, 0.0f, 1.0f, 0.0f));
  1004. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(67.0f, 62.0f), module, BORDL::RUNNING_LIGHT));
  1005. addParam(ParamWidget::create<LEDButton>(Vec(99.0f, 56.0f), module, BORDL::RESET_PARAM, 0.0f, 1.0f, 0.0f));
  1006. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(105.0f, 62.0f), module, BORDL::RESET_LIGHT));
  1007. stepsParam = ParamWidget::create<BidooBlueSnapKnob>(Vec(134.0f, 52.0f), module, BORDL::STEPS_PARAM, 1.0f, 16.0f, 8.0f);
  1008. addParam(stepsParam);
  1009. static const float portX0[4] = {20.0f, 58.0f, 96.0f, 135.0f};
  1010. addInput(Port::create<PJ301MPort>(Vec(portX0[0], 90.0f), Port::INPUT, module, BORDL::CLOCK_INPUT));
  1011. addInput(Port::create<PJ301MPort>(Vec(portX0[1], 90.0f), Port::INPUT, module, BORDL::EXT_CLOCK_INPUT));
  1012. addInput(Port::create<PJ301MPort>(Vec(portX0[2], 90.0f), Port::INPUT, module, BORDL::RESET_INPUT));
  1013. addInput(Port::create<PJ301MPort>(Vec(portX0[3], 90.0f), Port::INPUT, module, BORDL::STEPS_INPUT));
  1014. rootNoteParam = ParamWidget::create<BidooBlueSnapKnob>(Vec(portX0[0]-2.0f, 140.0f), module, BORDL::ROOT_NOTE_PARAM, 0.0f, BORDL::NUM_NOTES-0.9f, 0.0f);
  1015. addParam(rootNoteParam);
  1016. scaleParam = ParamWidget::create<BidooBlueSnapKnob>(Vec(portX0[1]-2.0f, 140.0f), module, BORDL::SCALE_PARAM, 0.0f, BORDL::NUM_SCALES-0.9f, 0.0f);
  1017. addParam(scaleParam);
  1018. gateTimeParam = ParamWidget::create<BidooBlueKnob>(Vec(portX0[2]-2.0f, 140.0f), module, BORDL::GATE_TIME_PARAM, 0.1f, 1.0f, 0.5f);
  1019. addParam(gateTimeParam);
  1020. slideTimeParam = ParamWidget::create<BidooBlueKnob>(Vec(portX0[3]-2.0f, 140.0f), module, BORDL::SLIDE_TIME_PARAM , 0.1f, 1.0f, 0.2f);
  1021. addParam(slideTimeParam);
  1022. addInput(Port::create<PJ301MPort>(Vec(portX0[0], 180.0f), Port::INPUT, module, BORDL::ROOT_NOTE_INPUT));
  1023. addInput(Port::create<PJ301MPort>(Vec(portX0[1], 180.0f), Port::INPUT, module, BORDL::SCALE_INPUT));
  1024. addInput(Port::create<PJ301MPort>(Vec(portX0[2], 180.0f), Port::INPUT, module, BORDL::GATE_TIME_INPUT));
  1025. addInput(Port::create<PJ301MPort>(Vec(portX0[3], 180.0f), Port::INPUT, module, BORDL::SLIDE_TIME_INPUT));
  1026. playModeParam = ParamWidget::create<BlueCKD6>(Vec(portX0[0]-1.0f, 230.0f), module, BORDL::PLAY_MODE_PARAM, 0.0f, 4.0f, 0.0f);
  1027. addParam(playModeParam);
  1028. countModeParam = ParamWidget::create<BlueCKD6>(Vec(portX0[1]-1.0f, 230.0f), module, BORDL::COUNT_MODE_PARAM, 0.0f, 4.0f, 0.0f);
  1029. addParam(countModeParam);
  1030. addInput(Port::create<PJ301MPort>(Vec(portX0[2], 232.0f), Port::INPUT, module, BORDL::PATTERN_INPUT));
  1031. patternParam = ParamWidget::create<BORDLPatternRoundBlackSnapKnob>(Vec(portX0[3],230.0f), module, BORDL::PATTERN_PARAM, 1.0f, 16.0f, 1.0f);
  1032. addParam(patternParam);
  1033. static const float portX1[8] = {200.0f, 238.0f, 276.0f, 315.0f, 353.0f, 392.0f, 430.0f, 469.0f};
  1034. sensitivityParam = ParamWidget::create<BidooBlueTrimpot>(Vec(portX1[0]-24.0f, 32.0f), module, BORDL::SENSITIVITY_PARAM, 0.1f, 1.0f, 1.0f);
  1035. addParam(sensitivityParam);
  1036. for (int i = 0; i < 8; i++) {
  1037. pitchParams[i] = ParamWidget::create<BidooBlueKnob>(Vec(portX1[i]+1.0f, 76.0f), module, BORDL::TRIG_PITCH_PARAM + i, 0.0f, 10.001f, 3.0f);
  1038. addParam(pitchParams[i]);
  1039. pitchRndParams[i] = ParamWidget::create<BidooBlueTrimpot>(Vec(portX1[i]+6.5f, 108.0f), module, BORDL::TRIG_PITCHRND_PARAM + i, 0.0f, 1.0f, 0.0f);
  1040. addParam(pitchRndParams[i]);
  1041. accentParams[i] = ParamWidget::create<BidooBlueKnob>(Vec(portX1[i]+1.0f, 129.0f), module, BORDL::TRIG_ACCENT_PARAM + i, 0.0f, 10.0f, 0.0f);
  1042. addParam(accentParams[i]);
  1043. rndAccentParams[i] = ParamWidget::create<BidooBlueTrimpot>(Vec(portX1[i]+6.5f, 160.0f), module, BORDL::TRIG_RNDACCENT_PARAM + i, 0.0f, 1.0f, 0.0f);
  1044. addParam(rndAccentParams[i]);
  1045. {
  1046. BORDLPitchDisplay *displayPitch = new BORDLPitchDisplay();
  1047. displayPitch->module = module;
  1048. displayPitch->box.pos = Vec(portX1[i]+15.0f, 45.0f);
  1049. displayPitch->box.size = Vec(20.0f, 10.0f);
  1050. displayPitch->index = i;
  1051. addChild(displayPitch);
  1052. }
  1053. pulseParams[i] = ParamWidget::create<BidooBlueSnapKnob>(Vec(portX1[i]+1.0f, 216.0f), module, BORDL::TRIG_COUNT_PARAM + i, 1.0f, 8.0f, 1.0f);
  1054. addParam(pulseParams[i]);
  1055. pulseProbParams[i] = ParamWidget::create<BidooBlueTrimpot>(Vec(portX1[i]+6.5f, 247.0f), module, BORDL::TRIG_GATEPROB_PARAM + i, 0.0f, 1.0f, 1.0f);
  1056. addParam(pulseProbParams[i]);
  1057. {
  1058. BORDLPulseDisplay *displayPulse = new BORDLPulseDisplay();
  1059. displayPulse->module = module;
  1060. displayPulse->box.pos = Vec(portX1[i]+15.0f, 197.0f);
  1061. displayPulse->box.size = Vec(20.0f, 10.0f);
  1062. displayPulse->index = i;
  1063. addChild(displayPulse);
  1064. }
  1065. typeParams[i] = ParamWidget::create<BidooBlueSnapKnob>(Vec(portX1[i]+1.0f, 288.0f), module, BORDL::TRIG_TYPE_PARAM + i, 0.0f, 5.0f, 2.0f);
  1066. addParam(typeParams[i]);
  1067. {
  1068. BORDLGateDisplay *displayGate = new BORDLGateDisplay();
  1069. displayGate->module = module;
  1070. displayGate->box.pos = Vec(portX1[i]+5.0f, 275.0f);
  1071. displayGate->box.size = Vec(20.0f, 10.0f);
  1072. displayGate->index = i;
  1073. addChild(displayGate);
  1074. }
  1075. slideParams[i] = ParamWidget::create<LEDButton>(Vec(portX1[i]+7.0f, 320.0f), module, BORDL::TRIG_SLIDE_PARAM + i, 0.0f, 1.0f, 0.0f);
  1076. addParam(slideParams[i]);
  1077. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(portX1[i]+13.0f, 326.0f), module, BORDL::SLIDES_LIGHTS + i));
  1078. skipParams[i] = ParamWidget::create<LEDButton>(Vec(portX1[i]+7.0f, 341.0f), module, BORDL::TRIG_SKIP_PARAM + i, 0.0f, 1.0f, 0.0f);
  1079. addParam(skipParams[i]);
  1080. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(portX1[i]+13.0f, 347.0f), module, BORDL::SKIPS_LIGHTS + i));
  1081. }
  1082. addInput(Port::create<PJ301MPort>(Vec(10.0f, 331.0f), Port::INPUT, module, BORDL::EXTGATE1_INPUT));
  1083. addInput(Port::create<PJ301MPort>(Vec(43.0f, 331.0f), Port::INPUT, module, BORDL::EXTGATE2_INPUT));
  1084. addOutput(Port::create<PJ301MPort>(Vec(76.5f, 331.0f), Port::OUTPUT, module, BORDL::GATE_OUTPUT));
  1085. addOutput(Port::create<PJ301MPort>(Vec(109.5f, 331.0f), Port::OUTPUT, module, BORDL::PITCH_OUTPUT));
  1086. addOutput(Port::create<PJ301MPort>(Vec(143.0f, 331.0f), Port::OUTPUT, module, BORDL::ACC_OUTPUT));
  1087. }
  1088. struct BORDLRandPitchItem : MenuItem {
  1089. BORDLWidget *bordlWidget;
  1090. void onAction(EventAction &e) override {
  1091. for (int i = 0; i < 8; i++){
  1092. int index = BORDL::TRIG_PITCH_PARAM + i;
  1093. auto it = std::find_if(bordlWidget->params.begin(), bordlWidget->params.end(), [&index](const ParamWidget* m) -> bool { return m->paramId == index; });
  1094. if (it != bordlWidget->params.end())
  1095. {
  1096. auto index = std::distance(bordlWidget->params.begin(), it);
  1097. bordlWidget->params[index]->randomize();
  1098. }
  1099. }
  1100. }
  1101. };
  1102. struct BORDLRandGatesItem : MenuItem {
  1103. BORDLWidget *bordlWidget;
  1104. void onAction(EventAction &e) override {
  1105. for (int i = 0; i < 8; i++){
  1106. int index = BORDL::TRIG_COUNT_PARAM + i;
  1107. auto it = std::find_if(bordlWidget->params.begin(), bordlWidget->params.end(), [&index](const ParamWidget* m) -> bool { return m->paramId == index; });
  1108. if (it != bordlWidget->params.end())
  1109. {
  1110. auto index = std::distance(bordlWidget->params.begin(), it);
  1111. bordlWidget->params[index]->randomize();
  1112. }
  1113. }
  1114. for (int i = 0; i < 8; i++){
  1115. int index = BORDL::TRIG_TYPE_PARAM + i;
  1116. auto it = std::find_if(bordlWidget->params.begin(), bordlWidget->params.end(), [&index](const ParamWidget* m) -> bool { return m->paramId == index; });
  1117. if (it != bordlWidget->params.end())
  1118. {
  1119. auto index = std::distance(bordlWidget->params.begin(), it);
  1120. bordlWidget->params[index]->randomize();
  1121. }
  1122. }
  1123. }
  1124. };
  1125. struct BORDLRandSlideSkipItem : MenuItem {
  1126. BORDL *bordlModule;
  1127. void onAction(EventAction &e) override {
  1128. bordlModule->randomizeSlidesSkips();
  1129. }
  1130. };
  1131. struct BORDLPitchModeItem : MenuItem {
  1132. BORDL *bordlModule;
  1133. void onAction(EventAction &e) override {
  1134. bordlModule->pitchMode = !bordlModule->pitchMode;
  1135. }
  1136. void step() override {
  1137. rightText = bordlModule->pitchMode ? "✔" : "";
  1138. MenuItem::step();
  1139. }
  1140. };
  1141. struct BORDLPitchQuantizeModeItem : MenuItem {
  1142. BORDL *bordlModule;
  1143. void onAction(EventAction &e) override {
  1144. bordlModule->pitchQuantizeMode = !bordlModule->pitchQuantizeMode;
  1145. }
  1146. void step() override {
  1147. rightText = bordlModule->pitchQuantizeMode ? "✔" : "";
  1148. MenuItem::step();
  1149. }
  1150. };
  1151. struct DisconnectMenuItem : MenuItem {
  1152. ModuleWidget *moduleWidget;
  1153. void onAction(EventAction &e) override {
  1154. moduleWidget->disconnect();
  1155. }
  1156. };
  1157. struct ResetMenuItem : MenuItem {
  1158. BORDLWidget *bordlWidget;
  1159. BORDL *bordlModule;
  1160. void onAction(EventAction &e) override {
  1161. for (int i = 0; i < BORDL::NUM_PARAMS; i++){
  1162. if (i != BORDL::PATTERN_PARAM) {
  1163. auto it = std::find_if(bordlWidget->params.begin(), bordlWidget->params.end(), [&i](const ParamWidget* m) -> bool { return m->paramId == i; });
  1164. if (it != bordlWidget->params.end())
  1165. {
  1166. auto index = std::distance(bordlWidget->params.begin(), it);
  1167. bordlWidget->params[index]->setValue(bordlWidget->params[index]->defaultValue);
  1168. }
  1169. }
  1170. }
  1171. bordlModule->updateFlag = false;
  1172. bordlModule->reset();
  1173. bordlModule->playMode = 0;
  1174. bordlModule->countMode = 0;
  1175. bordlModule->updateFlag = true;
  1176. }
  1177. };
  1178. struct RandomizeMenuItem : MenuItem {
  1179. ModuleWidget *moduleWidget;
  1180. void onAction(EventAction &e) override {
  1181. moduleWidget->randomize();
  1182. }
  1183. };
  1184. struct CloneMenuItem : MenuItem {
  1185. ModuleWidget *moduleWidget;
  1186. void onAction(EventAction &e) override {
  1187. RACK_PLUGIN_UI_RACKWIDGET->cloneModule(moduleWidget);
  1188. }
  1189. };
  1190. struct DeleteMenuItem : MenuItem {
  1191. ModuleWidget *moduleWidget;
  1192. void onAction(EventAction &e) override {
  1193. RACK_PLUGIN_UI_RACKWIDGET->deleteModule(moduleWidget);
  1194. moduleWidget->finalizeEvents();
  1195. delete moduleWidget;
  1196. }
  1197. };
  1198. struct BORDLCopyItem : MenuItem {
  1199. BORDL *bordlModule;
  1200. void onAction(EventAction &e) override {
  1201. bordlModule->copyPattern = bordlModule->selectedPattern;
  1202. }
  1203. };
  1204. struct BORDLPasteItem : MenuItem {
  1205. BORDL *bordlModule;
  1206. BORDLWidget *bordlWidget;
  1207. void onAction(EventAction &e) override {
  1208. if (bordlModule && bordlWidget && (bordlModule->copyPattern != bordlModule->selectedPattern) && bordlModule->updateFlag)
  1209. {
  1210. bordlModule->updateFlag = false;
  1211. bordlWidget->stepsParam->setValue(bordlModule->patterns[bordlModule->copyPattern].numberOfStepsParam);
  1212. bordlWidget->rootNoteParam->setValue(bordlModule->patterns[bordlModule->copyPattern].rootNote);
  1213. bordlWidget->scaleParam->setValue(bordlModule->patterns[bordlModule->copyPattern].scale);
  1214. bordlWidget->gateTimeParam->setValue(bordlModule->patterns[bordlModule->copyPattern].gateTime);
  1215. bordlWidget->slideTimeParam->setValue(bordlModule->patterns[bordlModule->copyPattern].slideTime);
  1216. bordlWidget->sensitivityParam->setValue(bordlModule->patterns[bordlModule->copyPattern].sensitivity);
  1217. bordlModule->playMode = bordlModule->patterns[bordlModule->copyPattern].playMode;
  1218. bordlModule->countMode = bordlModule->patterns[bordlModule->copyPattern].countMode;
  1219. for (int i = 0; i < 8; i++) {
  1220. bordlWidget->pitchParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].pitch);
  1221. bordlWidget->pulseParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].pulsesParam);
  1222. bordlWidget->typeParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].type);
  1223. bordlModule->skipState[i] = bordlModule->patterns[bordlModule->copyPattern].steps[i].skipParam ? 't' : 'f';
  1224. bordlModule->slideState[i] = bordlModule->patterns[bordlModule->copyPattern].steps[i].slide ? 't' : 'f';
  1225. bordlWidget->pulseProbParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].gateProb);
  1226. bordlWidget->pitchRndParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].pitchRnd);
  1227. bordlWidget->accentParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].accent);
  1228. bordlWidget->rndAccentParams[i]->setValue(bordlModule->patterns[bordlModule->copyPattern].steps[i].rndAccent);
  1229. }
  1230. bordlModule->updateFlag = true;
  1231. }
  1232. }
  1233. };
  1234. Menu *BORDLWidget::createContextMenu() {
  1235. BORDLWidget *bordlWidget = dynamic_cast<BORDLWidget*>(this);
  1236. assert(bordlWidget);
  1237. BORDL *bordlModule = dynamic_cast<BORDL*>(module);
  1238. assert(bordlModule);
  1239. Menu *menu = rack::global_ui->ui.gScene->createMenu();
  1240. MenuLabel *menuLabel = new MenuLabel();
  1241. menuLabel->text = model->author + " " + model->name;
  1242. menu->addChild(menuLabel);
  1243. ResetMenuItem *resetItem = new ResetMenuItem();
  1244. resetItem->text = "Initialize";
  1245. resetItem->rightText = "+I";
  1246. resetItem->bordlWidget = this;
  1247. resetItem->bordlModule = bordlModule;
  1248. menu->addChild(resetItem);
  1249. DisconnectMenuItem *disconnectItem = new DisconnectMenuItem();
  1250. disconnectItem->text = "Disconnect cables";
  1251. disconnectItem->moduleWidget = this;
  1252. menu->addChild(disconnectItem);
  1253. CloneMenuItem *cloneItem = new CloneMenuItem();
  1254. cloneItem->text = "Duplicate";
  1255. cloneItem->rightText = "+D";
  1256. cloneItem->moduleWidget = this;
  1257. menu->addChild(cloneItem);
  1258. DeleteMenuItem *deleteItem = new DeleteMenuItem();
  1259. deleteItem->text = "Delete";
  1260. deleteItem->rightText = "Backspace/Delete";
  1261. deleteItem->moduleWidget = this;
  1262. menu->addChild(deleteItem);
  1263. MenuLabel *spacerLabel = new MenuLabel();
  1264. menu->addChild(spacerLabel);
  1265. BORDLRandPitchItem *randomizePitchItem = new BORDLRandPitchItem();
  1266. randomizePitchItem->text = "Randomize pitch";
  1267. randomizePitchItem->bordlWidget = bordlWidget;
  1268. menu->addChild(randomizePitchItem);
  1269. BORDLRandGatesItem *randomizeGatesItem = new BORDLRandGatesItem();
  1270. randomizeGatesItem->text = "Randomize gates";
  1271. randomizeGatesItem->bordlWidget = bordlWidget;
  1272. menu->addChild(randomizeGatesItem);
  1273. BORDLRandSlideSkipItem *randomizeSlideSkipItem = new BORDLRandSlideSkipItem();
  1274. randomizeSlideSkipItem->text = "Randomize slides and skips";
  1275. randomizeSlideSkipItem->bordlModule = bordlModule;
  1276. menu->addChild(randomizeSlideSkipItem);
  1277. MenuLabel *spacerLabel2 = new MenuLabel();
  1278. menu->addChild(spacerLabel2);
  1279. BORDLCopyItem *copyItem = new BORDLCopyItem();
  1280. copyItem->text = "Copy pattern";
  1281. copyItem->bordlModule = bordlModule;
  1282. menu->addChild(copyItem);
  1283. BORDLPasteItem *pasteItem = new BORDLPasteItem();
  1284. pasteItem->text = "Paste pattern";
  1285. pasteItem->bordlModule = bordlModule;
  1286. pasteItem->bordlWidget = bordlWidget;
  1287. menu->addChild(pasteItem);
  1288. MenuLabel *spacerLabel3 = new MenuLabel();
  1289. menu->addChild(spacerLabel3);
  1290. BORDLPitchModeItem *pitchModeItem = new BORDLPitchModeItem();
  1291. pitchModeItem->text = "Pitch mode continuous/triggered";
  1292. pitchModeItem->bordlModule = bordlModule;
  1293. menu->addChild(pitchModeItem);
  1294. BORDLPitchQuantizeModeItem *pitchQuantizeModeItem = new BORDLPitchQuantizeModeItem();
  1295. pitchQuantizeModeItem->text = "Pitch full quantize";
  1296. pitchQuantizeModeItem->bordlModule = bordlModule;
  1297. menu->addChild(pitchQuantizeModeItem);
  1298. return menu;
  1299. }
  1300. } // namespace rack_plugin_Bidoo
  1301. using namespace rack_plugin_Bidoo;
  1302. RACK_PLUGIN_MODEL_INIT(Bidoo, BORDL) {
  1303. Model *modelBORDL = Model::create<BORDL, BORDLWidget>("Bidoo", "bordL", "bordL sequencer", SEQUENCER_TAG);
  1304. return modelBORDL;
  1305. }