diff --git a/UI.hpp b/UI.hpp index 67d1ed3..2c6a962 100644 --- a/UI.hpp +++ b/UI.hpp @@ -4539,9 +4539,9 @@ void UI_func_seq_vel_editor(uint8_t param) if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) { if (LCDML.BT_checkDown()) - seq_active_track = constrain(seq_active_track + 1, 0, 9); + seq_active_track = constrain(seq_active_track + 1, 0, NUM_SEQ_PATTERN - 1); else if (LCDML.BT_checkUp()) - seq_active_track = constrain(seq_active_track - 1, 0, 9); + seq_active_track = constrain(seq_active_track - 1, 0, NUM_SEQ_PATTERN - 1); } } if ( seq_data[seq_active_track][seq_menu - 1] > 0 ) @@ -4897,14 +4897,14 @@ void UI_func_seq_pattern_editor(uint8_t param) { if (LCDML.BT_checkDown()) { - temp_int = constrain(temp_int + 1, 0, 9); + temp_int = constrain(temp_int + 1, 0, NUM_SEQ_PATTERN - 1); if (temp_int == seq_active_track)temp_int++; if (temp_int > 9)temp_int = 0; } else if (LCDML.BT_checkUp()) { - temp_int = constrain(temp_int - 1, 0, 9); + temp_int = constrain(temp_int - 1, 0, NUM_SEQ_PATTERN - 1); if (temp_int == seq_active_track)temp_int--; - if (temp_int < 0)temp_int = 9; + if (temp_int < 0)temp_int = NUM_SEQ_PATTERN - 1; } } } else if (seq_active_function == 99) @@ -4941,9 +4941,9 @@ void UI_func_seq_pattern_editor(uint8_t param) if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) { if (LCDML.BT_checkDown()) - seq_active_track = constrain(seq_active_track + 1, 0, 9); + seq_active_track = constrain(seq_active_track + 1, 0, NUM_SEQ_PATTERN - 1); else if (LCDML.BT_checkUp()) - seq_active_track = constrain(seq_active_track - 1, 0, 9); + seq_active_track = constrain(seq_active_track - 1, 0, NUM_SEQ_PATTERN - 1); lcd.setCursor(1, 0); if (seq_content_type[seq_active_track] == 0) lcd.print("Drum "); else if (seq_content_type[seq_active_track] == 1) lcd.print("Instr "); else if (seq_content_type[seq_active_track] == 2) lcd.print("Chord "); else lcd.print("Arp "); @@ -5055,7 +5055,6 @@ void UI_func_seq_pattern_editor(uint8_t param) } if ( seq_menu == 1) { - //lcd.setCursor(11, 0); if (seq_running == false && seq_recording == false) { seq_running = true; @@ -5448,6 +5447,9 @@ void UI_func_arpeggio(uint8_t param) seq_running = !seq_running; timer1.stop(); MicroDexed[0]->panic(); +#if NUM_DEXED > 1 + MicroDexed[1]->panic(); +#endif arp_refresh_display_play_status(); seq_step = 0; arp_octave = 0; @@ -5459,7 +5461,6 @@ void UI_func_arpeggio(uint8_t param) arp_refresh_display_play_status(); timer1.start(); } - } else if ( seq_temp_select_menu == 3 && seq_temp_active_menu == 0 ) { diff --git a/config.h b/config.h index 614cd11..6cdbd01 100644 --- a/config.h +++ b/config.h @@ -118,6 +118,11 @@ // NUMBER OF SAMPLES IN DRUMSET #define NUM_DRUMSET_CONFIG 69 +// SEQUENCER + +#define NUM_SEQ_PATTERN 10 +#define NUM_SEQ_TRACKS 4 + // CHORUS parameters #define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer. #define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE diff --git a/dexed_sd.cpp b/dexed_sd.cpp index a0639d6..a4b317a 100644 --- a/dexed_sd.cpp +++ b/dexed_sd.cpp @@ -45,11 +45,11 @@ extern void sequencer(); extern float drums_volume; //extern StaticJsonDocument data_json; extern uint8_t seq_chain_lenght; -extern uint8_t seq_data[10][16]; -extern uint8_t seq_vel[10][16]; -extern uint8_t seq_patternchain[4][4]; -extern uint8_t seq_content_type[10]; -extern uint8_t seq_track_type[4]; +extern uint8_t seq_data[NUM_SEQ_PATTERN][16]; +extern uint8_t seq_vel[NUM_SEQ_PATTERN][16]; +extern uint8_t seq_patternchain[NUM_SEQ_TRACKS][4]; +extern uint8_t seq_content_type[NUM_SEQ_PATTERN]; +extern uint8_t seq_track_type[NUM_SEQ_TRACKS]; extern uint8_t seq_chord_key_ammount; extern uint8_t seq_element_shift; extern int seq_oct_shift; @@ -63,7 +63,7 @@ extern uint8_t arp_lenght; extern uint8_t arp_style; extern uint8_t seq_chord_velocity; extern uint8_t seq_chord_dexed_inst; -extern uint8_t seq_inst_dexed[4]; +extern uint8_t seq_inst_dexed[NUM_SEQ_TRACKS]; extern char seq_name[FILENAME_LEN]; extern char seq_name_temp[FILENAME_LEN]; extern PeriodicTimer timer1; @@ -945,24 +945,132 @@ bool save_sd_fx_json(uint8_t fx, uint8_t target) return (false); } +bool save_sd_seq_sub_vel_json(uint8_t seq_number) +{ + char filename[FILENAME_LEN]; + int count = 0; + seq_number = constrain(seq_number, 0, 99); + if (sd_card > 0) + { + File json; + StaticJsonDocument data_json; + sprintf(filename, "/%s/%d-vel.json", SEQ_CONFIG_PATH, seq_number); +#ifdef DEBUG + Serial.print(F("Saving sequencer velocity ")); + Serial.print(seq_number); + Serial.print(F(" to ")); + Serial.println(filename); +#endif + int total = sizeof(seq_vel); + int columns = sizeof(seq_vel[0]); + int rows = total / columns; + AudioNoInterrupts(); + SD.begin(); + SD.remove(filename); + json = SD.open(filename, FILE_WRITE); + if (json) + { + for (uint8_t i = 0; i < rows; i++) + { + for (uint8_t j = 0; j < columns; j++) { + data_json["seq_velocity"][count] = seq_vel[i][j]; + count++; + } + } +#ifdef DEBUG + Serial.println(F("Write JSON data:")); + serializeJsonPretty(data_json, Serial); + Serial.println(); +#endif + serializeJsonPretty(data_json, json); + json.close(); + AudioInterrupts(); + return (true); + } + json.close(); + } + else + { +#ifdef DEBUG + Serial.print(F("E : Cannot open ")); + Serial.print(filename); + Serial.println(F(" on SD.")); +#endif + } + return (false); +} + +bool save_sd_seq_sub_patterns_json(uint8_t seq_number) +{ + char filename[FILENAME_LEN]; + int count = 0; + seq_number = constrain(seq_number, 0, 99); + if (sd_card > 0) + { + File json; + StaticJsonDocument data_json; + sprintf(filename, "/%s/%d-pat.json", SEQ_CONFIG_PATH, seq_number); +#ifdef DEBUG + Serial.print(F("Saving sequencer patterns ")); + 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; + AudioNoInterrupts(); + SD.begin(); + SD.remove(filename); + json = SD.open(filename, FILE_WRITE); + if (json) + { + for (uint8_t i = 0; i < rows; i++) + { + for (uint8_t j = 0; j < columns; j++) { + data_json["seq_data"][count] = seq_data[i][j]; + count++; + } + } +#ifdef DEBUG + Serial.println(F("Write JSON data:")); + serializeJsonPretty(data_json, Serial); + Serial.println(); +#endif + serializeJsonPretty(data_json, json); + json.close(); + AudioInterrupts(); + return (true); + } + json.close(); + } + else + { +#ifdef DEBUG + Serial.print(F("E : Cannot open ")); + Serial.print(filename); + Serial.println(F(" on SD.")); +#endif + } + return (false); +} bool save_sd_seq_json(uint8_t seq_number) { char filename[FILENAME_LEN]; int count = 0; seq_number = constrain(seq_number, 0, 99); + save_sd_seq_sub_vel_json(seq_number); + save_sd_seq_sub_patterns_json(seq_number); 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); @@ -989,32 +1097,15 @@ bool save_sd_seq_json(uint8_t seq_number) Serial.print(" Columns: "); Serial.print(columns); Serial.print(F(" ")); - AudioNoInterrupts(); SD.begin(); SD.remove(filename); json = SD.open(filename, FILE_WRITE); if (json) { - for (uint8_t i = 0; i < rows; i++) - { - for (uint8_t j = 0; j < columns; j++) { - data_json["seq_data"][count] = seq_data[i][j]; - count++; - } - } - count = 0; - for (uint8_t i = 0; i < rows; i++) - { - for (uint8_t j = 0; j < columns; j++) { - data_json["seq_velocity"][count] = seq_vel[i][j]; - count++; - } - } total = sizeof(seq_patternchain); columns = sizeof(seq_patternchain[0]); rows = total / columns; - Serial.print(F("Chain Rows: ")); Serial.print(rows); Serial.print(" Chain Columns: "); @@ -1042,13 +1133,11 @@ 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; - 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]; } @@ -1061,8 +1150,6 @@ bool save_sd_seq_json(uint8_t seq_number) for (uint8_t i = 0; i < FILENAME_LEN; i++) { data_json["seq_name"][i] = seq_name[i]; } - - #ifdef DEBUG Serial.println(F("Write JSON data:")); serializeJsonPretty(data_json, Serial); @@ -1074,7 +1161,6 @@ bool save_sd_seq_json(uint8_t seq_number) return (true); } json.close(); - } else { @@ -1123,22 +1209,20 @@ void get_sd_seq_name_json(uint8_t seq_number) } } -bool load_sd_seq_json(uint8_t seq_number) +bool load_sd_seq_sub_vel_json(uint8_t seq_number) { if (seq_number < 0) return (false); seq_number = constrain(seq_number, 0, 99); - load_sd_fx_json(seq_number, 1); - if (sd_card > 0) { File json; StaticJsonDocument data_json; char filename[FILENAME_LEN]; - sprintf(filename, "/%s/%d-S.json", SEQ_CONFIG_PATH, seq_number); + sprintf(filename, "/%s/%d-vel.json", SEQ_CONFIG_PATH, seq_number); // first check if file exists... AudioNoInterrupts(); @@ -1146,7 +1230,7 @@ bool load_sd_seq_json(uint8_t seq_number) { // ... and if: load #ifdef DEBUG - Serial.print(F("Found Sequencer configuration [")); + Serial.print(F("Found velocity data [")); Serial.print(filename); Serial.println(F("]... loading...")); Serial.println(F(" ")); @@ -1155,7 +1239,6 @@ bool load_sd_seq_json(uint8_t seq_number) if (json) { deserializeJson(data_json, json); - json.close(); AudioInterrupts(); @@ -1164,30 +1247,158 @@ bool load_sd_seq_json(uint8_t seq_number) serializeJsonPretty(data_json, Serial); Serial.println(); #endif - int total = sizeof(seq_data); - int columns = sizeof(seq_data[0]); + int total = sizeof(seq_vel); + int columns = sizeof(seq_vel[0]); int rows = total / columns; int count = 0; - for (uint8_t i = 0; i < rows; i++) { for (uint8_t j = 0; j < columns; j++) { - seq_data[i][j] = data_json["seq_data"][count]; + seq_vel[i][j] = data_json["seq_velocity"][count]; count++; } } - count = 0; + return (true); + } +#ifdef DEBUG + else + { + Serial.print(F("E : Cannot open ")); + Serial.print(filename); + Serial.println(F(" on SD.")); + } + } + else + { + Serial.print(F("No ")); + Serial.print(filename); + Serial.println(F(" available.")); +#endif + } + } + return (false); +} + +bool load_sd_seq_sub_patterns_json(uint8_t seq_number) +{ + if (seq_number < 0) + return (false); + + seq_number = constrain(seq_number, 0, 99); + + if (sd_card > 0) + { + File json; + StaticJsonDocument data_json; + char filename[FILENAME_LEN]; + + sprintf(filename, "/%s/%d-pat.json", SEQ_CONFIG_PATH, seq_number); + + // first check if file exists... + AudioNoInterrupts(); + if (SD.exists(filename)) + { + // ... and if: load +#ifdef DEBUG + Serial.print(F("Found pattern data [")); + Serial.print(filename); + Serial.println(F("]... loading...")); + Serial.println(F(" ")); +#endif + json = SD.open(filename); + if (json) + { + deserializeJson(data_json, json); + + json.close(); + AudioInterrupts(); + +#ifdef DEBUG + Serial.println(F("Read JSON data:")); + serializeJsonPretty(data_json, Serial); + Serial.println(); +#endif + int total = sizeof(seq_data); + int columns = sizeof(seq_data[0]); + int rows = total / columns; + int count = 0; + for (uint8_t i = 0; i < rows; i++) { for (uint8_t j = 0; j < columns; j++) { - seq_vel[i][j] = data_json["seq_velocity"][count]; + seq_data[i][j] = data_json["seq_data"][count]; count++; } } - total = sizeof(seq_patternchain); - columns = sizeof(seq_patternchain[0]); - rows = total / columns; - count = 0; + return (true); + } +#ifdef DEBUG + else + { + Serial.print(F("E : Cannot open ")); + Serial.print(filename); + Serial.println(F(" on SD.")); + } + } + else + { + Serial.print(F("No ")); + Serial.print(filename); + Serial.println(F(" available.")); +#endif + } + } + return (false); +} + +bool load_sd_seq_json(uint8_t seq_number) +{ + if (seq_number < 0) + return (false); + + seq_number = constrain(seq_number, 0, 99); + + load_sd_seq_sub_patterns_json(seq_number); + load_sd_seq_sub_vel_json(seq_number); + + load_sd_fx_json(seq_number, 1); + + if (sd_card > 0) + { + File json; + StaticJsonDocument data_json; + char filename[FILENAME_LEN]; + + sprintf(filename, "/%s/%d-S.json", SEQ_CONFIG_PATH, seq_number); + + // first check if file exists... + AudioNoInterrupts(); + if (SD.exists(filename)) + { + // ... and if: load +#ifdef DEBUG + Serial.print(F("Found Sequencer configuration [")); + Serial.print(filename); + Serial.println(F("]... loading...")); + Serial.println(F(" ")); +#endif + json = SD.open(filename); + if (json) + { + deserializeJson(data_json, json); + + json.close(); + AudioInterrupts(); + +#ifdef DEBUG + Serial.println(F("Read JSON data:")); + serializeJsonPretty(data_json, Serial); + Serial.println(); +#endif + int total = sizeof(seq_patternchain); + int columns = sizeof(seq_patternchain[0]); + int rows = total / columns; + int count = 0; for (uint8_t i = 0; i < rows; i++) { for (uint8_t j = 0; j < columns; j++) { @@ -1210,7 +1421,6 @@ bool load_sd_seq_json(uint8_t seq_number) seq_name[i] = data_json["seq_name"][i]; } } - count = 0; seq_tempo_ms = data_json["seq_tempo_ms"] ; seq_bpm = data_json["seq_bpm"]; @@ -1225,17 +1435,12 @@ 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"]; - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { configuration.performance.bank[instance_id] = data_json["bank"][instance_id]; configuration.performance.voice[instance_id] = data_json["voice"][instance_id]; load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); load_sd_voiceconfig_json(seq_number, instance_id, 1); - //check_configuration_dexed(instance_id); - //set_voiceconfig_params(instance_id); - //MicroDexed[instance_id]->ControllersRefresh(); MicroDexed[instance_id]->setGain(midi_volume_transform(map(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0, 127))); MicroDexed[instance_id]->panic(); #ifdef DEBUG @@ -1245,16 +1450,13 @@ bool load_sd_seq_json(uint8_t seq_number) Serial.print(F(" ")); #endif } - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) set_voiceconfig_params(instance_id); set_fx_params(); - if (seq_running) timer1.begin(sequencer, seq_tempo_ms / 2); else timer1.begin(sequencer, seq_tempo_ms / 2, false); - return (true); } #ifdef DEBUG diff --git a/drums.h b/drums.h index baeb98a..8cab2d3 100644 --- a/drums.h +++ b/drums.h @@ -46,4 +46,6 @@ typedef struct drum_config_s { enum {DRUM_NONE, DRUM_BASS, DRUM_SNARE, DRUM_HIHAT, DRUM_HANDCLAP, DRUM_RIDE, DRUM_CRASH, DRUM_LOWTOM, DRUM_MIDTOM, DRUM_HIGHTOM, DRUM_PERCUSSION}; + + #endif