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.

1360 lines
43KB

  1. //============================================================================================================
  2. //!
  3. //! \file Seq-G2.cpp
  4. //!
  5. //! \brief Seq-G2 is a thing.
  6. //!
  7. //============================================================================================================
  8. #include "Gratrix.hpp"
  9. #include "dsp/digital.hpp"
  10. namespace rack_plugin_Gratrix {
  11. #define PROGRAMS 12
  12. #define RATIO 2
  13. #define LCD_ROWS 2
  14. #define LCD_COLS 16
  15. #define LCD_TEXT 4
  16. #define PRG_ROWS 1
  17. #define PRG_COLS 8
  18. #define NOB_ROWS 0
  19. #define NOB_COLS LCD_COLS
  20. #define BUT_ROWS 6
  21. #define BUT_COLS (NOB_COLS*RATIO)
  22. #define OUT_LEFT 1
  23. #define OUT_RIGHT 1
  24. #define GATE_STATES 4
  25. struct GtxModule_Seq_G2 : Module {
  26. enum ParamIds {
  27. CLOCK_PARAM,
  28. RUN_PARAM,
  29. RESET_PARAM,
  30. PROG_PARAM,
  31. PLAY_PARAM,
  32. EDIT_PARAM,
  33. COPY_PARAM,
  34. PASTE_PARAM,
  35. STEPS_PARAM,
  36. CLEAR_PARAM,
  37. RANDOM_PARAM,
  38. SPAN_R_PARAM,
  39. SPAN_C_PARAM,
  40. PRG_ROW_PARAM,
  41. PRG_COL_PARAM,
  42. PRG_SPAN_PARAM,
  43. PRG_STRIDE_PARAM,
  44. PRG_NOTE_PARAM,
  45. PRG_OCTAVE_PARAM,
  46. PRG_VALUE_PARAM,
  47. PRG_GATE_PARAM,
  48. NOB_PARAM,
  49. BUT_PARAM = NOB_PARAM + (NOB_COLS * NOB_ROWS),
  50. NUM_PARAMS = BUT_PARAM + (BUT_COLS * BUT_ROWS)
  51. };
  52. enum InputIds {
  53. CLOCK_INPUT,
  54. EXT_CLOCK_INPUT,
  55. RESET_INPUT,
  56. STEPS_INPUT,
  57. PROG_INPUT,
  58. GATE_INPUT, // N+1
  59. VOCT_INPUT, // N+1
  60. NUM_INPUTS,
  61. OFF_INPUTS = GATE_INPUT
  62. };
  63. enum OutputIds {
  64. LCD_OUTPUT,
  65. NOB_OUTPUT = LCD_OUTPUT + LCD_ROWS * (OUT_LEFT + OUT_RIGHT),
  66. BUT_OUTPUT = NOB_OUTPUT + NOB_ROWS * (OUT_LEFT + OUT_RIGHT),
  67. GATE_OUTPUT = BUT_OUTPUT + BUT_ROWS * (OUT_LEFT + OUT_RIGHT), // N
  68. VOCT_OUTPUT, // N
  69. NUM_OUTPUTS,
  70. OFF_OUTPUTS = GATE_OUTPUT
  71. };
  72. enum LightIds {
  73. RUNNING_LIGHT,
  74. RESET_LIGHT,
  75. PROG_LIGHT,
  76. CLEAR_LIGHT = PROG_LIGHT + PROGRAMS * 2,
  77. RANDOM_LIGHT,
  78. COPY_LIGHT,
  79. PASTE_LIGHT,
  80. BUT_LIGHT,
  81. NUM_LIGHTS = BUT_LIGHT + (BUT_COLS * BUT_ROWS) * 3
  82. };
  83. struct Decode
  84. {
  85. /*static constexpr*/ float e = static_cast<float>(PROGRAMS); // Static constexpr gives
  86. /*static constexpr*/ float s = 1.0f / e; // link error on Mac build.
  87. float in = 0;
  88. float out = 0;
  89. int note = 0;
  90. int key = 0;
  91. int oct = 0;
  92. void step(float input)
  93. {
  94. int safe, fnote;
  95. in = input;
  96. fnote = std::floor(in * PROGRAMS + 0.5f);
  97. out = fnote * s;
  98. note = static_cast<int>(fnote);
  99. safe = note + (PROGRAMS * 1000); // push away from negative numbers
  100. key = safe % PROGRAMS;
  101. oct = (safe / PROGRAMS) - 1000;
  102. }
  103. };
  104. static constexpr bool is_nob_snap(std::size_t row) { return false; }
  105. static constexpr std::size_t lcd_val_map(std::size_t row, std::size_t col) { return LCD_OUTPUT + (OUT_LEFT + OUT_RIGHT) * row + col; }
  106. static constexpr std::size_t nob_val_map(std::size_t row, std::size_t col) { return NOB_OUTPUT + (OUT_LEFT + OUT_RIGHT) * row + col; }
  107. static constexpr std::size_t but_val_map(std::size_t row, std::size_t col) { return BUT_OUTPUT + (OUT_LEFT + OUT_RIGHT) * row + col; }
  108. static constexpr std::size_t nob_map(std::size_t row, std::size_t col) { return NOB_PARAM + NOB_COLS * row + col; }
  109. static constexpr std::size_t but_map(std::size_t row, std::size_t col) { return BUT_PARAM + BUT_COLS * row + col; }
  110. static constexpr std::size_t led_map(std::size_t row, std::size_t col, std::size_t idx) { return BUT_LIGHT + 3 * (BUT_COLS * row + col) + idx; }
  111. static constexpr std::size_t imap(std::size_t port, std::size_t bank)
  112. {
  113. return (port < OFF_INPUTS) ? port : port + bank * (NUM_INPUTS - OFF_INPUTS);
  114. }
  115. static constexpr std::size_t omap(std::size_t port, std::size_t bank)
  116. {
  117. return (port < OFF_OUTPUTS) ? port : port + bank * (NUM_OUTPUTS - OFF_OUTPUTS);
  118. }
  119. Decode prg_nob;
  120. Decode prg_cv;
  121. bool running = true;
  122. SchmittTrigger clockTrigger; // for external clock
  123. // For buttons
  124. SchmittTrigger runningTrigger;
  125. SchmittTrigger resetTrigger;
  126. SchmittTrigger clearTrigger;
  127. SchmittTrigger randomTrigger;
  128. SchmittTrigger copyTrigger;
  129. SchmittTrigger pasteTrigger;
  130. SchmittTrigger gateTriggers[BUT_ROWS][BUT_COLS];
  131. float phase = 0.0f;
  132. int index = 0;
  133. int numSteps = 0;
  134. std::size_t play_prog = 0;
  135. std::size_t edit_prog = 0;
  136. struct LcdData
  137. {
  138. bool active;
  139. int8_t mode;
  140. int8_t note; // C
  141. int8_t octave; // 4 --> C4 is 0V
  142. float value;
  143. LcdData()
  144. {
  145. reset();
  146. }
  147. void reset()
  148. {
  149. active = false;
  150. mode = 0;
  151. note = 0; // C
  152. octave = 4; // 4 --> C4 is 0V
  153. value = 0.0f;
  154. }
  155. float to_voct() const
  156. {
  157. switch (mode)
  158. {
  159. case 0 : return (octave - 4.0f) + (note / 12.0f);
  160. case 1 : return value;
  161. default : return 0.0f;
  162. }
  163. }
  164. #if 0
  165. std::ostream &debug(std::ostream &os) const
  166. {
  167. os << static_cast<int>(mode) << " " << static_cast<int>(note) << " " << static_cast<int>(octave) << " " << value;
  168. return os;
  169. }
  170. #endif
  171. };
  172. #if LCD_ROWS
  173. LcdData lcd_state[PROGRAMS][LCD_ROWS][LCD_COLS] = {};
  174. LcdData lcd_cache [LCD_ROWS][LCD_COLS] = {};
  175. #endif
  176. #if PRG_ROWS
  177. struct Caches
  178. {
  179. Cache<int8_t> prg_row;
  180. Cache<int8_t> prg_col;
  181. Cache<int8_t> prg_note;
  182. Cache<int8_t> prg_octave;
  183. Cache<float > prg_value;
  184. Cache<int8_t> prg_gate;
  185. Cache<int8_t> prg_rows;
  186. Cache<int8_t> prg_cols;
  187. void reset()
  188. {
  189. prg_row .reset();
  190. prg_col .reset();
  191. prg_note .reset();
  192. prg_octave.reset();
  193. prg_value .reset();
  194. prg_gate .reset();
  195. prg_rows .reset();
  196. prg_cols .reset();
  197. }
  198. };
  199. Caches caches;
  200. #endif
  201. #if BUT_ROWS
  202. uint8_t but_state[PROGRAMS][BUT_ROWS][BUT_COLS] = {};
  203. uint8_t but_cache [BUT_ROWS][BUT_COLS] = {};
  204. float but_lights [BUT_ROWS][BUT_COLS] = {};
  205. #endif
  206. float resetLight = 0.0f;
  207. float clearLight = 0.0f;
  208. float randomLight = 0.0f;
  209. float copyLight = 0.0f;
  210. float pasteLight = 0.0f;
  211. enum GateMode
  212. {
  213. GM_OFF,
  214. GM_CONTINUOUS,
  215. GM_RETRIGGER,
  216. GM_TRIGGER,
  217. };
  218. PulseGenerator gatePulse;
  219. //--------------------------------------------------------------------------------------------------------
  220. //! \brief Constructor.
  221. GtxModule_Seq_G2()
  222. :
  223. Module(
  224. NUM_PARAMS,
  225. (GTX__N+1) * (NUM_INPUTS - OFF_INPUTS ) + OFF_INPUTS,
  226. (GTX__N ) * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS,
  227. NUM_LIGHTS)
  228. {
  229. onReset();
  230. }
  231. //--------------------------------------------------------------------------------------------------------
  232. //! \brief Step function.
  233. void step() override
  234. {
  235. const float lightLambda = 0.075f;
  236. // Decode program info
  237. prg_nob.step(params[PROG_PARAM].value / 12.0f);
  238. prg_cv .step(inputs[PROG_INPUT].value);
  239. // Input leds
  240. float prog_leds[PROGRAMS * 2] = {};
  241. prog_leds[prg_nob.key * 2 ] = 1.0f; // Green
  242. prog_leds[prg_cv .key * 2 + 1] = 1.0f; // Red
  243. // Determine what is playing and what is editing
  244. bool play_is_cv = (params[PLAY_PARAM].value < 0.5f);
  245. bool edit_is_cv = (params[EDIT_PARAM].value < 0.5f);
  246. play_prog = play_is_cv ? prg_cv.key : prg_nob.key;
  247. edit_prog = edit_is_cv ? prg_cv.key : prg_nob.key;
  248. // Run
  249. if (runningTrigger.process(params[RUN_PARAM].value))
  250. {
  251. running = !running;
  252. }
  253. bool nextStep = false;
  254. if (running)
  255. {
  256. if (inputs[EXT_CLOCK_INPUT].active)
  257. {
  258. // External clock
  259. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value))
  260. {
  261. phase = 0.0f;
  262. nextStep = true;
  263. }
  264. }
  265. else
  266. {
  267. // Internal clock
  268. float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  269. phase += clockTime * engineGetSampleTime();
  270. if (phase >= 1.0f)
  271. {
  272. phase -= 1.0f;
  273. nextStep = true;
  274. }
  275. }
  276. }
  277. // Update knobs
  278. knob_pull(edit_prog);
  279. // Trigger buttons
  280. {
  281. const float dim = 1.0f / lightLambda * engineGetSampleTime();
  282. // Reset
  283. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value))
  284. {
  285. phase = 0.0f;
  286. index = BUT_COLS;
  287. nextStep = true;
  288. resetLight = 1.0f;
  289. }
  290. resetLight -= resetLight * dim;
  291. // Clear current program
  292. if (clearTrigger.process(params[CLEAR_PARAM].value))
  293. {
  294. clear_prog(edit_prog);
  295. clearLight = 1.0f;
  296. }
  297. clearLight -= clearLight * dim;
  298. // Randomise current program
  299. if (randomTrigger.process(params[RANDOM_PARAM].value))
  300. {
  301. randomize_prog(edit_prog);
  302. randomLight = 1.0f;
  303. }
  304. randomLight -= randomLight * dim;
  305. // Copy current program
  306. if (copyTrigger.process(params[COPY_PARAM].value))
  307. {
  308. copy_prog(edit_prog);
  309. copyLight = 1.0f;
  310. }
  311. copyLight -= copyLight * dim;
  312. // Paste current program
  313. if (pasteTrigger.process(params[PASTE_PARAM].value))
  314. {
  315. paste_prog(edit_prog);
  316. pasteLight = 1.0f;
  317. }
  318. pasteLight -= pasteLight * dim;
  319. }
  320. numSteps = RATIO * clamp(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, static_cast<float>(LCD_COLS));
  321. if (nextStep)
  322. {
  323. // Advance step
  324. index += 1;
  325. if (index >= numSteps)
  326. {
  327. index = 0;
  328. }
  329. #if BUT_ROWS
  330. for (int row = 0; row < BUT_ROWS; row++)
  331. {
  332. but_lights[row][index] = 1.0f;
  333. }
  334. #endif
  335. gatePulse.trigger(1e-3);
  336. }
  337. bool pulse = gatePulse.process(engineGetSampleTime());
  338. #if BUT_ROWS
  339. // Gate buttons
  340. for (int col = 0; col < BUT_COLS; ++col)
  341. {
  342. for (int row = 0; row < BUT_ROWS; ++row)
  343. {
  344. // User input to alter state of buttons
  345. if (gateTriggers[row][col].process(params[but_map(row, col)].value))
  346. {
  347. auto state = but_state[edit_prog][row][col];
  348. if (++state >= GATE_STATES)
  349. {
  350. state = GM_OFF;
  351. }
  352. std::size_t span_r = static_cast<std::size_t>(params[SPAN_R_PARAM].value + 0.5f);
  353. std::size_t span_c = static_cast<std::size_t>(params[SPAN_C_PARAM].value + 0.5f);
  354. for (std::size_t r = row; r < row + span_r && r < BUT_ROWS; ++r)
  355. {
  356. for (std::size_t c = col; c < col + span_c && c < BUT_COLS; ++c)
  357. {
  358. but_state[edit_prog][r][c] = state;
  359. }
  360. }
  361. }
  362. // Get state of buttons for lights
  363. {
  364. bool gateOn = (running && (col == index) && (but_state[edit_prog][row][col] > 0));
  365. switch (but_state[edit_prog][row][col])
  366. {
  367. case GM_CONTINUOUS : break;
  368. case GM_RETRIGGER : gateOn = gateOn && !pulse; break;
  369. case GM_TRIGGER : gateOn = gateOn && pulse; break;
  370. default : break;
  371. }
  372. but_lights[row][col] -= but_lights[row][col] / lightLambda * engineGetSampleTime();
  373. if (col < numSteps)
  374. {
  375. float val = (play_prog == edit_prog) ? 1.0f : 0.1f;
  376. lights[led_map(row, col, 1)].value = but_state[edit_prog][row][col] == GM_CONTINUOUS ? 1.0f - val * but_lights[row][col] : val * but_lights[row][col]; // Green
  377. lights[led_map(row, col, 2)].value = but_state[edit_prog][row][col] == GM_RETRIGGER ? 1.0f - val * but_lights[row][col] : val * but_lights[row][col]; // Blue
  378. lights[led_map(row, col, 0)].value = but_state[edit_prog][row][col] == GM_TRIGGER ? 1.0f - val * but_lights[row][col] : val * but_lights[row][col]; // Red
  379. }
  380. else
  381. {
  382. lights[led_map(row, col, 1)].value = 0.01f; // Green
  383. lights[led_map(row, col, 2)].value = 0.01f; // Blue
  384. lights[led_map(row, col, 0)].value = 0.01f; // Red
  385. }
  386. }
  387. }
  388. }
  389. #endif
  390. // Compute row outputs
  391. #if LCD_ROWS
  392. std::size_t lcd_index = index / RATIO;
  393. float lcd_val[LCD_ROWS];
  394. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  395. {
  396. lcd_val[row] = lcd_state[play_prog][row][lcd_index].to_voct();
  397. }
  398. #endif
  399. #if NOB_ROWS
  400. std::size_t nob_index = index / RATIO;
  401. float nob_val[NOB_ROWS];
  402. for (std::size_t row = 0; row < NOB_ROWS; ++row)
  403. {
  404. nob_val[row] = params[nob_map(row, nob_index)].value;
  405. if (is_nob_snap(row)) nob_val[row] /= 12.0f;
  406. }
  407. #endif
  408. #if BUT_ROWS
  409. bool but_val[BUT_ROWS];
  410. for (std::size_t row = 0; row < BUT_ROWS; ++row)
  411. {
  412. but_val[row] = running && (but_state[play_prog][row][index] > 0);
  413. switch (but_state[play_prog][row][index])
  414. {
  415. case GM_CONTINUOUS : break;
  416. case GM_RETRIGGER : but_val[row] = but_val[row] && !pulse; break;
  417. case GM_TRIGGER : but_val[row] = but_val[row] && pulse; break;
  418. default : break;
  419. }
  420. }
  421. #endif
  422. // Write row outputs
  423. #if LCD_ROWS
  424. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  425. {
  426. if (OUT_LEFT || OUT_RIGHT) outputs[lcd_val_map(row, 0)].value = lcd_val[row];
  427. if (OUT_LEFT && OUT_RIGHT) outputs[lcd_val_map(row, 1)].value = lcd_val[row];
  428. }
  429. #endif
  430. #if NOB_ROWS
  431. for (std::size_t row = 0; row < NOB_ROWS; ++row)
  432. {
  433. if (OUT_LEFT || OUT_RIGHT) outputs[nob_val_map(row, 0)].value = nob_val[row];
  434. if (OUT_LEFT && OUT_RIGHT) outputs[nob_val_map(row, 1)].value = nob_val[row];
  435. }
  436. #endif
  437. #if BUT_ROWS
  438. for (std::size_t row = 0; row < BUT_ROWS; ++row)
  439. {
  440. if (OUT_LEFT || OUT_RIGHT) outputs[but_val_map(row, 0)].value = but_val[row] ? 10.0f : 0.0f;
  441. if (OUT_LEFT && OUT_RIGHT) outputs[but_val_map(row, 1)].value = but_val[row] ? 10.0f : 0.0f;
  442. }
  443. #endif
  444. // Detemine poly outputs
  445. #if BUT_ROWS
  446. for (std::size_t i=0; i<GTX__N && i<BUT_ROWS; ++i)
  447. {
  448. // Pass V/OCT trough (for now)
  449. outputs[omap(VOCT_OUTPUT, i)].value = inputs[imap(VOCT_INPUT, i)].active ? inputs[imap(VOCT_INPUT, i)].value : inputs[imap(VOCT_INPUT, GTX__N)].value;
  450. // Generate gate out
  451. float gate_in = inputs[imap(GATE_INPUT, i)].active ? inputs[imap(GATE_INPUT, i)].value : inputs[imap(GATE_INPUT, GTX__N)].value;
  452. outputs[omap(GATE_OUTPUT, i)].value = (but_val[i] && gate_in >= 1.0f) ? 10.0f : 0.0f;
  453. }
  454. #endif
  455. // Update LEDs
  456. lights[RUNNING_LIGHT].value = running ? 1.0f : 0.0f;
  457. lights[RESET_LIGHT] .value = resetLight;
  458. lights[CLEAR_LIGHT] .value = clearLight;
  459. lights[RANDOM_LIGHT] .value = randomLight;
  460. lights[COPY_LIGHT] .value = copyLight;
  461. lights[PASTE_LIGHT] .value = pasteLight;
  462. for (std::size_t i=0; i<PROGRAMS; ++i)
  463. {
  464. lights[PROG_LIGHT + i * 2 ].value = prog_leds[i * 2 ];
  465. lights[PROG_LIGHT + i * 2 + 1].value = prog_leds[i * 2 + 1];
  466. }
  467. }
  468. //--------------------------------------------------------------------------------------------------------
  469. //! \brief Save state.
  470. json_t *toJson() override
  471. {
  472. if (json_t *jo_root = json_object())
  473. {
  474. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  475. // Running
  476. json_object_set_new(jo_root, "running", json_boolean(running));
  477. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  478. // LCD state
  479. #if LCD_ROWS
  480. if (json_t *ja_progs = json_array()) { for (std::size_t prog = 0; prog < PROGRAMS; ++prog) {
  481. if (json_t *ja_rows = json_array()) { for (std::size_t row = 0; row < LCD_ROWS; ++row ) {
  482. if (json_t *ja_cols = json_array()) { for (std::size_t col = 0; col < LCD_COLS; ++col ) {
  483. if (json_t *jo_data = json_object()) { auto &current = lcd_state[prog][row][col];
  484. if (json_t *ji = json_integer(static_cast<int>(current.mode ))) json_object_set_new(jo_data, "mode", ji);
  485. if (json_t *ji = json_integer(static_cast<int>(current.note ))) json_object_set_new(jo_data, "note", ji);
  486. if (json_t *ji = json_integer(static_cast<int>(current.octave))) json_object_set_new(jo_data, "octave", ji);
  487. if (json_t *ji = json_real(static_cast<double>(current.value ))) json_object_set_new(jo_data, "value", ji);
  488. json_array_append_new(ja_cols, jo_data ); } }
  489. json_array_append_new(ja_rows, ja_cols ); } }
  490. json_array_append_new(ja_progs, ja_rows ); } }
  491. json_object_set_new (jo_root, "lcd", ja_progs); }
  492. #endif
  493. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  494. // Button state
  495. #if BUT_ROWS
  496. if (json_t *ja_progs = json_array()) { for (std::size_t prog = 0; prog < PROGRAMS; ++prog) {
  497. if (json_t *ja_rows = json_array()) { for (std::size_t row = 0; row < BUT_ROWS; ++row ) {
  498. if (json_t *ja_cols = json_array()) { for (std::size_t col = 0; col < BUT_COLS; ++col ) {
  499. if (json_t *jo_data = json_object()) { auto &current = but_state[prog][row][col];
  500. if (json_t *ji = json_integer(static_cast<int>(current))) json_object_set_new(jo_data, "mode", ji);
  501. json_array_append_new(ja_cols, jo_data ); } }
  502. json_array_append_new(ja_rows, ja_cols ); } }
  503. json_array_append_new(ja_progs, ja_rows ); } }
  504. json_object_set_new (jo_root, "but", ja_progs); }
  505. #endif
  506. return jo_root;
  507. }
  508. return nullptr;
  509. }
  510. //--------------------------------------------------------------------------------------------------------
  511. //! \brief Load state.
  512. void fromJson(json_t *jo_root) override
  513. {
  514. if (jo_root)
  515. {
  516. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  517. // Running
  518. if (json_t *jb = json_object_get(jo_root, "running"))
  519. {
  520. running = json_is_true(jb);
  521. }
  522. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  523. // LCD state
  524. #if LCD_ROWS
  525. for (std::size_t prog = 0; prog < PROGRAMS; ++prog) {
  526. for (std::size_t row = 0; row < LCD_ROWS; ++row ) {
  527. for (std::size_t col = 0; col < LCD_COLS; ++col ) {
  528. lcd_state[prog][row][col].reset();
  529. } } }
  530. if (json_t *ja_progs = json_object_get(jo_root, "lcd")) { for (std::size_t prog = 0; prog < PROGRAMS && prog < json_array_size(ja_progs); ++prog) {
  531. if (json_t *ja_rows = json_array_get (ja_progs, prog)) { for (std::size_t row = 0; row < LCD_ROWS && row < json_array_size(ja_rows); ++row ) {
  532. if (json_t *ja_cols = json_array_get (ja_rows, row )) { for (std::size_t col = 0; col < LCD_COLS && col < json_array_size(ja_cols); ++col ) {
  533. if (json_t *jo_data = json_array_get (ja_cols, col )) { auto &current = lcd_state[prog][row][col];
  534. if (json_t *jo = json_object_get(jo_data, "mode" )) current.mode = static_cast<int8_t>(json_integer_value(jo));
  535. if (json_t *jo = json_object_get(jo_data, "note" )) current.note = static_cast<int8_t>(json_integer_value(jo));
  536. if (json_t *jo = json_object_get(jo_data, "octave")) current.octave = static_cast<int8_t>(json_integer_value(jo));
  537. if (json_t *jo = json_object_get(jo_data, "value" )) current.value = static_cast<float> (json_real_value (jo));
  538. } } } } } } }
  539. caches.reset();
  540. #endif
  541. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  542. // Button state
  543. #if BUT_ROWS
  544. for (std::size_t prog = 0; prog < PROGRAMS; ++prog) {
  545. for (std::size_t row = 0; row < LCD_ROWS; ++row ) {
  546. for (std::size_t col = 0; col < LCD_COLS; ++col ) {
  547. but_state[prog][row][col] = GM_OFF;
  548. } } }
  549. if (json_t *ja_progs = json_object_get(jo_root, "but")) { for (std::size_t prog = 0; prog < PROGRAMS && prog < json_array_size(ja_progs); ++prog) {
  550. if (json_t *ja_rows = json_array_get (ja_progs, prog)) { for (std::size_t row = 0; row < BUT_ROWS && row < json_array_size(ja_rows); ++row ) {
  551. if (json_t *ja_cols = json_array_get (ja_rows, row )) { for (std::size_t col = 0; col < BUT_COLS && col < json_array_size(ja_cols); ++col ) {
  552. if (json_t *jo_data = json_array_get (ja_cols, col )) { auto &current = but_state[prog][row][col];
  553. if (json_t *jo = json_object_get(jo_data, "mode" )) current = static_cast<uint8_t>(json_integer_value(jo));
  554. } } } } } } }
  555. #endif
  556. }
  557. }
  558. //--------------------------------------------------------------------------------------------------------
  559. //! \brief Reset state.
  560. void onReset() override
  561. {
  562. for (std::size_t prog = 0; prog < PROGRAMS; ++prog)
  563. {
  564. clear_prog(prog);
  565. }
  566. }
  567. //--------------------------------------------------------------------------------------------------------
  568. //! \brief Random state.
  569. void randomize() override
  570. {
  571. for (std::size_t prog = 0; prog < PROGRAMS; ++prog)
  572. {
  573. randomize_prog(prog);
  574. }
  575. }
  576. //--------------------------------------------------------------------------------------------------------
  577. //! \brief Knob params to state.
  578. //!
  579. //! Only updates on knob value change, otheriwse current value always applied to current program.
  580. void knob_pull(std::size_t prog)
  581. {
  582. #if LCD_ROWS && PRG_ROWS
  583. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  584. {
  585. for (std::size_t col = 0; col < LCD_COLS; ++col)
  586. {
  587. lcd_state[prog][row][col].active = false;
  588. }
  589. }
  590. {
  591. std::size_t prg_row = static_cast<std::size_t>(params[PRG_ROW_PARAM].value + 0.5f);
  592. if (prg_row < LCD_ROWS)
  593. {
  594. std::size_t prg_col = static_cast<std::size_t>(params[PRG_COL_PARAM].value + 0.5f);
  595. if (prg_col < LCD_COLS)
  596. {
  597. std::size_t prg_span = static_cast<std::size_t>(params[PRG_SPAN_PARAM ].value + 0.5f);
  598. std::size_t prg_stride = static_cast<std::size_t>(params[PRG_STRIDE_PARAM].value + 0.5f);
  599. int8_t prg_note = static_cast<int8_t>(params[PRG_NOTE_PARAM ].value + 0.5f);
  600. int8_t prg_octave = static_cast<int8_t>(params[PRG_OCTAVE_PARAM].value + 0.5f);
  601. float prg_value = params[PRG_VALUE_PARAM ].value;
  602. // int8_t prg_gate = static_cast<int8_t>(params[PRG_GATE_PARAM ].value + 0.5f);
  603. std::size_t col_max = prg_col + prg_span * prg_stride;
  604. if (col_max > LCD_COLS)
  605. {
  606. col_max = LCD_COLS;
  607. }
  608. for (std::size_t col = prg_col; col < col_max; col += prg_stride)
  609. {
  610. auto &current = lcd_state[prog][prg_row][col];
  611. current.active = true;
  612. if (caches.prg_note.test(prg_note))
  613. {
  614. current.note = prg_note;
  615. current.mode = 0;
  616. }
  617. if (caches.prg_octave.test(prg_octave))
  618. {
  619. current.octave = prg_octave;
  620. current.mode = 0;
  621. }
  622. if (caches.prg_value.test(prg_value))
  623. {
  624. current.value = prg_value;
  625. current.mode = 1;
  626. }
  627. }
  628. caches.prg_note .set(prg_note);
  629. caches.prg_octave.set(prg_octave);
  630. caches.prg_value .set(prg_value);
  631. }
  632. }
  633. }
  634. #endif
  635. }
  636. //--------------------------------------------------------------------------------------------------------
  637. //! \brief Clear a program.
  638. void clear_prog(std::size_t prog)
  639. {
  640. #if LCD_ROWS
  641. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  642. {
  643. for (std::size_t col = 0; col < LCD_COLS; col++)
  644. {
  645. lcd_state[prog][row][col] = LcdData();
  646. }
  647. }
  648. #endif
  649. #if BUT_ROWS
  650. for (std::size_t row = 0; row < BUT_ROWS; row++)
  651. {
  652. for (std::size_t col = 0; col < BUT_COLS; col++)
  653. {
  654. but_state[prog][row][col] = GM_OFF;
  655. }
  656. }
  657. #endif
  658. caches.reset();
  659. }
  660. //--------------------------------------------------------------------------------------------------------
  661. //! \brief Randomize a program.
  662. void randomize_prog(std::size_t prog)
  663. {
  664. #if BUT_ROWS
  665. for (std::size_t row = 0; row < BUT_ROWS; row++)
  666. {
  667. for (std::size_t col = 0; col < BUT_COLS; col++)
  668. {
  669. uint32_t r = randomu32() % (GATE_STATES + 1);
  670. if (r >= GATE_STATES) r = GM_CONTINUOUS;
  671. but_state[prog][row][col] = r;
  672. }
  673. }
  674. #endif
  675. caches.reset();
  676. }
  677. //--------------------------------------------------------------------------------------------------------
  678. //! \brief Copy a program.
  679. void copy_prog(std::size_t prog)
  680. {
  681. #if LCD_ROWS
  682. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  683. {
  684. for (std::size_t col = 0; col < LCD_COLS; col++)
  685. {
  686. lcd_cache[row][col] = lcd_state[prog][row][col];
  687. }
  688. }
  689. #endif
  690. #if BUT_ROWS
  691. for (std::size_t row = 0; row < BUT_ROWS; row++)
  692. {
  693. for (std::size_t col = 0; col < BUT_COLS; col++)
  694. {
  695. but_cache[row][col] = but_state[prog][row][col];
  696. }
  697. }
  698. #endif
  699. }
  700. //--------------------------------------------------------------------------------------------------------
  701. //! \brief Paste a program.
  702. void paste_prog(std::size_t prog)
  703. {
  704. #if LCD_ROWS
  705. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  706. {
  707. for (std::size_t col = 0; col < LCD_COLS; col++)
  708. {
  709. lcd_state[prog][row][col] = lcd_cache[row][col];
  710. }
  711. }
  712. #endif
  713. #if BUT_ROWS
  714. for (std::size_t row = 0; row < BUT_ROWS; row++)
  715. {
  716. for (std::size_t col = 0; col < BUT_COLS; col++)
  717. {
  718. but_state[prog][row][col] = but_cache[row][col];
  719. }
  720. }
  721. #endif
  722. caches.reset();
  723. }
  724. };
  725. #if LCD_ROWS
  726. //============================================================================================================
  727. //! \brief Display.
  728. struct Display : TransparentWidget
  729. {
  730. GtxModule_Seq_G2 *module;
  731. int frame = 0;
  732. std::shared_ptr<Font> font;
  733. float tx[LCD_COLS] = {};
  734. float ty[LCD_ROWS] = {};
  735. char text[LCD_ROWS][LCD_COLS][LCD_TEXT + 1] = {};
  736. //--------------------------------------------------------------------------------------------------------
  737. //! \brief Constructor.
  738. Display(GtxModule_Seq_G2 *module_, const Rect &box_)
  739. :
  740. module(module_)
  741. {
  742. box = box_;
  743. font = Font::load(assetPlugin(plugin, "res/fonts/lcd-solid/LCD_Solid.ttf"));
  744. for (std::size_t col = 0; col < LCD_COLS; col++)
  745. {
  746. tx[col] = 4.0f + col * box.size.x / static_cast<double>(LCD_COLS);
  747. }
  748. for (std::size_t row = 0; row < LCD_ROWS; row++)
  749. {
  750. ty[row] = (row + 1) * 18.0f;
  751. }
  752. for (std::size_t col = 0; col < LCD_COLS; ++col)
  753. {
  754. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  755. {
  756. std::strncpy(text[row][col], "01234567012345670123456701234567", LCD_TEXT);
  757. }
  758. }
  759. }
  760. //--------------------------------------------------------------------------------------------------------
  761. //! \brief ...
  762. void draw_main(NVGcontext *vg)
  763. {
  764. nvgFontSize(vg, 16);
  765. nvgFontFaceId(vg, font->handle);
  766. nvgTextLetterSpacing(vg, -2);
  767. char old = 'x';
  768. for (std::size_t col = 0; col < LCD_COLS; ++col)
  769. {
  770. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  771. {
  772. if (old != text[row][col][0])
  773. {
  774. switch (text[row][col][0])
  775. {
  776. case 'p' : nvgFillColor(vg, nvgRGBA(0xe1, 0x02, 0x78, 0xc0)); break;
  777. default : nvgFillColor(vg, nvgRGBA(0x28, 0xb0, 0xf3, 0xc0)); break;
  778. }
  779. old = text[row][col][0];
  780. }
  781. nvgText(vg, tx[col], ty[row], text[row][col] + 1, NULL);
  782. }
  783. }
  784. }
  785. //--------------------------------------------------------------------------------------------------------
  786. //! \brief ...
  787. void draw(NVGcontext *vg) override
  788. {
  789. // Calculate
  790. if (++frame >= 4)
  791. {
  792. frame = 0;
  793. static const char *note_names[13] = {"C-", "C#", "D-", "Eb", "E-", "F-", "F#", "G-", "Ab", "A-", "Bb", "B-", "??"};
  794. static const char *octave_names[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "?"};
  795. for (std::size_t col = 0; col < LCD_COLS; ++col)
  796. {
  797. for (std::size_t row = 0; row < LCD_ROWS; ++row)
  798. {
  799. bool active = module->lcd_state[module->edit_prog][row][col].active;
  800. int mode = module->lcd_state[module->edit_prog][row][col].mode;
  801. text[row][col][0] = active ? 'p' : 'b';
  802. switch (mode)
  803. {
  804. case 0 :
  805. {
  806. int note = module->lcd_state[module->edit_prog][row][col].note;
  807. int octave = module->lcd_state[module->edit_prog][row][col].octave;
  808. if (note < 0 || note > 12) note = 12;
  809. if (octave < 0 || octave > 9) octave = 9;
  810. text[row][col][1] = note_names[ note][0];
  811. text[row][col][2] = note_names[ note][1];
  812. text[row][col][3] = octave_names[octave][0];
  813. text[row][col][4] = '\0';
  814. }
  815. break;
  816. case 1 :
  817. {
  818. float value = module->lcd_state[module->edit_prog][row][col].value;
  819. snprintf(&text[row][col][1], 4, "%4.2f", value);
  820. }
  821. break;
  822. default :
  823. {
  824. text[row][col][1] = '?';
  825. text[row][col][2] = '\0';
  826. }
  827. break;
  828. }
  829. }
  830. }
  831. }
  832. draw_main(vg);
  833. }
  834. };
  835. #endif
  836. //============================================================================================================
  837. //! \brief The widget.
  838. struct GtxWidget_Seq_G2 : ModuleWidget
  839. {
  840. GtxWidget_Seq_G2(GtxModule_Seq_G2 *module) : ModuleWidget(module)
  841. {
  842. GTX__WIDGET();
  843. box.size = Vec((OUT_LEFT+LCD_COLS+OUT_RIGHT)*3*15, 380);
  844. float grid_left = 3*15*OUT_LEFT;
  845. float grid_right = 3*15*OUT_RIGHT;
  846. float grid_size = box.size.x - grid_left - grid_right;
  847. auto display_rect = Rect(Vec(grid_left, 35), Vec(grid_size, (rad_but()+1.5) * 2 * LCD_ROWS));
  848. #if LCD_ROWS
  849. float g_lcdX[LCD_COLS] = {};
  850. for (std::size_t i = 0; i < LCD_COLS; i++)
  851. {
  852. float x = grid_size / static_cast<double>(LCD_COLS);
  853. g_lcdX[i] = grid_left + x * (i + 0.5);
  854. }
  855. #endif
  856. #if NOB_ROWS
  857. float g_nobX[NOB_COLS] = {};
  858. for (std::size_t i = 0; i < NOB_COLS; i++)
  859. {
  860. float x = grid_size / static_cast<double>(NOB_COLS);
  861. g_nobX[i] = grid_left + x * (i + 0.5);
  862. }
  863. #endif
  864. #if BUT_ROWS
  865. float g_butX[BUT_COLS] = {};
  866. for (std::size_t i = 0; i < BUT_COLS; i++)
  867. {
  868. float x = grid_size / static_cast<double>(BUT_COLS);
  869. g_butX[i] = grid_left + x * (i + 0.5);
  870. }
  871. #endif
  872. float gridXl = grid_left / 2;
  873. float gridXr = box.size.x - grid_right / 2;
  874. float portX[10] = {};
  875. for (std::size_t i = 0; i < 10; i++)
  876. {
  877. float x = 5*6*15 / static_cast<double>(10);
  878. portX[i] = 2*6*15 + x * (i + 0.5);
  879. }
  880. float dX = 0.5*(portX[1]-portX[0]);
  881. float portY[4] = {};
  882. portY[0] = gy(2-0.24);
  883. portY[1] = gy(2+0.22);
  884. float dY = 0.5*(portY[1]-portY[0]);
  885. portY[2] = portY[0] + 0.45 * dY;
  886. portY[3] = portY[0] + dY;
  887. float gridY[LCD_ROWS + PRG_ROWS + NOB_ROWS + BUT_ROWS] = {};
  888. {
  889. std::size_t j = 0;
  890. float pos = 35;
  891. #if LCD_ROWS
  892. for (std::size_t row = 0; row < LCD_ROWS; ++row, ++j)
  893. {
  894. pos += rad_but() + 1.5;
  895. gridY[j] = pos;
  896. pos += rad_but() + 1.5;
  897. }
  898. #endif
  899. pos += 13;
  900. #if PRG_ROWS
  901. {
  902. pos += rad_n_s() + 4.5;
  903. gridY[j] = pos;
  904. pos += rad_n_s() + 4.5;
  905. ++j;
  906. }
  907. #endif
  908. #if NOB_ROWS
  909. for (std::size_t row = 0; row < NOB_ROWS; ++row, ++j)
  910. {
  911. pos += rad_n_s() + 4.5;
  912. gridY[j] = pos;
  913. pos += rad_n_s() + 4.5;
  914. }
  915. #endif
  916. #if BUT_ROWS
  917. for (std::size_t row = 0; row < BUT_ROWS; ++row, ++j)
  918. {
  919. pos += rad_but() + 1.5;
  920. gridY[j] = pos;
  921. pos += rad_but() + 1.5;
  922. }
  923. #endif
  924. }
  925. #if GTX__SAVE_SVG
  926. {
  927. PanelGen pg(assetPlugin(plugin, "build/res/Seq-G2.svg"), box.size, "SEQ-G2");
  928. pg.rect(display_rect.pos, display_rect.size, "fill:#222222;stroke:none");
  929. {
  930. float y0 = display_rect.pos.y - 2;
  931. float y1 = display_rect.pos.y + display_rect.size.y + 3;
  932. pg.line(Vec(g_lcdX[0]-dX, y0), Vec(g_lcdX[0]-dX, y1), "fill:none;stroke:#CEE1FD;stroke-width:3");
  933. for (std::size_t i=3; i<LCD_COLS; i+=4)
  934. {
  935. pg.line(Vec(g_lcdX[i]+dX, y0), Vec(g_lcdX[i]+dX, y1), "fill:none;stroke:#CEE1FD;stroke-width:3");
  936. }
  937. }
  938. for (std::size_t i=0; i<LCD_COLS-1; i++)
  939. {
  940. double x = 0.5 * (g_lcdX[i] + g_lcdX[i+1]);
  941. double y0 = gridY[LCD_ROWS + PRG_ROWS ] - rad_but();
  942. double y1 = gridY[LCD_ROWS + PRG_ROWS + NOB_ROWS + BUT_ROWS - 1] + rad_but();
  943. if (i % 4 == 3)
  944. {
  945. pg.line(Vec(x, y0), Vec(x, y1), "fill:none;stroke:#7092BE;stroke-width:3");
  946. }
  947. else
  948. {
  949. pg.line(Vec(x, y0), Vec(x, y1), "fill:none;stroke:#7092BE;stroke-width:1");
  950. }
  951. }
  952. pg.line(Vec(portX[0]-dX, portY[0]-29), Vec(portX[0]-dX, portY[1]+16), "fill:none;stroke:#7092BE;stroke-width:2");
  953. pg.line(Vec(portX[2]+dX, portY[0]-29), Vec(portX[2]+dX, portY[1]+16), "fill:none;stroke:#7092BE;stroke-width:2");
  954. pg.line(Vec(portX[6]+dX, portY[0]-29), Vec(portX[6]+dX, portY[1]+16), "fill:none;stroke:#7092BE;stroke-width:2");
  955. pg.line(Vec(portX[9]+dX, portY[0]-29), Vec(portX[9]+dX, portY[1]+16), "fill:none;stroke:#7092BE;stroke-width:2");
  956. pg.line(Vec(portX[0], portY[0]), Vec(portX[0], portY[1]), "fill:none;stroke:#7092BE;stroke-width:1");
  957. pg.line(Vec(portX[2], portY[0]), Vec(portX[2], portY[1]), "fill:none;stroke:#7092BE;stroke-width:1");
  958. pg.line(Vec(portX[3], portY[0]), Vec(portX[3], portY[1]), "fill:none;stroke:#7092BE;stroke-width:1");
  959. pg.line(Vec(portX[7], portY[0]), Vec(portX[7], portY[1]), "fill:none;stroke:#7092BE;stroke-width:1");
  960. pg.line(Vec(portX[3]+dX, portY[2]), Vec(portX[5], portY[2]), "fill:none;stroke:#7092BE;stroke-width:1");
  961. pg.line(Vec(portX[3]+dX, portY[3]), Vec(portX[3]+dX, portY[2]), "fill:none;stroke:#7092BE;stroke-width:1");
  962. pg.line(Vec(portX[3], portY[3]), Vec(portX[3]+dX, portY[3]), "fill:none;stroke:#7092BE;stroke-width:1");
  963. pg.nob_sml_raw(g_lcdX[ 4], gridY[LCD_ROWS], "ROW");
  964. pg.nob_sml_raw(g_lcdX[ 5], gridY[LCD_ROWS], "COL");
  965. pg.nob_sml_raw(g_lcdX[ 6], gridY[LCD_ROWS], "SPAN");
  966. pg.nob_sml_raw(g_lcdX[ 7], gridY[LCD_ROWS], "STRIDE");
  967. pg.nob_sml_raw(g_lcdX[ 8], gridY[LCD_ROWS], "NOTE");
  968. pg.nob_sml_raw(g_lcdX[ 9], gridY[LCD_ROWS], "OCT");
  969. pg.nob_sml_raw(g_lcdX[10], gridY[LCD_ROWS], "VALUE");
  970. pg.nob_sml_raw(g_lcdX[11], gridY[LCD_ROWS], "---");
  971. pg.nob_sml_raw(portX[0], portY[0], "CLOCK");
  972. pg.nob_sml_raw(portX[1], portY[0], "RUN"); pg.nob_sml_raw(portX[1], portY[1], "EXT CLK");
  973. pg.nob_sml_raw(portX[2], portY[0], "RESET");
  974. pg.nob_sml_raw(portX[3], portY[0], "PROG");
  975. pg.nob_sml_raw(portX[4], portY[0], "PLAY"); pg.tog_raw2 (portX[4], portY[2], "KNOB", "CV");
  976. pg.nob_sml_raw(portX[5], portY[0], "EDIT"); pg.tog_raw2 (portX[5], portY[2], "KNOB", "CV");
  977. pg.nob_sml_raw(portX[6], portY[0], "COPY"); pg.nob_sml_raw(portX[6], portY[1], "PASTE");
  978. pg.nob_sml_raw(portX[7], portY[0], "STEPS");
  979. pg.nob_sml_raw(portX[8], portY[0], "CLEAR"); pg.nob_sml_raw(portX[8], portY[1], "RAND");
  980. pg.nob_sml_raw(portX[9], portY[0], "ROWS"); pg.nob_sml_raw(portX[9], portY[1], "COLS");
  981. pg.bus_in (0, 2, "GATE");
  982. pg.bus_in (1, 2, "V/OCT");
  983. pg.bus_out(8, 2, "GATE");
  984. pg.bus_out(7, 2, "V/OCT");
  985. }
  986. #endif
  987. setPanel(SVG::load(assetPlugin(plugin, "res/Seq-G2.svg")));
  988. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  989. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  990. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  991. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  992. addChild(new Display(module, display_rect));
  993. addParam(createParamGTX<KnobFreeSml> (Vec(portX[0], portY[0]), module, GtxModule_Seq_G2::CLOCK_PARAM, -2.0f, 6.0f, 2.0f));
  994. addParam(ParamWidget::create<LEDButton> (but(portX[1], portY[0]), module, GtxModule_Seq_G2::RUN_PARAM, 0.0f, 1.0f, 0.0f));
  995. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[1], portY[0]), module, GtxModule_Seq_G2::RUNNING_LIGHT));
  996. addParam(ParamWidget::create<LEDButton> (but(portX[2], portY[0]), module, GtxModule_Seq_G2::RESET_PARAM, 0.0f, 1.0f, 0.0f));
  997. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[2], portY[0]), module, GtxModule_Seq_G2::RESET_LIGHT));
  998. addParam(createParamGTX<KnobSnapSml> (Vec(portX[3], portY[0]), module, GtxModule_Seq_G2::PROG_PARAM, 0.0f, 11.0f, 0.0f));
  999. addParam(ParamWidget::create<CKSS> (tog(portX[4], portY[2]), module, GtxModule_Seq_G2::PLAY_PARAM, 0.0f, 1.0f, 1.0f));
  1000. addParam(ParamWidget::create<CKSS> (tog(portX[5], portY[2]), module, GtxModule_Seq_G2::EDIT_PARAM, 0.0f, 1.0f, 1.0f));
  1001. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX - 30, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 0*2)); // C
  1002. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX - 25, portY[1] - 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 1*2)); // C#
  1003. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX - 20, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 2*2)); // D
  1004. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX - 15, portY[1] - 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 3*2)); // Eb
  1005. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX - 10, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 4*2)); // E
  1006. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX , portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 5*2)); // F
  1007. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 5, portY[1] - 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 6*2)); // Fs
  1008. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 10, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 7*2)); // G
  1009. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 15, portY[1] - 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 8*2)); // Ab
  1010. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 20, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 9*2)); // A
  1011. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 25, portY[1] - 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 10*2)); // Bb
  1012. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(portX[4] + dX + 30, portY[1] + 5 + 1), module, GtxModule_Seq_G2::PROG_LIGHT + 11*2)); // B
  1013. addParam(ParamWidget::create<LEDButton> (but(portX[6], portY[0]), module, GtxModule_Seq_G2::COPY_PARAM, 0.0f, 1.0f, 0.0f));
  1014. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[6], portY[0]), module, GtxModule_Seq_G2::COPY_LIGHT));
  1015. addParam(ParamWidget::create<LEDButton> (but(portX[6], portY[1]), module, GtxModule_Seq_G2::PASTE_PARAM, 0.0f, 1.0f, 0.0f));
  1016. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[6], portY[1]), module, GtxModule_Seq_G2::PASTE_LIGHT));
  1017. addParam(createParamGTX<KnobSnapSml> (Vec(portX[7], portY[0]), module, GtxModule_Seq_G2::STEPS_PARAM, 1.0f, NOB_COLS, NOB_COLS));
  1018. addParam(ParamWidget::create<LEDButton> (but(portX[8], portY[0]), module, GtxModule_Seq_G2::CLEAR_PARAM, 0.0f, 1.0f, 0.0f));
  1019. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[8], portY[0]), module, GtxModule_Seq_G2::CLEAR_LIGHT));
  1020. addParam(ParamWidget::create<LEDButton> (but(portX[8], portY[1]), module, GtxModule_Seq_G2::RANDOM_PARAM, 0.0f, 1.0f, 0.0f));
  1021. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(l_m(portX[8], portY[1]), module, GtxModule_Seq_G2::RANDOM_LIGHT));
  1022. addParam(createParamGTX<KnobSnapSml> (Vec(portX[9], portY[0]), module, GtxModule_Seq_G2::SPAN_R_PARAM, 1.0f, 8.0f, 1.0f));
  1023. addParam(createParamGTX<KnobSnapSml> (Vec(portX[9], portY[1]), module, GtxModule_Seq_G2::SPAN_C_PARAM, 1.0f, 8.0f, 1.0f));
  1024. addInput(createInputGTX<PortInMed>(Vec(portX[0], portY[1]), module, GtxModule_Seq_G2::CLOCK_INPUT));
  1025. addInput(createInputGTX<PortInMed>(Vec(portX[1], portY[1]), module, GtxModule_Seq_G2::EXT_CLOCK_INPUT));
  1026. addInput(createInputGTX<PortInMed>(Vec(portX[2], portY[1]), module, GtxModule_Seq_G2::RESET_INPUT));
  1027. addInput(createInputGTX<PortInMed>(Vec(portX[3], portY[1]), module, GtxModule_Seq_G2::PROG_INPUT));
  1028. addInput(createInputGTX<PortInMed>(Vec(portX[7], portY[1]), module, GtxModule_Seq_G2::STEPS_INPUT));
  1029. {
  1030. std::size_t j = 0;
  1031. #if LCD_ROWS
  1032. for (std::size_t row = 0; row < LCD_ROWS; ++row, ++j)
  1033. {
  1034. if (OUT_LEFT ) addOutput(createOutputGTX<PortOutSml>(Vec(gridXl, gridY[j]), module, GtxModule_Seq_G2::lcd_val_map(row, 0)));
  1035. if (OUT_RIGHT) addOutput(createOutputGTX<PortOutSml>(Vec(gridXr, gridY[j]), module, GtxModule_Seq_G2::lcd_val_map(row, 1)));
  1036. }
  1037. #endif
  1038. #if PRG_ROWS
  1039. ++j;
  1040. #endif
  1041. #if NOB_ROWS
  1042. for (std::size_t row = 0; row < NOB_ROWS; ++row, ++j)
  1043. {
  1044. if (OUT_LEFT ) addOutput(createOutputGTX<PortOutSml>(Vec(gridXl, gridY[j]), module, GtxModule_Seq_G2::nob_val_map(row, 0)));
  1045. if (OUT_RIGHT) addOutput(createOutputGTX<PortOutSml>(Vec(gridXr, gridY[j]), module, GtxModule_Seq_G2::nob_val_map(row, 1)));
  1046. }
  1047. #endif
  1048. #if BUT_ROWS
  1049. for (std::size_t row = 0; row < BUT_ROWS; ++row, ++j)
  1050. {
  1051. if (OUT_LEFT ) addOutput(createOutputGTX<PortOutSml>(Vec(gridXl, gridY[j]), module, GtxModule_Seq_G2::but_val_map(row, 0)));
  1052. if (OUT_RIGHT) addOutput(createOutputGTX<PortOutSml>(Vec(gridXr, gridY[j]), module, GtxModule_Seq_G2::but_val_map(row, 1)));
  1053. }
  1054. #endif
  1055. }
  1056. {
  1057. std::size_t j = 0;
  1058. #if LCD_ROWS
  1059. for (std::size_t row = 0; row < LCD_ROWS; ++row, ++j)
  1060. {
  1061. ;
  1062. }
  1063. #endif
  1064. #if PRG_ROWS
  1065. {
  1066. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 4], gridY[j]), module, GtxModule_Seq_G2::PRG_ROW_PARAM, 0.0f, LCD_ROWS - 1, 0.0f));
  1067. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 5], gridY[j]), module, GtxModule_Seq_G2::PRG_COL_PARAM, 0.0f, LCD_COLS - 1, 0.0f));
  1068. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 6], gridY[j]), module, GtxModule_Seq_G2::PRG_SPAN_PARAM, 1.0f, LCD_COLS , 1.0f));
  1069. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 7], gridY[j]), module, GtxModule_Seq_G2::PRG_STRIDE_PARAM, 1.0f, LCD_COLS - 1, 1.0f));
  1070. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 8], gridY[j]), module, GtxModule_Seq_G2::PRG_NOTE_PARAM, 0.0f, 11.0f, 0.0f));
  1071. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[ 9], gridY[j]), module, GtxModule_Seq_G2::PRG_OCTAVE_PARAM, 0.0f, 8.0f, 4.0f));
  1072. addParam(createParamGTX<KnobFreeSml>(Vec(g_lcdX[10], gridY[j]), module, GtxModule_Seq_G2::PRG_VALUE_PARAM, 0.0f, 10.0f, 0.0f));
  1073. addParam(createParamGTX<KnobSnapSml>(Vec(g_lcdX[11], gridY[j]), module, GtxModule_Seq_G2::PRG_GATE_PARAM, 0.0f, 3.0f, 0.0f));
  1074. ++j;
  1075. }
  1076. #endif
  1077. #if NOB_ROWS
  1078. for (std::size_t row = 0; row < NOB_ROWS; ++row, ++j)
  1079. {
  1080. for (std::size_t col = 0; col < NOB_COLS; ++col)
  1081. {
  1082. if (GtxModule_Seq_G2::is_nob_snap(row))
  1083. {
  1084. addParam(createParamGTX<KnobSnapSml>(Vec(g_nobX[col], gridY[j]), module, GtxModule_Seq_G2::nob_map(row, col), 0.0f, 12.0f, 0.0f));
  1085. }
  1086. else
  1087. {
  1088. addParam(createParamGTX<KnobFreeSml>(Vec(g_nobX[col], gridY[j]), module, GtxModule_Seq_G2::nob_map(row, col), 0.0f, 10.0f, 0.0f));
  1089. }
  1090. }
  1091. }
  1092. #endif
  1093. #if BUT_ROWS
  1094. for (std::size_t row = 0; row < BUT_ROWS; ++row, ++j)
  1095. {
  1096. for (std::size_t col = 0; col < BUT_COLS; ++col)
  1097. {
  1098. addParam(ParamWidget::create<LEDButton> (but(g_butX[col], gridY[j]), module, GtxModule_Seq_G2::but_map(row, col), 0.0f, 1.0f, 0.0f));
  1099. addChild(ModuleLightWidget::create<MediumLight<RedGreenBlueLight>>(l_m(g_butX[col], gridY[j]), module, GtxModule_Seq_G2::led_map(row, col, 0)));
  1100. }
  1101. }
  1102. #endif
  1103. }
  1104. for (std::size_t i=0; i<GTX__N; ++i)
  1105. {
  1106. addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_Seq_G2::imap(GtxModule_Seq_G2::GATE_INPUT, i)));
  1107. addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(2, i)), module, GtxModule_Seq_G2::imap(GtxModule_Seq_G2::VOCT_INPUT, i)));
  1108. addOutput(createOutputGTX<PortOutMed>(Vec(px(8, i), py(2, i)), module, GtxModule_Seq_G2::omap(GtxModule_Seq_G2::GATE_OUTPUT, i)));
  1109. addOutput(createOutputGTX<PortOutMed>(Vec(px(7, i), py(2, i)), module, GtxModule_Seq_G2::omap(GtxModule_Seq_G2::VOCT_OUTPUT, i)));
  1110. }
  1111. addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_Seq_G2::imap(GtxModule_Seq_G2::GATE_INPUT, GTX__N)));
  1112. addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(2)), module, GtxModule_Seq_G2::imap(GtxModule_Seq_G2::VOCT_INPUT, GTX__N)));
  1113. }
  1114. };
  1115. } // namespace rack_plugin_Gratrix
  1116. using namespace rack_plugin_Gratrix;
  1117. RACK_PLUGIN_MODEL_INIT(Gratrix, Seq_G2) {
  1118. Model *model = Model::create<GtxModule_Seq_G2, GtxWidget_Seq_G2>("Gratrix", "Seq-G2-alpha1", "Seq-G2 (alpha)", SEQUENCER_TAG);
  1119. return model;
  1120. }