diff --git a/MicroDexed.ino b/MicroDexed.ino index 255951e..8a49bb5 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -1328,8 +1328,6 @@ void initial_values_from_eeprom(bool init) void check_configuration(void) { configuration.instances = constrain(configuration.instances, INSTANCES_MIN, INSTANCES_MAX); - configuration.instance_mode = constrain(configuration.instance_mode, INSTANCE_MODE_MIN, INSTANCE_MODE_MAX); - configuration.instance_splitpoint = constrain(configuration.instance_splitpoint, INSTANCE_SPLITPOINT_MAX, INSTANCE_SPLITPOINT_MAX); configuration.vol = constrain(configuration.vol, VOLUME_MIN, VOLUME_MAX); configuration.mono = constrain(configuration.mono, MONO_MIN, MONO_MAX); configuration.reverb_roomsize = constrain(configuration.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); @@ -1347,6 +1345,8 @@ void check_configuration(void) configuration.dexed[instance_id].midi_channel = constrain(configuration.dexed[instance_id].midi_channel, MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); configuration.dexed[instance_id].bank = constrain(configuration.dexed[instance_id].bank, 0, MAX_BANKS - 1); configuration.dexed[instance_id].voice = constrain(configuration.dexed[instance_id].voice, 0, MAX_VOICES - 1); + configuration.dexed[instance_id].lowest_note = constrain(configuration.dexed[instance_id].lowest_note, INSTANCE_LOWEST_NOTE_MIN, INSTANCE_LOWEST_NOTE_MAX); + configuration.dexed[instance_id].highest_note = constrain(configuration.dexed[instance_id].highest_note, INSTANCE_HIGHEST_NOTE_MIN, INSTANCE_HIGHEST_NOTE_MAX); configuration.dexed[instance_id].reverb_send = constrain(configuration.dexed[instance_id].reverb_send, REVERB_SEND_MIN, REVERB_SEND_MAX); configuration.dexed[instance_id].chorus_send = constrain(configuration.dexed[instance_id].chorus_send, CHORUS_SEND_MIN, CHORUS_SEND_MAX); configuration.dexed[instance_id].delay_send = constrain(configuration.dexed[instance_id].delay_send, DELAY_SEND_MIN, DELAY_SEND_MAX); @@ -1389,8 +1389,6 @@ void init_configuration(void) configuration.checksum = 0xffff; configuration.instances = INSTANCES_DEFAULT; - configuration.instance_mode = INSTANCE_MODE_DEFAULT; - configuration.instance_splitpoint = INSTANCE_SPLITPOINT_DEFAULT; configuration.vol = VOLUME_DEFAULT; configuration.mono = MONO_DEFAULT; configuration.reverb_roomsize = REVERB_ROOMSIZE_DEFAULT; diff --git a/config.h b/config.h index ae017ac..11538d7 100644 --- a/config.h +++ b/config.h @@ -290,6 +290,14 @@ enum { DEXED, CHORUS, DELAY, REVERB}; #define MIDI_CHANNEL_MAX 16 #define MIDI_CHANNEL_DEFAULT MIDI_CHANNEL_OMNI +#define INSTANCE_LOWEST_NOTE_MIN 21 +#define INSTANCE_LOWEST_NOTE_MAX 108 +#define INSTANCE_LOWEST_NOTE_DEFAULT 21 + +#define INSTANCE_HIGHEST_NOTE_MIN 21 +#define INSTANCE_HIGHEST_NOTE_MAX 108 +#define INSTANCE_HIGHEST_NOTE_DEFAULT 108 + #define REVERB_ROOMSIZE_MIN 0 #define REVERB_ROOMSIZE_MAX 100 #define REVERB_ROOMSIZE_DEFAULT 0 @@ -438,15 +446,13 @@ enum { DEXED, CHORUS, DELAY, REVERB}; #define INSTANCE_MODE_MAX 1 #define INSTANCE_MODE_DEFAULT 0 -#define INSTANCE_SPLITPOINT_MIN MIDI_AIS0 -#define INSTANCE_SPLITPOINT_MAX MIDI_B7 -#define INSTANCE_SPLITPOINT_DEFAULT MIDI_C3 - // typedef struct { uint8_t midi_channel; uint8_t bank; uint8_t voice; + uint8_t lowest_note; + uint8_t highest_note; uint8_t reverb_send; uint8_t chorus_send; uint8_t delay_send; @@ -479,8 +485,6 @@ typedef struct { typedef struct { uint32_t checksum; uint8_t instances; - uint8_t instance_mode; - uint8_t instance_splitpoint; uint8_t vol; uint8_t mono; uint8_t reverb_roomsize; diff --git a/dexed_sysex.cpp b/dexed_sysex.cpp index 3d0c5fe..0749f04 100644 --- a/dexed_sysex.cpp +++ b/dexed_sysex.cpp @@ -408,6 +408,7 @@ bool get_sysex_setup(File sysex, config_t configuration) #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) @@ -417,6 +418,10 @@ bool get_sysex_setup(File sysex, config_t configuration) #endif return (false); } + + sysex.seek(4); + uint8_t sysex_config_size = sysex.read(); + sysex.seek(sysex.size() - 1); // Bulk checksum bulk_checksum = sysex.read(); @@ -424,11 +429,6 @@ bool get_sysex_setup(File sysex, config_t configuration) for (n = 0; n < sysex.size() - 2; n++) { uint8_t d = sysex.read(); -#ifdef DEBUG - Serial.print(n + 6, DEC); - Serial.print(F("=")); - Serial.println(d); -#endif bulk_checksum_calc -= d; } bulk_checksum_calc &= 0x7f; @@ -452,6 +452,21 @@ bool get_sysex_setup(File sysex, config_t configuration) 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); +#endif + *(conf + n) = d; + } + configuration.checksum = crc32((uint8_t*)&configuration + 4, sizeof(configuration) - 4); + return (true); } @@ -504,3 +519,29 @@ bool load_sysex_setup(uint8_t b, uint8_t v, uint8_t instance_id) return (false); } + +bool save_sysex_setup(uint8_t b, uint8_t v, config_t configuration) +{ + const char* sysex_filename = "config.syx"; + + if (sd_card_available) + { + File sysex; + char sysex_file_name[20]; + + create_sysex_filename(b, sysex_file_name, v); + + sysex = SD.create(sysex_file_name); + if (!sysex) + { +#ifdef DEBUG + Serial.print(F("E : Cannot create ")); + Serial.print(sysex_file_name); + Serial.println(F("on SD.")); +#endif + return (false); + } + } + + return (false); +} diff --git a/dexed_sysex.h b/dexed_sysex.h index 6d991ef..c448415 100644 --- a/dexed_sysex.h +++ b/dexed_sysex.h @@ -44,6 +44,7 @@ extern char voice_names[NUM_DEXED][MAX_VOICES][VOICE_NAME_LEN]; extern uint8_t ui_state; extern uint8_t ui_main_state; extern config_t configuration; +extern uint32_t crc32(byte * calc_start, uint16_t calc_bytes); void create_sysex_filename(uint8_t b, char* sysex_file_name); void strip_extension(char* s, char *target); @@ -55,5 +56,6 @@ 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 get_sysex_setup(File sysex, uint8_t voice_number, uint8_t* data); bool load_sysex_setup(uint8_t b, uint8_t v, uint8_t instance_id); +bool save_sysex_setup(uint8_t b, uint8_t v, config_t configuration); #endif diff --git a/doc/sysex-format_dexed-setup.txt b/doc/sysex-format_dexed-setup.txt index 8afef73..582dc0f 100644 --- a/doc/sysex-format_dexed-setup.txt +++ b/doc/sysex-format_dexed-setup.txt @@ -7,42 +7,42 @@ SYSEX Message Controller-Set 11110000 F0 Status byte - start sysex 0iiiiiii 67 ID # (i=103; unofficial SYSEX-ID for MicroDexed) 0sssnnnn 00 Sub-status (s=0) & channel number (n=0; ch 1) - 0fffffff 00 format number (f=66..69; 1..4 MicroDexed setup(s)) - 0bbbbbbb 01 byte count MS byte - 0bbbbbbb 1B byte count LS byte (b=44; 1 instance - b=73; 2 instances - b=102; 3 instances - b=131; 4 instances) + 0fffffff ** format number (f=66..69; 1..4 MicroDexed setup(s)) + 0bbbbbbb ** byte count MS byte + 0bbbbbbb ** byte count LS byte (b=44; 1 instance + b=75; 2 instances + b=106; 3 instances + b=137; 4 instances) 0ddddddd ** data byte 1 setup config | | | - 0ddddddd ** data byte 19 - 0ddddddd ** data byte 20 instance config 0 + 0ddddddd ** data byte 13 + 0ddddddd ** data byte 14 instance config 0 | | | - 0ddddddd ** data byte 43 + 0ddddddd ** data byte 44 /-Optional--------------------------------------------\ - 0ddddddd ** data byte 44 instance config 1 + 0ddddddd ** data byte 45 instance config 1 | | | - 0ddddddd ** data byte 72 + 0ddddddd ** data byte 74 \-----------------------------------------------------/ /-Optional--------------------------------------------\ - 0ddddddd ** data byte 73 instance config 2 + 0ddddddd ** data byte 75 instance config 2 | | | - 0ddddddd ** data byte 101 + 0ddddddd ** data byte 105 \-----------------------------------------------------/ /-Optional--------------------------------------------\ - 0ddddddd ** data byte 102 instance config 3 + 0ddddddd ** data byte 106 instance config 3 | | | - 0ddddddd ** data byte 131 + 0ddddddd ** data byte 137 \-----------------------------------------------------/ 0eeeeeee ** checksum (masked 2's comp. of sum of ** bytes) 11110111 F7 Status - end sysex @@ -50,77 +50,48 @@ SYSEX Message Controller-Set Data Structure: MicroDexed Setup Dump ------------------------------------- -Parameter - Number Parameter Value Range ---------- --------- ----------- - 0 GLOBAL STERO/MONO 0-3 (0=stereo, 1=mono, 2=mono-r, 3=mono-l) - 1 GLOBAL REVERB-ROOMSIZE 0-100 - 2 GLOBAL REVERB-DAMPING 0-100 - 3 GLOBAL CHORUS-FREQUENCY 0-100 (multiplied by 1/10 Hz) - 4 GLOBAL CHORUS-WAVEFORM 0-1 (0=triangle, 1=sine) - 5 GLOBAL CHORUS-DEPTH 0-100 - 6 GLOBAL DELAY-TIME 0-60 (multiplied by 10ms) - 7 GLOBAL DELAY-FEEDBACK 0-100 - 8 DEXED 1 MONO/POLY MODE CHANGE 0-1 O=POLY - 9 DEXED 1 PITCH BEND RANGE 0-12 -10 DEXED 1 " " STEP 0-12 -11 DEXED 1 PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW -12 DEXED 1 " GLISS 0-1 -13 DEXED 1 " TIME 0-99 -14 DEXED 1 MOD WHEEL RANGE 0-99 -15 DEXED 1 " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias -16 DEXED 1 FOOT CONTROL RANGE 0-99 -17 DEXED 1 " " ASSIGN 0-7 " -18 DEXED 1 BREATH CONT RANGE 0-99 -19 DEXED 1 " " ASSIGN 0-7 " -20 DEXED 1 AFTERTOUCH RANGE 0-99 -21 DEXED 1 " ASSIGN 0-7 " -22 DEXED 1 OP1_ENABLE 0-1 -23 DEXED 1 OP2_ENABLE 0-1 -24 DEXED 1 OP3_ENABLE 0-1 -25 DEXED 1 OP4_ENABLE 0-1 -26 DEXED 1 OP5_ENABLE 0-1 -27 DEXED 1 OP6_ENABLE 0-1 -28 DEXED 1 MAX_NOTES 0-32 -29 DEXED 1 LOUDNESS 0-100 -30 DEXED 1 PANORAMA 0-40 (20 is middle) -31 DEXED 1 REVERB-LEVEL 0-100 -32 DEXED 1 CHORUS-LEVEL 0-100 -33 DEXED 1 DELAY-LEVEL 0-100 -34 DEXED 1 FILTER-CUTOFF 0-100 -35 DEXED 1 FILTER-RESONANCE 0-100 -26 DEXED 1 MIDI-CHANNEL 0-16 (0=OMNI) -37 DEXED 1 POLYPHONY 0-32 (depends on CPU and FX) -38 DEXED 1 ENGINE 0-2 (1=Modern, 2=Mark1, 2=OPL) + Number Parameter Value Range +--------- --------- ----------- + 0 GLOBAL STERO/MONO 0-3 (0=stereo, 1=mono, 2=mono-r, 3=mono-l) + 1 GLOBAL REVERB-ROOMSIZE 0-100 + 2 GLOBAL REVERB-DAMPING 0-100 + 3 GLOBAL REVERB-LEVEL 0-100 + 4 GLOBAL CHORUS-FREQUENCY 0-100 (multiplied by 1/10 Hz) + 5 GLOBAL CHORUS-WAVEFORM 0-1 (0=triangle, 1=sine) + 6 GLOBAL CHORUS-DEPTH 0-100 + 7 GLOBAL CHORUS-LEVEL 0-100 + 8 GLOBAL DELAY-TIME 0-50 (multiplied by 10ms) + 9 GLOBAL DELAY-FEEDBACK 0-100 +10 GLOBAL DELAY-LEVEL 0-100 --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- -39 DEXED 2 MONO/POLY MODE CHANGE 0-1 O=POLY -40 DEXED 2 PITCH BEND RANGE 0-12 -41 DEXED 2 " " STEP 0-12 -42 DEXED 2 PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW -43 DEXED 2 " GLISS 0-1 -44 DEXED 2 " TIME 0-99 -45 DEXED 2 MOD WHEEL RANGE 0-99 -46 DEXED 2 " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias -47 DEXED 2 FOOT CONTROL RANGE 0-99 -48 DEXED 2 " " ASSIGN 0-7 " -49 DEXED 2 BREATH CONT RANGE 0-99 -40 DEXED 2 " " ASSIGN 0-7 " -51 DEXED 2 AFTERTOUCH RANGE 0-99 -52 DEXED 2 " ASSIGN 0-7 " -53 DEXED 2 OP1_ENABLE 0-1 -54 DEXED 2 OP2_ENABLE 0-1 -55 DEXED 2 OP3_ENABLE 0-1 -56 DEXED 2 OP4_ENABLE 0-1 -57 DEXED 2 OP5_ENABLE 0-1 -58 DEXED 2 OP6_ENABLE 0-1 -59 DEXED 2 MAX_NOTES 0-32 -60 DEXED 2 LOUDNESS 0-100 -61 DEXED 2 PANORAMA 0-40 (20 is middle) -62 DEXED 2 REVERB-LEVEL 0-100 -63 DEXED 2 CHORUS-LEVEL 0-100 -64 DEXED 2 DELAY-LEVEL 0-100 -65 DEXED 2 FILTER-CUTOFF 0-100 -66 DEXED 2 FILTER-RESONANCE 0-100 -67 DEXED 2 MIDI-CHANNEL 0-16 (0=OMNI) -68 DEXED 2 POLYPHONY 0-32 (depends on CPU and FX) -69 DEXED 2 ENGINE 0-2 (1=Modern, 2=Mark1, 2=OPL) +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