diff --git a/MicroDexed.ino b/MicroDexed.ino index a140ddc..441fb67 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -21,6 +21,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "TeensyTimerTool.h" +using namespace TeensyTimerTool; + #include #include "config.h" #include @@ -325,6 +328,7 @@ char g_voice_name[NUM_DEXED][VOICE_NAME_LEN]; char g_bank_name[NUM_DEXED][BANK_NAME_LEN]; char receive_bank_filename[FILENAME_LEN]; uint8_t selected_instance_id = 0; +uint8_t seq_UI_last_step = 0; #ifdef TEENSY4 #if NUM_DEXED>1 int8_t midi_decay[NUM_DEXED] = { -1, -1}; @@ -358,6 +362,8 @@ extern LCDMenuLib2 LCDML; #endif extern void getNoteName(char* noteName, uint8_t noteNumber); +PeriodicTimer timer1; +extern char seq_chord_names[6][4]; /*********************************************************************** SETUP @@ -631,2155 +637,2186 @@ void setup() #endif LCDML.OTHER_jumpToFunc(UI_func_voice_select); -} - -void loop() -{ - // MIDI input handling - check_midi_devices(); - // check encoder - ENCODER[ENC_L].update(); - ENCODER[ENC_R].update(); + timer1.begin(sequencer, 74'000,false); - if (seq_running) { - sequencer(); - } -#ifdef ENABLE_LCD_UI - LCDML.loop(); -#endif + } - // CONTROL-RATE-EVENT-HANDLING - if (control_rate > CONTROL_RATE_MS) - { - control_rate = 0; + void loop() + { + // MIDI input handling + check_midi_devices(); - // check for value changes, unused voices and CPU overload - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - active_voices[instance_id] = MicroDexed[instance_id]->getNumNotesPlaying(); - if (active_voices[instance_id] == 0) - midi_voices[instance_id] = 0; - } + // check encoder + ENCODER[ENC_L].update(); + ENCODER[ENC_R].update(); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { +#ifdef ENABLE_LCD_UI + LCDML.loop(); +#endif + + if (seq_running) + { + if (seq_step != seq_UI_last_step) + { + seq_UI_last_step=seq_step; + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sequencer)) //is in UI of Sequencer + { + lcd.setCursor(seq_step, 1); + lcd.print("X"); + if (seq_step == 0) + { + lcd.setCursor(15, 1); + lcd.print(seq_find_shortname(15)[0]); + } + else + { + lcd.setCursor(seq_step - 1, 1); + lcd.print(seq_find_shortname(seq_step - 1)[0]); + } + + } + else if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_arpeggio)) //is in UI of Arpeggiator + { + lcd.setCursor(7, 0); + lcd.print( seq_chord_names[arp_chord - 200][0]); + lcd.print( seq_chord_names[arp_chord - 200][1]); + lcd.print( seq_chord_names[arp_chord - 200][2]); + lcd.print( seq_chord_names[arp_chord - 200][3]); + } + } + } + // CONTROL-RATE-EVENT-HANDLING + if (control_rate > CONTROL_RATE_MS) + { + control_rate = 0; + + // check for value changes, unused voices and CPU overload + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + active_voices[instance_id] = MicroDexed[instance_id]->getNumNotesPlaying(); + if (active_voices[instance_id] == 0) + midi_voices[instance_id] = 0; + } + + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { #ifdef TEENSY4 - if (midi_decay_timer > MIDI_DECAY_TIMER && midi_decay[instance_id] > 0) - { - midi_decay[instance_id]--; - lcd.createChar(6 + instance_id, (uint8_t*)special_chars[15 - (7 - midi_decay[instance_id])]); - lcd.setCursor(14 + instance_id, 1); - lcd.write(6 + instance_id); - } - else if (midi_voices[instance_id] == 0 && midi_decay[instance_id] == 0 && !MicroDexed[instance_id]->getSustain()) - { - midi_decay[instance_id]--; - lcd.setCursor(14 + instance_id, 1); - lcd.write(20); // blank - } + if (midi_decay_timer > MIDI_DECAY_TIMER && midi_decay[instance_id] > 0) + { + midi_decay[instance_id]--; + lcd.createChar(6 + instance_id, (uint8_t*)special_chars[15 - (7 - midi_decay[instance_id])]); + lcd.setCursor(14 + instance_id, 1); + lcd.write(6 + instance_id); + } + else if (midi_voices[instance_id] == 0 && midi_decay[instance_id] == 0 && !MicroDexed[instance_id]->getSustain()) + { + midi_decay[instance_id]--; + lcd.setCursor(14 + instance_id, 1); + lcd.write(20); // blank + } #else - static bool midi_playing[NUM_DEXED]; - if (midi_voices[instance_id] > 0 && midi_playing[instance_id] == false) - { - midi_playing[instance_id] = true; - lcd.setCursor(14 + instance_id, 1); - lcd.write(6 + instance_id); - } - else if (midi_voices[instance_id] == 0 && !MicroDexed[instance_id]->getSustain()) - { - midi_playing[instance_id] = false; - lcd.setCursor(14 + instance_id, 1); - lcd.write(20); // blank - } -#endif - } + static bool midi_playing[NUM_DEXED]; + if (midi_voices[instance_id] > 0 && midi_playing[instance_id] == false) + { + midi_playing[instance_id] = true; + lcd.setCursor(14 + instance_id, 1); + lcd.write(6 + instance_id); + } + else if (midi_voices[instance_id] == 0 && !MicroDexed[instance_id]->getSustain()) + { + midi_playing[instance_id] = false; + lcd.setCursor(14 + instance_id, 1); + lcd.write(20); // blank + } +#endif + } #ifdef TEENSY4 - if (midi_decay_timer > 250) - { - midi_decay_timer = 0; - } + if (midi_decay_timer > 250) + { + midi_decay_timer = 0; + } #endif - } - } - else - yield(); + } + } + else + yield(); #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) - if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC) - { - if (master_peak_r.available()) - if (master_peak_r.read() == 1.0) - peak_r++; - if (master_peak_l.available()) - if (master_peak_l.read() == 1.0) - peak_l++; - if (microdexed_peak.available()) - { - peak_dexed_value = microdexed_peak.read(); - if (peak_dexed_value > 0.99) - peak_dexed++; - } - cpu_mem_millis -= SHOW_CPU_LOAD_MSEC; - show_cpu_and_mem_usage(); - } -#endif -} - -/****************************************************************************** - MIDI MESSAGE HANDLER - ******************************************************************************/ -void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) -{ - // Check for MicroDexed - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { - if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) - { - if (configuration.dexed[instance_id].polyphony > 0) - MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); - - midi_voices[instance_id]++; + if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC) + { + if (master_peak_r.available()) + if (master_peak_r.read() == 1.0) + peak_r++; + if (master_peak_l.available()) + if (master_peak_l.read() == 1.0) + peak_l++; + if (microdexed_peak.available()) + { + peak_dexed_value = microdexed_peak.read(); + if (peak_dexed_value > 0.99) + peak_dexed++; + } + cpu_mem_millis -= SHOW_CPU_LOAD_MSEC; + show_cpu_and_mem_usage(); + } +#endif + } + + /****************************************************************************** + MIDI MESSAGE HANDLER + ******************************************************************************/ + void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) + { + // Check for MicroDexed + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { + if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) + { + if (configuration.dexed[instance_id].polyphony > 0) + MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); + + midi_voices[instance_id]++; #ifdef TEENSY4 - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - midi_decay_timer = 0; - midi_decay[instance_id] = min(inVelocity / 5, 7); - } -#endif -#ifdef DEBUG - char note_name[4]; - getNoteName(note_name, inNumber); - Serial.print(F("Keydown ")); - Serial.print(note_name); - Serial.print(F(" instance ")); - Serial.print(instance_id, DEC); - Serial.print(F(" MIDI-channel ")); - Serial.print(inChannel, DEC); - Serial.println(); -#endif - return; - } - } - } + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + midi_decay_timer = 0; + midi_decay[instance_id] = min(inVelocity / 5, 7); + } +#endif +#ifdef DEBUG + char note_name[4]; + getNoteName(note_name, inNumber); + Serial.print(F("Keydown ")); + Serial.print(note_name); + Serial.print(F(" instance ")); + Serial.print(instance_id, DEC); + Serial.print(F(" MIDI-channel ")); + Serial.print(inChannel, DEC); + Serial.println(); +#endif + return; + } + } + } #if NUM_DRUMS > 0 - // Check for Drum - if (inChannel == DRUM_MIDI_CHANNEL) - { - if (drum_counter >= NUM_DRUMS) - drum_counter = 0; - -#ifdef DEBUG - char note_name[4]; - getNoteName(note_name, inNumber); - Serial.print(F("=> Drum[")); - Serial.print(drum_counter, DEC); - Serial.print(F("]: ")); - Serial.println(note_name); -#endif - - for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG; d++) - { - if (inNumber == drum_config[d].midinote) - { - uint8_t slot = drum_get_slot(drum_config[d].drum_class); - float pan = mapfloat(drum_config[d].pan, -1.0, 1.0, 0.0, 1.0); - - drum_mixer_r.gain(slot, (1.0 - pan) * pseudo_log_curve(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); - drum_mixer_l.gain(slot, (pan) * pseudo_log_curve(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); - drum_reverb_send_mixer_r.gain(slot, (1.0 - pan) * pseudo_log_curve(drum_config[d].reverb_send)); - drum_reverb_send_mixer_l.gain(slot, pan * pseudo_log_curve(drum_config[d].reverb_send)); - - if (drum_config[d].drum_data != NULL) - Drum[slot]->play(drum_config[d].drum_data); - -#ifdef DEBUG - Serial.print(F("Drum ")); - Serial.print(drum_config[d].shortname); - Serial.print(F(" [")); - Serial.print(drum_config[d].name); - Serial.print(F("], Slot ")); - Serial.print(slot); - Serial.print(F(": V")); - Serial.print(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max), 2); - Serial.print(F(" P")); - Serial.print(drum_config[d].pan, 2); - Serial.print(F(" PAN")); - Serial.print(pan, 2); - Serial.print(F(" RS")); - Serial.println(drum_config[d].reverb_send, 2); -#endif - break; - } - } - } -#endif -} + // Check for Drum + if (inChannel == DRUM_MIDI_CHANNEL) + { + if (drum_counter >= NUM_DRUMS) + drum_counter = 0; + +#ifdef DEBUG + char note_name[4]; + getNoteName(note_name, inNumber); + Serial.print(F("=> Drum[")); + Serial.print(drum_counter, DEC); + Serial.print(F("]: ")); + Serial.println(note_name); +#endif + + for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG; d++) + { + if (inNumber == drum_config[d].midinote) + { + uint8_t slot = drum_get_slot(drum_config[d].drum_class); + float pan = mapfloat(drum_config[d].pan, -1.0, 1.0, 0.0, 1.0); + + drum_mixer_r.gain(slot, (1.0 - pan) * pseudo_log_curve(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); + drum_mixer_l.gain(slot, (pan) * pseudo_log_curve(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); + drum_reverb_send_mixer_r.gain(slot, (1.0 - pan) * pseudo_log_curve(drum_config[d].reverb_send)); + drum_reverb_send_mixer_l.gain(slot, pan * pseudo_log_curve(drum_config[d].reverb_send)); + + if (drum_config[d].drum_data != NULL) + Drum[slot]->play(drum_config[d].drum_data); + +#ifdef DEBUG + Serial.print(F("Drum ")); + Serial.print(drum_config[d].shortname); + Serial.print(F(" [")); + Serial.print(drum_config[d].name); + Serial.print(F("], Slot ")); + Serial.print(slot); + Serial.print(F(": V")); + Serial.print(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max), 2); + Serial.print(F(" P")); + Serial.print(drum_config[d].pan, 2); + Serial.print(F(" PAN")); + Serial.print(pan, 2); + Serial.print(F(" RS")); + Serial.println(drum_config[d].reverb_send, 2); +#endif + break; + } + } + } +#endif + } #if NUM_DRUMS > 0 -uint8_t drum_get_slot(uint8_t dt) -{ - for (uint8_t i = 0; i < NUM_DRUMS; i++) - { - if (!Drum[i]->isPlaying()) - drum_type[i] = DRUM_NONE; - else - { - if (drum_type[i] == dt) - { -#ifdef DEBUG - Serial.print(F("Stopping Drum ")); - Serial.print(i); - Serial.print(F(" type ")); - Serial.println(dt); -#endif - Drum[i]->stop(); - return (i); - } - } - } -#ifdef DEBUG - Serial.print(F("Using next free Drum slot ")); - Serial.println(drum_counter % 4); -#endif - drum_type[drum_counter % 4] = dt; - drum_counter++; - return (drum_counter - 1 % 4); -} -#endif - -void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { - if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) - { - if (configuration.dexed[instance_id].polyphony > 0) - MicroDexed[instance_id]->keyup(inNumber); - - midi_voices[instance_id]--; -#ifdef DEBUG - char note_name[4]; - getNoteName(note_name, inNumber); - Serial.print(F("KeyUp ")); - Serial.print(note_name); - Serial.print(F(" instance ")); - Serial.print(instance_id, DEC); - Serial.print(F(" MIDI-channel ")); - Serial.print(inChannel, DEC); - Serial.println(); -#endif - } - } - } -} - -void handleControlChange(byte inChannel, byte inCtrl, byte inValue) -{ - inCtrl = constrain(inCtrl, 0, 127); - inValue = constrain(inValue, 0, 127); - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { -#ifdef DEBUG - Serial.print(F("INSTANCE ")); - Serial.print(instance_id, DEC); - Serial.print(F(": CC#")); - Serial.print(inCtrl, DEC); - Serial.print(F(":")); - Serial.println(inValue, DEC); -#endif - - switch (inCtrl) { - case 0: // BankSelect MSB -#ifdef DEBUG - Serial.println(F("BANK-SELECT MSB CC")); -#endif - configuration.performance.bank[instance_id] = constrain((inValue << 7)&configuration.performance.bank[instance_id], 0, MAX_BANKS - 1); - /* load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } */ - break; - case 1: -#ifdef DEBUG - Serial.println(F("MODWHEEL CC")); -#endif - MicroDexed[instance_id]->setModWheel(inValue); - MicroDexed[instance_id]->ControllersRefresh(); - break; - case 2: -#ifdef DEBUG - Serial.println(F("BREATH CC")); -#endif - MicroDexed[instance_id]->setBreathController(inValue); - MicroDexed[instance_id]->ControllersRefresh(); - break; - case 4: -#ifdef DEBUG - Serial.println(F("FOOT CC")); -#endif - MicroDexed[instance_id]->setFootController(inValue); - MicroDexed[instance_id]->ControllersRefresh(); - break; - case 5: // Portamento time - configuration.dexed[instance_id].portamento_time = inValue; - MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); - break; - case 7: // Instance Volume -#ifdef DEBUG - Serial.println(F("VOLUME CC")); -#endif - configuration.dexed[instance_id].sound_intensity = map(inValue, 0, 0x7f, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); - MicroDexed[instance_id]->setGain(pseudo_log_curve(mapfloat(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX))); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sound_intensity)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 10: // Pan -#ifdef DEBUG - Serial.println(F("PANORAMA CC")); -#endif - configuration.dexed[instance_id].pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX); - mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_panorama)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 32: // BankSelect LSB -#ifdef DEBUG - Serial.println(F("BANK-SELECT LSB CC")); -#endif - configuration.performance.bank[instance_id] = constrain(inValue, 0, MAX_BANKS - 1); - /*load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - }*/ - break; - case 64: - MicroDexed[instance_id]->setSustain(inValue > 63); - if (!MicroDexed[instance_id]->getSustain()) - { - for (uint8_t note = 0; note < MicroDexed[instance_id]->getMaxNotes(); note++) - { - if (MicroDexed[instance_id]->voices[note].sustained && !MicroDexed[instance_id]->voices[note].keydown) - { - MicroDexed[instance_id]->voices[note].dx7_note->keyup(); - MicroDexed[instance_id]->voices[note].sustained = false; - } - } - } - break; - case 65: - MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 94: // CC 94: (de)tune - configuration.dexed[selected_instance_id].tune = map(inValue, 0, 0x7f, TUNE_MIN, TUNE_MAX); - MicroDexed[selected_instance_id]->setMasterTune((int((configuration.dexed[selected_instance_id].tune - 100) / 100.0 * 0x4000) << 11) * (1.0 / 12)); - MicroDexed[selected_instance_id]->doRefreshVoice(); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_tune)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; + uint8_t drum_get_slot(uint8_t dt) + { + for (uint8_t i = 0; i < NUM_DRUMS; i++) + { + if (!Drum[i]->isPlaying()) + drum_type[i] = DRUM_NONE; + else + { + if (drum_type[i] == dt) + { +#ifdef DEBUG + Serial.print(F("Stopping Drum ")); + Serial.print(i); + Serial.print(F(" type ")); + Serial.println(dt); +#endif + Drum[i]->stop(); + return (i); + } + } + } +#ifdef DEBUG + Serial.print(F("Using next free Drum slot ")); + Serial.println(drum_counter % 4); +#endif + drum_type[drum_counter % 4] = dt; + drum_counter++; + return (drum_counter - 1 % 4); + } +#endif + + void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { + if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) + { + if (configuration.dexed[instance_id].polyphony > 0) + MicroDexed[instance_id]->keyup(inNumber); + + midi_voices[instance_id]--; +#ifdef DEBUG + char note_name[4]; + getNoteName(note_name, inNumber); + Serial.print(F("KeyUp ")); + Serial.print(note_name); + Serial.print(F(" instance ")); + Serial.print(instance_id, DEC); + Serial.print(F(" MIDI-channel ")); + Serial.print(inChannel, DEC); + Serial.println(); +#endif + } + } + } + } + + void handleControlChange(byte inChannel, byte inCtrl, byte inValue) + { + inCtrl = constrain(inCtrl, 0, 127); + inValue = constrain(inValue, 0, 127); + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { +#ifdef DEBUG + Serial.print(F("INSTANCE ")); + Serial.print(instance_id, DEC); + Serial.print(F(": CC#")); + Serial.print(inCtrl, DEC); + Serial.print(F(":")); + Serial.println(inValue, DEC); +#endif + + switch (inCtrl) { + case 0: // BankSelect MSB +#ifdef DEBUG + Serial.println(F("BANK-SELECT MSB CC")); +#endif + configuration.performance.bank[instance_id] = constrain((inValue << 7)&configuration.performance.bank[instance_id], 0, MAX_BANKS - 1); + /* load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } */ + break; + case 1: +#ifdef DEBUG + Serial.println(F("MODWHEEL CC")); +#endif + MicroDexed[instance_id]->setModWheel(inValue); + MicroDexed[instance_id]->ControllersRefresh(); + break; + case 2: +#ifdef DEBUG + Serial.println(F("BREATH CC")); +#endif + MicroDexed[instance_id]->setBreathController(inValue); + MicroDexed[instance_id]->ControllersRefresh(); + break; + case 4: +#ifdef DEBUG + Serial.println(F("FOOT CC")); +#endif + MicroDexed[instance_id]->setFootController(inValue); + MicroDexed[instance_id]->ControllersRefresh(); + break; + case 5: // Portamento time + configuration.dexed[instance_id].portamento_time = inValue; + MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); + break; + case 7: // Instance Volume +#ifdef DEBUG + Serial.println(F("VOLUME CC")); +#endif + configuration.dexed[instance_id].sound_intensity = map(inValue, 0, 0x7f, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); + MicroDexed[instance_id]->setGain(pseudo_log_curve(mapfloat(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX))); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sound_intensity)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 10: // Pan +#ifdef DEBUG + Serial.println(F("PANORAMA CC")); +#endif + configuration.dexed[instance_id].pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_panorama)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 32: // BankSelect LSB +#ifdef DEBUG + Serial.println(F("BANK-SELECT LSB CC")); +#endif + configuration.performance.bank[instance_id] = constrain(inValue, 0, MAX_BANKS - 1); + /*load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + }*/ + break; + case 64: + MicroDexed[instance_id]->setSustain(inValue > 63); + if (!MicroDexed[instance_id]->getSustain()) + { + for (uint8_t note = 0; note < MicroDexed[instance_id]->getMaxNotes(); note++) + { + if (MicroDexed[instance_id]->voices[note].sustained && !MicroDexed[instance_id]->voices[note].keydown) + { + MicroDexed[instance_id]->voices[note].dx7_note->keyup(); + MicroDexed[instance_id]->voices[note].sustained = false; + } + } + } + break; + case 65: + MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 94: // CC 94: (de)tune + configuration.dexed[selected_instance_id].tune = map(inValue, 0, 0x7f, TUNE_MIN, TUNE_MAX); + MicroDexed[selected_instance_id]->setMasterTune((int((configuration.dexed[selected_instance_id].tune - 100) / 100.0 * 0x4000) << 11) * (1.0 / 12)); + MicroDexed[selected_instance_id]->doRefreshVoice(); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_tune)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; #if defined(USE_FX) - case 91: // CC 91: reverb send - configuration.fx.reverb_send[selected_instance_id] = map(inValue, 0, 0x7f, REVERB_SEND_MIN, REVERB_SEND_MAX); - reverb_mixer_r.gain(selected_instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); - reverb_mixer_l.gain(selected_instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_reverb_send)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 93: // CC 93: chorus level - configuration.fx.chorus_level[selected_instance_id] = map(inValue, 0, 0x7f, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); - chorus_mixer[selected_instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_chorus_level)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 103: // CC 103: filter resonance - configuration.fx.filter_resonance[instance_id] = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); - MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0)); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_resonance)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 104: // CC 104: filter cutoff - configuration.fx.filter_cutoff[instance_id] = map(inValue, 0, 0x7f, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); - MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0));; - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_cutoff)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 105: // CC 105: delay time - configuration.fx.delay_time[instance_id] = map(inValue, 0, 0x7f, DELAY_TIME_MIN, DELAY_TIME_MAX); - delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id] * 10, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10)); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_time)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 106: // CC 106: delay feedback - configuration.fx.delay_feedback[instance_id] = map(inValue, 0, 0x7f, DELAY_FEEDBACK_MIN , DELAY_FEEDBACK_MAX); - delay_fb_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0))); // amount of feedback - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_feedback)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 107: // CC 107: delay volume - configuration.fx.delay_level[instance_id] = map(inValue, 0, 0x7f, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); - delay_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0))); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_level)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; -#endif - case 120: - MicroDexed[instance_id]->panic(); - break; - case 121: - MicroDexed[instance_id]->resetControllers(); - break; - case 123: - MicroDexed[instance_id]->notesOff(); - break; - case 126: - if (inValue > 0) - MicroDexed[instance_id]->setMonoMode(true); - else - MicroDexed[instance_id]->setMonoMode(false); - break; - case 127: - if (inValue > 0) - MicroDexed[instance_id]->setMonoMode(true); - else - MicroDexed[instance_id]->setMonoMode(false); - break; - } - } - } -} - -void handleAfterTouch(byte inChannel, byte inPressure) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { - MicroDexed[instance_id]->setAftertouch(inPressure); - MicroDexed[instance_id]->ControllersRefresh(); - } - } -} - -void handlePitchBend(byte inChannel, int inPitch) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { - MicroDexed[instance_id]->setPitchbend(inPitch); - } - } -} - -void handleProgramChange(byte inChannel, byte inProgram) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (checkMidiChannel(inChannel, instance_id)) - { - configuration.performance.voice[instance_id] = constrain(inProgram, 0, MAX_VOICES - 1); + case 91: // CC 91: reverb send + configuration.fx.reverb_send[selected_instance_id] = map(inValue, 0, 0x7f, REVERB_SEND_MIN, REVERB_SEND_MAX); + reverb_mixer_r.gain(selected_instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); + reverb_mixer_l.gain(selected_instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_reverb_send)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 93: // CC 93: chorus level + configuration.fx.chorus_level[selected_instance_id] = map(inValue, 0, 0x7f, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); + chorus_mixer[selected_instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_chorus_level)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 103: // CC 103: filter resonance + configuration.fx.filter_resonance[instance_id] = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); + MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0)); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_resonance)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 104: // CC 104: filter cutoff + configuration.fx.filter_cutoff[instance_id] = map(inValue, 0, 0x7f, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); + MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0));; + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_cutoff)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 105: // CC 105: delay time + configuration.fx.delay_time[instance_id] = map(inValue, 0, 0x7f, DELAY_TIME_MIN, DELAY_TIME_MAX); + delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id] * 10, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10)); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_time)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 106: // CC 106: delay feedback + configuration.fx.delay_feedback[instance_id] = map(inValue, 0, 0x7f, DELAY_FEEDBACK_MIN , DELAY_FEEDBACK_MAX); + delay_fb_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0))); // amount of feedback + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_feedback)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 107: // CC 107: delay volume + configuration.fx.delay_level[instance_id] = map(inValue, 0, 0x7f, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); + delay_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0))); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_level)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; +#endif + case 120: + MicroDexed[instance_id]->panic(); + break; + case 121: + MicroDexed[instance_id]->resetControllers(); + break; + case 123: + MicroDexed[instance_id]->notesOff(); + break; + case 126: + if (inValue > 0) + MicroDexed[instance_id]->setMonoMode(true); + else + MicroDexed[instance_id]->setMonoMode(false); + break; + case 127: + if (inValue > 0) + MicroDexed[instance_id]->setMonoMode(true); + else + MicroDexed[instance_id]->setMonoMode(false); + break; + } + } + } + } + + void handleAfterTouch(byte inChannel, byte inPressure) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { + MicroDexed[instance_id]->setAftertouch(inPressure); + MicroDexed[instance_id]->ControllersRefresh(); + } + } + } + + void handlePitchBend(byte inChannel, int inPitch) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { + MicroDexed[instance_id]->setPitchbend(inPitch); + } + } + } + + void handleProgramChange(byte inChannel, byte inProgram) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (checkMidiChannel(inChannel, instance_id)) + { + configuration.performance.voice[instance_id] = constrain(inProgram, 0, MAX_VOICES - 1); #ifdef DISPLAY_LCD_SPI - change_disp_sd(false); + change_disp_sd(false); #endif - load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); + load_sd_voice(configuration.performance.bank[instance_id], configuration.performance.voice[instance_id], instance_id); #ifdef DISPLAY_LCD_SPI - change_disp_sd(true); -#endif - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - } - } -} - -void handleSystemExclusive(byte * sysex, uint len) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (!checkMidiChannel((sysex[2] & 0x0f) + 1 , instance_id)) - { -#ifdef DEBUG - Serial.print(F("INSTANCE ")); - Serial.print(instance_id, DEC); - Serial.println(F(": SYSEX-MIDI-Channel mismatch")); -#endif - return; - } - -#ifdef DEBUG - Serial.print(F("SysEx data length: [")); - Serial.print(len); - Serial.println(F("]")); - - Serial.println(F("SysEx data:")); - for (uint16_t i = 0; i < len; i++) - { - Serial.print(F("[0x")); - uint8_t s = sysex[i]; - if (s < 16) - Serial.print(F("0")); - Serial.print(s, HEX); - Serial.print(F("|")); - if (s < 100) - Serial.print(F("0")); - if (s < 10) - Serial.print(F("0")); - Serial.print(s, DEC); - Serial.print(F("]")); - if ((i + 1) % 16 == 0) - Serial.println(); - } - Serial.println(); -#endif - - // Check for SYSEX end byte - if (sysex[len - 1] != 0xf7) - { -#ifdef DEBUG - Serial.println(F("E: SysEx end status byte not detected.")); -#endif - return; - } - - if (sysex[1] != 0x43) // check for Yamaha sysex - { -#ifdef DEBUG - Serial.println(F("E: SysEx vendor not Yamaha.")); -#endif - return; - } - -#ifdef DEBUG - Serial.print(F("Substatus: [")); - Serial.print((sysex[2] & 0x70) >> 4); - Serial.println(F("]")); -#endif - - // parse parameter change - if (len == 7) - { - if (((sysex[3] & 0x7c) >> 2) != 0 && ((sysex[3] & 0x7c) >> 2) != 2) - { -#ifdef DEBUG - Serial.println(F("E: Not a SysEx parameter or function parameter change.")); -#endif - return; - } - - sysex[4] &= 0x7f; - sysex[5] &= 0x7f; - - if ((sysex[3] & 0x7c) >> 2 == 0) - { -#ifdef DEBUG - Serial.println(F("SysEx Voice parameter:")); - Serial.print("Parameter #"); - Serial.print(sysex[4] + ((sysex[3] & 0x03) * 128), DEC); - Serial.print(" Value: "); - Serial.println(sysex[5], DEC); -#endif - MicroDexed[instance_id]->setVoiceDataElement(sysex[4] + ((sysex[3] & 0x03) * 128), sysex[5]); - } - else if ((sysex[3] & 0x7c) >> 2 == 2) - { -#ifdef DEBUG - Serial.println(F("SysEx Function parameter:")); - Serial.print("Parameter #"); - Serial.print(sysex[4], DEC); - Serial.print(" Value: "); - Serial.println(sysex[5], DEC); -#endif - switch (sysex[4]) - { - case 65: - configuration.dexed[instance_id].pb_range = constrain(sysex[5], PB_RANGE_MIN, PB_RANGE_MAX); - MicroDexed[instance_id]->setPitchbendRange(configuration.dexed[instance_id].pb_range); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_pb_range)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 66: - configuration.dexed[instance_id].pb_step = constrain(sysex[5], PB_STEP_MIN, PB_STEP_MAX); - MicroDexed[instance_id]->setPitchbendRange(configuration.dexed[instance_id].pb_step); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_pb_step)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 67: - configuration.dexed[instance_id].portamento_mode = constrain(sysex[5], PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); - MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 68: - configuration.dexed[instance_id].portamento_glissando = constrain(sysex[5], PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); - MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_glissando)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 69: - configuration.dexed[instance_id].portamento_time = constrain(sysex[5], PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); - MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_time)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 70: - configuration.dexed[instance_id].mw_range = constrain(sysex[5], MW_RANGE_MIN, MW_RANGE_MAX); - MicroDexed[instance_id]->setModWheelRange(configuration.dexed[instance_id].mw_range); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_mw_range)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 71: - configuration.dexed[instance_id].mw_assign = constrain(sysex[5], MW_ASSIGN_MIN, MW_ASSIGN_MAX); - MicroDexed[instance_id]->setModWheelTarget(configuration.dexed[instance_id].mw_assign); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_mw_assign)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 72: - configuration.dexed[instance_id].fc_range = constrain(sysex[5], FC_RANGE_MIN, FC_RANGE_MAX); - MicroDexed[instance_id]->setFootControllerRange(configuration.dexed[instance_id].fc_range); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_fc_range)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 73: - configuration.dexed[instance_id].fc_assign = constrain(sysex[5], FC_ASSIGN_MIN, FC_ASSIGN_MAX); - MicroDexed[instance_id]->setFootControllerTarget(configuration.dexed[instance_id].fc_assign); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_fc_assign)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 74: - configuration.dexed[instance_id].bc_range = constrain(sysex[5], BC_RANGE_MIN, BC_RANGE_MAX); - MicroDexed[instance_id]->setBreathControllerRange(configuration.dexed[instance_id].bc_range); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_bc_range)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 75: - configuration.dexed[instance_id].bc_assign = constrain(sysex[5], BC_ASSIGN_MIN, BC_ASSIGN_MAX); - MicroDexed[instance_id]->setBreathControllerTarget(configuration.dexed[instance_id].bc_assign); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_bc_assign)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 76: - configuration.dexed[instance_id].at_range = constrain(sysex[5], AT_RANGE_MIN, AT_RANGE_MAX); - MicroDexed[instance_id]->setAftertouchRange(configuration.dexed[instance_id].at_range); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_at_range)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - case 77: - configuration.dexed[instance_id].at_assign = constrain(sysex[5], AT_ASSIGN_MIN, AT_ASSIGN_MAX); - MicroDexed[instance_id]->setAftertouchTarget(configuration.dexed[instance_id].at_assign); - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_at_assign)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - break; - default: - MicroDexed[instance_id]->setVoiceDataElement(sysex[4], sysex[5]); // set function parameter - break; - } - MicroDexed[instance_id]->ControllersRefresh(); - } -#ifdef DEBUG - else - { - Serial.println(F("E: Unknown SysEx voice or function.")); - } -#endif - } - else if (len == 163) - { - int32_t bulk_checksum_calc = 0; - int8_t bulk_checksum = sysex[161]; - - // 1 Voice bulk upload -#ifdef DEBUG - Serial.println(F("One Voice bulk upload")); -#endif - - if ((sysex[3] & 0x7f) != 0) - { -#ifdef DEBUG - Serial.println(F("E: Not a SysEx voice bulk upload.")); -#endif - return; - } - - if (((sysex[4] << 7) | sysex[5]) != 0x9b) - { -#ifdef DEBUG - Serial.println(F("E: Wrong length for SysEx voice bulk upload (not 155).")); -#endif - return; - } - - // checksum calculation - for (uint8_t i = 0; i < 155 ; i++) - { - bulk_checksum_calc -= sysex[i + 6]; - } - bulk_checksum_calc &= 0x7f; - - if (bulk_checksum_calc != bulk_checksum) - { -#ifdef DEBUG - Serial.print(F("E: Checksum error for one voice [0x")); - Serial.print(bulk_checksum, HEX); - Serial.print(F("/0x")); - Serial.print(bulk_checksum_calc, HEX); - Serial.println(F("]")); + change_disp_sd(true); #endif - return; - } - - // fix voice name - for (uint8_t i = 0; i < 10; i++) - { - if (sysex[151 + i] > 126) // filter characters - sysex[151 + i] = 32; - } - - // load sysex-data into voice memory - MicroDexed[instance_id]->loadVoiceParameters(&sysex[6]); - -#ifdef DEBUG - show_patch(instance_id); -#endif - - // show voice name - strncpy(g_voice_name[instance_id], (char*)&sysex[151], VOICE_NAME_LEN - 1); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + } + } + } + + void handleSystemExclusive(byte * sysex, uint len) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (!checkMidiChannel((sysex[2] & 0x0f) + 1 , instance_id)) + { +#ifdef DEBUG + Serial.print(F("INSTANCE ")); + Serial.print(instance_id, DEC); + Serial.println(F(": SYSEX-MIDI-Channel mismatch")); +#endif + return; + } + +#ifdef DEBUG + Serial.print(F("SysEx data length: [")); + Serial.print(len); + Serial.println(F("]")); + + Serial.println(F("SysEx data:")); + for (uint16_t i = 0; i < len; i++) + { + Serial.print(F("[0x")); + uint8_t s = sysex[i]; + if (s < 16) + Serial.print(F("0")); + Serial.print(s, HEX); + Serial.print(F("|")); + if (s < 100) + Serial.print(F("0")); + if (s < 10) + Serial.print(F("0")); + Serial.print(s, DEC); + Serial.print(F("]")); + if ((i + 1) % 16 == 0) + Serial.println(); + } + Serial.println(); +#endif + + // Check for SYSEX end byte + if (sysex[len - 1] != 0xf7) + { +#ifdef DEBUG + Serial.println(F("E: SysEx end status byte not detected.")); +#endif + return; + } + + if (sysex[1] != 0x43) // check for Yamaha sysex + { +#ifdef DEBUG + Serial.println(F("E: SysEx vendor not Yamaha.")); +#endif + return; + } + +#ifdef DEBUG + Serial.print(F("Substatus: [")); + Serial.print((sysex[2] & 0x70) >> 4); + Serial.println(F("]")); +#endif + + // parse parameter change + if (len == 7) + { + if (((sysex[3] & 0x7c) >> 2) != 0 && ((sysex[3] & 0x7c) >> 2) != 2) + { +#ifdef DEBUG + Serial.println(F("E: Not a SysEx parameter or function parameter change.")); +#endif + return; + } + + sysex[4] &= 0x7f; + sysex[5] &= 0x7f; + + if ((sysex[3] & 0x7c) >> 2 == 0) + { +#ifdef DEBUG + Serial.println(F("SysEx Voice parameter:")); + Serial.print("Parameter #"); + Serial.print(sysex[4] + ((sysex[3] & 0x03) * 128), DEC); + Serial.print(" Value: "); + Serial.println(sysex[5], DEC); +#endif + MicroDexed[instance_id]->setVoiceDataElement(sysex[4] + ((sysex[3] & 0x03) * 128), sysex[5]); + } + else if ((sysex[3] & 0x7c) >> 2 == 2) + { +#ifdef DEBUG + Serial.println(F("SysEx Function parameter:")); + Serial.print("Parameter #"); + Serial.print(sysex[4], DEC); + Serial.print(" Value: "); + Serial.println(sysex[5], DEC); +#endif + switch (sysex[4]) + { + case 65: + configuration.dexed[instance_id].pb_range = constrain(sysex[5], PB_RANGE_MIN, PB_RANGE_MAX); + MicroDexed[instance_id]->setPitchbendRange(configuration.dexed[instance_id].pb_range); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_pb_range)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 66: + configuration.dexed[instance_id].pb_step = constrain(sysex[5], PB_STEP_MIN, PB_STEP_MAX); + MicroDexed[instance_id]->setPitchbendRange(configuration.dexed[instance_id].pb_step); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_pb_step)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 67: + configuration.dexed[instance_id].portamento_mode = constrain(sysex[5], PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); + MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 68: + configuration.dexed[instance_id].portamento_glissando = constrain(sysex[5], PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); + MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_glissando)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 69: + configuration.dexed[instance_id].portamento_time = constrain(sysex[5], PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); + MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_time)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 70: + configuration.dexed[instance_id].mw_range = constrain(sysex[5], MW_RANGE_MIN, MW_RANGE_MAX); + MicroDexed[instance_id]->setModWheelRange(configuration.dexed[instance_id].mw_range); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_mw_range)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 71: + configuration.dexed[instance_id].mw_assign = constrain(sysex[5], MW_ASSIGN_MIN, MW_ASSIGN_MAX); + MicroDexed[instance_id]->setModWheelTarget(configuration.dexed[instance_id].mw_assign); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_mw_assign)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 72: + configuration.dexed[instance_id].fc_range = constrain(sysex[5], FC_RANGE_MIN, FC_RANGE_MAX); + MicroDexed[instance_id]->setFootControllerRange(configuration.dexed[instance_id].fc_range); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_fc_range)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 73: + configuration.dexed[instance_id].fc_assign = constrain(sysex[5], FC_ASSIGN_MIN, FC_ASSIGN_MAX); + MicroDexed[instance_id]->setFootControllerTarget(configuration.dexed[instance_id].fc_assign); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_fc_assign)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 74: + configuration.dexed[instance_id].bc_range = constrain(sysex[5], BC_RANGE_MIN, BC_RANGE_MAX); + MicroDexed[instance_id]->setBreathControllerRange(configuration.dexed[instance_id].bc_range); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_bc_range)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 75: + configuration.dexed[instance_id].bc_assign = constrain(sysex[5], BC_ASSIGN_MIN, BC_ASSIGN_MAX); + MicroDexed[instance_id]->setBreathControllerTarget(configuration.dexed[instance_id].bc_assign); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_bc_assign)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 76: + configuration.dexed[instance_id].at_range = constrain(sysex[5], AT_RANGE_MIN, AT_RANGE_MAX); + MicroDexed[instance_id]->setAftertouchRange(configuration.dexed[instance_id].at_range); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_at_range)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + case 77: + configuration.dexed[instance_id].at_assign = constrain(sysex[5], AT_ASSIGN_MIN, AT_ASSIGN_MAX); + MicroDexed[instance_id]->setAftertouchTarget(configuration.dexed[instance_id].at_assign); + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_at_assign)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + break; + default: + MicroDexed[instance_id]->setVoiceDataElement(sysex[4], sysex[5]); // set function parameter + break; + } + MicroDexed[instance_id]->ControllersRefresh(); + } +#ifdef DEBUG + else + { + Serial.println(F("E: Unknown SysEx voice or function.")); + } +#endif + } + else if (len == 163) + { + int32_t bulk_checksum_calc = 0; + int8_t bulk_checksum = sysex[161]; + + // 1 Voice bulk upload +#ifdef DEBUG + Serial.println(F("One Voice bulk upload")); +#endif + + if ((sysex[3] & 0x7f) != 0) + { +#ifdef DEBUG + Serial.println(F("E: Not a SysEx voice bulk upload.")); +#endif + return; + } + + if (((sysex[4] << 7) | sysex[5]) != 0x9b) + { +#ifdef DEBUG + Serial.println(F("E: Wrong length for SysEx voice bulk upload (not 155).")); +#endif + return; + } + + // checksum calculation + for (uint8_t i = 0; i < 155 ; i++) + { + bulk_checksum_calc -= sysex[i + 6]; + } + bulk_checksum_calc &= 0x7f; + + if (bulk_checksum_calc != bulk_checksum) + { +#ifdef DEBUG + Serial.print(F("E: Checksum error for one voice [0x")); + Serial.print(bulk_checksum, HEX); + Serial.print(F("/0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.println(F("]")); +#endif + return; + } + + // fix voice name + for (uint8_t i = 0; i < 10; i++) + { + if (sysex[151 + i] > 126) // filter characters + sysex[151 + i] = 32; + } + + // load sysex-data into voice memory + MicroDexed[instance_id]->loadVoiceParameters(&sysex[6]); + +#ifdef DEBUG + show_patch(instance_id); +#endif + + // show voice name + strncpy(g_voice_name[instance_id], (char*)&sysex[151], VOICE_NAME_LEN - 1); + + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + } + } + else if (len == 4104) + { + if (strlen(receive_bank_filename) > 0 && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sysex_receive_bank)) + { + int32_t bulk_checksum_calc = 0; + int8_t bulk_checksum = sysex[4102]; - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - LCDML.OTHER_updateFunc(); - LCDML.loop_menu(); - } - } - else if (len == 4104) - { - if (strlen(receive_bank_filename) > 0 && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sysex_receive_bank)) - { - int32_t bulk_checksum_calc = 0; - int8_t bulk_checksum = sysex[4102]; - - // 1 Bank bulk upload - if ((sysex[3] & 0x7f) != 9) - { + // 1 Bank bulk upload + if ((sysex[3] & 0x7f) != 9) + { #ifdef DEBUG - Serial.println(F("E: Not a SysEx bank bulk upload.")); + Serial.println(F("E: Not a SysEx bank bulk upload.")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (TYPE) ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + lcd.setCursor(0, 1); + lcd.print(F("Error (TYPE) ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + return; + } #ifdef DEBUG - Serial.println(F("Bank bulk upload.")); + Serial.println(F("Bank bulk upload.")); #endif - if (((sysex[4] << 7) | sysex[5]) != 0x1000) - { + if (((sysex[4] << 7) | sysex[5]) != 0x1000) + { #ifdef DEBUG - Serial.println(F("E: Wrong length for SysEx bank bulk upload (not 4096).")); + Serial.println(F("E: Wrong length for SysEx bank bulk upload (not 4096).")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (SIZE) ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + lcd.setCursor(0, 1); + lcd.print(F("Error (SIZE) ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + return; + } #ifdef DEBUG - Serial.println(F("Bank type ok")); + Serial.println(F("Bank type ok")); #endif - // checksum calculation - for (uint16_t i = 0; i < 4096 ; i++) - { - bulk_checksum_calc -= sysex[i + 6]; - } - bulk_checksum_calc &= 0x7f; + // checksum calculation + for (uint16_t i = 0; i < 4096 ; i++) + { + bulk_checksum_calc -= sysex[i + 6]; + } + bulk_checksum_calc &= 0x7f; - if (bulk_checksum_calc != bulk_checksum) - { + if (bulk_checksum_calc != bulk_checksum) + { #ifdef DEBUG - Serial.print(F("E: Checksum error for bank [0x")); - Serial.print(bulk_checksum, HEX); - Serial.print(F("/0x")); - Serial.print(bulk_checksum_calc, HEX); - Serial.println(F("]")); + Serial.print(F("E: Checksum error for bank [0x")); + Serial.print(bulk_checksum, HEX); + Serial.print(F("/0x")); + Serial.print(bulk_checksum_calc, HEX); + Serial.println(F("]")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (CHECKSUM)")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + lcd.setCursor(0, 1); + lcd.print(F("Error (CHECKSUM)")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + return; + } #ifdef DEBUG - Serial.println(F("Bank checksum ok")); + Serial.println(F("Bank checksum ok")); #endif - if (save_sd_bank(receive_bank_filename, sysex)) - { + if (save_sd_bank(receive_bank_filename, sysex)) + { #ifdef DEBUG - Serial.print(F("Bank saved as [")); - Serial.print(receive_bank_filename); - Serial.println(F("]")); + Serial.print(F("Bank saved as [")); + Serial.print(receive_bank_filename); + Serial.println(F("]")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Done. ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - } - else - { + lcd.setCursor(0, 1); + lcd.print(F("Done. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + else + { #ifdef DEBUG - Serial.println(F("Error during saving bank as [")); - Serial.print(receive_bank_filename); - Serial.println(F("]")); + Serial.println(F("Error during saving bank as [")); + Serial.print(receive_bank_filename); + Serial.println(F("]")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error. ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - } - memset(receive_bank_filename, 0, FILENAME_LEN); - } + lcd.setCursor(0, 1); + lcd.print(F("Error. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + memset(receive_bank_filename, 0, FILENAME_LEN); + } #ifdef DEBUG - else - Serial.println(F("E: Not in MIDI receive bank mode.")); + else + Serial.println(F("E: Not in MIDI receive bank mode.")); #endif - } + } #ifdef DEBUG - else - Serial.println(F("E: SysEx parameter length wrong.")); + else + Serial.println(F("E: SysEx parameter length wrong.")); #endif - } -} + } + } -void handleTimeCodeQuarterFrame(byte data) -{ - ; -} + void handleTimeCodeQuarterFrame(byte data) + { + ; + } -void handleAfterTouchPoly(byte inChannel, byte inNumber, byte inVelocity) -{ - ; -} + void handleAfterTouchPoly(byte inChannel, byte inNumber, byte inVelocity) + { + ; + } -void handleSongSelect(byte inSong) -{ - ; -} + void handleSongSelect(byte inSong) + { + ; + } -void handleTuneRequest(void) -{ - ; -} + void handleTuneRequest(void) + { + ; + } -void handleClock(void) -{ - if (midi_bpm_counter % 24 == 0) - { - midi_bpm = (60000.0f / float(midi_bpm_timer) + 0.5); + void handleClock(void) + { + if (midi_bpm_counter % 24 == 0) + { + midi_bpm = (60000.0f / float(midi_bpm_timer) + 0.5); - if (_midi_bpm > -1 && _midi_bpm != midi_bpm) - { + if (_midi_bpm > -1 && _midi_bpm != midi_bpm) + { #ifdef DEBUG - Serial.print(F("MIDI Clock: ")); - Serial.print(midi_bpm); - Serial.print(F(" bpm (")); - Serial.print(midi_bpm_timer, DEC); - Serial.println(F("ms per quarter)")); + Serial.print(F("MIDI Clock: ")); + Serial.print(midi_bpm); + Serial.print(F(" bpm (")); + Serial.print(midi_bpm_timer, DEC); + Serial.println(F("ms per quarter)")); #endif #ifdef USE_FX - /* - 1 1/16 = 6 ticks / 0.0625 - 2 1/16T = 9 ticks / 0.09375 - 3 1/8 = 12 ticks / 0.125 - 4 1/8T = 18 ticks / 0.1875 - 5 1/4 = 24 ticks / 0.25 - 6 1/4T = 36 ticks / 0.375 - 7 1/2 = 48 ticks / 0.5 - 8 1/2T = 72 ticks / 0.75 - 9 1/1 = 96 ticks / 1.0 - */ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - if (configuration.fx.delay_sync[instance_id] > 0) - { - uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[configuration.fx.delay_sync[instance_id]] / float(midi_bpm) + 0.5); - delay_fx[instance_id]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10)); -#ifdef DEBUG - Serial.print(F("Setting Delay-Sync of instance ")); - Serial.print(instance_id); - Serial.print(F(" to ")); - Serial.print(constrain(midi_sync_delay_time, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10), DEC); - Serial.println(F(" ms")); -#endif - } - } -#endif - } - - _midi_bpm = midi_bpm; - midi_bpm_counter = 0; - midi_bpm_timer = 0; - } - - midi_bpm_counter++; -} - -void handleStart(void) -{ - midi_bpm_timer = 0; - midi_bpm_counter = 0; - _midi_bpm = -1; -} - -void handleContinue(void) -{ - ; -} - -void handleStop(void) -{ - ; -} - -void handleActiveSensing(void) -{ - ; -} - -void handleSystemReset(void) -{ - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { -#ifdef DEBUG - Serial.println(F("MIDI SYSEX RESET")); -#endif - MicroDexed[instance_id]->notesOff(); - MicroDexed[instance_id]->panic(); - MicroDexed[instance_id]->resetControllers(); - } -} - -/****************************************************************************** - MIDI HELPER - ******************************************************************************/ -bool checkMidiChannel(byte inChannel, uint8_t instance_id) -{ - // check for MIDI channel - if (configuration.dexed[instance_id].midi_channel == MIDI_CHANNEL_OMNI) - { - return (true); - } - else if (inChannel != configuration.dexed[instance_id].midi_channel) - { -#ifdef DEBUG - Serial.print(F("INSTANCE ")); - Serial.print(instance_id, DEC); - Serial.print(F(": Ignoring MIDI data on channel ")); - Serial.print(inChannel); - Serial.print(F("(listening on ")); - Serial.print(configuration.dexed[instance_id].midi_channel); - Serial.println(F(")")); -#endif - return (false); - } - return (true); -} - -void init_MIDI_send_CC(void) -{ -#ifdef DEBUG - Serial.println("init_MIDI_send_CC():"); -#endif - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 7, configuration.dexed[selected_instance_id].sound_intensity); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 10, configuration.dexed[selected_instance_id].pan); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 91, configuration.fx.reverb_send[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 93, configuration.fx.chorus_level[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 94, configuration.dexed[selected_instance_id].tune); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 103, configuration.fx.filter_resonance[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 104, configuration.fx.filter_cutoff[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 105, configuration.fx.delay_time[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 106, configuration.fx.delay_feedback[selected_instance_id]); - MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 107, configuration.fx.delay_level[selected_instance_id]); -} - -/****************************************************************************** - VOLUME HELPER - ******************************************************************************/ - -void set_volume(uint8_t v, uint8_t m) -{ - configuration.sys.vol = v; - - if (configuration.sys.vol > 100) - configuration.sys.vol = 100; - - configuration.sys.mono = m; - -#ifdef DEBUG - Serial.print(F("Setting volume: VOL=")); - Serial.println(v, DEC); -#endif - - volume_r.gain(pseudo_log_curve(v / 100.0)); - volume_l.gain(pseudo_log_curve(v / 100.0)); - - switch (m) - { - case 0: // stereo - stereo2mono.stereo(true); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); - break; - case 1: // mono both - stereo2mono.stereo(false); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_DEFAULT, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); - break; - case 2: // mono right - volume_l.gain(0.0); - stereo2mono.stereo(false); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_MAX, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); - break; - case 3: // mono left - volume_r.gain(0.0); - stereo2mono.stereo(false); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_MIN, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); - break; - } -} - -/****************************************************************************** - EEPROM HELPER - ******************************************************************************/ - -void initial_values_from_eeprom(bool init) -{ - uint16_t _m_; - - if (init == true) - init_configuration(); - else - { - _m_ = (EEPROM[EEPROM_START_ADDRESS + offsetof(configuration_s, _marker_)] << 8) | EEPROM[EEPROM_START_ADDRESS + offsetof(configuration_s, _marker_) + 1]; - if (_m_ != EEPROM_MARKER) - { -#ifdef DEBUG - Serial.println(F("Found wrong EEPROM marker, initializing EEPROM...")); -#endif - configuration._marker_ = EEPROM_MARKER; - init_configuration(); - } - -#ifdef DEBUG - Serial.println(F("Loading initial system data from EEPROM.")); -#endif - - eeprom_get_performance(); - eeprom_get_sys(); - eeprom_get_fx(); - for (uint8_t i = 0; i < NUM_DEXED; i++) - { - eeprom_get_dexed(i); - } - -#ifdef DEBUG - Serial.println(F("OK, loaded!")); -#endif - - check_configuration(); - } - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - set_voiceconfig_params(instance_id); - } - set_fx_params(); - set_sys_params(); - set_volume(configuration.sys.vol, configuration.sys.mono); - -#ifdef DEBUG - show_configuration(); -#endif -} - -void check_configuration(void) -{ - check_configuration_sys(); - check_configuration_fx(); - check_configuration_performance(); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - check_configuration_dexed(instance_id); -} - -void check_configuration_sys(void) -{ - configuration.sys.instances = constrain(configuration.sys.instances, INSTANCES_MIN, INSTANCES_MAX); - configuration.sys.vol = constrain(configuration.sys.vol, VOLUME_MIN, VOLUME_MAX); - configuration.sys.mono = constrain(configuration.sys.mono, MONO_MIN, MONO_MAX); - configuration.sys.soft_midi_thru = constrain(configuration.sys.soft_midi_thru, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); - configuration.sys.performance_number = constrain(configuration.sys.performance_number, PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); -} - -void check_configuration_fx(void) -{ + /* + 1 1/16 = 6 ticks / 0.0625 + 2 1/16T = 9 ticks / 0.09375 + 3 1/8 = 12 ticks / 0.125 + 4 1/8T = 18 ticks / 0.1875 + 5 1/4 = 24 ticks / 0.25 + 6 1/4T = 36 ticks / 0.375 + 7 1/2 = 48 ticks / 0.5 + 8 1/2T = 72 ticks / 0.75 + 9 1/1 = 96 ticks / 1.0 + */ + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + if (configuration.fx.delay_sync[instance_id] > 0) + { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[configuration.fx.delay_sync[instance_id]] / float(midi_bpm) + 0.5); + delay_fx[instance_id]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10)); +#ifdef DEBUG + Serial.print(F("Setting Delay-Sync of instance ")); + Serial.print(instance_id); + Serial.print(F(" to ")); + Serial.print(constrain(midi_sync_delay_time, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10), DEC); + Serial.println(F(" ms")); +#endif + } + } +#endif + } + + _midi_bpm = midi_bpm; + midi_bpm_counter = 0; + midi_bpm_timer = 0; + } + + midi_bpm_counter++; + } + + void handleStart(void) + { + midi_bpm_timer = 0; + midi_bpm_counter = 0; + _midi_bpm = -1; + } + + void handleContinue(void) + { + ; + } + + void handleStop(void) + { + ; + } + + void handleActiveSensing(void) + { + ; + } + + void handleSystemReset(void) + { + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { +#ifdef DEBUG + Serial.println(F("MIDI SYSEX RESET")); +#endif + MicroDexed[instance_id]->notesOff(); + MicroDexed[instance_id]->panic(); + MicroDexed[instance_id]->resetControllers(); + } + } + + /****************************************************************************** + MIDI HELPER + ******************************************************************************/ + bool checkMidiChannel(byte inChannel, uint8_t instance_id) + { + // check for MIDI channel + if (configuration.dexed[instance_id].midi_channel == MIDI_CHANNEL_OMNI) + { + return (true); + } + else if (inChannel != configuration.dexed[instance_id].midi_channel) + { +#ifdef DEBUG + Serial.print(F("INSTANCE ")); + Serial.print(instance_id, DEC); + Serial.print(F(": Ignoring MIDI data on channel ")); + Serial.print(inChannel); + Serial.print(F("(listening on ")); + Serial.print(configuration.dexed[instance_id].midi_channel); + Serial.println(F(")")); +#endif + return (false); + } + return (true); + } + + void init_MIDI_send_CC(void) + { +#ifdef DEBUG + Serial.println("init_MIDI_send_CC():"); +#endif + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 7, configuration.dexed[selected_instance_id].sound_intensity); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 10, configuration.dexed[selected_instance_id].pan); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 91, configuration.fx.reverb_send[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 93, configuration.fx.chorus_level[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 94, configuration.dexed[selected_instance_id].tune); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 103, configuration.fx.filter_resonance[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 104, configuration.fx.filter_cutoff[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 105, configuration.fx.delay_time[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 106, configuration.fx.delay_feedback[selected_instance_id]); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 107, configuration.fx.delay_level[selected_instance_id]); + } + + /****************************************************************************** + VOLUME HELPER + ******************************************************************************/ + + void set_volume(uint8_t v, uint8_t m) + { + configuration.sys.vol = v; + + if (configuration.sys.vol > 100) + configuration.sys.vol = 100; + + configuration.sys.mono = m; + +#ifdef DEBUG + Serial.print(F("Setting volume: VOL=")); + Serial.println(v, DEC); +#endif + + volume_r.gain(pseudo_log_curve(v / 100.0)); + volume_l.gain(pseudo_log_curve(v / 100.0)); + + switch (m) + { + case 0: // stereo + stereo2mono.stereo(true); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + break; + case 1: // mono both + stereo2mono.stereo(false); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_DEFAULT, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + break; + case 2: // mono right + volume_l.gain(0.0); + stereo2mono.stereo(false); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_MAX, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + break; + case 3: // mono left + volume_r.gain(0.0); + stereo2mono.stereo(false); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + mono2stereo[instance_id]->panorama(mapfloat(PANORAMA_MIN, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + break; + } + } + + /****************************************************************************** + EEPROM HELPER + ******************************************************************************/ + + void initial_values_from_eeprom(bool init) + { + uint16_t _m_; + + if (init == true) + init_configuration(); + else + { + _m_ = (EEPROM[EEPROM_START_ADDRESS + offsetof(configuration_s, _marker_)] << 8) | EEPROM[EEPROM_START_ADDRESS + offsetof(configuration_s, _marker_) + 1]; + if (_m_ != EEPROM_MARKER) + { +#ifdef DEBUG + Serial.println(F("Found wrong EEPROM marker, initializing EEPROM...")); +#endif + configuration._marker_ = EEPROM_MARKER; + init_configuration(); + } + +#ifdef DEBUG + Serial.println(F("Loading initial system data from EEPROM.")); +#endif + + eeprom_get_performance(); + eeprom_get_sys(); + eeprom_get_fx(); + for (uint8_t i = 0; i < NUM_DEXED; i++) + { + eeprom_get_dexed(i); + } + +#ifdef DEBUG + Serial.println(F("OK, loaded!")); +#endif + + check_configuration(); + } + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + set_voiceconfig_params(instance_id); + } + set_fx_params(); + set_sys_params(); + set_volume(configuration.sys.vol, configuration.sys.mono); + +#ifdef DEBUG + show_configuration(); +#endif + } + + void check_configuration(void) + { + check_configuration_sys(); + check_configuration_fx(); + check_configuration_performance(); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + check_configuration_dexed(instance_id); + } + + void check_configuration_sys(void) + { + configuration.sys.instances = constrain(configuration.sys.instances, INSTANCES_MIN, INSTANCES_MAX); + configuration.sys.vol = constrain(configuration.sys.vol, VOLUME_MIN, VOLUME_MAX); + configuration.sys.mono = constrain(configuration.sys.mono, MONO_MIN, MONO_MAX); + configuration.sys.soft_midi_thru = constrain(configuration.sys.soft_midi_thru, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); + configuration.sys.performance_number = constrain(configuration.sys.performance_number, PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); + } + + void check_configuration_fx(void) + { #ifdef USE_PLATEREVERB - configuration.fx.reverb_lowpass = constrain(configuration.fx.reverb_lowpass, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX); - configuration.fx.reverb_lodamp = constrain(configuration.fx.reverb_lodamp, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX); - configuration.fx.reverb_hidamp = constrain(configuration.fx.reverb_hidamp, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX); - configuration.fx.reverb_diffusion = constrain(configuration.fx.reverb_diffusion, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX); + configuration.fx.reverb_lowpass = constrain(configuration.fx.reverb_lowpass, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX); + configuration.fx.reverb_lodamp = constrain(configuration.fx.reverb_lodamp, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX); + configuration.fx.reverb_hidamp = constrain(configuration.fx.reverb_hidamp, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX); + configuration.fx.reverb_diffusion = constrain(configuration.fx.reverb_diffusion, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX); #else - configuration.fx.reverb_damping = constrain(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); -#endif - configuration.fx.reverb_roomsize = constrain(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); - configuration.fx.reverb_level = constrain(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - configuration.fx.filter_cutoff[instance_id] = constrain(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); - configuration.fx.filter_resonance[instance_id] = constrain(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); - configuration.fx.chorus_frequency[instance_id] = constrain(configuration.fx.chorus_frequency[instance_id], CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); - configuration.fx.chorus_waveform[instance_id] = constrain(configuration.fx.chorus_waveform[instance_id], CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); - configuration.fx.chorus_depth[instance_id] = constrain(configuration.fx.chorus_depth[instance_id], CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); - configuration.fx.chorus_level[instance_id] = constrain(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); - configuration.fx.delay_time[instance_id] = constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX); - configuration.fx.delay_feedback[instance_id] = constrain(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); - configuration.fx.delay_level[instance_id] = constrain(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); - configuration.fx.delay_sync[instance_id] = constrain(configuration.fx.delay_sync[instance_id], DELAY_SYNC_MIN, DELAY_SYNC_MAX); - configuration.fx.reverb_send[instance_id] = constrain(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX); - } -} - -void check_configuration_performance(void) -{ - configuration.performance.fx_number = constrain(configuration.performance.fx_number, FX_NUM_MIN, FX_NUM_MAX); - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - configuration.performance.bank[instance_id] = constrain(configuration.performance.bank[instance_id], 0, MAX_BANKS - 1); - configuration.performance.voice[instance_id] = constrain(configuration.performance.voice[instance_id], 0, MAX_VOICES - 1); - configuration.performance.voiceconfig_number[instance_id] = constrain(configuration.performance.voiceconfig_number[instance_id], VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); - } -} - -void check_configuration_dexed(uint8_t instance_id) -{ - configuration.dexed[instance_id].midi_channel = constrain(configuration.dexed[instance_id].midi_channel, MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); - 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].sound_intensity = constrain(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); - configuration.dexed[instance_id].pan = constrain(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX); - configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose, TRANSPOSE_MIN, TRANSPOSE_MAX); - configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune, TUNE_MIN, TUNE_MAX); - configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony, POLYPHONY_MIN, POLYPHONY_MAX); - configuration.dexed[instance_id].velocity_level = constrain(configuration.dexed[instance_id].velocity_level, VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); - configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly, MONOPOLY_MIN, MONOPOLY_MAX); - configuration.dexed[instance_id].note_refresh = constrain(configuration.dexed[instance_id].note_refresh, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); - configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range, PB_RANGE_MIN, PB_RANGE_MAX); - configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step, PB_STEP_MIN, PB_STEP_MAX); - configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range, MW_RANGE_MIN, MW_RANGE_MAX); - configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign, MW_ASSIGN_MIN, MW_ASSIGN_MAX); - configuration.dexed[instance_id].mw_mode = constrain(configuration.dexed[instance_id].mw_mode, MW_MODE_MIN, MW_MODE_MAX); - configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range, FC_RANGE_MIN, FC_RANGE_MAX); - configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign, FC_ASSIGN_MIN, FC_ASSIGN_MAX); - configuration.dexed[instance_id].fc_mode = constrain(configuration.dexed[instance_id].fc_mode, FC_MODE_MIN, FC_MODE_MAX); - configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range, BC_RANGE_MIN, BC_RANGE_MAX); - configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign, BC_ASSIGN_MIN, BC_ASSIGN_MAX); - configuration.dexed[instance_id].bc_mode = constrain(configuration.dexed[instance_id].bc_mode, BC_MODE_MIN, BC_MODE_MAX); - configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range, AT_RANGE_MIN, AT_RANGE_MAX); - configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign, AT_ASSIGN_MIN, AT_ASSIGN_MAX); - configuration.dexed[instance_id].at_mode = constrain(configuration.dexed[instance_id].at_mode, AT_MODE_MIN, AT_MODE_MAX); - configuration.dexed[instance_id].portamento_mode = constrain(configuration.dexed[instance_id].portamento_mode, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); - configuration.dexed[instance_id].portamento_glissando = constrain(configuration.dexed[instance_id].portamento_glissando, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); - configuration.dexed[instance_id].portamento_time = constrain(configuration.dexed[instance_id].portamento_time, PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); - configuration.dexed[instance_id].op_enabled = constrain(configuration.dexed[instance_id].op_enabled, OP_ENABLED_MIN, OP_ENABLED_MAX); -} - -void init_configuration(void) -{ -#ifdef DEBUG - Serial.println(F("INITIALIZING CONFIGURATION")); -#endif - - configuration.sys.instances = INSTANCES_DEFAULT; - configuration.sys.vol = VOLUME_DEFAULT; - configuration.sys.mono = MONO_DEFAULT; - configuration.sys.soft_midi_thru = SOFT_MIDI_THRU_DEFAULT; - configuration.sys.performance_number = PERFORMANCE_NUM_DEFAULT; + configuration.fx.reverb_damping = constrain(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); +#endif + configuration.fx.reverb_roomsize = constrain(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); + configuration.fx.reverb_level = constrain(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + configuration.fx.filter_cutoff[instance_id] = constrain(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); + configuration.fx.filter_resonance[instance_id] = constrain(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); + configuration.fx.chorus_frequency[instance_id] = constrain(configuration.fx.chorus_frequency[instance_id], CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); + configuration.fx.chorus_waveform[instance_id] = constrain(configuration.fx.chorus_waveform[instance_id], CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); + configuration.fx.chorus_depth[instance_id] = constrain(configuration.fx.chorus_depth[instance_id], CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); + configuration.fx.chorus_level[instance_id] = constrain(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); + configuration.fx.delay_time[instance_id] = constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX); + configuration.fx.delay_feedback[instance_id] = constrain(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); + configuration.fx.delay_level[instance_id] = constrain(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); + configuration.fx.delay_sync[instance_id] = constrain(configuration.fx.delay_sync[instance_id], DELAY_SYNC_MIN, DELAY_SYNC_MAX); + configuration.fx.reverb_send[instance_id] = constrain(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX); + } + } + + void check_configuration_performance(void) + { + configuration.performance.fx_number = constrain(configuration.performance.fx_number, FX_NUM_MIN, FX_NUM_MAX); + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + configuration.performance.bank[instance_id] = constrain(configuration.performance.bank[instance_id], 0, MAX_BANKS - 1); + configuration.performance.voice[instance_id] = constrain(configuration.performance.voice[instance_id], 0, MAX_VOICES - 1); + configuration.performance.voiceconfig_number[instance_id] = constrain(configuration.performance.voiceconfig_number[instance_id], VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); + } + } + + void check_configuration_dexed(uint8_t instance_id) + { + configuration.dexed[instance_id].midi_channel = constrain(configuration.dexed[instance_id].midi_channel, MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); + 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].sound_intensity = constrain(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); + configuration.dexed[instance_id].pan = constrain(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX); + configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose, TRANSPOSE_MIN, TRANSPOSE_MAX); + configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune, TUNE_MIN, TUNE_MAX); + configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony, POLYPHONY_MIN, POLYPHONY_MAX); + configuration.dexed[instance_id].velocity_level = constrain(configuration.dexed[instance_id].velocity_level, VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); + configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly, MONOPOLY_MIN, MONOPOLY_MAX); + configuration.dexed[instance_id].note_refresh = constrain(configuration.dexed[instance_id].note_refresh, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); + configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range, PB_RANGE_MIN, PB_RANGE_MAX); + configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step, PB_STEP_MIN, PB_STEP_MAX); + configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range, MW_RANGE_MIN, MW_RANGE_MAX); + configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign, MW_ASSIGN_MIN, MW_ASSIGN_MAX); + configuration.dexed[instance_id].mw_mode = constrain(configuration.dexed[instance_id].mw_mode, MW_MODE_MIN, MW_MODE_MAX); + configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range, FC_RANGE_MIN, FC_RANGE_MAX); + configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign, FC_ASSIGN_MIN, FC_ASSIGN_MAX); + configuration.dexed[instance_id].fc_mode = constrain(configuration.dexed[instance_id].fc_mode, FC_MODE_MIN, FC_MODE_MAX); + configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range, BC_RANGE_MIN, BC_RANGE_MAX); + configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign, BC_ASSIGN_MIN, BC_ASSIGN_MAX); + configuration.dexed[instance_id].bc_mode = constrain(configuration.dexed[instance_id].bc_mode, BC_MODE_MIN, BC_MODE_MAX); + configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range, AT_RANGE_MIN, AT_RANGE_MAX); + configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign, AT_ASSIGN_MIN, AT_ASSIGN_MAX); + configuration.dexed[instance_id].at_mode = constrain(configuration.dexed[instance_id].at_mode, AT_MODE_MIN, AT_MODE_MAX); + configuration.dexed[instance_id].portamento_mode = constrain(configuration.dexed[instance_id].portamento_mode, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); + configuration.dexed[instance_id].portamento_glissando = constrain(configuration.dexed[instance_id].portamento_glissando, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); + configuration.dexed[instance_id].portamento_time = constrain(configuration.dexed[instance_id].portamento_time, PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); + configuration.dexed[instance_id].op_enabled = constrain(configuration.dexed[instance_id].op_enabled, OP_ENABLED_MIN, OP_ENABLED_MAX); + } + + void init_configuration(void) + { +#ifdef DEBUG + Serial.println(F("INITIALIZING CONFIGURATION")); +#endif + + configuration.sys.instances = INSTANCES_DEFAULT; + configuration.sys.vol = VOLUME_DEFAULT; + configuration.sys.mono = MONO_DEFAULT; + configuration.sys.soft_midi_thru = SOFT_MIDI_THRU_DEFAULT; + configuration.sys.performance_number = PERFORMANCE_NUM_DEFAULT; #ifdef USE_PLATEREVERB - configuration.fx.reverb_lowpass = REVERB_LOWPASS_DEFAULT; - configuration.fx.reverb_lodamp = REVERB_LODAMP_DEFAULT; - configuration.fx.reverb_hidamp = REVERB_HIDAMP_DEFAULT; - configuration.fx.reverb_diffusion = REVERB_DIFFUSION_DEFAULT; + configuration.fx.reverb_lowpass = REVERB_LOWPASS_DEFAULT; + configuration.fx.reverb_lodamp = REVERB_LODAMP_DEFAULT; + configuration.fx.reverb_hidamp = REVERB_HIDAMP_DEFAULT; + configuration.fx.reverb_diffusion = REVERB_DIFFUSION_DEFAULT; #else - configuration.fx.reverb_damping = REVERB_DAMPING_DEFAULT; -#endif - - configuration.fx.reverb_roomsize = REVERB_ROOMSIZE_DEFAULT; - configuration.fx.reverb_level = REVERB_LEVEL_DEFAULT; - - configuration.performance.fx_number = FX_NUM_DEFAULT; - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT; - configuration.performance.voice[instance_id] = SYSEXSOUND_DEFAULT; - configuration.performance.voiceconfig_number[instance_id] = VOICECONFIG_NUM_DEFAULT; - - configuration.dexed[instance_id].midi_channel = DEFAULT_MIDI_CHANNEL; - configuration.dexed[instance_id].lowest_note = INSTANCE_LOWEST_NOTE_MIN; - configuration.dexed[instance_id].highest_note = INSTANCE_HIGHEST_NOTE_MAX; - configuration.dexed[instance_id].sound_intensity = SOUND_INTENSITY_DEFAULT; - configuration.dexed[instance_id].pan = PANORAMA_DEFAULT; - configuration.dexed[instance_id].transpose = TRANSPOSE_DEFAULT; - configuration.dexed[instance_id].tune = TUNE_DEFAULT; - configuration.dexed[instance_id].polyphony = POLYPHONY_DEFAULT; - configuration.dexed[instance_id].velocity_level = VELOCITY_LEVEL_DEFAULT; - configuration.dexed[instance_id].monopoly = MONOPOLY_DEFAULT; - configuration.dexed[instance_id].note_refresh = NOTE_REFRESH_DEFAULT; - configuration.dexed[instance_id].pb_range = PB_RANGE_DEFAULT; - configuration.dexed[instance_id].pb_step = PB_STEP_DEFAULT; - configuration.dexed[instance_id].mw_range = MW_RANGE_DEFAULT; - configuration.dexed[instance_id].mw_assign = MW_ASSIGN_DEFAULT; - configuration.dexed[instance_id].mw_mode = MW_MODE_DEFAULT; - configuration.dexed[instance_id].fc_range = FC_RANGE_DEFAULT; - configuration.dexed[instance_id].fc_assign = FC_ASSIGN_DEFAULT; - configuration.dexed[instance_id].fc_mode = FC_MODE_DEFAULT; - configuration.dexed[instance_id].bc_range = BC_RANGE_DEFAULT; - configuration.dexed[instance_id].bc_assign = BC_ASSIGN_DEFAULT; - configuration.dexed[instance_id].bc_mode = BC_MODE_DEFAULT; - configuration.dexed[instance_id].at_range = AT_RANGE_DEFAULT; - configuration.dexed[instance_id].at_assign = AT_ASSIGN_DEFAULT; - configuration.dexed[instance_id].at_mode = AT_MODE_DEFAULT; - configuration.dexed[instance_id].portamento_mode = PORTAMENTO_MODE_DEFAULT; - configuration.dexed[instance_id].portamento_glissando = PORTAMENTO_GLISSANDO_DEFAULT; - configuration.dexed[instance_id].portamento_time = PORTAMENTO_TIME_DEFAULT; - configuration.dexed[instance_id].op_enabled = OP_ENABLED_DEFAULT; - - configuration.fx.filter_cutoff[instance_id] = FILTER_CUTOFF_DEFAULT; - configuration.fx.filter_resonance[instance_id] = FILTER_RESONANCE_DEFAULT; - configuration.fx.chorus_frequency[instance_id] = CHORUS_FREQUENCY_DEFAULT; - configuration.fx.chorus_waveform[instance_id] = CHORUS_WAVEFORM_DEFAULT; - configuration.fx.chorus_depth[instance_id] = CHORUS_DEPTH_DEFAULT; - configuration.fx.chorus_level[instance_id] = CHORUS_LEVEL_DEFAULT; - configuration.fx.delay_time[instance_id] = DELAY_TIME_DEFAULT / 10; - configuration.fx.delay_feedback[instance_id] = DELAY_FEEDBACK_DEFAULT; - configuration.fx.delay_level[instance_id] = DELAY_LEVEL_DEFAULT; - configuration.fx.delay_sync[instance_id] = DELAY_SYNC_DEFAULT; - configuration.fx.reverb_send[instance_id] = REVERB_SEND_DEFAULT; - - configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT; - configuration.performance.voice[instance_id] = SYSEXSOUND_DEFAULT; - - configuration.dexed[instance_id].polyphony = POLYPHONY_DEFAULT; - - MicroDexed[instance_id]->ControllersRefresh(); - } - - set_volume(configuration.sys.vol, configuration.sys.mono); - - eeprom_update(); -} - -void eeprom_update(void) -{ - uint8_t* c = (uint8_t*)&configuration; - for (uint16_t i = 0; i < sizeof(configuration); i++) - EEPROM.update(EEPROM_START_ADDRESS + i, c[i]); -} - -void eeprom_update_sys(void) -{ - uint8_t* c = (uint8_t*)&configuration.sys; - - for (uint16_t i = 0; i < sizeof(configuration.sys); i++) - EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys) + i, c[i]); - -#ifdef DEBUG - Serial.println(F("Updating EEPROM sys.")); -#endif -} - -bool eeprom_get_sys(void) -{ - EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, sys), configuration.sys); - return (true); -} - -void eeprom_update_fx(void) -{ - uint8_t* c = (uint8_t*)&configuration.fx; - - for (uint16_t i = 0; i < sizeof(configuration.fx); i++) - EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx) + i, c[i]); - -#ifdef DEBUG - Serial.println(F("Updating EEPROM fx.")); -#endif -} - -bool eeprom_get_fx(void) -{ - EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, fx), configuration.fx); - return (true); -} - -void eeprom_update_dexed(uint8_t instance_id) -{ + configuration.fx.reverb_damping = REVERB_DAMPING_DEFAULT; +#endif + + configuration.fx.reverb_roomsize = REVERB_ROOMSIZE_DEFAULT; + configuration.fx.reverb_level = REVERB_LEVEL_DEFAULT; + + configuration.performance.fx_number = FX_NUM_DEFAULT; + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT; + configuration.performance.voice[instance_id] = SYSEXSOUND_DEFAULT; + configuration.performance.voiceconfig_number[instance_id] = VOICECONFIG_NUM_DEFAULT; + + configuration.dexed[instance_id].midi_channel = DEFAULT_MIDI_CHANNEL; + configuration.dexed[instance_id].lowest_note = INSTANCE_LOWEST_NOTE_MIN; + configuration.dexed[instance_id].highest_note = INSTANCE_HIGHEST_NOTE_MAX; + configuration.dexed[instance_id].sound_intensity = SOUND_INTENSITY_DEFAULT; + configuration.dexed[instance_id].pan = PANORAMA_DEFAULT; + configuration.dexed[instance_id].transpose = TRANSPOSE_DEFAULT; + configuration.dexed[instance_id].tune = TUNE_DEFAULT; + configuration.dexed[instance_id].polyphony = POLYPHONY_DEFAULT; + configuration.dexed[instance_id].velocity_level = VELOCITY_LEVEL_DEFAULT; + configuration.dexed[instance_id].monopoly = MONOPOLY_DEFAULT; + configuration.dexed[instance_id].note_refresh = NOTE_REFRESH_DEFAULT; + configuration.dexed[instance_id].pb_range = PB_RANGE_DEFAULT; + configuration.dexed[instance_id].pb_step = PB_STEP_DEFAULT; + configuration.dexed[instance_id].mw_range = MW_RANGE_DEFAULT; + configuration.dexed[instance_id].mw_assign = MW_ASSIGN_DEFAULT; + configuration.dexed[instance_id].mw_mode = MW_MODE_DEFAULT; + configuration.dexed[instance_id].fc_range = FC_RANGE_DEFAULT; + configuration.dexed[instance_id].fc_assign = FC_ASSIGN_DEFAULT; + configuration.dexed[instance_id].fc_mode = FC_MODE_DEFAULT; + configuration.dexed[instance_id].bc_range = BC_RANGE_DEFAULT; + configuration.dexed[instance_id].bc_assign = BC_ASSIGN_DEFAULT; + configuration.dexed[instance_id].bc_mode = BC_MODE_DEFAULT; + configuration.dexed[instance_id].at_range = AT_RANGE_DEFAULT; + configuration.dexed[instance_id].at_assign = AT_ASSIGN_DEFAULT; + configuration.dexed[instance_id].at_mode = AT_MODE_DEFAULT; + configuration.dexed[instance_id].portamento_mode = PORTAMENTO_MODE_DEFAULT; + configuration.dexed[instance_id].portamento_glissando = PORTAMENTO_GLISSANDO_DEFAULT; + configuration.dexed[instance_id].portamento_time = PORTAMENTO_TIME_DEFAULT; + configuration.dexed[instance_id].op_enabled = OP_ENABLED_DEFAULT; + + configuration.fx.filter_cutoff[instance_id] = FILTER_CUTOFF_DEFAULT; + configuration.fx.filter_resonance[instance_id] = FILTER_RESONANCE_DEFAULT; + configuration.fx.chorus_frequency[instance_id] = CHORUS_FREQUENCY_DEFAULT; + configuration.fx.chorus_waveform[instance_id] = CHORUS_WAVEFORM_DEFAULT; + configuration.fx.chorus_depth[instance_id] = CHORUS_DEPTH_DEFAULT; + configuration.fx.chorus_level[instance_id] = CHORUS_LEVEL_DEFAULT; + configuration.fx.delay_time[instance_id] = DELAY_TIME_DEFAULT / 10; + configuration.fx.delay_feedback[instance_id] = DELAY_FEEDBACK_DEFAULT; + configuration.fx.delay_level[instance_id] = DELAY_LEVEL_DEFAULT; + configuration.fx.delay_sync[instance_id] = DELAY_SYNC_DEFAULT; + configuration.fx.reverb_send[instance_id] = REVERB_SEND_DEFAULT; + + configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT; + configuration.performance.voice[instance_id] = SYSEXSOUND_DEFAULT; + + configuration.dexed[instance_id].polyphony = POLYPHONY_DEFAULT; + + MicroDexed[instance_id]->ControllersRefresh(); + } + + set_volume(configuration.sys.vol, configuration.sys.mono); + + eeprom_update(); + } + + void eeprom_update(void) + { + uint8_t* c = (uint8_t*)&configuration; + for (uint16_t i = 0; i < sizeof(configuration); i++) + EEPROM.update(EEPROM_START_ADDRESS + i, c[i]); + } + + void eeprom_update_sys(void) + { + uint8_t* c = (uint8_t*)&configuration.sys; + + for (uint16_t i = 0; i < sizeof(configuration.sys); i++) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys) + i, c[i]); + +#ifdef DEBUG + Serial.println(F("Updating EEPROM sys.")); +#endif + } + + bool eeprom_get_sys(void) + { + EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, sys), configuration.sys); + return (true); + } + + void eeprom_update_fx(void) + { + uint8_t* c = (uint8_t*)&configuration.fx; + + for (uint16_t i = 0; i < sizeof(configuration.fx); i++) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx) + i, c[i]); + +#ifdef DEBUG + Serial.println(F("Updating EEPROM fx.")); +#endif + } + + bool eeprom_get_fx(void) + { + EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, fx), configuration.fx); + return (true); + } + + void eeprom_update_dexed(uint8_t instance_id) + { #if NUM_DEXED == 1 - uint8_t* c = (uint8_t*)&configuration.dexed[0]; + uint8_t* c = (uint8_t*)&configuration.dexed[0]; - for (uint16_t i = 0; i < sizeof(configuration.dexed[0]); i++) - EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]) + i, c[i]); + for (uint16_t i = 0; i < sizeof(configuration.dexed[0]); i++) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]) + i, c[i]); #else - uint8_t* c; + uint8_t* c; - if (instance_id == 0) - c = (uint8_t*)&configuration.dexed[0]; - else - c = (uint8_t*)&configuration.dexed[1]; + if (instance_id == 0) + c = (uint8_t*)&configuration.dexed[0]; + else + c = (uint8_t*)&configuration.dexed[1]; - for (uint16_t i = 0; i < sizeof(configuration.dexed[instance_id]); i++) - { - if (instance_id == 0) - EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]) + i, c[i]); - else - EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1]) + i, c[i]); - } + for (uint16_t i = 0; i < sizeof(configuration.dexed[instance_id]); i++) + { + if (instance_id == 0) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]) + i, c[i]); + else + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1]) + i, c[i]); + } #endif #ifdef DEBUG - Serial.print(F("Updating EEPROM dexed (instance ")); - Serial.print(instance_id); - Serial.println(F(").")); + Serial.print(F("Updating EEPROM dexed (instance ")); + Serial.print(instance_id); + Serial.println(F(").")); #endif -} + } -bool eeprom_get_dexed(uint8_t instance_id) -{ - for (uint8_t instance_id = 0; instance_id < MAX_DEXED; instance_id++) - { - if (instance_id == 0) - EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]), configuration.dexed[0]); - else - EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1]), configuration.dexed[1]); - } - return (true); -} + bool eeprom_get_dexed(uint8_t instance_id) + { + for (uint8_t instance_id = 0; instance_id < MAX_DEXED; instance_id++) + { + if (instance_id == 0) + EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0]), configuration.dexed[0]); + else + EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1]), configuration.dexed[1]); + } + return (true); + } -void eeprom_update_performance() -{ - EEPROM.put(EEPROM_START_ADDRESS + offsetof(configuration_s, performance), configuration.performance); + void eeprom_update_performance() + { + EEPROM.put(EEPROM_START_ADDRESS + offsetof(configuration_s, performance), configuration.performance); #ifdef DEBUG - Serial.println(F("Updating EEPROM performance.")); + Serial.println(F("Updating EEPROM performance.")); #endif -} + } -bool eeprom_get_performance() -{ - EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, performance), configuration.performance); + bool eeprom_get_performance() + { + EEPROM.get(EEPROM_START_ADDRESS + offsetof(configuration_s, performance), configuration.performance); #ifdef DEBUG - Serial.println(F("Getting EEPROM performance.")); + Serial.println(F("Getting EEPROM performance.")); #endif - return (true); -} + return (true); + } -/****************************************************************************** - PARAMETER-HELPERS -******************************************************************************/ + /****************************************************************************** + PARAMETER-HELPERS + ******************************************************************************/ -void set_fx_params(void) -{ + void set_fx_params(void) + { #if defined(USE_FX) - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - // CHORUS - switch (configuration.fx.chorus_waveform[instance_id]) - { - case 0: - chorus_modulator[instance_id]->begin(WAVEFORM_TRIANGLE); - break; - case 1: - chorus_modulator[instance_id]->begin(WAVEFORM_SINE); - break; - default: - chorus_modulator[instance_id]->begin(WAVEFORM_TRIANGLE); - } - chorus_modulator[instance_id]->phase(0); - chorus_modulator[instance_id]->frequency(configuration.fx.chorus_frequency[instance_id] / 10.0); - chorus_modulator[instance_id]->amplitude(mapfloat(configuration.fx.chorus_depth[instance_id], CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX, 0.0, 1.0)); - chorus_modulator[instance_id]->offset(0.0); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + // CHORUS + switch (configuration.fx.chorus_waveform[instance_id]) + { + case 0: + chorus_modulator[instance_id]->begin(WAVEFORM_TRIANGLE); + break; + case 1: + chorus_modulator[instance_id]->begin(WAVEFORM_SINE); + break; + default: + chorus_modulator[instance_id]->begin(WAVEFORM_TRIANGLE); + } + chorus_modulator[instance_id]->phase(0); + chorus_modulator[instance_id]->frequency(configuration.fx.chorus_frequency[instance_id] / 10.0); + chorus_modulator[instance_id]->amplitude(mapfloat(configuration.fx.chorus_depth[instance_id], CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX, 0.0, 1.0)); + chorus_modulator[instance_id]->offset(0.0); #if MOD_FILTER_OUTPUT == MOD_BUTTERWORTH_FILTER_OUTPUT - // Butterworth filter, 12 db/octave - modchorus_filter[instance_id]->setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707); + // Butterworth filter, 12 db/octave + modchorus_filter[instance_id]->setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707); #elif MOD_FILTER_OUTPUT == MOD_LINKWITZ_RILEY_FILTER_OUTPUT - // Linkwitz-Riley filter, 48 dB/octave - modchorus_filter[instance_id]->setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54); - modchorus_filter[instance_id]->setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3); - modchorus_filter[instance_id]->setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54); - modchorus_filter[instance_id]->setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3); -#endif - chorus_mixer[instance_id]->gain(0, 1.0); - chorus_mixer[instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); - - // DELAY - delay_mixer[instance_id]->gain(0, 1.0); - delay_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0))); - delay_fb_mixer[instance_id]->gain(0, 1.0); - delay_fb_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0))); - if (configuration.fx.delay_level[selected_instance_id] <= DELAY_LEVEL_MIN) - delay_fx[instance_id]->disable(0); - else - delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX) * 10); - - // REVERB SEND - reverb_mixer_r.gain(instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); - reverb_mixer_l.gain(instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); - - // DEXED FILTER - MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0)); - MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0)); - MicroDexed[instance_id]->doRefreshVoice(); - } - - // REVERB + // Linkwitz-Riley filter, 48 dB/octave + modchorus_filter[instance_id]->setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54); + modchorus_filter[instance_id]->setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3); + modchorus_filter[instance_id]->setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54); + modchorus_filter[instance_id]->setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3); +#endif + chorus_mixer[instance_id]->gain(0, 1.0); + chorus_mixer[instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); + + // DELAY + delay_mixer[instance_id]->gain(0, 1.0); + delay_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0))); + delay_fb_mixer[instance_id]->gain(0, 1.0); + delay_fb_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0))); + if (configuration.fx.delay_level[selected_instance_id] <= DELAY_LEVEL_MIN) + delay_fx[instance_id]->disable(0); + else + delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX) * 10); + + // REVERB SEND + reverb_mixer_r.gain(instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); + reverb_mixer_l.gain(instance_id, pseudo_log_curve(mapfloat(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, 1.0))); + + // DEXED FILTER + MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0)); + MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0)); + MicroDexed[instance_id]->doRefreshVoice(); + } + + // REVERB #ifdef USE_PLATEREVERB - reverb.size(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); - reverb.lowpass(mapfloat(configuration.fx.reverb_lowpass, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX, 0.0, 1.0)); - reverb.lodamp(mapfloat(configuration.fx.reverb_lodamp, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX, 0.0, 1.0)); - reverb.hidamp(mapfloat(configuration.fx.reverb_hidamp, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX, 0.0, 1.0)); - reverb.diffusion(mapfloat(configuration.fx.reverb_diffusion, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX, 0.0, 1.0)); + reverb.size(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); + reverb.lowpass(mapfloat(configuration.fx.reverb_lowpass, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX, 0.0, 1.0)); + reverb.lodamp(mapfloat(configuration.fx.reverb_lodamp, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX, 0.0, 1.0)); + reverb.hidamp(mapfloat(configuration.fx.reverb_hidamp, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX, 0.0, 1.0)); + reverb.diffusion(mapfloat(configuration.fx.reverb_diffusion, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX, 0.0, 1.0)); #else - freeverb.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); - freeverb.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0)); + freeverb.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); + freeverb.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0)); #endif #if NUM_DRUMS > 0 #ifdef USE_FX - reverb_mixer_r.gain(2, 1.0); // Drums Reverb-Send - reverb_mixer_l.gain(2, 1.0); // Drums Reverb-Send + reverb_mixer_r.gain(2, 1.0); // Drums Reverb-Send + reverb_mixer_l.gain(2, 1.0); // Drums Reverb-Send #endif #endif - master_mixer_r.gain(3, pseudo_log_curve(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0))); - master_mixer_l.gain(3, pseudo_log_curve(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0))); + master_mixer_r.gain(3, pseudo_log_curve(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0))); + master_mixer_l.gain(3, pseudo_log_curve(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0))); #endif #ifdef SGTL5000_AUDIO_ENHANCE - sgtl5000_1.eqBands( - mapfloat(configuration.fx.eq_bass, EQ_BASS_MIN, EQ_BASS_MAX, -1.0, 1.0), - mapfloat(configuration.fx.eq_midbass, EQ_MIDBASS_MIN, EQ_MIDBASS_MAX, -1.0, 1.0), - mapfloat(configuration.fx.eq_mid, EQ_MID_MIN, EQ_MID_MAX, -1.0, 1.0), - mapfloat(configuration.fx.eq_midtreble, EQ_MIDTREBLE_MIN, EQ_MIDTREBLE_MAX, -1.0, 1.0), - mapfloat(configuration.fx.eq_treble, EQ_TREBLE_MIN, EQ_TREBLE_MAX, -1.0, 1.0) - ); -#endif - - init_MIDI_send_CC(); -} - -void set_voiceconfig_params(uint8_t instance_id) -{ - // INIT PEAK MIXER - microdexed_peak_mixer.gain(instance_id, 1.0); - - // Controller - MicroDexed[instance_id]->setMaxNotes(configuration.dexed[instance_id].polyphony); - MicroDexed[instance_id]->setPBController(configuration.dexed[instance_id].pb_range, configuration.dexed[instance_id].pb_step); - MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign, configuration.dexed[instance_id].mw_mode); - MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign, configuration.dexed[instance_id].fc_mode); - MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); - MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); - MicroDexed[instance_id]->ControllersRefresh(); - MicroDexed[instance_id]->setOPAll(configuration.dexed[instance_id].op_enabled); - MicroDexed[instance_id]->doRefreshVoice(); - MicroDexed[instance_id]->setMonoMode(configuration.dexed[instance_id].monopoly); - - // Dexed output level - MicroDexed[instance_id]->setGain(mapfloat(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX)); - - // PANORAMA - mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); -} - -void set_sys_params(void) -{ - // set initial volume - set_volume(configuration.sys.vol, configuration.sys.mono); -} - -/****************************************************************************** - HELPERS - ******************************************************************************/ - -// https://www.reddit.com/r/Teensy/comments/7r19uk/reset_and_reboot_teensy_lc_via_code/ + sgtl5000_1.eqBands( + mapfloat(configuration.fx.eq_bass, EQ_BASS_MIN, EQ_BASS_MAX, -1.0, 1.0), + mapfloat(configuration.fx.eq_midbass, EQ_MIDBASS_MIN, EQ_MIDBASS_MAX, -1.0, 1.0), + mapfloat(configuration.fx.eq_mid, EQ_MID_MIN, EQ_MID_MAX, -1.0, 1.0), + mapfloat(configuration.fx.eq_midtreble, EQ_MIDTREBLE_MIN, EQ_MIDTREBLE_MAX, -1.0, 1.0), + mapfloat(configuration.fx.eq_treble, EQ_TREBLE_MIN, EQ_TREBLE_MAX, -1.0, 1.0) + ); +#endif + + init_MIDI_send_CC(); + } + + void set_voiceconfig_params(uint8_t instance_id) + { + // INIT PEAK MIXER + microdexed_peak_mixer.gain(instance_id, 1.0); + + // Controller + MicroDexed[instance_id]->setMaxNotes(configuration.dexed[instance_id].polyphony); + MicroDexed[instance_id]->setPBController(configuration.dexed[instance_id].pb_range, configuration.dexed[instance_id].pb_step); + MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign, configuration.dexed[instance_id].mw_mode); + MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign, configuration.dexed[instance_id].fc_mode); + MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); + MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); + MicroDexed[instance_id]->ControllersRefresh(); + MicroDexed[instance_id]->setOPAll(configuration.dexed[instance_id].op_enabled); + MicroDexed[instance_id]->doRefreshVoice(); + MicroDexed[instance_id]->setMonoMode(configuration.dexed[instance_id].monopoly); + + // Dexed output level + MicroDexed[instance_id]->setGain(mapfloat(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX)); + + // PANORAMA + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + } + + void set_sys_params(void) + { + // set initial volume + set_volume(configuration.sys.vol, configuration.sys.mono); + } + + /****************************************************************************** + HELPERS + ******************************************************************************/ + + // https://www.reddit.com/r/Teensy/comments/7r19uk/reset_and_reboot_teensy_lc_via_code/ #define SCB_AIRCR (*(volatile uint32_t *)0xE000ED0C) // Application Interrupt and Reset Control location -void _softRestart(void) -{ - Serial.end(); //clears the serial monitor if used - SCB_AIRCR = 0x05FA0004; //write value for restart -} - -float pseudo_log_curve(float value) -{ - //return (mapfloat(_pseudo_log * arm_sin_f32(value), 0.0, _pseudo_log * arm_sin_f32(1.0), 0.0, 1.0)); - //return (1 - sqrt(1 - value * value)); - //return (pow(2, value) - 1); - return (pow(value, 2.2)); -} - -uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc -{ - const uint32_t crc_table[16] = - { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - uint32_t crc = ~0L; - - for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index) - { - crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4); - crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4); - crc = ~crc; - } - - return (crc); -} - -void generate_version_string(char* buffer, uint8_t len) -{ - char tmp[3]; - - memset(buffer, 0, len); - strncat(buffer, VERSION, len); + void _softRestart(void) + { + Serial.end(); //clears the serial monitor if used + SCB_AIRCR = 0x05FA0004; //write value for restart + } + + float pseudo_log_curve(float value) + { + //return (mapfloat(_pseudo_log * arm_sin_f32(value), 0.0, _pseudo_log * arm_sin_f32(1.0), 0.0, 1.0)); + //return (1 - sqrt(1 - value * value)); + //return (pow(2, value) - 1); + return (pow(value, 2.2)); + } + + uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc + { + const uint32_t crc_table[16] = + { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc = ~0L; + + for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index) + { + crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4); + crc = ~crc; + } + + return (crc); + } + + void generate_version_string(char* buffer, uint8_t len) + { + char tmp[3]; + + memset(buffer, 0, len); + strncat(buffer, VERSION, len); #if defined(TEENSY3_5) - strncat(buffer, "-3.5", 4); + strncat(buffer, "-3.5", 4); #elif defined(TEENSY3_6) - strncat(buffer, "-3.6", 4); + strncat(buffer, "-3.6", 4); #elif defined(TEENSY4) - strncat(buffer, "-4.0", 4); + strncat(buffer, "-4.0", 4); #endif #if defined(USE_FX) - strncat(buffer, "FX", 2); + strncat(buffer, "FX", 2); #endif #if defined(MAX_NOTES) - strncat(buffer, "-", 1); - itoa (MAX_NOTES, tmp, 10); - strncat(buffer, tmp, 2); + strncat(buffer, "-", 1); + itoa (MAX_NOTES, tmp, 10); + strncat(buffer, tmp, 2); #endif -} + } #ifdef DISPLAY_LCD_SPI -void change_disp_sd(bool disp) -{ - if (sd_card > 0) - { - digitalWrite(sd_card, disp); - digitalWrite(U8X8_CS_PIN, !disp); - } -} + void change_disp_sd(bool disp) + { + if (sd_card > 0) + { + digitalWrite(sd_card, disp); + digitalWrite(U8X8_CS_PIN, !disp); + } + } #endif -uint8_t check_sd_cards(void) -{ - uint8_t ret = 0; + uint8_t check_sd_cards(void) + { + uint8_t ret = 0; - memset(sd_string, 0, sizeof(sd_string)); + memset(sd_string, 0, sizeof(sd_string)); - for (uint8_t i = 0; i < sizeof(cs_pins); i++) - { + for (uint8_t i = 0; i < sizeof(cs_pins); i++) + { #ifdef DEBUG - Serial.print(F("Checking CS pin ")); - Serial.print(cs_pins[i], DEC); - Serial.println(F(" for SD card")); + Serial.print(F("Checking CS pin ")); + Serial.print(cs_pins[i], DEC); + Serial.println(F(" for SD card")); #endif - SPI.setMOSI(mosi_pins[i]); - SPI.setSCK(sck_pins[i]); + SPI.setMOSI(mosi_pins[i]); + SPI.setSCK(sck_pins[i]); - if (SD.begin(cs_pins[i]) == true) - { + if (SD.begin(cs_pins[i]) == true) + { #ifdef DEBUG - Serial.print(F("Found. Using pin ")); - Serial.println(cs_pins[i], DEC); + Serial.print(F("Found. Using pin ")); + Serial.println(cs_pins[i], DEC); #endif - ret = cs_pins[i]; - break; - } - } + ret = cs_pins[i]; + break; + } + } - if (ret >= 0) - { - if (!card.init(SPI_HALF_SPEED, ret)) - { + if (ret >= 0) + { + if (!card.init(SPI_HALF_SPEED, ret)) + { #ifdef DEBUG - Serial.println(F("SD card initialization failed.")); + Serial.println(F("SD card initialization failed.")); #endif - ret = -1; - } - } + ret = -1; + } + } - if (ret >= 0) - { + if (ret >= 0) + { #ifdef DEBUG - Serial.print(F("Card type: ")); + Serial.print(F("Card type: ")); #endif - switch (card.type()) { - case SD_CARD_TYPE_SD1: - sprintf(sd_string, "%-5s", "SD1"); + switch (card.type()) { + case SD_CARD_TYPE_SD1: + sprintf(sd_string, "%-5s", "SD1"); #ifdef DEBUG - Serial.println(F("SD1")); + Serial.println(F("SD1")); #endif - break; - case SD_CARD_TYPE_SD2: - sprintf(sd_string, "%-5s", "SD2"); + break; + case SD_CARD_TYPE_SD2: + sprintf(sd_string, "%-5s", "SD2"); #ifdef DEBUG - Serial.println(F("SD2")); + Serial.println(F("SD2")); #endif - break; - case SD_CARD_TYPE_SDHC: - sprintf(sd_string, "%-5s", "SD2"); + break; + case SD_CARD_TYPE_SDHC: + sprintf(sd_string, "%-5s", "SD2"); #ifdef DEBUG - Serial.println(F("SDHC")); + Serial.println(F("SDHC")); #endif - break; - default: - sprintf(sd_string, "%-5s", "UKNW"); + break; + default: + sprintf(sd_string, "%-5s", "UKNW"); #ifdef DEBUG - Serial.println(F("Unknown")); + Serial.println(F("Unknown")); #endif - } + } - if (!volume.init(card)) - { + if (!volume.init(card)) + { #ifdef DEBUG - Serial.println(F("Could not find FAT16/FAT32 partition.")); + Serial.println(F("Could not find FAT16/FAT32 partition.")); #endif - ret = -1; - } - } + ret = -1; + } + } - if (ret >= 0) - { - uint32_t volumesize; + if (ret >= 0) + { + uint32_t volumesize; - volumesize = volume.blocksPerCluster() * volume.clusterCount() / 2097152; + volumesize = volume.blocksPerCluster() * volume.clusterCount() / 2097152; #ifdef DEBUG - Serial.print(F("Volume type is FAT")); - Serial.println(volume.fatType(), DEC); - Serial.print(F("Volume size (GB): ")); - Serial.println(volumesize); + Serial.print(F("Volume type is FAT")); + Serial.println(volume.fatType(), DEC); + Serial.print(F("Volume size (GB): ")); + Serial.println(volumesize); #endif - sprintf(sd_string + 5, "FAT%2d %02dGB", volume.fatType(), int(volumesize)); - } + sprintf(sd_string + 5, "FAT%2d %02dGB", volume.fatType(), int(volumesize)); + } #ifdef DEBUG - Serial.println(sd_string); + Serial.println(sd_string); #endif - return (ret); -} + return (ret); + } -void check_and_create_directories(void) -{ - if (sd_card > 0) - { - uint8_t i; - char tmp[FILENAME_LEN]; + void check_and_create_directories(void) + { + if (sd_card > 0) + { + uint8_t i; + char tmp[FILENAME_LEN]; #ifdef DEBUG - Serial.println(F("Directory check... ")); + Serial.println(F("Directory check... ")); #endif - // create directories for banks - for (i = 0; i < MAX_BANKS; i++) - { - sprintf(tmp, "/%d", i); - if (!SD.exists(tmp)) - { + // create directories for banks + for (i = 0; i < MAX_BANKS; i++) + { + sprintf(tmp, "/%d", i); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } - } + SD.mkdir(tmp); + } + } - // create directories for configuration files - sprintf(tmp, "/%s", VOICE_CONFIG_PATH); - if (!SD.exists(tmp)) - { + // create directories for configuration files + sprintf(tmp, "/%s", VOICE_CONFIG_PATH); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } - sprintf(tmp, "/%s", PERFORMANCE_CONFIG_PATH); - if (!SD.exists(tmp)) - { + SD.mkdir(tmp); + } + sprintf(tmp, "/%s", PERFORMANCE_CONFIG_PATH); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } - sprintf(tmp, "/%s", FX_CONFIG_PATH); - if (!SD.exists(tmp)) - { + SD.mkdir(tmp); + } + sprintf(tmp, "/%s", FX_CONFIG_PATH); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } - sprintf(tmp, "/%s", FAV_CONFIG_PATH); - if (!SD.exists(tmp)) - { + SD.mkdir(tmp); + } + sprintf(tmp, "/%s", FAV_CONFIG_PATH); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } - sprintf(tmp, "/%s", SEQ_CONFIG_PATH); - if (!SD.exists(tmp)) - { + SD.mkdir(tmp); + } + sprintf(tmp, "/%s", SEQ_CONFIG_PATH); + if (!SD.exists(tmp)) + { #ifdef DEBUG - Serial.print(F("Creating directory ")); - Serial.println(tmp); + Serial.print(F("Creating directory ")); + Serial.println(tmp); #endif - SD.mkdir(tmp); - } + SD.mkdir(tmp); + } - //check if updated Fav-System is ready or if setup has to run once. - - sprintf(tmp, "/%s/fav-v2", FAV_CONFIG_PATH); - if (!SD.exists(tmp)) { - - // Clear now obsolte marker files from Favs. - // Only needs to run once. - for (uint8_t i = 0; i < MAX_BANKS; i++) - { - sprintf(tmp, "/%s/%d/hasfav", FAV_CONFIG_PATH, i); -#ifdef DEBUG - Serial.print(F("Delete Marker File")); - Serial.println(tmp); -#endif - if (SD.exists(tmp)) - SD.remove(tmp); - } - // Remove empty Folders. rmdir will only remove strictly emtpy folders, which is the desired result. - // Only needs to run once. - for (uint8_t i = 0; i < MAX_BANKS; i++) - { - sprintf(tmp, "/%s/%d", FAV_CONFIG_PATH, i); -#ifdef DEBUG - Serial.print(F("Delete empty folder ")); - Serial.println(tmp); -#endif - if (SD.exists(tmp)) - SD.rmdir(tmp); - } - sprintf(tmp, "/%s/fav-v2", FAV_CONFIG_PATH); - if (!SD.exists(tmp)) - SD.mkdir(tmp); // Set Marker so that the Cleanup loops only run once. - } -#ifdef DEBUG - else - Serial.println(F("No SD card for directory check available.")); -#endif - } -} + //check if updated Fav-System is ready or if setup has to run once. -/****************************************************************************** - DEBUG HELPER - ******************************************************************************/ -#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) -void show_cpu_and_mem_usage(void) -{ - uint32_t sum_xrun = 0; - uint16_t sum_render_time_max = 0; + sprintf(tmp, "/%s/fav-v2", FAV_CONFIG_PATH); + if (!SD.exists(tmp)) { - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - sum_xrun += MicroDexed[instance_id]->getXRun(); - sum_render_time_max += MicroDexed[instance_id]->getRenderTimeMax(); - MicroDexed[instance_id]->resetRenderTimeMax(); - } - if (AudioProcessorUsageMax() > 99.9) - { - cpumax++; + // Clear now obsolte marker files from Favs. + // Only needs to run once. + for (uint8_t i = 0; i < MAX_BANKS; i++) + { + sprintf(tmp, "/%s/%d/hasfav", FAV_CONFIG_PATH, i); #ifdef DEBUG - Serial.print(F("*")); + Serial.print(F("Delete Marker File")); + Serial.println(tmp); #endif - } + if (SD.exists(tmp)) + SD.remove(tmp); + } + // Remove empty Folders. rmdir will only remove strictly emtpy folders, which is the desired result. + // Only needs to run once. + for (uint8_t i = 0; i < MAX_BANKS; i++) + { + sprintf(tmp, "/%s/%d", FAV_CONFIG_PATH, i); #ifdef DEBUG - else - Serial.print(F(" ")); - Serial.print(F("CPU:")); - Serial.print(AudioProcessorUsage(), 2); - Serial.print(F("%|CPUMAX:")); - Serial.print(AudioProcessorUsageMax(), 2); - Serial.print(F("%|CPUMAXCNT:")); - Serial.print(cpumax, DEC); + Serial.print(F("Delete empty folder ")); + Serial.println(tmp); +#endif + if (SD.exists(tmp)) + SD.rmdir(tmp); + } + sprintf(tmp, "/%s/fav-v2", FAV_CONFIG_PATH); + if (!SD.exists(tmp)) + SD.mkdir(tmp); // Set Marker so that the Cleanup loops only run once. + } +#ifdef DEBUG + else + Serial.println(F("No SD card for directory check available.")); +#endif + } + } + + /****************************************************************************** + DEBUG HELPER + ******************************************************************************/ +#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) + void show_cpu_and_mem_usage(void) + { + uint32_t sum_xrun = 0; + uint16_t sum_render_time_max = 0; + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + sum_xrun += MicroDexed[instance_id]->getXRun(); + sum_render_time_max += MicroDexed[instance_id]->getRenderTimeMax(); + MicroDexed[instance_id]->resetRenderTimeMax(); + } + if (AudioProcessorUsageMax() > 99.9) + { + cpumax++; +#ifdef DEBUG + Serial.print(F("*")); +#endif + } +#ifdef DEBUG + else + Serial.print(F(" ")); + Serial.print(F("CPU:")); + Serial.print(AudioProcessorUsage(), 2); + Serial.print(F("%|CPUMAX:")); + Serial.print(AudioProcessorUsageMax(), 2); + Serial.print(F("%|CPUMAXCNT:")); + Serial.print(cpumax, DEC); #ifdef TEENSY4 - Serial.print(F("|CPUTEMP:")); - Serial.print(tempmonGetTemp(), 2); - Serial.print(F("C|MEM:")); + Serial.print(F("|CPUTEMP:")); + Serial.print(tempmonGetTemp(), 2); + Serial.print(F("C|MEM:")); #else - Serial.print(F("|MEM:")); -#endif - Serial.print(AudioMemoryUsage(), DEC); - Serial.print(F("|MEMMAX:")); - Serial.print(AudioMemoryUsageMax(), DEC); - Serial.print(F("|AUDIO_MEM_MAX:")); - Serial.print(AUDIO_MEM, DEC); - Serial.print(F("|RENDERTIMEMAX:")); - Serial.print(sum_render_time_max, DEC); - Serial.print(F("|XRUN:")); - Serial.print(sum_xrun, DEC); - Serial.print(F("|PEAKR:")); - Serial.print(peak_r, DEC); - Serial.print(F("|PEAKL:")); - Serial.print(peak_l, DEC); - Serial.print(F("|PEAKMD:")); - Serial.print(peak_dexed, DEC); - Serial.print(F("|ACTPEAKMD:")); - Serial.print(peak_dexed_value, 1); - Serial.print(F("|BLOCKSIZE:")); - Serial.print(AUDIO_BLOCK_SAMPLES, DEC); - Serial.print(F("|RAM:")); - Serial.print(FreeMem(), DEC); - - Serial.print(F("|ACTVOICES:")); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - Serial.print(instance_id, DEC); - Serial.print(F("=")); - Serial.print(active_voices[instance_id], DEC); - Serial.print(F("/")); - Serial.print(MAX_NOTES / NUM_DEXED, DEC); - if (instance_id != NUM_DEXED - 1) - Serial.print(F(",")); - } - Serial.println(); -#endif - AudioProcessorUsageMaxReset(); - AudioMemoryUsageMaxReset(); -} -#endif - -#ifdef DEBUG -void show_configuration(void) -{ - Serial.println(); - Serial.println(F("CONFIGURATION:")); - Serial.println(F("System")); - Serial.print(F(" Instances ")); Serial.println(configuration.sys.instances, DEC); - Serial.print(F(" Volume ")); Serial.println(configuration.sys.vol, DEC); - Serial.print(F(" Mono ")); Serial.println(configuration.sys.mono, DEC); - Serial.print(F(" Soft MIDI Thru ")); Serial.println(configuration.sys.soft_midi_thru, DEC); - Serial.println(F("FX")); - Serial.print(F(" Reverb Roomsize ")); Serial.println(configuration.fx.reverb_roomsize, DEC); - Serial.print(F(" Reverb Level ")); Serial.println(configuration.fx.reverb_level, DEC); + Serial.print(F("|MEM:")); +#endif + Serial.print(AudioMemoryUsage(), DEC); + Serial.print(F("|MEMMAX:")); + Serial.print(AudioMemoryUsageMax(), DEC); + Serial.print(F("|AUDIO_MEM_MAX:")); + Serial.print(AUDIO_MEM, DEC); + Serial.print(F("|RENDERTIMEMAX:")); + Serial.print(sum_render_time_max, DEC); + Serial.print(F("|XRUN:")); + Serial.print(sum_xrun, DEC); + Serial.print(F("|PEAKR:")); + Serial.print(peak_r, DEC); + Serial.print(F("|PEAKL:")); + Serial.print(peak_l, DEC); + Serial.print(F("|PEAKMD:")); + Serial.print(peak_dexed, DEC); + Serial.print(F("|ACTPEAKMD:")); + Serial.print(peak_dexed_value, 1); + Serial.print(F("|BLOCKSIZE:")); + Serial.print(AUDIO_BLOCK_SAMPLES, DEC); + Serial.print(F("|RAM:")); + Serial.print(FreeMem(), DEC); + + Serial.print(F("|ACTVOICES:")); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + Serial.print(instance_id, DEC); + Serial.print(F("=")); + Serial.print(active_voices[instance_id], DEC); + Serial.print(F("/")); + Serial.print(MAX_NOTES / NUM_DEXED, DEC); + if (instance_id != NUM_DEXED - 1) + Serial.print(F(",")); + } + Serial.println(); +#endif + AudioProcessorUsageMaxReset(); + AudioMemoryUsageMaxReset(); + } +#endif + +#ifdef DEBUG + void show_configuration(void) + { + Serial.println(); + Serial.println(F("CONFIGURATION:")); + Serial.println(F("System")); + Serial.print(F(" Instances ")); Serial.println(configuration.sys.instances, DEC); + Serial.print(F(" Volume ")); Serial.println(configuration.sys.vol, DEC); + Serial.print(F(" Mono ")); Serial.println(configuration.sys.mono, DEC); + Serial.print(F(" Soft MIDI Thru ")); Serial.println(configuration.sys.soft_midi_thru, DEC); + Serial.println(F("FX")); + Serial.print(F(" Reverb Roomsize ")); Serial.println(configuration.fx.reverb_roomsize, DEC); + Serial.print(F(" Reverb Level ")); Serial.println(configuration.fx.reverb_level, DEC); #ifdef USE_PLATEREVERB - Serial.print(F(" Reverb Lowpass ")); Serial.println(configuration.fx.reverb_lowpass, DEC); - Serial.print(F(" Reverb Lodamp ")); Serial.println(configuration.fx.reverb_lodamp, DEC); - Serial.print(F(" Reverb Hidamp ")); Serial.println(configuration.fx.reverb_hidamp, DEC); - Serial.print(F(" Reverb Diffusion ")); Serial.println(configuration.fx.reverb_diffusion, DEC); + Serial.print(F(" Reverb Lowpass ")); Serial.println(configuration.fx.reverb_lowpass, DEC); + Serial.print(F(" Reverb Lodamp ")); Serial.println(configuration.fx.reverb_lodamp, DEC); + Serial.print(F(" Reverb Hidamp ")); Serial.println(configuration.fx.reverb_hidamp, DEC); + Serial.print(F(" Reverb Diffusion ")); Serial.println(configuration.fx.reverb_diffusion, DEC); #else - Serial.print(F(" Reverb Damping ")); Serial.println(configuration.fx.reverb_damping, DEC); -#endif - - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - Serial.print(F("Dexed instance ")); - Serial.println(instance_id, DEC); - Serial.print(F(" MIDI-Channel ")); Serial.println(configuration.dexed[instance_id].midi_channel, DEC); - Serial.print(F(" Lowest Note ")); Serial.println(configuration.dexed[instance_id].lowest_note, DEC); - Serial.print(F(" Highest Note ")); Serial.println(configuration.dexed[instance_id].highest_note, DEC); - Serial.print(F(" Filter Cutoff ")); Serial.println(configuration.fx.filter_cutoff[instance_id], DEC); - Serial.print(F(" Filter Resonance ")); Serial.println(configuration.fx.filter_resonance[instance_id], DEC); - Serial.print(F(" Chorus Frequency ")); Serial.println(configuration.fx.chorus_frequency[instance_id], DEC); - Serial.print(F(" Chorus Waveform ")); Serial.println(configuration.fx.chorus_waveform[instance_id], DEC); - Serial.print(F(" Chorus Depth ")); Serial.println(configuration.fx.chorus_depth[instance_id], DEC); - Serial.print(F(" Chorus Level ")); Serial.println(configuration.fx.chorus_level[instance_id], DEC); - Serial.print(F(" Delay Time ")); Serial.println(configuration.fx.delay_time[instance_id], DEC); - Serial.print(F(" Delay Feedback ")); Serial.println(configuration.fx.delay_feedback[instance_id], DEC); - Serial.print(F(" Delay Level ")); Serial.println(configuration.fx.delay_level[instance_id], DEC); - Serial.print(F(" Delay Sync ")); Serial.println(configuration.fx.delay_sync[instance_id], DEC); - Serial.print(F(" Reverb Send ")); Serial.println(configuration.fx.reverb_send[instance_id], DEC); - Serial.print(F(" Sound Intensity ")); Serial.println(configuration.dexed[instance_id].sound_intensity, DEC); - Serial.print(F(" Panorama ")); Serial.println(configuration.dexed[instance_id].pan, DEC); - Serial.print(F(" Transpose ")); Serial.println(configuration.dexed[instance_id].transpose, DEC); - Serial.print(F(" Tune ")); Serial.println(configuration.dexed[instance_id].tune, DEC); - Serial.print(F(" Polyphony ")); Serial.println(configuration.dexed[instance_id].polyphony, DEC); - Serial.print(F(" Mono/Poly ")); Serial.println(configuration.dexed[instance_id].monopoly, DEC); - Serial.print(F(" Note Refresh ")); Serial.println(configuration.dexed[instance_id].note_refresh, DEC); - Serial.print(F(" Pitchbend Range ")); Serial.println(configuration.dexed[instance_id].pb_range, DEC); - Serial.print(F(" Pitchbend Step ")); Serial.println(configuration.dexed[instance_id].pb_step, DEC); - Serial.print(F(" Modwheel Range ")); Serial.println(configuration.dexed[instance_id].mw_range, DEC); - Serial.print(F(" Modwheel Assign ")); Serial.println(configuration.dexed[instance_id].mw_assign, DEC); - Serial.print(F(" Modwheel Mode ")); Serial.println(configuration.dexed[instance_id].mw_mode, DEC); - Serial.print(F(" Footctrl Range ")); Serial.println(configuration.dexed[instance_id].fc_range, DEC); - Serial.print(F(" Footctrl Assign ")); Serial.println(configuration.dexed[instance_id].fc_assign, DEC); - Serial.print(F(" Footctrl Mode ")); Serial.println(configuration.dexed[instance_id].fc_mode, DEC); - Serial.print(F(" BreathCtrl Range ")); Serial.println(configuration.dexed[instance_id].bc_range, DEC); - Serial.print(F(" Breathctrl Assign ")); Serial.println(configuration.dexed[instance_id].bc_assign, DEC); - Serial.print(F(" Breathctrl Mode ")); Serial.println(configuration.dexed[instance_id].bc_mode, DEC); - Serial.print(F(" Aftertouch Range ")); Serial.println(configuration.dexed[instance_id].at_range, DEC); - Serial.print(F(" Aftertouch Assign ")); Serial.println(configuration.dexed[instance_id].at_assign, DEC); - Serial.print(F(" Aftertouch Mode ")); Serial.println(configuration.dexed[instance_id].at_mode, DEC); - Serial.print(F(" Portamento Mode ")); Serial.println(configuration.dexed[instance_id].portamento_mode, DEC); - Serial.print(F(" Portamento Glissando ")); Serial.println(configuration.dexed[instance_id].portamento_glissando, DEC); - Serial.print(F(" Portamento Time ")); Serial.println(configuration.dexed[instance_id].portamento_time, DEC); - Serial.print(F(" OP Enabled ")); Serial.println(configuration.dexed[instance_id].op_enabled, DEC); - Serial.flush(); - } - - Serial.println(F("Performance")); - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) - { - Serial.print(F(" Bank ")); Serial.print(instance_id, DEC); Serial.print(" "); Serial.println(configuration.performance.bank[instance_id], DEC); - Serial.print(F(" Voice ")); Serial.print(instance_id, DEC); Serial.print(" "); Serial.println(configuration.performance.voice[instance_id], DEC); - } - Serial.print(F(" FX-Number ")); Serial.println(configuration.performance.fx_number, DEC); - - Serial.println(); - Serial.flush(); -} - -void show_patch(uint8_t instance_id) -{ - char vn[VOICE_NAME_LEN]; - - Serial.print(F("INSTANCE ")); - Serial.println(instance_id, DEC); - - memset(vn, 0, sizeof(vn)); - Serial.println(F("+==========================================================================================================+")); - for (int8_t i = 5; i >= 0; --i) - { - Serial.println(F("+==========================================================================================================+")); - Serial.print(F("| OP")); - Serial.print(6 - i, DEC); - Serial.println(F(" |")); - Serial.println(F("+======+======+======+======+======+======+======+======+================+================+================+")); - Serial.println(F("| R1 | R2 | R3 | R4 | L1 | L2 | L3 | L4 | LEV_SCL_BRK_PT | SCL_LEFT_DEPTH | SCL_RGHT_DEPTH |")); - Serial.println(F("+------+------+------+------+------+------+------+------+----------------+----------------+----------------+")); - Serial.print("| "); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R1)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R2)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R3)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R4)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L1)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L2)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L3)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L4)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_LEV_SCL_BRK_PT)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_LEFT_DEPTH)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_RGHT_DEPTH)); - Serial.println(F(" |")); - Serial.println(F("+======+======+======+======+======+===+==+==+===+======+====+========+==+====+=======+===+================+")); - Serial.println(F("| SCL_L_CURVE | SCL_R_CURVE | RT_SCALE | AMS | KVS | OUT_LEV | OP_MOD | FRQ_C | FRQ_F | DETUNE |")); - Serial.println(F("+-------------+-------------+----------+-----+-----+---------+--------+-------+-------+--------------------+")); - Serial.print(F("| ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_LEFT_CURVE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_RGHT_CURVE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_RATE_SCALE)); - Serial.print(F(" |")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_AMP_MOD_SENS)); - Serial.print(F(" |")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_KEY_VEL_SENS)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OUTPUT_LEV)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_MODE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_FREQ_COARSE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_FREQ_FINE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_DETUNE)); - Serial.println(F(" |")); - } - Serial.println(F("+=======+=====+=+=======+===+===+======++====+==+==+====+====+==+======+======+=====+=+====================+")); - Serial.println(F("| PR1 | PR2 | PR3 | PR4 | PL1 | PL2 | PL3 | PL4 | ALG | FB | OKS | TRANSPOSE |")); - Serial.println(F("+-------+-------+-------+-------+-------+-------+-------+-------+------+------+-----+----------------------+")); - Serial.print(F("| ")); - for (int8_t i = 0; i < 8; i++) - { - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + i)); - Serial.print(F(" | ")); - } - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_ALGORITHM)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_FEEDBACK)); - Serial.print(F(" |")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_OSC_KEY_SYNC)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_TRANSPOSE)); - Serial.println(F(" |")); - Serial.println(F("+=======+=+=====+===+===+=====+=+=======+=======+==+====+=====+=+======++=====+=====+======================+")); - Serial.println(F("| LFO SPD | LFO DLY | LFO PMD | LFO AMD | LFO SYNC | LFO WAVE | LFO PMS | NAME |")); - Serial.println(F("+---------+---------+---------+---------+----------+----------+---------+----------------------------------+")); - Serial.print(F("| ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_SPEED)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_DELAY)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_DEP)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_AMP_MOD_DEP)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_SYNC)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_WAVE)); - Serial.print(F(" | ")); - SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_SENS)); - Serial.print(F(" | ")); - MicroDexed[instance_id]->getName(vn); - Serial.print(vn); - Serial.println(F(" |")); - Serial.println(F("+=========+=========+=========+=========+==========+==========+=========+==================================+")); - Serial.println(F("+==========================================================================================================+")); -} - -void SerialPrintFormatInt3(uint8_t num) -{ - char buf[4]; - sprintf(buf, "%3d", num); - Serial.print(buf); -} + Serial.print(F(" Reverb Damping ")); Serial.println(configuration.fx.reverb_damping, DEC); +#endif + + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + Serial.print(F("Dexed instance ")); + Serial.println(instance_id, DEC); + Serial.print(F(" MIDI-Channel ")); Serial.println(configuration.dexed[instance_id].midi_channel, DEC); + Serial.print(F(" Lowest Note ")); Serial.println(configuration.dexed[instance_id].lowest_note, DEC); + Serial.print(F(" Highest Note ")); Serial.println(configuration.dexed[instance_id].highest_note, DEC); + Serial.print(F(" Filter Cutoff ")); Serial.println(configuration.fx.filter_cutoff[instance_id], DEC); + Serial.print(F(" Filter Resonance ")); Serial.println(configuration.fx.filter_resonance[instance_id], DEC); + Serial.print(F(" Chorus Frequency ")); Serial.println(configuration.fx.chorus_frequency[instance_id], DEC); + Serial.print(F(" Chorus Waveform ")); Serial.println(configuration.fx.chorus_waveform[instance_id], DEC); + Serial.print(F(" Chorus Depth ")); Serial.println(configuration.fx.chorus_depth[instance_id], DEC); + Serial.print(F(" Chorus Level ")); Serial.println(configuration.fx.chorus_level[instance_id], DEC); + Serial.print(F(" Delay Time ")); Serial.println(configuration.fx.delay_time[instance_id], DEC); + Serial.print(F(" Delay Feedback ")); Serial.println(configuration.fx.delay_feedback[instance_id], DEC); + Serial.print(F(" Delay Level ")); Serial.println(configuration.fx.delay_level[instance_id], DEC); + Serial.print(F(" Delay Sync ")); Serial.println(configuration.fx.delay_sync[instance_id], DEC); + Serial.print(F(" Reverb Send ")); Serial.println(configuration.fx.reverb_send[instance_id], DEC); + Serial.print(F(" Sound Intensity ")); Serial.println(configuration.dexed[instance_id].sound_intensity, DEC); + Serial.print(F(" Panorama ")); Serial.println(configuration.dexed[instance_id].pan, DEC); + Serial.print(F(" Transpose ")); Serial.println(configuration.dexed[instance_id].transpose, DEC); + Serial.print(F(" Tune ")); Serial.println(configuration.dexed[instance_id].tune, DEC); + Serial.print(F(" Polyphony ")); Serial.println(configuration.dexed[instance_id].polyphony, DEC); + Serial.print(F(" Mono/Poly ")); Serial.println(configuration.dexed[instance_id].monopoly, DEC); + Serial.print(F(" Note Refresh ")); Serial.println(configuration.dexed[instance_id].note_refresh, DEC); + Serial.print(F(" Pitchbend Range ")); Serial.println(configuration.dexed[instance_id].pb_range, DEC); + Serial.print(F(" Pitchbend Step ")); Serial.println(configuration.dexed[instance_id].pb_step, DEC); + Serial.print(F(" Modwheel Range ")); Serial.println(configuration.dexed[instance_id].mw_range, DEC); + Serial.print(F(" Modwheel Assign ")); Serial.println(configuration.dexed[instance_id].mw_assign, DEC); + Serial.print(F(" Modwheel Mode ")); Serial.println(configuration.dexed[instance_id].mw_mode, DEC); + Serial.print(F(" Footctrl Range ")); Serial.println(configuration.dexed[instance_id].fc_range, DEC); + Serial.print(F(" Footctrl Assign ")); Serial.println(configuration.dexed[instance_id].fc_assign, DEC); + Serial.print(F(" Footctrl Mode ")); Serial.println(configuration.dexed[instance_id].fc_mode, DEC); + Serial.print(F(" BreathCtrl Range ")); Serial.println(configuration.dexed[instance_id].bc_range, DEC); + Serial.print(F(" Breathctrl Assign ")); Serial.println(configuration.dexed[instance_id].bc_assign, DEC); + Serial.print(F(" Breathctrl Mode ")); Serial.println(configuration.dexed[instance_id].bc_mode, DEC); + Serial.print(F(" Aftertouch Range ")); Serial.println(configuration.dexed[instance_id].at_range, DEC); + Serial.print(F(" Aftertouch Assign ")); Serial.println(configuration.dexed[instance_id].at_assign, DEC); + Serial.print(F(" Aftertouch Mode ")); Serial.println(configuration.dexed[instance_id].at_mode, DEC); + Serial.print(F(" Portamento Mode ")); Serial.println(configuration.dexed[instance_id].portamento_mode, DEC); + Serial.print(F(" Portamento Glissando ")); Serial.println(configuration.dexed[instance_id].portamento_glissando, DEC); + Serial.print(F(" Portamento Time ")); Serial.println(configuration.dexed[instance_id].portamento_time, DEC); + Serial.print(F(" OP Enabled ")); Serial.println(configuration.dexed[instance_id].op_enabled, DEC); + Serial.flush(); + } + + Serial.println(F("Performance")); + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + { + Serial.print(F(" Bank ")); Serial.print(instance_id, DEC); Serial.print(" "); Serial.println(configuration.performance.bank[instance_id], DEC); + Serial.print(F(" Voice ")); Serial.print(instance_id, DEC); Serial.print(" "); Serial.println(configuration.performance.voice[instance_id], DEC); + } + Serial.print(F(" FX-Number ")); Serial.println(configuration.performance.fx_number, DEC); + + Serial.println(); + Serial.flush(); + } + + void show_patch(uint8_t instance_id) + { + char vn[VOICE_NAME_LEN]; + + Serial.print(F("INSTANCE ")); + Serial.println(instance_id, DEC); + + memset(vn, 0, sizeof(vn)); + Serial.println(F("+==========================================================================================================+")); + for (int8_t i = 5; i >= 0; --i) + { + Serial.println(F("+==========================================================================================================+")); + Serial.print(F("| OP")); + Serial.print(6 - i, DEC); + Serial.println(F(" |")); + Serial.println(F("+======+======+======+======+======+======+======+======+================+================+================+")); + Serial.println(F("| R1 | R2 | R3 | R4 | L1 | L2 | L3 | L4 | LEV_SCL_BRK_PT | SCL_LEFT_DEPTH | SCL_RGHT_DEPTH |")); + Serial.println(F("+------+------+------+------+------+------+------+------+----------------+----------------+----------------+")); + Serial.print("| "); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R1)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R2)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R3)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_R4)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L1)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L2)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L3)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_EG_L4)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_LEV_SCL_BRK_PT)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_LEFT_DEPTH)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_RGHT_DEPTH)); + Serial.println(F(" |")); + Serial.println(F("+======+======+======+======+======+===+==+==+===+======+====+========+==+====+=======+===+================+")); + Serial.println(F("| SCL_L_CURVE | SCL_R_CURVE | RT_SCALE | AMS | KVS | OUT_LEV | OP_MOD | FRQ_C | FRQ_F | DETUNE |")); + Serial.println(F("+-------------+-------------+----------+-----+-----+---------+--------+-------+-------+--------------------+")); + Serial.print(F("| ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_LEFT_CURVE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_SCL_RGHT_CURVE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_RATE_SCALE)); + Serial.print(F(" |")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_AMP_MOD_SENS)); + Serial.print(F(" |")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_KEY_VEL_SENS)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OUTPUT_LEV)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_MODE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_FREQ_COARSE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_FREQ_FINE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement((i * 21) + DEXED_OP_OSC_DETUNE)); + Serial.println(F(" |")); + } + Serial.println(F("+=======+=====+=+=======+===+===+======++====+==+==+====+====+==+======+======+=====+=+====================+")); + Serial.println(F("| PR1 | PR2 | PR3 | PR4 | PL1 | PL2 | PL3 | PL4 | ALG | FB | OKS | TRANSPOSE |")); + Serial.println(F("+-------+-------+-------+-------+-------+-------+-------+-------+------+------+-----+----------------------+")); + Serial.print(F("| ")); + for (int8_t i = 0; i < 8; i++) + { + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + i)); + Serial.print(F(" | ")); + } + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_ALGORITHM)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_FEEDBACK)); + Serial.print(F(" |")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_OSC_KEY_SYNC)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_TRANSPOSE)); + Serial.println(F(" |")); + Serial.println(F("+=======+=+=====+===+===+=====+=+=======+=======+==+====+=====+=+======++=====+=====+======================+")); + Serial.println(F("| LFO SPD | LFO DLY | LFO PMD | LFO AMD | LFO SYNC | LFO WAVE | LFO PMS | NAME |")); + Serial.println(F("+---------+---------+---------+---------+----------+----------+---------+----------------------------------+")); + Serial.print(F("| ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_SPEED)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_DELAY)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_DEP)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_AMP_MOD_DEP)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_SYNC)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_WAVE)); + Serial.print(F(" | ")); + SerialPrintFormatInt3(MicroDexed[instance_id]->getVoiceDataElement(DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_SENS)); + Serial.print(F(" | ")); + MicroDexed[instance_id]->getName(vn); + Serial.print(vn); + Serial.println(F(" |")); + Serial.println(F("+=========+=========+=========+=========+==========+==========+=========+==================================+")); + Serial.println(F("+==========================================================================================================+")); + } + + void SerialPrintFormatInt3(uint8_t num) + { + char buf[4]; + sprintf(buf, "%3d", num); + Serial.print(buf); + } #ifdef TEENSY3_6 -/* From: https://forum.pjrc.com/threads/33443-How-to-display-free-ram */ -extern "C" char* sbrk(int incr); -uint32_t FreeMem(void) -{ - char top; - return &top - reinterpret_cast(sbrk(0)); -} + /* From: https://forum.pjrc.com/threads/33443-How-to-display-free-ram */ + extern "C" char* sbrk(int incr); + uint32_t FreeMem(void) + { + char top; + return &top - reinterpret_cast(sbrk(0)); + } #else -/* From: https://forum.pjrc.com/threads/33443-How-to-display-free-ram */ -extern unsigned long _heap_end; -extern char *__brkval; -int FreeMem(void) -{ - return (char *)&_heap_end - __brkval; -} + /* From: https://forum.pjrc.com/threads/33443-How-to-display-free-ram */ + extern unsigned long _heap_end; + extern char *__brkval; + int FreeMem(void) + { + return (char *)&_heap_end - __brkval; + } #endif #endif diff --git a/UI.hpp b/UI.hpp index 56c718b..9f5f57b 100644 --- a/UI.hpp +++ b/UI.hpp @@ -51,6 +51,9 @@ #endif #define _LCDML_DISP_cfg_scrollbar 1 // enable a scrollbar +extern PeriodicTimer timer1; +extern void sequencer(void); + extern config_t configuration; extern void set_volume(uint8_t v, uint8_t m); extern bool load_sysex(uint8_t b, uint8_t v); @@ -65,6 +68,7 @@ extern float pseudo_log_curve(float value); extern uint8_t selected_instance_id; extern char receive_bank_filename[FILENAME_LEN]; + #if NUM_DRUMS > 0 #include "drums.h" extern drum_config_t drum_config[NUM_DRUMSET_CONFIG]; @@ -82,7 +86,6 @@ extern bool seq_recording; uint8_t seq_active_function = 99; uint8_t activesample; extern uint8_t seq_active_track; -extern elapsedMillis seq_millis_timer; extern uint8_t seq_menu; extern uint8_t seq_temp_select_menu; extern uint8_t seq_temp_active_menu; @@ -4068,7 +4071,7 @@ void UI_func_seq_lenght(uint8_t param) void UI_func_seq_tempo(uint8_t param) { - char tmp[5]; + char tmp[7]; if (LCDML.FUNC_setup()) // ****** SETUP ********* { encoderDir[ENC_R].reset(); @@ -4084,19 +4087,21 @@ void UI_func_seq_tempo(uint8_t param) if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) { if (LCDML.BT_checkDown()) - seq_bpm = constrain(seq_bpm + ENCODER[ENC_R].speed(), 60, 180); + seq_bpm = constrain(seq_bpm + ENCODER[ENC_R].speed(), 50, 190); else if (LCDML.BT_checkUp()) - seq_bpm = constrain(seq_bpm - ENCODER[ENC_R].speed(), 60, 180); + seq_bpm = constrain(seq_bpm - ENCODER[ENC_R].speed(), 50, 190); } - seq_tempo_ms = 60000 / seq_bpm / 4; + // seq_tempo_ms = 60000 / seq_bpm / 4; + seq_tempo_ms = 60000000 / seq_bpm / 4; - sprintf(tmp, "[%3d]", seq_bpm); lcd.setCursor(0, 1); + sprintf(tmp, "[%3d]", seq_bpm); lcd.print(tmp); - - lcd.setCursor(9, 1); - sprintf(tmp, "[%3d]", seq_tempo_ms); + lcd.setCursor(11, 1); + sprintf(tmp, "%3d", seq_tempo_ms / 1000); lcd.print(tmp); + //timer1.stop(); + timer1.begin(sequencer, seq_tempo_ms / 2); } if (LCDML.FUNC_close()) // ****** STABLE END ********* { @@ -4522,6 +4527,7 @@ void UI_func_sequencer(uint8_t param) { seq_running = true; lcd.print("REC"); + timer1.start(); } else if (seq_running == true && seq_recording == false) { seq_running = true; @@ -4536,6 +4542,7 @@ void UI_func_sequencer(uint8_t param) seq_step = 0; seq_chain_active_step = 0; lcd.print("PLY"); + timer1.stop(); MicroDexed[0]->panic(); } } else if ( seq_menu == 2) @@ -4788,7 +4795,8 @@ void UI_func_arpeggio(uint8_t param) lcd.print("Maj"); lcd.setCursor( 11, 1); lcd.print("1/16"); - + lcd.setCursor( 7, 0); + lcd.print(" "); arp_refresh_display_play_status(); } if (LCDML.FUNC_loop()) // ****** LOOP ********* @@ -4841,15 +4849,26 @@ void UI_func_arpeggio(uint8_t param) seq_temp_active_menu = 0; } - else if ( seq_temp_select_menu == 2 && seq_temp_active_menu == 0 ) + //else if ( seq_temp_select_menu == 2 && seq_temp_active_menu == 0 ) + else if ( seq_temp_select_menu == 2 ) { - seq_running = !seq_running; - arp_refresh_display_play_status(); - MicroDexed[0]->panic(); - seq_step = 0; - arp_octave = 0; - arp_step = 0; - seq_chain_active_step = 0; + + if (seq_running) { + seq_running = !seq_running; + timer1.stop(); + MicroDexed[0]->panic(); + arp_refresh_display_play_status(); + seq_step = 0; + arp_octave = 0; + arp_step = 0; + seq_chain_active_step = 0; + } else + { + seq_running = !seq_running; + arp_refresh_display_play_status(); + timer1.start(); + } + } else if ( seq_temp_select_menu == 3 && seq_temp_active_menu == 0 ) { @@ -4871,6 +4890,10 @@ void UI_func_arpeggio(uint8_t param) if (arp_speed == 0)lcd.print("1/16"); else if (arp_speed == 1)lcd.print("1/8 "); if (seq_temp_select_menu == 0) { + lcd.setCursor( 3, 0); + lcd.print("["); + lcd.setCursor( 5, 0); + lcd.print("]"); lcd.setCursor( 11, 0); lcd.print(" "); lcd.setCursor( 15, 0); @@ -4879,24 +4902,22 @@ void UI_func_arpeggio(uint8_t param) lcd.print(" "); lcd.setCursor( 9, 1); lcd.print(" "); - lcd.setCursor( 3, 0); - lcd.print("["); - lcd.setCursor( 5, 0); - lcd.print("]"); lcd.setCursor( 10, 1); lcd.print(" "); lcd.setCursor( 15, 1); lcd.print(" "); + } else if (seq_temp_select_menu == 1) { - lcd.setCursor( 11, 0); - lcd.print(" "); - lcd.print(" "); lcd.setCursor( 3, 0); lcd.print(" "); lcd.setCursor( 5, 0); lcd.print(" "); + lcd.setCursor( 11, 0); + lcd.print(" "); + lcd.setCursor( 15, 0); + lcd.print(" "); lcd.setCursor( 5, 1); lcd.print("["); lcd.setCursor( 9, 1); @@ -4908,14 +4929,14 @@ void UI_func_arpeggio(uint8_t param) lcd.print(" "); lcd.setCursor( 9, 1); lcd.print(" "); - lcd.setCursor( 11, 0); - lcd.print("["); - lcd.setCursor( 15, 0); - lcd.print("]"); lcd.setCursor( 10, 1); lcd.print(" "); lcd.setCursor( 15, 1); lcd.print(" "); + lcd.setCursor( 11, 0); + lcd.print("["); + lcd.setCursor( 15, 0); + lcd.print("]"); } else if (seq_temp_select_menu == 3) { @@ -4923,14 +4944,14 @@ void UI_func_arpeggio(uint8_t param) lcd.print(" "); lcd.setCursor( 15, 0); lcd.print(" "); - lcd.setCursor( 10, 1); - lcd.print("["); - lcd.setCursor( 15, 1); - lcd.print("]"); lcd.setCursor( 3, 0); lcd.print(" "); lcd.setCursor( 5, 0); lcd.print(" "); + lcd.setCursor( 10, 1); + lcd.print("["); + lcd.setCursor( 15, 1); + lcd.print("]"); } } if (LCDML.FUNC_close()) // ****** STABLE END ********* diff --git a/sequencer.cpp b/sequencer.cpp index bad6929..5bf8ae8 100644 --- a/sequencer.cpp +++ b/sequencer.cpp @@ -12,8 +12,9 @@ extern void handleNoteOff(byte , byte , byte ); extern void UI_func_sequencer(uint8_t); extern void UI_func_arpeggio(uint8_t); extern const char* seq_find_shortname(uint8_t); +boolean interrupt_swapper = false; -void sequencer(void) +void sequencer_part1(void) { //if (seq_note_in > 0 && seq_note_in < 62 && seq_recording == false ) { //handleNoteOff(configuration.dexed[0].midi_channel, seq_data[3][seq_step] + seq_transpose , 0); @@ -24,155 +25,143 @@ void sequencer(void) //seq_note_in = 0; //} - if (seq_millis_timer > seq_timer_previous + seq_tempo_ms) - { - seq_timer_previous = seq_millis_timer; - - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sequencer)) { //is in UI of Sequencer + // if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sequencer)) { //is in UI of Sequencer - //write to sequencer if in sequencer menu - if (seq_note_in > 0 && seq_recording == true) { + //write to sequencer if in sequencer menu + // if (seq_note_in > 0 && seq_recording == true) { + // + // // if ( seq_content_type[ seq_patternchain[seq_chain_active_step][active_track] ] == 1) handleNoteOff(configuration.dexed[0].midi_channel, seq_data[active_track][seq_step] + seq_transpose , 0); + // + // seq_data[seq_active_track][seq_step] = seq_note_in; + // seq_vel[seq_active_track][seq_step] = seq_note_in_velocity; + // seq_note_in = 0; + // seq_note_in_velocity = 0; + // } - // if ( seq_content_type[ seq_patternchain[seq_chain_active_step][active_track] ] == 1) handleNoteOff(configuration.dexed[0].midi_channel, seq_data[active_track][seq_step] + seq_transpose , 0); - - seq_data[seq_active_track][seq_step] = seq_note_in; - seq_vel[seq_active_track][seq_step] = seq_note_in_velocity; - seq_note_in = 0; - seq_note_in_velocity = 0; - } - lcd.setCursor(seq_step, 1); - lcd.print("X"); - if (seq_step == 0) { - lcd.setCursor(15, 1); - lcd.print(seq_find_shortname(15)[0]); - } - else + for (uint8_t d = 0; d < 4; d++) + { + if ( seq_track_type[d] == 0) { // drum track + if (seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0 && seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0) { - lcd.setCursor(seq_step - 1, 1); - lcd.print(seq_find_shortname(seq_step - 1)[0]); + handleNoteOn(DRUM_MIDI_CHANNEL, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] , seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]); } } - else if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_arpeggio)) { //is in UI of Arpeggiator - lcd.setCursor(7, 0); - lcd.print( seq_chord_names[arp_chord - 200][0]); - lcd.print( seq_chord_names[arp_chord - 200][1]); - lcd.print( seq_chord_names[arp_chord - 200][2]); - lcd.print( seq_chord_names[arp_chord - 200][3]); - } - for (uint8_t d = 0; d < 4; d++) - { - if ( seq_track_type[d] == 0) { // drum track - if (seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0 && seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0) + else { + if (seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0 && seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0) // instrument track + { + if (seq_track_type[d] == 1 || seq_track_type[d] == 3 ) { - handleNoteOn(DRUM_MIDI_CHANNEL, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] , seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]); + handleNoteOn(configuration.dexed[seq_inst_dexed[d]].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose , seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]); } - } - else { - if (seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0 && seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 0) // instrument track - { - if (seq_track_type[d] == 1 || seq_track_type[d] == 3 ) + seq_prev_note[d] = seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose; + seq_prev_vel[d] = seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]; + if (seq_track_type[d] == 2) { //Chords + if (seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 199) { - handleNoteOn(configuration.dexed[seq_inst_dexed[d]].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose , seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]); - } - seq_prev_note[d] = seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose; - seq_prev_vel[d] = seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]; - if (seq_track_type[d] == 2) { //Chords - if (seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] > 199) - { - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][0], seq_chord_velocity); - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][1], seq_chord_velocity); - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][2], seq_chord_velocity); - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][3], seq_chord_velocity); - } - } - else if (seq_track_type[d] == 3) { //Arp - arp_step = 0; - arp_counter = 0; - arp_note = seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose; - arp_chord = seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]; + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][0], seq_chord_velocity); + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][1], seq_chord_velocity); + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][2], seq_chord_velocity); + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose + seq_chords[seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step] - 200][3], seq_chord_velocity); } } + else if (seq_track_type[d] == 3) { //Arp + arp_step = 0; + arp_counter = 0; + arp_note = seq_data[ seq_patternchain[seq_chain_active_step][d] ][seq_step] + seq_transpose; + arp_chord = seq_vel[ seq_patternchain[seq_chain_active_step][d] ][seq_step]; + } } - if (seq_track_type[d] == 3) - { //Arp - if (arp_speed == 0 || (arp_speed == 1 && arp_counter == 2) ) { - if (arp_step == 0 ) { - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + arp_octave * 12 , seq_chord_velocity); - arp_note_prev = arp_note + arp_octave * 12; + } + if (seq_track_type[d] == 3) + { //Arp + if (arp_speed == 0 || (arp_speed == 1 && arp_counter == 2) ) { + if (arp_step == 0 ) { + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + arp_octave * 12 , seq_chord_velocity); + arp_note_prev = arp_note + arp_octave * 12; + } + else + { if (arp_style == 0) { //arp up + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + seq_chords[arp_chord - 200][arp_step - 1] + arp_octave * 12, seq_chord_velocity); + arp_note_prev = arp_note + seq_chords[arp_chord - 200][arp_step - 1] + arp_octave * 12; } - else - { if (arp_style == 0) { //arp up - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + seq_chords[arp_chord - 200][arp_step - 1] + arp_octave * 12, seq_chord_velocity); - arp_note_prev = arp_note + seq_chords[arp_chord - 200][arp_step - 1] + arp_octave * 12; - } - else if (arp_style == 3) { //arp random - uint8_t rnd1 = random(4); - uint8_t rnd2 = random(arp_oct_usersetting + 1) * 12; - handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + seq_chords[arp_chord - 200][rnd1] + rnd2, seq_chord_velocity); - arp_note_prev = arp_note + seq_chords[arp_chord - 200][rnd1] + rnd2; - } + else if (arp_style == 3) { //arp random + uint8_t rnd1 = random(4); + uint8_t rnd2 = random(arp_oct_usersetting + 1) * 12; + handleNoteOn(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note + seq_chords[arp_chord - 200][rnd1] + rnd2, seq_chord_velocity); + arp_note_prev = arp_note + seq_chords[arp_chord - 200][rnd1] + rnd2; } } } - seq_noteoffsent[d] = false; } + seq_noteoffsent[d] = false; + } - seq_step++; + seq_step++; - if (arp_speed == 0) // Arp Speed 1/16 - { - arp_step++; - } - else + if (arp_speed == 0) // Arp Speed 1/16 + { + arp_step++; + } + else + { + if (arp_speed == 1) // Arp Speed 1/8 { - if (arp_speed == 1) // Arp Speed 1/8 - { - if (arp_counter > 1) { - arp_counter = 0; - arp_step++; - } - arp_counter++; + if (arp_counter > 1) { + arp_counter = 0; + arp_step++; } + arp_counter++; } - if (arp_step > 3 || seq_chords[arp_chord - 200][arp_step] == 0 ) { - arp_step = 0; - arp_octave++; - if (arp_octave > arp_oct_usersetting) arp_octave = 0; - } - if (seq_step > 15) { - seq_step = 0; - if (seq_chain_lenght > 0) { - seq_chain_active_step++; - if (seq_chain_active_step > seq_chain_lenght) - { - seq_chain_active_step = 0; - } + } + if (arp_step > 3 || seq_chords[arp_chord - 200][arp_step] == 0 ) { + arp_step = 0; + arp_octave++; + if (arp_octave > arp_oct_usersetting) arp_octave = 0; + } + if (seq_step > 15) { + seq_step = 0; + if (seq_chain_lenght > 0) { + seq_chain_active_step++; + if (seq_chain_active_step > seq_chain_lenght) + { + seq_chain_active_step = 0; } } } - if (seq_millis_timer > seq_timer_previous + 80 ) +} + +void sequencer_part2(void) +{ + for (uint8_t d = 0; d < 4; d++) { - for (uint8_t d = 0; d < 4; d++) - { - if ( seq_noteoffsent[d] == false) { - if ( seq_prev_note[d] > 0 && seq_track_type[d] > 0) //test instrument sequencer Instance=0 - { - handleNoteOff(configuration.dexed[seq_inst_dexed[d]].midi_channel, seq_prev_note[d] , 0); - if (seq_track_type[d] == 2) { //Chords - if ( seq_prev_vel[d] > 199) { - handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][0], 0); - handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][1] , 0); - handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][2] , 0); - handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][3] , 0); - } - } - else if (seq_track_type[d] == 3) - { //Arp - handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note_prev, 0); + if ( seq_noteoffsent[d] == false) { + if ( seq_prev_note[d] > 0 && seq_track_type[d] > 0) + { + handleNoteOff(configuration.dexed[seq_inst_dexed[d]].midi_channel, seq_prev_note[d] , 0); + if (seq_track_type[d] == 2) { //Chords + if ( seq_prev_vel[d] > 199) { + handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][0], 0); + handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][1] , 0); + handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][2] , 0); + handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, seq_prev_note[d] + seq_chords[seq_prev_vel[d] - 200][3] , 0); } } + else if (seq_track_type[d] == 3) + { //Arp + handleNoteOff(configuration.dexed[seq_chord_dexed_inst].midi_channel, arp_note_prev, 0); + } } seq_noteoffsent[d] = true; } } } + + +void sequencer(void) +{ // Runs in Interrupt Timer. Switches between the Noteon and Noteoff Task, each cycle + + interrupt_swapper = !interrupt_swapper; + + if (interrupt_swapper) sequencer_part1(); + else sequencer_part2(); +} diff --git a/sequencer.h b/sequencer.h index 84a5237..025d8eb 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,15 +3,13 @@ uint8_t seq_active_track = 0; uint8_t seq_menu; bool seq_button_r = false; bool seq_noteoffsent[4] = {false, false, false, false}; -elapsedMillis seq_millis_timer; uint8_t seq_step = 0; -uint32_t seq_timer_previous = 0; bool seq_running = false; bool seq_recording = false; uint8_t seq_note_in; uint8_t seq_note_in_velocity; int seq_transpose; -uint8_t seq_inst_dexed[4] = { 1, 1, 1, 1 }; +uint8_t seq_inst_dexed[4] = { 0, 0, 0, 1 }; uint8_t seq_chord_dexed_inst = 0; uint8_t seq_chord_velocity = 50; uint8_t arp_style = 0; // up, down, up&down, random @@ -64,11 +62,10 @@ uint8_t seq_data[10][16] = {72 , 0 , 0 , 0 , 72 , 0 , 0 , 0 , 72 , 0 , 0 74 , 0 , 0 , 72 , 0 , 0 , 74 , 0 , 0 , 0 , 76 , 0 , 0 , 0 , 0 , 0 , 74 , 0 , 0 , 72 , 0 , 0 , 71 , 0 , 0 , 0 , 67 , 0 , 0 , 0 , 0 , 0 , 69 , 0 , 0 , 76 , 0 , 0 , 69 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 - }; uint8_t seq_vel[10][16] = {120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, 0, 105, 80, 105, 70, 106, 98, 106, 70, 126, 97, 106, 70, 106, 99, 90, 65, - 120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 120, 50, 120, 120, 0, 0, + 120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 120, 60, 120, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 200, 200, 200, 200, 200, 200, 201, 0, 0, 0, 0, 0, 0, 0, 0, 200, @@ -80,8 +77,8 @@ uint8_t seq_vel[10][16] = {120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, uint8_t seq_patternchain[4][4] = { 0 , 1 , 6 , 9 , 0 , 1 , 5 , 8 , 0 , 1 , 6 , 9 , 2 , 1 , 5 , 7 }; -uint8_t seq_content_type[10] = { 0, 0, 0, 0 , 1, 2, 2 , 1 , 1 , 1 }; // 0 = track is Drumtrack, 1= Instrumenttrack, 2= Chord or Arpeggio -uint8_t seq_track_type[4] = { 0, 0, 3, 1 }; // 0 = track is Drumtrack, 1 = Instrumenttrack, 2 = Chord, 3 = Arp +uint8_t seq_content_type[10] = { 0, 0, 0, 0 , 1, 1, 1 , 1 , 1 , 1 }; // 0 = track is Drumtrack, 1= Instrumenttrack, 2= Chord or Arpeggio +uint8_t seq_track_type[4] = { 0, 0, 1, 1 }; // 0 = track is Drumtrack, 1 = Instrumenttrack, 2 = Chord, 3 = Arp //uint8_t seq_reverb[4][16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0,