diff options
author | Bad Diode <bd@badd10de.dev> | 2023-04-03 20:56:38 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2023-04-03 20:56:38 +0200 |
commit | 0fdb142de3225dcc9f4b1eb940ec26ff869c0eb2 (patch) | |
tree | 28f87b9d0a28f6b792eb8de4067e53e08c910dff | |
parent | 6d0cec873eecc694d1ff61f398c5764a7fa55dae (diff) | |
download | stepper-0fdb142de3225dcc9f4b1eb940ec26ff869c0eb2.tar.gz stepper-0fdb142de3225dcc9f4b1eb940ec26ff869c0eb2.zip |
Add pattern selection control
-rw-r--r-- | src/sequencer.c | 221 |
1 files changed, 154 insertions, 67 deletions
diff --git a/src/sequencer.c b/src/sequencer.c index 3f477f3..511e5e4 100644 --- a/src/sequencer.c +++ b/src/sequencer.c | |||
@@ -6,7 +6,6 @@ | |||
6 | // - Copy paste trigs/notes/params | 6 | // - Copy paste trigs/notes/params |
7 | // - Different banks for storing patterns | 7 | // - Different banks for storing patterns |
8 | // - Buttons on the left side for selecting different patterns | 8 | // - Buttons on the left side for selecting different patterns |
9 | // - Pattern chaining or song mode | ||
10 | // - Allow control BPM | 9 | // - Allow control BPM |
11 | // - Finish noise channel | 10 | // - Finish noise channel |
12 | 11 | ||
@@ -24,8 +23,6 @@ | |||
24 | // Theme colors. | 23 | // Theme colors. |
25 | #define COL_CURSOR COL_BLUE | 24 | #define COL_CURSOR COL_BLUE |
26 | #define COL_NOTE_PRESSED COL_GREY | 25 | #define COL_NOTE_PRESSED COL_GREY |
27 | #define COL_CURRENT_CHANNEL COL_GREY | ||
28 | #define COL_CURRENT_TRIG COL_GREY | ||
29 | #define COL_WAVE_A COL_RED | 26 | #define COL_WAVE_A COL_RED |
30 | #define COL_WAVE_B COL_CYAN | 27 | #define COL_WAVE_B COL_CYAN |
31 | 28 | ||
@@ -56,6 +53,12 @@ | |||
56 | #define R_SIDEBAR_X ((TRIG_START_X) + (TRIG_OFFSET_X) * 8 + 4) | 53 | #define R_SIDEBAR_X ((TRIG_START_X) + (TRIG_OFFSET_X) * 8 + 4) |
57 | #define L_SIDEBAR_X ((CHAN_START_X) - 26) | 54 | #define L_SIDEBAR_X ((CHAN_START_X) - 26) |
58 | 55 | ||
56 | #define PAT_START_X (L_SIDEBAR_X + 5) | ||
57 | #define PAT_START_Y 18 | ||
58 | #define PAT_W 14 | ||
59 | #define PAT_H 12 | ||
60 | #define PAT_OFFSET_Y 17 | ||
61 | |||
59 | #define SEQ_N_CHANNELS 4 | 62 | #define SEQ_N_CHANNELS 4 |
60 | 63 | ||
61 | // | 64 | // |
@@ -184,12 +187,15 @@ static const u32 square_wave[16] = { | |||
184 | // Globals. | 187 | // Globals. |
185 | // | 188 | // |
186 | 189 | ||
187 | static int bpm = 75; | 190 | const int default_bpm = 75; |
188 | static int step_counter = 0; | 191 | static int step_counter = 0; |
189 | int trig_selection_loc = 0; | 192 | int trig_selection_loc = 0; |
190 | int param_selection_loc = 0; | 193 | int param_selection_loc = 0; |
191 | int channel_selection_loc = 0; | 194 | int channel_selection_loc = 0; |
195 | int pattern_selection_loc = 1; | ||
192 | int play_status = 0; | 196 | int play_status = 0; |
197 | static int current_pattern = 0; | ||
198 | static int next_pattern = 0; | ||
193 | 199 | ||
194 | typedef struct TriggerNote { | 200 | typedef struct TriggerNote { |
195 | bool active; | 201 | bool active; |
@@ -238,7 +244,7 @@ typedef struct ChannelNoise { | |||
238 | ChannelNoiseParams params[16]; | 244 | ChannelNoiseParams params[16]; |
239 | } ChannelNoise; | 245 | } ChannelNoise; |
240 | 246 | ||
241 | static ChannelSquare ch1 = { | 247 | const ChannelSquare default_ch1 = { |
242 | .notes = { | 248 | .notes = { |
243 | {true, NOTE_C_4}, | 249 | {true, NOTE_C_4}, |
244 | {true, NOTE_D_4}, | 250 | {true, NOTE_D_4}, |
@@ -278,7 +284,7 @@ static ChannelSquare ch1 = { | |||
278 | .active = false, | 284 | .active = false, |
279 | }; | 285 | }; |
280 | 286 | ||
281 | static ChannelSquare ch2 = { | 287 | const ChannelSquare default_ch2 = { |
282 | .notes = { | 288 | .notes = { |
283 | {true, NOTE_C_4}, | 289 | {true, NOTE_C_4}, |
284 | {true, NOTE_D_4}, | 290 | {true, NOTE_D_4}, |
@@ -318,7 +324,7 @@ static ChannelSquare ch2 = { | |||
318 | .active = false, | 324 | .active = false, |
319 | }; | 325 | }; |
320 | 326 | ||
321 | static ChannelWave ch3 = { | 327 | const ChannelWave default_ch3 = { |
322 | .notes = { | 328 | .notes = { |
323 | {true, NOTE_C_4}, | 329 | {true, NOTE_C_4}, |
324 | {true, NOTE_D_4}, | 330 | {true, NOTE_D_4}, |
@@ -358,8 +364,7 @@ static ChannelWave ch3 = { | |||
358 | .active = false, | 364 | .active = false, |
359 | }; | 365 | }; |
360 | 366 | ||
361 | // TODO: Add default noise parameters data. | 367 | const ChannelNoise default_ch4 = { |
362 | static ChannelNoise ch4 = { | ||
363 | .notes = { | 368 | .notes = { |
364 | {true, NOTE_C_4}, | 369 | {true, NOTE_C_4}, |
365 | {false, NOTE_D_4}, | 370 | {false, NOTE_D_4}, |
@@ -399,6 +404,25 @@ static ChannelNoise ch4 = { | |||
399 | .active = true, | 404 | .active = true, |
400 | }; | 405 | }; |
401 | 406 | ||
407 | typedef struct Pattern { | ||
408 | int bpm; | ||
409 | ChannelSquare ch1; | ||
410 | ChannelSquare ch2; | ||
411 | ChannelWave ch3; | ||
412 | ChannelNoise ch4; | ||
413 | } Pattern; | ||
414 | |||
415 | static Pattern patterns[8] = { | ||
416 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
417 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
418 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
419 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
420 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
421 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
422 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
423 | {default_bpm, default_ch1, default_ch2, default_ch3, default_ch4}, | ||
424 | }; | ||
425 | |||
402 | // | 426 | // |
403 | // Channel render functions. | 427 | // Channel render functions. |
404 | // | 428 | // |
@@ -413,16 +437,16 @@ draw_channels(void) { | |||
413 | bool active = false; | 437 | bool active = false; |
414 | switch (i) { | 438 | switch (i) { |
415 | case 0: { | 439 | case 0: { |
416 | active = ch1.active; | 440 | active = patterns[pattern_selection_loc].ch1.active; |
417 | } break; | 441 | } break; |
418 | case 1: { | 442 | case 1: { |
419 | active = ch2.active; | 443 | active = patterns[pattern_selection_loc].ch2.active; |
420 | } break; | 444 | } break; |
421 | case 2: { | 445 | case 2: { |
422 | active = ch3.active; | 446 | active = patterns[pattern_selection_loc].ch3.active; |
423 | } break; | 447 | } break; |
424 | case 3: { | 448 | case 3: { |
425 | active = ch4.active; | 449 | active = patterns[pattern_selection_loc].ch4.active; |
426 | } break; | 450 | } break; |
427 | } | 451 | } |
428 | u8 clr = active ? COL_FG : COL_GREY; | 452 | u8 clr = active ? COL_FG : COL_GREY; |
@@ -454,7 +478,7 @@ clear_trigger(size_t i) { | |||
454 | size_t x0 = TRIG_START_X + offset_x + 1; | 478 | size_t x0 = TRIG_START_X + offset_x + 1; |
455 | size_t x1 = TRIG_START_X + offset_x + TRIG_W - 1; | 479 | size_t x1 = TRIG_START_X + offset_x + TRIG_W - 1; |
456 | size_t y0 = TRIG_START_Y + offset_y + 1; | 480 | size_t y0 = TRIG_START_Y + offset_y + 1; |
457 | size_t y1 = TRIG_START_Y + offset_y + TRIG_H - 1; | 481 | size_t y1 = TRIG_START_Y + offset_y + TRIG_H - 4; |
458 | draw_filled_rect(x0, y0, x1, y1, COL_BG); | 482 | draw_filled_rect(x0, y0, x1, y1, COL_BG); |
459 | } | 483 | } |
460 | 484 | ||
@@ -463,16 +487,16 @@ draw_trigger(size_t chan, size_t i) { | |||
463 | TriggerNote trig = {0}; | 487 | TriggerNote trig = {0}; |
464 | switch (chan) { | 488 | switch (chan) { |
465 | case 0: { | 489 | case 0: { |
466 | trig = ch1.notes[i]; | 490 | trig = patterns[pattern_selection_loc].ch1.notes[i]; |
467 | } break; | 491 | } break; |
468 | case 1: { | 492 | case 1: { |
469 | trig = ch2.notes[i]; | 493 | trig = patterns[pattern_selection_loc].ch2.notes[i]; |
470 | } break; | 494 | } break; |
471 | case 2: { | 495 | case 2: { |
472 | trig = ch3.notes[i]; | 496 | trig = patterns[pattern_selection_loc].ch3.notes[i]; |
473 | } break; | 497 | } break; |
474 | case 3: { | 498 | case 3: { |
475 | trig = ch4.notes[i]; | 499 | trig = patterns[pattern_selection_loc].ch4.notes[i]; |
476 | } break; | 500 | } break; |
477 | } | 501 | } |
478 | if (trig.active) { | 502 | if (trig.active) { |
@@ -503,8 +527,8 @@ void | |||
503 | draw_current_step(u8 col) { | 527 | draw_current_step(u8 col) { |
504 | size_t offset_x = TRIG_OFFSET_X * (step_counter % 8); | 528 | size_t offset_x = TRIG_OFFSET_X * (step_counter % 8); |
505 | size_t offset_y = step_counter < 8 ? 2 : 2 + TRIG_OFFSET_Y; | 529 | size_t offset_y = step_counter < 8 ? 2 : 2 + TRIG_OFFSET_Y; |
506 | size_t x0 = TRIG_START_X + 4 + offset_x; | 530 | size_t x0 = TRIG_START_X + 3 + offset_x; |
507 | size_t x1 = TRIG_START_X - 4 + TRIG_W + offset_x; | 531 | size_t x1 = TRIG_START_X - 3 + TRIG_W + offset_x; |
508 | size_t y = TRIG_START_Y - 4 + TRIG_H + offset_y; | 532 | size_t y = TRIG_START_Y - 4 + TRIG_H + offset_y; |
509 | draw_line(x0, y, x1, y, col); | 533 | draw_line(x0, y, x1, y, col); |
510 | } | 534 | } |
@@ -531,28 +555,44 @@ draw_play() { | |||
531 | 555 | ||
532 | void | 556 | void |
533 | draw_pattern_buttons() { | 557 | draw_pattern_buttons() { |
534 | size_t x = L_SIDEBAR_X; | 558 | size_t x = PAT_START_X; |
535 | size_t y = PARAMS_START_Y + 17; | 559 | size_t y = PAT_START_Y; |
536 | txt_drawf_small("PAT", x + 5, y - 10, 4, COL_FG); | 560 | txt_drawf_small("PAT", x, y - 10, 4, COL_FG); |
537 | char pat_names[] = { | 561 | char pat_names[] = { |
538 | 'A', 'B', 'C', 'D', | 562 | 'A', 'B', 'C', 'D', |
539 | 'E', 'F', 'G', 'H', | 563 | 'E', 'F', 'G', 'H', |
540 | }; | 564 | }; |
541 | for (size_t i = 0; i < 8; i++) { | 565 | for (int i = 0; i < 8; i++) { |
542 | draw_rect(x + 5, y, x + 19, y + 12, COL_GREY); | 566 | int color = COL_GREY; |
543 | txt_drawc(pat_names[i], x + 9, y + 2, 6, COL_GREY); | 567 | if (i == current_pattern) { |
544 | y += 17; | 568 | color = COL_FG; |
569 | } | ||
570 | if (i == next_pattern && current_pattern != next_pattern) { | ||
571 | color = COL_BLUE; | ||
572 | } | ||
573 | draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG); | ||
574 | draw_rect(x, y, x + PAT_W, y + PAT_H, color); | ||
575 | txt_drawc(pat_names[i], x + 4, y + 2, 6, color); | ||
576 | y += PAT_OFFSET_Y; | ||
545 | } | 577 | } |
546 | } | 578 | } |
547 | 579 | ||
548 | void | 580 | void |
581 | draw_pattern_cursor(size_t i, u8 clr) { | ||
582 | size_t offset_x = 0; | ||
583 | size_t offset_y = PAT_H + i * PAT_OFFSET_Y + 2; | ||
584 | size_t x0 = PAT_START_X + offset_x; | ||
585 | size_t x1 = PAT_START_X + offset_x + PAT_W; | ||
586 | size_t y = PAT_START_Y + offset_y; | ||
587 | draw_line(x0, y, x1, y, clr); | ||
588 | } | ||
589 | |||
590 | void | ||
549 | draw_stop() { | 591 | draw_stop() { |
550 | size_t x = R_SIDEBAR_X; | 592 | size_t x = R_SIDEBAR_X; |
551 | size_t y = TRIG_START_Y + 14; | 593 | size_t y = TRIG_START_Y + 14; |
552 | draw_rect(x, y, x + 24, y + 10, COL_RED); | 594 | draw_rect(x, y, x + 24, y + 10, COL_RED); |
553 | draw_filled_rect(x + 10, y + 3, x + 14, y + 7, COL_RED); | 595 | draw_filled_rect(x + 10, y + 3, x + 14, y + 7, COL_RED); |
554 | // DEBUG: ... | ||
555 | draw_pattern_buttons(); | ||
556 | } | 596 | } |
557 | 597 | ||
558 | void | 598 | void |
@@ -566,6 +606,7 @@ draw_bpm() { | |||
566 | txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG); | 606 | txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG); |
567 | 607 | ||
568 | // Make sure its horizontally centered if only 2 digits | 608 | // Make sure its horizontally centered if only 2 digits |
609 | int bpm = patterns[current_pattern].bpm; | ||
569 | if (bpm >= 100) { | 610 | if (bpm >= 100) { |
570 | txt_drawf("%d", x + 3, y + 7, 6, COL_FG, bpm); | 611 | txt_drawf("%d", x + 3, y + 7, 6, COL_FG, bpm); |
571 | } else { | 612 | } else { |
@@ -907,9 +948,10 @@ IWRAM_CODE | |||
907 | void | 948 | void |
908 | draw_parameters_wave(void) { | 949 | draw_parameters_wave(void) { |
909 | // Draw current wave data. | 950 | // Draw current wave data. |
951 | Pattern *pat = &patterns[pattern_selection_loc]; | ||
910 | { | 952 | { |
911 | u8 *wave_a = ch3.params[trig_selection_loc].wave_a; | 953 | u8 *wave_a = pat->ch3.params[trig_selection_loc].wave_a; |
912 | u8 *wave_b = ch3.params[trig_selection_loc].wave_b; | 954 | u8 *wave_b = pat->ch3.params[trig_selection_loc].wave_b; |
913 | 955 | ||
914 | size_t x = PARAMS_START_X; | 956 | size_t x = PARAMS_START_X; |
915 | size_t y = PARAMS_START_Y + 13; | 957 | size_t y = PARAMS_START_Y + 13; |
@@ -966,7 +1008,7 @@ draw_parameters_wave(void) { | |||
966 | draw_line(x, y + 17, x + 30, y + 17, COL_FG); | 1008 | draw_line(x, y + 17, x + 30, y + 17, COL_FG); |
967 | txt_drawf_small("mode", x + 6, y, 4, COL_FG); | 1009 | txt_drawf_small("mode", x + 6, y, 4, COL_FG); |
968 | 1010 | ||
969 | switch (ch3.params[trig_selection_loc].wave_mode) { | 1011 | switch (pat->ch3.params[trig_selection_loc].wave_mode) { |
970 | case 0: { | 1012 | case 0: { |
971 | txt_drawf("A", x + 12, y + 7, 6, COL_FG); | 1013 | txt_drawf("A", x + 12, y + 7, 6, COL_FG); |
972 | } break; | 1014 | } break; |
@@ -990,7 +1032,7 @@ draw_parameters_wave(void) { | |||
990 | draw_line(x, y + 20, x + 30, y + 20, COL_FG); | 1032 | draw_line(x, y + 20, x + 30, y + 20, COL_FG); |
991 | txt_drawf_small("vol", x + 8, y + 3, 4, COL_FG); | 1033 | txt_drawf_small("vol", x + 8, y + 3, 4, COL_FG); |
992 | 1034 | ||
993 | switch (ch3.params[trig_selection_loc].wave_volume) { | 1035 | switch (pat->ch3.params[trig_selection_loc].wave_volume) { |
994 | case 0: { | 1036 | case 0: { |
995 | txt_drawf("0", x + 12, y + 10, 6, COL_FG); | 1037 | txt_drawf("0", x + 12, y + 10, 6, COL_FG); |
996 | } break; | 1038 | } break; |
@@ -1375,12 +1417,13 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1375 | void | 1417 | void |
1376 | draw_parameters(void) { | 1418 | draw_parameters(void) { |
1377 | clear_parameters(); | 1419 | clear_parameters(); |
1420 | Pattern *pat = &patterns[pattern_selection_loc]; | ||
1378 | switch (channel_selection_loc) { | 1421 | switch (channel_selection_loc) { |
1379 | case 0: { | 1422 | case 0: { |
1380 | draw_parameters_square(&ch1.params[trig_selection_loc], true); | 1423 | draw_parameters_square(&pat->ch1.params[trig_selection_loc], true); |
1381 | } break; | 1424 | } break; |
1382 | case 1: { | 1425 | case 1: { |
1383 | draw_parameters_square(&ch2.params[trig_selection_loc], false); | 1426 | draw_parameters_square(&pat->ch2.params[trig_selection_loc], false); |
1384 | } break; | 1427 | } break; |
1385 | case 2: { | 1428 | case 2: { |
1386 | draw_parameters_wave(); | 1429 | draw_parameters_wave(); |
@@ -1392,9 +1435,14 @@ draw_parameters(void) { | |||
1392 | 1435 | ||
1393 | void | 1436 | void |
1394 | irq_timer(void) { | 1437 | irq_timer(void) { |
1395 | if (ch1.active) { | 1438 | if (current_pattern != next_pattern && step_counter == 0) { |
1396 | TriggerNote *trig = &ch1.notes[step_counter]; | 1439 | current_pattern = next_pattern; |
1397 | ChannelSquareParams *params = &ch1.params[step_counter]; | 1440 | draw_pattern_buttons(); |
1441 | } | ||
1442 | Pattern *pat = &patterns[current_pattern]; | ||
1443 | if (pat->ch1.active) { | ||
1444 | TriggerNote *trig = &pat->ch1.notes[step_counter]; | ||
1445 | ChannelSquareParams *params = &pat->ch1.params[step_counter]; | ||
1398 | if (trig->active) { | 1446 | if (trig->active) { |
1399 | SOUND_SQUARE1_SWEEP = SOUND_SWEEP_NUMBER(params->sweep_number) | 1447 | SOUND_SQUARE1_SWEEP = SOUND_SWEEP_NUMBER(params->sweep_number) |
1400 | | SOUND_SWEEP_DIR(params->sweep_direction) | 1448 | | SOUND_SWEEP_DIR(params->sweep_direction) |
@@ -1410,9 +1458,9 @@ irq_timer(void) { | |||
1410 | SOUND_SQUARE1_CTRL = 0; | 1458 | SOUND_SQUARE1_CTRL = 0; |
1411 | SOUND_SQUARE1_FREQ = 0; | 1459 | SOUND_SQUARE1_FREQ = 0; |
1412 | } | 1460 | } |
1413 | if (ch2.active) { | 1461 | if (pat->ch2.active) { |
1414 | TriggerNote *trig = &ch2.notes[step_counter]; | 1462 | TriggerNote *trig = &pat->ch2.notes[step_counter]; |
1415 | ChannelSquareParams *params = &ch2.params[step_counter]; | 1463 | ChannelSquareParams *params = &pat->ch2.params[step_counter]; |
1416 | if (trig->active) { | 1464 | if (trig->active) { |
1417 | SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(params->env_volume) | 1465 | SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(params->env_volume) |
1418 | | SOUND_SQUARE_ENV_TIME(params->env_time) | 1466 | | SOUND_SQUARE_ENV_TIME(params->env_time) |
@@ -1425,9 +1473,9 @@ irq_timer(void) { | |||
1425 | SOUND_SQUARE2_CTRL = 0; | 1473 | SOUND_SQUARE2_CTRL = 0; |
1426 | SOUND_SQUARE2_FREQ = 0; | 1474 | SOUND_SQUARE2_FREQ = 0; |
1427 | } | 1475 | } |
1428 | if (ch3.active) { | 1476 | if (pat->ch3.active) { |
1429 | TriggerNote *trig = &ch3.notes[step_counter]; | 1477 | TriggerNote *trig = &pat->ch3.notes[step_counter]; |
1430 | ChannelWaveParams *params = &ch3.params[step_counter]; | 1478 | ChannelWaveParams *params = &pat->ch3.params[step_counter]; |
1431 | if (trig->active) { | 1479 | if (trig->active) { |
1432 | switch (params->wave_mode) { | 1480 | switch (params->wave_mode) { |
1433 | case 0: { | 1481 | case 0: { |
@@ -1477,9 +1525,9 @@ irq_timer(void) { | |||
1477 | SOUND_WAVE_CTRL = 0; | 1525 | SOUND_WAVE_CTRL = 0; |
1478 | SOUND_WAVE_FREQ = 0; | 1526 | SOUND_WAVE_FREQ = 0; |
1479 | } | 1527 | } |
1480 | if (ch4.active) { | 1528 | if (pat->ch4.active) { |
1481 | TriggerNote *trig = &ch4.notes[step_counter]; | 1529 | TriggerNote *trig = &pat->ch4.notes[step_counter]; |
1482 | ChannelNoiseParams *params = &ch4.params[step_counter]; | 1530 | ChannelNoiseParams *params = &pat->ch4.params[step_counter]; |
1483 | SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(params->env_volume) | 1531 | SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(params->env_volume) |
1484 | | SOUND_NOISE_ENV_TIME(params->env_time) | 1532 | | SOUND_NOISE_ENV_TIME(params->env_time) |
1485 | | SOUND_NOISE_ENV_DIR(params->env_direction); | 1533 | | SOUND_NOISE_ENV_DIR(params->env_direction); |
@@ -1533,18 +1581,19 @@ set_time(int bpm) { | |||
1533 | 1581 | ||
1534 | TriggerNote * | 1582 | TriggerNote * |
1535 | get_current_trig(void) { | 1583 | get_current_trig(void) { |
1584 | Pattern *pat = &patterns[pattern_selection_loc]; | ||
1536 | switch (channel_selection_loc) { | 1585 | switch (channel_selection_loc) { |
1537 | case 0: { | 1586 | case 0: { |
1538 | return &ch1.notes[trig_selection_loc]; | 1587 | return &pat->ch1.notes[trig_selection_loc]; |
1539 | } break; | 1588 | } break; |
1540 | case 1: { | 1589 | case 1: { |
1541 | return &ch2.notes[trig_selection_loc]; | 1590 | return &pat->ch2.notes[trig_selection_loc]; |
1542 | } break; | 1591 | } break; |
1543 | case 2: { | 1592 | case 2: { |
1544 | return &ch3.notes[trig_selection_loc]; | 1593 | return &pat->ch3.notes[trig_selection_loc]; |
1545 | } break; | 1594 | } break; |
1546 | case 3: { | 1595 | case 3: { |
1547 | return &ch4.notes[trig_selection_loc]; | 1596 | return &pat->ch4.notes[trig_selection_loc]; |
1548 | } break; | 1597 | } break; |
1549 | } | 1598 | } |
1550 | return NULL; | 1599 | return NULL; |
@@ -1557,6 +1606,7 @@ void (*input_handler)(void); | |||
1557 | 1606 | ||
1558 | void handle_trigger_selection(void); | 1607 | void handle_trigger_selection(void); |
1559 | void handle_channel_selection(void); | 1608 | void handle_channel_selection(void); |
1609 | void handle_pattern_selection(void); | ||
1560 | void handle_param_selection_sq1(void); | 1610 | void handle_param_selection_sq1(void); |
1561 | void handle_param_selection_sq2(void); | 1611 | void handle_param_selection_sq2(void); |
1562 | void handle_param_selection_wave(void); | 1612 | void handle_param_selection_wave(void); |
@@ -1567,16 +1617,16 @@ handle_channel_selection(void) { | |||
1567 | if (key_tap(KEY_B)) { | 1617 | if (key_tap(KEY_B)) { |
1568 | switch (channel_selection_loc) { | 1618 | switch (channel_selection_loc) { |
1569 | case 0: { | 1619 | case 0: { |
1570 | ch1.active ^= 1; | 1620 | patterns[pattern_selection_loc].ch1.active ^= 1; |
1571 | } break; | 1621 | } break; |
1572 | case 1: { | 1622 | case 1: { |
1573 | ch2.active ^= 1; | 1623 | patterns[pattern_selection_loc].ch2.active ^= 1; |
1574 | } break; | 1624 | } break; |
1575 | case 2: { | 1625 | case 2: { |
1576 | ch3.active ^= 1; | 1626 | patterns[pattern_selection_loc].ch3.active ^= 1; |
1577 | } break; | 1627 | } break; |
1578 | case 3: { | 1628 | case 3: { |
1579 | ch4.active ^= 1; | 1629 | patterns[pattern_selection_loc].ch4.active ^= 1; |
1580 | } break; | 1630 | } break; |
1581 | } | 1631 | } |
1582 | draw_channels(); | 1632 | draw_channels(); |
@@ -1585,11 +1635,15 @@ handle_channel_selection(void) { | |||
1585 | trig_selection_loc = 0; | 1635 | trig_selection_loc = 0; |
1586 | param_selection_loc = 0; | 1636 | param_selection_loc = 0; |
1587 | input_handler = handle_trigger_selection; | 1637 | input_handler = handle_trigger_selection; |
1588 | draw_channel_cursor(channel_selection_loc, COL_CURRENT_CHANNEL); | 1638 | draw_channel_cursor(channel_selection_loc, COL_GREY); |
1589 | draw_trig_cursor(trig_selection_loc, COL_CURSOR); | 1639 | draw_trig_cursor(trig_selection_loc, COL_CURSOR); |
1590 | TriggerNote *trig = get_current_trig(); | 1640 | TriggerNote *trig = get_current_trig(); |
1591 | draw_note(trig->note, COL_NOTE_PRESSED); | 1641 | draw_note(trig->note, COL_NOTE_PRESSED); |
1592 | draw_parameters(); | 1642 | draw_parameters(); |
1643 | } else if (key_tap(KEY_LEFT)) { | ||
1644 | input_handler = handle_pattern_selection; | ||
1645 | draw_channel_cursor(channel_selection_loc, COL_GREY); | ||
1646 | draw_pattern_cursor(pattern_selection_loc, COL_CURSOR); | ||
1593 | } else if (key_tap(KEY_UP)) { | 1647 | } else if (key_tap(KEY_UP)) { |
1594 | draw_channel_cursor(channel_selection_loc, COL_BG); | 1648 | draw_channel_cursor(channel_selection_loc, COL_BG); |
1595 | if (channel_selection_loc == 0) { | 1649 | if (channel_selection_loc == 0) { |
@@ -1612,6 +1666,33 @@ handle_channel_selection(void) { | |||
1612 | } | 1666 | } |
1613 | 1667 | ||
1614 | void | 1668 | void |
1669 | handle_pattern_selection(void) { | ||
1670 | if (key_tap(KEY_B)) { | ||
1671 | next_pattern = pattern_selection_loc; | ||
1672 | draw_pattern_buttons(); | ||
1673 | } | ||
1674 | if (key_tap(KEY_RIGHT)) { | ||
1675 | input_handler = handle_channel_selection; | ||
1676 | draw_channel_cursor(channel_selection_loc, COL_CURSOR); | ||
1677 | draw_pattern_cursor(pattern_selection_loc, COL_GREY); | ||
1678 | } else if (key_tap(KEY_UP)) { | ||
1679 | if (pattern_selection_loc > 0) { | ||
1680 | draw_pattern_cursor(pattern_selection_loc, COL_BG); | ||
1681 | pattern_selection_loc = pattern_selection_loc - 1; | ||
1682 | draw_pattern_cursor(pattern_selection_loc, COL_CURSOR); | ||
1683 | draw_triggers(); | ||
1684 | } | ||
1685 | } else if (key_tap(KEY_DOWN)) { | ||
1686 | if (pattern_selection_loc < 7) { | ||
1687 | draw_pattern_cursor(pattern_selection_loc, COL_BG); | ||
1688 | pattern_selection_loc = pattern_selection_loc + 1; | ||
1689 | draw_pattern_cursor(pattern_selection_loc, COL_CURSOR); | ||
1690 | draw_triggers(); | ||
1691 | } | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1695 | void | ||
1615 | handle_param_selection_sq1(void) { | 1696 | handle_param_selection_sq1(void) { |
1616 | // Go back to trigger selection. | 1697 | // Go back to trigger selection. |
1617 | if (key_tap(KEY_A)) { | 1698 | if (key_tap(KEY_A)) { |
@@ -1674,7 +1755,8 @@ handle_param_selection_sq1(void) { | |||
1674 | } else { | 1755 | } else { |
1675 | inc = 1; | 1756 | inc = 1; |
1676 | } | 1757 | } |
1677 | ChannelSquareParams *params = &ch1.params[trig_selection_loc]; | 1758 | Pattern *pat = &patterns[pattern_selection_loc]; |
1759 | ChannelSquareParams *params = &pat->ch1.params[trig_selection_loc]; | ||
1678 | switch (param_selection_loc) { | 1760 | switch (param_selection_loc) { |
1679 | case 0: { | 1761 | case 0: { |
1680 | params->duty_cycle = CLAMP(params->duty_cycle + inc, 0, 3); | 1762 | params->duty_cycle = CLAMP(params->duty_cycle + inc, 0, 3); |
@@ -1734,7 +1816,8 @@ handle_param_selection_sq2(void) { | |||
1734 | } else { | 1816 | } else { |
1735 | inc = 1; | 1817 | inc = 1; |
1736 | } | 1818 | } |
1737 | ChannelSquareParams *params = &ch2.params[trig_selection_loc]; | 1819 | Pattern *pat = &patterns[pattern_selection_loc]; |
1820 | ChannelSquareParams *params = &pat->ch2.params[trig_selection_loc]; | ||
1738 | switch (param_selection_loc) { | 1821 | switch (param_selection_loc) { |
1739 | case 0: { | 1822 | case 0: { |
1740 | params->duty_cycle = CLAMP(params->duty_cycle + inc, 0, 3); | 1823 | params->duty_cycle = CLAMP(params->duty_cycle + inc, 0, 3); |
@@ -1756,6 +1839,8 @@ handle_param_selection_sq2(void) { | |||
1756 | 1839 | ||
1757 | void | 1840 | void |
1758 | handle_param_selection_wave(void) { | 1841 | handle_param_selection_wave(void) { |
1842 | Pattern *pat = &patterns[pattern_selection_loc]; | ||
1843 | |||
1759 | // Go back to trigger selection. | 1844 | // Go back to trigger selection. |
1760 | if (key_tap(KEY_A)) { | 1845 | if (key_tap(KEY_A)) { |
1761 | draw_params_cursor(param_selection_loc, COL_BG); | 1846 | draw_params_cursor(param_selection_loc, COL_BG); |
@@ -1864,7 +1949,7 @@ handle_param_selection_wave(void) { | |||
1864 | if (param_selection_loc < 32) { | 1949 | if (param_selection_loc < 32) { |
1865 | // Draw on wave a. | 1950 | // Draw on wave a. |
1866 | u8 byte_number = param_selection_loc / 2; | 1951 | u8 byte_number = param_selection_loc / 2; |
1867 | u8 *byte = &ch3.params[trig_selection_loc].wave_a; | 1952 | u8 *byte = &pat->ch3.params[trig_selection_loc].wave_a; |
1868 | byte += byte_number; | 1953 | byte += byte_number; |
1869 | if (odd) { | 1954 | if (odd) { |
1870 | *byte = (~0xF & *byte) | ((*byte + inc) & 0xF); | 1955 | *byte = (~0xF & *byte) | ((*byte + inc) & 0xF); |
@@ -1874,7 +1959,7 @@ handle_param_selection_wave(void) { | |||
1874 | } else if (param_selection_loc < 64){ | 1959 | } else if (param_selection_loc < 64){ |
1875 | // Draw on wave b. | 1960 | // Draw on wave b. |
1876 | u8 byte_number = (param_selection_loc - 32) / 2; | 1961 | u8 byte_number = (param_selection_loc - 32) / 2; |
1877 | u8 *byte = &ch3.params[trig_selection_loc].wave_b; | 1962 | u8 *byte = &pat->ch3.params[trig_selection_loc].wave_b; |
1878 | byte += byte_number; | 1963 | byte += byte_number; |
1879 | if (odd) { | 1964 | if (odd) { |
1880 | *byte = (~0xF & *byte) | ((*byte + inc) & 0xF); | 1965 | *byte = (~0xF & *byte) | ((*byte + inc) & 0xF); |
@@ -1883,8 +1968,8 @@ handle_param_selection_wave(void) { | |||
1883 | } | 1968 | } |
1884 | } else if (param_selection_loc < 72) { | 1969 | } else if (param_selection_loc < 72) { |
1885 | // Copy default waves. | 1970 | // Copy default waves. |
1886 | u32 *wave_a = &ch3.params[trig_selection_loc].wave_a; | 1971 | u32 *wave_a = &pat->ch3.params[trig_selection_loc].wave_a; |
1887 | u32 *wave_b = &ch3.params[trig_selection_loc].wave_b; | 1972 | u32 *wave_b = &pat->ch3.params[trig_selection_loc].wave_b; |
1888 | switch (param_selection_loc) { | 1973 | switch (param_selection_loc) { |
1889 | case 64: { | 1974 | case 64: { |
1890 | memcpy32(wave_a, sine_wave, 16); | 1975 | memcpy32(wave_a, sine_wave, 16); |
@@ -1918,10 +2003,10 @@ handle_param_selection_wave(void) { | |||
1918 | } break; | 2003 | } break; |
1919 | } | 2004 | } |
1920 | } else if (param_selection_loc == 72) { | 2005 | } else if (param_selection_loc == 72) { |
1921 | u8 *wave_mode = &ch3.params[trig_selection_loc].wave_mode; | 2006 | u8 *wave_mode = &pat->ch3.params[trig_selection_loc].wave_mode; |
1922 | *wave_mode = CLAMP(*wave_mode + inc, 0, 2); | 2007 | *wave_mode = CLAMP(*wave_mode + inc, 0, 2); |
1923 | } else if (param_selection_loc == 73) { | 2008 | } else if (param_selection_loc == 73) { |
1924 | u8 *wave_volume = &ch3.params[trig_selection_loc].wave_volume; | 2009 | u8 *wave_volume = &pat->ch3.params[trig_selection_loc].wave_volume; |
1925 | *wave_volume = CLAMP(*wave_volume + inc, 0, 4); | 2010 | *wave_volume = CLAMP(*wave_volume + inc, 0, 4); |
1926 | } | 2011 | } |
1927 | draw_parameters(); | 2012 | draw_parameters(); |
@@ -2185,7 +2270,7 @@ handle_trigger_selection(void) { | |||
2185 | } break; | 2270 | } break; |
2186 | } | 2271 | } |
2187 | draw_params_cursor(param_selection_loc, COL_CURSOR); | 2272 | draw_params_cursor(param_selection_loc, COL_CURSOR); |
2188 | draw_trig_cursor(trig_selection_loc, COL_CURRENT_TRIG); | 2273 | draw_trig_cursor(trig_selection_loc, COL_GREY); |
2189 | } | 2274 | } |
2190 | } | 2275 | } |
2191 | 2276 | ||
@@ -2202,7 +2287,7 @@ handle_sequencer_input(void) { | |||
2202 | } | 2287 | } |
2203 | step_counter = 0; | 2288 | step_counter = 0; |
2204 | if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) { | 2289 | if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) { |
2205 | set_time(bpm); | 2290 | set_time(patterns[current_pattern].bpm); |
2206 | } else { | 2291 | } else { |
2207 | draw_current_step(COL_RED); | 2292 | draw_current_step(COL_RED); |
2208 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; | 2293 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; |
@@ -2249,12 +2334,14 @@ sequencer_init(void) { | |||
2249 | // Initialize input handler. | 2334 | // Initialize input handler. |
2250 | input_handler = handle_trigger_selection; | 2335 | input_handler = handle_trigger_selection; |
2251 | draw_trig_cursor(trig_selection_loc, COL_CURSOR); | 2336 | draw_trig_cursor(trig_selection_loc, COL_CURSOR); |
2252 | draw_channel_cursor(channel_selection_loc, COL_CURRENT_CHANNEL); | 2337 | draw_channel_cursor(channel_selection_loc, COL_GREY); |
2338 | draw_pattern_cursor(pattern_selection_loc, COL_GREY); | ||
2253 | draw_current_step(COL_RED); | 2339 | draw_current_step(COL_RED); |
2254 | draw_parameters(); | 2340 | draw_parameters(); |
2255 | draw_bpm(); | 2341 | draw_bpm(); |
2256 | draw_play(); | 2342 | draw_play(); |
2257 | draw_stop(); | 2343 | draw_stop(); |
2344 | draw_pattern_buttons(); | ||
2258 | 2345 | ||
2259 | // Initialize sound system. | 2346 | // Initialize sound system. |
2260 | SOUND_STATUS = SOUND_ENABLE; | 2347 | SOUND_STATUS = SOUND_ENABLE; |