aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2023-04-03 19:12:24 +0200
committerBad Diode <bd@badd10de.dev>2023-04-03 19:12:24 +0200
commitd8084032bec70170c9614708c6ee10316b19e0c2 (patch)
tree212c05716f21745b2e16f956cc77d51440b0391b
parentd96f6da677bc319f7868e832f09948c94ee6a148 (diff)
downloadstepper-d8084032bec70170c9614708c6ee10316b19e0c2.tar.gz
stepper-d8084032bec70170c9614708c6ee10316b19e0c2.zip
Add noise parameter struct and more ui elements
-rw-r--r--src/sequencer.c318
-rw-r--r--src/text/text.h9
2 files changed, 205 insertions, 122 deletions
diff --git a/src/sequencer.c b/src/sequencer.c
index 8c3f89a..fbdbbfd 100644
--- a/src/sequencer.c
+++ b/src/sequencer.c
@@ -29,6 +29,35 @@
29#define COL_WAVE_A COL_RED 29#define COL_WAVE_A COL_RED
30#define COL_WAVE_B COL_CYAN 30#define COL_WAVE_B COL_CYAN
31 31
32#define CHAN_W 19
33#define CHAN_H 8
34#define CHAN_START_X 34
35#define CHAN_START_Y 92
36#define CHAN_OFFSET_Y 12
37
38#define TRIG_W 15
39#define TRIG_H 24
40#define TRIG_START_X 63
41#define TRIG_START_Y 92
42#define TRIG_OFFSET_X (TRIG_W + 3)
43#define TRIG_OFFSET_Y (TRIG_H + 7)
44
45#define PIANO_W 170
46#define PIANO_H 20
47#define PIANO_START_X 34
48#define PIANO_START_Y 65
49#define PIANO_NOTE_W 2
50
51#define PARAMS_W 170
52#define PARAMS_H 64
53#define PARAMS_START_X 34
54#define PARAMS_START_Y 1
55
56#define R_SIDEBAR_X ((TRIG_START_X) + (TRIG_OFFSET_X) * 8 + 2)
57#define L_SIDEBAR_X ((CHAN_START_X) - 29)
58
59#define SEQ_N_CHANNELS 4
60
32// 61//
33// Assets. 62// Assets.
34// 63//
@@ -155,11 +184,12 @@ static const u32 square_wave[16] = {
155// Globals. 184// Globals.
156// 185//
157 186
158static int bpm = 115; 187static int bpm = 75;
159static int step_counter = 0; 188static int step_counter = 0;
160int trig_selection_loc = 0; 189int trig_selection_loc = 0;
161int param_selection_loc = 0; 190int param_selection_loc = 0;
162int channel_selection_loc = 3; 191int channel_selection_loc = 0;
192int play_status = 0;
163 193
164typedef struct TriggerNote { 194typedef struct TriggerNote {
165 bool active; 195 bool active;
@@ -183,6 +213,13 @@ typedef struct ChannelWaveParams {
183 u32 wave_b[4]; 213 u32 wave_b[4];
184} ChannelWaveParams; 214} ChannelWaveParams;
185 215
216typedef struct ChannelNoiseParams {
217 u8 env_volume;
218 u8 env_time;
219 u8 env_direction;
220 u8 bit_mode;
221} ChannelNoiseParams;
222
186typedef struct ChannelSquare { 223typedef struct ChannelSquare {
187 bool active; 224 bool active;
188 TriggerNote notes[16]; 225 TriggerNote notes[16];
@@ -198,6 +235,7 @@ typedef struct ChannelWave {
198typedef struct ChannelNoise { 235typedef struct ChannelNoise {
199 bool active; 236 bool active;
200 TriggerNote notes[16]; 237 TriggerNote notes[16];
238 ChannelNoiseParams params[16];
201} ChannelNoise; 239} ChannelNoise;
202 240
203static ChannelSquare ch1 = { 241static ChannelSquare ch1 = {
@@ -323,7 +361,7 @@ static ChannelWave ch3 = {
323// TODO: Add default noise parameters data. 361// TODO: Add default noise parameters data.
324static ChannelNoise ch4 = { 362static ChannelNoise ch4 = {
325 .notes = { 363 .notes = {
326 {true, 0}, 364 {true, NOTE_C_4},
327 {false, NOTE_D_4}, 365 {false, NOTE_D_4},
328 {false, NOTE_E_4}, 366 {false, NOTE_E_4},
329 {false, NOTE_F_4}, 367 {false, NOTE_F_4},
@@ -340,19 +378,74 @@ static ChannelNoise ch4 = {
340 {false, NOTE_C_4}, 378 {false, NOTE_C_4},
341 {false, NOTE_C_4}, 379 {false, NOTE_C_4},
342 }, 380 },
381 .params = {
382 {0xF, 0x2, 0, 0},
383 {0xF, 0x2, 0, 0},
384 {0xF, 0x2, 0, 0},
385 {0xF, 0x2, 0, 0},
386 {0xF, 0x2, 0, 0},
387 {0xF, 0x2, 0, 0},
388 {0xF, 0x2, 0, 0},
389 {0xF, 0x2, 0, 0},
390 {0xF, 0x2, 0, 0},
391 {0xF, 0x2, 0, 0},
392 {0xF, 0x2, 0, 0},
393 {0xF, 0x2, 0, 0},
394 {0xF, 0x2, 0, 0},
395 {0xF, 0x2, 0, 0},
396 {0xF, 0x2, 0, 0},
397 {0xF, 0x2, 0, 0},
398 },
343 .active = true, 399 .active = true,
344}; 400};
345 401
346// 402//
347// Trigger render functions. 403// Channel render functions.
348// 404//
349 405
350#define TRIG_W 15 406void
351#define TRIG_H 24 407draw_channels(void) {
352#define TRIG_START_X 64 408 // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG
353#define TRIG_START_Y 92 409 // channels for now, since FM may take some time to develop.
354#define TRIG_OFFSET_X (TRIG_W + 3) 410 Tile *channel_tiles = ASSETS_CHANNEL_BUTTONS;
355#define TRIG_OFFSET_Y (TRIG_H + 7) 411 size_t k = 0;
412 for (size_t i = 0; i < 4; i++) {
413 bool active = false;
414 switch (i) {
415 case 0: {
416 active = ch1.active;
417 } break;
418 case 1: {
419 active = ch2.active;
420 } break;
421 case 2: {
422 active = ch3.active;
423 } break;
424 case 3: {
425 active = ch4.active;
426 } break;
427 }
428 u8 clr = active ? COL_FG : COL_GREY;
429 size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y;
430 draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false);
431 draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false);
432 draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false);
433 }
434}
435
436void
437draw_channel_cursor(size_t i, u8 clr) {
438 size_t offset_x = 0;
439 size_t offset_y = CHAN_H + i * CHAN_OFFSET_Y + 1;
440 size_t x0 = CHAN_START_X + offset_x;
441 size_t x1 = CHAN_START_X + offset_x + CHAN_W;
442 size_t y = CHAN_START_Y + offset_y;
443 draw_line(x0, y, x1, y, clr);
444}
445
446//
447// Trigger render functions.
448//
356 449
357void 450void
358clear_trigger(size_t i) { 451clear_trigger(size_t i) {
@@ -407,6 +500,80 @@ draw_trig_cursor(size_t i, u8 clr) {
407} 500}
408 501
409void 502void
503draw_current_step(u8 col) {
504 size_t offset_x = TRIG_OFFSET_X * (step_counter % 8);
505 size_t offset_y = step_counter < 8 ? 2 : 2 + TRIG_OFFSET_Y;
506 size_t x0 = TRIG_START_X + 4 + offset_x;
507 size_t x1 = TRIG_START_X - 4 + TRIG_W + offset_x;
508 size_t y = TRIG_START_Y - 4 + TRIG_H + offset_y;
509 draw_line(x0, y, x1, y, col);
510}
511
512void
513draw_play() {
514 size_t x = R_SIDEBAR_X;
515 size_t y = TRIG_START_Y;
516 draw_filled_rect(x, y, x + 24, y + 10, COL_BG);
517 draw_rect(x, y, x + 24, y + 10, COL_CYAN);
518 if (play_status == 1) {
519 // Pause button
520 draw_filled_rect(x + 10, y + 3, x + 11, y + 7, COL_CYAN);
521 draw_filled_rect(x + 13, y + 3, x + 14, y + 7, COL_CYAN);
522 } else {
523 // Play button
524 x += 1;
525 draw_line(x + 10, y + 2, x + 10, y + 8, COL_CYAN);
526 draw_line(x + 11, y + 3, x + 11, y + 7, COL_CYAN);
527 draw_line(x + 12, y + 4, x + 12, y + 6, COL_CYAN);
528 draw_line(x + 13, y + 5, x + 13, y + 5, COL_CYAN);
529 }
530}
531
532void
533draw_pattern_buttons() {
534 size_t x = L_SIDEBAR_X;
535 size_t y = PARAMS_START_Y + 17;
536 txt_drawf_small("PAT", x + 5, y - 10, 4, COL_FG);
537 char pat_names[] = {
538 'A', 'B', 'C', 'D',
539 'E', 'F', 'G', 'H',
540 };
541 for (size_t i = 0; i < 8; i++) {
542 draw_rect(x + 5, y, x + 19, y + 12, COL_GREY);
543 txt_drawc(pat_names[i], x + 9, y + 2, 6, COL_GREY);
544 y += 17;
545 }
546}
547
548void
549draw_stop() {
550 size_t x = R_SIDEBAR_X;
551 size_t y = TRIG_START_Y + 14;
552 draw_rect(x, y, x + 24, y + 10, COL_RED);
553 draw_filled_rect(x + 10, y + 3, x + 14, y + 7, COL_RED);
554 // DEBUG: ...
555 draw_pattern_buttons();
556}
557
558void
559draw_bpm() {
560 size_t x = R_SIDEBAR_X;
561 size_t y = TRIG_START_Y + TRIG_H + 9;
562
563 // Draw bounding box.
564 draw_rect(x, y, x + 24, y + 22, COL_FG);
565 draw_line(x + 5, y, x + 19, y, COL_BG);
566 txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG);
567
568 // Make sure its horizontally centered if only 2 digits
569 if (bpm >= 100) {
570 txt_drawf("%d", x + 3, y + 7, 6, COL_FG, bpm);
571 } else {
572 txt_drawf("%d", x + 6, y + 7, 6, COL_FG, bpm);
573 }
574}
575
576void
410draw_triggers(void) { 577draw_triggers(void) {
411 for (size_t i = 0; i < 16; i++) { 578 for (size_t i = 0; i < 16; i++) {
412 size_t offset_x = TRIG_OFFSET_X * (i % 8); 579 size_t offset_x = TRIG_OFFSET_X * (i % 8);
@@ -421,62 +588,6 @@ draw_triggers(void) {
421 } 588 }
422} 589}
423 590
424//
425// Channel render functions.
426//
427
428#define CHAN_W 19
429#define CHAN_H 8
430#define CHAN_START_X 35
431#define CHAN_START_Y 92
432#define CHAN_OFFSET_Y 12
433
434void
435draw_channels(void) {
436 // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG
437 // channels for now, since FM may take some time to develop.
438 Tile *channel_tiles = ASSETS_CHANNEL_BUTTONS;
439 size_t k = 0;
440 for (size_t i = 0; i < 4; i++) {
441 bool active = false;
442 switch (i) {
443 case 0: {
444 active = ch1.active;
445 } break;
446 case 1: {
447 active = ch2.active;
448 } break;
449 case 2: {
450 active = ch3.active;
451 } break;
452 case 3: {
453 active = ch4.active;
454 } break;
455 }
456 u8 clr = active ? COL_FG : COL_GREY;
457 size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y;
458 draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false);
459 draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false);
460 draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false);
461 }
462}
463
464void
465draw_channel_cursor(size_t i, u8 clr) {
466 size_t offset_x = 0;
467 size_t offset_y = CHAN_H + i * CHAN_OFFSET_Y + 1;
468 size_t x0 = CHAN_START_X + offset_x;
469 size_t x1 = CHAN_START_X + offset_x + CHAN_W;
470 size_t y = CHAN_START_Y + offset_y;
471 draw_line(x0, y, x1, y, clr);
472}
473
474#define PIANO_W 170
475#define PIANO_H 20
476#define PIANO_START_X 35
477#define PIANO_START_Y 65
478#define PIANO_NOTE_W 2
479
480void 591void
481draw_note(u8 note, u8 clr) { 592draw_note(u8 note, u8 clr) {
482 size_t octave = note / 12; 593 size_t octave = note / 12;
@@ -611,11 +722,6 @@ draw_piano(void) {
611 } 722 }
612} 723}
613 724
614#define PARAMS_W 170
615#define PARAMS_H 64
616#define PARAMS_START_X 35
617#define PARAMS_START_Y 1
618
619void 725void
620draw_params_cursor_wave(size_t i, u8 clr) { 726draw_params_cursor_wave(size_t i, u8 clr) {
621 u8 x_positions[] = { 727 u8 x_positions[] = {
@@ -1373,49 +1479,11 @@ irq_timer(void) {
1373 } 1479 }
1374 if (ch4.active) { 1480 if (ch4.active) {
1375 TriggerNote *trig = &ch4.notes[step_counter]; 1481 TriggerNote *trig = &ch4.notes[step_counter];
1376 // ChannelNoiseParams *params = &ch4.params[step_counter]; 1482 ChannelNoiseParams *params = &ch4.params[step_counter];
1483 SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(params->env_volume)
1484 | SOUND_NOISE_ENV_TIME(params->env_time)
1485 | SOUND_NOISE_ENV_DIR(params->env_direction);
1377 if (trig->active) { 1486 if (trig->active) {
1378 // switch (params->wave_mode) {
1379 // case 0: {
1380 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1);
1381 // memcpy32(SOUND_WAVE_RAM, params->wave_a, 16);
1382 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
1383 // | SOUND_WAVE_BANK_SELECT(0);
1384 // } break;
1385 // case 1: {
1386 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0);
1387 // memcpy32(SOUND_WAVE_RAM, params->wave_b, 16);
1388 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
1389 // | SOUND_WAVE_BANK_SELECT(1);
1390 // } break;
1391 // case 2: {
1392 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0);
1393 // memcpy32(SOUND_WAVE_RAM, params->wave_b, 16);
1394 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1);
1395 // memcpy32(SOUND_WAVE_RAM, params->wave_a, 16);
1396 // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1)
1397 // | SOUND_WAVE_BANK_SELECT(0);
1398 // } break;
1399 // }
1400 // SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE;
1401
1402 // switch (params->wave_volume) {
1403 // case 0: {
1404 // SOUND_WAVE_CTRL = SOUND_WAVE_MUTE;
1405 // } break;
1406 // case 1: {
1407 // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_25;
1408 // } break;
1409 // case 2: {
1410 // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_50;
1411 // } break;
1412 // case 3: {
1413 // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_75;
1414 // } break;
1415 // case 4: {
1416 // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100;
1417 // } break;
1418 // }
1419 static const u8 div_freq[] = { 1487 static const u8 div_freq[] = {
1420 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, 1488 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4,
1421 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, 1489 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4,
@@ -1432,14 +1500,10 @@ irq_timer(void) {
1432 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1500 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1434 }; 1502 };
1435 SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(0xF)
1436 | SOUND_NOISE_ENV_TIME(0x2)
1437 | SOUND_NOISE_ENV_DIR(0)
1438 | SOUND_NOISE_LENGTH(50);
1439 SOUND_NOISE_FREQ = SOUND_FREQ_RESET 1503 SOUND_NOISE_FREQ = SOUND_FREQ_RESET
1440 | SOUND_NOISE_PRESTEP_FREQ(pre_freq[trig->note]) 1504 | SOUND_NOISE_PRESTEP_FREQ(pre_freq[trig->note])
1441 | SOUND_NOISE_DIV_FREQ(div_freq[trig->note]) 1505 | SOUND_NOISE_DIV_FREQ(div_freq[trig->note])
1442 | SOUND_NOISE_COUNTER_STAGE(0) 1506 | SOUND_NOISE_COUNTER_STAGE(1)
1443 | SOUND_NOISE_TIMED_MODE(0); 1507 | SOUND_NOISE_TIMED_MODE(0);
1444 } else { 1508 } else {
1445 SOUND_NOISE_FREQ = 0; 1509 SOUND_NOISE_FREQ = 0;
@@ -1448,7 +1512,9 @@ irq_timer(void) {
1448 SOUND_NOISE_CTRL = 0; 1512 SOUND_NOISE_CTRL = 0;
1449 SOUND_NOISE_FREQ = 0; 1513 SOUND_NOISE_FREQ = 0;
1450 } 1514 }
1515 draw_current_step(COL_BG);
1451 step_counter = (step_counter + 1) % 16; 1516 step_counter = (step_counter + 1) % 16;
1517 draw_current_step(COL_RED);
1452} 1518}
1453 1519
1454void 1520void
@@ -1489,8 +1555,6 @@ get_current_trig(void) {
1489// selection. 1555// selection.
1490void (*input_handler)(void); 1556void (*input_handler)(void);
1491 1557
1492#define SEQ_N_CHANNELS 4
1493
1494void handle_trigger_selection(void); 1558void handle_trigger_selection(void);
1495void handle_channel_selection(void); 1559void handle_channel_selection(void);
1496void handle_param_selection_sq1(void); 1560void handle_param_selection_sq1(void);
@@ -2132,23 +2196,31 @@ handle_sequencer_input(void) {
2132 2196
2133 if (key_tap(KEY_START)) { 2197 if (key_tap(KEY_START)) {
2134 // Stop the sequencer or start playing from the beginning. 2198 // Stop the sequencer or start playing from the beginning.
2199 play_status ^= 1;
2200 if (step_counter != 0) {
2201 draw_current_step(COL_BG);
2202 }
2135 step_counter = 0; 2203 step_counter = 0;
2136 if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) { 2204 if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) {
2137 set_time(bpm); 2205 set_time(bpm);
2138 } else { 2206 } else {
2207 draw_current_step(COL_RED);
2139 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; 2208 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE;
2140 SOUND_SQUARE1_CTRL = 0; 2209 SOUND_SQUARE1_CTRL = 0;
2141 SOUND_SQUARE2_CTRL = 0; 2210 SOUND_SQUARE2_CTRL = 0;
2142 SOUND_WAVE_CTRL = 0; 2211 SOUND_WAVE_CTRL = 0;
2143 SOUND_NOISE_CTRL = 0; 2212 SOUND_NOISE_CTRL = 0;
2144 } 2213 }
2214 draw_play();
2145 } else if (key_tap(KEY_SELECT)) { 2215 } else if (key_tap(KEY_SELECT)) {
2146 // Play/pause. 2216 // Play/pause.
2217 play_status ^= 1;
2147 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; 2218 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE;
2148 SOUND_SQUARE1_CTRL = 0; 2219 SOUND_SQUARE1_CTRL = 0;
2149 SOUND_SQUARE2_CTRL = 0; 2220 SOUND_SQUARE2_CTRL = 0;
2150 SOUND_WAVE_CTRL = 0; 2221 SOUND_WAVE_CTRL = 0;
2151 SOUND_NOISE_CTRL = 0; 2222 SOUND_NOISE_CTRL = 0;
2223 draw_play();
2152 } 2224 }
2153} 2225}
2154 2226
@@ -2178,7 +2250,11 @@ sequencer_init(void) {
2178 input_handler = handle_trigger_selection; 2250 input_handler = handle_trigger_selection;
2179 draw_trig_cursor(trig_selection_loc, COL_CURSOR); 2251 draw_trig_cursor(trig_selection_loc, COL_CURSOR);
2180 draw_channel_cursor(channel_selection_loc, COL_CURRENT_CHANNEL); 2252 draw_channel_cursor(channel_selection_loc, COL_CURRENT_CHANNEL);
2253 draw_current_step(COL_RED);
2181 draw_parameters(); 2254 draw_parameters();
2255 draw_bpm();
2256 draw_play();
2257 draw_stop();
2182 2258
2183 // Initialize sound system. 2259 // Initialize sound system.
2184 SOUND_STATUS = SOUND_ENABLE; 2260 SOUND_STATUS = SOUND_ENABLE;
@@ -2187,6 +2263,4 @@ sequencer_init(void) {
2187 | SOUND_WAVE 2263 | SOUND_WAVE
2188 | SOUND_NOISE, 3); 2264 | SOUND_NOISE, 3);
2189 SOUND_DSOUND_MASTER = SOUND_DMG25; 2265 SOUND_DSOUND_MASTER = SOUND_DMG25;
2190 // SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(0x8) | SOUND_NOISE_ENV_TIME(0) | SOUND_NOISE_ENV_DIR(1) | 0x4;
2191 // SOUND_NOISE_FREQ = SOUND_FREQ_RESET | SOUND_NOISE_PRESTEP_FREQ(0x7) | SOUND_NOISE_DIV_FREQ(2) | SOUND_NOISE_COUNTER_STAGE(1);
2192} 2266}
diff --git a/src/text/text.h b/src/text/text.h
index 647a021..0bcf090 100644
--- a/src/text/text.h
+++ b/src/text/text.h
@@ -119,6 +119,15 @@ txt_draws(char *msg, size_t x, size_t y, size_t spacing, u8 clr) {
119 } 119 }
120} 120}
121 121
122static inline
123void
124txt_drawc(char c, size_t x, size_t y, size_t spacing, u8 clr) {
125 Tile *tile = FONT_DATA;
126 tile += c;
127 draw_tile(x, y, tile, clr, true);
128 x += spacing;
129}
130
122// Print text to the screen with formatting. 131// Print text to the screen with formatting.
123#define txt_printf(msg, ...) \ 132#define txt_printf(msg, ...) \
124 { \ 133 { \