From d8084032bec70170c9614708c6ee10316b19e0c2 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Mon, 3 Apr 2023 19:12:24 +0200 Subject: Add noise parameter struct and more ui elements --- src/sequencer.c | 318 ++++++++++++++++++++++++++++++++++---------------------- src/text/text.h | 9 ++ 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 @@ #define COL_WAVE_A COL_RED #define COL_WAVE_B COL_CYAN +#define CHAN_W 19 +#define CHAN_H 8 +#define CHAN_START_X 34 +#define CHAN_START_Y 92 +#define CHAN_OFFSET_Y 12 + +#define TRIG_W 15 +#define TRIG_H 24 +#define TRIG_START_X 63 +#define TRIG_START_Y 92 +#define TRIG_OFFSET_X (TRIG_W + 3) +#define TRIG_OFFSET_Y (TRIG_H + 7) + +#define PIANO_W 170 +#define PIANO_H 20 +#define PIANO_START_X 34 +#define PIANO_START_Y 65 +#define PIANO_NOTE_W 2 + +#define PARAMS_W 170 +#define PARAMS_H 64 +#define PARAMS_START_X 34 +#define PARAMS_START_Y 1 + +#define R_SIDEBAR_X ((TRIG_START_X) + (TRIG_OFFSET_X) * 8 + 2) +#define L_SIDEBAR_X ((CHAN_START_X) - 29) + +#define SEQ_N_CHANNELS 4 + // // Assets. // @@ -155,11 +184,12 @@ static const u32 square_wave[16] = { // Globals. // -static int bpm = 115; +static int bpm = 75; static int step_counter = 0; int trig_selection_loc = 0; int param_selection_loc = 0; -int channel_selection_loc = 3; +int channel_selection_loc = 0; +int play_status = 0; typedef struct TriggerNote { bool active; @@ -183,6 +213,13 @@ typedef struct ChannelWaveParams { u32 wave_b[4]; } ChannelWaveParams; +typedef struct ChannelNoiseParams { + u8 env_volume; + u8 env_time; + u8 env_direction; + u8 bit_mode; +} ChannelNoiseParams; + typedef struct ChannelSquare { bool active; TriggerNote notes[16]; @@ -198,6 +235,7 @@ typedef struct ChannelWave { typedef struct ChannelNoise { bool active; TriggerNote notes[16]; + ChannelNoiseParams params[16]; } ChannelNoise; static ChannelSquare ch1 = { @@ -323,7 +361,7 @@ static ChannelWave ch3 = { // TODO: Add default noise parameters data. static ChannelNoise ch4 = { .notes = { - {true, 0}, + {true, NOTE_C_4}, {false, NOTE_D_4}, {false, NOTE_E_4}, {false, NOTE_F_4}, @@ -340,19 +378,74 @@ static ChannelNoise ch4 = { {false, NOTE_C_4}, {false, NOTE_C_4}, }, + .params = { + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + {0xF, 0x2, 0, 0}, + }, .active = true, }; // -// Trigger render functions. +// Channel render functions. // -#define TRIG_W 15 -#define TRIG_H 24 -#define TRIG_START_X 64 -#define TRIG_START_Y 92 -#define TRIG_OFFSET_X (TRIG_W + 3) -#define TRIG_OFFSET_Y (TRIG_H + 7) +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. + Tile *channel_tiles = ASSETS_CHANNEL_BUTTONS; + size_t k = 0; + for (size_t i = 0; i < 4; i++) { + bool active = false; + switch (i) { + case 0: { + active = ch1.active; + } break; + case 1: { + active = ch2.active; + } break; + case 2: { + active = ch3.active; + } break; + case 3: { + active = ch4.active; + } break; + } + u8 clr = active ? COL_FG : COL_GREY; + size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y; + draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false); + draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false); + draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false); + } +} + +void +draw_channel_cursor(size_t i, u8 clr) { + size_t offset_x = 0; + size_t offset_y = CHAN_H + i * CHAN_OFFSET_Y + 1; + size_t x0 = CHAN_START_X + offset_x; + size_t x1 = CHAN_START_X + offset_x + CHAN_W; + size_t y = CHAN_START_Y + offset_y; + draw_line(x0, y, x1, y, clr); +} + +// +// Trigger render functions. +// void clear_trigger(size_t i) { @@ -406,6 +499,80 @@ draw_trig_cursor(size_t i, u8 clr) { draw_line(x0, y, x1, y, clr); } +void +draw_current_step(u8 col) { + size_t offset_x = TRIG_OFFSET_X * (step_counter % 8); + size_t offset_y = step_counter < 8 ? 2 : 2 + TRIG_OFFSET_Y; + size_t x0 = TRIG_START_X + 4 + offset_x; + size_t x1 = TRIG_START_X - 4 + TRIG_W + offset_x; + size_t y = TRIG_START_Y - 4 + TRIG_H + offset_y; + draw_line(x0, y, x1, y, col); +} + +void +draw_play() { + size_t x = R_SIDEBAR_X; + size_t y = TRIG_START_Y; + draw_filled_rect(x, y, x + 24, y + 10, COL_BG); + draw_rect(x, y, x + 24, y + 10, COL_CYAN); + if (play_status == 1) { + // Pause button + draw_filled_rect(x + 10, y + 3, x + 11, y + 7, COL_CYAN); + draw_filled_rect(x + 13, y + 3, x + 14, y + 7, COL_CYAN); + } else { + // Play button + x += 1; + draw_line(x + 10, y + 2, x + 10, y + 8, COL_CYAN); + draw_line(x + 11, y + 3, x + 11, y + 7, COL_CYAN); + draw_line(x + 12, y + 4, x + 12, y + 6, COL_CYAN); + draw_line(x + 13, y + 5, x + 13, y + 5, COL_CYAN); + } +} + +void +draw_pattern_buttons() { + size_t x = L_SIDEBAR_X; + size_t y = PARAMS_START_Y + 17; + txt_drawf_small("PAT", x + 5, y - 10, 4, COL_FG); + char pat_names[] = { + 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', + }; + for (size_t i = 0; i < 8; i++) { + draw_rect(x + 5, y, x + 19, y + 12, COL_GREY); + txt_drawc(pat_names[i], x + 9, y + 2, 6, COL_GREY); + y += 17; + } +} + +void +draw_stop() { + size_t x = R_SIDEBAR_X; + size_t y = TRIG_START_Y + 14; + draw_rect(x, y, x + 24, y + 10, COL_RED); + draw_filled_rect(x + 10, y + 3, x + 14, y + 7, COL_RED); + // DEBUG: ... + draw_pattern_buttons(); +} + +void +draw_bpm() { + size_t x = R_SIDEBAR_X; + size_t y = TRIG_START_Y + TRIG_H + 9; + + // Draw bounding box. + draw_rect(x, y, x + 24, y + 22, COL_FG); + draw_line(x + 5, y, x + 19, y, COL_BG); + txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG); + + // Make sure its horizontally centered if only 2 digits + if (bpm >= 100) { + txt_drawf("%d", x + 3, y + 7, 6, COL_FG, bpm); + } else { + txt_drawf("%d", x + 6, y + 7, 6, COL_FG, bpm); + } +} + void draw_triggers(void) { for (size_t i = 0; i < 16; i++) { @@ -421,62 +588,6 @@ draw_triggers(void) { } } -// -// Channel render functions. -// - -#define CHAN_W 19 -#define CHAN_H 8 -#define CHAN_START_X 35 -#define CHAN_START_Y 92 -#define CHAN_OFFSET_Y 12 - -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. - Tile *channel_tiles = ASSETS_CHANNEL_BUTTONS; - size_t k = 0; - for (size_t i = 0; i < 4; i++) { - bool active = false; - switch (i) { - case 0: { - active = ch1.active; - } break; - case 1: { - active = ch2.active; - } break; - case 2: { - active = ch3.active; - } break; - case 3: { - active = ch4.active; - } break; - } - u8 clr = active ? COL_FG : COL_GREY; - size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y; - draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false); - draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false); - draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false); - } -} - -void -draw_channel_cursor(size_t i, u8 clr) { - size_t offset_x = 0; - size_t offset_y = CHAN_H + i * CHAN_OFFSET_Y + 1; - size_t x0 = CHAN_START_X + offset_x; - size_t x1 = CHAN_START_X + offset_x + CHAN_W; - size_t y = CHAN_START_Y + offset_y; - draw_line(x0, y, x1, y, clr); -} - -#define PIANO_W 170 -#define PIANO_H 20 -#define PIANO_START_X 35 -#define PIANO_START_Y 65 -#define PIANO_NOTE_W 2 - void draw_note(u8 note, u8 clr) { size_t octave = note / 12; @@ -611,11 +722,6 @@ draw_piano(void) { } } -#define PARAMS_W 170 -#define PARAMS_H 64 -#define PARAMS_START_X 35 -#define PARAMS_START_Y 1 - void draw_params_cursor_wave(size_t i, u8 clr) { u8 x_positions[] = { @@ -1373,49 +1479,11 @@ irq_timer(void) { } if (ch4.active) { TriggerNote *trig = &ch4.notes[step_counter]; - // ChannelNoiseParams *params = &ch4.params[step_counter]; + ChannelNoiseParams *params = &ch4.params[step_counter]; + SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(params->env_volume) + | SOUND_NOISE_ENV_TIME(params->env_time) + | SOUND_NOISE_ENV_DIR(params->env_direction); if (trig->active) { - // switch (params->wave_mode) { - // case 0: { - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); - // memcpy32(SOUND_WAVE_RAM, params->wave_a, 16); - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) - // | SOUND_WAVE_BANK_SELECT(0); - // } break; - // case 1: { - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); - // memcpy32(SOUND_WAVE_RAM, params->wave_b, 16); - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) - // | SOUND_WAVE_BANK_SELECT(1); - // } break; - // case 2: { - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); - // memcpy32(SOUND_WAVE_RAM, params->wave_b, 16); - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); - // memcpy32(SOUND_WAVE_RAM, params->wave_a, 16); - // SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) - // | SOUND_WAVE_BANK_SELECT(0); - // } break; - // } - // SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; - - // switch (params->wave_volume) { - // case 0: { - // SOUND_WAVE_CTRL = SOUND_WAVE_MUTE; - // } break; - // case 1: { - // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_25; - // } break; - // case 2: { - // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_50; - // } break; - // case 3: { - // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_75; - // } break; - // case 4: { - // SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100; - // } break; - // } static const u8 div_freq[] = { 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, 7, 6, 5, 4, @@ -1432,14 +1500,10 @@ irq_timer(void) { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(0xF) - | SOUND_NOISE_ENV_TIME(0x2) - | SOUND_NOISE_ENV_DIR(0) - | SOUND_NOISE_LENGTH(50); SOUND_NOISE_FREQ = SOUND_FREQ_RESET | SOUND_NOISE_PRESTEP_FREQ(pre_freq[trig->note]) | SOUND_NOISE_DIV_FREQ(div_freq[trig->note]) - | SOUND_NOISE_COUNTER_STAGE(0) + | SOUND_NOISE_COUNTER_STAGE(1) | SOUND_NOISE_TIMED_MODE(0); } else { SOUND_NOISE_FREQ = 0; @@ -1448,7 +1512,9 @@ irq_timer(void) { SOUND_NOISE_CTRL = 0; SOUND_NOISE_FREQ = 0; } + draw_current_step(COL_BG); step_counter = (step_counter + 1) % 16; + draw_current_step(COL_RED); } void @@ -1489,8 +1555,6 @@ get_current_trig(void) { // selection. void (*input_handler)(void); -#define SEQ_N_CHANNELS 4 - void handle_trigger_selection(void); void handle_channel_selection(void); void handle_param_selection_sq1(void); @@ -2132,23 +2196,31 @@ handle_sequencer_input(void) { if (key_tap(KEY_START)) { // Stop the sequencer or start playing from the beginning. + play_status ^= 1; + if (step_counter != 0) { + draw_current_step(COL_BG); + } step_counter = 0; if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) { set_time(bpm); } else { + draw_current_step(COL_RED); TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; SOUND_SQUARE1_CTRL = 0; SOUND_SQUARE2_CTRL = 0; SOUND_WAVE_CTRL = 0; SOUND_NOISE_CTRL = 0; } + draw_play(); } else if (key_tap(KEY_SELECT)) { // Play/pause. + play_status ^= 1; TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; SOUND_SQUARE1_CTRL = 0; SOUND_SQUARE2_CTRL = 0; SOUND_WAVE_CTRL = 0; SOUND_NOISE_CTRL = 0; + draw_play(); } } @@ -2178,7 +2250,11 @@ sequencer_init(void) { input_handler = handle_trigger_selection; draw_trig_cursor(trig_selection_loc, COL_CURSOR); draw_channel_cursor(channel_selection_loc, COL_CURRENT_CHANNEL); + draw_current_step(COL_RED); draw_parameters(); + draw_bpm(); + draw_play(); + draw_stop(); // Initialize sound system. SOUND_STATUS = SOUND_ENABLE; @@ -2187,6 +2263,4 @@ sequencer_init(void) { | SOUND_WAVE | SOUND_NOISE, 3); SOUND_DSOUND_MASTER = SOUND_DMG25; - // SOUND_NOISE_CTRL = SOUND_NOISE_ENV_VOL(0x8) | SOUND_NOISE_ENV_TIME(0) | SOUND_NOISE_ENV_DIR(1) | 0x4; - // SOUND_NOISE_FREQ = SOUND_FREQ_RESET | SOUND_NOISE_PRESTEP_FREQ(0x7) | SOUND_NOISE_DIV_FREQ(2) | SOUND_NOISE_COUNTER_STAGE(1); } 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) { } } +static inline +void +txt_drawc(char c, size_t x, size_t y, size_t spacing, u8 clr) { + Tile *tile = FONT_DATA; + tile += c; + draw_tile(x, y, tile, clr, true); + x += spacing; +} + // Print text to the screen with formatting. #define txt_printf(msg, ...) \ { \ -- cgit v1.2.1