diff --git a/UI.hpp b/UI.hpp index 3fadddd..5e8bc12 100644 --- a/UI.hpp +++ b/UI.hpp @@ -4108,50 +4108,148 @@ void UI_func_save_fx(uint8_t param) void UI_func_save_voice(uint8_t param) { static bool yesno; + static uint8_t mode; + + uint8_t instance_id = 0; if (LCDML.FUNC_setup()) // ****** SETUP ********* { encoderDir[ENC_R].reset(); + yesno = false; + mode = 0; + + char bank_name[BANK_NAME_LEN]; + + if (!get_bank_name(configuration.performance.bank[instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + lcd.setCursor(0, 0); - lcd.print(F("Save Voice")); - lcd.setCursor(0, 1); - lcd.print(F("[NO ]")); + lcd.print(F("Save to Bank")); + lcd.show(1, 0, 2, configuration.performance.bank[instance_id]); + lcd.show(1, 4, 10, bank_name); + lcd.show(1, 2, 2, " ["); + lcd.show(1, 14, 1, "]"); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; - if (LCDML.FUNC_loop()) // ****** LOOP ********* + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) { - if ((LCDML.BT_checkDown() || LCDML.BT_checkUp())) + switch (mode) + { + case 0: // Bank selection + if (LCDML.BT_checkDown()) + configuration.performance.bank[instance_id] = constrain(configuration.performance.bank[instance_id] + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + else if (LCDML.BT_checkUp() && configuration.performance.bank[instance_id] > 0) + configuration.performance.bank[instance_id] = constrain(configuration.performance.bank[instance_id] - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + + if (!get_bank_name(configuration.performance.bank[instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + + lcd.show(1, 0, 2, configuration.performance.bank[instance_id]); + lcd.show(1, 4, 10, bank_name); + break; + case 1: // Voice selection + if (LCDML.BT_checkDown() && configuration.performance.voice[instance_id] < MAX_VOICES - 1) + configuration.performance.voice[instance_id] = constrain(configuration.performance.voice[instance_id] + ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + else if (LCDML.BT_checkUp() && configuration.performance.voice[instance_id] > 0) + configuration.performance.voice[instance_id] = constrain(configuration.performance.voice[instance_id] - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + + if (!get_bank_name(configuration.performance.bank[instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(configuration.performance.bank[instance_id], bank_name, configuration.performance.voice[instance_id], voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, configuration.performance.voice[instance_id] + 1); + lcd.show(1, 4, 10, voice_name); + break; + case 2: // Yes/No selection + yesno = !yesno; + if (yesno == true) + { + lcd.show(1, 1, 3, "YES"); + } + else + { + lcd.show(1, 1, 3, "NO"); + } + break; + } + } + else if (LCDML.BT_checkEnter()) + { + if (encoderDir[ENC_R].ButtonShort()) + mode++; + + if (mode == 1) + { + if (!get_bank_name(configuration.performance.bank[instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(configuration.performance.bank[instance_id], bank_name, configuration.performance.voice[instance_id], voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(0, 0, 16, "Save to Bank"); + lcd.show(0, 13, 2, configuration.performance.bank[instance_id]); + lcd.show(1, 0, 2, configuration.performance.voice[instance_id] + 1); + lcd.show(1, 4, 10, voice_name); + } + if (mode == 2) + { + lcd.show(0, 0, 16, "Overwrite?"); + lcd.show(1, 0, 15, "[NO"); + lcd.show(1, 4, 1, "]"); + } + else if (mode > 2) { - yesno = !yesno; if (yesno == true) { - lcd.setCursor(1, 1); - lcd.print(F("YES")); - } - else - { - lcd.setCursor(1, 1); - lcd.print(F("NO ")); + bool ret = save_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); + +#ifdef DEBUG + if (ret == true) + Serial.println(F("Saving voice OK.")); + else + Serial.println(F("Error while saving voice.")); +#endif + + lcd.show(1, 0, 16, "Done."); + delay(500); + + mode = 0xff; } + + LCDML.FUNC_goBackToMenu(); } } + } - if (LCDML.FUNC_close()) // ****** STABLE END ********* + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) { - if (yesno == true) + lcd.show(1, 0, 16, "Canceled."); + delay(500); + } + else + { + if (instance_id == 0) { - LCDML.DISP_clear(); - lcd.print(F("Save Cfg default")); - - // Storing on inside bank TBD - - lcd.setCursor(0, 1); - lcd.print(F("Done. ")); - delay(500); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[0]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[0]); } - - encoderDir[ENC_R].reset(); +#if NUM_DEXED > 1 + else + { + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[1]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[1]); + } +#endif } + encoderDir[ENC_R].reset(); } } diff --git a/dexed_sd.cpp b/dexed_sd.cpp index aaa7926..1d3dabe 100644 --- a/dexed_sd.cpp +++ b/dexed_sd.cpp @@ -36,9 +36,6 @@ bool load_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id) { -#if DEBUG - bool found = false; -#endif v = constrain(v, 0, MAX_VOICES - 1); b = constrain(b, 0, MAX_BANKS - 1); @@ -89,10 +86,59 @@ bool load_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id) #endif sysex.close(); } + + return (false); +} + +bool save_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id) +{ + v = constrain(v, 0, MAX_VOICES - 1); + b = constrain(b, 0, MAX_BANKS - 1); + + if (sd_card > 0) + { + File sysex; + char filename[FILENAME_LEN]; + char bank_name[BANK_NAME_LEN]; + uint8_t data[128]; + + get_bank_name(b, bank_name, sizeof(bank_name)); + sprintf(filename, "/%d/%s.syx", b, bank_name); + + sysex = SD.open(filename, FILE_WRITE); + if (!sysex) + { +#ifdef DEBUG + Serial.print(F("E : Cannot open ")); + Serial.print(filename); + Serial.println(F(" on SD.")); +#endif + return (false); + } + + MicroDexed[instance_id]->encodeVoice(data); + + if (put_sd_voice(sysex, v, data)) + { +#ifdef DEBUG + char voice_name[VOICE_NAME_LEN]; + strncpy(voice_name, (char*)&MicroDexed[instance_id]->data[145], sizeof(voice_name)); + Serial.print(F("Saving voice to ")); + Serial.print(filename); + Serial.print(F(" [")); + Serial.print(voice_name); + Serial.println(F("]")); +#endif + sysex.close(); + + return (true); + } #ifdef DEBUG - if (found == false) - Serial.println(F("E : File not found.")); + else + Serial.println(F("E : Cannot load voice data")); #endif + sysex.close(); + } return (false); } @@ -177,6 +223,72 @@ bool get_sd_voice(File sysex, uint8_t voice_number, uint8_t* data) return (true); } +bool put_sd_voice(File sysex, uint8_t voice_number, uint8_t* data) +{ + uint16_t n; + int32_t bulk_checksum_calc = 0; + + sysex.seek(0); + + if (sysex.size() != 4104) // check sysex size + { +#ifdef DEBUG + Serial.println(F("E : SysEx file size wrong.")); +#endif + return (false); + } + if (sysex.read() != 0xf0) // check sysex start-byte + { +#ifdef DEBUG + Serial.println(F("E : SysEx start byte not found.")); +#endif + return (false); + } + if (sysex.read() != 0x43) // check sysex vendor is Yamaha + { +#ifdef DEBUG + Serial.println(F("E : SysEx vendor not Yamaha.")); +#endif + return (false); + } + sysex.seek(4103); + if (sysex.read() != 0xf7) // check sysex end-byte + { +#ifdef DEBUG + Serial.println(F("E : SysEx end byte not found.")); +#endif + return (false); + } + sysex.seek(3); + if (sysex.read() != 0x09) // check for sysex type (0x09=32 voices) + { +#ifdef DEBUG + Serial.println(F("E : SysEx type not 32 voices.")); +#endif + return (false); + } + + sysex.seek(6 + voice_number * 128); + sysex.write(data, 128); + + // checksum calculation + sysex.seek(6); // start of bulk data + for (n = 0; n < 4096; n++) + { + uint8_t d = sysex.read(); + bulk_checksum_calc -= d; + } + sysex.seek(4102); // Bulk checksum + sysex.write(bulk_checksum_calc & 0x7f); + +#ifdef DEBUG + Serial.print(F("Bulk checksum : 0x")); + Serial.println(bulk_checksum_calc & 0x7f, HEX); +#endif + + return (true); +} + /****************************************************************************** SD VOICECONFIG ******************************************************************************/ diff --git a/dexed_sd.h b/dexed_sd.h index 1e9d666..0c48a1d 100644 --- a/dexed_sd.h +++ b/dexed_sd.h @@ -48,7 +48,9 @@ extern void set_voiceconfig_params(uint8_t instance_id); extern void set_sys_params(void); bool load_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id); +bool save_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id); bool get_sd_voice(File sysex, uint8_t voice_number, uint8_t* data); +bool put_sd_voice(File sysex, uint8_t voice_number, uint8_t* data); bool load_sd_voiceconfig(uint8_t vc, uint8_t instance_id); bool save_sd_voiceconfig(uint8_t vc, uint8_t instance_id);