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.

1310 lines
40KB

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