From ca67fe00a89b834328f2b48c35e0a534ee91a075 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 9 Feb 2023 16:20:26 +0100 Subject: Add state saving to flash --- src/app.c | 105 ++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/app.c b/src/app.c index 29d114f..4f52d89 100644 --- a/src/app.c +++ b/src/app.c @@ -180,24 +180,30 @@ typedef struct Voice { u8 d1; u8 d2; u8 port; + u8 age; } Voice; +typedef struct State { + // Polyphony. + u8 active; + u8 ch_min; + u8 ch_max; + u8 ch_listen[16]; + Mode mode; +} State; + // Globals. u16 frame = 0; u16 n_voices = 0; -u8 active = 1; -u8 ch_min = 0; -u8 ch_max = 7; -u8 ch_listen[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; -Mode mode = MOD_POLY_SETUP; Voice voices[16] = {0}; +State state = {0}; +u32 note_counter = 0; // store ADC frame pointer static const u16 *g_ADC = 0; void -poly_active_toggle(void) { - // Stop existing playing notes. +poly_stop_all(void) { for (u8 i = 0; i < 16; i++) { Voice *voice = &voices[i]; if (voice->active) { @@ -210,33 +216,39 @@ poly_active_toggle(void) { } } n_voices = 0; - active = !active; +} + +void +poly_active_toggle(void) { + poly_stop_all(); + state.active = !state.active; } void select_ch_min(u8 target) { - if (target <= ch_max) { - ch_min = target; + if (target <= state.ch_max) { + state.ch_min = target; } } void select_ch_max(u8 target) { - if (target >= ch_min) { - ch_max = target; + if (target >= state.ch_min) { + state.ch_max = target; } } void select_ch_sel(u8 target) { - ch_listen[target] = !ch_listen[target]; + poly_stop_all(); + state.ch_listen[target] = !state.ch_listen[target]; } void app_surface_event(u8 type, u8 index, u8 value) { switch (type) { case TYPEPAD: { - switch (mode) { + switch (state.mode) { case MOD_POLY_MAIN: { if (value && index == POLY_PAD_ACTIVE) { poly_active_toggle(); @@ -306,45 +318,41 @@ app_surface_event(u8 type, u8 index, u8 value) { } break; case TYPESETUP: { if (value) { - switch (mode) { + switch (state.mode) { case MOD_POLY_MAIN: { - mode = MOD_POLY_SETUP; + state.mode = MOD_POLY_SETUP; } break; case MOD_POLY_SETUP: { - mode = MOD_POLY_MAIN; - // TODO: save to flash. + state.mode = MOD_POLY_MAIN; + hal_write_flash(0, (u8*)&state, sizeof(State)); + } 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 - // // long and can be organized however we need. - // hal_write_flash(0, buttons, BUTTON_COUNT); - // } } break; } } void app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { - if (!active) { + if (!state.active) { hal_send_midi(port, status, d1, d2); return; } u8 channel = status & 0x0F; // If the channel isn't set to listen, just passthrough the message. - if (!ch_listen[channel]) { + if (!state.ch_listen[channel]) { hal_send_midi(port, status, d1, d2); return; } if ((status & 0xF0) == NOTEON) { - if (n_voices == (ch_max - ch_min + 1)) { + // TODO: Only do this if voice stealing is disabled. + if (n_voices == (state.ch_max - state.ch_min + 1)) { return; } // Find if the note was already pressed. - for (u8 i = ch_min; i <= ch_max; i++) { + for (u8 i = state.ch_min; i <= state.ch_max; i++) { Voice *voice = &voices[i]; // Stop voice if needed. if (voice->active && voice->d1 == d1) { @@ -358,7 +366,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 = state.ch_min; i <= state.ch_max; i++) { Voice *voice = &voices[i]; // Register voice. if (!voice->active) { @@ -371,17 +379,17 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { NOTEON | voice->channel, voice->d1, voice->d2); + voice->age = note_counter++; break; } } // TODO: if there are no free slots choose the oldest active one. // TODO: - Send noteoff message for the previous active channel. - // TODO: send noteon message. // TODO: Round robin scheduling? n_voices++; } else if ((status & 0xF0) == NOTEOFF) { - for (u8 i = ch_min; i <= ch_max; i++) { + for (u8 i = state.ch_min; i <= state.ch_max; i++) { Voice *voice = &voices[i]; // Register voice. if (voice->active && voice->d1 == d1) { @@ -391,6 +399,8 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { break; } } + } else { + hal_send_midi(port, status, d1, d2); } } @@ -451,7 +461,7 @@ clear_pads(void) { void draw_poly_active_button(void) { - if (active) { + if (state.active) { hal_plot_led(TYPEPAD, 11, 0, MAXLED, 0); } else { hal_plot_led(TYPEPAD, 11, MAXLED, 0, 0); @@ -468,22 +478,22 @@ draw_poly_main(void) { void draw_min_channel(void) { for (u8 i = 0; i < 8; i++) { - if (i == ch_min) { + if (i == state.ch_min) { hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED); continue; } - if (ch_max < 8 && i > ch_max) { + if (state.ch_max < 8 && i > state.ch_max) { hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, 5, 0, 0); continue; } hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED / 2, 0, 0); } for (u8 i = 0; i < 8; i++) { - if ((i + 8) == ch_min) { + if ((i + 8) == state.ch_min) { hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, MAXLED, MAXLED, MAXLED); continue; } - if (ch_max < 16 && (i + 8) > ch_max) { + if (state.ch_max < 16 && (i + 8) > state.ch_max) { hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, 5, 0, 0); continue; } @@ -494,22 +504,22 @@ draw_min_channel(void) { void draw_max_channel(void) { for (u8 i = 0; i < 8; i++) { - if (i == ch_max) { + if (i == state.ch_max) { hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED, MAXLED, MAXLED); continue; } - if (i < ch_min) { + if (i < state.ch_min) { hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, 5, 5, 0); continue; } hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED / 2, MAXLED / 2, 0); } for (u8 i = 0; i < 8; i++) { - if ((i + 8) == ch_max) { + if ((i + 8) == state.ch_max) { hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, MAXLED, MAXLED, MAXLED); continue; } - if (ch_min >= 8 && (i + 8) < ch_min) { + if (state.ch_min >= 8 && (i + 8) < state.ch_min) { hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, 5, 5, 0); continue; } @@ -520,14 +530,14 @@ draw_max_channel(void) { void draw_sel_channel(void) { for (u8 i = 0; i < 8; i++) { - if (ch_listen[i]) { + if (state.ch_listen[i]) { hal_plot_led(TYPEPAD, POLY_PAD_SEL_CH_0 + i, 20, 0, 40); } else { hal_plot_led(TYPEPAD, POLY_PAD_SEL_CH_0 + i, 2, 0, 5); } } for (u8 i = 0; i < 8; i++) { - if (ch_listen[i + 8]) { + if (state.ch_listen[i + 8]) { hal_plot_led(TYPEPAD, POLY_PAD_SEL_CH_8 + i, 20, 0, 40); } else { hal_plot_led(TYPEPAD, POLY_PAD_SEL_CH_8 + i, 2, 0, 5); @@ -546,7 +556,7 @@ draw_poly_setup(void) { void draw_scene(void) { - switch (mode) { + switch (state.mode) { case MOD_POLY_MAIN: { draw_poly_main(); } break; @@ -574,7 +584,14 @@ app_timer_event() { void app_init(const u16 *adc_raw) { // example - load button states from flash - // hal_read_flash(0, buttons, BUTTON_COUNT); + state = (State){ + .active = 1, + .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)); // store off the raw ADC frame pointer for later use g_ADC = adc_raw; -- cgit v1.2.1