diff --git a/MicroDexed.ino b/MicroDexed.ino index 7107cb5..4ea17ad 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -20,7 +20,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ #include @@ -82,12 +81,15 @@ uint32_t overload = 0; uint32_t peak = 0; uint16_t render_time_max = 0; uint8_t bank = 0; +uint8_t max_loaded_banks=0; uint8_t voice = 0; float vol = VOLUME; float vol_right = 1.0; float vol_left = 1.0; -char bank_name[11]; -char voice_name[11]; +char bank_name[BANK_NAME_LEN]; +char voice_name[VOICE_NAME_LEN]; +char bank_names[MAX_BANKS][BANK_NAME_LEN]; +char voice_names[MAX_VOICES][VOICE_NAME_LEN]; #ifdef MASTER_KEY_MIDI bool master_key_enabled = false; #endif @@ -180,17 +182,41 @@ void setup() Serial.println(F("SD card found.")); sd_card_available = true; + // read all bank names + max_loaded_banks=get_bank_names(); + strip_extension(bank_names[bank],bank_name); + + // read all voice name for actual bank + get_voice_names_from_bank(bank); +#ifdef DEBUG + Serial.print(F("Bank [")); + Serial.print(bank_names[bank]); + Serial.print(F("/")); + Serial.print(bank_name); + Serial.println(F("]")); + for (uint8_t n = 0; n < MAX_VOICES; n++) + { + if (n < 10) + Serial.print(F(" ")); + Serial.print(F(" ")); + Serial.print(n, DEC); + Serial.print(F("[")); + Serial.print(voice_names[n]); + Serial.println(F("]")); + } +#endif // load default SYSEX data load_sysex(bank, voice); + } + #ifdef I2C_DISPLAY - enc[0].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); - enc_val[0] = enc[0].read(); - enc[1].write(voice); - enc_val[1] = enc[1].read(); - but[0].update(); - but[1].update(); + enc[0].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); + enc_val[0] = enc[0].read(); + enc[1].write(voice); + enc_val[1] = enc[1].read(); + but[0].update(); + but[1].update(); #endif - } #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) // Initialize processor and memory measurements @@ -383,7 +409,7 @@ bool handle_master_key(uint8_t data) #ifdef I2C_DISPLAY lcd.show(1, 0, 2, voice + 1); lcd.show(1, 2, 1, " "); - lcd.show(1, 3, 10, voice_name); + lcd.show(1, 3, 10, voice_names[voice]); #endif } #ifdef DEBUG @@ -414,8 +440,9 @@ bool handle_master_key(uint8_t data) Serial.println(bank, DEC); #endif #ifdef I2C_DISPLAY - if (get_bank_voice_name(bank, voice)) + if (get_voice_names_from_bank(bank)) { + strip_extension(bank_names[bank],bank_name); lcd.show(0, 0, 2, bank + 1); lcd.show(0, 2, 1, " "); lcd.show(0, 3, 10, bank_name); @@ -588,12 +615,12 @@ void set_volume(float v, float vr, float vl) #endif #ifdef TEENSY_AUDIO_BOARD - //sgtl5000_1.dacVolume(log(vol * vol_left)+1, log(vol * vol_right)+1); - sgtl5000_1.dacVolume(1 - pow((1 - vol * vol_left), 2.7), (1 - pow((1 - vol * vol_right), 2.7))); + //sgtl5000_1.dacVolume(vol * vol_left, vol * vol_right); + sgtl5000_1.dacVolume(pow(vol * vol_left, 0.2), pow(vol * vol_right, 0.2)); #else - volume_master.gain(1 - pow(1 - lvol, 2.7)); - volume_r.gain(1 - pow(1 - vr, 2.7)); - volume_l.gain(1 - pow(1 - vl, 2.7)); + volume_master.gain(pow(lvol, 0.2)); + volume_r.gain(pow(vr, 0.2)); + volume_l.gain(pow(vl, 0.2)); #endif } @@ -772,7 +799,7 @@ void show_cpu_and_mem_usage(void) void show_patch(void) { uint8_t i; - char voicename[11]; + char voicename[VOICE_NAME_LEN]; memset(voicename, 0, sizeof(voicename)); for (i = 0; i < 6; i++) diff --git a/UI.cpp b/UI.cpp index 08613ee..cce569e 100644 --- a/UI.cpp +++ b/UI.cpp @@ -109,33 +109,33 @@ void handle_ui(void) case UI_MAIN_BANK: if (enc[i].read() <= 0) enc[i].write(0); - else if (enc[i].read() >= MAX_BANKS) - enc[i].write(MAX_BANKS); + else if (enc[i].read() > max_loaded_banks-1) + enc[i].write(max_loaded_banks-1); bank = enc[i].read(); - if (!get_bank_voice_name(bank, voice)) + if (!get_voice_names_from_bank(bank)) { bank--; enc[i].write(bank); - get_bank_voice_name(bank, voice); + get_voice_names_from_bank(bank); } break; case UI_MAIN_VOICE: if (enc[i].read() <= 0) enc[i].write(0); - else if (enc[i].read() >= MAX_VOICES) - enc[i].write(MAX_VOICES); + else if (enc[i].read() > MAX_VOICES-1) + enc[i].write(MAX_VOICES-1); voice = enc[i].read(); break; case UI_MAIN_VOICE_SELECTED: ui_main_state = UI_MAIN_VOICE; if (enc[i].read() <= 0) enc[i].write(0); - else if (enc[i].read() >= MAX_VOICES) + else if (enc[i].read() >= MAX_VOICES-1) enc[i].write(MAX_VOICES); voice = enc[i].read(); break; } - get_bank_voice_name(bank, voice); + get_voice_names_from_bank(bank); ui_show_main(); break; } @@ -157,6 +157,8 @@ void ui_show_main(void) lcd.clear(); lcd.show(0, 0, 2, bank + 1); lcd.show(0, 2, 1, " "); + strip_extension(bank_names[bank], bank_name); + if (ui_main_state == UI_MAIN_BANK) { lcd.show(0, 2, 1, "["); @@ -171,17 +173,17 @@ void ui_show_main(void) if (ui_main_state == UI_MAIN_VOICE) { lcd.show(1, 2, 1, "<"); - lcd.show(1, 3, 10, voice_name); + lcd.show(1, 3, 10, voice_names[voice]); lcd.show(1, 14, 1, ">"); } else if (ui_main_state == UI_MAIN_VOICE_SELECTED) { lcd.show(1, 2, 1, "["); - lcd.show(1, 3, 10, voice_name); + lcd.show(1, 3, 10, voice_names[voice]); lcd.show(1, 14, 1, "]"); } else - lcd.show(1, 3, 10, voice_name); + lcd.show(1, 3, 10, voice_names[voice]); } void ui_show_volume(void) diff --git a/UI.h b/UI.h index 6b89594..f76a071 100644 --- a/UI.h +++ b/UI.h @@ -40,9 +40,10 @@ extern float vol_left; extern float vol_right; extern LiquidCrystalPlus_I2C lcd; extern uint8_t bank; +extern uint8_t max_loaded_banks; extern uint8_t voice; -extern char bank_name[11]; -extern char voice_name[11]; +extern char bank_name[BANK_NAME_LEN]; +extern char voice_name[VOICE_NAME_LEN]; extern uint8_t ui_state; extern uint8_t ui_main_state; extern void update_eeprom_checksum(void); diff --git a/config.h b/config.h index 65dc6b5..56081cd 100644 --- a/config.h +++ b/config.h @@ -49,6 +49,8 @@ #define SAMPLE_RATE 44100 #define MAX_BANKS 99 #define MAX_VOICES 32 // voices per bank +#define BANK_NAME_LEN 13 // FAT12 filenames (plus '\0') +#define VOICE_NAME_LEN 11 // 10 (plus '\0') #if !defined(__MK66FX1M0__) // check for Teensy-3.6 #define MAX_NOTES 11 // No? diff --git a/dexed_sysex.cpp b/dexed_sysex.cpp index db6b78d..4186d27 100644 --- a/dexed_sysex.cpp +++ b/dexed_sysex.cpp @@ -32,64 +32,193 @@ #include "config.h" #include "UI.h" -bool get_bank_voice_name(uint8_t b, uint8_t v) +void create_sysex_filename(uint8_t b, char* sysex_file_name) { - File root; + // init and set name for actual bank + memset(sysex_file_name, 0, 4 + VOICE_NAME_LEN); + sysex_file_name[0] = '/'; + itoa(b, &sysex_file_name[1], 10); + strcat(sysex_file_name, "/"); + strcat(sysex_file_name, bank_names[b]); +#ifdef DEBUG + Serial.print(F("Created sysex_filename from bank ")); + Serial.print(b, DEC); + Serial.print(F(" and name ")); + Serial.print(bank_names[b]); + Serial.print(F(": [")); + Serial.print(sysex_file_name); + Serial.println(F("]")); +#endif +} + +void strip_extension(char* s, char* target) +{ + char tmp[BANK_NAME_LEN]; + char* token; + + strcpy(tmp,s); + token = strtok(tmp, "."); + if (token == NULL) + strcpy(target, "*ERROR*"); + else + strcpy(target, token); +} + +bool get_voice_names_from_bank(uint8_t b) +{ + File sysex; + uint8_t voice_counter = 0; + int32_t bulk_checksum_calc = 0; + int8_t bulk_checksum; + b %= MAX_BANKS; + // erase all data for voice names + memset(voice_names, 0, MAX_VOICES * VOICE_NAME_LEN); + if (sd_card_available) { - char bankdir[4]; + char sysex_file_name[4 + VOICE_NAME_LEN]; + + // init and set name for actual bank + create_sysex_filename(b, sysex_file_name); - memset(bankdir, 0, sizeof(bankdir)); - bankdir[0] = '/'; - itoa(b, &bankdir[1], 10); +#ifdef DEBUG + Serial.print(F("Reading voice names for bank [")); + Serial.print(sysex_file_name); + Serial.println(F("]")); +#endif - root = SD.open(bankdir); - if (!root) + // try to open bank directory + sysex = SD.open(sysex_file_name); + if (!sysex) + return (false); + + if (sysex.size() != 4104) // check sysex size { #ifdef DEBUG - Serial.println(F("E: Cannot open main dir from SD.")); + Serial.println(F("E : SysEx file size wrong.")); #endif return (false); } - while (42 == 42) + if (sysex.read() != 0xf0) // check sysex start-byte { - File entry = root.openNextFile(); - if (!entry) +#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(4102); // Bulk checksum + bulk_checksum = sysex.read(); + + sysex.seek(6); // start of bulk data + + for (uint16_t n = 0; n < 4096; n++) + { + uint8_t d = sysex.read(); + + if ((n % 128) >= 118 && (n % 128) < 128) // found the start of the voicename { - // No more files - break; + voice_names[voice_counter][(n % 128) - 118] = d; } - else + if (n % 128 == 127) + voice_counter++; + bulk_checksum_calc -= d; + } + bulk_checksum_calc &= 0x7f; + +#ifdef DEBUG + Serial.print(F("Bulk checksum : 0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.print(F(" [0x")); + Serial.print(bulk_checksum, HEX); + Serial.println(F("]")); +#endif + + if (bulk_checksum_calc != bulk_checksum) + { +#ifdef DEBUG + Serial.print(F("E : Bulk checksum mismatch : 0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.print(F(" != 0x")); + Serial.println(bulk_checksum, HEX); +#endif + return (false); + } + } + else + return (false); +} + +uint8_t get_bank_names(void) +{ + File root; + uint8_t bank_counter = 0; + + // erase all data for bank names + memset(bank_names, 0, MAX_BANKS * BANK_NAME_LEN); + + if (sd_card_available) + { + char bankdir[4]; + + do + { + // init and set name for actual bank directory + memset(bankdir, 0, sizeof(bankdir)); + bankdir[0] = '/'; + itoa(bank_counter, &bankdir[1], 10); + + // try to open directory + root = SD.open(bankdir); + if (!root) + break; + + // read filenames + File entry = root.openNextFile(); + if (!entry.isDirectory()) { - if (!entry.isDirectory()) - { - char *token; - uint8_t data[128]; - - if (get_sysex_voice(bankdir, entry, v, data)) - strncpy(voice_name, (char*)&data[118], 10); - else - strcpy(voice_name, "*ERROR*"); - - token = strtok(entry.name(), "."); - if (token == NULL) - strcpy(bank_name, "*ERROR*"); - else - strcpy(bank_name, token); - - return (true); - } + strcpy(bank_names[bank_counter], entry.name()); +#ifdef DEBUG + Serial.print(F("Found bank [")); + Serial.print(bank_names[bank_counter]); + Serial.println(F("]")); +#endif + bank_counter++; } - } + } while (root); + + return (bank_counter); } - return (false); + else + return (bank_counter); } bool load_sysex(uint8_t b, uint8_t v) { - File root; bool found = false; v %= MAX_VOICES; @@ -97,170 +226,126 @@ bool load_sysex(uint8_t b, uint8_t v) if (sd_card_available) { - char bankdir[4]; + File sysex; + char sysex_file_name[4 + VOICE_NAME_LEN]; + uint8_t data[128]; - memset(bankdir, 0, sizeof(bankdir)); - bankdir[0] = '/'; - itoa(b, &bankdir[1], 10); + create_sysex_filename(b, sysex_file_name); - root = SD.open(bankdir); - if (!root) + sysex = SD.open(sysex_file_name); + if (!sysex) { #ifdef DEBUG - Serial.println(F("E: Cannot open main dir from SD.")); + Serial.print(F("E : Cannot open ")); + Serial.print(sysex_file_name); + Serial.println(F("from SD.")); #endif return (false); } - while (42 == 42) + + if (get_sysex_voice(sysex, v, data)) { - File entry = root.openNextFile(); - if (!entry) - { - // No more files - break; - } - else - { - if (!entry.isDirectory()) - { - uint8_t data[128]; - found = true; - if (get_sysex_voice(bankdir, entry, v, data)) - { #ifdef DEBUG - char n[11]; - - strncpy(n, (char*)&data[118], 10); - Serial.print("Loading sysex "); - Serial.print(bankdir); - Serial.print("/"); - Serial.print(entry.name()); - Serial.print(F(" [")); - Serial.print(n); - Serial.println(F("]")); - + char n[11]; + + strncpy(n, (char*)&data[118], 10); + Serial.print("Loading sysex "); + Serial.print(sysex_file_name); + Serial.print(F(" [")); + Serial.print(voice_names[v]); + Serial.println(F(" [")); #endif - char *token; - - token = strtok(entry.name(), "."); - if (token != NULL) - strcpy(bank_name, token); - else - strcpy(bank_name, "*ERROR*"); - - return (dexed->loadSysexVoice(data)); - } - else + return (dexed->loadSysexVoice(data)); + } + else #ifdef DEBUG - Serial.println(F("E: Cannot load voice data")); + Serial.println(F("E : Cannot load voice data")); #endif - entry.close(); - break; - } - } - } } - #ifdef DEBUG if (found == false) - Serial.println(F("E: File not found.")); + Serial.println(F("E : File not found.")); #endif return (false); } -bool get_sysex_voice(char* dir, File sysex, uint8_t voice_number, uint8_t* data) +bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data) { - File file; uint16_t n; int32_t bulk_checksum_calc = 0; int8_t bulk_checksum; - char sysex_file[20]; - - strcpy(sysex_file, dir); - strcat(sysex_file, "/"); - strcat(sysex_file, sysex.name()); if (sysex.size() != 4104) // check sysex size { #ifdef DEBUG - Serial.println(F("E: SysEx file size wrong.")); + Serial.println(F("E : SysEx file size wrong.")); #endif return (false); } - if (file = SD.open(sysex_file)) + if (sysex.read() != 0xf0) // check sysex start-byte { - if (file.read() != 0xf0) // check sysex start-byte - { #ifdef DEBUG - Serial.println(F("E: SysEx start byte not found.")); + Serial.println(F("E : SysEx start byte not found.")); #endif - return (false); - } - if (file.read() != 0x43) // check sysex vendor is Yamaha - { + return (false); + } + if (sysex.read() != 0x43) // check sysex vendor is Yamaha + { #ifdef DEBUG - Serial.println(F("E: SysEx vendor not Yamaha.")); + Serial.println(F("E : SysEx vendor not Yamaha.")); #endif - return (false); - } - file.seek(4103); - if (file.read() != 0xf7) // check sysex end-byte - { + return (false); + } + sysex.seek(4103); + if (sysex.read() != 0xf7) // check sysex end-byte + { #ifdef DEBUG - Serial.println(F("E: SysEx end byte not found.")); + Serial.println(F("E : SysEx end byte not found.")); #endif - return (false); - } - file.seek(3); - if (file.read() != 0x09) // check for sysex type (0x09=32 voices) - { + 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.")); + Serial.println(F("E : SysEx type not 32 voices.")); #endif - return (false); - } - file.seek(4102); // Bulk checksum - bulk_checksum = file.read(); + return (false); + } + sysex.seek(4102); // Bulk checksum + bulk_checksum = sysex.read(); - file.seek(6); // start of bulk data - for (n = 0; n < 4096; n++) + sysex.seek(6); // start of bulk data + for (n = 0; n < 4096; n++) + { + uint8_t d = sysex.read(); + if (n >= voice_number * 128 && n < (voice_number + 1) * 128) { - uint8_t d = file.read(); - if (n >= voice_number * 128 && n < (voice_number + 1) * 128) - { - data[n - (voice_number * 128)] = d; - } - bulk_checksum_calc -= d; + data[n - (voice_number * 128)] = d; } - bulk_checksum_calc &= 0x7f; + bulk_checksum_calc -= d; + } + bulk_checksum_calc &= 0x7f; #ifdef DEBUG - Serial.print(F("Bulk checksum: 0x")); - Serial.print(bulk_checksum_calc, HEX); - Serial.print(F(" [0x")); - Serial.print(bulk_checksum, HEX); - Serial.println(F("]")); + Serial.print(F("Bulk checksum : 0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.print(F(" [0x")); + Serial.print(bulk_checksum, HEX); + Serial.println(F("]")); #endif - if (bulk_checksum_calc != bulk_checksum) - { + if (bulk_checksum_calc != bulk_checksum) + { #ifdef DEBUG - Serial.print(F("E: Bulk checksum mismatch: 0x")); - Serial.print(bulk_checksum_calc, HEX); - Serial.print(F(" != 0x")); - Serial.println(bulk_checksum, HEX); + Serial.print(F("E : Bulk checksum mismatch : 0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.print(F(" != 0x")); + Serial.println(bulk_checksum, HEX); #endif - return (false); - } - } -#ifdef DEBUG - else - { - Serial.print(F("Cannot open ")); - Serial.println(sysex.name()); + return (false); } -#endif render_time_max = 0; diff --git a/dexed_sysex.h b/dexed_sysex.h index 2acf7df..d0d771f 100644 --- a/dexed_sysex.h +++ b/dexed_sysex.h @@ -33,13 +33,19 @@ extern Dexed* dexed; extern uint16_t render_time_max; extern uint8_t bank; extern uint8_t voice; -extern char bank_name[11]; -extern char voice_name[11]; +extern char bank_name[BANK_NAME_LEN]; +extern char voice_name[VOICE_NAME_LEN]; +extern char bank_names[MAX_BANKS][BANK_NAME_LEN]; +extern char voice_names[MAX_VOICES][VOICE_NAME_LEN]; extern uint8_t ui_state; extern uint8_t ui_main_state; +void create_sysex_filename(uint8_t b, char* sysex_file_name); +void strip_extension(char* s, char *target); +bool get_voice_names_from_bank(uint8_t b); +uint8_t get_bank_names(void); bool get_bank_voice_name(uint8_t b, uint8_t v); bool load_sysex(uint8_t b, uint8_t v); -bool get_sysex_voice(char* dir, File sysex, uint8_t voice_number, uint8_t* data); +bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data); #endif