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.

634 lines
24KB

  1. #include <string.h>
  2. #include "FrozenWasteland.hpp"
  3. #include "dsp/digital.hpp"
  4. #define NUM_RULERS 10
  5. #define MAX_DIVISIONS 6
  6. #define TRACK_COUNT 4
  7. #define MAX_STEPS 18
  8. #define sMIN(a,b) (((a)>(b))?(b):(a))
  9. #define sMAX(a,b) (((a)>(b))?(a):(b))
  10. struct QuadGolombRulerRhythm : Module {
  11. enum ParamIds {
  12. STEPS_1_PARAM,
  13. DIVISIONS_1_PARAM,
  14. OFFSET_1_PARAM,
  15. PAD_1_PARAM,
  16. ACCENTS_1_PARAM,
  17. ACCENT_ROTATE_1_PARAM,
  18. STEPS_2_PARAM,
  19. DIVISIONS_2_PARAM,
  20. OFFSET_2_PARAM,
  21. PAD_2_PARAM,
  22. ACCENTS_2_PARAM,
  23. ACCENT_ROTATE_2_PARAM,
  24. STEPS_3_PARAM,
  25. DIVISIONS_3_PARAM,
  26. OFFSET_3_PARAM,
  27. PAD_3_PARAM,
  28. ACCENTS_3_PARAM,
  29. ACCENT_ROTATE_3_PARAM,
  30. STEPS_4_PARAM,
  31. DIVISIONS_4_PARAM,
  32. OFFSET_4_PARAM,
  33. PAD_4_PARAM,
  34. ACCENTS_4_PARAM,
  35. ACCENT_ROTATE_4_PARAM,
  36. CHAIN_MODE_PARAM,
  37. CONSTANT_TIME_MODE_PARAM,
  38. NUM_PARAMS
  39. };
  40. enum InputIds {
  41. STEPS_1_INPUT,
  42. DIVISIONS_1_INPUT,
  43. OFFSET_1_INPUT,
  44. PAD_1_INPUT,
  45. ACCENTS_1_INPUT,
  46. ACCENT_ROTATE_1_INPUT,
  47. START_1_INPUT,
  48. STEPS_2_INPUT,
  49. DIVISIONS_2_INPUT,
  50. OFFSET_2_INPUT,
  51. PAD_2_INPUT,
  52. ACCENTS_2_INPUT,
  53. ACCENT_ROTATE_2_INPUT,
  54. START_2_INPUT,
  55. STEPS_3_INPUT,
  56. DIVISIONS_3_INPUT,
  57. OFFSET_3_INPUT,
  58. PAD_3_INPUT,
  59. ACCENTS_3_INPUT,
  60. ACCENT_ROTATE_3_INPUT,
  61. START_3_INPUT,
  62. STEPS_4_INPUT,
  63. DIVISIONS_4_INPUT,
  64. OFFSET_4_INPUT,
  65. PAD_4_INPUT,
  66. ACCENTS_4_INPUT,
  67. ACCENT_ROTATE_4_INPUT,
  68. START_4_INPUT,
  69. CLOCK_INPUT,
  70. RESET_INPUT,
  71. MUTE_INPUT,
  72. NUM_INPUTS
  73. };
  74. enum OutputIds {
  75. OUTPUT_1,
  76. ACCENT_OUTPUT_1,
  77. EOC_OUTPUT_1,
  78. OUTPUT_2,
  79. ACCENT_OUTPUT_2,
  80. EOC_OUTPUT_2,
  81. OUTPUT_3,
  82. ACCENT_OUTPUT_3,
  83. EOC_OUTPUT_3,
  84. OUTPUT_4,
  85. ACCENT_OUTPUT_4,
  86. EOC_OUTPUT_4,
  87. NUM_OUTPUTS
  88. };
  89. enum LightIds {
  90. CHAIN_MODE_NONE_LIGHT,
  91. CHAIN_MODE_BOSS_LIGHT,
  92. CHAIN_MODE_EMPLOYEE_LIGHT,
  93. MUTED_LIGHT,
  94. CONSTANT_TIME_LIGHT,
  95. NUM_LIGHTS
  96. };
  97. enum ChainModes {
  98. CHAIN_MODE_NONE,
  99. CHAIN_MODE_BOSS,
  100. CHAIN_MODE_EMPLOYEE
  101. };
  102. bool beatMatrix[TRACK_COUNT][MAX_STEPS];
  103. bool accentMatrix[TRACK_COUNT][MAX_STEPS];
  104. int beatIndex[TRACK_COUNT];
  105. int stepsCount[TRACK_COUNT];
  106. float stepDuration[TRACK_COUNT];
  107. float lastStepTime[TRACK_COUNT];
  108. float maxStepCount;
  109. const int rulerOrders[NUM_RULERS] = {1,2,3,4,5,5,6,6,6,6};
  110. const int rulerLengths[NUM_RULERS] = {0,1,3,6,11,11,17,17,17,17};
  111. const int rulers[NUM_RULERS][MAX_DIVISIONS] = {{0},
  112. {0,1},
  113. {0,1,3},
  114. {0,1,4,6},
  115. {0,1,4,9,11},
  116. {0,2,7,8,11},
  117. {0,1,4,10,12,17},
  118. {0,1,4,10,15,17},
  119. {0,1,8,11,13,17},
  120. {0,1,8,12,14,17}};
  121. bool running[TRACK_COUNT];
  122. int chainMode = 0;
  123. bool initialized = false;
  124. bool muted = false;
  125. bool constantTime = false;
  126. float time = 0.0;
  127. float duration = 0.0;
  128. bool secondClockReceived = false;
  129. SchmittTrigger clockTrigger,resetTrigger,chainModeTrigger,constantTimeTrigger,muteTrigger,startTrigger[TRACK_COUNT];
  130. PulseGenerator beatPulse[TRACK_COUNT],accentPulse[TRACK_COUNT],eocPulse[TRACK_COUNT];
  131. QuadGolombRulerRhythm() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS,NUM_LIGHTS) {
  132. for(unsigned i = 0; i < TRACK_COUNT; i++) {
  133. beatIndex[i] = 0;
  134. stepsCount[i] = MAX_STEPS;
  135. lastStepTime[i] = 0.0;
  136. stepDuration[i] = 0.0;
  137. running[i] = true;
  138. for(unsigned j = 0; j < MAX_STEPS; j++) {
  139. beatMatrix[i][j] = false;
  140. accentMatrix[i][j] = false;
  141. }
  142. }
  143. }
  144. void step() override;
  145. json_t *toJson() override {
  146. json_t *rootJ = json_object();
  147. json_object_set_new(rootJ, "constantTime", json_integer((bool) constantTime));
  148. json_object_set_new(rootJ, "chainMode", json_integer((int) chainMode));
  149. json_object_set_new(rootJ, "muted", json_integer((bool) muted));
  150. return rootJ;
  151. }
  152. void fromJson(json_t *rootJ) override {
  153. json_t *ctJ = json_object_get(rootJ, "constantTime");
  154. if (ctJ)
  155. constantTime = json_integer_value(ctJ);
  156. json_t *cmJ = json_object_get(rootJ, "chainMode");
  157. if (cmJ)
  158. chainMode = json_integer_value(cmJ);
  159. json_t *mutedJ = json_object_get(rootJ, "muted");
  160. if (mutedJ)
  161. muted = json_integer_value(mutedJ);
  162. }
  163. void setRunningState() {
  164. for(int trackNumber=0;trackNumber<TRACK_COUNT;trackNumber++)
  165. {
  166. if(chainMode == CHAIN_MODE_EMPLOYEE && inputs[(trackNumber * 7) + 6].active) { //START Input needs to be active
  167. running[trackNumber] = false;
  168. }
  169. else {
  170. running[trackNumber] = true;
  171. }
  172. }
  173. }
  174. void advanceBeat(int trackNumber) {
  175. beatIndex[trackNumber]++;
  176. lastStepTime[trackNumber] = 0.0;
  177. //End of Cycle
  178. if(beatIndex[trackNumber] >= stepsCount[trackNumber]) {
  179. beatIndex[trackNumber] = 0;
  180. eocPulse[trackNumber].trigger(1e-3);
  181. //If in a chain mode, stop running until start trigger received
  182. if(chainMode != CHAIN_MODE_NONE && inputs[(trackNumber * 7) + 6].active) { //START Input needs to be active
  183. running[trackNumber] = false;
  184. }
  185. }
  186. }
  187. // For more advanced Module features, read Rack's engine.hpp header file
  188. // - onSampleRateChange: event triggered by a change of sample rate
  189. // - onReset, onRandomize, onCreate, onDelete: implements special behavior when user clicks these from the context menu
  190. };
  191. void QuadGolombRulerRhythm::step() {
  192. int accentLevelArray[MAX_STEPS];
  193. int beatLocation[MAX_STEPS];
  194. //Set startup state
  195. if(!initialized) {
  196. setRunningState();
  197. initialized = true;
  198. }
  199. // Modes
  200. if (constantTimeTrigger.process(params[CONSTANT_TIME_MODE_PARAM].value)) {
  201. constantTime = !constantTime;
  202. for(int trackNumber=0;trackNumber<TRACK_COUNT;trackNumber++) {
  203. beatIndex[trackNumber] = 0;
  204. }
  205. setRunningState();
  206. }
  207. lights[CONSTANT_TIME_LIGHT].value = constantTime;
  208. if (chainModeTrigger.process(params[CHAIN_MODE_PARAM].value)) {
  209. chainMode = (chainMode + 1) % 3;
  210. setRunningState();
  211. }
  212. lights[CHAIN_MODE_NONE_LIGHT].value = chainMode == CHAIN_MODE_NONE ? 1.0 : 0.0;
  213. lights[CHAIN_MODE_BOSS_LIGHT].value = chainMode == CHAIN_MODE_BOSS ? 1.0 : 0.0;
  214. lights[CHAIN_MODE_EMPLOYEE_LIGHT].value = chainMode == CHAIN_MODE_EMPLOYEE ? 1.0 : 0.0;
  215. lights[MUTED_LIGHT].value = muted ? 1.0 : 0.0;
  216. for(int trackNumber=0;trackNumber<TRACK_COUNT;trackNumber++) {
  217. //clear out the matrix and levels
  218. for(int j=0;j<MAX_STEPS;j++)
  219. {
  220. beatMatrix[trackNumber][j] = false;
  221. accentMatrix[trackNumber][j] = false;
  222. accentLevelArray[j] = 0;
  223. beatLocation[j] = 0;
  224. }
  225. float stepsCountf = params[trackNumber * 6].value;
  226. if(inputs[trackNumber * 7].active) {
  227. stepsCountf += inputs[trackNumber * 7].value;
  228. }
  229. stepsCountf = clamp(stepsCountf,0.0f,18.0f);
  230. float divisionf = params[(trackNumber * 6) + 1].value;
  231. if(inputs[(trackNumber * 7) + 1].active) {
  232. divisionf += inputs[(trackNumber * 7) + 1].value;
  233. }
  234. divisionf = clamp(divisionf,0.0f,(float)(NUM_RULERS-1));
  235. float offsetf = params[(trackNumber * 6) + 2].value;
  236. if(inputs[(trackNumber * 7) + 2].active) {
  237. offsetf += inputs[(trackNumber * 7) + 2].value;
  238. }
  239. offsetf = clamp(offsetf,0.0f,17.0f);
  240. float padf = params[trackNumber * 6 + 3].value;
  241. if(inputs[trackNumber * 7 + 3].active) {
  242. padf += inputs[trackNumber * 7 + 3].value;
  243. }
  244. padf = clamp(padf,0.0f,stepsCountf - divisionf);
  245. //Use this to reduce range of accent params/inputs so the range of motion of knob/modulation is more useful.
  246. float divisionScale = 1;
  247. if(stepsCountf > 0) {
  248. divisionScale = divisionf / stepsCountf;
  249. }
  250. float accentDivisionf = params[(trackNumber * 6) + 4].value * divisionScale;
  251. if(inputs[(trackNumber * 7) + 4].active) {
  252. accentDivisionf += inputs[(trackNumber * 7) + 4].value * divisionScale;
  253. }
  254. accentDivisionf = clamp(accentDivisionf,0.0f,divisionf);
  255. float accentRotationf = params[(trackNumber * 6) + 5].value * divisionScale;
  256. if(inputs[(trackNumber * 7) + 5].active) {
  257. accentRotationf += inputs[(trackNumber * 7) + 5].value * divisionScale;
  258. }
  259. if(divisionf > 0) {
  260. accentRotationf = clamp(accentRotationf,0.0f,divisionf-1);
  261. } else {
  262. accentRotationf = 0;
  263. }
  264. if(stepsCountf > maxStepCount)
  265. maxStepCount = stepsCountf;
  266. stepsCount[trackNumber] = int(stepsCountf);
  267. int division = int(divisionf);
  268. int offset = int(offsetf);
  269. int pad = int(padf);
  270. int accentDivision = int(accentDivisionf);
  271. int accentRotation = int(accentRotationf);
  272. //Calculate Beats if there are divisions to calcuate for
  273. //Ruler Lengths and orders are 0 based, which is why I add 1 here.
  274. //Yes, I could add 1 to length in the constant array, but I want that to match wikipedia definition
  275. if(stepsCount[trackNumber] > 0 && division > 0) {
  276. int rulerToUse = division - 1;
  277. int actualStepCount = stepsCount[trackNumber] - pad;
  278. while(rulerLengths[rulerToUse] + 1 > actualStepCount && rulerToUse >= 0) {
  279. rulerToUse -=1;
  280. }
  281. //Multiply beats so that low division beats fill out entire pattern
  282. int spaceMultiplier = (actualStepCount / (rulerLengths[rulerToUse] + 1)) + 1;
  283. if(actualStepCount % (rulerLengths[rulerToUse] + 1) == 0) {
  284. spaceMultiplier -=1;
  285. }
  286. for (int j = 0; j < rulerOrders[rulerToUse];j++)
  287. {
  288. int divisionLocation = rulers[rulerToUse][j] * spaceMultiplier;
  289. divisionLocation +=pad;
  290. if(j > 0) {
  291. divisionLocation -=1;
  292. }
  293. beatMatrix[trackNumber][(divisionLocation + offset) % stepsCount[trackNumber]] = true;
  294. beatLocation[j] = (divisionLocation + offset) % stepsCount[trackNumber];
  295. }
  296. //Calculate Accents
  297. int level = 0;
  298. int restsLeft = sMAX(0,rulerOrders[rulerToUse]-accentDivision); // just make sure no negatives
  299. do {
  300. accentLevelArray[level] = sMIN(restsLeft,accentDivision);
  301. restsLeft = restsLeft - accentDivision;
  302. level += 1;
  303. } while (restsLeft > 0 && level < MAX_STEPS);
  304. int tempIndex =0;
  305. for (int j = 0; j < accentDivision; j++) {
  306. accentMatrix[trackNumber][beatLocation[(tempIndex + accentRotation) % rulerOrders[rulerToUse]]] = true;
  307. tempIndex++;
  308. for (int k = 0; k < MAX_STEPS; k++) {
  309. if (accentLevelArray[k] > j) {
  310. tempIndex++;
  311. }
  312. }
  313. }
  314. }
  315. }
  316. if(inputs[RESET_INPUT].active) {
  317. if(resetTrigger.process(inputs[RESET_INPUT].value)) {
  318. for(int trackNumber=0;trackNumber<TRACK_COUNT;trackNumber++)
  319. {
  320. beatIndex[trackNumber] = 0;
  321. }
  322. setRunningState();
  323. }
  324. }
  325. if(inputs[MUTE_INPUT].active) {
  326. if(muteTrigger.process(inputs[MUTE_INPUT].value)) {
  327. muted = !muted;
  328. }
  329. }
  330. //See if need to start up
  331. for(int trackNumber=0;trackNumber < TRACK_COUNT;trackNumber++) {
  332. if(chainMode != CHAIN_MODE_NONE && inputs[(trackNumber * 7) + 6].active && !running[trackNumber]) {
  333. if(startTrigger[trackNumber].process(inputs[(trackNumber * 7) + 6].value)) {
  334. running[trackNumber] = true;
  335. }
  336. }
  337. }
  338. //Advance beat on trigger if not in constant time mode
  339. float timeAdvance =1.0 / engineGetSampleRate();
  340. time += timeAdvance;
  341. if(inputs[CLOCK_INPUT].active) {
  342. if(clockTrigger.process(inputs[CLOCK_INPUT].value)) {
  343. if(secondClockReceived) {
  344. duration = time;
  345. }
  346. time = 0;
  347. secondClockReceived = true;
  348. for(int trackNumber=0;trackNumber < TRACK_COUNT;trackNumber++)
  349. {
  350. if(running[trackNumber]) {
  351. if(!constantTime) {
  352. advanceBeat(trackNumber);
  353. }
  354. }
  355. }
  356. }
  357. bool resyncAll = false;
  358. //For constant time, don't rely on clock trigger to advance beat, use time
  359. for(int trackNumber=0;trackNumber < TRACK_COUNT;trackNumber++) {
  360. if(stepsCount[trackNumber] > 0)
  361. stepDuration[trackNumber] = duration * maxStepCount / (float)stepsCount[trackNumber];
  362. if(running[trackNumber]) {
  363. lastStepTime[trackNumber] +=timeAdvance;
  364. if(constantTime && stepDuration[trackNumber] > 0.0 && lastStepTime[trackNumber] >= stepDuration[trackNumber]) {
  365. advanceBeat(trackNumber);
  366. if(stepsCount[trackNumber] >= (int)maxStepCount && beatIndex[trackNumber] == 0) {
  367. resyncAll = true;
  368. }
  369. }
  370. }
  371. }
  372. if(resyncAll) {
  373. for(int trackNumber=0;trackNumber < TRACK_COUNT;trackNumber++) {
  374. lastStepTime[trackNumber] = 0;
  375. beatIndex[trackNumber] = 0;
  376. }
  377. }
  378. }
  379. // Set output to current state
  380. for(int trackNumber=0;trackNumber<TRACK_COUNT;trackNumber++) {
  381. float outputValue = (lastStepTime[trackNumber] < stepDuration[trackNumber] / 2) ? 10.0 : 0.0;
  382. //Send out beat
  383. if(beatMatrix[trackNumber][beatIndex[trackNumber]] == true && running[trackNumber] && !muted) {
  384. outputs[trackNumber * 3].value = outputValue;
  385. } else {
  386. outputs[trackNumber * 3].value = 0.0;
  387. }
  388. //send out accent
  389. if(accentMatrix[trackNumber][beatIndex[trackNumber]] == true && running[trackNumber] && !muted) {
  390. outputs[trackNumber * 3 + 1].value = outputValue;
  391. } else {
  392. outputs[trackNumber * 3 + 1].value = 0.0;
  393. }
  394. //Send out End of Cycle
  395. outputs[(trackNumber * 3) + 2].value = eocPulse[trackNumber].process(1.0 / engineGetSampleRate()) ? 10.0 : 0;
  396. }
  397. }
  398. struct QBRBeatDisplay : TransparentWidget {
  399. QuadGolombRulerRhythm *module;
  400. int frame = 0;
  401. std::shared_ptr<Font> font;
  402. QBRBeatDisplay() {
  403. font = Font::load(assetPlugin(plugin, "res/fonts/Sudo.ttf"));
  404. }
  405. void drawBox(NVGcontext *vg, float stepNumber, float trackNumber,bool isBeat,bool isAccent,bool isCurrent) {
  406. //nvgSave(vg);
  407. //Rect b = Rect(Vec(0, 0), box.size);
  408. //nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y);
  409. float boxX = stepNumber * 22.5;
  410. float boxY = trackNumber * 22.5;
  411. float opacity = 0x80; // Testing using opacity for accents
  412. if(isAccent) {
  413. opacity = 0xff;
  414. }
  415. NVGcolor strokeColor = nvgRGBA(0, 0xe0, 0xef, 0xff);
  416. NVGcolor fillColor = nvgRGBA(0,0xe0,0xef,opacity);
  417. if(isCurrent)
  418. {
  419. strokeColor = nvgRGBA(0x2f, 0xf0, 0, 0xff);
  420. fillColor = nvgRGBA(0x2f,0xf0,0,opacity);
  421. }
  422. nvgStrokeColor(vg, strokeColor);
  423. nvgStrokeWidth(vg, 1.0);
  424. nvgBeginPath(vg);
  425. nvgRect(vg,boxX,boxY,21,21.0);
  426. nvgStroke(vg);
  427. nvgClosePath(vg);
  428. if(isBeat) {
  429. nvgFillColor(vg, fillColor);
  430. nvgFill(vg);
  431. }
  432. }
  433. void draw(NVGcontext *vg) override {
  434. for(int trackNumber = 0;trackNumber < 4;trackNumber++) {
  435. for(int stepNumber = 0;stepNumber < module->stepsCount[trackNumber];stepNumber++) {
  436. bool isBeat = module->beatMatrix[trackNumber][stepNumber];
  437. bool isAccent = module->accentMatrix[trackNumber][stepNumber];
  438. bool isCurrent = module->beatIndex[trackNumber] == stepNumber && module->running[trackNumber];
  439. drawBox(vg, float(stepNumber), float(trackNumber),isBeat,isAccent,isCurrent);
  440. }
  441. }
  442. }
  443. };
  444. struct QuadGolombRulerRhythmWidget : ModuleWidget {
  445. QuadGolombRulerRhythmWidget(QuadGolombRulerRhythm *module);
  446. };
  447. QuadGolombRulerRhythmWidget::QuadGolombRulerRhythmWidget(QuadGolombRulerRhythm *module) : ModuleWidget(module) {
  448. box.size = Vec(15*29, RACK_GRID_HEIGHT);
  449. {
  450. SVGPanel *panel = new SVGPanel();
  451. panel->box.size = box.size;
  452. panel->setBackground(SVG::load(assetPlugin(plugin, "res/QuadGolombRulerRhythm.svg")));
  453. addChild(panel);
  454. }
  455. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH - 12, 0)));
  456. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH + 12, 0)));
  457. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH - 12, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  458. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH + 12, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  459. {
  460. QBRBeatDisplay *display = new QBRBeatDisplay();
  461. display->module = module;
  462. display->box.pos = Vec(16, 34);
  463. display->box.size = Vec(box.size.x-30, 135);
  464. addChild(display);
  465. }
  466. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(22, 138), module, QuadGolombRulerRhythm::STEPS_1_PARAM, 0.0, 18.2, 18.0));
  467. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(61, 138), module, QuadGolombRulerRhythm::DIVISIONS_1_PARAM, 0.0, 10.2, 2.0));
  468. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(100, 138), module, QuadGolombRulerRhythm::OFFSET_1_PARAM, 0.0, 17.2, 0.0));
  469. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(139, 138), module, QuadGolombRulerRhythm::PAD_1_PARAM, 0.0, 17.2, 0.0));
  470. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(178, 138), module, QuadGolombRulerRhythm::ACCENTS_1_PARAM, 0.0, 17.2, 0.0));
  471. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(217, 138), module, QuadGolombRulerRhythm::ACCENT_ROTATE_1_PARAM, 0.0, 17.2, 0.0));
  472. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(22, 195), module, QuadGolombRulerRhythm::STEPS_2_PARAM, 0.0, 18.0, 18.0));
  473. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(61, 195), module, QuadGolombRulerRhythm::DIVISIONS_2_PARAM, 0.0, 10.2, 2.0));
  474. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(100, 195), module, QuadGolombRulerRhythm::OFFSET_2_PARAM, 0.0, 17.2, 0.0));
  475. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(139, 195), module, QuadGolombRulerRhythm::PAD_2_PARAM, 0.0, 17.2, 0.0));
  476. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(178, 195), module, QuadGolombRulerRhythm::ACCENTS_2_PARAM, 0.0, 17.2, 0.0));
  477. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(217, 195), module, QuadGolombRulerRhythm::ACCENT_ROTATE_2_PARAM, 0.0, 17.2, 0.0));
  478. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(22, 252), module, QuadGolombRulerRhythm::STEPS_3_PARAM, 0.0, 18.2, 18.0));
  479. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(61, 252), module, QuadGolombRulerRhythm::DIVISIONS_3_PARAM, 0.0, 10.2, 2.0));
  480. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(100, 252), module, QuadGolombRulerRhythm::OFFSET_3_PARAM, 0.0, 17.2, 0.0));
  481. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(139, 252), module, QuadGolombRulerRhythm::PAD_3_PARAM, 0.0, 17.2, 0.0));
  482. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(178, 252), module, QuadGolombRulerRhythm::ACCENTS_3_PARAM, 0.0, 17.2, 0.0));
  483. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(217, 252), module, QuadGolombRulerRhythm::ACCENT_ROTATE_3_PARAM, 0.0, 17.2, 0.0));
  484. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(22, 309), module, QuadGolombRulerRhythm::STEPS_4_PARAM, 0.0, 18.2, 18.0));
  485. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(61, 309), module, QuadGolombRulerRhythm::DIVISIONS_4_PARAM, 0.0, 10.2, 2.0));
  486. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(100, 309), module, QuadGolombRulerRhythm::OFFSET_4_PARAM, 0.0, 17.2, 0.0));
  487. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(139, 309), module, QuadGolombRulerRhythm::PAD_4_PARAM, 0.0, 17.2, 0.0));
  488. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(178, 309), module, QuadGolombRulerRhythm::ACCENTS_4_PARAM, 0.0, 17.2, 0.0));
  489. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(217, 309), module, QuadGolombRulerRhythm::ACCENT_ROTATE_4_PARAM, 0.0, 17.2, 0.0));
  490. addParam(ParamWidget::create<CKD6>(Vec(250, 285), module, QuadGolombRulerRhythm::CHAIN_MODE_PARAM, 0.0, 1.0, 0.0));
  491. addParam(ParamWidget::create<CKD6>(Vec(360, 285), module, QuadGolombRulerRhythm::CONSTANT_TIME_MODE_PARAM, 0.0, 1.0, 0.0));
  492. addInput(Port::create<PJ301MPort>(Vec(23, 163), Port::INPUT, module, QuadGolombRulerRhythm::STEPS_1_INPUT));
  493. addInput(Port::create<PJ301MPort>(Vec(62, 163), Port::INPUT, module, QuadGolombRulerRhythm::DIVISIONS_1_INPUT));
  494. addInput(Port::create<PJ301MPort>(Vec(101, 163), Port::INPUT, module, QuadGolombRulerRhythm::OFFSET_1_INPUT));
  495. addInput(Port::create<PJ301MPort>(Vec(140, 163), Port::INPUT, module, QuadGolombRulerRhythm::PAD_1_INPUT));
  496. addInput(Port::create<PJ301MPort>(Vec(179, 163), Port::INPUT, module, QuadGolombRulerRhythm::ACCENTS_1_INPUT));
  497. addInput(Port::create<PJ301MPort>(Vec(218, 163), Port::INPUT, module, QuadGolombRulerRhythm::ACCENT_ROTATE_1_INPUT));
  498. addInput(Port::create<PJ301MPort>(Vec(23, 220), Port::INPUT, module, QuadGolombRulerRhythm::STEPS_2_INPUT));
  499. addInput(Port::create<PJ301MPort>(Vec(62, 220), Port::INPUT, module, QuadGolombRulerRhythm::DIVISIONS_2_INPUT));
  500. addInput(Port::create<PJ301MPort>(Vec(101, 220), Port::INPUT, module, QuadGolombRulerRhythm::OFFSET_2_INPUT));
  501. addInput(Port::create<PJ301MPort>(Vec(140, 220), Port::INPUT, module, QuadGolombRulerRhythm::PAD_2_INPUT));
  502. addInput(Port::create<PJ301MPort>(Vec(179, 220), Port::INPUT, module, QuadGolombRulerRhythm::ACCENTS_2_INPUT));
  503. addInput(Port::create<PJ301MPort>(Vec(218, 220), Port::INPUT, module, QuadGolombRulerRhythm::ACCENT_ROTATE_2_INPUT));
  504. addInput(Port::create<PJ301MPort>(Vec(23, 277), Port::INPUT, module, QuadGolombRulerRhythm::STEPS_3_INPUT));
  505. addInput(Port::create<PJ301MPort>(Vec(62, 277), Port::INPUT, module, QuadGolombRulerRhythm::DIVISIONS_3_INPUT));
  506. addInput(Port::create<PJ301MPort>(Vec(101, 277), Port::INPUT, module, QuadGolombRulerRhythm::OFFSET_3_INPUT));
  507. addInput(Port::create<PJ301MPort>(Vec(140, 277), Port::INPUT, module, QuadGolombRulerRhythm::PAD_3_INPUT));
  508. addInput(Port::create<PJ301MPort>(Vec(179, 277), Port::INPUT, module, QuadGolombRulerRhythm::ACCENTS_3_INPUT));
  509. addInput(Port::create<PJ301MPort>(Vec(218, 277), Port::INPUT, module, QuadGolombRulerRhythm::ACCENT_ROTATE_3_INPUT));
  510. addInput(Port::create<PJ301MPort>(Vec(23, 334), Port::INPUT, module, QuadGolombRulerRhythm::STEPS_4_INPUT));
  511. addInput(Port::create<PJ301MPort>(Vec(62, 334), Port::INPUT, module, QuadGolombRulerRhythm::DIVISIONS_4_INPUT));
  512. addInput(Port::create<PJ301MPort>(Vec(101, 334), Port::INPUT, module, QuadGolombRulerRhythm::OFFSET_4_INPUT));
  513. addInput(Port::create<PJ301MPort>(Vec(140, 334), Port::INPUT, module, QuadGolombRulerRhythm::PAD_4_INPUT));
  514. addInput(Port::create<PJ301MPort>(Vec(179, 334), Port::INPUT, module, QuadGolombRulerRhythm::ACCENTS_4_INPUT));
  515. addInput(Port::create<PJ301MPort>(Vec(218, 334), Port::INPUT, module, QuadGolombRulerRhythm::ACCENT_ROTATE_4_INPUT));
  516. addInput(Port::create<PJ301MPort>(Vec(262, 343), Port::INPUT, module, QuadGolombRulerRhythm::CLOCK_INPUT));
  517. addInput(Port::create<PJ301MPort>(Vec(302, 343), Port::INPUT, module, QuadGolombRulerRhythm::RESET_INPUT));
  518. addInput(Port::create<PJ301MPort>(Vec(335, 343), Port::INPUT, module, QuadGolombRulerRhythm::MUTE_INPUT));
  519. addInput(Port::create<PJ301MPort>(Vec(322, 145), Port::INPUT, module, QuadGolombRulerRhythm::START_1_INPUT));
  520. addInput(Port::create<PJ301MPort>(Vec(322, 175), Port::INPUT, module, QuadGolombRulerRhythm::START_2_INPUT));
  521. addInput(Port::create<PJ301MPort>(Vec(322, 205), Port::INPUT, module, QuadGolombRulerRhythm::START_3_INPUT));
  522. addInput(Port::create<PJ301MPort>(Vec(322, 235), Port::INPUT, module, QuadGolombRulerRhythm::START_4_INPUT));
  523. addOutput(Port::create<PJ301MPort>(Vec(255, 145), Port::OUTPUT, module, QuadGolombRulerRhythm::OUTPUT_1));
  524. addOutput(Port::create<PJ301MPort>(Vec(286, 145), Port::OUTPUT, module, QuadGolombRulerRhythm::ACCENT_OUTPUT_1));
  525. addOutput(Port::create<PJ301MPort>(Vec(354, 145), Port::OUTPUT, module, QuadGolombRulerRhythm::EOC_OUTPUT_1));
  526. addOutput(Port::create<PJ301MPort>(Vec(256, 175), Port::OUTPUT, module, QuadGolombRulerRhythm::OUTPUT_2));
  527. addOutput(Port::create<PJ301MPort>(Vec(286, 175), Port::OUTPUT, module, QuadGolombRulerRhythm::ACCENT_OUTPUT_2));
  528. addOutput(Port::create<PJ301MPort>(Vec(354, 175), Port::OUTPUT, module, QuadGolombRulerRhythm::EOC_OUTPUT_2));
  529. addOutput(Port::create<PJ301MPort>(Vec(256, 205), Port::OUTPUT, module, QuadGolombRulerRhythm::OUTPUT_3));
  530. addOutput(Port::create<PJ301MPort>(Vec(286, 205), Port::OUTPUT, module, QuadGolombRulerRhythm::ACCENT_OUTPUT_3));
  531. addOutput(Port::create<PJ301MPort>(Vec(354, 205), Port::OUTPUT, module, QuadGolombRulerRhythm::EOC_OUTPUT_3));
  532. addOutput(Port::create<PJ301MPort>(Vec(256, 235), Port::OUTPUT, module, QuadGolombRulerRhythm::OUTPUT_4));
  533. addOutput(Port::create<PJ301MPort>(Vec(286, 235), Port::OUTPUT, module, QuadGolombRulerRhythm::ACCENT_OUTPUT_4));
  534. addOutput(Port::create<PJ301MPort>(Vec(354, 235), Port::OUTPUT, module, QuadGolombRulerRhythm::EOC_OUTPUT_4));
  535. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(282, 285), module, QuadGolombRulerRhythm::CHAIN_MODE_NONE_LIGHT));
  536. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(282, 300), module, QuadGolombRulerRhythm::CHAIN_MODE_BOSS_LIGHT));
  537. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(282, 315), module, QuadGolombRulerRhythm::CHAIN_MODE_EMPLOYEE_LIGHT));
  538. addChild(ModuleLightWidget::create<LargeLight<RedLight>>(Vec(363, 347), module, QuadGolombRulerRhythm::MUTED_LIGHT));
  539. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(395, 295), module, QuadGolombRulerRhythm::CONSTANT_TIME_LIGHT));
  540. }
  541. RACK_PLUGIN_MODEL_INIT(FrozenWasteland, QuadGolombRulerRhythm) {
  542. Model *modelQuadGolombRulerRhythm = Model::create<QuadGolombRulerRhythm, QuadGolombRulerRhythmWidget>("Frozen Wasteland", "QuadGolombRulerRhythm", "Quad Golomb Ruler Rhythm", SEQUENCER_TAG);
  543. return modelQuadGolombRulerRhythm;
  544. }