diff --git a/UI.hpp b/UI.hpp index c3e06a7..8824ec7 100644 --- a/UI.hpp +++ b/UI.hpp @@ -1467,7 +1467,7 @@ void UI_func_delay_time(uint8_t param) lcd_special_chars(BLOCKBAR); if (configuration.fx.delay_sync[selected_instance_id] > 0) { - lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]); + lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]); //goto MIDI Sync } else { @@ -1528,7 +1528,7 @@ void UI_func_delay_time(uint8_t param) if (configuration.fx.delay_sync[selected_instance_id] > 0) { - lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]); + lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]);//MIDI Sync Delay } else { @@ -4300,15 +4300,21 @@ void UI_func_seq_tempo(uint8_t param) else if (LCDML.BT_checkUp()) seq_bpm = constrain(seq_bpm - ENCODER[ENC_R].speed(), 50, 190); } - // seq_tempo_ms = 60000 / seq_bpm / 4; seq_tempo_ms = 60000000 / seq_bpm / 4; - lcd.setCursor(0, 1); sprintf(tmp, "[%3d]", seq_bpm); lcd.print(tmp); lcd.setCursor(11, 1); sprintf(tmp, "%3d", seq_tempo_ms / 1000); lcd.print(tmp); + for (uint8_t i = 0; i < MAX_DEXED; i++) + { + if (configuration.fx.delay_sync[i] > 0) + { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[configuration.fx.delay_sync[i]] / seq_bpm); + delay_fx[i]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN, DELAY_TIME_MAX * 10)); + } + } //timer1.stop(); timer1.begin(sequencer, seq_tempo_ms / 2); } @@ -5667,7 +5673,7 @@ void UI_func_seq_state_save(uint8_t param) lcd.setCursor(0, 1); sprintf(tmp, "[%2d]", temp_int); lcd.print(tmp); - sprintf(tmp, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, temp_int); + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); if (SD.exists(tmp)) overwrite = true; else @@ -5707,7 +5713,7 @@ void UI_func_seq_state_save(uint8_t param) if (yesno == true) { char tmp[FILENAME_LEN]; - sprintf(tmp, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, temp_int); + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); SD.remove(tmp); } save_sd_seq_json(temp_int); @@ -5729,7 +5735,7 @@ void UI_func_seq_state_save(uint8_t param) if (mode == 0) { char tmp[FILENAME_LEN]; - sprintf(tmp, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, temp_int); + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); if (SD.exists(tmp)) overwrite = true; else @@ -6466,13 +6472,13 @@ void UI_func_load_performance(uint8_t param) lcd.print("Does not exist."); else { - load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[0], 0); + load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[0], 0, 0); set_voiceconfig_params(0); #if NUM_DEXED > 1 - load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[1], 1); + load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[1], 1, 0); set_voiceconfig_params(1); #endif - load_sd_fx_json(configuration.performance.fx_number); + load_sd_fx_json(configuration.performance.fx_number, 0); set_fx_params(); lcd.print("Done. "); @@ -6680,7 +6686,7 @@ void UI_func_load_voiceconfig(uint8_t param) if (mode > 0) { mode = 0xff; lcd.setCursor(0, 1); - if (load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id) == false) + if (load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id, 0) == false) lcd.print("Does not exist. "); else lcd.print("Done. "); @@ -6810,7 +6816,7 @@ void UI_func_save_voiceconfig(uint8_t param) sprintf(tmp, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[selected_instance_id]); SD.remove(tmp); } - save_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id); + save_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id, 0); lcd.show(1, 0, 16, "Done."); delay(MESSAGE_WAIT_TIME); LCDML.FUNC_goBackToMenu(); @@ -6919,7 +6925,7 @@ void UI_func_load_fx(uint8_t param) mode = 0xff; lcd.setCursor(0, 1); - if (load_sd_fx_json(configuration.performance.fx_number) == false) + if (load_sd_fx_json(configuration.performance.fx_number, 0) == false) lcd.print("Does not exist. "); else lcd.print("Done. "); @@ -7017,7 +7023,7 @@ void UI_func_save_fx(uint8_t param) sprintf(tmp, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, configuration.performance.fx_number); SD.remove(tmp); } - save_sd_fx_json(configuration.performance.fx_number); + save_sd_fx_json(configuration.performance.fx_number, 0); lcd.show(1, 0, 16, "Done."); LCDML.FUNC_goBackToMenu(); @@ -8539,7 +8545,7 @@ void lcd_special_chars(uint8_t mode) void lcd_display_delay_sync(uint8_t sync) { lcd.show(0, 0, LCD_cols - 2, "Delay Sync"); - lcd.show(1, 0, 10, "MIDI Sync "); + if (seq_running == false)lcd.show(1, 0, 10, "MIDI Sync "); else lcd.show(1, 0, 10, "Seq. Sync "); switch (sync) { case 1: @@ -8570,20 +8576,26 @@ void lcd_display_delay_sync(uint8_t sync) lcd.show(1, 10, 6, "1/1"); break; } + if (seq_running == false) { - uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[sync] / midi_bpm + 0.5); - if (midi_sync_delay_time > DELAY_MAX_TIME) - { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[sync] / midi_bpm + 0.5); + if (midi_sync_delay_time > DELAY_MAX_TIME) + { #ifdef DEBUG - Serial.println(F("Calculated MIDI-Sync delay: ")); - Serial.print(round(60000.0 * midi_ticks_factor[sync] / midi_bpm), DEC); - Serial.println(F("ms")); - Serial.println(F("MIDI-Sync delay: midi_sync_delay_time")); - Serial.print(midi_sync_delay_time, DEC); - Serial.println(F("ms")); + Serial.println(F("Calculated MIDI-Sync delay: ")); + Serial.print(round(60000.0 * midi_ticks_factor[sync] / midi_bpm), DEC); + Serial.println(F("ms")); + Serial.println(F("MIDI-Sync delay: midi_sync_delay_time")); + Serial.print(midi_sync_delay_time, DEC); + Serial.println(F("ms")); #endif - lcd.show(1, 15, 1, "!"); + } + } else + { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[sync] / seq_bpm); + delay_fx[selected_instance_id]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN, DELAY_TIME_MAX * 10)); } + lcd.show(1, 15, 1, "!"); } void eeprom_update_var(uint16_t pos, uint8_t val, const char* val_string) diff --git a/config.h b/config.h index 1843c28..408a4b8 100644 --- a/config.h +++ b/config.h @@ -296,6 +296,9 @@ #define SEQ_CONFIG_PATH "SEQ" #define SEQ_CONFIG_NAME "SEQ" +#define DRUM_CONFIG_PATH "DRM" +#define DRUM_CONFIG_NAME "DRM" + #define MAX_PERF_MOD 30 //************************************************************************************************* @@ -633,7 +636,8 @@ #define EQ_7_DEFAULT 0 // Buffer-size define for load/save configuration as JSON -#define JSON_BUFFER_SIZE 8192 + +#define JSON_BUFFER_SIZE 7168 // Internal configuration structure typedef struct dexed_s { diff --git a/dexed_sd.cpp b/dexed_sd.cpp index a51cf99..b9291cc 100644 --- a/dexed_sd.cpp +++ b/dexed_sd.cpp @@ -61,6 +61,7 @@ extern uint8_t seq_chord_velocity; extern uint8_t seq_chord_dexed_inst; extern uint8_t seq_inst_dexed[4]; extern PeriodicTimer timer1; +extern float pseudo_log_curve(float value); typedef struct drum_config_s { uint8_t drum_class; // Type of drum @@ -439,7 +440,7 @@ bool save_sd_bank(const char* bank_filename, uint8_t* data) /****************************************************************************** SD VOICECONFIG ******************************************************************************/ -bool load_sd_voiceconfig_json(int8_t vc, uint8_t instance_id) +bool load_sd_voiceconfig_json(uint8_t vc, uint8_t instance_id, uint8_t target) { char filename[FILENAME_LEN]; @@ -449,8 +450,10 @@ bool load_sd_voiceconfig_json(int8_t vc, uint8_t instance_id) { File json; StaticJsonDocument data_json; - sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, vc); - + if (target == 0) + sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, vc); + else + sprintf(filename, "/%s/%d-v%d.json", SEQ_CONFIG_PATH, vc, instance_id); // first check if file exists... AudioNoInterrupts(); if (SD.exists(filename)) @@ -531,7 +534,7 @@ bool load_sd_voiceconfig_json(int8_t vc, uint8_t instance_id) return (false); } -bool save_sd_voiceconfig_json(uint8_t vc, uint8_t instance_id) +bool save_sd_voiceconfig_json(uint8_t vc, uint8_t instance_id, uint8_t target) { char filename[FILENAME_LEN]; @@ -541,8 +544,10 @@ bool save_sd_voiceconfig_json(uint8_t vc, uint8_t instance_id) { File json; StaticJsonDocument data_json; - sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, vc); - + if (target == 0) + sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, vc); + else + sprintf(filename, "/%s/%d-v%d.json", SEQ_CONFIG_PATH, vc, instance_id); #ifdef DEBUG Serial.print(F("Saving voice config ")); Serial.print(vc); @@ -617,7 +622,7 @@ bool save_sd_voiceconfig_json(uint8_t vc, uint8_t instance_id) /****************************************************************************** SD FX ******************************************************************************/ -bool load_sd_fx_json(int8_t fx) +bool load_sd_fx_json(uint8_t fx, uint8_t target) { if (fx < 0) return (false); @@ -629,9 +634,10 @@ bool load_sd_fx_json(int8_t fx) File json; StaticJsonDocument data_json; char filename[FILENAME_LEN]; - - sprintf(filename, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, fx); - + if (target == 0) + sprintf(filename, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, fx); + else + sprintf(filename, "/%s/%d-fx.json", SEQ_CONFIG_PATH, fx); // first check if file exists... AudioNoInterrupts(); if (SD.exists(filename)) @@ -711,7 +717,7 @@ bool load_sd_fx_json(int8_t fx) return (false); } -bool save_sd_fx_json(uint8_t fx) +bool save_sd_fx_json(uint8_t fx, uint8_t target) { char filename[FILENAME_LEN]; @@ -721,8 +727,10 @@ bool save_sd_fx_json(uint8_t fx) { File json; StaticJsonDocument data_json; - sprintf(filename, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, fx); - + if (target == 0) + sprintf(filename, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, fx); + else + sprintf(filename, "/%s/%d-fx.json", SEQ_CONFIG_PATH, fx); #ifdef DEBUG Serial.print(F("Saving fx config ")); Serial.print(fx); @@ -787,8 +795,8 @@ bool save_sd_fx_json(uint8_t fx) return (false); } -bool load_sd_seq_drumsettings_json(uint8_t number) -{ // test function , to save drumsettings for use in sequencer, so storing in the SEQ_Path for now +bool load_sd_drumsettings_json(uint8_t number, uint8_t target) +{ if (number < 0) return (false); @@ -799,9 +807,10 @@ bool load_sd_seq_drumsettings_json(uint8_t number) File json; StaticJsonDocument data_json; char filename[FILENAME_LEN]; - - sprintf(filename, "/%s/%s%d-d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, number); - + if (target == 0) + sprintf(filename, "/%s/%s%d.json", SEQ_CONFIG_PATH, DRUM_CONFIG_NAME, number); //change to DRUM + else + sprintf(filename, "/%s/%d-d.json", SEQ_CONFIG_PATH, number); // first check if file exists... AudioNoInterrupts(); if (SD.exists(filename)) @@ -832,7 +841,6 @@ bool load_sd_seq_drumsettings_json(uint8_t number) drum_config[i].vol_min = data_json["vol_min"][i] ; drum_config[i].reverb_send = data_json["reverb_send"][i]; } - return (true); } #ifdef DEBUG @@ -856,8 +864,8 @@ bool load_sd_seq_drumsettings_json(uint8_t number) return (false); } -bool save_sd_seq_drumsettings_json(uint8_t number) -{ // test function , to save drumsettings for use in sequencer, since storing in the SEQ_Path for now +bool save_sd_drumsettings_json(uint8_t number, uint8_t target) +{ char filename[FILENAME_LEN]; number = constrain(number, 0, 99); @@ -865,8 +873,10 @@ bool save_sd_seq_drumsettings_json(uint8_t number) { File json; StaticJsonDocument data_json; - sprintf(filename, "/%s/%s%d-d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, number); - + if (target == 0) + sprintf(filename, "/%s/%s%d-d.json", DRUM_CONFIG_PATH, DRUM_CONFIG_NAME, number); + else + sprintf(filename, "/%s/%d-d.json", SEQ_CONFIG_PATH, number); #ifdef DEBUG Serial.print(F("Saving drums config ")); Serial.print(number); @@ -876,10 +886,10 @@ bool save_sd_seq_drumsettings_json(uint8_t number) AudioNoInterrupts(); - if (SD.exists(filename)){ - Serial.println("remove old drumsettings file"); - SD.remove(filename); - } + if (SD.exists(filename)) { + Serial.println("remove old drumsettings file"); + SD.remove(filename); + } json = SD.open(filename, FILE_WRITE); if (json) { @@ -922,21 +932,38 @@ bool save_sd_seq_json(uint8_t seq_number) int count = 0; seq_number = constrain(seq_number, 0, 99); - save_sd_seq_drumsettings_json(seq_number); + save_sd_drumsettings_json(seq_number, 1); // Destination (1) = sequencer path + + sprintf(filename, "/%s/%d-fx.json", SEQ_CONFIG_PATH, seq_number); + +#ifdef DEBUG + Serial.print(F("write SEQ-FX-Config ")); + Serial.print(seq_number); + Serial.print(F(" ")); +#endif + save_sd_fx_json(seq_number, 1); + for (uint8_t i = 0; i < MAX_DEXED; i++) + { sprintf(filename, "/%s/%d-v%d.json", SEQ_CONFIG_PATH, seq_number, i); + +#ifdef DEBUG + Serial.print(F("Write Voice-Config for sequencer")); + Serial.print(filename); + Serial.print(F(" ")); +#endif + save_sd_voiceconfig_json(seq_number, i, 1); + } if (sd_card > 0) { File json; StaticJsonDocument data_json; - sprintf(filename, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, seq_number); - + sprintf(filename, "/%s/%d-S.json", SEQ_CONFIG_PATH, seq_number); #ifdef DEBUG Serial.print(F("Saving sequencer config ")); Serial.print(seq_number); Serial.print(F(" to ")); Serial.println(filename); #endif - int total = sizeof(seq_data); int columns = sizeof(seq_data[0]); int rows = total / columns; @@ -975,7 +1002,6 @@ bool save_sd_seq_json(uint8_t seq_number) Serial.print(" Chain Columns: "); Serial.print(columns); Serial.print(F(" ")); - count = 0; for (uint8_t i = 0; i < rows; i++) { @@ -985,7 +1011,6 @@ bool save_sd_seq_json(uint8_t seq_number) } } count = 0; - data_json["seq_tempo_ms"] = seq_tempo_ms ; data_json["seq_bpm"] = seq_bpm; data_json["arp_play_basenote"] = arp_play_basenote; @@ -999,7 +1024,12 @@ bool save_sd_seq_json(uint8_t seq_number) data_json["chord_key_ammount"] = seq_chord_key_ammount; data_json["seq_oct_shift"] = seq_oct_shift; data_json["seq_element_shift"] = seq_element_shift; - data_json["performance"] = configuration.sys.performance_number; + + for (uint8_t i = 0; i < MAX_DEXED; i++) + { + data_json["bank"][i] = configuration.performance.bank[i]; + data_json["voice"][i] = configuration.performance.voice[i]; + } for (uint8_t i = 0; i < sizeof(seq_track_type); i++) { data_json["track_type"][i] = seq_track_type[i]; @@ -1035,7 +1065,6 @@ bool save_sd_seq_json(uint8_t seq_number) return (false); } - bool load_sd_seq_json(uint8_t seq_number) { if (seq_number < 0) @@ -1043,14 +1072,16 @@ bool load_sd_seq_json(uint8_t seq_number) seq_number = constrain(seq_number, 0, 99); - load_sd_seq_drumsettings_json(seq_number); + load_sd_drumsettings_json(seq_number, 1); + load_sd_fx_json(seq_number, 1); + if (sd_card > 0) { File json; StaticJsonDocument data_json; char filename[FILENAME_LEN]; - sprintf(filename, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, seq_number); + sprintf(filename, "/%s/%d-S.json", SEQ_CONFIG_PATH, seq_number); // first check if file exists... AudioNoInterrupts(); @@ -1061,6 +1092,7 @@ bool load_sd_seq_json(uint8_t seq_number) Serial.print(F("Found Sequencer configuration [")); Serial.print(filename); Serial.println(F("]... loading...")); + Serial.println(F(" ")); #endif json = SD.open(filename); if (json) @@ -1129,9 +1161,28 @@ bool load_sd_seq_json(uint8_t seq_number) seq_chord_key_ammount = data_json["chord_key_ammount"]; seq_oct_shift = data_json["seq_oct_shift"]; seq_element_shift = data_json["seq_element_shift"]; - configuration.sys.performance_number = data_json["performance"]; - load_sd_performance_json(configuration.sys.performance_number); + AudioNoInterrupts(); + + for (uint8_t i = 0; i < MAX_DEXED; i++) + { configuration.performance.bank[i] = data_json["bank"][i]; + configuration.performance.voice[i] = data_json["voice"][i]; + load_sd_voice(configuration.performance.bank[i], configuration.performance.voice[i], i); + load_sd_voiceconfig_json(seq_number, i, 1); + //check_configuration_dexed(i); + //set_voiceconfig_params(i); + //MicroDexed[i]->ControllersRefresh(); + MicroDexed[i]->setGain(pseudo_log_curve(mapfloat(configuration.dexed[i].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX))); + MicroDexed[i]->panic(); +#ifdef DEBUG + Serial.print(F(" ")); + Serial.print(F("Load Voice-Config for sequencer")); + Serial.print(i); + Serial.print(F(" ")); +#endif + } + AudioInterrupts(); + set_fx_params(); if (seq_running) timer1.begin(sequencer, seq_tempo_ms / 2); else @@ -1169,7 +1220,7 @@ bool check_sd_seq_exists(uint8_t number) { char filename[FILENAME_LEN]; - sprintf(filename, "/%s/%s%d.json", SEQ_CONFIG_PATH, SEQ_CONFIG_NAME, number); + sprintf(filename, "/%s/%d-S.json", SEQ_CONFIG_PATH, number); // check if file exists... @@ -1191,21 +1242,18 @@ bool check_sd_seq_exists(uint8_t number) /****************************************************************************** SD PERFORMANCE ******************************************************************************/ -bool load_sd_performance_json(int8_t p) +bool load_sd_performance_json(uint8_t p) { if (p < 0) return (false); p = constrain(p, 0, MAX_PERFORMANCE); - if (sd_card > 0) { File json; StaticJsonDocument data_json; char filename[FILENAME_LEN]; - sprintf(filename, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, p); - // first check if file exists... AudioNoInterrupts(); if (SD.exists(filename)) @@ -1241,11 +1289,11 @@ bool load_sd_performance_json(int8_t p) for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); - load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[instance_id], instance_id); + load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[instance_id], instance_id, 0); MicroDexed[instance_id]->ControllersRefresh(); MicroDexed[instance_id]->panic(); } - load_sd_fx_json(configuration.performance.fx_number); + load_sd_fx_json(configuration.performance.fx_number, 0); return (true); } @@ -1273,10 +1321,8 @@ bool load_sd_performance_json(int8_t p) bool save_sd_performance_json(uint8_t p) { char filename[FILENAME_LEN]; - p = constrain(p, 0, MAX_PERFORMANCE); sprintf(filename, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, p); - if (sd_card > 0) { File json; @@ -1299,12 +1345,10 @@ bool save_sd_performance_json(uint8_t p) Serial.print(configuration.performance.fx_number); Serial.println(F(" does not exists, creating one.")); #endif - //save_sd_performance_json(configuration.performance.fx_number); - save_sd_fx_json(configuration.performance.fx_number); + save_sd_fx_json(configuration.performance.fx_number, 0); } for (uint8_t i = 0; i < MAX_DEXED; i++) - { - sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[i]); + { sprintf(filename, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[i]); if (!SD.exists(filename)) { #ifdef DEBUG @@ -1312,12 +1356,10 @@ bool save_sd_performance_json(uint8_t p) Serial.print(configuration.performance.voiceconfig_number[i]); Serial.println(F(" does not exists, creating one.")); #endif - save_sd_voiceconfig_json(configuration.performance.voiceconfig_number[i], i); + save_sd_voiceconfig_json(configuration.performance.voiceconfig_number[i], i, 0); } } - sprintf(filename, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, p); - json = SD.open(filename, FILE_WRITE); if (json) {