diff --git a/MicroDexed.ino b/MicroDexed.ino index 49f7622..e4d98f1 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -1151,12 +1151,12 @@ void handleSystemExclusive(byte * sysex, uint len) LCDML.loop_menu(); } } - else if (len == 4104 && strlen(receive_bank_filename) > 0) + else if (len == 4104 && strlen(receive_bank_filename) > 0 && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sysex_receive_bank)) { int32_t bulk_checksum_calc = 0; int8_t bulk_checksum = sysex[4102]; - // 1 Voice bulk upload + // 1 Bank bulk upload #ifdef DEBUG Serial.println(F("Bank bulk upload")); #endif @@ -1196,23 +1196,30 @@ void handleSystemExclusive(byte * sysex, uint len) return; } -#ifdef DEBUG if (save_sd_bank(receive_bank_filename, sysex)) { +#ifdef DEBUG Serial.print(F("Bank saved as [")); Serial.print(receive_bank_filename); Serial.println(F("]")); +#endif + lcd.setCursor(0, 1); + lcd.print(F("Done. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); } else { +#ifdef DEBUG Serial.println(F("Error during saving bank as [")); Serial.print(receive_bank_filename); Serial.println(F("]")); - } -#else - save_sd_bank(receive_bank_filename, sysex); #endif - + lcd.setCursor(0, 1); + lcd.print(F("Error. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } memset(receive_bank_filename, 0, FILENAME_LEN); } #ifdef DEBUG diff --git a/UI.hpp b/UI.hpp index 1ebbe61..cd4b52d 100644 --- a/UI.hpp +++ b/UI.hpp @@ -58,6 +58,7 @@ extern void eeprom_update_fx(void); extern void eeprom_update_dexed(uint8_t instance_id); extern float pseudo_log_curve(float value); extern uint8_t selected_instance_id; +extern char receive_bank_filename[FILENAME_LEN]; #ifdef DISPLAY_LCD_SPI extern void change_disp_sd(bool d); @@ -97,6 +98,7 @@ extern char g_bank_name[NUM_DEXED][BANK_NAME_LEN]; ************************************************************************/ elapsedMillis back_from_volume; uint8_t instance_num[8][8]; +char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; #ifdef I2C_DISPLAY #include @@ -253,6 +255,7 @@ void UI_func_eq_bass(uint8_t param); void UI_func_eq_treble(uint8_t param); void UI_function_not_enabled(void); void UI_function_not_implemented(uint8_t param); +bool UI_select_name(uint8_t y, uint8_t x, char* edit_string, uint8_t len, bool init); void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign); void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign); void lcd_display_bar_int(const char* title, uint32_t value, float factor, int32_t min_value, int32_t max_value, uint8_t size, bool zeros, bool sign, bool init); @@ -4678,14 +4681,27 @@ void UI_func_save_voice(uint8_t param) void UI_func_sysex_receive_bank(uint8_t param) { + static bool yesno; + static uint8_t mode; + static uint8_t bank_number; + static uint8_t ui_select_name_state; + if (LCDML.FUNC_setup()) // ****** SETUP ********* { encoderDir[ENC_R].reset(); + yesno = false; + mode = 0; + bank_number = configuration.performance.bank[selected_instance_id]; + lcd.setCursor(0, 0); lcd.print(F("MIDI Recv Bank")); lcd.setCursor(0, 1); - lcd.print(F("Not implemented.")); + lcd.print(F("[ ]")); + if (!get_bank_name(configuration.performance.bank[selected_instance_id], receive_bank_filename, sizeof(receive_bank_filename))) + strncpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename)); + lcd.show(1, 1, 2, bank_number); + lcd.show(1, 5, 10, receive_bank_filename); } if (LCDML.FUNC_loop()) // ****** LOOP ********* @@ -4694,18 +4710,121 @@ void UI_func_sysex_receive_bank(uint8_t param) { if (LCDML.BT_checkDown()) { - ; + switch (mode) + { + case 0: + bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename))) + strncpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename)); + lcd.show(1, 1, 2, bank_number); + lcd.show(1, 5, 10, receive_bank_filename); + break; + case 1: + yesno = !yesno; + if (yesno) + lcd.show(1, 12, 3, "YES"); + else + lcd.show(1, 12, 3, "NO"); + break; + case 2: + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + break; + } } else if (LCDML.BT_checkUp()) { - ; + switch (mode) + { + case 0: + bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename))) + strncpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename)); + lcd.show(1, 1, 2, bank_number); + lcd.show(1, 5, 10, receive_bank_filename); + break; + case 1: + yesno = !yesno; + if (yesno) + lcd.show(1, 12, 3, "YES"); + else + lcd.show(1, 12, 3, "NO"); + break; + case 2: + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + break; + } + } + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + if (mode == 0) + { + if (!strncmp(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename))) + { + yesno = true; + strncpy(receive_bank_filename, "EMPTY", BANK_NAME_LEN); + mode += 2; + lcd.blink(); + } + else + { + mode = 1; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [NO ]")); + } + } + else if (mode == 1 && yesno == true) + { + mode = 2; + lcd.setCursor(0, 1); + lcd.print(F("[ ] ")); + lcd.blink(); + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, true); + } + else if (mode == 2) + { + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + if (ui_select_name_state == true) + { + if (yesno == true) + { + mode = 0xff; + + lcd.noBlink(); + lcd.setCursor(0, 1); + lcd.print(F("Waiting... ")); + /// Storing is done in SYSEX code + } + } + } + else if (mode >= 1 && yesno == false) + { + Serial.println(mode, DEC); + memset(receive_bank_filename, 0, sizeof(receive_bank_filename)); + mode = 0xff; + lcd.noBlink(); + lcd.setCursor(0, 1); + lcd.print(F("Canceled. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); } } + encoderDir[ENC_R].reset(); } if (LCDML.FUNC_close()) // ****** STABLE END ********* { encoderDir[ENC_R].reset(); + + memset(receive_bank_filename, 0, sizeof(receive_bank_filename)); + lcd.noBlink(); + + if (mode < 0xff) + { + lcd.setCursor(0, 1); + lcd.print(F("Canceled. ")); + delay(MESSAGE_WAIT_TIME); + } } } @@ -4942,6 +5061,91 @@ void UI_function_not_implemented(uint8_t param) } } +bool UI_select_name(uint8_t y, uint8_t x, char* edit_string, uint8_t len, bool init) +{ + static int8_t edit_pos; + static bool edit_mode; + + if (init == true) + { + lcd.setCursor(x, y); + lcd.print(edit_string); + edit_mode = false; + edit_pos = 0; + lcd.setCursor(x, y); + return (false); + } + + if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) + { + if (LCDML.BT_checkDown()) + { + if (edit_mode == true) + { + edit_string[edit_pos] = constrain(edit_string[edit_pos] + 1, 32, 126); + lcd.setCursor(x + edit_pos, y); + lcd.print(edit_string[edit_pos]); + } + else + { + edit_pos = constrain(edit_pos + 1, 0, len); + + if (edit_pos == len) + { + lcd.noBlink(); + lcd.setCursor(x - 1, y); + lcd.print(F(" ")); + lcd.setCursor(x + len, y); + lcd.print(F(" ")); + lcd.setCursor(x + len + 1, y); + lcd.print(F("[OK]")); + } + } + } + else if (LCDML.BT_checkUp()) + { + if (edit_mode == true) + { + edit_string[edit_pos] = constrain(edit_string[edit_pos] - 1, 32, 126); + lcd.setCursor(x + edit_pos, y); + lcd.print(edit_string[edit_pos]); + } + else + { + edit_pos = constrain(edit_pos - 1, 0, len - 1); + + if (edit_pos == len - 1) + { + lcd.setCursor(x - 1, y); + lcd.print(F("[")); + lcd.setCursor(x + len, y); + lcd.print(F("]")); + lcd.setCursor(x + len + 1, y); + lcd.print(F(" ")); + lcd.blink(); + } + } + } + } + else if (LCDML.BT_checkEnter()) + { + if (edit_pos >= len) + { + edit_pos = 0; + edit_mode = false; + return (true); + } + else + { + edit_mode = !edit_mode; + } + } + lcd.setCursor(x + edit_pos, y); + encoderDir[ENC_R].reset(); + + return (false); +} + void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign) { lcd_display_float(float(var), size, 0, zeros, brackets, sign); diff --git a/config.h b/config.h index 8666ec1..89afb2a 100644 --- a/config.h +++ b/config.h @@ -43,13 +43,18 @@ // Tools for testing MIDI: https://github.com/gbevin/SendMIDI // https://github.com/gbevin/ReceiveMIDI // -// e.g. sendmidi dev "MicroDexed MIDI" on 80 127 && sleep 1.0 && sendmidi dev "MicroDexed MIDI" off 80 0 +// e.g.: +// * sendmidi dev "MicroDexed MIDI" on 80 127 && sleep 1.0 && sendmidi dev "MicroDexed MIDI" off 80 0 +// * sendmidi dev "MicroDexed MIDI" syx syf addon/SD/90/RitCh1.syx // // Receiving and storing MIDI SYSEX with Linux: // amidi -p hw:2,0,0 -d -r /tmp/bkup1.syx // +// For SYSEX Bank upload via USB: +// sed -i.orig 's/SYSEX_MAX_LEN = 290/SYSEX_MAX_LEN = 4104/' /usr/local/arduino-teensy-1.8.12/hardware/teensy/avr/libraries/USBHost_t36/USBHost_t36.h +// sed -i.orig 's/^#define USB_MIDI_SYSEX_MAX 290/#define USB_MIDI_SYSEX_MAX 4104/' /usr/local/arduino-teensy-1.8.12/hardware/teensy/avr/cores/teensy3/usb_midi.h -#define VERSION "0.9.9j" +#define VERSION "0.9.9k" //************************************************************************************************* //* DEVICE SETTINGS diff --git a/midi_devices.hpp b/midi_devices.hpp index 2a10971..4051f95 100644 --- a/midi_devices.hpp +++ b/midi_devices.hpp @@ -35,8 +35,14 @@ extern config_t configuration; #include #endif +// override default sysex size settings +struct MicroDexedSettings : public midi::DefaultSettings +{ + static const unsigned SysExMaxSize = 4104; // Accept SysEx messages up to 1024 bytes long. +}; + #ifdef MIDI_DEVICE_DIN -MIDI_CREATE_INSTANCE(HardwareSerial, MIDI_DEVICE_DIN, midi_serial); +MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, MIDI_DEVICE_DIN, midi_serial, MicroDexedSettings); #endif #ifdef MIDI_DEVICE_USB_HOST USBHost usb_host;