From 436b4a1d28f5939e1c0f8792317a639b091b0f29 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 8 Jun 2021 13:36:20 +0200 Subject: Start FSM based input handling --- src/sequencer.c | 778 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 473 insertions(+), 305 deletions(-) (limited to 'src') diff --git a/src/sequencer.c b/src/sequencer.c index 43e6ffc..46e57ef 100644 --- a/src/sequencer.c +++ b/src/sequencer.c @@ -1,4 +1,98 @@ #include "rng.c" +#include "text.h" + +// +// Assets. +// + +#define ASSETS_DATA ((u32*)(MEM_VRAM + KB(32))) + +static const u32 note_names[] = { + 0x000000e0, 0x202020e0, 0x0000000e, 0x080e020e, + 0x00000098, 0xa8a8a898, 0x00000038, 0x203b0a39, + 0x00000060, 0xa0a0a060, 0x0000000e, 0x080e020e, + 0x000000b8, 0x889888b8, 0x00000038, 0x203b0a39, + 0x000000e0, 0x206020e0, 0x0000000e, 0x080e020e, + 0x000000e0, 0x20602020, 0x0000000e, 0x080e020e, + 0x000000b8, 0x8888a8b8, 0x00000038, 0x203b0a39, + 0x000000e0, 0x2020a0e0, 0x0000000e, 0x080e020e, + 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x203b0a39, + 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x080e020e, + 0x000000b8, 0xa898a8b8, 0x00000038, 0x203b0a39, + 0x000000e0, 0xa060a0e0, 0x0000000e, 0x080e020e, + 0x000000e0, 0x202020e0, 0x0000000e, 0x080c080e, + 0x00000098, 0xa8a8a898, 0x00000038, 0x20332239, + 0x00000060, 0xa0a0a060, 0x0000000e, 0x080c080e, + 0x000000b8, 0x889888b8, 0x00000038, 0x20332239, + 0x000000e0, 0x206020e0, 0x0000000e, 0x080c080e, + 0x000000e0, 0x20602020, 0x0000000e, 0x080c080e, + 0x000000b8, 0x8888a8b8, 0x00000038, 0x20332239, + 0x000000e0, 0x2020a0e0, 0x0000000e, 0x080c080e, + 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x20332239, + 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x080c080e, + 0x000000b8, 0xa898a8b8, 0x00000038, 0x20332239, + 0x000000e0, 0xa060a0e0, 0x0000000e, 0x080c080e, + 0x000000e0, 0x202020e0, 0x0000000a, 0x0a0e0808, + 0x00000098, 0xa8a8a898, 0x00000028, 0x283b2221, + 0x00000060, 0xa0a0a060, 0x0000000a, 0x0a0e0808, + 0x000000b8, 0x889888b8, 0x00000028, 0x283b2221, + 0x000000e0, 0x206020e0, 0x0000000a, 0x0a0e0808, + 0x000000e0, 0x20602020, 0x0000000a, 0x0a0e0808, + 0x000000b8, 0x8888a8b8, 0x00000028, 0x283b2221, + 0x000000e0, 0x2020a0e0, 0x0000000a, 0x0a0e0808, + 0x000000b8, 0xa8a8b8a8, 0x00000028, 0x283b2221, + 0x000000e0, 0xa0a0e0a0, 0x0000000a, 0x0a0e0808, + 0x000000b8, 0xa898a8b8, 0x00000028, 0x283b2221, + 0x000000e0, 0xa060a0e0, 0x0000000a, 0x0a0e0808, + 0x000000e0, 0x202020e0, 0x0000000e, 0x020e080e, + 0x00000098, 0xa8a8a898, 0x00000038, 0x083b2239, + 0x00000060, 0xa0a0a060, 0x0000000e, 0x020e080e, + 0x000000b8, 0x889888b8, 0x00000038, 0x083b2239, + 0x000000e0, 0x206020e0, 0x0000000e, 0x020e080e, + 0x000000e0, 0x20602020, 0x0000000e, 0x020e080e, + 0x000000b8, 0x8888a8b8, 0x00000038, 0x083b2239, + 0x000000e0, 0x2020a0e0, 0x0000000e, 0x020e080e, + 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x083b2239, + 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x020e080e, + 0x000000b8, 0xa898a8b8, 0x00000038, 0x083b2239, + 0x000000e0, 0xa060a0e0, 0x0000000e, 0x020e080e, + 0x000000e0, 0x202020e0, 0x0000000e, 0x020e0a0e, + 0x00000098, 0xa8a8a898, 0x00000038, 0x083b2a39, + 0x00000060, 0xa0a0a060, 0x0000000e, 0x020e0a0e, + 0x000000b8, 0x889888b8, 0x00000038, 0x083b2a39, + 0x000000e0, 0x206020e0, 0x0000000e, 0x020e0a0e, + 0x000000e0, 0x20602020, 0x0000000e, 0x020e0a0e, + 0x000000b8, 0x8888a8b8, 0x00000038, 0x083b2a39, + 0x000000e0, 0x2020a0e0, 0x0000000e, 0x020e0a0e, + 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x083b2a39, + 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x020e0a0e, + 0x000000b8, 0xa898a8b8, 0x00000038, 0x083b2a39, + 0x000000e0, 0xa060a0e0, 0x0000000e, 0x020e0a0e, + 0x000000e0, 0x202020e0, 0x0000000e, 0x08040202, + 0x00000098, 0xa8a8a898, 0x00000038, 0x20130a09, + 0x00000060, 0xa0a0a060, 0x0000000e, 0x08040202, + 0x000000b8, 0x889888b8, 0x00000038, 0x20130a09, + 0x000000e0, 0x206020e0, 0x0000000e, 0x08040202, + 0x000000e0, 0x20602020, 0x0000000e, 0x08040202, + 0x000000b8, 0x8888a8b8, 0x00000038, 0x20130a09, + 0x000000e0, 0x2020a0e0, 0x0000000e, 0x08040202, + 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x20130a09, + 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x08040202, + 0x000000b8, 0xa898a8b8, 0x00000038, 0x20130a09, + 0x000000e0, 0xa060a0e0, 0x0000000e, 0x08040202, + 0x000000e0, 0x202020e0, 0x0000000e, 0x0a0e0a0e, +}; + +static const u32 channel_buttons[] = { + 0xff017111, 0x117101ff, 0xff008585, 0x879500ff, + 0x0f080808, 0x0808080f, 0xff01b989, 0x89b901ff, + 0xff004242, 0x434a00ff, 0x0f080909, 0x0909080f, + 0xff015d45, 0xc55d01ff, 0xff00a1a1, 0xa1a500ff, + 0x0f080a0a, 0x0a0a080f, 0xff015d45, 0xc55d01ff, + 0xff00a1a1, 0xa12500ff, 0x0f080a0a, 0x0a0b080f, + 0xff01c141, 0xc14101ff, 0xff00151c, 0x141400ff, + 0x0f080808, 0x0808080f, +}; // // Globals. @@ -12,7 +106,7 @@ static int bpm = 115; static int step_counter = 0; int trig_selection_loc = 0; int param_selection_loc = 64; -int channel_selection_loc = 2; +int channel_selection_loc = 0; SeqSelect current_selection = SEQ_SELECT_TRIGGER; // @@ -61,19 +155,19 @@ typedef struct SeqTrigger { static SeqTrigger sequences[3][16] = { // Synth 1. { - {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_D_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_D_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_E_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_F_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_G_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_A_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_G_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_A_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_B_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, - {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, + {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}}, @@ -99,22 +193,22 @@ static SeqTrigger sequences[3][16] = { }, // Synth 3. { - {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, - {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}}, + {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, + {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0}, {0}}, }, }; @@ -127,20 +221,53 @@ static SeqTrigger sequences[3][16] = { #define TRIG_OFFSET_Y (TRIG_H + 7) void -draw_triggers(void) { - for (size_t i = 0; i < 8; i++) { - size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i; - size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i; - size_t y0 = TRIG_START_Y; - size_t y1 = TRIG_START_Y + TRIG_H; - draw_rect(x0, y0, x1, y1, 1); +clear_trigger(size_t i) { + size_t offset_x = TRIG_OFFSET_X * (i % 8); + size_t offset_y = i < 8 ? 0 : TRIG_OFFSET_Y; + size_t x0 = TRIG_START_X + offset_x + 1; + size_t x1 = TRIG_START_X + offset_x + TRIG_W - 1; + size_t y0 = TRIG_START_Y + offset_y + 1; + size_t y1 = TRIG_START_Y + offset_y + TRIG_H - 1; + draw_filled_rect(x0, y0, x1, y1, 0); +} + +void +draw_trigger(size_t chan, size_t i) { + if (sequences[chan][i].trigger) { + size_t offset_x = TRIG_OFFSET_X * (i % 8); + size_t offset_y = i < 8 ? 0 : TRIG_OFFSET_Y; + size_t x = TRIG_START_X + offset_x; + size_t y = TRIG_START_Y + offset_y; + Tile *tiles = ASSETS_DATA; + tiles += 2 * sequences[chan][i].note; + draw_tile(x, y, tiles, true); + draw_tile(x + 8, y, tiles + 1, true); + } else { + clear_trigger(i); } - for (size_t i = 0; i < 8; i++) { - size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i; - size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i; - size_t y0 = TRIG_START_Y + TRIG_OFFSET_Y; - size_t y1 = TRIG_START_Y + TRIG_H + TRIG_OFFSET_Y; +} + +void +draw_trig_cursor(size_t i, u8 clr) { + size_t offset_x = TRIG_OFFSET_X * (i % 8); + size_t offset_y = i < 8 ? 1 : 1 + TRIG_OFFSET_Y; + size_t x0 = TRIG_START_X + offset_x; + size_t x1 = TRIG_START_X + TRIG_W + offset_x; + size_t y = TRIG_START_Y + TRIG_H + offset_y; + draw_line(x0, y, x1, y, clr); +} + +void +draw_triggers(void) { + for (size_t i = 0; i < 16; i++) { + size_t offset_x = TRIG_OFFSET_X * (i % 8); + size_t offset_y = i < 8 ? 0 : 0 + TRIG_OFFSET_Y; + size_t x0 = TRIG_START_X + offset_x; + size_t x1 = TRIG_START_X + offset_x + TRIG_W; + size_t y0 = TRIG_START_Y + offset_y; + size_t y1 = TRIG_START_Y + offset_y + TRIG_H; draw_rect(x0, y0, x1, y1, 1); + draw_trigger(channel_selection_loc, i); } } @@ -152,16 +279,6 @@ void draw_channels(void) { // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG // channels for now, since FM may take some time to develop. - u32 channel_buttons[] = { - 0xff017111, 0x117101ff, 0xff008585, 0x879500ff, - 0x0f080808, 0x0808080f, 0xff01b989, 0x89b901ff, - 0xff004242, 0x434a00ff, 0x0f080909, 0x0909080f, - 0xff015d45, 0xc55d01ff, 0xff00a1a1, 0xa1a500ff, - 0x0f080a0a, 0x0a0a080f, 0xff015d45, 0xc55d01ff, - 0xff00a1a1, 0xa12500ff, 0x0f080a0a, 0x0a0b080f, - 0xff01c141, 0xc14101ff, 0xff00151c, 0x141400ff, - 0x0f080808, 0x0808080f, - }; Tile channel_tiles[3 * 4] = {0}; unpack_tiles(channel_buttons, channel_tiles, 3 * 4); size_t k = 0; @@ -213,9 +330,9 @@ irq_timer_0(void) { // TODO: Should we compare if previous and current wave are the // same before updating? SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); - memcpy(SOUND_WAVE_RAM, trig->wave_a, 16); + dma_copy(SOUND_WAVE_RAM, trig->wave_a, 16, 3); SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); - memcpy(SOUND_WAVE_RAM, trig->wave_b, 16); + dma_copy(SOUND_WAVE_RAM, trig->wave_b, 16, 3); switch (trig->wave_mode) { case 0: { @@ -261,252 +378,306 @@ irq_timer_0(void) { step_counter = (step_counter + 1) % 16; } +void +set_time(int bpm) { + // The number of ticks of a 1024 cycle clock in a step based on the BPM can + // be calculated as: + // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s + // Y ms -> Ye-3 / 59.99e-9 / 1024 = Z ticks + // We have to operate on integer values, so the numbers have been + // precalculated to `n_ticks = 244181 / bmp` + int n_ticks = -244181 / bpm; + irs_set(IRQ_TIMER_0, irq_timer_0); + TIMER_DATA_0 = n_ticks; + TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3; +} + #define SEQ_N_CHANNELS 3 void -handle_sequencer_input(void) { - poll_keys(); +trigger_cursor(void) { SeqTrigger *trig = &sequences[channel_selection_loc][trig_selection_loc]; - if (current_selection == SEQ_SELECT_TRIGGER) { - if (key_tap(KEY_LEFT)) { - if (trig_selection_loc == 0 || trig_selection_loc == 8) { - current_selection = SEQ_SELECT_CHANNEL; - } else { - trig_selection_loc = MAX(trig_selection_loc - 1, 0); - } - } else if (key_tap(KEY_RIGHT)) { - if (trig_selection_loc != 7) { - trig_selection_loc = MIN(trig_selection_loc + 1, 15); - } - } else if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { - trig_selection_loc = (trig_selection_loc + 8) % 16; - } else if (key_tap(KEY_B)) { - trig->trigger ^= 1; - } else if (key_tap(KEY_L)) { - if (trig->trigger) { - trig->note = MAX(trig->note - 1, NOTE_C_2); - } - } else if (key_tap(KEY_R)) { - if (trig->trigger) { - trig->note = MIN( trig->note + 1, NOTE_C_8); - } - } else if (key_tap(KEY_A)) { - // Switch to parameter selection. - current_selection = SEQ_SELECT_PARAMETER; - } - } else if (current_selection == SEQ_SELECT_PARAMETER) { - if (channel_selection_loc < 2) { - // Move through the selected synth parameters. - if (key_tap(KEY_LEFT)) { - int max_param = 6; - if (channel_selection_loc == 1) { - max_param = 3; - } - if (param_selection_loc == 0) { - param_selection_loc = max_param; - } else { - param_selection_loc = MAX(param_selection_loc - 1, 0); - } - } - if (key_tap(KEY_RIGHT)) { - int max_param = 6; - if (channel_selection_loc == 1) { - max_param = 3; - } - if (param_selection_loc == max_param) { - param_selection_loc = 0; - } else { - param_selection_loc = MIN(param_selection_loc + 1, max_param); - } - } - - // Adjust the parameters up or down. - if (key_tap(KEY_L) || key_tap(KEY_R)) { - int inc; - if (key_tap(KEY_L)) { - inc = -1; - } else { - inc = 1; - } - switch (param_selection_loc) { - case 0: { - trig->env_volume = CLAMP(trig->env_volume + inc, 0, 15); - } break; - case 1: { - trig->env_time = CLAMP(trig->env_time + inc, 0, 7); - } break; - case 2: { - trig->env_direction ^= 1; - } break; - case 3: { - trig->duty_cycle = CLAMP(trig->duty_cycle + inc, 0, 3); - } break; - case 4: { - trig->sweep_number = CLAMP(trig->sweep_number + inc, 0, 7); - } break; - case 5: { - trig->sweep_time = CLAMP(trig->sweep_time + inc, 0, 7); - } break; - case 6: { - if (trig->sweep_direction == 0) { - trig->sweep_direction = 1; - } else { - trig->sweep_direction = 0; - } - } break; - } - } - } else if (channel_selection_loc == 2) { - if (key_tap(KEY_LEFT) || key_tap(KEY_RIGHT)) { - int inc = 0; - int loc = param_selection_loc; - if (key_tap(KEY_RIGHT)) { - if (loc == 15 || loc == 31) { - inc = 17; - } else if (loc != 47 && loc != 63){ - inc = 1; - } - } else { - if (loc == 32 || loc == 48) { - inc = -17; - } else if (loc != 16 && loc != 64){ - inc = -1; - } - } - param_selection_loc = CLAMP(loc + inc, 0, 71); - } - if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { - int inc = 0; - int loc = param_selection_loc; - if (key_tap(KEY_UP)) { - if ((loc >= 16 && loc < 32) || (loc >= 48 && loc < 64)) { - inc = -16; - } else if (loc == 64) { - inc = -48; - } else if (loc == 65) { - inc = -45; - } else if (loc == 66) { - inc = -42; - } else if (loc == 67) { - inc = -39; - } else if (loc == 68) { - inc = -20; - } else if (loc == 69) { - inc = -17; - } else if (loc == 70) { - inc = -14; - } else if (loc == 71) { - inc = -11; - } - } else { - if (loc < 16 || (loc >= 32 && loc < 48)) { - inc = 16; - } else if (loc >= 16 && loc <= 19){ - inc = 48 - (loc - 16); - } else if (loc >= 20 && loc <= 23){ - inc = 45 - (loc - 20); - } else if (loc >= 24 && loc <= 27){ - inc = 42 - (loc - 24); - } else if (loc >= 28 && loc <= 31){ - inc = 39 - (loc - 28); - } else if (loc >= 48 && loc <= 51){ - inc = 20 - (loc - 48); - } else if (loc >= 52 && loc <= 55){ - inc = 17 - (loc - 52); - } else if (loc >= 56 && loc <= 59){ - inc = 14 - (loc - 56); - } else if (loc >= 60 && loc <= 63){ - inc = 11 - (loc - 60); - } - } - param_selection_loc = CLAMP(loc + inc, 0, 71); - } - if (key_tap(KEY_R) || key_tap(KEY_L)) { - int odd = param_selection_loc & 0x1; - int inc; - if (key_tap(KEY_R)) { - inc = 1; - } else { - inc = -1; - } - // Wave: AA BB CC DD ... - // ^^ - // |`- odd - // `-- even - if (param_selection_loc < 32) { - u8 byte_number = param_selection_loc >> 1; - u8 byte = sequences[2][trig_selection_loc].wave_a[byte_number]; - if (odd) { - byte = (~0xF & byte) | ((byte + inc) & 0xF); - } else { - byte = (0xF & byte) | (((byte >> 4) + inc) & 0xF) << 4; - } - sequences[2][trig_selection_loc].wave_a[byte_number] = byte; - } else if (param_selection_loc < 64){ - u8 byte_number = (param_selection_loc - 32) >> 1; - u8 byte = sequences[2][trig_selection_loc].wave_b[byte_number]; - if (odd) { - byte = (~0xF & byte) | (byte + inc); - } else { - byte = (0xF & byte) | ((byte >> 4) + inc) << 4; - } - sequences[2][trig_selection_loc].wave_b[byte_number] = byte; - } else if (param_selection_loc == 64){ - memcpy(&trig->wave_a, &sine_wave, 16); - } else if (param_selection_loc == 65){ - memcpy(&trig->wave_a, &saw_wave, 16); - } else if (param_selection_loc == 66){ - memcpy(&trig->wave_a, &square_wave, 16); - } else if (param_selection_loc == 67){ - u32 rand_wave[4] = { - rng32(), rng32(), rng32(), rng32(), - }; - memcpy(&trig->wave_a, &rand_wave, 16); - } else if (param_selection_loc == 68){ - memcpy(&trig->wave_b, &sine_wave, 16); - } else if (param_selection_loc == 69){ - memcpy(&trig->wave_b, &saw_wave, 16); - } else if (param_selection_loc == 70){ - memcpy(&trig->wave_b, &square_wave, 16); - } else if (param_selection_loc == 71){ - u32 rand_wave[4] = { - rng32(), rng32(), rng32(), rng32(), - }; - memcpy(&trig->wave_b, &rand_wave, 16); - } - } - } - - // Go back to trigger selection. - if (key_tap(KEY_A)) { - current_selection = SEQ_SELECT_TRIGGER; - } - - // Enable disable trigger. - if (key_tap(KEY_B)) { - trig->trigger ^= 1; + if (key_tap(KEY_LEFT)) { + if (trig_selection_loc == 0 || trig_selection_loc == 8) { + // current_selection = SEQ_SELECT_CHANNEL; + } else { + draw_trig_cursor(trig_selection_loc, 0); + trig_selection_loc = MAX(trig_selection_loc - 1, 0); + draw_trig_cursor(trig_selection_loc, 3); } - } else if (current_selection == SEQ_SELECT_CHANNEL) { - if (key_tap(KEY_RIGHT)) { - current_selection = SEQ_SELECT_TRIGGER; - trig_selection_loc = 0; - param_selection_loc = 0; + } else if (key_tap(KEY_RIGHT)) { + if (trig_selection_loc != 7) { + draw_trig_cursor(trig_selection_loc, 0); + trig_selection_loc = MIN(trig_selection_loc + 1, 15); + draw_trig_cursor(trig_selection_loc, 3); } - if (key_tap(KEY_UP)) { - if (channel_selection_loc == 0) { - channel_selection_loc = SEQ_N_CHANNELS - 1; - } else { - channel_selection_loc = MAX(channel_selection_loc - 1, 0); - } + } else if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { + draw_trig_cursor(trig_selection_loc, 0); + trig_selection_loc = (trig_selection_loc + 8) % 16; + draw_trig_cursor(trig_selection_loc, 3); + } else if (key_tap(KEY_B)) { + trig->trigger ^= 1; + } else if (key_tap(KEY_L)) { + if (trig->trigger) { + trig->note = MAX(trig->note - 1, NOTE_C_2); } - if (key_tap(KEY_DOWN)) { - if (channel_selection_loc == SEQ_N_CHANNELS - 1) { - channel_selection_loc = 0; - } else { - channel_selection_loc = MIN(channel_selection_loc + 1, SEQ_N_CHANNELS); - } + } else if (key_tap(KEY_R)) { + if (trig->trigger) { + trig->note = MIN( trig->note + 1, NOTE_C_8); } + } else if (key_tap(KEY_A)) { + // Switch to parameter selection. + // current_selection = SEQ_SELECT_PARAMETER; } +} + +void (*input_handler)(void); + +void +handle_sequencer_input(void) { + poll_keys(); + input_handler(); + // SeqTrigger *trig = &sequences[channel_selection_loc][trig_selection_loc]; + // if (current_selection == SEQ_SELECT_TRIGGER) { + // if (key_tap(KEY_LEFT)) { + // if (trig_selection_loc == 0 || trig_selection_loc == 8) { + // current_selection = SEQ_SELECT_CHANNEL; + // } else { + // trig_selection_loc = MAX(trig_selection_loc - 1, 0); + // } + // } else if (key_tap(KEY_RIGHT)) { + // if (trig_selection_loc != 7) { + // trig_selection_loc = MIN(trig_selection_loc + 1, 15); + // } + // } else if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { + // trig_selection_loc = (trig_selection_loc + 8) % 16; + // } else if (key_tap(KEY_B)) { + // trig->trigger ^= 1; + // } else if (key_tap(KEY_L)) { + // if (trig->trigger) { + // trig->note = MAX(trig->note - 1, NOTE_C_2); + // } + // } else if (key_tap(KEY_R)) { + // if (trig->trigger) { + // trig->note = MIN( trig->note + 1, NOTE_C_8); + // } + // } else if (key_tap(KEY_A)) { + // // Switch to parameter selection. + // current_selection = SEQ_SELECT_PARAMETER; + // } + // } else if (current_selection == SEQ_SELECT_PARAMETER) { + // if (channel_selection_loc < 2) { + // // Move through the selected synth parameters. + // if (key_tap(KEY_LEFT)) { + // int max_param = 6; + // if (channel_selection_loc == 1) { + // max_param = 3; + // } + // if (param_selection_loc == 0) { + // param_selection_loc = max_param; + // } else { + // param_selection_loc = MAX(param_selection_loc - 1, 0); + // } + // } + // if (key_tap(KEY_RIGHT)) { + // int max_param = 6; + // if (channel_selection_loc == 1) { + // max_param = 3; + // } + // if (param_selection_loc == max_param) { + // param_selection_loc = 0; + // } else { + // param_selection_loc = MIN(param_selection_loc + 1, max_param); + // } + // } + + // // Adjust the parameters up or down. + // if (key_tap(KEY_L) || key_tap(KEY_R)) { + // int inc; + // if (key_tap(KEY_L)) { + // inc = -1; + // } else { + // inc = 1; + // } + // switch (param_selection_loc) { + // case 0: { + // trig->env_volume = CLAMP(trig->env_volume + inc, 0, 15); + // } break; + // case 1: { + // trig->env_time = CLAMP(trig->env_time + inc, 0, 7); + // } break; + // case 2: { + // trig->env_direction ^= 1; + // } break; + // case 3: { + // trig->duty_cycle = CLAMP(trig->duty_cycle + inc, 0, 3); + // } break; + // case 4: { + // trig->sweep_number = CLAMP(trig->sweep_number + inc, 0, 7); + // } break; + // case 5: { + // trig->sweep_time = CLAMP(trig->sweep_time + inc, 0, 7); + // } break; + // case 6: { + // if (trig->sweep_direction == 0) { + // trig->sweep_direction = 1; + // } else { + // trig->sweep_direction = 0; + // } + // } break; + // } + // } + // } else if (channel_selection_loc == 2) { + // if (key_tap(KEY_LEFT) || key_tap(KEY_RIGHT)) { + // int inc = 0; + // int loc = param_selection_loc; + // if (key_tap(KEY_RIGHT)) { + // if (loc == 15 || loc == 31) { + // inc = 17; + // } else if (loc != 47 && loc != 63){ + // inc = 1; + // } + // } else { + // if (loc == 32 || loc == 48) { + // inc = -17; + // } else if (loc != 16 && loc != 64){ + // inc = -1; + // } + // } + // param_selection_loc = CLAMP(loc + inc, 0, 71); + // } + // if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { + // int inc = 0; + // int loc = param_selection_loc; + // if (key_tap(KEY_UP)) { + // if ((loc >= 16 && loc < 32) || (loc >= 48 && loc < 64)) { + // inc = -16; + // } else if (loc == 64) { + // inc = -48; + // } else if (loc == 65) { + // inc = -45; + // } else if (loc == 66) { + // inc = -42; + // } else if (loc == 67) { + // inc = -39; + // } else if (loc == 68) { + // inc = -20; + // } else if (loc == 69) { + // inc = -17; + // } else if (loc == 70) { + // inc = -14; + // } else if (loc == 71) { + // inc = -11; + // } + // } else { + // if (loc < 16 || (loc >= 32 && loc < 48)) { + // inc = 16; + // } else if (loc >= 16 && loc <= 19){ + // inc = 48 - (loc - 16); + // } else if (loc >= 20 && loc <= 23){ + // inc = 45 - (loc - 20); + // } else if (loc >= 24 && loc <= 27){ + // inc = 42 - (loc - 24); + // } else if (loc >= 28 && loc <= 31){ + // inc = 39 - (loc - 28); + // } else if (loc >= 48 && loc <= 51){ + // inc = 20 - (loc - 48); + // } else if (loc >= 52 && loc <= 55){ + // inc = 17 - (loc - 52); + // } else if (loc >= 56 && loc <= 59){ + // inc = 14 - (loc - 56); + // } else if (loc >= 60 && loc <= 63){ + // inc = 11 - (loc - 60); + // } + // } + // param_selection_loc = CLAMP(loc + inc, 0, 71); + // } + // if (key_tap(KEY_R) || key_tap(KEY_L)) { + // int odd = param_selection_loc & 0x1; + // int inc; + // if (key_tap(KEY_R)) { + // inc = 1; + // } else { + // inc = -1; + // } + // // Wave: AA BB CC DD ... + // // ^^ + // // |`- odd + // // `-- even + // if (param_selection_loc < 32) { + // u8 byte_number = param_selection_loc >> 1; + // u8 byte = sequences[2][trig_selection_loc].wave_a[byte_number]; + // if (odd) { + // byte = (~0xF & byte) | ((byte + inc) & 0xF); + // } else { + // byte = (0xF & byte) | (((byte >> 4) + inc) & 0xF) << 4; + // } + // sequences[2][trig_selection_loc].wave_a[byte_number] = byte; + // } else if (param_selection_loc < 64){ + // u8 byte_number = (param_selection_loc - 32) >> 1; + // u8 byte = sequences[2][trig_selection_loc].wave_b[byte_number]; + // if (odd) { + // byte = (~0xF & byte) | (byte + inc); + // } else { + // byte = (0xF & byte) | ((byte >> 4) + inc) << 4; + // } + // sequences[2][trig_selection_loc].wave_b[byte_number] = byte; + // } else if (param_selection_loc == 64){ + // dma_copy(&trig->wave_a, &sine_wave, 16); + // } else if (param_selection_loc == 65){ + // dma_copy(&trig->wave_a, &saw_wave, 16); + // } else if (param_selection_loc == 66){ + // dma_copy(&trig->wave_a, &square_wave, 16); + // } else if (param_selection_loc == 67){ + // u32 rand_wave[4] = { + // rng32(), rng32(), rng32(), rng32(), + // }; + // dma_copy(&trig->wave_a, &rand_wave, 16); + // } else if (param_selection_loc == 68){ + // dma_copy(&trig->wave_b, &sine_wave, 16); + // } else if (param_selection_loc == 69){ + // dma_copy(&trig->wave_b, &saw_wave, 16); + // } else if (param_selection_loc == 70){ + // dma_copy(&trig->wave_b, &square_wave, 16); + // } else if (param_selection_loc == 71){ + // u32 rand_wave[4] = { + // rng32(), rng32(), rng32(), rng32(), + // }; + // dma_copy(&trig->wave_b, &rand_wave, 16); + // } + // } + // } + + // // Go back to trigger selection. + // if (key_tap(KEY_A)) { + // current_selection = SEQ_SELECT_TRIGGER; + // } + + // // Enable disable trigger. + // if (key_tap(KEY_B)) { + // trig->trigger ^= 1; + // } + // } else if (current_selection == SEQ_SELECT_CHANNEL) { + // if (key_tap(KEY_RIGHT)) { + // current_selection = SEQ_SELECT_TRIGGER; + // trig_selection_loc = 0; + // param_selection_loc = 0; + // } + // if (key_tap(KEY_UP)) { + // if (channel_selection_loc == 0) { + // channel_selection_loc = SEQ_N_CHANNELS - 1; + // } else { + // channel_selection_loc = MAX(channel_selection_loc - 1, 0); + // } + // } + // if (key_tap(KEY_DOWN)) { + // if (channel_selection_loc == SEQ_N_CHANNELS - 1) { + // channel_selection_loc = 0; + // } else { + // channel_selection_loc = MIN(channel_selection_loc + 1, SEQ_N_CHANNELS); + // } + // } + // } if (key_tap(KEY_START)) { step_counter = 0; @@ -526,41 +697,38 @@ handle_sequencer_input(void) { SOUND_WAVE_CTRL = 0; } - if (key_tap(KEY_LEFT) - || key_tap(KEY_RIGHT) - || key_tap(KEY_UP) - || key_tap(KEY_DOWN) - || key_tap(KEY_L) - || key_tap(KEY_R) - ) { - } + // if (key_tap(KEY_LEFT) + // || key_tap(KEY_RIGHT) + // || key_tap(KEY_UP) + // || key_tap(KEY_DOWN) + // || key_tap(KEY_L) + // || key_tap(KEY_R) + // ) { + // } } void -set_time(int bpm) { - // The number of ticks of a 1024 cycle clock in a step based on the BPM can - // be calculated as: - // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s - // Y ms -> Ye-3 / 59.99e-9 / 1024 = Z ticks - // We have to operate on integer values, so the numbers have been - // precalculated to `n_ticks = 244181 / bmp` - int n_ticks = -244181 / bpm; - irs_set(IRQ_TIMER_0, irq_timer_0); - TIMER_DATA_0 = n_ticks; - TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3; +load_note_names(void) { + unpack_tiles(note_names, ASSETS_DATA, 2 * 73); } void sequencer_init(void) { + // TODO: Unpack non-sprite tiles directly on the VRAM. + load_note_names(); + // Initialize background objects and sprites. draw_triggers(); draw_channels(); + // Initialize input handler. + input_handler = trigger_cursor; + draw_trig_cursor(trig_selection_loc, 3); + // Initialize sound system. SOUND_STATUS = SOUND_ENABLE; SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2 | SOUND_WAVE, 3); SOUND_DSOUND_MASTER = SOUND_DMG25; - set_time(bpm); } -- cgit v1.2.1