Reoganized SD card read/write.

Added reading and writing of dexed-configurations.
pull/32/head
Holger Wirtz 4 years ago
parent eeaf8b6f46
commit 448b3c4bd8
  1. 6
      MicroDexed.ino
  2. 11
      UI.hpp
  3. 7
      config.h
  4. 572
      dexed_sd.cpp
  5. 21
      dexed_sd.h
  6. 77
      doc/sysex-format_dexed-setup.txt

@ -32,7 +32,7 @@
#include <SPI.h>
#include "midi_devices.hpp"
#include "dexed.h"
#include "dexed_sysex.h"
#include "dexed_sd.h"
#include "effect_modulated_delay.h"
#include "effect_stereo_mono.h"
#include "effect_mono_stereo.h"
@ -413,7 +413,7 @@ void setup()
#endif
// load default SYSEX data
load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
}
}
@ -872,7 +872,7 @@ void handleProgramChange(byte inChannel, byte inProgram)
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.dexed[instance_id].bank, inProgram, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, inProgram, instance_id);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
#endif

@ -558,6 +558,7 @@ void lcdml_menu_control(void)
LCDML.FUNC_setGBAToLastFunc();
else
LCDML.FUNC_setGBAToLastCursorPos();
//LCDML.FUNC_setGBA();
LCDML.OTHER_jumpToFunc(UI_func_voice_select);
}
@ -3048,7 +3049,7 @@ void UI_func_voice_select(uint8_t param)
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
@ -3073,7 +3074,7 @@ void UI_func_voice_select(uint8_t param)
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
@ -3091,7 +3092,7 @@ void UI_func_voice_select(uint8_t param)
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
@ -3115,7 +3116,7 @@ void UI_func_voice_select(uint8_t param)
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
@ -3360,7 +3361,7 @@ void UI_func_save_config(uint8_t param)
LCDML.DISP_clear();
lcd.print(F("Storing config"));
save_sysex_config(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
save_sd_voiceconfig(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
lcd.setCursor(0, 1);
lcd.print(F("Done."));

@ -224,6 +224,7 @@
#define BANK_NAME_LEN 13 // FAT12 filenames (plus '\0')
#define VOICE_NAME_LEN 11 // 10 (plus '\0')
#define FILENAME_LEN BANK_NAME_LEN + VOICE_NAME_LEN
#define VOICE_CONFIG_NAME "VCFG"
//*************************************************************************************************
//* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!!
@ -502,9 +503,6 @@ enum { DEXED, CHORUS, DELAY, REVERB};
//
typedef struct {
uint8_t midi_channel;
uint8_t bank;
uint8_t voice;
uint8_t lowest_note;
uint8_t highest_note;
uint8_t reverb_send;
@ -539,6 +537,9 @@ typedef struct {
uint8_t portamento_glissando;
uint8_t portamento_time;
uint8_t op_enabled;
uint8_t midi_channel;
uint8_t bank;
uint8_t voice;
} dexed_t;
// struct for holding the current configuration

@ -28,220 +28,13 @@
#include <Wire.h>
#include <SD.h>
#include "dexed.h"
#include "dexed_sysex.h"
#include "dexed_sd.h"
extern AudioSourceMicroDexed * MicroDexed[NUM_DEXED];
extern void show_patch(uint8_t instance_id);
/******************************************************************************
SD BANK/VOICE LOADING
******************************************************************************/
/*
void create_sysex_filename(uint8_t b, char* sysex_file_name, uint8_t instance_id)
{
// 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[instance_id][b]);
#ifdef DEBUG
Serial.print(F("Created sysex_filename from bank "));
Serial.print(b, DEC);
Serial.print(F(" and name "));
Serial.print(bank_names[instance_id][b]);
Serial.print(F(": ["));
Serial.print(sysex_file_name);
Serial.println(F("]"));
#endif
}
*/
void create_sysex_bankfilename(char* filename, uint8_t b, uint8_t instance_id)
{
// init and set name for actual bank
memset(filename, 0, FILENAME_LEN);
sprintf(filename, "/%d/%s", b, bank_names[instance_id][b]);
#ifdef DEBUG
Serial.print(F("Created sysex_filename from bank "));
Serial.print(b, DEC);
Serial.print(F(" and name "));
Serial.print(bank_names[instance_id][b]);
Serial.print(F(": ["));
Serial.print(filename);
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, uint8_t instance_id)
{
File sysex;
uint8_t voice_counter = 0;
int32_t bulk_checksum_calc = 0;
int8_t bulk_checksum;
b = constrain(b, 0, MAX_BANKS - 1);
// erase all data for voice names
memset(voice_names[instance_id], 0, MAX_VOICES * VOICE_NAME_LEN);
if (sd_card > 0)
{
char sysex_file_name[FILENAME_LEN];
// init and set name for actual bank
create_sysex_bankfilename(sysex_file_name, b, instance_id);
#ifdef DEBUG
Serial.print(F("Reading voice names for bank ["));
Serial.print(sysex_file_name);
Serial.println(F("]"));
#endif
// 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 : 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(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
{
voice_names[instance_id][voice_counter][(n % 128) - 118] = d;
}
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);
}
}
return (false);
}
uint8_t get_bank_names(uint8_t instance_id)
{
File root;
uint8_t bank_counter = 0;
// erase all data for bank names
memset(bank_names[instance_id], 0, MAX_BANKS * BANK_NAME_LEN);
if (sd_card > 0)
{
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())
{
while (strncmp(entry.name(), "CONFIG", 6) == 0)
{
entry = root.openNextFile();
}
strcpy(bank_names[instance_id][bank_counter], entry.name());
#ifdef DEBUG
Serial.print(F("Found bank ["));
Serial.print(bank_names[instance_id][bank_counter]);
Serial.println(F("]"));
#endif
bank_counter++;
}
} while (root);
return (bank_counter);
}
else
return (0);
}
bool load_sysex(uint8_t b, uint8_t v, uint8_t instance_id)
bool load_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id)
{
#if DEBUG
bool found = false;
@ -252,27 +45,27 @@ bool load_sysex(uint8_t b, uint8_t v, uint8_t instance_id)
if (sd_card > 0)
{
File sysex;
char sysex_file_name[FILENAME_LEN];
char filename[FILENAME_LEN];
uint8_t data[128];
create_sysex_bankfilename(sysex_file_name, b, instance_id);
sprintf(filename, "/%d/%s", b, bank_names[instance_id][b]);
sysex = SD.open(sysex_file_name);
sysex = SD.open(filename);
if (!sysex)
{
#ifdef DEBUG
Serial.print(F("E : Cannot open "));
Serial.print(sysex_file_name);
Serial.println(F("from SD."));
Serial.print(filename);
Serial.println(F(" on SD."));
#endif
return (false);
}
if (get_sysex_voice(sysex, v, data))
if (get_sd_voice(sysex, v, data))
{
#ifdef DEBUG
Serial.print(F("Loading sysex "));
Serial.print(sysex_file_name);
Serial.print(F("Loading voice from "));
Serial.print(filename);
Serial.print(F(" ["));
Serial.print(voice_names[instance_id][v]);
Serial.println(F("]"));
@ -282,6 +75,9 @@ bool load_sysex(uint8_t b, uint8_t v, uint8_t instance_id)
show_patch(instance_id);
#endif
configuration.dexed[instance_id].transpose = MicroDexed[instance_id]->data[DEXED_VOICE_OFFSET + DEXED_TRANSPOSE];
load_sd_voiceconfig(b, v, instance_id); // check for coice config to load
return (ret);
}
#ifdef DEBUG
@ -297,7 +93,7 @@ bool load_sysex(uint8_t b, uint8_t v, uint8_t instance_id)
return (false);
}
bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data)
bool get_sd_voice(File sysex, uint8_t voice_number, uint8_t* data)
{
uint16_t n;
int32_t bulk_checksum_calc = 0;
@ -348,9 +144,7 @@ bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data)
{
uint8_t d = sysex.read();
if (n >= voice_number * 128 && n < (voice_number + 1) * 128)
{
data[n - (voice_number * 128)] = d;
}
bulk_checksum_calc -= d;
}
bulk_checksum_calc &= 0x7f;
@ -379,41 +173,57 @@ bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data)
return (true);
}
bool write_sysex_config(File sysex, config_t configuration)
/******************************************************************************
SD VOICE CONFIG
******************************************************************************/
bool load_sd_voiceconfig(uint8_t b, uint8_t v, uint8_t instance_id)
{
uint16_t n;
char* c = (char*)&configuration;
// write sysex start
sysex.write(0xf0);
// write sysex vendor is unofficial SYSEX-ID for MicroDexed
sysex.write(0x67);
// write sysex format number (f=66..69; 1..4 MicroDexed setup(s))
sysex.write(0x66);
if (sd_card > 0)
{
File sysex;
char filename[FILENAME_LEN];
// write configuration data
for (n = 0; n < sizeof(configuration); n++)
sysex.write(c + n);
sprintf(filename, "/%d/%s%d.syx", b, VOICE_CONFIG_NAME, v);
// write sysex end
sysex.write(0xf7);
// first check if file exists...
if (SD.exists(filename))
{
// ... and if: load
#ifdef DEBUG
Serial.print(F("Found voice configuration ["));
Serial.print(filename);
Serial.println(F("]... loading..."));
#endif
sysex = SD.open(filename);
if (!sysex)
{
#ifdef DEBUG
Serial.print(F("E : Cannot open "));
Serial.print(filename);
Serial.println(F(" on SD."));
#endif
return (get_sd_voiceconfig(sysex, (uint8_t*)&configuration.dexed[instance_id]));
}
}
else
{
#ifdef DEBUG
Serial.print(F("No "));
Serial.print(filename);
Serial.println(F(" available."));
#endif
}
}
return (true);
return (false);
}
bool read_sysex_config(File sysex, config_t configuration)
bool get_sd_voiceconfig(File sysex, uint8_t* conf)
{
uint16_t n;
int32_t bulk_checksum_calc = 0;
int8_t bulk_checksum;
if (sysex.size() != 47 || sysex.size() != 78) // 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
@ -428,36 +238,31 @@ bool read_sysex_config(File sysex, config_t configuration)
#endif
return (false);
}
sysex.seek(sysex.size());
if (sysex.read() != 0xf7) // check sysex end-byte
if (sysex.read() != 0x42) // check for sysex type (66 = MicroDexed voice setup)
{
#ifdef DEBUG
Serial.println(F("E : SysEx end byte not found."));
Serial.println(F("E : SysEx type not MicroDexed setup."));
#endif
return (false);
}
sysex.seek(3);
uint8_t dexed_sysex_setup_type = sysex.read();
if (dexed_sysex_setup_type >= 0x42 && dexed_sysex_setup_type < 0x45) // check for sysex type (0x75=MicroDexed setup for one to four instances)
sysex.seek(sysex.size());
if (sysex.read() != 0xf7) // check sysex end-byte
{
#ifdef DEBUG
Serial.println(F("E : SysEx type not MicroDexed setup."));
Serial.println(F("E : SysEx end byte not found."));
#endif
return (false);
}
sysex.seek(4);
uint8_t sysex_config_size = sysex.read();
sysex.seek(sysex.size() - 1); // Bulk checksum
bulk_checksum = sysex.read();
sysex.seek(6); // start of bulk data
for (n = 0; n < sysex.size() - 2; n++)
sysex.seek(3); // start of bulk data
for (n = 0; n < sysex.size() - 3; n++)
{
uint8_t d = sysex.read();
bulk_checksum_calc -= d;
*conf++ = d;
}
bulk_checksum_calc &= 0x7f;
@ -479,26 +284,15 @@ bool read_sysex_config(File sysex, config_t configuration)
#endif
return (false);
}
// Now everything is ok and we can read the data
sysex.seek(6); // start of bulk data
uint8_t* conf = (uint8_t*)&configuration + 4;
for (n = 0; n < sysex_config_size; n++)
{
uint8_t d = sysex.read();
#ifdef DEBUG
Serial.print(n + 6, DEC);
Serial.print(F("="));
Serial.println(d);
Serial.println(F("Voice config loaded."));
#endif
*(conf + n) = d;
}
configuration.checksum = crc32((uint8_t*)&configuration + 4, sizeof(configuration) - 4);
return (true);
}
bool save_sysex_config(uint8_t b, uint8_t v, uint8_t instance_id)
bool save_sd_voiceconfig(uint8_t b, uint8_t v, uint8_t instance_id)
{
v = constrain(v, 0, MAX_VOICES - 1);
b = constrain(b, 0, MAX_BANKS - 1);
@ -506,12 +300,12 @@ bool save_sysex_config(uint8_t b, uint8_t v, uint8_t instance_id)
if (sd_card > 0)
{
File sysex;
char sysex_config_filename[FILENAME_LEN];
char filename[FILENAME_LEN];
sprintf(sysex_config_filename, "/%d/config%d.syx", b, v);
sprintf(filename, "/%d/%s%d.syx", b, VOICE_CONFIG_NAME, v);
#ifdef DEBUG
Serial.print(F("saving config "));
Serial.print(F("Saving config "));
Serial.print(b);
Serial.print(F("/"));
Serial.print(v);
@ -519,30 +313,246 @@ bool save_sysex_config(uint8_t b, uint8_t v, uint8_t instance_id)
Serial.print(instance_id);
Serial.print(F("]"));
Serial.print(F(" to "));
Serial.println(sysex_config_filename);
Serial.println(filename);
#endif
sysex = SD.open(sysex_config_filename, FILE_WRITE);
sysex = SD.open(filename, FILE_WRITE);
if (!sysex)
{
#ifdef DEBUG
Serial.print(F("E : Cannot open "));
Serial.print(sysex_config_filename);
Serial.print(filename);
Serial.println(F(" on SD."));
#endif
return (false);
}
if (write_sysex_config(sysex, configuration))
if (write_sd_voiceconfig(sysex, (uint8_t*)&configuration.dexed[instance_id], sizeof(configuration.dexed[instance_id])))
{
sysex.close();
return (true);
}
#ifdef DEBUG
else
Serial.println(F("E : Cannot load setup data"));
Serial.println(F("E : Cannot save voice data"));
#endif
}
return (false);
}
bool write_sd_voiceconfig(File sysex, uint8_t* data, uint16_t len)
{
// write sysex start
sysex.write(0xf0);
// write sysex vendor is unofficial SYSEX-ID for MicroDexed
sysex.write(0x67);
// write sysex format number (f=66 MicroDexed voice config)
sysex.write(0x42);
// write data
sysex.write(data, len - 2); // minus 2 because at the end of the struct are voice and ban number - not very interesting here...
// write checksum
sysex.write(calc_checksum(data, len - 2));
// write sysex end
sysex.write(0xf7);
return (true);
}
/******************************************************************************
HELPER FUNCTIONS
******************************************************************************/
uint8_t calc_checksum(uint8_t* data, uint16_t len)
{
int32_t bulk_checksum_calc = 0;
for (uint16_t n = 0; n < len; n++)
bulk_checksum_calc -= data[n];
return (bulk_checksum_calc & 0x7f);
}
void create_sd_voiceconfig_filename(char* filename, uint8_t b, uint8_t instance_id)
{
// init and set name for actual bank
memset(filename, 0, FILENAME_LEN);
sprintf(filename, "/%d/%s", b, bank_names[instance_id][b]);
#ifdef DEBUG
Serial.print(F("Created filename from bank "));
Serial.print(b, DEC);
Serial.print(F(" and name "));
Serial.print(bank_names[instance_id][b]);
Serial.print(F(": ["));
Serial.print(filename);
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, uint8_t instance_id)
{
File sysex;
uint8_t voice_counter = 0;
int32_t bulk_checksum_calc = 0;
int8_t bulk_checksum;
b = constrain(b, 0, MAX_BANKS - 1);
// erase all data for voice names
memset(voice_names[instance_id], 0, MAX_VOICES * VOICE_NAME_LEN);
if (sd_card > 0)
{
char filename[FILENAME_LEN];
sprintf(filename, "/%d/%s", b, bank_names[instance_id][b]);
#ifdef DEBUG
Serial.print(F("Reading voice names for bank ["));
Serial.print(filename);
Serial.println(F("]"));
#endif
// try to open bank directory
sysex = SD.open(filename);
if (!sysex)
return (false);
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(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
{
voice_names[instance_id][voice_counter][(n % 128) - 118] = d;
}
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);
}
}
return (false);
}
uint8_t get_bank_names(uint8_t instance_id)
{
File root;
uint8_t bank_counter = 0;
// erase all data for bank names
memset(bank_names[instance_id], 0, MAX_BANKS * BANK_NAME_LEN);
if (sd_card > 0)
{
char bankdir[4];
do
{
// init and set name for actual bank directory
sprintf(bankdir, "/%d", bank_counter);
// try to open directory
root = SD.open(bankdir);
if (!root)
break;
// read filenames
File entry = root.openNextFile();
if (!entry.isDirectory())
{
while ((strncmp(entry.name(), VOICE_CONFIG_NAME, sizeof(VOICE_CONFIG_NAME) - 1) == 0))
{
entry = root.openNextFile();
}
strcpy(bank_names[instance_id][bank_counter], entry.name());
#ifdef DEBUG
Serial.print(F("Found bank ["));
Serial.print(bank_names[instance_id][bank_counter]);
Serial.println(F("]"));
#endif
bank_counter++;
}
} while (root);
return (bank_counter);
}
else
return (0);
}

@ -32,7 +32,8 @@
extern uint8_t sd_card;
extern Dexed* dexed;
extern AudioSourceMicroDexed * MicroDexed[NUM_DEXED];
//extern uint16_t render_time_max;
extern void show_patch(uint8_t instance_id);
extern uint8_t bank;
extern uint8_t voice;
extern char bank_name[NUM_DEXED][BANK_NAME_LEN];
@ -44,16 +45,16 @@ extern uint8_t ui_main_state;
extern config_t configuration;
extern uint32_t crc32(byte * calc_start, uint16_t calc_bytes);
void create_sysex_bankfilename(char* filename, uint8_t b, uint8_t instance_id);
bool load_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 load_sd_voiceconfig(uint8_t b, uint8_t v, uint8_t instance_id);
bool get_sd_voiceconfig(File sysex, uint8_t* conf);
bool save_sd_voiceconfig(uint8_t b, uint8_t v, uint8_t instance_id);
bool write_sd_voiceconfig(File sysex, uint8_t* data, uint16_t len);
uint8_t calc_checksum(uint8_t* data, uint16_t len);
void strip_extension(char* s, char *target);
bool get_voice_names_from_bank(uint8_t b, uint8_t i);
uint8_t get_bank_names(uint8_t instance_id);
bool get_bank_voice_name(uint8_t b, uint8_t v);
bool load_sysex(uint8_t b, uint8_t v, uint8_t instance_id);
bool get_sysex_voice(File sysex, uint8_t voice_number, uint8_t* data);
void create_sysex_setup_filename(uint8_t b, uint8_t v, char* sysex_setup_file_name);
bool write_sysex_config(File sysex, config_t configuration);
bool load_sysex_config(uint8_t b, uint8_t v, uint8_t instance_id);
bool save_sysex_config(uint8_t b, uint8_t v, uint8_t instance_id);
#endif

@ -6,53 +6,54 @@ SYSEX Message Controller-Set
11110000 F0 Status byte - start sysex
0iiiiiii 67 ID # (i=103; unofficial SYSEX-ID for MicroDexed)
0fffffff ** format number (f=66 MicroDexed config)
0fffffff ** format number (f=66 MicroDexed voice config)
0ddddddd ** data byte 1 setup config
| | |
0ddddddd ** data byte 13
0ddddddd ** data byte 14 instance config 0
| | |
0ddddddd ** data byte 44
0ddddddd ** data byte 35
0eeeeeee ** checksum (masked 2's complement of sum of 155 bytes)
11110111 F7 Status - end sysex
Data Structure: MicroDexed Setup Dump
-------------------------------------
Number Parameter Value Range
--------- --------- -----------
11 DEXED 1 MIDI-CHANNEL 0-16 (0=OMNI)
12 DEXED 1 BANK 0-99
13 DEXED 1 VOICE 0-31
14 DEXED 1 LOWEST NOTE 21-108
15 DEXED 1 HIGHEST NOTE 21-108
16 DEXED 1 REVERB SEND 0-100
17 DEXED 1 CHORUS SEND 0-100
18 DEXED 1 DELAY SEND 0-100
19 DEXED 2 FILTER-CUTOFF 0-100
20 DEXED 2 FILTER-RESONANCE 0-100
21 DEXED 2 TRANSPOSE 0-48
22 DEXED 2 TUNE 0-100
23 DEXED 2 SOUND INTENSITY 0-100
24 DEXED 2 PANORAMA 0-40 (20 is middle)
25 DEXED 1 POLYPHONY 0-32 (depends on CPU and FX)
26 DEXED 1 ENGINE 0-2 (1=Modern, 2=Mark1, 2=OPL)
27 DEXED 1 MONO/POLY MODE CHANGE 0-1 O=POLY
28 DEXED 1 PITCH BEND RANGE 0-12
29 DEXED 1 " " STEP 0-12
30 DEXED 1 MOD WHEEL RANGE 0-99
31 DEXED 1 " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias
32 DEXED 1 FOOT CONTROL RANGE 0-99
33 DEXED 1 " " ASSIGN 0-7 "
34 DEXED 1 BREATH CONT RANGE 0-99
35 DEXED 1 " " ASSIGN 0-7 "
36 DEXED 1 AFTERTOUCH RANGE 0-99
37 DEXED 1 " ASSIGN 0-7 "
38 DEXED 1 PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW
39 DEXED 1 " GLISS 0-1
40 DEXED 1 " TIME 0-99
41 DEXED 1 OP_ENABLE 0-31
01 DEXED LOWEST NOTE 21-108
02 DEXED HIGHEST NOTE 21-108
03 DEXED REVERB SEND 0-100
04 DEXED CHORUS SEND 0-100
05 DEXED DELAY SEND 0-100
06 DEXED FILTER-CUTOFF 0-100
07 DEXED FILTER-RESONANCE 0-100
08 DEXED TRANSPOSE 0-48
09 DEXED TUNE 0-100
10 DEXED SOUND INTENSITY 0-100
11 DEXED PANORAMA 0-40 (20 is middle)
12 DEXED POLYPHONY 0-32 (depends on CPU and FX)
13 DEXED VELOCITY LEVEL 100-127
14 DEXED ENGINE 0-2 1=Modern, 2=Mark1, 2=OPL
15 DEXED MONO/POLY MODE CHANGE 0-1 O=POLY
16 DEXED NOTE REFRESH MODE 0-2
17 DEXED PITCH BEND RANGE 0-12
18 DEXED " " STEP 0-12
19 DEXED MOD WHEEL RANGE 0-99
20 DEXED " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias
21 DEXED " " MODE 0-2 1=linear, 2=reverse, 3=direct
22 DEXED FOOT CONTROL RANGE 0-99
23 DEXED " " ASSIGN 0-7 "
24 DEXED " " MODE 0-2 1=linear, 2=reverse, 3=direct
25 DEXED BREATH CONT RANGE 0-99
26 DEXED " " ASSIGN 0-7 "
27 DEXED " " MODE 0-2 1=linear, 2=reverse, 3=direct
28 DEXED AFTERTOUCH RANGE 0-99
29 DEXED " ASSIGN 0-7 "
30 DEXED " MODE 0-2 1=linear, 2=reverse, 3=direct
31 DEXED PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW
32 DEXED " GLISS 0-1
33 DEXED " TIME 0-99
34 DEXED OP_ENABLE 0-31
35 DEXED MIDI-CHANNEL 0-16 0=OMNI
---------
Number Parameter Value Range

Loading…
Cancel
Save