|
|
|
@ -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; |
|
|
|
|
|
|
|
|
|