From 6e331bd4b16b17cb9a5d0b38aab0099b9cd23d06 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 9 Feb 2023 15:11:22 +0100 Subject: Add midi range selection --- src/app.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 252 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/app.c b/src/app.c index 7917a54..466a1a3 100644 --- a/src/app.c +++ b/src/app.c @@ -32,29 +32,7 @@ #include "app.h" -// Housekeeping and debugging. -u16 frame = 0; -u16 n_voices = 0; -u8 active = 1; -u8 ch_min = 4; -u8 ch_max = 8; - -typedef struct Voice { - u8 active; - u8 channel; - u8 d1; - u8 d2; - u8 port; -} Voice; - -Voice voices[16] = {0}; - -// store ADC frame pointer -static const u16 *g_ADC = 0; - -// buffer to store pad states for flash save -#define BUTTON_COUNT 100 -u8 buttons[BUTTON_COUNT] = {0}; +// Font. u16 font_numbers[10] = { /* * 0: 111 | 1111 0110 1101 1110 @@ -138,42 +116,168 @@ u16 font_numbers[10] = { 0xF792, }; -enum Buttons { +// Enums and structs. +typedef enum Button { POLY_PAD_ACTIVE = 11, -}; + POLY_PAD_MIN_CH_0 = 11 + 10 * 7 + 0, + POLY_PAD_MIN_CH_1 = 11 + 10 * 7 + 1, + POLY_PAD_MIN_CH_2 = 11 + 10 * 7 + 2, + POLY_PAD_MIN_CH_3 = 11 + 10 * 7 + 3, + POLY_PAD_MIN_CH_4 = 11 + 10 * 7 + 4, + POLY_PAD_MIN_CH_5 = 11 + 10 * 7 + 5, + POLY_PAD_MIN_CH_6 = 11 + 10 * 7 + 6, + POLY_PAD_MIN_CH_7 = 11 + 10 * 7 + 7, + POLY_PAD_MIN_CH_8 = 11 + 10 * 6 + 0, + POLY_PAD_MIN_CH_9 = 11 + 10 * 6 + 1, + POLY_PAD_MIN_CH_A = 11 + 10 * 6 + 2, + POLY_PAD_MIN_CH_B = 11 + 10 * 6 + 3, + POLY_PAD_MIN_CH_C = 11 + 10 * 6 + 4, + POLY_PAD_MIN_CH_D = 11 + 10 * 6 + 5, + POLY_PAD_MIN_CH_E = 11 + 10 * 6 + 6, + POLY_PAD_MIN_CH_F = 11 + 10 * 6 + 7, + POLY_PAD_MAX_CH_0 = 11 + 10 * 5 + 0, + POLY_PAD_MAX_CH_1 = 11 + 10 * 5 + 1, + POLY_PAD_MAX_CH_2 = 11 + 10 * 5 + 2, + POLY_PAD_MAX_CH_3 = 11 + 10 * 5 + 3, + POLY_PAD_MAX_CH_4 = 11 + 10 * 5 + 4, + POLY_PAD_MAX_CH_5 = 11 + 10 * 5 + 5, + POLY_PAD_MAX_CH_6 = 11 + 10 * 5 + 6, + POLY_PAD_MAX_CH_7 = 11 + 10 * 5 + 7, + POLY_PAD_MAX_CH_8 = 11 + 10 * 4 + 0, + POLY_PAD_MAX_CH_9 = 11 + 10 * 4 + 1, + POLY_PAD_MAX_CH_A = 11 + 10 * 4 + 2, + POLY_PAD_MAX_CH_B = 11 + 10 * 4 + 3, + POLY_PAD_MAX_CH_C = 11 + 10 * 4 + 4, + POLY_PAD_MAX_CH_D = 11 + 10 * 4 + 5, + POLY_PAD_MAX_CH_E = 11 + 10 * 4 + 6, + POLY_PAD_MAX_CH_F = 11 + 10 * 4 + 7, +} Button; + +typedef enum Mode { + MOD_POLY_MAIN = 0, + MOD_POLY_SETUP = 1, +} Mode; + +typedef struct Voice { + u8 active; + u8 channel; + u8 d1; + u8 d2; + u8 port; +} Voice; + +// Globals. +u16 frame = 0; +u16 n_voices = 0; +u8 active = 1; +u8 ch_min = 0; +u8 ch_max = 4; +Mode mode = MOD_POLY_SETUP; +Voice voices[16] = {0}; + +// store ADC frame pointer +static const u16 *g_ADC = 0; + +void +poly_active_toggle(void) { + // Stop existing playing notes. + for (u8 i = 0; i < 16; i++) { + Voice *voice = &voices[i]; + if (voice->active) { + voice->active = 0; + hal_send_midi( + voice->port, + NOTEOFF | voice->channel, + voice->d1, + voice->d2); + } + } + n_voices = 0; + active = !active; +} + +void +select_ch_min(u8 target) { + if (target <= ch_max) { + ch_min = target; + } +} + +void +select_ch_max(u8 target) { + if (target >= ch_min) { + ch_max = target; + } +} void app_surface_event(u8 type, u8 index, u8 value) { switch (type) { case TYPEPAD: { - if (value && index == POLY_PAD_ACTIVE) { - // Stop existing playing notes. - for (u8 i = 0; i < 16; i++) { - Voice *voice = &voices[i]; - if (voice->active) { - voice->active = 0; - hal_send_midi( - voice->port, - NOTEOFF | voice->channel, - voice->d1, - voice->d2); + switch (mode) { + case MOD_POLY_MAIN: { + if (value && index == POLY_PAD_ACTIVE) { + poly_active_toggle(); } - } - n_voices = 0; - active = !active; + } break; + case MOD_POLY_SETUP: { + if (value) { + switch (index) { + // Handle min channel selection. + case POLY_PAD_MIN_CH_0: { select_ch_min(0); } break; + case POLY_PAD_MIN_CH_1: { select_ch_min(1); } break; + case POLY_PAD_MIN_CH_2: { select_ch_min(2); } break; + case POLY_PAD_MIN_CH_3: { select_ch_min(3); } break; + case POLY_PAD_MIN_CH_4: { select_ch_min(4); } break; + case POLY_PAD_MIN_CH_5: { select_ch_min(5); } break; + case POLY_PAD_MIN_CH_6: { select_ch_min(6); } break; + case POLY_PAD_MIN_CH_7: { select_ch_min(7); } break; + case POLY_PAD_MIN_CH_8: { select_ch_min(8); } break; + case POLY_PAD_MIN_CH_9: { select_ch_min(9); } break; + case POLY_PAD_MIN_CH_A: { select_ch_min(10); } break; + case POLY_PAD_MIN_CH_B: { select_ch_min(11); } break; + case POLY_PAD_MIN_CH_C: { select_ch_min(12); } break; + case POLY_PAD_MIN_CH_D: { select_ch_min(13); } break; + case POLY_PAD_MIN_CH_E: { select_ch_min(14); } break; + case POLY_PAD_MIN_CH_F: { select_ch_min(15); } break; + // Handle max channel selection. + case POLY_PAD_MAX_CH_0: { select_ch_max(0); } break; + case POLY_PAD_MAX_CH_1: { select_ch_max(1); } break; + case POLY_PAD_MAX_CH_2: { select_ch_max(2); } break; + case POLY_PAD_MAX_CH_3: { select_ch_max(3); } break; + case POLY_PAD_MAX_CH_4: { select_ch_max(4); } break; + case POLY_PAD_MAX_CH_5: { select_ch_max(5); } break; + case POLY_PAD_MAX_CH_6: { select_ch_max(6); } break; + case POLY_PAD_MAX_CH_7: { select_ch_max(7); } break; + case POLY_PAD_MAX_CH_8: { select_ch_max(8); } break; + case POLY_PAD_MAX_CH_9: { select_ch_max(9); } break; + case POLY_PAD_MAX_CH_A: { select_ch_max(10); } break; + case POLY_PAD_MAX_CH_B: { select_ch_max(11); } break; + case POLY_PAD_MAX_CH_C: { select_ch_max(12); } break; + case POLY_PAD_MAX_CH_D: { select_ch_max(13); } break; + case POLY_PAD_MAX_CH_E: { select_ch_max(14); } break; + case POLY_PAD_MAX_CH_F: { select_ch_max(15); } break; + // TODO: Handle listen channel selection. + // Handle active toggle. + case POLY_PAD_ACTIVE: { poly_active_toggle(); } break; + default: break; + } + } + } break; } - // // toggle it and store it off, so we can save to flash if we want to - // if (value) { - // buttons[index] = MAXLED * !buttons[index]; - // } - - // // example - light / extinguish pad LEDs - // hal_plot_led(TYPEPAD, index, 0, 0, buttons[index]); - - // // example - send MIDI - // hal_send_midi(DINMIDI, NOTEON | 0, index, value); } break; case TYPESETUP: { + if (value) { + switch (mode) { + case MOD_POLY_MAIN: { + mode = MOD_POLY_SETUP; + } break; + case MOD_POLY_SETUP: { + mode = MOD_POLY_MAIN; + // TODO: save to flash. + } break; + } + } // if (value) { // // Pressing the setup button will save the current buttons/pad // // state to the flash. The flash memory is USER_AREA_SIZE bytes @@ -192,12 +296,12 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { } u8 channel = status & 0x0F; if ((status & 0xF0) == NOTEON) { - if (n_voices == (ch_max - ch_min)) { + if (n_voices == (ch_max - ch_min + 1)) { return; } // Find if the note was already pressed. - for (u8 i = ch_min; i < ch_max; i++) { + for (u8 i = ch_min; i <= ch_max; i++) { Voice *voice = &voices[i]; // Stop voice if needed. if (voice->active && voice->d1 == d1) { @@ -211,7 +315,7 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { } // Find next free voice slot. - for (u8 i = ch_min; i < ch_max; i++) { + for (u8 i = ch_min; i <= ch_max; i++) { Voice *voice = &voices[i]; // Register voice. if (!voice->active) { @@ -234,7 +338,7 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { // TODO: Round robin scheduling? n_voices++; } else if ((status & 0xF0) == NOTEOFF) { - for (u8 i = ch_min; i < ch_max; i++) { + for (u8 i = ch_min; i <= ch_max; i++) { Voice *voice = &voices[i]; // Register voice. if (voice->active && voice->d1 == d1) { @@ -303,10 +407,7 @@ clear_pads(void) { } void -draw_poly_scene(void) { - print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0); - print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0); - +draw_poly_active_button(void) { if (active) { hal_plot_led(TYPEPAD, 11, 0, MAXLED, 0); } else { @@ -314,11 +415,103 @@ draw_poly_scene(void) { } } +void +draw_poly_main(void) { + print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0); + print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0); + draw_poly_active_button(); +} + +void +draw_min_channel(void) { + for (u8 i = 0; i < 8; i++) { + if (i == ch_min) { + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED); + continue; + } + if (ch_max < 8 && i > ch_max) { + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, 0, 0, 5); + continue; + } + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, 0, 0, MAXLED / 2); + } + for (u8 i = 0; i < 8; i++) { + if ((i + 8) == ch_min) { + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, MAXLED, MAXLED, MAXLED); + continue; + } + if (ch_max < 16 && (i + 8) > ch_max) { + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, 0, 0, 5); + continue; + } + hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, 0, 0, MAXLED / 2); + } +} + +void +draw_max_channel(void) { + // for (u8 i = 0; i < 8; i++) { + // u8 color = 5; + // if (i == ch_max) { + // color = MAXLED; + // } + // hal_plot_led(TYPEPAD, 11 + 10 * 5 + i, color, 10, 10); + // color = 5; + // if (i + 8 == ch_max) { + // color = MAXLED; + // } + // hal_plot_led(TYPEPAD, 11 + 10 * 4 + i, color, 10, 10); + // } + for (u8 i = 0; i < 8; i++) { + if (i == ch_max) { + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED, MAXLED, MAXLED); + continue; + } + if (i < ch_min) { + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, 5, 0, 0); + continue; + } + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED / 2, 0, 0); + } + for (u8 i = 0; i < 8; i++) { + if ((i + 8) == ch_max) { + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, MAXLED, MAXLED, MAXLED); + continue; + } + if (ch_min >= 8 && (i + 8) < ch_min) { + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, 5, 0, 0); + continue; + } + hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, MAXLED / 2, 0, 0); + } +} + +void +draw_poly_setup(void) { + // TODO: ... + draw_min_channel(); + draw_max_channel(); + // draw_listen_channel(); + draw_poly_active_button(); +} + +void +draw_scene(void) { + switch (mode) { + case MOD_POLY_MAIN: { + draw_poly_main(); + } break; + case MOD_POLY_SETUP: { + draw_poly_setup(); + } break; + } +} + void render(void) { if (frame++ == 1000 / 10) { clear_pads(); - draw_poly_scene(); + draw_scene(); frame = 0; } } @@ -332,7 +525,7 @@ app_timer_event() { void app_init(const u16 *adc_raw) { // example - load button states from flash - hal_read_flash(0, buttons, BUTTON_COUNT); + // hal_read_flash(0, buttons, BUTTON_COUNT); // store off the raw ADC frame pointer for later use g_ADC = adc_raw; -- cgit v1.2.1