From 9bb91b5496b5a1bc730bdc70b3352a789c35d995 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 28 Jun 2023 10:31:18 +0200 Subject: Initial kbd implementation --- src/app.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 209 insertions(+), 10 deletions(-) (limited to 'src/app.c') diff --git a/src/app.c b/src/app.c index 21f376a..a5c187a 100644 --- a/src/app.c +++ b/src/app.c @@ -117,6 +117,29 @@ u16 font_numbers[10] = { }; // Enums and structs. +typedef enum Pads { + POLY_PAD_ROW_0 = 11 + 10 * 7 + 0, + POLY_PAD_ROW_1 = 11 + 10 * 6 + 0, + POLY_PAD_ROW_2 = 11 + 10 * 5 + 0, + POLY_PAD_ROW_3 = 11 + 10 * 4 + 0, + POLY_PAD_ROW_4 = 11 + 10 * 3 + 0, + POLY_PAD_ROW_5 = 11 + 10 * 2 + 0, + POLY_PAD_ROW_6 = 11 + 10 * 1 + 0, + POLY_PAD_ROW_7 = 11 + 10 * 0 + 0, + POLY_TOP_ROW = 11 + 10 * 8 + 0, +} Pads; + +Pads row_idx[] = { + POLY_PAD_ROW_0, + POLY_PAD_ROW_1, + POLY_PAD_ROW_2, + POLY_PAD_ROW_3, + POLY_PAD_ROW_4, + POLY_PAD_ROW_5, + POLY_PAD_ROW_6, + POLY_PAD_ROW_7, +}; + typedef enum Button { POLY_PAD_ACTIVE = 11, POLY_PAD_STEAL = 11 + 7, @@ -173,6 +196,7 @@ typedef enum Button { typedef enum Mode { MOD_POLY_MAIN = 0, MOD_POLY_SETUP = 1, + MOD_POLY_KBD = 2, } Mode; typedef enum Stealing { @@ -182,6 +206,19 @@ typedef enum Stealing { POLY_STEAL_LOW = 3, } Stealing; +typedef struct Color { + int r; + int g; + int b; +} Color; + +Color colors[] = { + { MAXLED, MAXLED, MAXLED }, // White + { MAXLED, 0, 0 }, // Red + { 0, MAXLED, 0 }, // Green + { 0, 0, MAXLED }, // Blue +}; + typedef struct Voice { u8 active; u8 channel; @@ -192,6 +229,8 @@ typedef struct Voice { } Voice; typedef struct State { + // Magic. + u32 magic; // Polyphony. u8 active; u8 stealing; @@ -199,6 +238,8 @@ typedef struct State { u8 ch_max; u8 ch_listen[16]; Mode mode; + // Keyboard. + u8 kbd_octave; } State; // Globals. @@ -265,6 +306,87 @@ select_ch_sel(u8 target) { state.ch_listen[target] = !state.ch_listen[target]; } +int +kbd_find_note(int index) { + int note = -1; + int black = 0; + int row = 0; + + // A + if (index >= POLY_PAD_ROW_0 && index <= (POLY_PAD_ROW_0 + 7)) { + row = POLY_PAD_ROW_0; + black = 1; + note = 12 * (state.kbd_octave + 5); + } + if (index >= POLY_PAD_ROW_1 && index <= (POLY_PAD_ROW_1 + 7)) { + row = POLY_PAD_ROW_1; + note = 12 * (state.kbd_octave + 5); + } + + // B + if (index >= POLY_PAD_ROW_2 && index <= (POLY_PAD_ROW_2 + 7)) { + row = POLY_PAD_ROW_2; + black = 1; + note = 12 * (state.kbd_octave + 4); + } + if (index >= POLY_PAD_ROW_3 && index <= (POLY_PAD_ROW_3 + 7)) { + row = POLY_PAD_ROW_3; + note = 12 * (state.kbd_octave + 4); + } + + // C + if (index >= POLY_PAD_ROW_4 && index <= (POLY_PAD_ROW_4 + 7)) { + row = POLY_PAD_ROW_4; + black = 1; + note = 12 * (state.kbd_octave + 3); + } + if (index >= POLY_PAD_ROW_5 && index <= (POLY_PAD_ROW_5 + 7)) { + row = POLY_PAD_ROW_5; + note = 12 * (state.kbd_octave + 3); + } + + // D + if (index >= POLY_PAD_ROW_6 && index <= (POLY_PAD_ROW_6 + 7)) { + row = POLY_PAD_ROW_6; + black = 1; + note = 12 * (state.kbd_octave + 2); + } + if (index >= POLY_PAD_ROW_7 && index <= (POLY_PAD_ROW_7 + 7)) { + row = POLY_PAD_ROW_7; + note = 12 * (state.kbd_octave + 2); + } + + // Invalid pad index. + if (note < 0) { + return -1; + } + + // Find note offset. + if (black) { + switch (index - row) { + case 1: { return note + 1; } break; + case 2: { return note + 3; } break; + case 4: { return note + 6; } break; + case 5: { return note + 8; } break; + case 6: { return note + 10; } break; + default: { return -1; } break; + } + } else { + switch (index - row) { + case 0: { return note + 0; } break; + case 1: { return note + 2; } break; + case 2: { return note + 4; } break; + case 3: { return note + 5; } break; + case 4: { return note + 7; } break; + case 5: { return note + 9; } break; + case 6: { return note + 11; } break; + case 7: { return note + 12; } break; + default: { return -1; } break; + } + } + return -1; +} + void app_surface_event(u8 type, u8 index, u8 value) { switch (type) { @@ -340,18 +462,57 @@ app_surface_event(u8 type, u8 index, u8 value) { } } } break; + case MOD_POLY_KBD: { + // Transposition. + if (index >= POLY_TOP_ROW && index <= (POLY_TOP_ROW + 7)) { + switch (index - POLY_TOP_ROW) { + case 0: { + if (state.kbd_octave < 3) { + state.kbd_octave++; + } + } break; + case 1: { + if (state.kbd_octave > 0) { + state.kbd_octave--; + } + } break; + default: {} break; + } + return; + } + u8 channel = 0; + // TODO: Velocity on/off configuration. + // TODO: Velocity curve adjustment. + // TODO: Aftertouch? + // TODO: Different colors for different octaves. + // TODO: Per KBD channel selection. + int note = kbd_find_note(index); + if (note == -1) { + return; + } + + if (value) { + hal_send_midi(USBSTANDALONE, NOTEON | channel, note, value); + hal_send_midi(USBMIDI, NOTEON | channel, note, value); + hal_send_midi(DINMIDI, NOTEON | channel, note, value); + } else { + hal_send_midi(USBSTANDALONE, NOTEOFF | channel, note, value); + hal_send_midi(USBMIDI, NOTEOFF | channel, note, value); + hal_send_midi(DINMIDI, NOTEOFF | channel, note, value); + } + } break; } } break; case TYPESETUP: { if (value) { switch (state.mode) { + case MOD_POLY_KBD: case MOD_POLY_MAIN: { state.mode = MOD_POLY_SETUP; } break; case MOD_POLY_SETUP: { - state.mode = MOD_POLY_MAIN; + state.mode = MOD_POLY_KBD; hal_write_flash(0, (u8*)&state, sizeof(State)); - } break; } } @@ -575,6 +736,14 @@ draw_poly_main(void) { void draw_min_channel(void) { + // for (u8 i = 0; i < 8; i++) { + // if (state.ch_max < 8 && i > state.ch_max) { + // clr = colors[1]; + // } else if (i != state.ch_min){ + // clr = colors[2]; + // } + // hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, clr.r, clr.g, clr.b); + // } for (u8 i = 0; i < 8; i++) { if (i == state.ch_min) { hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED); @@ -652,6 +821,25 @@ draw_poly_setup(void) { draw_poly_active_button(); } +void +draw_kbd(int loc, Color clr) { + if (loc < 0 || loc >= 7) { + return; + } + Color clr_top = clr; + Color clr_bot = (Color){clr_top.r / 4, clr_top.g / 4, clr_top.b / 4 }; + int idx_top = row_idx[loc]; + int idx_bot = row_idx[loc + 1]; + hal_plot_led(TYPEPAD, idx_top + 1, clr_bot.r, clr_bot.g, clr_bot.b); + hal_plot_led(TYPEPAD, idx_top + 2, clr_bot.r, clr_bot.g, clr_bot.b); + hal_plot_led(TYPEPAD, idx_top + 4, clr_bot.r, clr_bot.g, clr_bot.b); + hal_plot_led(TYPEPAD, idx_top + 5, clr_bot.r, clr_bot.g, clr_bot.b); + hal_plot_led(TYPEPAD, idx_top + 6, clr_bot.r, clr_bot.g, clr_bot.b); + for (u8 i = 0; i < 8; i++) { + hal_plot_led(TYPEPAD, idx_bot + i, clr_top.r, clr_top.g, clr_top.b); + } +} + void draw_scene(void) { switch (state.mode) { @@ -661,6 +849,12 @@ draw_scene(void) { case MOD_POLY_SETUP: { draw_poly_setup(); } break; + case MOD_POLY_KBD: { + draw_kbd(0, colors[0]); + draw_kbd(2, colors[1]); + draw_kbd(4, colors[2]); + draw_kbd(6, colors[3]); + } break; } } @@ -682,15 +876,20 @@ app_timer_event() { void app_init(const u16 *adc_raw) { // example - load button states from flash - state = (State){ - .active = 1, - .stealing = POLY_STEAL_OFF, - .ch_min = 0, - .ch_max = 7, - .ch_listen = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - .mode = MOD_POLY_MAIN, - }; hal_read_flash(0, (u8*)&state, sizeof(State)); + if (state.magic != 0xbadd10de) { + state = (State){ + .magic = 0xbadd10de, + .active = 1, + .stealing = POLY_STEAL_OFF, + .ch_min = 0, + .ch_max = 7, + .ch_listen = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + .mode = MOD_POLY_MAIN, + .kbd_octave = 0, + }; + } + state.mode = MOD_POLY_KBD; // DEBUG: // store off the raw ADC frame pointer for later use g_ADC = adc_raw; -- cgit v1.2.1