diff --git a/MicroDexed.ino b/MicroDexed.ino index 23d1f5e..6c4f73a 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -637,2186 +637,2184 @@ void setup() #endif LCDML.OTHER_jumpToFunc(UI_func_voice_select); + timer1.begin(sequencer, 90000, false); +} - timer1.begin(sequencer, 74'000,false); +void loop() +{ + // MIDI input handling + check_midi_devices(); - } + // check encoder + ENCODER[ENC_L].update(); + ENCODER[ENC_R].update(); - void loop() - { - // MIDI input handling - check_midi_devices(); +#ifdef ENABLE_LCD_UI + LCDML.loop(); +#endif - // check encoder - ENCODER[ENC_L].update(); - ENCODER[ENC_R].update(); + 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][0]); + lcd.print( seq_chord_names[arp_chord][1]); + lcd.print( seq_chord_names[arp_chord][2]); + lcd.print( seq_chord_names[arp_chord][3]); + } + } + } + // CONTROL-RATE-EVENT-HANDLING + if (control_rate > CONTROL_RATE_MS) + { + control_rate = 0; -#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][0]); - lcd.print( seq_chord_names[arp_chord][1]); - lcd.print( seq_chord_names[arp_chord][2]); - lcd.print( seq_chord_names[arp_chord][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++) - { + // 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); + 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("]")); -#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(); + } + } + } +} - // 1 Bank bulk upload - if ((sysex[3] & 0x7f) != 9) - { +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.println(F("E: Not a SysEx bank bulk upload.")); + Serial.print(F("INSTANCE ")); + Serial.print(instance_id, DEC); + Serial.println(F(": SYSEX-MIDI-Channel mismatch")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (TYPE) ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + return; + } #ifdef DEBUG - Serial.println(F("Bank bulk upload.")); + 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 - if (((sysex[4] << 7) | sysex[5]) != 0x1000) - { + // Check for SYSEX end byte + if (sysex[len - 1] != 0xf7) + { #ifdef DEBUG - Serial.println(F("E: Wrong length for SysEx bank bulk upload (not 4096).")); + Serial.println(F("E: SysEx end status byte not detected.")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (SIZE) ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + return; + } + if (sysex[1] != 0x43) // check for Yamaha sysex + { #ifdef DEBUG - Serial.println(F("Bank type ok")); + Serial.println(F("E: SysEx vendor not Yamaha.")); #endif + return; + } - // checksum calculation - for (uint16_t i = 0; i < 4096 ; i++) - { - bulk_checksum_calc -= sysex[i + 6]; - } - bulk_checksum_calc &= 0x7f; +#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]; + + // 1 Bank bulk upload + if ((sysex[3] & 0x7f) != 9) + { +#ifdef DEBUG + 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; + } + +#ifdef DEBUG + Serial.println(F("Bank bulk upload.")); +#endif + + if (((sysex[4] << 7) | sysex[5]) != 0x1000) + { +#ifdef DEBUG + 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; + } - 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.println(F("Bank type ok")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Error (CHECKSUM)")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - return; - } + // 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) + { #ifdef DEBUG - Serial.println(F("Bank checksum ok")); + 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; + } - 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.println(F("Bank checksum ok")); #endif - lcd.setCursor(0, 1); - lcd.print(F("Done. ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - } - else - { + + if (save_sd_bank(receive_bank_filename, sysex)) + { #ifdef DEBUG - Serial.println(F("Error during saving bank 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("Error. ")); - delay(MESSAGE_WAIT_TIME); - LCDML.FUNC_goBackToMenu(); - } - memset(receive_bank_filename, 0, FILENAME_LEN); - } + lcd.setCursor(0, 1); + lcd.print(F("Done. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + else + { #ifdef DEBUG - else - Serial.println(F("E: Not in MIDI receive bank mode.")); + 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); + } #ifdef DEBUG - else - Serial.println(F("E: SysEx parameter length wrong.")); + else + Serial.println(F("E: Not in MIDI receive bank mode.")); #endif - } - } + } +#ifdef DEBUG + 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. + //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 + } +} - sprintf(tmp, "/%s/fav-v2", FAV_CONFIG_PATH); - if (!SD.exists(tmp)) { +/****************************************************************************** + 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; - // 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); + 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("Delete Marker File")); - Serial.println(tmp); + Serial.print(F("*")); #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 - } - } - - /****************************************************************************** - 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); + 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