diff --git a/addon/SD/SEQ/UI.hpp b/addon/SD/SEQ/UI.hpp new file mode 100644 index 0000000..bc2bab4 --- /dev/null +++ b/addon/SD/SEQ/UI.hpp @@ -0,0 +1,9654 @@ +/* + MicroDexed + + MicroDexed is a port of the Dexed sound engine + (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6/4.x with audio shield. + Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android + + (c)2018-2021 H. Wirtz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef ENABLE_LCD_UI +#ifndef _UI_HPP_ +#define _UI_HPP_ + +#include +#include +#include "config.h" +#include "disp_plus.h" +#include "synth_dexed.h" +#include "effect_modulated_delay.h" +#include "effect_stereo_mono.h" +#ifdef USE_PLATEREVERB +#include "effect_platervbstereo.h" +#else +#include "effect_freeverbf.h" +#endif +#include "drumset.h" + +#define _LCDML_DISP_cols LCD_cols +#define _LCDML_DISP_rows LCD_rows + +#ifdef I2C_DISPLAY +#define _LCDML_DISP_cfg_cursor 0x7E // cursor Symbol +#else +#define _LCDML_DISP_cfg_cursor 0x8d // cursor Symbol +#endif +#define _LCDML_DISP_cfg_scrollbar 1 // enable a scrollbar + +extern PeriodicTimer timer1; +extern void sequencer(void); +extern bool check_sd_seq_exists(uint8_t); + +extern config_t configuration; +extern void set_volume(uint8_t v, uint8_t m); +extern bool load_sysex(uint8_t b, uint8_t v); +extern void generate_version_string(char* buffer, uint8_t len); +extern void initial_values_from_eeprom(bool init); +extern void _softRestart(void); +extern void eeprom_update_sys(void); +extern void eeprom_update_performance(void); +extern void eeprom_update_fx(void); +extern void eeprom_update_dexed(uint8_t instance_id); +//extern float pseudo_log_curve(float value); +extern float midi_volume_transform(uint8_t midi_amp); +extern float volume_transform(float amp); +extern uint8_t selected_instance_id; +extern char receive_bank_filename[FILENAME_LEN]; + +#if NUM_DRUMS > 0 +#include "drums.h" +extern void get_sd_seq_name_json(uint8_t number); +extern drum_config_t drum_config[NUM_DRUMSET_CONFIG]; +extern char seq_name[FILENAME_LEN]; +extern char seq_name_temp[FILENAME_LEN]; +extern uint8_t seq_vel[NUM_SEQ_PATTERN][16]; +extern uint8_t seq_patternchain[4][NUM_SEQ_TRACKS]; +extern uint8_t seq_content_type[NUM_SEQ_PATTERN]; +extern uint8_t seq_track_type[NUM_SEQ_TRACKS]; +extern uint8_t seq_step; +extern uint8_t seq_chord_key_ammount; +extern int seq_tempo_ms; +extern uint8_t seq_bpm; +extern uint8_t seq_chain_lenght; +extern bool seq_running; +extern bool seq_recording; +extern bool smartfilter; +extern uint8_t seq_state_last_loadsave; +extern uint8_t seq_active_track; +extern uint8_t seq_menu; +extern uint8_t seq_temp_select_menu; +extern uint8_t seq_temp_active_menu; +extern uint8_t seq_chain_active_chainstep; //for editor +extern uint8_t seq_chain_active_step; +extern int seq_transpose; +extern uint8_t seq_inst_dexed[NUM_SEQ_TRACKS]; +extern uint8_t arp_step; +extern uint8_t arp_note; +extern uint8_t arp_chord; +extern uint8_t arp_octave; +extern uint8_t arp_lenght; +extern uint8_t arp_style; +extern uint8_t arp_speed; +extern uint8_t seq_element_shift; +extern int seq_oct_shift; +extern char arp_style_names[4][3]; +extern char seq_chord_names[7][4]; +extern uint8_t seq_data_buffer[16]; +extern float drums_volume; +extern uint8_t drum_midi_channel; +uint8_t seq_active_function = 99; +uint8_t activesample; extern uint8_t seq_data[10][16]; +#endif + +#ifdef DISPLAY_LCD_SPI +extern void change_disp_sd(bool d); +#endif + +#ifdef SGTL5000_AUDIO_ENHANCE +#include "control_sgtl5000plus.h" +extern AudioControlSGTL5000Plus sgtl5000; +#else +extern AudioControlSGTL5000 sgtl5000; +#endif + +#if defined(USE_FX) +extern AudioSynthWaveform* chorus_modulator[NUM_DEXED]; +extern AudioEffectModulatedDelay* modchorus[NUM_DEXED]; +extern AudioMixer4* chorus_mixer[NUM_DEXED]; +extern AudioMixer4* delay_fb_mixer[NUM_DEXED]; +extern AudioEffectDelay* delay_fx[NUM_DEXED]; +extern AudioMixer4* delay_mixer[NUM_DEXED]; +#endif +extern AudioEffectMonoStereo* mono2stereo[NUM_DEXED]; + +extern AudioMixer4 microdexed_peak_mixer; +extern AudioAnalyzePeak microdexed_peak; +#if defined(USE_FX) +extern AudioMixer4 reverb_mixer_r; +extern AudioMixer4 reverb_mixer_l; +#ifdef USE_PLATEREVERB +extern AudioEffectPlateReverb reverb; +#else +extern AudioEffectFreeverbStereoFloat freeverb; +#endif +#endif +extern AudioMixer4 master_mixer_r; +extern AudioMixer4 master_mixer_l; +extern AudioEffectStereoMono stereo2mono; +extern AudioAnalyzePeak master_peak_r; +extern AudioAnalyzePeak master_peak_l; + +extern char sd_string[LCD_cols + 1]; +extern char g_voice_name[NUM_DEXED][VOICE_NAME_LEN]; +extern char g_bank_name[NUM_DEXED][BANK_NAME_LEN]; +extern int perform_attack_mod[NUM_DEXED]; +extern int perform_release_mod[NUM_DEXED]; +extern float midi_ticks_factor[10]; +extern uint8_t midi_bpm; + +/*********************************************************************** + GLOBAL +************************************************************************/ +elapsedMillis back_from_volume; +uint8_t instance_num[8][8]; +const char accepted_chars[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-abcdefghijklmnopqrstuvwxyz"; +const char noteNames[12][3] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; +uint8_t active_perform_page = 1; +uint8_t orig_attack_values[2][7]; +uint8_t orig_release_values[2][7]; +int temp_int; +bool menu_select_toggle; +float temp_float; + + +#ifdef I2C_DISPLAY +#include +Disp_Plus lcd(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows); +#endif + +#ifdef U8X8_DISPLAY +#include +#ifdef U8X8_HAVE_HW_SPI +#include +#endif +#ifdef U8X8_HAVE_HW_I2C +#include +#endif +Disp_Plus lcd(/* cs=*/ U8X8_CS_PIN, /* dc=*/ U8X8_DC_PIN, /* reset=*/ U8X8_RESET_PIN); +//Disp_Plus lcd(U8X8_PIN_NONE); +#endif + +const uint8_t scroll_bar[5][8] = { + {B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001}, // scrollbar top + {B11111, B11111, B10001, B10001, B10001, B10001, B10001, B10001}, // scroll state 1 + {B10001, B10001, B11111, B11111, B10001, B10001, B10001, B10001}, // scroll state 2 + {B10001, B10001, B10001, B10001, B11111, B11111, B10001, B10001}, // scroll state 3 + {B10001, B10001, B10001, B10001, B10001, B10001, B11111, B11111} // scrollbar bottom +}; + +const uint8_t block_bar[5][8] = { + {B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000}, + {B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000}, + {B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100}, + {B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110}, + {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111} +}; + +const uint8_t meter_bar[5][8] = { + {B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000}, + {B01000, B01000, B01000, B01000, B01000, B01000, B01000, B01000}, + {B00100, B00100, B00100, B00100, B00100, B00100, B00100, B00100}, + {B00010, B00010, B00010, B00010, B00010, B00010, B00010, B00010}, + {B00001, B00001, B00001, B00001, B00001, B00001, B00001, B00001} +}; + +const uint8_t special_chars[22][8] = { + {B11111, B11011, B10011, B11011, B11011, B11011, B11011, B11111}, // [0] 1 small invers + {B11111, B11011, B10101, B11101, B11011, B10111, B10001, B11111}, // [1] 2 small invers + {B11111, B11011, B10011, B11011, B11011, B11011, B11011, B11111}, // [2] 1 OP invers + {B11111, B11011, B10101, B11101, B11011, B10111, B10001, B11111}, // [3] 2 OP invers + {B11111, B10001, B11101, B11011, B11101, B10101, B11011, B11111}, // [4] 3 OP invers + {B11111, B10111, B10111, B10101, B10001, B11101, B11101, B11111}, // [5] 4 OP invers + {B11111, B10001, B10111, B10011, B11101, B11101, B10011, B11111}, // [6] 5 OP invers + {B11111, B11001, B10111, B10011, B10101, B10101, B11011, B11111}, // [7] 6 OP invers + {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111}, // [8] Level 1 + {B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111}, // [9] Level 2 + {B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111}, // [10] Level 3 + {B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111}, // [11] Level 4 + {B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111}, // [12] Level 5 + {B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111}, // [13] Level 6 + {B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111}, // [14] Level 7 + {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111}, // [15] Level 8 + {B00100, B00110, B00101, B00101, B01101, B11101, B11100, B11000}, // [16] Note + {B01110, B10001, B10001, B01110, B00100, B00100, B00110, B00110}, // [17] Disabled 2nd instance symbol + {B11111, B10001, B10111, B10001, B10111, B10111, B10111, B11111}, // [18] Favorites Icon + {B01000, B01100, B01110, B01111, B01110, B01100, B01000, B00000}, // [19] Play Symbol + {B00000, B01110, B11111, B11111, B11111, B01110, B00000, B00000}, // [20] Record Symbol + {B00000, B00000, B01110, B01110, B01110, B00000, B00000, B00000} // [21] Stop Symbol +}; + +enum { SCROLLBAR, BLOCKBAR, METERBAR }; +enum { ENC_R, ENC_L }; +enum {MENU_VOICE_BANK, MENU_VOICE_SOUND}; + +void lcdml_menu_display(void); +void lcdml_menu_clear(void); +void lcdml_menu_control(void); +#ifdef USE_FX +void UI_func_reverb_roomsize(uint8_t param); +void UI_func_reverb_damping(uint8_t param); +void UI_func_reverb_lowpass(uint8_t param); +void UI_func_reverb_lodamp(uint8_t param); +void UI_func_reverb_hidamp(uint8_t param); +void UI_func_reverb_diffusion(uint8_t param); +void UI_func_reverb_level(uint8_t param); +void UI_func_chorus_frequency(uint8_t param); +void UI_func_chorus_waveform(uint8_t param); +void UI_func_chorus_depth(uint8_t param); +void UI_func_chorus_level(uint8_t param); +void UI_func_delay_time(uint8_t param); +void UI_func_delay_feedback(uint8_t param); +void UI_func_delay_level(uint8_t param); +void UI_func_reverb_send(uint8_t param); +void UI_func_filter_cutoff(uint8_t param); +void UI_func_filter_resonance(uint8_t param); +void UI_func_drum_reverb_send(uint8_t param); +#endif +void UI_func_transpose(uint8_t param); +void UI_func_tune(uint8_t param); +void UI_func_midi_channel(uint8_t param); +void UI_func_lowest_note(uint8_t param); +void UI_func_highest_note(uint8_t param); +void UI_func_sound_intensity(uint8_t param); +void UI_func_panorama(uint8_t param); +void UI_func_stereo_mono(uint8_t param); +void UI_func_note_refresh(uint8_t param); +void UI_func_polyphony(uint8_t param); +void UI_func_mono_poly(uint8_t param); +void UI_func_pb_range(uint8_t param); +void UI_func_pb_step(uint8_t param); +void UI_func_mw_range(uint8_t param); +void UI_func_mw_assign(uint8_t param); +void UI_func_mw_mode(uint8_t param); +void UI_func_fc_range(uint8_t param); +void UI_func_fc_assign(uint8_t param); +void UI_func_fc_mode(uint8_t param); +void UI_func_bc_range(uint8_t param); +void UI_func_bc_assign(uint8_t param); +void UI_func_bc_mode(uint8_t param); +void UI_func_at_range(uint8_t param); +void UI_func_at_assign(uint8_t param); +void UI_func_at_mode(uint8_t param); +void UI_func_portamento_mode(uint8_t param); +void UI_func_portamento_glissando(uint8_t param); +void UI_func_portamento_time(uint8_t param); +void UI_handle_OP(uint8_t param); +void UI_func_information(uint8_t param); +void UI_func_seq_pattern_editor(uint8_t param); +void UI_func_seq_vel_editor(uint8_t param); +void UI_func_seq_live_transpose_oct(uint8_t param); +void UI_func_arp_shift(uint8_t param); +void UI_func_seq_chord_keys_ammount(uint8_t param); +void UI_func_seq_lenght(uint8_t param); +void UI_func_seq_tempo(uint8_t param); +void UI_func_seq_pat_chain(uint8_t param); +void UI_func_arpeggio(uint8_t param); +void UI_func_seq_track_setup(uint8_t param); +void UI_func_dexed_assign(uint8_t param); +void UI_func_seq_display_style(uint8_t param); +void UI_func_seq_state_load(uint8_t param); +void UI_func_seq_state_save(uint8_t param); +void UI_func_set_sequence_name(uint8_t param); +void UI_func_volume(uint8_t param); +void UI_func_smart_filter(uint8_t param); +void UI_func_drum_midi_channel(uint8_t param); +void UI_func_load_performance(uint8_t param); +void UI_func_save_performance(uint8_t param); +void UI_func_load_voiceconfig(uint8_t param); +void UI_func_save_voiceconfig(uint8_t param); +void UI_func_save_voice(uint8_t param); +void UI_func_load_fx(uint8_t param); +void UI_func_save_fx(uint8_t param); +void UI_func_eeprom_reset(uint8_t param); +void UI_func_midi_soft_thru(uint8_t param); +void UI_func_velocity_level(uint8_t param); +void UI_func_voice_select(uint8_t param); +void UI_func_sysex_send_voice(uint8_t param); +void UI_func_sysex_receive_bank(uint8_t param); +void UI_func_sysex_send_bank(uint8_t param); +void UI_func_eq_1(uint8_t param); +void UI_func_eq_2(uint8_t param); +void UI_func_eq_3(uint8_t param); +void UI_func_eq_4(uint8_t param); +void UI_func_eq_5(uint8_t param); +void UI_func_eq_6(uint8_t param); +void UI_func_eq_7(uint8_t param); +void UI_function_not_enabled(void); +void UI_function_not_implemented(uint8_t param); +void UI_func_favorites(uint8_t param); +void UI_update_instance_icons(); +bool UI_select_name(uint8_t y, uint8_t x, char* edit_string, uint8_t len, bool init); +uint8_t search_accepted_char(uint8_t c); +void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign); +void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign); +void lcd_display_bar_int(const char* title, uint32_t value, float factor, int32_t min_value, int32_t max_value, uint8_t size, bool zeros, bool sign, bool init); +void lcd_display_bar_float(const char* title, float value, float factor, int32_t min_value, int32_t max_value, uint8_t size_number, uint8_t size_fraction, bool zeros, bool sign, bool init); +void lcd_display_meter_int(const char* title, uint32_t value, float factor, float offset, int32_t min_value, int32_t max_value, uint8_t size, bool zeros, bool sign, bool init); +void lcd_display_meter_float(const char* title, float value, float factor, float offset, int32_t min_value, int32_t max_value, uint8_t size_number, uint8_t size_fraction, bool zeros, bool sign, bool init); +void lcd_active_instance_number(uint8_t instance_id); +void lcd_OP_active_instance_number(uint8_t instance_id, uint8_t op); +void lcd_special_chars(uint8_t mode); +void eeprom_update_var(uint16_t pos, uint8_t val, const char* val_string); +void lcd_display_delay_sync(uint8_t sync); +void string_trim(char *s); +void save_favorite(uint8_t b, uint8_t v, uint8_t instance_id); +void draw_favorite_icon(uint8_t b, uint8_t v, uint8_t instance_id); +bool check_favorite(uint8_t b, uint8_t v, uint8_t instance_id); +bool quick_check_favorites_in_bank(uint8_t b, uint8_t instance_id); +void locate_previous_non_favorite(); +void locate_previous_favorite(); +void locate_next_favorite(); +void locate_next_non_favorite(); +void locate_random_non_favorite(); +void UI_func_drums_main_volume(uint8_t param); +void UI_func_drum_volume(uint8_t param); +void UI_func_drum_pan(uint8_t param); +void UI_func_drum_pitch(uint8_t param); +void UI_func_drum_tune_offset(uint8_t param); + +char* basename(const char* filename); +char* strip_extension(char* filename); + +// normal menu +LCDMenuLib2_menu LCDML_0(255, 0, 0, NULL, NULL); // normal root menu element (do not change) +LCDMenuLib2 LCDML(LCDML_0, _LCDML_DISP_rows, _LCDML_DISP_cols, lcdml_menu_display, lcdml_menu_clear, lcdml_menu_control); + +#if defined(USE_FX) +#if defined(TEENSY4) +#include "UI_FX_T4.h" +#else +#include "UI_FX.h" +#endif +#else +#include "UI_NO_FX.h" +#endif + +int favsearcher = 0; + +// create menu +LCDML_createMenu(_LCDML_DISP_cnt); + +/*********************************************************************** + CONTROL + ***********************************************************************/ +class EncoderDirection +{ + public: + EncoderDirection(void) + { + reset(); + } + + void reset(void) + { + button_short = false; + button_long = false; + button_pressed = false; + left = false; + right = false; + up = false; + down = false; + } + + void ButtonShort(bool state) + { + button_short = state; + } + + bool ButtonShort(void) + { + if (button_short == true) + { + button_short = false; + return (true); + } + return (false); + } + + void ButtonLong(bool state) + { + button_long = state; + } + + bool ButtonLong(void) + { + if (button_long == true) + { + button_long = false; + return (true); + } + return (false); + } + + void ButtonPressed(bool state) + { + button_pressed = state; + } + + bool ButtonPressed(void) + { + return (button_pressed); + } + + void Left(bool state) + { + left = state; + } + + bool Left(void) + { + if (left == true) + { + left = false; + return (true); + } + return (false); + } + + void Right(bool state) + { + right = state; + } + + bool Right(void) + { + if (right == true) + { + right = false; + return (true); + } + return (false); + } + + void Up(bool state) + { + up = state; + } + + bool Up(void) + { + if (up == true) + { + up = false; + return (true); + } + return (false); + } + + void Down(bool state) + { + down = state; + } + + bool Down(void) + { + if (down == true) + { + down = false; + return (true); + } + return (false); + } + + private: + bool button_short; + bool button_long; + bool button_pressed; + bool left; + bool right; + bool up; + bool down; +}; + +//Encoder ENCODER[NUM_ENCODER] = {Encoder(ENC_R_PIN_B, ENC_R_PIN_A), Encoder(ENC_L_PIN_B, ENC_L_PIN_A)}; +MD_REncoder ENCODER[NUM_ENCODER] = {MD_REncoder(ENC_R_PIN_B, ENC_R_PIN_A), MD_REncoder(ENC_L_PIN_B, ENC_L_PIN_A)}; +EncoderDirection encoderDir[NUM_ENCODER]; + +long g_LCDML_CONTROL_button_press_time[NUM_ENCODER] = {0, 0}; +bool g_LCDML_CONTROL_button_prev[NUM_ENCODER] = {HIGH, HIGH}; +uint8_t g_LCDML_CONTROL_prev[NUM_ENCODER] = {0, 0}; +bool menu_init = true; + +#ifdef U8X8_DISPLAY +const uint8_t * flipped_scroll_bar[5]; +const uint8_t * flipped_block_bar[7]; +const uint8_t * flipped_meter_bar[7]; + +uint8_t * rotTile(const uint8_t * tile) +{ + uint8_t * newt = new uint8_t[8]; + for (int x = 0; x < 8; x++) { + uint8_t newb = 0; + for (int y = 0 ; y < 8; y++) { + newb |= (tile[y] << x) & 0x80; + newb >>= 1; + } + newt[x] = newb; + } + return newt; +} +#endif + +void smart_filter(uint8_t dir) +{ + bool found = false; + + //search backwards + if (dir == 0) { + if (smartfilter) { + do { + if (found == false) activesample = constrain(activesample - 1, 0, NUM_DRUMSET_CONFIG - 2); + for (uint8_t d = 0; d < 10; d++) + { + if (seq_content_type[d] == 0) { + for (uint8_t y = 0; y < 16; y++) + { + if (drum_config[activesample].midinote == seq_data[d][y] || drum_config[activesample].midinote == seq_vel[d][y]) + { + found = true; + break; + } + } + } + } + } while (found == false && activesample > 0 ); + } + else + activesample = constrain(activesample - 1, 0, NUM_DRUMSET_CONFIG - 2); + } + else //search forwards + { + if (smartfilter) { + do { + if (found == false) activesample = constrain(activesample + 1, 0, NUM_DRUMSET_CONFIG - 2); + for (uint8_t d = 0; d < 10; d++) + { + if (seq_content_type[d] == 0) { + + for (uint8_t y = 0; y < 16; y++) + { + if (drum_config[activesample].midinote == seq_data[d][y] || drum_config[activesample].midinote == seq_vel[d][y]) + { + found = true; + break; + } + } + } + } + } while (found == false && activesample < NUM_DRUMSET_CONFIG - 2 ); + } + else + activesample = constrain(activesample + 1, 0, NUM_DRUMSET_CONFIG - 2); + } +} + +void setup_ui(void) +{ + // LCD Begin +#ifdef I2C_DISPLAY + lcd.init(); + lcd.backlight(); + lcd.clear(); + lcd.noCursor(); +#else + lcd.begin(); + lcd.clear(); + lcd.setFont(u8x8_font_amstrad_cpc_extended_f); +#endif + lcd.setCursor(3, 0); + lcd.print(F("MicroDexed")); + lcd.setCursor(0, 1); + lcd.print(F("(c)parasiTstudio")); + + lcd_special_chars(SCROLLBAR); + // LCDMenuLib Setup + LCDML_setup(_LCDML_DISP_cnt); + // Enable Menu Rollover + //LCDML.MENU_enRollover(); + // Enable Screensaver (screensaver menu function, time to activate in ms) + //LCDML.SCREEN_enable(UI_func_voice_select, VOICE_SELECTION_MS); +} + +#ifdef DEBUG +void setup_debug_message(void) +{ + // LCD Begin + lcd.clear(); + lcd.setCursor(1, 0); + lcd.print(F("* DEBUG MODE *")); + lcd.setCursor(1, 1); + lcd.print(F("ENABLE CONSOLE")); + delay(300); + lcd.setCursor(1, 1); + lcd.print(_LCDML_VERSION); + lcd.print(F(" ")); +} +#endif + +/*********************************************************************** + MENU CONTROL + ***********************************************************************/ +uint8_t get_current_cursor_id(void) +{ + LCDMenuLib2_menu *tmp; + + if ((tmp = LCDML.MENU_getCurrentObj()) != NULL) + return (tmp->getChild(LCDML.MENU_getCursorPosAbs())->getID()); + else + return (0); +} + +void lcdml_menu_control(void) +{ + // If something must init, put in in the setup condition + if (LCDML.BT_setup()) + { + pinMode(BUT_R_PIN, INPUT_PULLUP); + pinMode(BUT_L_PIN, INPUT_PULLUP); + + ENCODER[ENC_R].begin(); + ENCODER[ENC_L].begin(); + } + + if (back_from_volume > BACK_FROM_VOLUME_MS && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_volume)) + { + encoderDir[ENC_L].reset(); + encoderDir[ENC_R].reset(); + + if (LCDML.MENU_getLastActiveFunctionID() < 0xff) + LCDML.OTHER_jumpToID(LCDML.MENU_getLastActiveFunctionID()); + else + LCDML.OTHER_setCursorToID(LCDML.MENU_getLastCursorPositionID()); + //LCDML.FUNC_goBackToMenu(); + } + + // Volatile Variables + long g_LCDML_CONTROL_Encoder_position[NUM_ENCODER] = {ENCODER[ENC_R].read(), ENCODER[ENC_L].read()}; + bool button[NUM_ENCODER] = {digitalRead(BUT_R_PIN), digitalRead(BUT_L_PIN)}; + + /************************************************************************************ + Basic encoder handling (from LCDMenuLib2) + ************************************************************************************/ + + // RIGHT + if (g_LCDML_CONTROL_Encoder_position[ENC_R] <= -3) + { + if (!button[ENC_R]) + { + LCDML.BT_left(); +#ifdef DEBUG + Serial.println(F("ENC-R left")); +#endif + encoderDir[ENC_R].Left(true); + g_LCDML_CONTROL_button_prev[ENC_R] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_R] = -1; + } + else + { +#ifdef DEBUG + Serial.println(F("ENC-R down")); +#endif + encoderDir[ENC_R].Down(true); + LCDML.BT_down(); + } + ENCODER[ENC_R].write(g_LCDML_CONTROL_Encoder_position[ENC_R] + 4); + } + else if (g_LCDML_CONTROL_Encoder_position[ENC_R] >= 3) + { + if (!button[ENC_R]) + { +#ifdef DEBUG + Serial.println(F("ENC-R right")); +#endif + encoderDir[ENC_R].Right(true); + LCDML.BT_right(); + g_LCDML_CONTROL_button_prev[ENC_R] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_R] = -1; + } + else + { +#ifdef DEBUG + Serial.println(F("ENC-R up")); +#endif + encoderDir[ENC_R].Up(true); + LCDML.BT_up(); + } + ENCODER[ENC_R].write(g_LCDML_CONTROL_Encoder_position[ENC_R] - 4); + } + else + { + if (!button[ENC_R] && g_LCDML_CONTROL_button_prev[ENC_R]) //falling edge, button pressed + { + encoderDir[ENC_R].ButtonPressed(true); + g_LCDML_CONTROL_button_prev[ENC_R] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_R] = millis(); + } + else if (button[ENC_R] && !g_LCDML_CONTROL_button_prev[ENC_R]) //rising edge, button not active + { + encoderDir[ENC_R].ButtonPressed(false); + g_LCDML_CONTROL_button_prev[ENC_R] = HIGH; + + if (g_LCDML_CONTROL_button_press_time[ENC_R] < 0) + { + g_LCDML_CONTROL_button_press_time[ENC_R] = millis(); + //Reset for left right action + } + else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_R]) >= LONG_BUTTON_PRESS) + { +#ifdef DEBUG + Serial.println("ENC-R long released"); +#endif + //LCDML.BT_quit(); + encoderDir[ENC_R].ButtonLong(true); + } + else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_R]) >= BUT_DEBOUNCE_MS) + { +#ifdef DEBUG + Serial.println(F("ENC-R short")); +#endif + encoderDir[ENC_R].ButtonShort(true); + + LCDML.BT_enter(); + } + } + } + + if (encoderDir[ENC_R].ButtonPressed() == true && (millis() - g_LCDML_CONTROL_button_press_time[ENC_R]) >= LONG_BUTTON_PRESS) + { +#ifdef DEBUG + Serial.println("ENC-R long recognized"); +#endif + encoderDir[ENC_R].ButtonLong(true); + + // if (seq_running) { + // seq_running = false; + // seq_recording = false; + // seq_step = 0; + // seq_chain_active_step = 0; + // MicroDexed[0]->panic(); + // } + + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + LCDML.BT_enter(); + LCDML.OTHER_updateFunc(); + LCDML.loop_menu(); + encoderDir[ENC_R].ButtonPressed(false); + encoderDir[ENC_R].ButtonLong(false); + } + else + { + if (LCDML.FUNC_getID() < 0xff) + LCDML.FUNC_setGBAToLastFunc(); + else + LCDML.FUNC_setGBAToLastCursorPos(); + + LCDML.OTHER_jumpToFunc(UI_func_voice_select); + encoderDir[ENC_R].reset(); + } + } + + // LEFT + if (g_LCDML_CONTROL_Encoder_position[ENC_L] <= -3) + { + if (!button[ENC_L]) + { +#ifdef DEBUG + Serial.println(F("ENC-L left")); +#endif + encoderDir[ENC_L].Left(true); + LCDML.BT_left(); + g_LCDML_CONTROL_button_prev[ENC_L] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_L] = -1; + } + else + { +#ifdef DEBUG + Serial.println(F("ENC-L down")); +#endif + encoderDir[ENC_L].Down(true); + LCDML.BT_down(); + if (LCDML.FUNC_getID() != LCDML.OTHER_getIDFromFunction(UI_func_volume)) + { + LCDML.OTHER_jumpToFunc(UI_func_volume); + } + } + ENCODER[ENC_L].write(g_LCDML_CONTROL_Encoder_position[ENC_L] + 4); + } + else if (g_LCDML_CONTROL_Encoder_position[ENC_L] >= 3) + { + if (!button[ENC_L]) + { +#ifdef DEBUG + Serial.println(F("ENC-L right")); +#endif + encoderDir[ENC_L].Right(true); + LCDML.BT_right(); + g_LCDML_CONTROL_button_prev[ENC_L] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_L] = -1; + } + else + { +#ifdef DEBUG + Serial.println(F("ENC-L up")); +#endif + encoderDir[ENC_L].Up(true); + LCDML.BT_up(); + if (LCDML.FUNC_getID() != LCDML.OTHER_getIDFromFunction(UI_func_volume)) + { + LCDML.OTHER_jumpToFunc(UI_func_volume); + } + } + ENCODER[ENC_L].write(g_LCDML_CONTROL_Encoder_position[ENC_L] - 4); + } + else + { + if (!button[ENC_L] && g_LCDML_CONTROL_button_prev[ENC_L]) //falling edge, button pressed + { + encoderDir[ENC_L].ButtonPressed(true); + g_LCDML_CONTROL_button_prev[ENC_L] = LOW; + g_LCDML_CONTROL_button_press_time[ENC_L] = millis(); + } + else if (button[ENC_L] && !g_LCDML_CONTROL_button_prev[ENC_L]) //rising edge, button not active + { + encoderDir[ENC_L].ButtonPressed(false); + g_LCDML_CONTROL_button_prev[ENC_L] = HIGH; + + if (g_LCDML_CONTROL_button_press_time[ENC_L] < 0) + { + g_LCDML_CONTROL_button_press_time[ENC_L] = millis(); + //Reset for left right action + } + else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_L]) >= LONG_BUTTON_PRESS) + { +#ifdef DEBUG + Serial.println(F("ENC-L long released")); +#endif + //encoderDir[ENC_L].ButtonLong(true); + //LCDML.BT_quit(); + } + else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_L]) >= BUT_DEBOUNCE_MS) + { + //LCDML.BT_enter(); +#ifdef DEBUG + Serial.println(F("ENC-L short")); +#endif + encoderDir[ENC_L].ButtonShort(true); + + if ((LCDML.MENU_getLastActiveFunctionID() == 0xff && LCDML.MENU_getLastCursorPositionID() == 0) || menu_init == true) + { + LCDML.MENU_goRoot(); + menu_init = false; + } + else if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_volume)) + { + encoderDir[ENC_L].reset(); + encoderDir[ENC_R].reset(); + + if (LCDML.MENU_getLastActiveFunctionID() < 0xff) + LCDML.OTHER_jumpToID(LCDML.MENU_getLastActiveFunctionID()); + else + LCDML.OTHER_setCursorToID(LCDML.MENU_getLastCursorPositionID()); + } + else + LCDML.BT_quit(); + } + } + } + + if (encoderDir[ENC_L].ButtonPressed() == true && (millis() - g_LCDML_CONTROL_button_press_time[ENC_L]) >= LONG_BUTTON_PRESS) + { +#ifdef DEBUG + Serial.println(F("ENC-L long recognized")); +#endif + + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + save_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); + + //for (uint8_t i = 0; i < NUM_DEXED; i++) + // MicroDexed[i]->panic(); + + encoderDir[ENC_L].reset(); + encoderDir[ENC_R].reset(); + } +} + +/*********************************************************************** + MENU DISPLAY + ***********************************************************************/ +void lcdml_menu_clear(void) +{ + lcd.clear(); + lcd.setCursor(0, 0); +} + +void lcdml_menu_display(void) +{ + // update content + // *************** + if (LCDML.DISP_checkMenuUpdate()) { + // clear menu + // *************** + LCDML.DISP_clear(); + + // declaration of some variables + // *************** + // content variable + char content_text[_LCDML_DISP_cols]; // save the content text of every menu element + // menu element object + LCDMenuLib2_menu *tmp; + // some limit values + uint8_t i = LCDML.MENU_getScroll(); + uint8_t maxi = _LCDML_DISP_rows + i; + uint8_t n = 0; + + // check if this element has children + if ((tmp = LCDML.MENU_getDisplayedObj()) != NULL) + { + // loop to display lines + do + { + // check if a menu element has a condition and if the condition be true + if (tmp->checkCondition()) + { + // check the type off a menu element + if (tmp->checkType_menu() == true) + { + // display normal content + LCDML_getContent(content_text, tmp->getID()); + lcd.setCursor(1, n); + lcd.print(content_text); + } + else + { + if (tmp->checkType_dynParam()) { + tmp->callback(n); + } + } + // increment some values + i++; + n++; + } + // try to go to the next sibling and check the number of displayed rows + } while (((tmp = tmp->getSibling(1)) != NULL) && (i < maxi)); + } + } + + if (LCDML.DISP_checkMenuCursorUpdate()) + { + // init vars + uint8_t n_max = (LCDML.MENU_getChilds() >= _LCDML_DISP_rows) ? _LCDML_DISP_rows : (LCDML.MENU_getChilds()); + uint8_t scrollbar_min = 0; + uint8_t scrollbar_max = LCDML.MENU_getChilds(); + uint8_t scrollbar_cur_pos = LCDML.MENU_getCursorPosAbs(); + uint8_t scroll_pos = ((1.*n_max * _LCDML_DISP_rows) / (scrollbar_max - 1) * scrollbar_cur_pos); + + // display rows + for (uint8_t n = 0; n < n_max; n++) + { + //set cursor + lcd.setCursor(0, n); + + //set cursor char + if (n == LCDML.MENU_getCursorPos()) { + lcd.write(_LCDML_DISP_cfg_cursor); + } else { + lcd.write(' '); + } + + // delete or reset scrollbar + if (_LCDML_DISP_cfg_scrollbar == 1) { + if (scrollbar_max > n_max) { +#ifdef I2C_DISPLAY + lcd.setCursor((_LCDML_DISP_cols - 1), n); + lcd.write((uint8_t)0); +#else + lcd.drawTile((_LCDML_DISP_cols - 1), n, 1, flipped_scroll_bar[0]); + lcd.setCursor((_LCDML_DISP_cols), n + 1); +#endif + } + else { + lcd.setCursor((_LCDML_DISP_cols - 1), n); + lcd.print(F(" ")); + } + } + } + + // display scrollbar + if (_LCDML_DISP_cfg_scrollbar == 1) { + if (scrollbar_max > n_max) { + //set scroll position + if (scrollbar_cur_pos == scrollbar_min) { + // min pos +#ifdef I2C_DISPLAY + lcd.setCursor((_LCDML_DISP_cols - 1), 0); + lcd.write((uint8_t)1); +#else + lcd.drawTile((_LCDML_DISP_cols - 1), 0, 1, flipped_scroll_bar[1]); + lcd.setCursor((_LCDML_DISP_cols), 1); +#endif + } else if (scrollbar_cur_pos == (scrollbar_max - 1)) { + // max pos +#ifdef I2C_DISPLAY + lcd.setCursor((_LCDML_DISP_cols - 1), (n_max - 1)); + lcd.write((uint8_t)4); +#else + lcd.drawTile((_LCDML_DISP_cols - 1), (n_max - 1), 1, flipped_scroll_bar[4]); + lcd.setCursor((_LCDML_DISP_cols), (n_max)); +#endif + } else { + // between +#ifdef I2C_DISPLAY + lcd.setCursor((_LCDML_DISP_cols - 1), scroll_pos / n_max); + lcd.write((uint8_t)(scroll_pos % n_max) + 1); +#else + lcd.drawTile((_LCDML_DISP_cols - 1), scroll_pos / n_max, 1, flipped_scroll_bar[(scroll_pos % n_max) + 1]); + lcd.setCursor((_LCDML_DISP_cols), (scroll_pos / n_max) + 1); +#endif + } + } + } + } +} + +//#################################################################################################################################################################################################### + +/*********************************************************************** + MENU + ***********************************************************************/ + +#ifdef USE_FX +void UI_func_reverb_roomsize(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Room", configuration.fx.reverb_roomsize, 1.0, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_roomsize = constrain(configuration.fx.reverb_roomsize + ENCODER[ENC_R].speed(), REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_roomsize = constrain(configuration.fx.reverb_roomsize - ENCODER[ENC_R].speed(), REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); + } + lcd_display_bar_int("Reverb Room", configuration.fx.reverb_roomsize, 1.0, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 3, false, false, false); + +#ifdef USE_PLATEREVERB + reverb.size(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); +#else + freeverb.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_roomsize), configuration.fx.reverb_roomsize); + } +} + +#if USE_PLATEREVERB != 1 +void UI_func_reverb_damping(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Damp.", configuration.fx.reverb_damping, 1.0, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_damping = constrain(configuration.fx.reverb_damping + ENCODER[ENC_R].speed(), REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_damping = constrain(configuration.fx.reverb_damping - ENCODER[ENC_R].speed(), REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); + } + + lcd_display_bar_int("Reverb Damp.", configuration.fx.reverb_damping, 1.0, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 3, false, false, false); + + freeverb.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_damping), configuration.fx.reverb_damping); + } +} +#else +void UI_func_reverb_lowpass(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Lowpass", configuration.fx.reverb_lowpass, 1.0, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_lowpass = constrain(configuration.fx.reverb_lowpass + ENCODER[ENC_R].speed(), REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_lowpass = constrain(configuration.fx.reverb_lowpass - ENCODER[ENC_R].speed(), REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX); + } + + lcd_display_bar_int("Reverb Lowpass", configuration.fx.reverb_lowpass, 1.0, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX, 3, false, false, false); + + reverb.lowpass(mapfloat(configuration.fx.reverb_lowpass, REVERB_LOWPASS_MIN, REVERB_LOWPASS_MAX, 0.0, 1.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_lowpass), configuration.fx.reverb_lowpass); + } +} + +void UI_func_reverb_lodamp(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Lodamp.", configuration.fx.reverb_lodamp, 1.0, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_lodamp = constrain(configuration.fx.reverb_lodamp + ENCODER[ENC_R].speed(), REVERB_LODAMP_MIN, REVERB_LODAMP_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_lodamp = constrain(configuration.fx.reverb_lodamp - ENCODER[ENC_R].speed(), REVERB_LODAMP_MIN, REVERB_LODAMP_MAX); + } + + lcd_display_bar_int("Reverb Lodamp.", configuration.fx.reverb_lodamp, 1.0, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX, 3, false, false, false); + + reverb.lodamp(mapfloat(configuration.fx.reverb_lodamp, REVERB_LODAMP_MIN, REVERB_LODAMP_MAX, 0.0, 1.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_lodamp), configuration.fx.reverb_lodamp); + } +} + +void UI_func_reverb_hidamp(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Hidamp.", configuration.fx.reverb_hidamp, 1.0, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_hidamp = constrain(configuration.fx.reverb_hidamp + ENCODER[ENC_R].speed(), REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_hidamp = constrain(configuration.fx.reverb_hidamp - ENCODER[ENC_R].speed(), REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX); + } + + lcd_display_bar_int("Reverb Hidamp.", configuration.fx.reverb_hidamp, 1.0, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX, 3, false, false, false); + + reverb.hidamp(mapfloat(configuration.fx.reverb_hidamp, REVERB_HIDAMP_MIN, REVERB_HIDAMP_MAX, 0.0, 1.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_hidamp), configuration.fx.reverb_hidamp); + } +} + +void UI_func_reverb_diffusion(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Diff.", configuration.fx.reverb_diffusion, 1.0, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_diffusion = constrain(configuration.fx.reverb_diffusion + ENCODER[ENC_R].speed(), REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_diffusion = constrain(configuration.fx.reverb_diffusion - ENCODER[ENC_R].speed(), REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX); + } + + lcd_display_bar_int("Reverb Diff.", configuration.fx.reverb_diffusion, 1.0, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX, 3, false, false, false); + + reverb.diffusion(mapfloat(configuration.fx.reverb_diffusion, REVERB_DIFFUSION_MIN, REVERB_DIFFUSION_MAX, 0.0, 1.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_diffusion), configuration.fx.reverb_diffusion); + } +} +#endif // PLATEREVERB != 1 + +void UI_func_reverb_level(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Level", configuration.fx.reverb_level, 1.0, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 3, false, false, true); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.fx.reverb_level = constrain(configuration.fx.reverb_level + ENCODER[ENC_R].speed(), REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.reverb_level = constrain(configuration.fx.reverb_level - ENCODER[ENC_R].speed(), REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); + } + + lcd_display_bar_int("Reverb Level", configuration.fx.reverb_level, 1.0, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 3, false, false, true); + + //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, volume_transform(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, VOL_MAX_FLOAT))); + master_mixer_l.gain(3, volume_transform(mapfloat(configuration.fx.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, VOL_MAX_FLOAT))); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_level), configuration.fx.reverb_level); + } +} + +void UI_func_chorus_frequency(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_float("Chorus Frq.", configuration.fx.chorus_frequency[selected_instance_id], 0.1, CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX, 2, 1, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.fx.chorus_frequency[selected_instance_id] = constrain(configuration.fx.chorus_frequency[selected_instance_id] + ENCODER[ENC_R].speed(), CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.chorus_frequency[selected_instance_id] = constrain(configuration.fx.chorus_frequency[selected_instance_id] - ENCODER[ENC_R].speed(), CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + lcd_display_bar_float("Chorus Frq.", configuration.fx.chorus_frequency[selected_instance_id], 0.1, CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX, 2, 1, false, false, false); + + chorus_modulator[selected_instance_id]->frequency(configuration.fx.chorus_frequency[selected_instance_id] / 10.0); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_frequency[0]), configuration.fx.chorus_frequency[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_frequency[1]), configuration.fx.chorus_frequency[1]); +#endif + } +} + +void UI_func_chorus_waveform(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Chorus Wavefrm")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) + configuration.fx.chorus_waveform[selected_instance_id] = constrain(configuration.fx.chorus_waveform[selected_instance_id] + 1, CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); + else if (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) + configuration.fx.chorus_waveform[selected_instance_id] = constrain(configuration.fx.chorus_waveform[selected_instance_id] - 1, CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + + lcd.setCursor(0, 1); + switch (configuration.fx.chorus_waveform[selected_instance_id]) + { + case 0: + chorus_modulator[selected_instance_id]->begin(WAVEFORM_TRIANGLE); + lcd.print(F("[TRIANGLE]")); + break; + case 1: + chorus_modulator[selected_instance_id]->begin(WAVEFORM_SINE); + lcd.print(F("[SINE ]")); + break; + default: + chorus_modulator[selected_instance_id]->begin(WAVEFORM_TRIANGLE); + lcd.print(F("[TRIANGLE]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_waveform[0]), configuration.fx.chorus_waveform[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_waveform[1]), configuration.fx.chorus_waveform[1]); +#endif + } +} + +void UI_func_chorus_depth(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Chorus Dpt.", configuration.fx.chorus_depth[selected_instance_id], 1.0, CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.fx.chorus_depth[selected_instance_id] = constrain(configuration.fx.chorus_depth[selected_instance_id] + ENCODER[ENC_R].speed(), CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); + else if (LCDML.BT_checkUp()) + configuration.fx.chorus_depth[selected_instance_id] = constrain(configuration.fx.chorus_depth[selected_instance_id] - ENCODER[ENC_R].speed(), CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Chorus Dpt.", configuration.fx.chorus_depth[selected_instance_id], 1.0, CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX, 3, false, false, false); + + chorus_modulator[selected_instance_id]->amplitude(configuration.fx.chorus_depth[selected_instance_id] / 100.0); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_depth[0]), configuration.fx.chorus_depth[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_depth[1]), configuration.fx.chorus_depth[1]); +#endif + } +} + +void UI_func_chorus_level(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Chorus Lvl.", configuration.fx.chorus_level[selected_instance_id], 1.0, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.chorus_level[selected_instance_id] = constrain(configuration.fx.chorus_level[selected_instance_id] + ENCODER[ENC_R].speed(), CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 93, configuration.fx.chorus_level[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.chorus_level[selected_instance_id] = constrain(configuration.fx.chorus_level[selected_instance_id] - ENCODER[ENC_R].speed(), CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 93, configuration.fx.chorus_level[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Chorus Lvl.", configuration.fx.chorus_level[selected_instance_id], 1.0, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 3, false, false, false); + + //chorus_mixer[selected_instance_id]->gain(0, pseudo_log_curve(1.0 - mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5))); + //chorus_mixer[selected_instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5))); + //chorus_mixer[selected_instance_id]->gain(0, 1.0 - mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); + 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_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_level[0]), configuration.fx.chorus_level[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_level[1]), configuration.fx.chorus_level[1]); +#endif + } +} + +void UI_func_delay_time(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + if (configuration.fx.delay_sync[selected_instance_id] > 0) + { + lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]); //goto MIDI Sync + } + else + { +#if DELAY_TIME_MAX >= 100 + lcd_display_bar_int("Delay Time", configuration.fx.delay_time[selected_instance_id], 10.0, DELAY_TIME_MIN, DELAY_TIME_MAX, 4, false, false, true); +#else + lcd_display_bar_int("Delay Time", configuration.fx.delay_time[selected_instance_id], 10.0, DELAY_TIME_MIN, DELAY_TIME_MAX, 3, false, false, true); +#endif + } + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (configuration.fx.delay_time[selected_instance_id] == DELAY_TIME_MIN && configuration.fx.delay_sync[selected_instance_id] > DELAY_SYNC_MIN) + { + // MIDI-sync delay + configuration.fx.delay_sync[selected_instance_id] = constrain(configuration.fx.delay_sync[selected_instance_id] - 1, DELAY_SYNC_MIN, DELAY_SYNC_MAX); + } + else + { + configuration.fx.delay_time[selected_instance_id] = constrain(configuration.fx.delay_time[selected_instance_id] + ENCODER[ENC_R].speed(), DELAY_TIME_MIN, DELAY_TIME_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 105, configuration.fx.delay_time[selected_instance_id]); + } + } + else if (LCDML.BT_checkUp()) + { + if (configuration.fx.delay_time[selected_instance_id] == DELAY_TIME_MIN && configuration.fx.delay_sync[selected_instance_id] > DELAY_SYNC_MIN) + { + // MIDI-sync delay + configuration.fx.delay_sync[selected_instance_id] = constrain(configuration.fx.delay_sync[selected_instance_id] + 1, DELAY_SYNC_MIN, DELAY_SYNC_MAX); + } + else + { + if (configuration.fx.delay_time[selected_instance_id] == DELAY_TIME_MIN) + configuration.fx.delay_sync[selected_instance_id] = DELAY_SYNC_MIN + 1; + else + { + configuration.fx.delay_time[selected_instance_id] = constrain(configuration.fx.delay_time[selected_instance_id] - ENCODER[ENC_R].speed(), DELAY_TIME_MIN, DELAY_TIME_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 105, configuration.fx.delay_time[selected_instance_id]); + } + } + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + if (configuration.fx.delay_sync[selected_instance_id] > 0) + { + lcd_display_delay_sync(configuration.fx.delay_sync[selected_instance_id]);//MIDI Sync Delay + } + else + { +#if DELAY_TIME_MAX >= 100 + lcd_display_bar_int("Delay Time", configuration.fx.delay_time[selected_instance_id], 10.0, DELAY_TIME_MIN, DELAY_TIME_MAX, 4, false, false, true); +#else + lcd_display_bar_int("Delay Time", configuration.fx.delay_time[selected_instance_id], 10.0, DELAY_TIME_MIN, DELAY_TIME_MAX, 3, false, false, true); +#endif + if (configuration.fx.delay_time[selected_instance_id] <= DELAY_TIME_MIN) + delay_fx[selected_instance_id]->disable(0); + else + delay_fx[selected_instance_id]->delay(0, constrain(configuration.fx.delay_time[selected_instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX) * 10); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_time[0]), configuration.fx.delay_time[0]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_sync[0]), configuration.fx.delay_sync[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_time[1]), configuration.fx.delay_time[1]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_sync[1]), configuration.fx.delay_sync[1]); +#endif + } +} + +void UI_func_delay_feedback(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Delay Feedb.", configuration.fx.delay_feedback[selected_instance_id], 1.0, DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.delay_feedback[selected_instance_id] = constrain(configuration.fx.delay_feedback[selected_instance_id] + ENCODER[ENC_R].speed(), DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 106, configuration.fx.delay_feedback[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.delay_feedback[selected_instance_id] = constrain(configuration.fx.delay_feedback[selected_instance_id] - ENCODER[ENC_R].speed(), DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 106, configuration.fx.delay_feedback[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Delay Feedb.", configuration.fx.delay_feedback[selected_instance_id], 1.0, DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 3, false, false, false); + + delay_fb_mixer[selected_instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_feedback[selected_instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0, 127))); // amount of feedback + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_feedback[0]), configuration.fx.delay_feedback[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_feedback[1]), configuration.fx.delay_feedback[1]); +#endif + } +} + +void UI_func_delay_level(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Delay Lvl.", configuration.fx.delay_level[selected_instance_id], 1.0, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.delay_level[selected_instance_id] = constrain(configuration.fx.delay_level[selected_instance_id] + ENCODER[ENC_R].speed(), DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 107, configuration.fx.delay_level[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.delay_level[selected_instance_id] = constrain(configuration.fx.delay_level[selected_instance_id] - ENCODER[ENC_R].speed(), DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 107, configuration.fx.delay_level[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Delay Lvl.", configuration.fx.delay_level[selected_instance_id], 1.0, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 3, false, false, false); + + delay_mixer[selected_instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_level[selected_instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0, 127))); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_level[0]), configuration.fx.delay_level[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.delay_level[1]), configuration.fx.delay_level[1]); +#endif + } +} + +void UI_func_reverb_send(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Reverb Send", configuration.fx.reverb_send[selected_instance_id], 1.0, REVERB_SEND_MIN, REVERB_SEND_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.reverb_send[selected_instance_id] = constrain(configuration.fx.reverb_send[selected_instance_id] + ENCODER[ENC_R].speed(), REVERB_SEND_MIN, REVERB_SEND_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 91, configuration.fx.reverb_send[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.reverb_send[selected_instance_id] = constrain(configuration.fx.reverb_send[selected_instance_id] - ENCODER[ENC_R].speed(), REVERB_SEND_MIN, REVERB_SEND_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 91, configuration.fx.reverb_send[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Reverb Send", configuration.fx.reverb_send[selected_instance_id], 1.0, REVERB_SEND_MIN, REVERB_SEND_MAX, 3, false, false, false); + + reverb_mixer_r.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT))); + reverb_mixer_l.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT))); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_send[0]), configuration.fx.reverb_send[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.reverb_send[1]), configuration.fx.reverb_send[1]); +#endif + } +} + +void UI_func_filter_cutoff(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Filter Cutoff", configuration.fx.filter_cutoff[selected_instance_id], 1.0, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.filter_cutoff[selected_instance_id] = constrain(configuration.fx.filter_cutoff[selected_instance_id] + ENCODER[ENC_R].speed(), FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 104, configuration.fx.filter_cutoff[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.filter_cutoff[selected_instance_id] = constrain(configuration.fx.filter_cutoff[selected_instance_id] - ENCODER[ENC_R].speed(), FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 104, configuration.fx.filter_cutoff[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Filter Cutoff", configuration.fx.filter_cutoff[selected_instance_id], 1.0, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 3, false, false, false); + + MicroDexed[selected_instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[selected_instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.filter_cutoff[0]), configuration.fx.filter_cutoff[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.filter_cutoff[1]), configuration.fx.filter_cutoff[1]); +#endif + } +} + +void UI_func_filter_resonance(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Filter Reso.", configuration.fx.filter_resonance[selected_instance_id], 1.0, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.filter_resonance[selected_instance_id] = constrain(configuration.fx.filter_resonance[selected_instance_id] + ENCODER[ENC_R].speed(), FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 103, configuration.fx.filter_resonance[selected_instance_id]); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.filter_resonance[selected_instance_id] = constrain(configuration.fx.filter_resonance[selected_instance_id] - ENCODER[ENC_R].speed(), FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 103, configuration.fx.filter_resonance[selected_instance_id]); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Filter Reso.", configuration.fx.filter_resonance[selected_instance_id], 1.0, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 3, false, false, false); + + MicroDexed[selected_instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[selected_instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0)); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.filter_resonance[0]), configuration.fx.filter_resonance[0]); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.filter_resonance[1]), configuration.fx.filter_resonance[1]); +#endif + } +} +#endif + +void UI_func_transpose(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(METERBAR); + lcd_display_meter_int("Transpose", configuration.dexed[selected_instance_id].transpose, 1.0, -24.0, TRANSPOSE_MIN, TRANSPOSE_MAX, 2, false, true, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].transpose = constrain(configuration.dexed[selected_instance_id].transpose + ENCODER[ENC_R].speed(), TRANSPOSE_MIN, TRANSPOSE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].transpose = constrain(configuration.dexed[selected_instance_id].transpose - ENCODER[ENC_R].speed(), TRANSPOSE_MIN, TRANSPOSE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_meter_int("Transpose", configuration.dexed[selected_instance_id].transpose, 1.0, -24.0, TRANSPOSE_MIN, TRANSPOSE_MAX, 2, false, true, true); + + MicroDexed[selected_instance_id]->setTranspose(configuration.dexed[selected_instance_id].transpose); + MicroDexed[selected_instance_id]->notesOff(); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 144, configuration.dexed[selected_instance_id].transpose, 0); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].transpose), configuration.dexed[0].transpose); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].transpose), configuration.dexed[1].transpose); +#endif + } +} + +void UI_func_tune(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(METERBAR); + lcd_display_meter_int("Fine Tune", configuration.dexed[selected_instance_id].tune, 1.0, -100.0, TUNE_MIN, TUNE_MAX, 3, false, true, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.dexed[selected_instance_id].tune = constrain(configuration.dexed[selected_instance_id].tune + ENCODER[ENC_R].speed(), TUNE_MIN, TUNE_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 94, configuration.dexed[selected_instance_id].tune); + } + else if (LCDML.BT_checkUp()) + { + configuration.dexed[selected_instance_id].tune = constrain(configuration.dexed[selected_instance_id].tune - ENCODER[ENC_R].speed(), TUNE_MIN, TUNE_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 94, configuration.dexed[selected_instance_id].tune); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_meter_int("Fine Tune", configuration.dexed[selected_instance_id].tune, 1.0, -100.0, TUNE_MIN, TUNE_MAX, 3, false, true, false); + + 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_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].tune), configuration.dexed[0].tune); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].tune), configuration.dexed[1].tune); +#endif + } +} + +void UI_func_midi_channel(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("MIDI Channel")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) + configuration.dexed[selected_instance_id].midi_channel = constrain(configuration.dexed[selected_instance_id].midi_channel + ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); + else if (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) + configuration.dexed[selected_instance_id].midi_channel = constrain(configuration.dexed[selected_instance_id].midi_channel - ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + + lcd.setCursor(0, 1); + if (configuration.dexed[selected_instance_id].midi_channel == 0) + { + lcd.print(F("[OMNI]")); + } + else + { + lcd_display_int(configuration.dexed[selected_instance_id].midi_channel, 4, false, true, false); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].midi_channel), configuration.dexed[0].midi_channel); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].midi_channel), configuration.dexed[1].midi_channel); +#endif + } +} + +void getNoteName(char* noteName, uint8_t noteNumber) +{ + char notes [12][3] = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"}; + uint8_t oct_index = noteNumber - 12; + + noteNumber -= 21; + sprintf(noteName, "%2s%1d", notes[noteNumber % 12], oct_index / 12); +} + +void UI_func_lowest_note(uint8_t param) +{ + char note_name[4]; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + getNoteName(note_name, configuration.dexed[selected_instance_id].lowest_note); + lcd.setCursor(0, 0); + lcd.print(F("Lowest Note")); + lcd.setCursor(0, 1); + lcd.print(F("[")); + lcd.print(note_name); + lcd.print(F("]")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].lowest_note = constrain(configuration.dexed[selected_instance_id].lowest_note + ENCODER[ENC_R].speed(), INSTANCE_LOWEST_NOTE_MIN, INSTANCE_LOWEST_NOTE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].lowest_note = constrain(configuration.dexed[selected_instance_id].lowest_note - ENCODER[ENC_R].speed(), INSTANCE_LOWEST_NOTE_MIN, INSTANCE_LOWEST_NOTE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + getNoteName(note_name, configuration.dexed[selected_instance_id].lowest_note); + lcd.setCursor(1, 1); + lcd.print(note_name); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].lowest_note), configuration.dexed[0].lowest_note); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].lowest_note), configuration.dexed[1].lowest_note); +#endif + } +} + +void UI_func_highest_note(uint8_t param) +{ + char note_name[4]; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + getNoteName(note_name, configuration.dexed[selected_instance_id].highest_note); + lcd.setCursor(0, 0); + lcd.print(F("Highest Note")); + lcd.setCursor(0, 1); + lcd.print(F("[")); + lcd.print(note_name); + lcd.print(F("]")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].highest_note = constrain(configuration.dexed[selected_instance_id].highest_note + ENCODER[ENC_R].speed(), INSTANCE_HIGHEST_NOTE_MIN, INSTANCE_HIGHEST_NOTE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].highest_note = constrain(configuration.dexed[selected_instance_id].highest_note - ENCODER[ENC_R].speed(), INSTANCE_HIGHEST_NOTE_MIN, INSTANCE_HIGHEST_NOTE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + getNoteName(note_name, configuration.dexed[selected_instance_id].highest_note); + lcd.setCursor(1, 1); + lcd.print(note_name); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].highest_note), configuration.dexed[0].highest_note); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].highest_note), configuration.dexed[1].highest_note); +#endif + } +} + +void UI_func_sound_intensity(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Voice Level", configuration.dexed[selected_instance_id].sound_intensity, 1.0, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + encoderDir[ENC_R].reset(); + + if (LCDML.BT_checkDown()) + { + configuration.dexed[selected_instance_id].sound_intensity = constrain(configuration.dexed[selected_instance_id].sound_intensity + ENCODER[ENC_R].speed(), SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 7, configuration.dexed[selected_instance_id].sound_intensity); + } + else if (LCDML.BT_checkUp()) + { + configuration.dexed[selected_instance_id].sound_intensity = constrain(configuration.dexed[selected_instance_id].sound_intensity - ENCODER[ENC_R].speed(), SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 7, configuration.dexed[selected_instance_id].sound_intensity); + } + +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Voice Level", configuration.dexed[selected_instance_id].sound_intensity, 1.0, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 3, false, false, false); + MicroDexed[selected_instance_id]->setGain(midi_volume_transform(map(configuration.dexed[selected_instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0, 127))); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].sound_intensity), configuration.dexed[0].sound_intensity); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].sound_intensity), configuration.dexed[1].sound_intensity); +#endif + } +} + +void UI_func_panorama(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + if (configuration.sys.mono > 0) + { + lcd.setCursor(0, 0); + lcd.print(F("Panorama")); + lcd.setCursor(0, 1); + lcd.print(F("MONO-disabled")); + return; + } + lcd_special_chars(METERBAR); + lcd_display_meter_float("Panorama", configuration.dexed[selected_instance_id].pan, 0.05, -20.0, PANORAMA_MIN, PANORAMA_MAX, 1, 1, false, true, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown() && encoderDir[ENC_R].Down() && configuration.sys.mono == 0) + { + configuration.dexed[selected_instance_id].pan = constrain(configuration.dexed[selected_instance_id].pan + ENCODER[ENC_R].speed(), PANORAMA_MIN, PANORAMA_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 10, map(configuration.dexed[selected_instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, 0, 127)); + } + else if (LCDML.BT_checkUp() && encoderDir[ENC_R].Up() && configuration.sys.mono == 0) + { + configuration.dexed[selected_instance_id].pan = constrain(configuration.dexed[selected_instance_id].pan - ENCODER[ENC_R].speed(), PANORAMA_MIN, PANORAMA_MAX); + MD_sendControlChange(configuration.dexed[selected_instance_id].midi_channel, 10, map(configuration.dexed[selected_instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, 0, 127)); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + + if (configuration.sys.mono == 0) + { + lcd_display_meter_float("Panorama", configuration.dexed[selected_instance_id].pan, 0.05, -20.0, PANORAMA_MIN, PANORAMA_MAX, 1, 1, false, true, false); + mono2stereo[selected_instance_id]->panorama(mapfloat(configuration.dexed[selected_instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].pan), configuration.dexed[0].pan); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].pan), configuration.dexed[1].pan); +#endif + } +} + +void UI_func_favorites(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_L].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Favorites")); + lcd.setCursor(0, 1); + switch (configuration.sys.favorites) + { + case 0: + lcd.print(F("[ All presets ]")); + break; + case 1: + lcd.print(F("[ FAVs. only ]")); + break; + case 2: + lcd.print(F("[non-FAVs. only]")); + break; + case 3: + lcd.print(F("[random non-FAV]")); + break; + } + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown()) + configuration.sys.favorites = constrain(configuration.sys.favorites + 1, 0, 3); + else if (LCDML.BT_checkUp()) + configuration.sys.favorites = constrain(configuration.sys.favorites - 1, 0, 3); + + lcd.setCursor(0, 1); + switch (configuration.sys.favorites) + { + case 0: + lcd.print(F("[ All presets ]")); + break; + case 1: + lcd.print(F("[ FAVs. only ]")); + break; + case 2: + lcd.print(F("[non-FAVs. only]")); + break; + case 3: + lcd.print(F("[random non-FAV]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_L].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys.favorites), configuration.sys.favorites); + } +} + + +void UI_func_stereo_mono(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Stereo/Mono")); + lcd.setCursor(0, 1); + switch (configuration.sys.mono) + { + case 0: + lcd.print(F("[STEREO]")); + stereo2mono.stereo(true); + break; + case 1: + lcd.print(F("[MONO ]")); + stereo2mono.stereo(false); + break; + case 2: + lcd.print(F("[MONO-R]")); + stereo2mono.stereo(false); + break; + case 3: + lcd.print(F("[MONO-L]")); + stereo2mono.stereo(false); + break; + } + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown()) + configuration.sys.mono = constrain(configuration.sys.mono + 1, MONO_MIN, MONO_MAX); + else if (LCDML.BT_checkUp()) + configuration.sys.mono = constrain(configuration.sys.mono - 1, MONO_MIN, MONO_MAX); + + lcd.setCursor(0, 1); + switch (configuration.sys.mono) + { + case 0: + lcd.print(F("[STEREO]")); + stereo2mono.stereo(true); + break; + case 1: + lcd.print(F("[MONO ]")); + stereo2mono.stereo(false); + break; + case 2: + lcd.print(F("[MONO-R]")); + stereo2mono.stereo(false); + break; + case 3: + lcd.print(F("[MONO-L]")); + stereo2mono.stereo(false); + break; + } + set_volume(configuration.sys.vol, configuration.sys.mono); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys.mono), configuration.sys.mono); + } +} + +void UI_func_polyphony(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); +#if NUM_DEXED>1 + lcd_display_bar_int("Polyphony", configuration.dexed[selected_instance_id].polyphony, 1.0, POLYPHONY_MIN, POLYPHONY_MAX - configuration.dexed[(selected_instance_id + 1) % NUM_DEXED].polyphony, 2, false, false, true); +#else + lcd_display_bar_int("Polyphony", configuration.dexed[selected_instance_id].polyphony, 1.0, POLYPHONY_MIN, POLYPHONY_MAX, 2, false, false, true); +#endif + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { +#if NUM_DEXED>1 + if (configuration.dexed[selected_instance_id].polyphony < POLYPHONY_MAX - configuration.dexed[(selected_instance_id + 1) % NUM_DEXED].polyphony) + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony + 1, POLYPHONY_MIN, POLYPHONY_MAX - configuration.dexed[(selected_instance_id + 1) % NUM_DEXED].polyphony); +#else + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony + 1, POLYPHONY_MIN, POLYPHONY_MAX); +#endif + } + else if (LCDML.BT_checkUp()) + { + if (configuration.dexed[selected_instance_id].polyphony - 1 < 0) + configuration.dexed[selected_instance_id].polyphony = 0; + else + { +#if NUM_DEXED>1 + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony - 1, POLYPHONY_MIN, POLYPHONY_MAX - configuration.dexed[(selected_instance_id + 1) % NUM_DEXED].polyphony); +#else + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony - 1, POLYPHONY_MIN, POLYPHONY_MAX); +#endif + } + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + lcd_active_instance_number(selected_instance_id); +#endif + } + +#if NUM_DEXED>1 + lcd_display_bar_int("Polyphony", configuration.dexed[selected_instance_id].polyphony, 1.0, POLYPHONY_MIN, POLYPHONY_MAX - configuration.dexed[(selected_instance_id + 1) % NUM_DEXED].polyphony, 2, false, false, false); +#else + lcd_display_bar_int("Polyphony", configuration.dexed[selected_instance_id].polyphony, 1.0, POLYPHONY_MIN, POLYPHONY_MAX, 2, false, false, false); +#endif + MicroDexed[selected_instance_id]->setMaxNotes(configuration.dexed[selected_instance_id].polyphony); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].polyphony), configuration.dexed[0].polyphony); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].polyphony), configuration.dexed[1].polyphony); +#endif + } +} + +void UI_func_mono_poly(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Mono/Poly")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].monopoly = constrain(configuration.dexed[selected_instance_id].monopoly + 1, MONOPOLY_MIN, MONOPOLY_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].monopoly = constrain(configuration.dexed[selected_instance_id].monopoly - 1, MONOPOLY_MIN, MONOPOLY_MAX); + + MicroDexed[selected_instance_id]->setMonoMode(!configuration.dexed[selected_instance_id].monopoly); + configuration.dexed[selected_instance_id].monopoly = MicroDexed[selected_instance_id]->getMonoMode(); + } +#if NUM_DEXED > 1 + if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + lcd_active_instance_number(selected_instance_id); +#endif + } + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].monopoly) + { + case 1: + lcd.print(F("[MONOPHONIC]")); + break; + case 0: + lcd.print(F("[POLYPHONIC]")); + break; + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].monopoly), configuration.dexed[0].monopoly); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].monopoly), configuration.dexed[1].monopoly); +#endif + } +} + +void UI_func_note_refresh(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Note Refresh")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].note_refresh = constrain(configuration.dexed[selected_instance_id].note_refresh + 1, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].note_refresh = constrain(configuration.dexed[selected_instance_id].note_refresh - 1, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setRefreshMode(configuration.dexed[selected_instance_id].note_refresh); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].note_refresh) + { + case 0: + lcd.print(F("[NORMAL ]")); + break; + case 1: + lcd.print(F("[RETRIGGERED]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].note_refresh), configuration.dexed[0].note_refresh); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].note_refresh), configuration.dexed[1].note_refresh); +#endif + } +} + +void UI_func_pb_range(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("PB Range", configuration.dexed[selected_instance_id].pb_range, 1.0, PB_RANGE_MIN, PB_RANGE_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].pb_range = constrain(configuration.dexed[selected_instance_id].pb_range + ENCODER[ENC_R].speed(), PB_RANGE_MIN, PB_RANGE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].pb_range = constrain(configuration.dexed[selected_instance_id].pb_range - ENCODER[ENC_R].speed(), PB_RANGE_MIN, PB_RANGE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("PB Range", configuration.dexed[selected_instance_id].pb_range, 1.0, PB_RANGE_MIN, PB_RANGE_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setPBController(configuration.dexed[selected_instance_id].pb_range, configuration.dexed[selected_instance_id].pb_step); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 65, configuration.dexed[selected_instance_id].pb_range, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].pb_range), configuration.dexed[0].pb_range); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].pb_range), configuration.dexed[1].pb_range); +#endif + } +} + +void UI_func_pb_step(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("PB Step", configuration.dexed[selected_instance_id].pb_step, 1.0, PB_STEP_MIN, PB_STEP_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].pb_step = constrain(configuration.dexed[selected_instance_id].pb_step + ENCODER[ENC_R].speed(), PB_STEP_MIN, PB_STEP_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].pb_step = constrain(configuration.dexed[selected_instance_id].pb_step - ENCODER[ENC_R].speed(), PB_STEP_MIN, PB_STEP_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("PB Step", configuration.dexed[selected_instance_id].pb_step, 1.0, PB_STEP_MIN, PB_STEP_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setPBController(configuration.dexed[selected_instance_id].pb_range, configuration.dexed[selected_instance_id].pb_step); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 66, configuration.dexed[selected_instance_id].pb_step, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].pb_step), configuration.dexed[0].pb_step); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].pb_step), configuration.dexed[1].pb_step); +#endif + } +} + +void UI_func_mw_range(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("MW Range", configuration.dexed[selected_instance_id].mw_range, 1.0, MW_RANGE_MIN, MW_RANGE_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].mw_range = constrain(configuration.dexed[selected_instance_id].mw_range + ENCODER[ENC_R].speed(), MW_RANGE_MIN, MW_RANGE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].mw_range = constrain(configuration.dexed[selected_instance_id].mw_range - ENCODER[ENC_R].speed(), MW_RANGE_MIN, MW_RANGE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("MW Range", configuration.dexed[selected_instance_id].mw_range, 1.0, MW_RANGE_MIN, MW_RANGE_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setMWController(configuration.dexed[selected_instance_id].mw_range, configuration.dexed[selected_instance_id].mw_assign, configuration.dexed[selected_instance_id].mw_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 70, configuration.dexed[selected_instance_id].mw_range, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].mw_range), configuration.dexed[0].mw_range); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].mw_range), configuration.dexed[1].mw_range); +#endif + } +} + +void UI_func_mw_assign(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("MW Assign")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].mw_assign = constrain(configuration.dexed[selected_instance_id].mw_assign + 1, MW_ASSIGN_MIN, MW_ASSIGN_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].mw_assign = constrain(configuration.dexed[selected_instance_id].mw_assign - 1, MW_ASSIGN_MIN, MW_ASSIGN_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setMWController(configuration.dexed[selected_instance_id].mw_range, configuration.dexed[selected_instance_id].mw_assign, configuration.dexed[selected_instance_id].mw_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 71, configuration.dexed[selected_instance_id].mw_assign, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].mw_assign) + { + case 0: + lcd.print(F("[ NONE ]")); + break; + case 1: + lcd.print(F("[PTCH ]")); + break; + case 2: + lcd.print(F("[ AMP ]")); + break; + case 3: + lcd.print(F("[PTCH AMP ]")); + break; + case 4: + lcd.print(F("[ EG]")); + break; + case 5: + lcd.print(F("[PTCH EG]")); + break; + case 6: + lcd.print(F("[ AMP EG]")); + break; + case 7: + lcd.print(F("[PTCH AMP EG]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].mw_assign), configuration.dexed[0].mw_assign); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].mw_assign), configuration.dexed[1].mw_assign); +#endif + } +} + +void UI_func_mw_mode(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("MW Mode")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].mw_mode = constrain(configuration.dexed[selected_instance_id].mw_mode + 1, MW_MODE_MIN, MW_MODE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].mw_mode = constrain(configuration.dexed[selected_instance_id].mw_mode - 1, MW_MODE_MIN, MW_MODE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setMWController(configuration.dexed[selected_instance_id].mw_range, configuration.dexed[selected_instance_id].mw_assign, configuration.dexed[selected_instance_id].mw_mode); + MicroDexed[selected_instance_id]->ControllersRefresh(); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].mw_mode) + { + case 0: + lcd.print(F("[LINEAR ]")); + break; + case 1: + lcd.print(F("[REVERSE LIN.]")); + break; + case 2: + lcd.print(F("[DIRECT ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].mw_mode), configuration.dexed[0].mw_mode); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].mw_mode), configuration.dexed[1].mw_mode); +#endif + } +} + +void UI_func_fc_range(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("FC Range", configuration.dexed[selected_instance_id].fc_range, 1.0, FC_RANGE_MIN, FC_RANGE_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].fc_range = constrain(configuration.dexed[selected_instance_id].fc_range + ENCODER[ENC_R].speed(), FC_RANGE_MIN, FC_RANGE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].fc_range = constrain(configuration.dexed[selected_instance_id].fc_range - ENCODER[ENC_R].speed(), FC_RANGE_MIN, FC_RANGE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("FC Range", configuration.dexed[selected_instance_id].fc_range, 1.0, FC_RANGE_MIN, FC_RANGE_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setFCController(configuration.dexed[selected_instance_id].fc_range, configuration.dexed[selected_instance_id].fc_assign, configuration.dexed[selected_instance_id].fc_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 72, configuration.dexed[selected_instance_id].fc_range, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].fc_range), configuration.dexed[0].fc_range); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].fc_range), configuration.dexed[1].fc_range); +#endif + } +} + +void UI_func_fc_assign(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("FC Assign")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].fc_assign = constrain(configuration.dexed[selected_instance_id].fc_assign + 1, FC_ASSIGN_MIN, FC_ASSIGN_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].fc_assign = constrain(configuration.dexed[selected_instance_id].fc_assign - 1, FC_ASSIGN_MIN, FC_ASSIGN_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setFCController(configuration.dexed[selected_instance_id].fc_range, configuration.dexed[selected_instance_id].fc_assign, configuration.dexed[selected_instance_id].fc_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 73, configuration.dexed[selected_instance_id].fc_assign, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].fc_assign) + { + case 0: + lcd.print(F("[ NONE ]")); + break; + case 1: + lcd.print(F("[PTCH ]")); + break; + case 2: + lcd.print(F("[ AMP ]")); + break; + case 3: + lcd.print(F("[PTCH AMP ]")); + break; + case 4: + lcd.print(F("[ EG]")); + break; + case 5: + lcd.print(F("[PTCH EG]")); + break; + case 6: + lcd.print(F("[ AMP EG]")); + break; + case 7: + lcd.print(F("[PTCH AMP EG]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].fc_assign), configuration.dexed[0].fc_assign); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].fc_assign), configuration.dexed[1].fc_assign); +#endif + } +} + +void UI_func_fc_mode(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("FC Mode")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].fc_mode = constrain(configuration.dexed[selected_instance_id].fc_mode + 1, FC_MODE_MIN, FC_MODE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].fc_mode = constrain(configuration.dexed[selected_instance_id].fc_mode - 1, FC_MODE_MIN, FC_MODE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setFCController(configuration.dexed[selected_instance_id].fc_range, configuration.dexed[selected_instance_id].fc_assign, configuration.dexed[selected_instance_id].fc_mode); + MicroDexed[selected_instance_id]->ControllersRefresh(); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].fc_mode) + { + case 0: + lcd.print(F("[LINEAR ]")); + break; + case 1: + lcd.print(F("[REVERSE LIN.]")); + break; + case 2: + lcd.print(F("[DIRECT ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].fc_mode), configuration.dexed[0].fc_mode); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].fc_mode), configuration.dexed[1].fc_mode); +#endif + } +} + +void UI_func_bc_range(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("BC Range", configuration.dexed[selected_instance_id].bc_range, 1.0, BC_RANGE_MIN, BC_RANGE_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].bc_range = constrain(configuration.dexed[selected_instance_id].bc_range + ENCODER[ENC_R].speed(), BC_RANGE_MIN, BC_RANGE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].bc_range = constrain(configuration.dexed[selected_instance_id].bc_range - ENCODER[ENC_R].speed(), BC_RANGE_MIN, BC_RANGE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("BC Range", configuration.dexed[selected_instance_id].bc_range, 1.0, BC_RANGE_MIN, BC_RANGE_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setBCController(configuration.dexed[selected_instance_id].bc_range, configuration.dexed[selected_instance_id].bc_assign, configuration.dexed[selected_instance_id].bc_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 74, configuration.dexed[selected_instance_id].bc_range, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].bc_range), configuration.dexed[0].bc_range); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].bc_range), configuration.dexed[1].bc_range); +#endif + } +} + +void UI_func_bc_assign(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("BC Assign")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].bc_assign = constrain(configuration.dexed[selected_instance_id].bc_assign + 1, BC_ASSIGN_MIN, BC_ASSIGN_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].bc_assign = constrain(configuration.dexed[selected_instance_id].bc_assign - 1, BC_ASSIGN_MIN, BC_ASSIGN_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setBCController(configuration.dexed[selected_instance_id].bc_range, configuration.dexed[selected_instance_id].bc_assign, configuration.dexed[selected_instance_id].bc_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 75, configuration.dexed[selected_instance_id].bc_assign, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].bc_assign) + { + case 0: + lcd.print(F("[ NONE ]")); + break; + case 1: + lcd.print(F("[PTCH ]")); + break; + case 2: + lcd.print(F("[ AMP ]")); + break; + case 3: + lcd.print(F("[PTCH AMP ]")); + break; + case 4: + lcd.print(F("[ EG]")); + break; + case 5: + lcd.print(F("[PTCH EG]")); + break; + case 6: + lcd.print(F("[ AMP EG]")); + break; + case 7: + lcd.print(F("[PTCH AMP EG]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].bc_assign), configuration.dexed[0].bc_assign); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].bc_assign), configuration.dexed[1].bc_assign); +#endif + } +} + +void UI_func_bc_mode(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("BC Mode")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].bc_mode = constrain(configuration.dexed[selected_instance_id].bc_mode + 1, BC_MODE_MIN, BC_MODE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].bc_mode = constrain(configuration.dexed[selected_instance_id].bc_mode - 1, BC_MODE_MIN, BC_MODE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setBCController(configuration.dexed[selected_instance_id].bc_range, configuration.dexed[selected_instance_id].bc_assign, configuration.dexed[selected_instance_id].bc_mode); + MicroDexed[selected_instance_id]->ControllersRefresh(); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].bc_mode) + { + case 0: + lcd.print(F("[LINEAR ]")); + break; + case 1: + lcd.print(F("[REVERSE LIN.]")); + break; + case 2: + lcd.print(F("[DIRECT ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].bc_mode), configuration.dexed[0].bc_mode); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].bc_mode), configuration.dexed[1].bc_mode); +#endif + } +} + +void UI_func_at_range(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("AT Range", configuration.dexed[selected_instance_id].at_range, 1.0, AT_RANGE_MIN, AT_RANGE_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].at_range = constrain(configuration.dexed[selected_instance_id].at_range + ENCODER[ENC_R].speed(), AT_RANGE_MIN, AT_RANGE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].at_range = constrain(configuration.dexed[selected_instance_id].at_range - ENCODER[ENC_R].speed(), AT_RANGE_MIN, AT_RANGE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("AT Range", configuration.dexed[selected_instance_id].at_range, 1.0, AT_RANGE_MIN, AT_RANGE_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setATController(configuration.dexed[selected_instance_id].at_range, configuration.dexed[selected_instance_id].at_assign, configuration.dexed[selected_instance_id].at_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 76, configuration.dexed[selected_instance_id].at_range, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_range), configuration.dexed[0].at_range); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].at_range), configuration.dexed[1].at_range); +#endif + } +} + +void UI_func_at_assign(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("AT Assign")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].at_assign = constrain(configuration.dexed[selected_instance_id].at_assign + 1, AT_ASSIGN_MIN, AT_ASSIGN_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].at_assign = constrain(configuration.dexed[selected_instance_id].at_assign - 1, AT_ASSIGN_MIN, AT_ASSIGN_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setATController(configuration.dexed[selected_instance_id].at_range, configuration.dexed[selected_instance_id].at_assign, configuration.dexed[selected_instance_id].at_mode); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 77, configuration.dexed[selected_instance_id].at_assign, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].at_assign) + { + case 0: + lcd.print(F("[ NONE ]")); + break; + case 1: + lcd.print(F("[PTCH ]")); + break; + case 2: + lcd.print(F("[ AMP ]")); + break; + case 3: + lcd.print(F("[PTCH AMP ]")); + break; + case 4: + lcd.print(F("[ EG]")); + break; + case 5: + lcd.print(F("[PTCH EG]")); + break; + case 6: + lcd.print(F("[ AMP EG]")); + break; + case 7: + lcd.print(F("[PTCH AMP EG]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_assign), configuration.dexed[0].at_assign); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].at_assign), configuration.dexed[1].at_assign); +#endif + } +} + +void UI_func_at_mode(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("AT Mode")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].at_mode = constrain(configuration.dexed[selected_instance_id].at_mode + 1, AT_MODE_MIN, AT_MODE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].at_mode = constrain(configuration.dexed[selected_instance_id].at_mode - 1, AT_MODE_MIN, AT_MODE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setATController(configuration.dexed[selected_instance_id].at_range, configuration.dexed[selected_instance_id].at_assign, configuration.dexed[selected_instance_id].at_mode); + MicroDexed[selected_instance_id]->ControllersRefresh(); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].at_mode) + { + case 0: + lcd.print(F("[LINEAR ]")); + break; + case 1: + lcd.print(F("[REVERSE LIN.]")); + break; + case 2: + lcd.print(F("[DIRECT ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_mode), configuration.dexed[0].at_mode); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].at_mode), configuration.dexed[1].at_mode); +#endif + } +} + +void UI_func_portamento_mode(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Port. Mode")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].portamento_mode = constrain(configuration.dexed[selected_instance_id].portamento_mode + 1, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].portamento_mode = constrain(configuration.dexed[selected_instance_id].portamento_mode - 1, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setPortamentoMode(configuration.dexed[selected_instance_id].portamento_mode, configuration.dexed[selected_instance_id].portamento_glissando, configuration.dexed[selected_instance_id].portamento_time); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 67, configuration.dexed[selected_instance_id].portamento_mode, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].portamento_mode) + { + case 0: + if (configuration.dexed[selected_instance_id].monopoly == 1) + lcd.print(F("[RETAIN ]")); + else + lcd.print(F("[FINGERED]")); + break; + case 1: + if (configuration.dexed[selected_instance_id].monopoly == 1) + lcd.print(F("[FOLLOW ]")); + else + lcd.print(F("[FULL ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].portamento_mode), configuration.dexed[0].portamento_mode); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].portamento_mode), configuration.dexed[1].portamento_mode); +#endif + } +} + +void UI_func_portamento_glissando(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Port. Gliss.")); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].portamento_glissando = constrain(configuration.dexed[selected_instance_id].portamento_glissando + 1, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].portamento_glissando = constrain(configuration.dexed[selected_instance_id].portamento_glissando - 1, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + MicroDexed[selected_instance_id]->setPortamentoMode(configuration.dexed[selected_instance_id].portamento_mode, configuration.dexed[selected_instance_id].portamento_glissando, configuration.dexed[selected_instance_id].portamento_time); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 68, configuration.dexed[selected_instance_id].portamento_glissando, 2); + + lcd.setCursor(0, 1); + switch (configuration.dexed[selected_instance_id].portamento_glissando) + { + case 0: + lcd.print(F("[OFF]")); + break; + case 1: + lcd.print(F("[ON ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].portamento_glissando), configuration.dexed[0].portamento_glissando); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].portamento_glissando), configuration.dexed[1].portamento_glissando); +#endif + } +} + +void UI_func_portamento_time(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Port. Time", configuration.dexed[selected_instance_id].portamento_time, 1.0, PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX, 2, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].portamento_time = constrain(configuration.dexed[selected_instance_id].portamento_time + ENCODER[ENC_R].speed(), PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].portamento_time = constrain(configuration.dexed[selected_instance_id].portamento_time - ENCODER[ENC_R].speed(), PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + lcd_display_bar_int("Portam. Time", configuration.dexed[selected_instance_id].portamento_time, 1.0, PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX, 2, false, false, false); + + MicroDexed[selected_instance_id]->setPortamentoMode(configuration.dexed[selected_instance_id].portamento_mode, configuration.dexed[selected_instance_id].portamento_glissando, configuration.dexed[selected_instance_id].portamento_time); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 69, configuration.dexed[selected_instance_id].portamento_time, 2); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].portamento_time), configuration.dexed[0].portamento_time); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].portamento_time), configuration.dexed[1].portamento_time); +#endif + } +} + +void UI_handle_OP(uint8_t param) +{ + static uint8_t op_selected; + + lcd_OP_active_instance_number(selected_instance_id, configuration.dexed[selected_instance_id].op_enabled); + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("OP Enable")); + lcd.setCursor(0, 1); + for (uint8_t i = 2; i < 8; i++) + lcd.write(i); + + UI_update_instance_icons(); + + lcd.setCursor(op_selected, 1); + lcd.blink(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) + { +#if NUM_DEXED>1 + if (op_selected == 0) + { + selected_instance_id = !selected_instance_id; + op_selected = 5; + lcd_OP_active_instance_number(selected_instance_id, configuration.dexed[selected_instance_id].op_enabled); + } + else +#endif + op_selected = constrain(op_selected - 1, 0, 5); + } + else if (LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) + { +#if NUM_DEXED>1 + if (op_selected == 5) + { + selected_instance_id = !selected_instance_id; + op_selected = 0; + lcd_OP_active_instance_number(selected_instance_id, configuration.dexed[selected_instance_id].op_enabled); + } + else +#endif + op_selected = constrain(op_selected + 1, 0, 5); + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + if (bitRead(configuration.dexed[selected_instance_id].op_enabled, op_selected)) + bitClear(configuration.dexed[selected_instance_id].op_enabled, op_selected); + else + bitSet(configuration.dexed[selected_instance_id].op_enabled, op_selected); + + lcd_OP_active_instance_number(selected_instance_id, configuration.dexed[selected_instance_id].op_enabled); + } + + lcd.setCursor(op_selected, 1); + + MicroDexed[selected_instance_id]->setOPAll(configuration.dexed[selected_instance_id].op_enabled); + MicroDexed[selected_instance_id]->doRefreshVoice(); + send_sysex_param(configuration.dexed[selected_instance_id].midi_channel, 155, configuration.dexed[selected_instance_id].op_enabled, 0); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd.noBlink(); + lcd.noCursor(); + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].op_enabled), configuration.dexed[0].op_enabled); +#if NUM_DEXED > 1 + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].op_enabled), configuration.dexed[1].op_enabled); +#endif + } +} + +void UI_func_drum_reverb_send(uint8_t param) +{ + char displayname[8] = {0, 0, 0, 0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = (int)(drum_config[activesample].reverb_send * 100); + lcd.setCursor(0, 0); + lcd.print("Drum Rev. Send"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(4, 5, 6, basename(drum_config[activesample].name)); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + // activesample = constrain(activesample + ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(1); + } + else if (LCDML.BT_checkUp()) + { + // activesample = constrain(activesample - ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(0); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), 0, REVERB_SEND_MAX); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), 0, REVERB_SEND_MAX); + } + } + } + if (LCDML.BT_checkEnter()) + { + if (menu_select_toggle) { + menu_select_toggle = false; + } else + { menu_select_toggle = true; + temp_int = (int)(drum_config[activesample].reverb_send * 100); + } + } + if (menu_select_toggle == false) { + lcd.setCursor(11, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print("["); + lcd.setCursor(3, 1); + lcd.print("]"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(4, 5, 6, basename(drum_config[activesample].name)); + sprintf(displayname, "%03d", (int)(drum_config[activesample].reverb_send * 100) ); + lcd.setCursor(12, 1); + lcd.print(displayname); + } else { + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(11, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + sprintf(displayname, "%03d", temp_int); + lcd.setCursor(12, 1); + lcd.print(displayname); + drum_config[activesample].reverb_send = mapfloat(temp_int, 0, 100, 0.0, 1.0); + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_drum_midi_channel(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("MIDI Channel")); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) + drum_midi_channel = constrain(drum_midi_channel + ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); + else if (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) + drum_midi_channel = constrain(drum_midi_channel - ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); + + lcd.setCursor(0, 1); + if (drum_midi_channel == 0) + { + lcd.print(F("[OMNI]")); + } + else + { + lcd_display_int(drum_midi_channel, 4, false, true, false); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + // EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].midi_channel), configuration.dexed[0].midi_channel); } + } +} +void UI_func_drums_main_volume(uint8_t param) +{ + char displayname[4] = {0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = mapfloat(drums_volume, 0.0, VOL_MAX_FLOAT, 0, 100); + lcd.setCursor(0, 0); + lcd.print(" Drums M.Volume "); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), 0, 100); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), 0, 100); + } + } + lcd.setCursor(5, 1); + sprintf(displayname, "%03d", temp_int); + lcd.print(displayname); + lcd.setCursor(8, 1); + lcd.print("/100"); + master_mixer_r.gain (2, volume_transform(mapfloat(temp_int, 0, 100, 0.0, VOL_MAX_FLOAT))); + master_mixer_l.gain (2, volume_transform(mapfloat(temp_int, 0, 100, 0.0, VOL_MAX_FLOAT))); + drums_volume = mapfloat(temp_int, 0, 100, 0.0, VOL_MAX_FLOAT); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} +void UI_func_drum_tune_offset(uint8_t param) +{ + char displayname[8] = {0, 0, 0, 0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = (int)(drum_config[activesample].p_offset * 200); + lcd.setCursor(0, 0); + lcd.print("DrumSmp. Tune"); + lcd.setCursor(1, 1); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + activesample = constrain(activesample + ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + } + else if (LCDML.BT_checkUp()) + { + activesample = constrain(activesample - ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), 0, 400); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), 0, 400); + } + } + } + if (LCDML.BT_checkEnter()) + { + if (menu_select_toggle) { + menu_select_toggle = false; + } else + { menu_select_toggle = true; + temp_int = (int)(drum_config[activesample].p_offset * 200); + } + } + if (menu_select_toggle == false) { + lcd.setCursor(11, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print("["); + lcd.setCursor(3, 1); + lcd.print("]"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + sprintf(displayname, "%03d", (int)(drum_config[activesample].p_offset * 200) ); + lcd.setCursor(12, 1); + lcd.print(displayname); + } else { + temp_float = mapfloat(temp_int, 0, 400, 0.0, 2.0); + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(11, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + sprintf(displayname, "%03d", temp_int); + lcd.setCursor(12, 1); + lcd.print(displayname); + drum_config[activesample].p_offset = temp_float; + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} +void UI_func_drum_pitch(uint8_t param) +{ + char displayname[8] = {0, 0, 0, 0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = (int)(drum_config[activesample].pitch * 200); + lcd.setCursor(0, 0); + lcd.print("DrumSmp. Pitch"); + lcd.setCursor(1, 1); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + activesample = constrain(activesample + ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + } + else if (LCDML.BT_checkUp()) + { + activesample = constrain(activesample - ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), 0, 400); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), 0, 400); + } + } + } + if (LCDML.BT_checkEnter()) + { + if (menu_select_toggle) { + menu_select_toggle = false; + } else + { menu_select_toggle = true; + temp_int = (int)(drum_config[activesample].pitch * 200); + } + } + if (menu_select_toggle == false) { + lcd.setCursor(11, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print("["); + lcd.setCursor(3, 1); + lcd.print("]"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + sprintf(displayname, "%03d", (int)(drum_config[activesample].pitch * 200) ); + lcd.setCursor(12, 1); + lcd.print(displayname); + } else { + temp_float = mapfloat(temp_int, 0, 400, 0.0, 2.0); + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(11, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + sprintf(displayname, "%03d", temp_int); + lcd.setCursor(12, 1); + lcd.print(displayname); + drum_config[activesample].pitch = temp_float; + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} +void UI_func_drum_volume(uint8_t param) +{ + char displayname[8] = {0, 0, 0, 0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = (int)(drum_config[activesample].vol_max * 100); + lcd.setCursor(0, 0); + lcd.print("DrumSmp. Volume"); + lcd.setCursor(1, 1); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + // activesample = constrain(activesample + ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(1); + } + else if (LCDML.BT_checkUp()) + { + // activesample = constrain(activesample - ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(0); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), 0, 100); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), 0, 100); + } + } + } + if (LCDML.BT_checkEnter()) + { + if (menu_select_toggle) { + menu_select_toggle = false; + } else + { menu_select_toggle = true; + temp_int = (int)(drum_config[activesample].vol_max * 100); + } + } + if (menu_select_toggle == false) { + lcd.setCursor(11, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print("["); + lcd.setCursor(3, 1); + lcd.print("]"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 7, basename(drum_config[activesample].name)); + sprintf(displayname, "%03d", (int)(drum_config[activesample].vol_max * 100) ); + lcd.setCursor(12, 1); + lcd.print(displayname); + } else { + temp_float = mapfloat(temp_int, 0, 100, 0.0, 1.0); + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(11, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + sprintf(displayname, "%03d", temp_int); + lcd.setCursor(12, 1); + lcd.print(displayname); + drum_config[activesample].vol_max = temp_float; + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_arp_shift(uint8_t param) +{ + char displayname[4] = {0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print("Arp/Chord Transp"); + lcd.setCursor(0, 1); + lcd.print("Oct"); + lcd.setCursor(4, 1); + sprintf(displayname, "%02d", seq_oct_shift); + lcd.print(displayname); + lcd.setCursor(8, 1); + lcd.print("Shift"); + lcd.setCursor(14, 1); + lcd.print(seq_element_shift); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + seq_oct_shift = constrain(seq_oct_shift + ENCODER[ENC_R].speed(), -2, 2); + } + else if (LCDML.BT_checkUp()) + { + seq_oct_shift = constrain(seq_oct_shift - ENCODER[ENC_R].speed(), -2, 2); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + seq_element_shift = constrain(seq_element_shift + ENCODER[ENC_R].speed(), 0, 6); + } + else if (LCDML.BT_checkUp()) + { + seq_element_shift = constrain(seq_element_shift - ENCODER[ENC_R].speed(), 0, 6); + } + } + } + if (LCDML.BT_checkEnter()) + { + menu_select_toggle = !menu_select_toggle; + } + if (menu_select_toggle == false) + { lcd.setCursor(13, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print("["); + lcd.setCursor(6, 1); + lcd.print("]"); + lcd.setCursor(4, 1); + sprintf(displayname, "%02d", seq_oct_shift); + lcd.print(displayname); + + } else { + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(6, 1); + lcd.print(" "); + lcd.setCursor(13, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + lcd.setCursor(14, 1); + lcd.print(seq_element_shift); + + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_drum_pan(uint8_t param) +{ + char displayname[8] = {0, 0, 0, 0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + temp_int = mapfloat(drum_config[activesample].pan, -1.0, 1.0, -99, 99); + lcd.setCursor(0, 0); + lcd.print("DrmSmp. Panorama"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 6, basename(drum_config[activesample].name)); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + //activesample = constrain(activesample + ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(1); + } + else if (LCDML.BT_checkUp()) + { + //activesample = constrain(activesample - ENCODER[ENC_R].speed(), 0, NUM_DRUMSET_CONFIG - 2); + smart_filter(0); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_R].speed(), -99, 99); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_R].speed(), -99, 99); + } + } + } + if (LCDML.BT_checkEnter()) + { + if (menu_select_toggle) { + menu_select_toggle = false; + } else + { menu_select_toggle = true; + } + } + if (menu_select_toggle == false) { + lcd.setCursor(11, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print("["); + lcd.setCursor(3, 1); + lcd.print("]"); + lcd.setCursor(1, 1); + sprintf(displayname, "%02d", activesample); + lcd.print(displayname); + lcd.show(1, 4, 6, basename(drum_config[activesample].name)); + } else { + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(3, 1); + lcd.print(" "); + lcd.setCursor(11, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + drum_config[activesample].pan = mapfloat(temp_int, -99, 99, -1.0, 1.0); + } + + temp_int = mapfloat(drum_config[activesample].pan, -1.0, 1.0, -99, 99); + + lcd.setCursor(12, 1); + if (temp_int > 1) { + lcd.print("R"); + } else if (temp_int < 0) { + lcd.print("L"); + } + else { + lcd.print("C"); + } + sprintf(displayname, "%02d", abs(temp_int)); + lcd.setCursor(13, 1); + lcd.print( displayname); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +const char* seq_find_drum_name_from_note(uint8_t note) +{ + bool found = false; + const char* shortname; + for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG - 1; d++) + { + if (note == drum_config[d].midinote) + { shortname = basename(drum_config[d].name); + found = true; + break; + } + } + if (found == false) shortname = " "; + + return shortname; +} + +const char* seq_find_shortname(uint8_t sstep) +{ + const char* shortname; + bool found = false; + if (seq_content_type[seq_active_track] == 0 && seq_vel[seq_active_track][sstep] < 210) //is Drumtrack and not a pitched sample + { + for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG - 1; d++) + { + if (seq_data[seq_active_track][sstep] == drum_config[d].midinote) + { + shortname = drum_config[d].shortname; + found = true; + break; + } + } + if (found == false) shortname = "-"; + } else + { + if (seq_data[seq_active_track][sstep] > 0 && seq_data[seq_active_track][sstep] != 130) + shortname = noteNames[seq_data[seq_active_track][sstep] % 12]; + else if (seq_data[seq_active_track][sstep] == 130) shortname = "~"; // note has tie/latch + else + shortname = "-"; + } + return shortname; +} + +void seq_printAllSeqSteps() +{ + lcd.setCursor(0, 1); + for (uint8_t i = 0; i < 16; i++) + { + lcd.print(seq_find_shortname(i)[0]); + } +} + +#ifdef TESTDISPLAY20x4 +void seq_printVelGraphBar() +{ + lcd.setCursor(0, 2); + for (uint8_t i = 0; i < 16; i++) + { + if (seq_vel[seq_active_track][i] == 0) + lcd.print(" "); + else if (seq_vel[seq_active_track][i] > 0 && seq_vel[seq_active_track][i] <= 20) + lcd.write(1); + else if (seq_vel[seq_active_track][i] > 21 && seq_vel[seq_active_track][i] <= 40) + lcd.write(2); + else if (seq_vel[seq_active_track][i] > 41 && seq_vel[seq_active_track][i] <= 60) + lcd.write(3); + else if (seq_vel[seq_active_track][i] > 61 && seq_vel[seq_active_track][i] <= 80) + lcd.write(4); + else if (seq_vel[seq_active_track][i] > 81 && seq_vel[seq_active_track][i] <= 90) + lcd.write(5); + else if (seq_vel[seq_active_track][i] > 91 && seq_vel[seq_active_track][i] <= 105) + lcd.write(6); + else if (seq_vel[seq_active_track][i] > 105 && seq_vel[seq_active_track][i] <= 128) + lcd.write(7); + else + lcd.print("C"); + } +} +#endif + +void UI_func_seq_display_style(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print("Seq. Disp. Style"); + lcd.setCursor(0, 1); + lcd.print("Pat."); + lcd.setCursor(9, 1); + lcd.print("="); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (menu_select_toggle == false) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + seq_active_track = constrain(seq_active_track + ENCODER[ENC_R].speed(), 0, NUM_SEQ_PATTERN - 1); + } + else if (LCDML.BT_checkUp()) + { + seq_active_track = constrain(seq_active_track - ENCODER[ENC_R].speed(), 0, NUM_SEQ_PATTERN - 1); + } + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + seq_content_type[seq_active_track] = constrain(seq_content_type[seq_active_track] + ENCODER[ENC_R].speed(), 0, 2); + } + else if (LCDML.BT_checkUp()) + { + seq_content_type[seq_active_track] = constrain(seq_content_type[seq_active_track] - ENCODER[ENC_R].speed(), 0, 2); + } + } + } + if (LCDML.BT_checkEnter()) + { + menu_select_toggle = !menu_select_toggle; + } + if (menu_select_toggle == false) { + lcd.setCursor(10, 1); + lcd.print(" "); + lcd.setCursor(15, 1); + lcd.print(" "); + lcd.setCursor(4, 1); + lcd.print("["); + if (seq_active_track < 10) + lcd.print ("0"); + lcd.print(seq_active_track); + lcd.print("]"); + } else { + lcd.setCursor(4, 1); + lcd.print(" "); + lcd.setCursor(7, 1); + lcd.print(" "); + lcd.setCursor(10, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + } + lcd.setCursor(11, 1); + if (seq_content_type[seq_active_track] == 0) + lcd.print("Drum"); + else if (seq_content_type[seq_active_track] == 1) + lcd.print("Inst"); + else + lcd.print("Chrd"); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_live_transpose_oct(uint8_t param) +{ //Select octave for live transpose of sequencer instrument track. Should be one of the lowest octaves available on the keyboard. + //Allowed range: C1-C5 to not restrict too much, even for very unusual user setups/configurations. + + char note_name[4]; + char note_name2[4]; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + getNoteName(note_name, seq_transpose); + getNoteName(note_name2, seq_transpose + 12); + lcd.setCursor(0, 0); + lcd.print(F("Live Transp.Oct.")); + lcd.setCursor(0, 1); + lcd.print(F("[")); + lcd.print(note_name); + lcd.print(F("] - ")); + lcd.print(("[")); + lcd.print(note_name2); + lcd.print(("]")); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + seq_transpose = constrain(seq_transpose + ENCODER[ENC_R].speed(), 24, 60); + else if (LCDML.BT_checkUp()) + seq_transpose = constrain(seq_transpose - ENCODER[ENC_R].speed(), 24, 60); + } + getNoteName(note_name, seq_transpose); + getNoteName(note_name2, seq_transpose + 12); + lcd.setCursor(0, 1); + lcd.print(F("[")); + lcd.print(note_name); + lcd.print(F("] - ")); + lcd.print(("[")); + lcd.print(note_name2); + lcd.print(("]")); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_chord_keys_ammount(uint8_t param) +{ + char displayname[4] = {0, 0, 0, 0}; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print("ChordTrack Keys:"); + lcd.setCursor(8, 1); + lcd.print("Keys"); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + seq_chord_key_ammount = constrain(seq_chord_key_ammount + ENCODER[ENC_R].speed(), 1, 7); + else if (LCDML.BT_checkUp()) + seq_chord_key_ammount = constrain(seq_chord_key_ammount - ENCODER[ENC_R].speed(), 1, 7); + } + lcd.setCursor(4, 1); + lcd.print("["); + sprintf(displayname, "%02d", seq_chord_key_ammount); + lcd.print(displayname); + lcd.print("]"); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_lenght(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(" Seq. lenght "); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + seq_chain_lenght = constrain(seq_chain_lenght + ENCODER[ENC_R].speed(), 0, 3); + else if (LCDML.BT_checkUp()) + seq_chain_lenght = constrain(seq_chain_lenght - ENCODER[ENC_R].speed(), 0, 3); + } + lcd.setCursor(3, 1); + lcd.print((seq_chain_lenght + 1) * 16 ); + lcd.setCursor(7, 1); + lcd.print("Steps"); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_tempo(uint8_t param) +{ + char tmp[7]; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(" Seq. Tempo "); + lcd.setCursor(5, 1); + lcd.print("BPM"); + lcd.setCursor(14, 1); + lcd.print("ms"); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + seq_bpm = constrain(seq_bpm + ENCODER[ENC_R].speed(), 50, 190); + else if (LCDML.BT_checkUp()) + seq_bpm = constrain(seq_bpm - ENCODER[ENC_R].speed(), 50, 190); + } + seq_tempo_ms = 60000000 / seq_bpm / 4; + lcd.setCursor(0, 1); + sprintf(tmp, "[%3d]", seq_bpm); + lcd.print(tmp); + lcd.setCursor(11, 1); + sprintf(tmp, "%3d", seq_tempo_ms / 1000); + lcd.print(tmp); +#ifdef USE_FX + for (uint8_t i = 0; i < MAX_DEXED; i++) + { + if (configuration.fx.delay_sync[i] > 0) + { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[configuration.fx.delay_sync[i]] / seq_bpm); + delay_fx[i]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN, DELAY_TIME_MAX * 10)); + } + } +#endif + //timer1.stop(); + timer1.begin(sequencer, seq_tempo_ms / 2); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_vel_editor(uint8_t param) +{ + char tmp[5]; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + // setup function + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print("V:"); + sprintf(tmp, "%03d", seq_vel[seq_active_track][seq_menu - 1]); + lcd.setCursor(2, 0); + lcd.print(tmp); + lcd.setCursor(12, 0); + lcd.print("["); + lcd.setCursor(13, 0); + if (seq_active_track < 10) + lcd.print("0"); + lcd.print(seq_active_track); + lcd.setCursor(15, 0); + lcd.print("]"); + + seq_printAllSeqSteps(); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (seq_active_function == 99) + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_menu = constrain(seq_menu + 1, 0, 16); + else if (LCDML.BT_checkUp()) + seq_menu = constrain(seq_menu - 1, 0, 16); + } + } + else if (seq_active_function == 0) + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_active_track = constrain(seq_active_track + 1, 0, NUM_SEQ_PATTERN - 1); + else if (LCDML.BT_checkUp()) + seq_active_track = constrain(seq_active_track - 1, 0, NUM_SEQ_PATTERN - 1); + } + } + if ( seq_data[seq_active_track][seq_menu - 1] > 0 ) + { + if (seq_vel[seq_active_track][seq_menu - 1] < 210) //it is a normal sample + { + if (seq_active_function == 1 && seq_content_type[seq_active_track] < 2 ) + { //if is Drum or normal Instrument Track + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] + 1, 0, 127); + else if (LCDML.BT_checkUp()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] - 1, 0, 127); + } + } + else if (seq_active_function == 1 && seq_content_type[seq_active_track] > 1 ) + { //is in Chord or Arp Mode + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] + 1, 200, 205); + else if (LCDML.BT_checkUp()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] - 1, 200, 205); + } + } + } + else + { + //is in pitched Sample Mode + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] + 1, 210, 215); + else if (LCDML.BT_checkUp()) + seq_vel[seq_active_track][seq_menu - 1] = constrain(seq_vel[seq_active_track][seq_menu - 1] - 1, 210, 215); + } + } + } + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if ( seq_menu == 0 && seq_active_function == 99) + { + seq_active_function = 0; + } else if ( seq_menu == 0 && seq_active_function == 0) + { + seq_active_function = 99; + } + else if (seq_menu > 0 && seq_active_function == 99) + { + seq_active_function = 1; + } + else + seq_active_function = 99; + } + //button check end <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + if ( seq_content_type[seq_active_track] > 1 && seq_vel[seq_active_track][seq_menu - 1] < 200) seq_vel[seq_active_track][seq_menu - 1] = 200; + if (seq_active_function == 0) { + lcd.setCursor(0, 0); + if (seq_content_type[seq_active_track] == 0) + lcd.print("Drum Track "); + else if (seq_content_type[seq_active_track] == 1) + lcd.print("Instr. Track "); + else + lcd.print("Chord Track "); + } + if (seq_menu > 0 && seq_content_type[seq_active_track] == 0) + { + lcd.setCursor(0, 0); + if (seq_vel[seq_active_track][seq_menu - 1] < 210 && seq_vel[seq_active_track][seq_menu - 1] > 0) //it is a normal sample + { + lcd.print("V:"); + sprintf(tmp, "%03d", seq_vel[seq_active_track][seq_menu - 1]); + lcd.setCursor(2, 0); + lcd.print(tmp); + } + else + { // else it is a live-pitched sample + if (seq_vel[seq_active_track][seq_menu - 1] > 0) { + lcd.setCursor(0, 0); + lcd.print("Smp:["); + lcd.setCursor(12, 0); + lcd.print("]"); + lcd.show(0, 5, 7, basename(drum_config[seq_vel[seq_active_track][seq_menu - 1] - 210].name)); + } + } + } + if (seq_menu == 0) { + lcd.setCursor(12, 0); + lcd.print("["); + if (seq_active_track < 10) + lcd.print("0"); + lcd.print(seq_active_track); + lcd.print("]"); + lcd.setCursor(0, 1); + seq_printAllSeqSteps(); + } else if (seq_menu == 1) { + lcd.setCursor(12, 0); + lcd.print(" "); + lcd.setCursor(15, 0); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.write(219); // cursor symbol + lcd.setCursor(1, 1); + lcd.print(seq_find_shortname(1)[0] ); + if (seq_vel[seq_active_track][seq_menu - 1] < 210 && seq_content_type[seq_active_track] < 2) //it is a normal sample + { + sprintf(tmp, "%03d", seq_vel[seq_active_track][seq_menu - 1]); + lcd.setCursor(2, 0); + lcd.print(tmp); + } + } else if (seq_menu > 1) + { + lcd.setCursor(seq_menu - 1, 1); + lcd.write(219); // cursor symbol + lcd.setCursor(seq_menu - 2, 1); + lcd.print(seq_find_shortname(seq_menu - 2)[0] ); + if (seq_menu < 16) { + lcd.setCursor(seq_menu , 1); + lcd.print(seq_find_shortname(seq_menu)[0] ); + } + } + if (seq_menu > 0) { + lcd.setCursor(4, 0); + if (seq_data[seq_active_track][seq_menu - 1] > 0) + { + if (seq_content_type[seq_active_track] == 0) //is Drumtrack + { + lcd.setCursor(0, 0); + if (seq_vel[seq_active_track][seq_menu - 1] < 210) //it is a normal sample + { + lcd.print("V:"); + sprintf(tmp, "%03d", seq_vel[seq_active_track][seq_menu - 1]); + lcd.print(tmp); + //lcd.setCursor(7, 0); + //lcd.print(" "); + lcd.show(0, 6, 5, seq_find_drum_name_from_note( seq_data[seq_active_track][seq_menu - 1]) ); + } + else + { // else it is a live-pitched sample + lcd.setCursor(0, 0); + lcd.print("Smp:["); + lcd.setCursor(12, 0); + lcd.print("]"); + lcd.setCursor(1, 0); + lcd.show(0, 5, 7, basename(drum_config[seq_vel[seq_active_track][seq_menu - 1] - 210].name)); + } + } else + { + if ( seq_data[seq_active_track][seq_menu - 1] != 130 ) //note not latched + { + if (seq_content_type[seq_active_track] < 2) + { + lcd.setCursor(0, 0); + lcd.print("Vel:"); + sprintf(tmp, "%03d", seq_vel[seq_active_track][seq_menu - 1]); + lcd.setCursor(4, 0); + lcd.print(tmp); + lcd.print(" "); + } + lcd.setCursor(8, 0); + lcd.print(noteNames[seq_data[seq_active_track][seq_menu - 1] % 12 ][0] ); + if (noteNames[seq_data[seq_active_track][seq_menu - 1] % 12 ][1] != '\0' ) { + lcd.print(noteNames[seq_data[seq_active_track][seq_menu - 1] % 12 ][1] ); + } + lcd.print( (seq_data[seq_active_track][seq_menu - 1] / 12) - 1); + lcd.print(" "); + } + else + { //note is latched + lcd.setCursor(0, 0); + lcd.print("latched note "); + } + if (seq_content_type[seq_active_track] > 1) + { + lcd.setCursor(0, 0); + if (seq_vel[seq_active_track][seq_menu - 1] == 200) lcd.print("Major " ); + else if (seq_vel[seq_active_track][seq_menu - 1] == 201) lcd.print("Minor " ); + else if (seq_vel[seq_active_track][seq_menu - 1] == 202) lcd.print("Seven " ); + else if (seq_vel[seq_active_track][seq_menu - 1] == 203) lcd.print("Aug " ); + else if (seq_vel[seq_active_track][seq_menu - 1] == 204) lcd.print("Dim " ); + else if (seq_vel[seq_active_track][seq_menu - 1] == 205) lcd.print("Major7 " ); + } + } + } + else + { + lcd.setCursor(0, 0); + lcd.print(" "); + } + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void seq_clear_active_pattern() +{ + memset(seq_data[seq_active_track], 0, sizeof(seq_data[seq_active_track])); + memset(seq_vel[seq_active_track], 0, sizeof(seq_vel[seq_active_track])); +} +void seq_clear_all_patterns() +{ + for (uint8_t i = 0; i < 10; i++) + { + memset(seq_data[i], 0, sizeof(seq_data[i])); + memset(seq_vel[i], 0, sizeof(seq_vel[i])); + } +} + +void seq_refresh_display_play_status() +{ + if (seq_running == false && seq_recording == false) + { + lcd.createChar(0, (uint8_t*)special_chars[19]); //play symbol +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); +#else + lcd.setCursor(10, 0); +#endif + lcd.write(0); + } else if (seq_running == true && seq_recording == false) + { + seq_note_in = 0; + lcd.createChar(0, (uint8_t*)special_chars[20]); //record symbol +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); +#else + lcd.setCursor(10, 0); +#endif + lcd.write(0); + } else if (seq_running == true && seq_recording == true) + { + seq_note_in = 0; + lcd.createChar(0, (uint8_t*)special_chars[21]); //stop symbol +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); +#else + lcd.setCursor(10, 0); +#endif + lcd.write(0); + } +} + +void arp_refresh_display_play_status() +{ + if (seq_running == false ) + { + lcd.createChar(0, (uint8_t*)special_chars[19]); //play symbol + lcd.setCursor(13, 0); + lcd.write(0); + } else if (seq_running == true ) + { + seq_note_in = 0; + lcd.createChar(0, (uint8_t*)special_chars[21]); //stop symbol + lcd.setCursor(13, 0); + lcd.write(0); + } +} +void seq_print_current_note() +{ + lcd.print(noteNames[seq_data[seq_active_track][seq_menu - 3] % 12 ][0] ); + if (noteNames[seq_data[seq_active_track][seq_menu - 3] % 12 ][1] != '\0' ) + { + lcd.print(noteNames[seq_data[seq_active_track][seq_menu - 3] % 12 ][1] ); + } + lcd.print( (seq_data[seq_active_track][seq_menu - 3] / 12) - 1); + lcd.print(" "); +} +void UI_func_seq_pattern_editor(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + lcd.createChar(0, (uint8_t*)special_chars[19]); //play symbol + record symbol switching +#ifdef TESTDISPLAY20x4 + lcd.createChar(1, (uint8_t*)special_chars[9]); //bar graph + lcd.createChar(2, (uint8_t*)special_chars[10]); //bar graph + lcd.createChar(3, (uint8_t*)special_chars[11]); //bar graph + lcd.createChar(4, (uint8_t*)special_chars[12]); //bar graph + lcd.createChar(5, (uint8_t*)special_chars[13]); //bar graph + lcd.createChar(6, (uint8_t*)special_chars[14]); //bar graph + lcd.createChar(7, (uint8_t*)special_chars[15]); //bar graph +#endif + temp_int = seq_data[seq_active_track][0]; + encoderDir[ENC_R].reset(); + seq_note_in = 0; + // setup function + seq_refresh_display_play_status(); +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); +#else + lcd.setCursor(13, 0); +#endif + if (seq_active_track < 10)lcd.print("0"); + lcd.print(seq_active_track); + seq_printAllSeqSteps(); +#ifdef TESTDISPLAY20x4 + seq_printVelGraphBar(); +#endif + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (seq_active_function == 40 ) { // pitch edit sample + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + seq_data[seq_active_track][seq_menu - 3] = constrain(seq_data[seq_active_track][seq_menu - 3] + 1, 1, 108); + } + else if (LCDML.BT_checkUp()) { + seq_data[seq_active_track][seq_menu - 3] = constrain(seq_data[seq_active_track][seq_menu - 3] - 1, 1, 108); + } + } + } + else if (seq_menu == 33) { // is in sub-function - fill pattern + seq_active_function = 95; + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + seq_temp_active_menu = constrain(seq_temp_active_menu + 1, 0, 3); + } + else if (LCDML.BT_checkUp()) { + seq_temp_active_menu = constrain(seq_temp_active_menu - 1, 0, 3); + } + } + } + else if (seq_menu == 32) { // is in sub-function - fill pattern + seq_active_function = 97; + if (seq_content_type[seq_active_track] == 0) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + seq_temp_select_menu = constrain(seq_temp_select_menu + 1, 0, NUM_DRUMSET_CONFIG - 1); + } + else if (LCDML.BT_checkUp()) { + seq_temp_select_menu = constrain(seq_temp_select_menu - 1, 0, NUM_DRUMSET_CONFIG - 1); + } + } + } + else + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_temp_select_menu = constrain(seq_temp_select_menu + 1, 0, 108 ); + else if (LCDML.BT_checkUp()) + seq_temp_select_menu = constrain(seq_temp_select_menu - 1, 0, 108 ); + } + } + } + else if (seq_menu == 30 || seq_menu == 31 ) { // is in sub-function - swap pattern or copy pattern + seq_active_function = 98; + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + + temp_int = constrain(temp_int + 1, 0, NUM_SEQ_PATTERN - 1); + if (temp_int == seq_active_track)temp_int++; + if (temp_int > NUM_SEQ_PATTERN - 1)temp_int = 0; + } + else if (LCDML.BT_checkUp()) { + temp_int = constrain(temp_int - 1, 0, NUM_SEQ_PATTERN - 1); + if (temp_int == seq_active_track)temp_int--; + if (temp_int < 0)temp_int = NUM_SEQ_PATTERN - 1; + } + } + } + else if (seq_menu == 34) { // is in transpose edit + seq_active_function = 94; + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + temp_int = constrain(temp_int + 1, -36, 36); + if (temp_int > 36)temp_int = 36; + } + else if (LCDML.BT_checkUp()) { + temp_int = constrain(temp_int - 1, -36, 36); + if (temp_int < -36)temp_int = -36; + } + } + } + else if (seq_active_function == 99 ) + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_menu = constrain(seq_menu + 1, 0, 18); + else if (LCDML.BT_checkUp()) + seq_menu = constrain(seq_menu - 1, 0, 18); + } + } + else if (seq_active_function == 0 ) { + if (seq_content_type[seq_active_track] == 0) // is in Drumedit mode + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + activesample = constrain(activesample + 1, 0, NUM_DRUMSET_CONFIG + 5 ); + else if (LCDML.BT_checkUp()) + activesample = constrain(activesample - 1, 0, NUM_DRUMSET_CONFIG + 5 ); + } + } + else //is in Instrument Mode + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + temp_int = constrain(temp_int + 1, 0, 116 ); + else if (LCDML.BT_checkUp()) + temp_int = constrain(temp_int - 1, 0, 116 ); + } + } + } else if (seq_active_function == 2) + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_active_track = constrain(seq_active_track + 1, 0, NUM_SEQ_PATTERN - 1); + else if (LCDML.BT_checkUp()) + seq_active_track = constrain(seq_active_track - 1, 0, NUM_SEQ_PATTERN - 1); + + lcd.setCursor(1, 0); + if (seq_content_type[seq_active_track] == 0) lcd.print("Drum "); else if (seq_content_type[seq_active_track] == 1) lcd.print("Instr "); else if (seq_content_type[seq_active_track] == 2) lcd.print("Chord "); else lcd.print("Arp "); + } + } + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if (seq_menu > 2 && seq_menu < 19 && seq_vel[seq_active_track][seq_menu - 3] > 209 && seq_active_function != 40 && activesample != NUM_DRUMSET_CONFIG - 1) //edit pitch of sample + { + seq_active_function = 40; + } else if ( seq_active_function == 40 ) // get out of pitch edit for samples + { + lcd.setCursor(8, 0); + lcd.print(" "); + seq_active_function = 0; + activesample = 0; + seq_refresh_display_play_status(); + seq_printAllSeqSteps(); + } else if (seq_menu == 34 ) //transpose pattern + { + seq_menu = 0; + seq_active_function = 0; + activesample = 0; + temp_int = seq_data[seq_active_track][0]; + lcd.setCursor(8, 0); + lcd.print(" "); + lcd.setCursor(12, 0); + lcd.print(" "); + lcd.setCursor(13, 0); + if (seq_active_track < 10)lcd.print("0"); + lcd.print(seq_active_track); + seq_refresh_display_play_status(); + seq_printAllSeqSteps(); + } + else if (seq_menu == 32 && seq_active_function == 97) //fill pattern every 1/4, 1/8, 1/16 step with active sample/note step 1 + { + seq_active_function = 96; + seq_menu = 33; + } else if (seq_menu == 33 && seq_active_function == 95) //fill pattern every 1/4, 1/8, 1/16 step with active sample/note step 2 + { + if (seq_content_type[seq_active_track] == 0) { //Drumtrack + for (uint8_t i = 0; i < 16; i++) + { + seq_data[seq_active_track][i] = drum_config[seq_temp_select_menu].midinote; + seq_vel[seq_active_track][i] = 120; + if (seq_temp_active_menu == 0) i = i + 3; else if (seq_temp_active_menu == 1) i = i + 1; + } + } + else + { //Inst. Track + for (uint8_t i = 0; i < 16; i++) + { + seq_data[seq_active_track][i] = seq_temp_select_menu; + seq_vel[seq_active_track][i] = 120; + if (seq_temp_active_menu == 0) i = i + 3; else if (seq_temp_active_menu == 1) i = i + 1; + } + } + seq_menu = 0; + seq_active_function = 0; + activesample = 0; + temp_int = seq_data[seq_active_track][0]; + lcd.setCursor(8, 0); + lcd.print(" "); + seq_refresh_display_play_status(); + seq_printAllSeqSteps(); + } else if (seq_menu == 31 && seq_active_function != 40) //copy patterns + { + memcpy( seq_data[temp_int], seq_data[seq_active_track], sizeof(seq_data[0])); + memcpy( seq_vel[temp_int], seq_vel[seq_active_track], sizeof(seq_vel[0])); + seq_content_type[temp_int] = seq_content_type[seq_active_track]; + seq_menu = 0; + seq_active_function = 0; + activesample = 0; + temp_int = seq_data[seq_active_track][0]; + lcd.setCursor(8, 0); + lcd.print(" "); + seq_refresh_display_play_status(); + seq_printAllSeqSteps(); + } else if (seq_menu == 30 && seq_active_function != 40) //swap patterns + { + uint8_t data_temp[1][16]; + uint8_t vel_temp[1][16]; + uint8_t content_type_temp; + memcpy( data_temp[0], seq_data[seq_active_track], sizeof(data_temp[0])); + memcpy( vel_temp[0], seq_vel[seq_active_track], sizeof(vel_temp[0])); + content_type_temp = seq_content_type[seq_active_track]; + memcpy( seq_data[seq_active_track], seq_data[temp_int], sizeof(data_temp[0])); + memcpy( seq_vel[seq_active_track], seq_vel[temp_int], sizeof(vel_temp[0])); + seq_content_type[seq_active_track] = seq_content_type[temp_int]; + memcpy( seq_data[temp_int], data_temp[0], sizeof(data_temp[0])); + memcpy( seq_vel[temp_int], vel_temp[0], sizeof(vel_temp[0])); + seq_content_type[temp_int] = content_type_temp; + seq_menu = 0; + seq_active_function = 0; + activesample = 0; + lcd.setCursor(8, 0); + lcd.print(" "); + temp_int = seq_data[seq_active_track][0]; + seq_refresh_display_play_status(); + seq_printAllSeqSteps(); + } + if ( seq_menu == 0 && seq_active_function == 99) + { + seq_active_function = 0; + } else if ( seq_menu == 0 && seq_active_function == 0) + { + if ( (seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG + 5) || (seq_content_type[seq_active_track] > 0 && temp_int == 116) ) + { //transpose pattern + lcd.setCursor(0, 0); + lcd.print("Transpose:[ 00]"); + for (uint8_t i = 0; i < 16; i++) + { + seq_data_buffer[i] = seq_data[seq_active_track][i]; + } + seq_menu = 34; + temp_int = 0; + seq_temp_select_menu = 0; + seq_temp_active_menu = 0; + } + if ( (seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG + 4) || (seq_content_type[seq_active_track] > 0 && temp_int == 115) ) + { //fill patterns + lcd.setCursor(0, 0); + lcd.print("Fill Pattern:"); + lcd.setCursor(9, 1); + lcd.print(" "); + seq_menu = 32; + seq_temp_select_menu = 0; + seq_temp_active_menu = 0; + } + else if ( (seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG + 3) || (seq_content_type[seq_active_track] > 0 && temp_int == 114) ) + { //swap patterns: Active pattern <-> destination pattern + lcd.setCursor(0, 0); + lcd.print("SwapPattern:"); + temp_int = seq_active_track + 1; + if (temp_int > NUM_SEQ_PATTERN - 1)temp_int = 0; + seq_menu = 30; + } else if ( ( seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG + 2) || ( seq_content_type[seq_active_track] > 0 && temp_int == 113) ) + { //copy pattern + lcd.setCursor(0, 0); + lcd.print("Copy Pattern:"); + temp_int = seq_active_track + 1; + if (temp_int > NUM_SEQ_PATTERN - 1)temp_int = 0; + seq_menu = 31; + } else if ( (seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG + 1) || (seq_content_type[seq_active_track] > 0 && temp_int == 112) ) + { //clear all patterns + seq_clear_all_patterns(); + seq_printAllSeqSteps(); + } else if ( (seq_content_type[seq_active_track] == 0 && activesample == NUM_DRUMSET_CONFIG) || (seq_content_type[seq_active_track] > 0 && temp_int == 111) ) + { //clear pattern + seq_clear_active_pattern(); + seq_printAllSeqSteps(); + } + seq_active_function = 99; + } + if ( seq_menu == 1 && seq_active_function != 40) + { + if (seq_running == false && seq_recording == false) + { + seq_running = true; + timer1.start(); + } else if (seq_running == true && seq_recording == false) + { + seq_running = true; + seq_recording = true; + seq_note_in = 0; + } else if (seq_running == true && seq_recording == true) + { + seq_running = false; + seq_recording = false; + seq_note_in = 0; + seq_step = 0; + seq_chain_active_step = 0; + timer1.stop(); + MicroDexed[0]->panic(); + } + } else if ( seq_menu == 2 && seq_active_function != 40) + { + if (seq_active_function != 2) seq_active_function = 2; else seq_active_function = 99; + + if (seq_content_type[seq_active_track] == 0) + { + if (activesample < NUM_DRUMSET_CONFIG - 1) + lcd.show(0, 1, 6, basename(drum_config[activesample].name)); + } else + { + if (temp_int < 109) { + lcd.setCursor(3, 0); + lcd.print(" "); + lcd.setCursor(1, 0); + lcd.print(noteNames[temp_int % 12 ]); + lcd.print( (temp_int / 12) - 1); + } + } + } else if (seq_menu > 2 && seq_menu < 30 && seq_active_function != 40) + { + if (seq_active_function == 99) + { + if (seq_content_type[seq_active_track] == 0) + { //Drumtrack + + if ( drum_config[activesample].midinote > 209 ) //it is a pitched sample + { + seq_vel[seq_active_track][seq_menu - 3] = drum_config[activesample].midinote; + //seq_data[seq_active_track][seq_menu - 3] = MIDI_C4; + } + else + // if (activesample == NUM_DRUMSET_CONFIG - 1) //user selected EMPTY note for pitched sample + // { + // seq_data[seq_active_track][seq_menu - 3] = 0; + // seq_vel[seq_active_track][seq_menu - 3] = 0; + // } + // else + //check if note is already there, if not -> insert it, else remove it from grid. + if (seq_data[seq_active_track][seq_menu - 3] == drum_config[activesample].midinote) + { + seq_data[seq_active_track][seq_menu - 3] = 0; + seq_vel[seq_active_track][seq_menu - 3] = 0; + } else + { + seq_data[seq_active_track][seq_menu - 3] = drum_config[activesample].midinote; + seq_vel[seq_active_track][seq_menu - 3] = 120; + } + } + else + { //Inst. Track + if (temp_int == 109 || seq_data[seq_active_track][seq_menu - 3] == temp_int ) + { //clear note + seq_data[seq_active_track][seq_menu - 3] = 0; + seq_vel[seq_active_track][seq_menu - 3] = 0; + } else if (temp_int == 110) { //latch note + seq_data[seq_active_track][seq_menu - 3] = 130; + //seq_vel[seq_active_track][seq_menu - 3] = 0; + } else + { + seq_data[seq_active_track][seq_menu - 3] = temp_int; + seq_vel[seq_active_track][seq_menu - 3] = 120; + } + } + } + else + seq_active_function = 99; + } + } + //button check end <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + if (seq_menu == 34 && seq_active_function == 94) + { //transpose + char displayname[4] = {0, 0, 0, 0}; + lcd.setCursor(10, 0); + lcd.print("["); + lcd.setCursor(11, 0); + if (temp_int > 0) { + lcd.print("+"); + } else if (temp_int < 0) + { + lcd.print("-"); + } + else { + lcd.print(" "); + } + sprintf(displayname, "%02d", abs(temp_int)); + lcd.print( displayname); + lcd.print("]"); + for (uint8_t i = 0; i < 16; i++) + { + if (seq_content_type[seq_active_track] == 0) { //drums + if (seq_data_buffer[i] != 0 && seq_data_buffer[i] + temp_int >= 0 && seq_data_buffer[i] + temp_int < 254 + && seq_vel[seq_active_track][i] >= 210 ) // pitched drums only + seq_data[seq_active_track][i] = seq_data_buffer[i] + temp_int; + } + else + //instruments + if (seq_content_type[seq_active_track] > 0) { + if (seq_data_buffer[i] != 0 && seq_data_buffer[i] != 130 && seq_data_buffer[i] + temp_int > 0 && seq_data_buffer[i] + temp_int < 254) + seq_data[seq_active_track][i] = seq_data_buffer[i] + temp_int; + } + } + seq_printAllSeqSteps(); + } + else if (seq_menu == 33) + { //fill pattern 2nd parameter + lcd.setCursor(4, 1); + lcd.print(" "); + lcd.setCursor(9, 1); + lcd.print(" "); + lcd.setCursor(10, 1); + lcd.print("["); + lcd.setCursor(15, 1); + lcd.print("]"); + lcd.setCursor(11, 1); + if (seq_temp_active_menu == 0) lcd.print(" 1/4"); + else if (seq_temp_active_menu == 1) lcd.print(" 1/8"); + else if (seq_temp_active_menu == 2) lcd.print("1/16"); + } else if (seq_menu == 32 ) { //fill pattern + if (seq_content_type[seq_active_track] == 0) { //drum + lcd.setCursor(0, 1); + lcd.print("with"); + lcd.setCursor(4, 1); + lcd.print("["); + lcd.setCursor(9, 1); + lcd.print("]"); + lcd.show(1, 5, 4, basename(drum_config[seq_temp_select_menu].name)); + lcd.setCursor(11, 1); + if (seq_temp_active_menu == 0) lcd.print(" 1/4"); + else if (seq_temp_active_menu == 1) lcd.print(" 1/8"); + else if (seq_temp_active_menu == 2) lcd.print("1/16"); + } else + { //inst + lcd.setCursor(0, 1); + lcd.print("with"); + lcd.setCursor(4, 1); + lcd.print("["); + lcd.setCursor(5, 1); + lcd.print(noteNames[seq_temp_select_menu % 12 ]); + lcd.print( (seq_temp_select_menu / 12) - 1); + lcd.print(" "); + lcd.setCursor(9, 1); + lcd.print("]"); + lcd.setCursor(11, 1); + if (seq_temp_active_menu == 0) lcd.print(" 1/4"); + else if (seq_temp_active_menu == 1) lcd.print(" 1/8"); + else if (seq_temp_active_menu == 2) lcd.print("1/16"); + } + } else if (seq_menu == 31) { //copy pattern + lcd.setCursor(12, 0); + lcd.print("["); + lcd.setCursor(15, 0); + lcd.print("]"); + lcd.setCursor(0, 1); + lcd.print(" to:[ ]"); + lcd.setCursor(13, 1); + if (temp_int < 10) lcd.print("0"); + lcd.print(temp_int); + } else if (seq_menu == 30) { //swap pattern + lcd.setCursor(12, 0); + lcd.print("["); + lcd.setCursor(15, 0); + lcd.print("]"); + lcd.setCursor(0, 1); + lcd.print(" with:[ ]"); + lcd.setCursor(13, 1); + if (temp_int < 10) lcd.print("0"); + lcd.print(temp_int); + } else if (seq_menu == 0) { +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); + lcd.print(" "); + lcd.setCursor(16, 0); + lcd.print(" "); +#else + lcd.setCursor(9, 0); + lcd.print(" "); + lcd.setCursor(11, 0); + lcd.print(" "); +#endif + lcd.setCursor(0, 0); + lcd.print("["); + if (seq_content_type[seq_active_track] == 0) //Drum Mode + { + if (activesample < NUM_DRUMSET_CONFIG - 1) { + lcd.show(0, 1, 6, basename(drum_config[activesample].name)); + } else if (activesample == NUM_DRUMSET_CONFIG - 1) { + lcd.setCursor(1, 0); + lcd.print("EMPTY "); + } else if (activesample == NUM_DRUMSET_CONFIG ) { + lcd.setCursor(1, 0); + lcd.print("ClrPat"); + } else if (activesample == NUM_DRUMSET_CONFIG + 1) { + lcd.setCursor(1, 0); + lcd.print("ClrAll"); + } + else if (activesample == NUM_DRUMSET_CONFIG + 2) { + lcd.setCursor(1, 0); + lcd.print("Copy P"); + } + else if (activesample == NUM_DRUMSET_CONFIG + 3) { + lcd.setCursor(1, 0); + lcd.print("Swap P"); + } + else if (activesample == NUM_DRUMSET_CONFIG + 4) { + lcd.setCursor(1, 0); + lcd.print("Fill P"); + } + else if (activesample == NUM_DRUMSET_CONFIG + 5) { + lcd.setCursor(1, 0); + lcd.print("Transp"); + } + lcd.setCursor(7, 0); + lcd.print("]"); + } else //Inst. Mode + { + if (temp_int < 109) { + lcd.setCursor(3, 0); + lcd.print(" "); + lcd.setCursor(1, 0); + lcd.print(noteNames[temp_int % 12 ]); + lcd.print( (temp_int / 12) - 1); + } else if (temp_int == 109) { + lcd.setCursor(1, 0); + lcd.print("EMPTY "); + } else if (temp_int == 110) { + lcd.setCursor(1, 0); + lcd.print("LATCH "); + } else if (temp_int == 111) { + lcd.setCursor(1, 0); + lcd.print("ClrPat"); + } else if (temp_int == 112) { + lcd.setCursor(1, 0); + lcd.print("ClrAll"); + } else if (temp_int == 113) { + lcd.setCursor(1, 0); + lcd.print("Copy P"); + } else if (temp_int == 114) { + lcd.setCursor(1, 0); + lcd.print("Swap P"); + } else if (temp_int == 115) { + lcd.setCursor(1, 0); + lcd.print("Fill P"); + } else if (temp_int == 116) { + lcd.setCursor(1, 0); + lcd.print("Transp"); + } + lcd.setCursor(7, 0); + lcd.print("]"); + } + } + else if (seq_menu == 1) { + lcd.setCursor(0, 0); + lcd.print(" "); + lcd.setCursor(7, 0); + lcd.print(" "); +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); + lcd.print(" "); + lcd.setCursor(19, 0); + lcd.print(" "); +#else + lcd.setCursor(12, 0); + lcd.print(" "); + lcd.setCursor(15, 0); + lcd.print(" "); +#endif +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); + lcd.print("["); + seq_refresh_display_play_status(); + lcd.setCursor(16, 0); + lcd.print("]"); +#else + lcd.setCursor(9, 0); + lcd.print("["); + seq_refresh_display_play_status(); + lcd.setCursor(11, 0); + lcd.print("]"); +#endif + } + if (seq_menu == 2) { +#ifdef TESTDISPLAY20x4 + lcd.setCursor(14, 0); + lcd.print(" "); + lcd.setCursor(16, 0); + lcd.print(" "); + lcd.setCursor(16, 0); + lcd.print("["); + lcd.setCursor(17, 0); + if (seq_active_track < 10) lcd.print("0"); + lcd.print(seq_active_track); + lcd.setCursor(19, 0); + lcd.print("]"); +#else + lcd.setCursor(9, 0); + lcd.print(" "); + lcd.setCursor(11, 0); + lcd.print(" "); + lcd.setCursor(12, 0); + lcd.print("["); + lcd.setCursor(13, 0); + if (seq_active_track < 10) lcd.print("0"); + lcd.print(seq_active_track); + lcd.setCursor(15, 0); + lcd.print("]"); + if (seq_content_type[seq_active_track] == 0) //Drum Mode + { + lcd.setCursor(0, 0); + lcd.print(" "); + lcd.show(0, 1, 6, basename(drum_config[activesample].name)); + lcd.print(" "); + } +#endif + lcd.setCursor(0, 1); + seq_printAllSeqSteps(); +#ifdef TESTDISPLAY20x4 + seq_printVelGraphBar(); +#endif + } + if (seq_menu == 3) { +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); + lcd.print(" "); + lcd.setCursor(19, 0); + lcd.print(" "); +#else + lcd.setCursor(12, 0); + lcd.print(" "); + lcd.setCursor(15, 0); + lcd.print(" "); +#endif + // lcd.setCursor(0, 1); + // lcd.print("_"); + // lcd.setCursor(1, 1); + // lcd.print(seq_find_shortname(1)[0]); + } + if (seq_menu > 2 && seq_menu < 19 && seq_active_function != 40) + { + if (seq_menu == 3) + lcd.setCursor(0, 1); + else + lcd.setCursor(seq_menu - 3, 1); + lcd.write(219); // cursor symbol + + if (seq_menu > 3) + { + lcd.setCursor(seq_menu - 4, 1); + + lcd.print(seq_find_shortname(seq_menu - 4)[0]); + } + if (seq_menu < 18) + { + lcd.setCursor(seq_menu - 2, 1); + lcd.print(seq_find_shortname(seq_menu - 2)[0]); + } + if (seq_vel[seq_active_track][seq_menu - 3] > 209 && activesample != NUM_DRUMSET_CONFIG - 1 ) //is pitched sample and selected item is not set to EMPTY + { + lcd.setCursor(0, 0); + lcd.print("[EDIT "); + seq_print_current_note(); + lcd.setCursor(8, 0); + lcd.print("?]"); + } + else + { + lcd.setCursor(0, 0); + lcd.print(" "); + lcd.show(0, 1, 6, basename(drum_config[activesample].name)); + lcd.print(" "); + } + } + else if (seq_active_function == 40 && activesample != NUM_DRUMSET_CONFIG - 1) + { //is in pitch edit function 40 + lcd.setCursor(1, 0); + lcd.show(0, 1, 4, basename(drum_config[activesample].name)); + lcd.setCursor(5, 0); + lcd.print("-"); + lcd.setCursor(6, 0); + seq_print_current_note(); + lcd.setCursor(9, 0); + lcd.print("]"); + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + seq_menu = 0; + seq_active_function = 99; + lcd_special_chars(SCROLLBAR); + } +} + +void UI_func_arpeggio(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.createChar(0, (uint8_t*)special_chars[19]); //play symbol + lcd.createChar(2, (uint8_t*)special_chars[21]); //stop symbol + seq_temp_select_menu = 0; + seq_temp_active_menu = 0; + lcd.setCursor( 0, 0); + lcd.print("Len"); + 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]); + lcd.setCursor( 0, 1); + lcd.print("Style"); + lcd.setCursor( 11, 1); + lcd.print("1/16"); + arp_refresh_display_play_status(); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (seq_temp_active_menu == 0) + { + if (LCDML.BT_checkDown()) + seq_temp_select_menu = constrain(seq_temp_select_menu + ENCODER[ENC_R].speed(), 0, 3); + else if (LCDML.BT_checkUp()) + seq_temp_select_menu = constrain(seq_temp_select_menu - ENCODER[ENC_R].speed(), 0, 3); + } + else if (seq_temp_active_menu == 1) // Octave setting + { + if (LCDML.BT_checkDown()) + arp_lenght = constrain(arp_lenght + ENCODER[ENC_R].speed(), 0, 9); + else if (LCDML.BT_checkUp()) + arp_lenght = constrain(arp_lenght - ENCODER[ENC_R].speed(), 0, 9); + } + else if (seq_temp_active_menu == 2) // Style setting + { + if (LCDML.BT_checkDown()) + arp_style = constrain(arp_style + ENCODER[ENC_R].speed(), 0, 3); + else if (LCDML.BT_checkUp()) + arp_style = constrain(arp_style - ENCODER[ENC_R].speed(), 0, 3); + } + else if (seq_temp_active_menu == 3) // Arp Speed setting + { + if (LCDML.BT_checkDown()) + arp_speed = constrain(arp_speed + ENCODER[ENC_R].speed(), 0, 1); + else if (LCDML.BT_checkUp()) + arp_speed = constrain(arp_speed - ENCODER[ENC_R].speed(), 0, 1); + } + + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if ( seq_temp_select_menu == 0 && seq_temp_active_menu == 0 ) + { + seq_temp_active_menu = 1; + } + else if ( seq_temp_select_menu == 0 && seq_temp_active_menu == 1 ) + { + seq_temp_active_menu = 0; + } + if ( seq_temp_select_menu == 1 && seq_temp_active_menu == 0 ) + { + seq_temp_active_menu = 2; + } + else if ( seq_temp_select_menu == 1 && seq_temp_active_menu == 2 ) + { + seq_temp_active_menu = 0; + } + + else if ( seq_temp_select_menu == 2 ) + { + + if (seq_running) { + seq_running = !seq_running; + timer1.stop(); + MicroDexed[0]->panic(); +#if NUM_DEXED > 1 + MicroDexed[1]->panic(); +#endif + arp_refresh_display_play_status(); + seq_step = 0; + arp_octave = 0; + arp_step = 0; + seq_chain_active_step = 0; + } else + { + seq_running = !seq_running; + arp_refresh_display_play_status(); + timer1.start(); + } + } + else if ( seq_temp_select_menu == 3 && seq_temp_active_menu == 0 ) + { + seq_temp_active_menu = 3; + } + else if ( seq_temp_select_menu == 3 && seq_temp_active_menu == 3 ) + { + seq_temp_active_menu = 0; + } + } + } + lcd.setCursor( 4, 0); + if (arp_lenght == 0) lcd.print("A"); else lcd.print(arp_lenght); //play all elements or from 1-xx elements + lcd.setCursor( 6, 1); + lcd.print( arp_style_names[arp_style][0] ); + lcd.print( arp_style_names[arp_style][1] ); + lcd.print( arp_style_names[arp_style][2] ); + lcd.setCursor( 11, 1); + if (arp_speed == 0)lcd.print("1/16"); else if (arp_speed == 1)lcd.print("1/8 "); + + if (seq_temp_select_menu == 0) { + lcd.setCursor( 3, 0); + lcd.print("["); + lcd.setCursor( 5, 0); + lcd.print("]"); + lcd.setCursor( 5, 1); + lcd.print(" "); + lcd.setCursor( 9, 1); + lcd.print(" "); + lcd.setCursor( 13, 1); + lcd.print(" "); + lcd.setCursor( 15, 1); + lcd.print(" "); + } + else if (seq_temp_select_menu == 1) + { + lcd.setCursor( 5, 1); + lcd.print("["); + lcd.setCursor( 9, 1); + lcd.print("]"); + lcd.setCursor( 3, 0); + lcd.print(" "); + lcd.setCursor( 5, 0); + lcd.print(" "); + lcd.setCursor( 13, 0); + lcd.print(" "); + lcd.setCursor( 15, 0); + lcd.print(" "); + } + else if (seq_temp_select_menu == 2) + { + lcd.setCursor( 5, 1); + lcd.print(" "); + lcd.setCursor( 9, 1); + lcd.print(" "); + lcd.setCursor( 13, 0); + lcd.print("["); + lcd.setCursor( 15, 0); + lcd.print("]"); + lcd.setCursor( 10, 1); + lcd.print(" "); + lcd.setCursor( 15, 1); + lcd.print(" "); + } + else if (seq_temp_select_menu == 3) + { + lcd.setCursor( 13, 0); + lcd.print(" "); + lcd.setCursor( 15, 0); + lcd.print(" "); + lcd.setCursor( 10, 1); + lcd.print("["); + lcd.setCursor( 15, 1); + lcd.print("]"); + lcd.setCursor( 3, 0); + lcd.print(" "); + lcd.setCursor( 5, 0); + lcd.print(" "); + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(SCROLLBAR); + } +} + +void UI_func_seq_pat_chain(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + // setup function + seq_temp_select_menu = 0; + seq_temp_active_menu = 99; + seq_menu = 0; + lcd.setCursor( 0, 0); + lcd.print("ChainStep:"); + lcd.setCursor( 13, 0); + lcd.print(seq_chain_active_chainstep + 1); + lcd.setCursor( 14, 0); + lcd.print("/"); + lcd.setCursor( 15, 0); + lcd.print(seq_chain_lenght + 1); + lcd.setCursor( 0, 1); + lcd.print("T"); + lcd.setCursor(10 , 1); + lcd.print("=P"); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (seq_temp_active_menu == 99) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_menu = constrain(seq_menu + 1, 0, 2); //menu select + else if (LCDML.BT_checkUp()) + seq_menu = constrain(seq_menu - 1, 0, 2); + } + } + else if (seq_temp_active_menu == 90) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_temp_select_menu = constrain(seq_temp_select_menu + 1, 0, NUM_SEQ_TRACKS - 1); + else if (LCDML.BT_checkUp()) + seq_temp_select_menu = constrain(seq_temp_select_menu - 1, 0, NUM_SEQ_TRACKS - 1); + } + } else if (seq_temp_active_menu == 20) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_chain_active_chainstep = constrain(seq_chain_active_chainstep + 1, 0, seq_chain_lenght); + else if (LCDML.BT_checkUp()) + seq_chain_active_chainstep = constrain(seq_chain_active_chainstep - 1, 0, seq_chain_lenght); + } + } + else if (seq_temp_active_menu == 18) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] = constrain(seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] + 1, 0, NUM_SEQ_PATTERN ); + } + else if (LCDML.BT_checkUp()) + { + seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] = constrain(seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] - 1, 0, NUM_SEQ_PATTERN ); + } + } + } + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if (seq_temp_active_menu == 99 && seq_menu == 0 ) + { + seq_temp_active_menu = 20; + } + else if (seq_temp_active_menu == 99 && seq_menu == 1 ) + { + seq_temp_active_menu = 90; + } + else if (seq_temp_active_menu == 99 && seq_menu == 2 ) + { + seq_temp_active_menu = 18; + } + else + seq_temp_active_menu = 99; + } + if (seq_menu == 0) // Chainselect modify + { + lcd.setCursor( 12, 1); + lcd.print(" "); + lcd.setCursor( 15, 1); + lcd.print(" "); + lcd.setCursor(1 , 1); + lcd.print(" "); + lcd.setCursor(3 , 1); + lcd.print(" "); + lcd.setCursor( 11, 0); + lcd.print("["); + lcd.setCursor( 13, 0); + lcd.print("]"); + } + else if (seq_menu == 1 ) { + lcd.setCursor( 12, 1); + lcd.print(" "); + lcd.setCursor( 15, 1); + lcd.print(" "); + lcd.setCursor( 11, 0); + lcd.print(" "); + lcd.setCursor( 13, 0); + lcd.print(" "); + lcd.setCursor(1 , 1); + lcd.print("["); + lcd.setCursor(3 , 1); + lcd.print("]"); + } + else if (seq_menu == 2 ) { + lcd.setCursor( 11, 0); + lcd.print(" "); + lcd.setCursor( 13, 0); + lcd.print(" "); + lcd.setCursor(1 , 1); + lcd.print(" "); + lcd.setCursor(3 , 1); + lcd.print(" "); + lcd.setCursor( 12, 1); + lcd.print("["); + lcd.setCursor( 15, 1); + lcd.print("]"); + } + lcd.setCursor( 12, 0); + lcd.print(seq_chain_active_chainstep + 1); + lcd.setCursor(2 , 1); + lcd.print( seq_temp_select_menu + 1); + lcd.setCursor(4 , 1); + if (seq_track_type[seq_temp_select_menu] == 0 ) lcd.print("(Drum)"); + else if (seq_track_type[seq_temp_select_menu] == 1 ) lcd.print("(Inst)"); + else if (seq_track_type[seq_temp_select_menu] == 2 ) lcd.print("(Chrd)"); else lcd.print("(Arp.)"); + lcd.setCursor( 13, 1); + if (seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] == NUM_SEQ_PATTERN)lcd.print("--"); //empty pattern + else + { + if (seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] < 10) + lcd.print("0"); + lcd.print(seq_patternchain[seq_chain_active_chainstep][seq_temp_select_menu] ); + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_track_setup(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + // setup function + seq_temp_active_menu = 99; + seq_temp_select_menu = 0; + lcd.setCursor(0 , 0); + lcd.print("Track Setup"); + lcd.setCursor(0 , 1); + lcd.print("Track "); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (seq_temp_active_menu == 99) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_temp_select_menu = constrain(seq_temp_select_menu + 1, 0, NUM_SEQ_TRACKS - 1); + else if (LCDML.BT_checkUp()) + seq_temp_select_menu = constrain(seq_temp_select_menu - 1, 0, NUM_SEQ_TRACKS - 1); + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_track_type[seq_temp_active_menu] = constrain(seq_track_type[seq_temp_active_menu] + 1, 0, 3); + else if (LCDML.BT_checkUp()) + seq_track_type[seq_temp_active_menu] = constrain(seq_track_type[seq_temp_active_menu] - 1, 0, 3); + } + } + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if (seq_temp_active_menu == 99) { + seq_temp_active_menu = seq_temp_select_menu; + } else + { + seq_temp_active_menu = 99; + } + } + if (seq_temp_active_menu == 99) + { + lcd.setCursor(8 , 1); + lcd.print(" "); + lcd.setCursor(15 , 1); + lcd.print(" "); + lcd.setCursor(5 , 1); + lcd.print("["); + lcd.setCursor(6 , 1); + lcd.print(seq_temp_select_menu + 1); + lcd.setCursor(7 , 1); + lcd.print("]"); + lcd.setCursor(9 , 1); + } else + { + lcd.setCursor(5 , 1); + lcd.print(" "); + lcd.setCursor(7 , 1); + lcd.print(" "); + lcd.setCursor(8 , 1); + lcd.print("["); + lcd.setCursor(15 , 1); + lcd.print("]"); + lcd.setCursor(9 , 1); + } + if (seq_track_type[seq_temp_select_menu] == 0 ) lcd.print("Drums "); else if (seq_track_type[seq_temp_select_menu] == 1 ) lcd.print("Instru"); + else if (seq_track_type[seq_temp_select_menu] == 2 )lcd.print("Chords"); else lcd.print("Arp "); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_dexed_assign(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + // setup function + seq_temp_active_menu = 99; + seq_temp_select_menu = 0; + lcd.setCursor(0 , 0); + lcd.print("dexed assign"); + lcd.setCursor(0 , 1); + lcd.print("Track "); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if (seq_temp_active_menu == 99) { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_temp_select_menu = constrain(seq_temp_select_menu + 1, 0, NUM_SEQ_TRACKS - 1); + else if (LCDML.BT_checkUp()) + seq_temp_select_menu = constrain(seq_temp_select_menu - 1, 0, NUM_SEQ_TRACKS - 1); + } + } else { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + seq_inst_dexed[seq_temp_active_menu] = constrain(seq_inst_dexed[seq_temp_active_menu] + 1, 0, 1); + else if (LCDML.BT_checkUp()) + seq_inst_dexed[seq_temp_active_menu] = constrain(seq_inst_dexed[seq_temp_active_menu] - 1, 0, 1); + } + } + if (LCDML.BT_checkEnter()) //handle button presses during menu >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + { + if (seq_temp_active_menu == 99) { + seq_temp_active_menu = seq_temp_select_menu; + } else + { + seq_temp_active_menu = 99; + } + } + if (seq_temp_active_menu == 99) + { + lcd.setCursor(8 , 1); + lcd.print(" "); + lcd.setCursor(15 , 1); + lcd.print(" "); + lcd.setCursor(5 , 1); + lcd.print("["); + lcd.setCursor(6 , 1); + lcd.print(seq_temp_select_menu + 1); + lcd.setCursor(7 , 1); + lcd.print("]"); + lcd.setCursor(9 , 1); + } else + { + lcd.setCursor(5 , 1); + lcd.print(" "); + lcd.setCursor(7 , 1); + lcd.print(" "); + lcd.setCursor(8 , 1); + lcd.print("["); + lcd.setCursor(15 , 1); + lcd.print("]"); + lcd.setCursor(9 , 1); + + } + if (seq_inst_dexed[seq_temp_select_menu] == 0 ) lcd.print("dexed0"); else if (seq_inst_dexed[seq_temp_select_menu] == 1 ) lcd.print("dexed1"); else lcd.print("??????"); + + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_state_load(uint8_t param) +{ + static uint8_t mode; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[10]; + if (seq_state_last_loadsave != 200)temp_int = seq_state_last_loadsave; else temp_int = param; + mode = 0; + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("Load Seq. state ")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", param); + lcd.print(tmp); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + temp_int = constrain(temp_int + ENCODER[ENC_L].speed(), 0, 99); + } + else if (LCDML.BT_checkUp()) + { + temp_int = constrain(temp_int - ENCODER[ENC_L].speed(), 0, 99); + } + else if (LCDML.BT_checkEnter()) + { + mode = 0xff; + lcd.setCursor(0, 1); + if (load_sd_seq_json(temp_int) == false) + lcd.print("Does not exist."); + else + { + load_sd_seq_json(temp_int); + seq_state_last_loadsave = temp_int; + lcd.print("Done. "); + } + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + } + lcd.setCursor(0, 1); + char tmp[10]; + sprintf(tmp, "[%2d]", temp_int); + lcd.print(tmp); + if (check_sd_seq_exists(temp_int)) + { + get_sd_seq_name_json(temp_int); + if ( seq_name_temp[0] != 0 ) + lcd.show(1, 5, 11, seq_name_temp); + else + lcd.print(" -- DATA --"); + } + else lcd.print(" "); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + else + encoderDir[ENC_R].reset(); + } +} + +void UI_func_seq_state_save(uint8_t param) +{ + static bool overwrite; + static bool yesno; + static uint8_t mode; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[FILENAME_LEN]; + yesno = false; + if (seq_state_last_loadsave != 200)temp_int = seq_state_last_loadsave; else temp_int = 0; + mode = 0; + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("Save Seq. state:")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", temp_int); + lcd.print(tmp); + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + if (check_sd_seq_exists(temp_int)) + { + get_sd_seq_name_json(temp_int); + if ( seq_name_temp[0] != 0 ) + lcd.show(1, 5, 11, seq_name_temp); + else + lcd.print(" -- DATA --"); + } + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (mode == 0) + temp_int = constrain(temp_int + ENCODER[ENC_L].speed(), 0, 99); + else + yesno = true; + } + else if (LCDML.BT_checkUp()) + { + if (mode == 0) + temp_int = constrain(temp_int - ENCODER[ENC_L].speed(), 0, 99); + else + yesno = false; + } + else if (LCDML.BT_checkEnter()) + { + if (mode == 0 && overwrite == true) + { + mode = 1; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [ ]")); + } + else + { + mode = 0xff; + if (overwrite == false || yesno == true) + { + if (yesno == true) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); + SD.remove(tmp); + } + save_sd_seq_json(temp_int); + lcd.show(1, 0, 16, "Done."); + seq_state_last_loadsave = temp_int; + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + else if (overwrite == true && yesno == false) + { + char tmp[10]; + + mode = 0; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d] ", temp_int); + lcd.print(tmp); + } + } + } + if (mode == 0) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%d-S.json", SEQ_CONFIG_PATH, temp_int); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", temp_int); + lcd.print(tmp); + lcd.setCursor(5, 1); + if (overwrite == false) { + lcd.print("-- empty --"); + } else if (check_sd_seq_exists(temp_int)) + { + get_sd_seq_name_json(temp_int); + if ( seq_name_temp[0] != 0 ) + lcd.show(1, 5, 11, seq_name_temp); else + lcd.print("-- DATA --"); + } + else lcd.print(" "); + } + else + { + lcd.setCursor(12, 1); + if (yesno == true) + lcd.print(F("YES")); + else + lcd.print(F("NO ")); + } + } + encoderDir[ENC_R].reset(); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + encoderDir[ENC_R].reset(); + } +} + +void UI_func_information(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char version_string[LCD_cols + 1]; + + encoderDir[ENC_R].reset(); + + generate_version_string(version_string, sizeof(version_string)); + + // setup function + lcd.setCursor(0, 0); + lcd.print(version_string); + lcd.setCursor(0, 1); + lcd.print(sd_string); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + ; + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_midi_soft_thru(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("MIDI Soft THRU")); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.sys.soft_midi_thru = constrain(configuration.sys.soft_midi_thru + 1, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); + else if (LCDML.BT_checkUp()) + configuration.sys.soft_midi_thru = constrain(configuration.sys.soft_midi_thru - 1, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); + } + + lcd.setCursor(0, 1); + switch (configuration.sys.soft_midi_thru) + { + case 0: + lcd.print(F("[OFF]")); + break; + case 1: + lcd.print(F("[ON ]")); + break; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys.soft_midi_thru), configuration.sys.soft_midi_thru); + } +} + +void UI_func_smart_filter(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Drm Smart Filter")); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + smartfilter = !smartfilter; + else if (LCDML.BT_checkUp()) + smartfilter = !smartfilter; + } + lcd.setCursor(0, 1); + if (smartfilter) lcd.print(F("[ON ]")); else lcd.print(F("[OFF]")); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_func_velocity_level(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Velocity Lvl", configuration.dexed[selected_instance_id].velocity_level, 1.0, VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX, 3, false, false, true); + + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + configuration.dexed[selected_instance_id].velocity_level = constrain(configuration.dexed[selected_instance_id].velocity_level + ENCODER[ENC_R].speed(), VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); + else if (LCDML.BT_checkUp()) + configuration.dexed[selected_instance_id].velocity_level = constrain(configuration.dexed[selected_instance_id].velocity_level - ENCODER[ENC_R].speed(), VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + + lcd_display_bar_int("Velocity Lvl", configuration.dexed[selected_instance_id].velocity_level, 1.0, VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX, 3, false, false, false); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + if (selected_instance_id == 0) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].velocity_level), configuration.dexed[0].velocity_level); +#if NUM_DEXED > 1 + else + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[1].velocity_level), configuration.dexed[1].velocity_level); +#endif + } +} + +void UI_func_eeprom_reset(uint8_t param) +{ + static bool yesno = false; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + // setup function + lcd.print("Reset EEPROM?"); + lcd.setCursor(0, 1); + lcd.print("[NO ]"); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + yesno = true; + else if (LCDML.BT_checkUp()) + yesno = false; + else if (LCDML.BT_checkEnter()) + { + if (yesno == true) + { + LCDML.DISP_clear(); + lcd.print("EEPROM Reset"); + + initial_values_from_eeprom(true); + lcd.setCursor(0, 1); + lcd.print("Done."); + delay(MESSAGE_WAIT_TIME); + _softRestart(); + } + else + { + lcd.setCursor(0, 1); + lcd.print("Canceled."); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + } + + if (yesno == true) + { + lcd.setCursor(1, 1); + lcd.print("YES"); + } + else + { + lcd.setCursor(1, 1); + lcd.print("NO "); + } + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd.setCursor(0, 1); + lcd.print("Canceled."); + delay(MESSAGE_WAIT_TIME); + + encoderDir[ENC_R].reset(); + } +} + +void UI_update_instance_icons() +{ +#ifdef TESTDISPLAY20x4 + lcd.setCursor(18, 0); + lcd.write(0); //Icon for first instance + lcd.setCursor(19, 0); + lcd.write(1); //Icon for second instance +#else + lcd.setCursor(14, 0); + lcd.write(0); //Icon for first instance + lcd.setCursor(15, 0); + lcd.write(1); //Icon for second instance +#endif +} + +void UI_func_voice_select(uint8_t param) +{ + static uint8_t menu_voice_select = MENU_VOICE_SOUND; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { +#ifdef TESTDISPLAY20x4 + lcd.setCursor(0, 3); + lcd.print("MENU"); + lcd.setCursor(17, 3); + lcd.print("+/-"); +#endif + encoderDir[ENC_R].reset(); + + lcd_active_instance_number(selected_instance_id); + + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; + + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + if (!get_voice_by_bank_name(configuration.performance.bank[selected_instance_id], bank_name, configuration.performance.voice[selected_instance_id], voice_name, sizeof(voice_name))) + strcpy(voice_name, "*ERROR*"); + + UI_update_instance_icons(); + + lcd.createChar(2, (uint8_t*)special_chars[18]); // favorites symbol + +#ifdef TEENSY3_6 + lcd.createChar(6, (uint8_t*)special_chars[16]); // MIDI activity note symbol + lcd.createChar(7, (uint8_t*)special_chars[16]); // MIDI activity note symbol +#endif + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; + + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && (encoderDir[ENC_R].ButtonShort() || encoderDir[ENC_R].ButtonLong()))) + { + uint8_t bank_tmp; + int8_t voice_tmp; + + // Reset Performance Modifiers to 0 after every preset change + for (uint8_t count_tmp = 0; count_tmp < NUM_DEXED; count_tmp++) + { + perform_attack_mod[count_tmp] = 0; + perform_release_mod[count_tmp] = 0; + } + active_perform_page = 1; + + if (LCDML.BT_checkUp()) + { + //start : show all presets + if (configuration.sys.favorites == 0) + { + switch (menu_voice_select) + { + case MENU_VOICE_BANK: + memset(g_bank_name[selected_instance_id], 0, BANK_NAME_LEN); + bank_tmp = constrain(configuration.performance.bank[selected_instance_id] - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + configuration.performance.bank[selected_instance_id] = bank_tmp; +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + break; + case MENU_VOICE_SOUND: + memset(g_voice_name[selected_instance_id], 0, VOICE_NAME_LEN); + voice_tmp = configuration.performance.voice[selected_instance_id] - ENCODER[ENC_R].speed(); + if (voice_tmp < 0 && configuration.performance.bank[selected_instance_id] - 1 >= 0) + { + configuration.performance.bank[selected_instance_id]--; + configuration.performance.bank[selected_instance_id] = constrain(configuration.performance.bank[selected_instance_id], 0, MAX_BANKS - 1); + } + else if (voice_tmp < 0 && configuration.performance.bank[selected_instance_id] - 1 <= 0) + { + voice_tmp = 0; + } + if (voice_tmp < 0) + voice_tmp = MAX_VOICES + voice_tmp; + configuration.performance.voice[selected_instance_id] = constrain(voice_tmp, 0, MAX_VOICES - 1); + +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + break; + } + } + else //only Favs + if (configuration.sys.favorites == 1) + { + locate_previous_favorite(); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + } + else //only non-Favs + if (configuration.sys.favorites == 2) + { + locate_previous_non_favorite(); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + //break; + + } else //random non-Favs + if (configuration.sys.favorites == 3) + { + locate_random_non_favorite(); + +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + } + } //end UP + else if (LCDML.BT_checkDown()) + { + //start : show all presets + if (configuration.sys.favorites == 0) + { + switch (menu_voice_select) + { + case MENU_VOICE_BANK: + memset(g_bank_name[selected_instance_id], 0, BANK_NAME_LEN); + bank_tmp = constrain(configuration.performance.bank[selected_instance_id] + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + configuration.performance.bank[selected_instance_id] = bank_tmp; +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + break; + case MENU_VOICE_SOUND: + memset(g_voice_name[selected_instance_id], 0, VOICE_NAME_LEN); + voice_tmp = configuration.performance.voice[selected_instance_id] + ENCODER[ENC_R].speed(); + if (voice_tmp >= MAX_VOICES && configuration.performance.bank[selected_instance_id] + 1 < MAX_BANKS) + { + voice_tmp %= MAX_VOICES; + configuration.performance.bank[selected_instance_id]++; + configuration.performance.bank[selected_instance_id] = constrain(configuration.performance.bank[selected_instance_id], 0, MAX_BANKS - 1); + } + else if (voice_tmp >= MAX_VOICES && configuration.performance.bank[selected_instance_id] + 1 >= MAX_BANKS) + { + voice_tmp = MAX_VOICES - 1; + } + configuration.performance.voice[selected_instance_id] = constrain(voice_tmp, 0, MAX_VOICES - 1); + +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + break; + } + } + else //only Favs + if (configuration.sys.favorites == 1) + { + + locate_next_favorite(); + +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + //break; + } + else //only non-Favs + if (configuration.sys.favorites == 2) + { + locate_next_non_favorite(); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + //break; + } else //random non-Favs + if (configuration.sys.favorites == 3) + { + locate_random_non_favorite(); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif + load_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif + } + + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonPressed()) + { + if (menu_voice_select == MENU_VOICE_BANK) + menu_voice_select = MENU_VOICE_SOUND; + else + menu_voice_select = MENU_VOICE_BANK; + } +#if NUM_DEXED > 1 + else if (LCDML.BT_checkEnter()) + { + selected_instance_id = !selected_instance_id; + lcd_active_instance_number(selected_instance_id); + UI_update_instance_icons(); + } +#endif + } + + if (strlen(g_bank_name[selected_instance_id]) > 0) + { + strcpy(bank_name, g_bank_name[selected_instance_id]); + } + else + { + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + } + + if (strlen(g_voice_name[selected_instance_id]) > 0) + { + strcpy(voice_name, g_voice_name[selected_instance_id]); + } + else + { + if (!get_voice_by_bank_name(configuration.performance.bank[selected_instance_id], bank_name, configuration.performance.voice[selected_instance_id], voice_name, sizeof(voice_name))) + strcpy(voice_name, "*ERROR*"); + } + + lcd.show(0, 0, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 0, 2, configuration.performance.voice[selected_instance_id] + 1); +#ifdef TESTDISPLAY20x4 + string_toupper(bank_name); + lcd.show(0, 4, 8, bank_name); + string_toupper(voice_name); + lcd.show(1, 4, 10, voice_name); + switch (menu_voice_select) + { + case MENU_VOICE_BANK: + lcd.show(0, 3, 1, "["); + lcd.show(0, 12, 1, "]"); + lcd.show(1, 3, 1, " "); + lcd.show(1, 14, 1, " "); + break; + case MENU_VOICE_SOUND: + lcd.show(0, 3, 1, " "); + lcd.show(0, 12, 1, " "); + lcd.show(1, 3, 1, "["); + lcd.show(1, 14, 1, "]"); + break; + } +#else + string_toupper(bank_name); + lcd.show(0, 3, 8, bank_name); + lcd.show(0, 12, 1, " "); //forced because this char does not clear after fav-search (because the bank name is one char to short to do it). + string_toupper(voice_name); + lcd.show(1, 3, 10, voice_name); + + switch (menu_voice_select) + { + case MENU_VOICE_BANK: + lcd.show(0, 2, 1, "["); + lcd.show(0, 11, 1, "]"); + lcd.show(1, 2, 1, " "); + lcd.show(1, 13, 1, " "); + break; + case MENU_VOICE_SOUND: + lcd.show(0, 2, 1, " "); + lcd.show(0, 11, 1, " "); + lcd.show(1, 2, 1, "["); + lcd.show(1, 13, 1, "]"); + break; + } +#endif + draw_favorite_icon(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + encoderDir[ENC_R].reset(); + if (selected_instance_id == 0) + { + //eeprom_update_var(offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[0], "configuration.performance.voice[0]"); + //eeprom_update_var(offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[0], "configuration.performance.bank[0]"); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[0]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[0]); + } +#if NUM_DEXED > 1 + else + { + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[1]), configuration.performance.voice[1]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[1]), configuration.performance.bank[1]); + } +#endif + } +} + +void UI_func_volume(uint8_t param) +{ + + char tmp[6]; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + + encoderDir[ENC_L].reset(); + + if (active_perform_page == 1) + { //Master Volume + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Master Vol.", configuration.sys.vol, 1.0, VOLUME_MIN, VOLUME_MAX, 3, false, false, true); + back_from_volume = 0; + } + + else if (active_perform_page == 2) + { // Live Performance Mod - Attack + lcd.setCursor(0, 0); + lcd.print("Live Modify"); + lcd.setCursor(0, 1); + lcd.print("Attack = "); + lcd.setCursor(13, 1); + sprintf(tmp, "%03d", perform_attack_mod[selected_instance_id]); + lcd.print(tmp); + back_from_volume = 0; + } + + else if (active_perform_page == 3) + { // Live Performance Mod - Release + lcd.setCursor(0, 0); + lcd.print("Live Modify"); + lcd.setCursor(11, 1); + lcd.print("Release = "); + lcd.setCursor(13, 1); + sprintf(tmp, "%03d", perform_release_mod[selected_instance_id]); + lcd.print(tmp); + back_from_volume = 0; + } + + lcd.setCursor(12, 0); + lcd.print("P"); + lcd.setCursor(13, 0); + lcd.print(active_perform_page); + lcd.setCursor(14, 0); + lcd.print("/3"); + + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + + if ( LCDML.BT_checkDown() && encoderDir[ENC_R].Down() ) + { + back_from_volume = 0; + active_perform_page++; + if (active_perform_page > 3)active_perform_page = 1; + } + else if ( LCDML.BT_checkUp() && encoderDir[ENC_R].Up() ) + { + back_from_volume = 0; + active_perform_page--; + if (active_perform_page < 1)active_perform_page = 3; + } + + if ((LCDML.BT_checkDown() && encoderDir[ENC_L].Down() ) || (LCDML.BT_checkUp() && encoderDir[ENC_L].Up() )) + { + if (active_perform_page == 1) { + back_from_volume = 0; + + if (LCDML.BT_checkDown() ) + { + configuration.sys.vol = constrain(configuration.sys.vol + ENCODER[ENC_L].speed(), VOLUME_MIN, VOLUME_MAX); + } + else if (LCDML.BT_checkUp() ) + { + configuration.sys.vol = constrain(configuration.sys.vol - ENCODER[ENC_L].speed(), VOLUME_MIN, VOLUME_MAX); + } + } + + else if ( active_perform_page == 2) + { //Attack + + if (LCDML.BT_checkDown() ) + { + if (perform_attack_mod[selected_instance_id] == 0) + for (uint8_t i = 0; i < 6; i++) { + orig_attack_values[selected_instance_id][i] = MicroDexed[selected_instance_id]->getOPRate(i, ATTACK); + } + perform_attack_mod[selected_instance_id] = constrain(perform_attack_mod[selected_instance_id] + ENCODER[ENC_L].speed(), -MAX_PERF_MOD, MAX_PERF_MOD); + for (uint8_t i = 0; i < 6; i++) + MicroDexed[selected_instance_id]->setOPRate(i, ATTACK, orig_attack_values[selected_instance_id][i] - perform_attack_mod[selected_instance_id] ); + } + else if (LCDML.BT_checkUp() ) + { + if (perform_attack_mod[selected_instance_id] == 0) // Save initial Values + for (uint8_t i = 0; i < 6; i++) { + orig_attack_values[selected_instance_id][i] = MicroDexed[selected_instance_id]->getOPRate(i, ATTACK); + } + + perform_attack_mod[selected_instance_id] = constrain(perform_attack_mod[selected_instance_id] - ENCODER[ENC_L].speed(), -MAX_PERF_MOD, MAX_PERF_MOD); + for (uint8_t i = 0; i < 6; i++) + MicroDexed[selected_instance_id]->setOPRate(i, ATTACK, orig_attack_values[selected_instance_id][i] - perform_attack_mod[selected_instance_id] ); + } + + } + else if (active_perform_page == 3) + { //Release + + if (LCDML.BT_checkDown() ) + { + if (perform_release_mod[selected_instance_id] == 0) // Save initial Values + for (uint8_t i = 0; i < 6; i++) { + orig_release_values[selected_instance_id][i] = MicroDexed[selected_instance_id]->getOPRate(i, RELEASE); + } + perform_release_mod[selected_instance_id] = constrain(perform_release_mod[selected_instance_id] + ENCODER[ENC_L].speed(), -MAX_PERF_MOD, MAX_PERF_MOD); + for (uint8_t i = 0; i < 6; i++) + MicroDexed[selected_instance_id]->setOPRate(i, RELEASE, orig_release_values[selected_instance_id][i] - perform_release_mod[selected_instance_id] ); + } + else if (LCDML.BT_checkUp() ) + { + if (perform_release_mod[selected_instance_id] == 0) + for (uint8_t i = 0; i < 6; i++) { + orig_release_values[selected_instance_id][i] = MicroDexed[selected_instance_id]->getOPRate(i, RELEASE); + } + perform_release_mod[selected_instance_id] = constrain(perform_release_mod[selected_instance_id] - ENCODER[ENC_L].speed(), -MAX_PERF_MOD, MAX_PERF_MOD); + for (uint8_t i = 0; i < 6; i++) + MicroDexed[selected_instance_id]->setOPRate(i, RELEASE, orig_release_values[selected_instance_id][i] - perform_release_mod[selected_instance_id] ); + } + } + } + + lcd.setCursor(13, 0); + lcd.print(active_perform_page); + + if (active_perform_page == 1) { //Master Volume + lcd.setCursor(0, 0); + lcd.print("Master Vol. "); + lcd_special_chars(BLOCKBAR); + lcd_display_bar_int("Master Vol.", configuration.sys.vol, 1.0, VOLUME_MIN, VOLUME_MAX, 3, false, false, false); + set_volume(configuration.sys.vol, configuration.sys.mono); + } + else if (active_perform_page == 2) { //Attack + lcd.setCursor(0, 0); + lcd.print("Live Modify"); + lcd.setCursor(0, 1); + lcd.print("Attack = "); + lcd.setCursor(13, 1); + sprintf(tmp, "%03d", perform_attack_mod[selected_instance_id]); + lcd.print(tmp); + back_from_volume = 0; + } + else if (active_perform_page == 3) { //Release + lcd.setCursor(0, 0); + lcd.print("Live Modify"); + lcd.setCursor(0, 1); + lcd.print("Release = "); + lcd.setCursor(13, 1); + sprintf(tmp, "%03d", perform_release_mod[selected_instance_id]); + lcd.print(tmp); + back_from_volume = 0; + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys.vol), configuration.sys.vol); + encoderDir[ENC_L].reset(); + } + +} + +void UI_func_load_performance(uint8_t param) +{ + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[10]; + + mode = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Load Perf. SD")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.sys.performance_number); + lcd.print(tmp); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.sys.performance_number = constrain(configuration.sys.performance_number + ENCODER[ENC_L].speed(), PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.sys.performance_number = constrain(configuration.sys.performance_number - ENCODER[ENC_L].speed(), PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); + } + else if (LCDML.BT_checkEnter()) + { + mode = 0xff; + + lcd.setCursor(0, 1); + if (load_sd_performance_json(configuration.sys.performance_number) == false) + lcd.print("Does not exist."); + else + { + load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[0], 0, 0); + set_voiceconfig_params(0); +#if NUM_DEXED > 1 + load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[1], 1, 0); + set_voiceconfig_params(1); +#endif + load_sd_fx_json(configuration.performance.fx_number, 0); + set_fx_params(); + + lcd.print("Done. "); + } + delay(MESSAGE_WAIT_TIME); + + LCDML.FUNC_goBackToMenu(); + } + + lcd.setCursor(0, 1); + char tmp[10]; + sprintf(tmp, "[%2d]", configuration.sys.performance_number); + lcd.print(tmp); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + else + eeprom_update_performance(); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_save_performance(uint8_t param) +{ + static bool overwrite; + static bool yesno; + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[FILENAME_LEN]; + + yesno = false; + mode = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Save Perf. SD")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.sys.performance_number); + lcd.print(tmp); + + sprintf(tmp, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, configuration.sys.performance_number); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (mode == 0) + configuration.sys.performance_number = constrain(configuration.sys.performance_number + ENCODER[ENC_L].speed(), PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); + else + yesno = true; + } + else if (LCDML.BT_checkUp()) + { + if (mode == 0) + configuration.sys.performance_number = constrain(configuration.sys.performance_number - ENCODER[ENC_L].speed(), PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX); + else + yesno = false; + } + else if (LCDML.BT_checkEnter()) + { + if (mode == 0 && overwrite == true) + { + mode = 1; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [ ]")); + } + else + { + mode = 0xff; + if (overwrite == false || yesno == true) + { + if (yesno == true) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, configuration.sys.performance_number); + SD.remove(tmp); + } + save_sd_performance_json(configuration.sys.performance_number); + lcd.show(1, 0, 16, "Done."); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + else if (overwrite == true && yesno == false) + { + char tmp[17]; + + mode = 0; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d] ", configuration.sys.performance_number); + lcd.print(tmp); + } + } + } + + if (mode == 0) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%s%d.json", PERFORMANCE_CONFIG_PATH, PERFORMANCE_CONFIG_NAME, configuration.sys.performance_number); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.sys.performance_number); + lcd.print(tmp); + } + else + { + lcd.setCursor(12, 1); + if (yesno == true) + lcd.print(F("YES")); + else + lcd.print(F("NO ")); + } + } + encoderDir[ENC_R].reset(); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, sys.performance_number), configuration.sys.performance_number); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_load_voiceconfig(uint8_t param) +{ +#if NUM_DEXED > 1 + static int8_t selected_instance_id; +#else + char tmp[4]; + uint8_t selected_instance_id = 0; +#endif + + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + + selected_instance_id = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Load VoiceCfg SD")); +#if NUM_DEXED > 1 + mode = 0; + lcd.setCursor(0, 1); + lcd.print(F("Instance [0]")); +#else + mode = 1; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(tmp); +#endif + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (mode == 0) + selected_instance_id = 1; + //selected_instance_id = (selected_instance_id + 1) % 2; + else if (mode == 1) + configuration.performance.voiceconfig_number[selected_instance_id] = constrain(configuration.performance.voiceconfig_number[selected_instance_id] + ENCODER[ENC_L].speed(), VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); + } + else if (LCDML.BT_checkUp()) + { + if (mode == 0) + //selected_instance_id = (selected_instance_id - 1) % 2; + selected_instance_id = 0; + else if (mode == 1) + configuration.performance.voiceconfig_number[selected_instance_id] = constrain(configuration.performance.voiceconfig_number[selected_instance_id] - ENCODER[ENC_L].speed(), VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); + } + else if (LCDML.BT_checkEnter()) + { + if (mode > 0) { + mode = 0xff; + lcd.setCursor(0, 1); + if (load_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id, 0) == false) + lcd.print("Does not exist. "); + else + lcd.print("Done. "); + + delay(MESSAGE_WAIT_TIME); + + LCDML.FUNC_goBackToMenu(); + } else mode = 1; + } + + if (mode == 0) + { + lcd.setCursor(10, 1); + lcd.print(selected_instance_id); + } + else if (mode == 1) + { + lcd.setCursor(0, 1); + char tmp[10]; + sprintf(tmp, "[%2d]", configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(tmp); + } + } + encoderDir[ENC_R].reset(); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + else + eeprom_update_dexed(selected_instance_id); + +#if NUM_DEXED > 1 + if (selected_instance_id > 0) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voiceconfig_number[1]), configuration.performance.voiceconfig_number[1]); + else +#endif + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voiceconfig_number[0]), configuration.performance.voiceconfig_number[0]); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_save_voiceconfig(uint8_t param) +{ +#if NUM_DEXED > 1 + static int8_t selected_instance_id; +#else + char tmp[5]; + uint8_t selected_instance_id = 0; +#endif + + static bool overwrite; + static bool yesno; + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + yesno = false; + selected_instance_id = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Save VoiceCfg SD")); +#if NUM_DEXED > 1 + mode = 0; + lcd.setCursor(0, 1); + lcd.print(F("Instance [0]")); +#else + mode = 1; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(tmp); + + sprintf(tmp, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[selected_instance_id]); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; +#endif + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (mode == 0) + selected_instance_id = 1; + // selected_instance_id = (selected_instance_id +1) % 2; + else if (mode == 1) + configuration.performance.voiceconfig_number[selected_instance_id] = constrain(configuration.performance.voiceconfig_number[selected_instance_id] + ENCODER[ENC_L].speed(), VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); + else + yesno = true; + } + else if (LCDML.BT_checkUp()) + { + if (mode == 0) + selected_instance_id = 0; + //selected_instance_id = (selected_instance_id - 1) % 2; + else if (mode == 1) + configuration.performance.voiceconfig_number[selected_instance_id] = constrain(configuration.performance.voiceconfig_number[selected_instance_id] - ENCODER[ENC_L].speed(), VOICECONFIG_NUM_MIN, VOICECONFIG_NUM_MAX); + else + yesno = false; + } + else if (LCDML.BT_checkEnter()) + { + if (mode == 1 && overwrite == true) + { + mode = 2; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [ ]")); + } + else if (mode > 0 ) + { + mode = 0xff; + if (overwrite == false || yesno == true) + { + if (yesno == true) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[selected_instance_id]); + SD.remove(tmp); + } + save_sd_voiceconfig_json(configuration.performance.voiceconfig_number[selected_instance_id], selected_instance_id, 0); + lcd.show(1, 0, 16, "Done."); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + else if (overwrite == true && yesno == false) + { + char tmp[17]; + + mode = 1; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d] ", configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(tmp); + } + } + else { + mode = 1; + lcd.setCursor(4, 1); + lcd.print(" "); + } + } + + if (mode == 0) + { + lcd.setCursor(10, 1); + //lcd.print(configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(selected_instance_id); + } + else if (mode == 1) + { + char tmp[FILENAME_LEN]; + + sprintf(tmp, "/%s/%s%d.json", VOICE_CONFIG_PATH, VOICE_CONFIG_NAME, configuration.performance.voiceconfig_number[selected_instance_id]); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.voiceconfig_number[selected_instance_id]); + lcd.print(tmp); + } + else if (mode == 2) + { + lcd.setCursor(12, 1); + if (yesno == true) + lcd.print(F("YES")); + else + lcd.print(F("NO ")); + } + } + encoderDir[ENC_R].reset(); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + +#if NUM_DEXED > 1 + if (selected_instance_id > 0) + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voiceconfig_number[1]), configuration.performance.voiceconfig_number[1]); + else +#endif + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voiceconfig_number[0]), configuration.performance.voiceconfig_number[0]); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_load_fx(uint8_t param) +{ + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[10]; + + mode = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Load FX SD")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.fx_number); + lcd.print(tmp); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + configuration.performance.fx_number = constrain(configuration.performance.fx_number + ENCODER[ENC_L].speed(), FX_NUM_MIN, FX_NUM_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.performance.fx_number = constrain(configuration.performance.fx_number - ENCODER[ENC_L].speed(), FX_NUM_MIN, FX_NUM_MAX); + } + else if (LCDML.BT_checkEnter()) + { + mode = 0xff; + + lcd.setCursor(0, 1); + if (load_sd_fx_json(configuration.performance.fx_number, 0) == false) + lcd.print("Does not exist. "); + else + lcd.print("Done. "); + + delay(MESSAGE_WAIT_TIME); + + LCDML.FUNC_goBackToMenu(); + } + + lcd.setCursor(0, 1); + char tmp[10]; + sprintf(tmp, "[%2d]", configuration.performance.fx_number); + lcd.print(tmp); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + else + eeprom_update_fx(); + + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.fx_number), configuration.performance.fx_number); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_save_fx(uint8_t param) +{ + static bool overwrite; + static bool yesno; + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + char tmp[FILENAME_LEN]; + + yesno = false; + mode = 0; + + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Save FX")); + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.fx_number); + lcd.print(tmp); + + sprintf(tmp, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, configuration.performance.fx_number); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) + { + if (LCDML.BT_checkDown()) + { + if (mode == 0) + configuration.performance.fx_number = constrain(configuration.performance.fx_number + ENCODER[ENC_L].speed(), FX_NUM_MIN, FX_NUM_MAX); + else + yesno = true; + } + else if (LCDML.BT_checkUp()) + { + if (mode == 0) + configuration.performance.fx_number = constrain(configuration.performance.fx_number - ENCODER[ENC_L].speed(), FX_NUM_MIN, FX_NUM_MAX); + else + yesno = false; + } + else if (LCDML.BT_checkEnter()) + { + if (mode == 0 && overwrite == true) + { + mode = 1; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [ ]")); + } + else + { + mode = 0xff; + if (overwrite == false || yesno == true) + { + if (yesno == true) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, configuration.performance.fx_number); + SD.remove(tmp); + } + save_sd_fx_json(configuration.performance.fx_number, 0); + + lcd.show(1, 0, 16, "Done."); + LCDML.FUNC_goBackToMenu(); + delay(MESSAGE_WAIT_TIME); + } + else if (overwrite == true && yesno == false) + { + char tmp[17]; + + mode = 0; + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d] ", configuration.performance.fx_number); + lcd.print(tmp); + } + } + } + + if (mode == 0) + { + char tmp[FILENAME_LEN]; + sprintf(tmp, "/%s/%s%d.json", FX_CONFIG_PATH, FX_CONFIG_NAME, configuration.performance.fx_number); + if (SD.exists(tmp)) + overwrite = true; + else + overwrite = false; + + lcd.setCursor(0, 1); + sprintf(tmp, "[%2d]", configuration.performance.fx_number); + lcd.print(tmp); + } + else + { + lcd.setCursor(12, 1); + if (yesno == true) + lcd.print(F("YES")); + else + lcd.print(F("NO ")); + } + } + encoderDir[ENC_R].reset(); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.fx_number), configuration.performance.fx_number); + + encoderDir[ENC_R].reset(); + } +} + +void UI_func_save_voice(uint8_t param) +{ + static bool yesno; + static uint8_t mode; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + yesno = false; +#if NUM_DEXED == 1 + mode = 1; +#else + mode = 0; +#endif + +#if NUM_DEXED == 1 + char bank_name[BANK_NAME_LEN]; + + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + + lcd.setCursor(0, 0); + lcd.print(F("Save to Bank")); + lcd.show(1, 0, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 3, 10, bank_name); + lcd.show(1, 2, 1, "["); + lcd.show(1, 13, 1, "]"); +#else + lcd.setCursor(0, 0); + lcd.print(F("Save Instance")); + lcd_active_instance_number(selected_instance_id); + lcd.setCursor(5, 1); + lcd.write(0); + lcd.setCursor(10, 1); + lcd.write(1); +#endif + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; + + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + switch (mode) + { + case 0: // Instance selection + if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) + selected_instance_id = !selected_instance_id; + + lcd_active_instance_number(selected_instance_id); + lcd.setCursor(5, 1); + lcd.write(0); + lcd.setCursor(10, 1); + lcd.write(1); + break; + case 1: // Bank selection + if (LCDML.BT_checkDown()) + configuration.performance.bank[selected_instance_id] = constrain(configuration.performance.bank[selected_instance_id] + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + else if (LCDML.BT_checkUp() && configuration.performance.bank[selected_instance_id] > 0) + configuration.performance.bank[selected_instance_id] = constrain(configuration.performance.bank[selected_instance_id] - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + + lcd.show(1, 0, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 3, 10, bank_name); + break; + case 2: // Voice selection + if (LCDML.BT_checkDown() && configuration.performance.voice[selected_instance_id] < MAX_VOICES - 1) + configuration.performance.voice[selected_instance_id] = constrain(configuration.performance.voice[selected_instance_id] + ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + else if (LCDML.BT_checkUp() && configuration.performance.voice[selected_instance_id] > 0) + configuration.performance.voice[selected_instance_id] = constrain(configuration.performance.voice[selected_instance_id] - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(configuration.performance.bank[selected_instance_id], bank_name, configuration.performance.voice[selected_instance_id], voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, configuration.performance.voice[selected_instance_id] + 1); + lcd.show(1, 3, 10, voice_name); + break; + case 3: // Yes/No selection + yesno = !yesno; + if (yesno == true) + { + lcd.show(1, 1, 3, "YES"); + } + else + { + lcd.show(1, 1, 3, "NO"); + } + break; + } + } + else if (LCDML.BT_checkEnter()) + { + if (encoderDir[ENC_R].ButtonShort()) + mode++; + switch (mode) + { + case 1: + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + lcd.setCursor(0, 0); + lcd.print(F("Save to Bank")); + lcd.show(1, 0, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 3, 10, bank_name); + lcd.show(1, 2, 2, " ["); + lcd.show(1, 14, 1, "]"); + break; + case 2: + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(configuration.performance.bank[selected_instance_id], bank_name, configuration.performance.voice[selected_instance_id], voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(0, 0, 16, "Save to Bank"); + lcd.show(0, 13, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 0, 2, configuration.performance.voice[selected_instance_id] + 1); + lcd.show(1, 3, 10, voice_name); + break; + case 3: + lcd.show(0, 0, 16, "Overwrite?"); + lcd.show(1, 0, 15, "[NO"); + lcd.show(1, 4, 1, "]"); + break; + default: + if (yesno == true) + { +#ifdef DEBUG + bool ret = save_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); + + if (ret == true) + Serial.println(F("Saving voice OK.")); + else + Serial.println(F("Error while saving voice.")); +#else + save_sd_voice(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); +#endif + + lcd.show(1, 0, 16, "Done."); + delay(MESSAGE_WAIT_TIME); + + mode = 0xff; + break; + } + + LCDML.FUNC_goBackToMenu(); + } + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + else + { + if (selected_instance_id == 0) + { + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[0]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[0]); + } +#if NUM_DEXED > 1 + else + { + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.voice[0]), configuration.performance.voice[1]); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, performance.bank[0]), configuration.performance.bank[1]); + } +#endif + } + encoderDir[ENC_R].reset(); + } +} + +void UI_func_sysex_receive_bank(uint8_t param) +{ + static bool yesno; + static uint8_t mode; + static uint8_t bank_number; + static uint8_t ui_select_name_state; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + yesno = false; + mode = 0; + bank_number = configuration.performance.bank[selected_instance_id]; + memset(receive_bank_filename, 0, sizeof(receive_bank_filename)); + + lcd.setCursor(0, 0); + lcd.print(F("MIDI Recv Bank")); + lcd.setCursor(2, 1); + lcd.print(F("[")); + lcd.setCursor(14, 1); + lcd.print(F("]")); + if (!get_bank_name(configuration.performance.bank[selected_instance_id], receive_bank_filename, sizeof(receive_bank_filename))) + strcpy(receive_bank_filename, "*ERROR*"); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, receive_bank_filename); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + switch (mode) + { + case 0: + bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename))) + strcpy(receive_bank_filename, "*ERROR*"); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, receive_bank_filename); + break; + case 1: + yesno = !yesno; + if (yesno) + lcd.show(1, 12, 3, "YES"); + else + lcd.show(1, 12, 3, "NO"); + break; + case 2: + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + break; + } + } + else if (LCDML.BT_checkUp()) + { + switch (mode) + { + case 0: + bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename))) + strcpy(receive_bank_filename, "*ERROR*"); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, receive_bank_filename); + break; + case 1: + yesno = !yesno; + if (yesno) + lcd.show(1, 12, 3, "YES"); + else + lcd.show(1, 12, 3, "NO"); + break; + case 2: + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + break; + } + } + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + if (mode == 0) + { + if (!strcmp(receive_bank_filename, "*ERROR*")) + { + yesno = true; + strcpy(receive_bank_filename, "NONAME"); + mode = 2; + lcd.setCursor(0, 1); + lcd.print(F("[ ] ")); + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, true); + lcd.blink(); + } + else + { + mode = 1; + lcd.setCursor(0, 1); + lcd.print(F("Overwrite: [NO ]")); + } + } + else if (mode == 1 && yesno == true) + { + mode = 2; + lcd.setCursor(0, 1); + lcd.print(F("[ ] ")); + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, true); + lcd.blink(); + } + else if (mode == 2) + { + ui_select_name_state = UI_select_name(1, 1, receive_bank_filename, BANK_NAME_LEN - 1, false); + if (ui_select_name_state == true) + { + if (yesno == true) + { +#ifdef DEBUG + Serial.print(F("Bank name: [")); + Serial.print(receive_bank_filename); + Serial.println(F("]")); +#endif + char tmp[FILENAME_LEN]; + strcpy(tmp, receive_bank_filename); + sprintf(receive_bank_filename, "/%d/%s.syx", bank_number, tmp); +#ifdef DEBUG + Serial.print(F("Receiving into bank ")); + Serial.print(bank_number); + Serial.print(F(" as filename ")); + Serial.print(receive_bank_filename); + Serial.println(F(".")); +#endif + mode = 0xff; + lcd.noBlink(); + lcd.setCursor(0, 1); + lcd.print(F("Waiting... ")); + /// Storing is done in SYSEX code + } + } + } + else if (mode >= 1 && yesno == false) + { + Serial.println(mode, DEC); + memset(receive_bank_filename, 0, sizeof(receive_bank_filename)); + mode = 0xff; + lcd.noBlink(); + lcd.setCursor(0, 1); + lcd.print(F("Canceled. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + } + encoderDir[ENC_R].reset(); + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + + memset(receive_bank_filename, 0, sizeof(receive_bank_filename)); + lcd.noBlink(); + + if (mode < 0xff) + { + lcd.setCursor(0, 1); + lcd.print(F("Canceled. ")); + delay(MESSAGE_WAIT_TIME); + } + } +} + +void UI_func_set_sequence_name(uint8_t param) +{ + static uint8_t mode; + static uint8_t ui_select_name_state; + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + mode = 0; + lcd.setCursor(0, 0); + lcd.print(F("Sequence Name")); + } + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) { + if (mode == 1) ui_select_name_state = UI_select_name(1, 1, seq_name_temp, BANK_NAME_LEN - 1, false); + } + else if (LCDML.BT_checkUp()) { + if (mode == 1) ui_select_name_state = UI_select_name(1, 1, seq_name_temp, BANK_NAME_LEN - 1, false); + // if (ui_select_name_state == false) { + // lcd.setCursor(12, 1); + // lcd.print(" "); + // lcd.setCursor(0, 1); + // lcd.print("["); + // lcd.setCursor(11, 1); + // lcd.print("]"); + // lcd.blink(); + // ui_select_name_state = UI_select_name(1, 1, seq_name_temp, BANK_NAME_LEN - 1, true); + // } + } + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + + if (mode == 1) + { + ui_select_name_state = UI_select_name(1, 1, seq_name_temp, BANK_NAME_LEN - 1, false); + if (ui_select_name_state == true) + { + strcpy( seq_name, seq_name_temp); + mode = 0xff; + lcd.noBlink(); + lcd.setCursor(0, 1); + lcd.print(F("OK. ")); + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + } + } + if (mode == 0 ) + { + mode = 1; + strcpy(seq_name_temp, seq_name); + lcd.setCursor(0, 1); + lcd.print(F("[ ] ")); + ui_select_name_state = UI_select_name(1, 1, seq_name_temp, BANK_NAME_LEN - 1, true); + lcd.blink(); + } + } + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + lcd.noBlink(); + } +} + +void UI_func_sysex_send_bank(uint8_t param) +{ + char bank_name[BANK_NAME_LEN]; + static uint8_t bank_number; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + bank_number = configuration.performance.bank[selected_instance_id]; + lcd.setCursor(0, 0); + lcd.print(F("MIDI Send Bank")); + if (!get_bank_name(configuration.performance.bank[selected_instance_id], bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + lcd.show(1, 2, 1, "["); + lcd.show(1, 14, 1, "]"); + lcd.show(1, 0, 2, configuration.performance.bank[selected_instance_id]); + lcd.show(1, 3, 10, bank_name); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + + } + else if (LCDML.BT_checkUp()) + { + bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + } + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, bank_name); + } + else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) + { + File sysex; + char filename[FILENAME_LEN]; + + if (get_bank_name(bank_number, bank_name, sizeof(bank_name))) + { + sprintf(filename, "/%d/%s.syx", bank_number, bank_name); +#ifdef DEBUG + Serial.print(F("Send bank ")); + Serial.print(filename); + Serial.println(F(" from SD.")); +#endif + sysex = SD.open(filename); + if (!sysex) + { +#ifdef DEBUG + Serial.println(F("Connot read from SD.")); +#endif + lcd.show(1, 0, 16, "Read error."); + bank_number = 0xff; + } + else + { + uint8_t bank_data[4104]; + + sysex.read(bank_data, 4104); + sysex.close(); + + lcd.show(1, 0, 16, "Sending Ch"); + if (configuration.dexed[selected_instance_id].midi_channel == MIDI_CHANNEL_OMNI) + { + lcd.show(1, 11, 2, "01"); + send_sysex_bank(1, bank_data); + } + else + { + lcd.show(1, 11, 2, configuration.dexed[selected_instance_id].midi_channel + 1); + send_sysex_bank(configuration.dexed[selected_instance_id].midi_channel, bank_data); + } + lcd.show(1, 0, 16, "Done."); + bank_number = 0xff; + } + } + else + { + lcd.show(1, 0, 16, "No bank."); + bank_number = 0xff; + } + + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + + if (bank_number < 0xff) + { + lcd.setCursor(0, 1); + lcd.print(F("Canceled. ")); + delay(MESSAGE_WAIT_TIME); + } + } +} + +void UI_func_sysex_send_voice(uint8_t param) +{ + static uint8_t mode; + static uint8_t bank_number; + static uint8_t voice_number; + + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + mode = 0; + bank_number = configuration.performance.bank[selected_instance_id]; + voice_number = configuration.performance.voice[selected_instance_id]; + + char bank_name[BANK_NAME_LEN]; + + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + + lcd.setCursor(0, 0); + lcd.print(F("MIDI Send Voice")); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, bank_name); + lcd.show(1, 2, 1, "["); + lcd.show(1, 13, 1, "]"); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; + + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + switch (mode) + { + case 0: // Bank selection + if (LCDML.BT_checkDown()) + bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + else if (LCDML.BT_checkUp() && bank_number > 0) + bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 3, 10, bank_name); + break; + case 1: // Voice selection + if (LCDML.BT_checkDown() && voice_number < MAX_VOICES - 1) + voice_number = constrain(voice_number + ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + else if (LCDML.BT_checkUp() && voice_number > 0) + voice_number = constrain(voice_number - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, voice_number + 1); + lcd.show(1, 3, 10, voice_name); + break; + } + } + else if (LCDML.BT_checkEnter()) + { + if (encoderDir[ENC_R].ButtonShort()) + mode++; + switch (mode) + { + case 1: + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, voice_number + 1); + lcd.show(1, 3, 10, voice_name); + break; + case 2: + File sysex; + char filename[FILENAME_LEN]; + + if (get_bank_name(bank_number, bank_name, sizeof(bank_name))) + { + sprintf(filename, "/%d/%s.syx", bank_number, bank_name); +#ifdef DEBUG + Serial.print(F("Send voice ")); + Serial.print(voice_number); + Serial.print(F(" of ")); + Serial.print(filename); + Serial.println(F(" from SD.")); +#endif + sysex = SD.open(filename); + if (!sysex) + { +#ifdef DEBUG + Serial.println(F("Connot read from SD.")); +#endif + lcd.show(1, 0, 16, "Read error."); + bank_number = 0xff; + } + else + { + uint8_t voice_data[155]; + uint8_t encoded_voice_data[128]; + + sysex.seek(6 + (voice_number * 128)); + sysex.read(encoded_voice_data, 128); + + MicroDexed[selected_instance_id]->decodeVoice(voice_data, encoded_voice_data); + + lcd.show(1, 0, 16, "Sending Ch"); + if (configuration.dexed[selected_instance_id].midi_channel == MIDI_CHANNEL_OMNI) + { + lcd.show(1, 11, 2, "01"); + send_sysex_voice(1, voice_data); + } + else + { + lcd.show(1, 11, 2, configuration.dexed[selected_instance_id].midi_channel + 1); + send_sysex_voice(configuration.dexed[selected_instance_id].midi_channel, voice_data); + } + delay(MESSAGE_WAIT_TIME); + lcd.show(1, 0, 16, "Done."); + sysex.close(); + + bank_number = 0xff; + } + } + else + { + lcd.show(1, 0, 16, "No voice."); + bank_number = 0xff; + } + + mode = 0xff; + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + + break; + } + } + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } + encoderDir[ENC_R].reset(); + } +} + +void UI_func_eq_1(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ Low-Cut")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_1 = constrain(configuration.fx.eq_1 + ENCODER[ENC_R].speed(), EQ_1_MIN, EQ_1_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_1 = constrain(configuration.fx.eq_1 - ENCODER[ENC_R].speed(), EQ_1_MIN, EQ_1_MAX); + } + } + lcd_display_meter_int("EQ Low-Cut [Hz]", configuration.fx.eq_1, 1.0, 0.0, EQ_1_MIN, EQ_1_MAX, 3, false, false, true); + sgtl5000.setEQFc(1, mapfloat(configuration.fx.eq_1, EQ_1_MIN, EQ_1_MAX, 15, 250)); + sgtl5000.setEQGain(1, 6.0); + sgtl5000.commitFilter(1); +#ifdef DEBUG + sgtl5000.show_params(1); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_1), configuration.fx.eq_1); + } +#endif +} + +void UI_func_eq_2(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ 120Hz")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_2 = constrain(configuration.fx.eq_2 + ENCODER[ENC_R].speed(), EQ_2_MIN, EQ_2_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_2 = constrain(configuration.fx.eq_2 - ENCODER[ENC_R].speed(), EQ_2_MIN, EQ_2_MAX); + } + } + lcd_display_meter_float("EQ 120Hz", configuration.fx.eq_2, 0.1, 0.0, EQ_2_MIN, EQ_2_MAX, 1, 1, false, true, true); + sgtl5000.setEQGain(2, mapfloat(configuration.fx.eq_2, EQ_2_MIN, EQ_2_MAX, -9.9, 9.9)); + sgtl5000.commitFilter(2); +#ifdef DEBUG + sgtl5000.show_params(2); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_2), configuration.fx.eq_2); + } +#endif +} + +void UI_func_eq_3(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ 220Hz")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_3 = constrain(configuration.fx.eq_3 + ENCODER[ENC_R].speed(), EQ_3_MIN, EQ_3_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_3 = constrain(configuration.fx.eq_3 - ENCODER[ENC_R].speed(), EQ_3_MIN, EQ_3_MAX); + } + } + lcd_display_meter_float("EQ 220Hz", configuration.fx.eq_3, 0.1, 0.0, EQ_3_MIN, EQ_3_MAX, 1, 1, false, true, true); + sgtl5000.setEQGain(3, mapfloat(configuration.fx.eq_3, EQ_3_MIN, EQ_3_MAX, -9.9, 9.9)); + sgtl5000.commitFilter(3); +#ifdef DEBUG + sgtl5000.show_params(3); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_3), configuration.fx.eq_3); + } +#endif +} + +void UI_func_eq_4(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ 1000Hz")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_4 = constrain(configuration.fx.eq_4 + ENCODER[ENC_R].speed(), EQ_4_MIN, EQ_4_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_4 = constrain(configuration.fx.eq_4 - ENCODER[ENC_R].speed(), EQ_4_MIN, EQ_4_MAX); + } + } + lcd_display_meter_float("EQ 1000Hz", configuration.fx.eq_4, 0.1, 0.0, EQ_4_MIN, EQ_4_MAX, 1, 1, false, true, true); + sgtl5000.setEQGain(4, mapfloat(configuration.fx.eq_4, EQ_4_MIN, EQ_4_MAX, -9.9, 9.9)); + sgtl5000.commitFilter(4); +#ifdef DEBUG + sgtl5000.show_params(4); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_4), configuration.fx.eq_4); + } +#endif +} + +void UI_func_eq_5(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ 2000Hz")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_5 = constrain(configuration.fx.eq_5 + ENCODER[ENC_R].speed(), EQ_5_MIN, EQ_5_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_5 = constrain(configuration.fx.eq_5 - ENCODER[ENC_R].speed(), EQ_5_MIN, EQ_5_MAX); + } + } + lcd_display_meter_float("EQ 2000Hz", configuration.fx.eq_5, 0.1, 0.0, EQ_5_MIN, EQ_5_MAX, 1, 1, false, true, true); + sgtl5000.setEQGain(5, mapfloat(configuration.fx.eq_5, EQ_5_MIN, EQ_5_MAX, -9.9, 9.9)); + sgtl5000.commitFilter(5); +#ifdef DEBUG + sgtl5000.show_params(5); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_5), configuration.fx.eq_5); + } +#endif +} + +void UI_func_eq_6(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ 7000Hz")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_6 = constrain(configuration.fx.eq_6 + ENCODER[ENC_R].speed(), EQ_6_MIN, EQ_6_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_6 = constrain(configuration.fx.eq_6 - ENCODER[ENC_R].speed(), EQ_6_MIN, EQ_6_MAX); + } + } + lcd_display_meter_float("EQ 7000Hz", configuration.fx.eq_6, 0.1, 0.0, EQ_6_MIN, EQ_6_MAX, 1, 1, false, true, true); + sgtl5000.setEQGain(6, mapfloat(configuration.fx.eq_6, EQ_6_MIN, EQ_6_MAX, -9.9, 9.9)); + sgtl5000.commitFilter(6); +#ifdef DEBUG + sgtl5000.show_params(1); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_6), configuration.fx.eq_6); + } +#endif +} + +void UI_func_eq_7(uint8_t param) +{ +#ifndef SGTL5000_AUDIO_ENHANCE + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd.setCursor(0, 0); + lcd.print(F("EQ High-Cut")); + lcd.setCursor(0, 1); + lcd.print(F("Not implemented.")); + } +#else + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + lcd_special_chars(METERBAR); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) + { + if (LCDML.BT_checkDown()) + { + configuration.fx.eq_7 = constrain(configuration.fx.eq_7 + ENCODER[ENC_R].speed(), EQ_7_MIN, EQ_7_MAX); + } + else if (LCDML.BT_checkUp()) + { + configuration.fx.eq_7 = constrain(configuration.fx.eq_7 - ENCODER[ENC_R].speed(), EQ_7_MIN, EQ_7_MAX); + } + } + lcd_display_meter_float("EQ High-Cut[kHz]", configuration.fx.eq_7, 1.0, 0.0, EQ_7_MIN, EQ_7_MAX, 3, 1, false, false, true); + sgtl5000.setEQFc(7, mapfloat(configuration.fx.eq_7, EQ_7_MIN, EQ_7_MAX, EQ_7_MIN * 1000.0, EQ_7_MAX * 1000.0)); + sgtl5000.commitFilter(7); +#ifdef DEBUG + sgtl5000.show_params(7); +#endif + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); + EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.eq_7), configuration.fx.eq_7); + } +#endif +} + +void UI_function_not_enabled(void) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Function not")); + lcd.setCursor(0, 1); + lcd.print(F("enbaled!")); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + ; + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +void UI_function_not_implemented(uint8_t param) +{ + if (LCDML.FUNC_setup()) // ****** SETUP ********* + { + encoderDir[ENC_R].reset(); + + lcd.setCursor(0, 0); + lcd.print(F("Function not")); + lcd.setCursor(0, 1); + lcd.print(F("implemented!")); + } + + if (LCDML.FUNC_loop()) // ****** LOOP ********* + { + ; + } + + if (LCDML.FUNC_close()) // ****** STABLE END ********* + { + encoderDir[ENC_R].reset(); + } +} + +bool UI_select_name(uint8_t y, uint8_t x, char* edit_string, uint8_t len, bool init) +{ + static int8_t edit_pos; + static bool edit_mode; + static uint8_t edit_value; + static uint8_t last_char_pos; + + if (init == true) + { + edit_mode = false; + edit_pos = 0; + edit_value = search_accepted_char(edit_string[edit_pos]); + last_char_pos = strlen(edit_string); + + string_trim(edit_string); // just to be sure + + lcd.setCursor(x, y); + lcd.print(edit_string); + lcd.setCursor(x, y); + + return (false); + } + + if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) + { + if (LCDML.BT_checkDown()) + { + if (edit_mode == true) + { + edit_value = search_accepted_char(edit_string[edit_pos]); + + if (edit_value < sizeof(accepted_chars) - 2) + edit_value++; + if (edit_value == 0 && edit_string[constrain(edit_pos + 1, 0, len)] > 0) + edit_value = 1; + + edit_string[edit_pos] = accepted_chars[edit_value]; + + lcd.setCursor(x + edit_pos, y); + lcd.print(edit_string[edit_pos]); + } + else + { + if (edit_string[edit_pos] != 0 && edit_string[edit_pos] != 32) + edit_pos = constrain(edit_pos + 1, 0, len); + else + { + if (edit_pos + 1 > last_char_pos) + edit_pos = len; + } + + if (edit_pos == len) + { + lcd.noBlink(); + lcd.setCursor(x - 1, y); + lcd.print(F(" ")); + lcd.setCursor(x + len, y); + lcd.print(F(" ")); + lcd.setCursor(x + len + 1, y); + lcd.print(F("[OK]")); + } + } + } + else if (LCDML.BT_checkUp()) + { + if (edit_mode == true) + { + edit_value = search_accepted_char(edit_string[edit_pos]); + + if (edit_value >= 1) + edit_value--; + if (edit_value == 0 && edit_string[constrain(edit_pos + 1, 0, len)] > 0) + edit_value = 1; + edit_string[edit_pos] = accepted_chars[edit_value]; + + lcd.setCursor(x + edit_pos, y); + lcd.print(edit_string[edit_pos]); + } + else + { + if (edit_pos - 1 > last_char_pos) + edit_pos = last_char_pos; + else + edit_pos = constrain(edit_pos - 1, 0, len - 1); + + if (edit_pos == last_char_pos) + { + lcd.setCursor(x - 1, y); + lcd.print(F("[")); + lcd.setCursor(x + len, y); + lcd.print(F("]")); + lcd.setCursor(x + len + 1, y); + lcd.print(F(" ")); + lcd.blink(); + } + } + } + } + else if (LCDML.BT_checkEnter()) + { + last_char_pos = strlen(edit_string); + if (edit_pos >= len) + { + edit_pos = 0; + edit_mode = false; + + return (true); + } + else + { + last_char_pos = strlen(edit_string); + edit_mode = !edit_mode; + } + if (edit_mode == false && edit_pos < len && edit_string[edit_pos] != 0 && edit_string[edit_pos] != 32) + edit_pos++; + if (edit_mode == true) + { + lcd.setCursor(x + len + 1, y); + lcd.print(F("*")); + } + else + { + lcd.setCursor(x + len + 1, y); + lcd.print(F(" ")); + } + + } + lcd.setCursor(x + edit_pos, y); + encoderDir[ENC_R].reset(); + + return (false); +} + +uint8_t search_accepted_char(uint8_t c) +{ + //if (c == 0) + // c = 32; + + for (uint8_t i = 0; i < sizeof(accepted_chars) - 1; i++) + { + Serial.print(i, DEC); + Serial.print(":"); + Serial.print(c); + Serial.print("=="); + Serial.println(accepted_chars[i], DEC); + if (c == accepted_chars[i]) + return (i); + } + return (0); +} + +void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign) +{ + lcd_display_float(float(var), size, 0, zeros, brackets, sign); +} + +void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign) +{ + char s[LCD_cols + 1]; + char f[LCD_cols + 1]; + + if (size_fraction > 0) + { + if (zeros == true && sign == true) + sprintf(f, "%%+0%d.%df", size_number + size_fraction + 2, size_fraction); + else if (zeros == true && sign == false) + sprintf(f, "%%+0%d.%df", size_number + size_fraction + 1, size_fraction); + else if (zeros == false && sign == true) + sprintf(f, "%%+%d.%df", size_number + size_fraction + 2, size_fraction); + else if (zeros == false && sign == false) + sprintf(f, "%%%d.%df", size_number + size_fraction + 1, size_fraction); + + sprintf(s, f, var); + } + else + { + if (zeros == true && sign == true) + sprintf(f, "%%+0%dd", size_number + 1); + else if (zeros == true && sign == false) + sprintf(f, "%%%0dd", size_number); + else if (zeros == false && sign == true) + sprintf(f, "%%+%dd", size_number + 1); + else if (zeros == false && sign == false) + sprintf(f, "%%%dd", size_number); + + sprintf(s, f, int(var)); + } + + if (brackets == true) + { + char tmp[LCD_cols + 1]; + + strcpy(tmp, s); + sprintf(s, "[%s]", tmp); + } + + lcd.print(s); +} + +inline void lcd_display_bar_int(const char* title, uint32_t value, float factor, int32_t min_value, int32_t max_value, uint8_t size, bool zeros, bool sign, bool init) +{ + lcd_display_bar_float(title, float(value), factor, min_value, max_value, size, 0, zeros, sign, init); +} + +void lcd_display_bar_float(const char* title, float value, float factor, int32_t min_value, int32_t max_value, uint8_t size_number, uint8_t size_fraction, bool zeros, bool sign, bool init) +{ + uint8_t size; + float v; + float _vi = 0.0; + uint8_t vf; + uint8_t vi; + + if (size_fraction == 0) + size = size_number; + else + size = size_number + size_fraction + 1; + if (sign == true) + size++; + + v = float((value - min_value) * (LCD_cols - size)) / (max_value - min_value); + vf = uint8_t(modff(v, &_vi) * 10.0 + 0.5); + vi = uint8_t(_vi); + + if (sign == true) + size += 1; + + // Title + if (init == true) + lcd.show(0, 0, LCD_cols - 2, title); + //lcd.show(0, 0, LCD_cols - 3, title); + + // Value + lcd.setCursor(LCD_cols - size, 1); + lcd_display_float(value * factor, size_number, size_fraction, zeros, false, sign); // TBD + + // Bar + lcd.setCursor(0, 1); + + if (vi == 0) + { + lcd.write((uint8_t)(vf / 2.0 - 0.5) + 2); + for (uint8_t i = vi + 1; i < LCD_cols - size; i++) + lcd.print(F(" ")); // empty block + } + else + { + for (uint8_t i = 0; i < vi; i++) + lcd.write((uint8_t)4 + 2); // full block + if (vi < LCD_cols - size) + lcd.write((uint8_t)(vf / 2.0 - 0.5) + 2); + for (uint8_t i = vi + 1; i < LCD_cols - size; i++) + lcd.print(F(" ")); // empty block + } +} + +inline void lcd_display_meter_int(const char* title, uint32_t value, float factor, float offset, int32_t min_value, int32_t max_value, uint8_t size, bool zeros, bool sign, bool init) +{ + lcd_display_meter_float(title, float(value), factor, offset, min_value, max_value, size, 0, zeros, sign, init); +} + +void lcd_display_meter_float(const char* title, float value, float factor, float offset, int32_t min_value, int32_t max_value, uint8_t size_number, uint8_t size_fraction, bool zeros, bool sign, bool init) +{ + uint8_t size = 0; + float v; + float _vi = 0.0; + uint8_t vf; + uint8_t vi; + + if (size_fraction == 0) + size = size_number; + else + size = size_number + size_fraction + 1; + if (sign == true) + size++; + + v = float((value - min_value) * (LCD_cols - size)) / (max_value - min_value); + vf = uint8_t(modff(v, &_vi) * 10.0 + 0.5); + vi = uint8_t(_vi); + + if (init == true) + { + // Title + lcd.setCursor(0, 0); + lcd.print(title); + } + + // Value + lcd.setCursor(LCD_cols - size, 1); + lcd_display_float((value + offset) * factor, size_number, size_fraction, zeros, false, sign); + + // Bar + lcd.setCursor(0, 1); + + if (vi == 0) + { + lcd.write((uint8_t)(vf / 2.0) + 2); + for (uint8_t i = 1; i < LCD_cols - size; i++) + lcd.print(F(" ")); // empty block + } + else if (vi == LCD_cols - size) + { + for (uint8_t i = 0; i < LCD_cols - size - 1; i++) + lcd.print(F(" ")); // empty block + lcd.write(4 + 2); + } + else + { + for (uint8_t i = 0; i < LCD_cols - size; i++) + lcd.print(F(" ")); // empty block + lcd.setCursor(vi, 1); + lcd.write((uint8_t)(vf / 2.0) + 2); + for (uint8_t i = vi + 1; i < LCD_cols - size; i++) + lcd.print(F(" ")); // empty block + } +} + +uint8_t bit_reverse8(uint8_t v) +{ + uint8_t result = 0; + for ( ; v > 0; v >>= 1 ) + (result <<= 1) |= (v & 1); + return (result); +} + +void lcd_active_instance_number(uint8_t instance_id) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (instance_id == 0) + { + if (configuration.dexed[instance_id].polyphony == 0) + instance_num[0][i] = bit_reverse8(special_chars[0][i]); + else + instance_num[0][i] = special_chars[0][i]; + + if (configuration.dexed[!instance_id].polyphony == 0) + { + instance_num[1][i] = bit_reverse8(special_chars[1][i]); + instance_num[1][i] = ~instance_num[1][i]; + } + else + instance_num[1][i] = ~special_chars[1][i]; + } + else + { + if (configuration.dexed[!instance_id].polyphony == 0) + { + instance_num[0][i] = bit_reverse8(special_chars[0][i]); + instance_num[0][i] = ~instance_num[0][i]; + } + else + instance_num[0][i] = ~special_chars[0][i]; + + if (configuration.dexed[instance_id].polyphony == 0) + instance_num[1][i] = bit_reverse8(special_chars[1][i]); + else + instance_num[1][i] = special_chars[1][i]; + } + } + +#if NUM_DEXED == 1 + lcd.createChar(0, instance_num[0]); + lcd.createChar(1, (uint8_t*)special_chars[17]); +#else + lcd.createChar(0, instance_num[0]); + lcd.createChar(1, instance_num[1]); +#endif +} + +void lcd_OP_active_instance_number(uint8_t instance_id, uint8_t op) +{ + uint8_t i, n; + + for (n = 2; n < 8; n++) + { + for (i = 0; i < 8; i++) + { + if (bitRead(op, n - 2)) + instance_num[n][i] = special_chars[n][i]; + else + instance_num[n][i] = ~special_chars[n][i]; + } + lcd.createChar(n, instance_num[n]); + } + + for (i = 0; i < 8; i++) + { + if (instance_id == 0) + { + if (configuration.dexed[instance_id].polyphony == 0) + instance_num[0][i] = bit_reverse8(special_chars[0][i]); + else + instance_num[0][i] = special_chars[0][i]; + + if (configuration.dexed[!instance_id].polyphony == 0) + { + instance_num[1][i] = bit_reverse8(special_chars[1][i]); + instance_num[1][i] = ~instance_num[1][i]; + } + else + instance_num[1][i] = ~special_chars[1][i]; + } + else + { + if (configuration.dexed[!instance_id].polyphony == 0) + { + instance_num[0][i] = bit_reverse8(special_chars[0][i]); + instance_num[0][i] = ~instance_num[0][i]; + } + else + instance_num[0][i] = ~special_chars[0][i]; + + if (configuration.dexed[instance_id].polyphony == 0) + instance_num[1][i] = bit_reverse8(special_chars[1][i]); + else + instance_num[1][i] = special_chars[1][i]; + } + } + + lcd.createChar(0, instance_num[0]); +#if NUM_DEXED > 1 + lcd.createChar(1, instance_num[1]); +#else + lcd.createChar(1, (uint8_t *)special_chars[17]); +#endif +} + +void lcd_special_chars(uint8_t mode) +{ + switch (mode) + { + case SCROLLBAR: + // set special chars for scrollbar + for (uint8_t i = 0; i < 5; i++) + { +#ifdef I2C_DISPLAY + lcd.createChar(i, (uint8_t*)scroll_bar[i]); +#else + flipped_scroll_bar[i] = rotTile(scroll_bar[i]); +#endif + } + break; + case BLOCKBAR: + // set special chars for volume-bar + for (uint8_t i = 0; i < 7; i++) + { +#ifdef I2C_DISPLAY + lcd.createChar(i + 2, (uint8_t*)block_bar[i]); +#else + flipped_block_bar[i] = rotTile(block_bar[i]); +#endif + } + break; + case METERBAR: + // set special chars for panorama-bar + for (uint8_t i = 0; i < 7; i++) + { +#ifdef I2C_DISPLAY + lcd.createChar(i + 2, (uint8_t*)meter_bar[i]); +#else + flipped_meter_bar[i] = rotTile(meter_bar[i]); +#endif + } + break; + } +} + +#ifdef USE_FX +void lcd_display_delay_sync(uint8_t sync) +{ + lcd.show(0, 0, LCD_cols - 2, "Delay Sync"); + if (seq_running == false)lcd.show(1, 0, 10, "MIDI Sync "); else lcd.show(1, 0, 10, "Seq. Sync "); + switch (sync) + { + case 1: + lcd.show(1, 10, 6, "1/16"); + break; + case 2: + lcd.show(1, 10, 6, "1/16T"); + break; + case 3: + lcd.show(1, 10, 6, "1/8"); + break; + case 4: + lcd.show(1, 10, 6, "1/8T"); + break; + case 5: + lcd.show(1, 10, 6, "1/4"); + break; + case 6: + lcd.show(1, 10, 6, "1/4T"); + break; + case 7: + lcd.show(1, 10, 6, "1/2"); + break; + case 8: + lcd.show(1, 10, 6, "1/2T"); + break; + case 9: + lcd.show(1, 10, 6, "1/1"); + break; + } + if (seq_running == false) { + + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[sync] / midi_bpm + 0.5); + if (midi_sync_delay_time > DELAY_MAX_TIME) + { +#ifdef DEBUG + Serial.println(F("Calculated MIDI-Sync delay: ")); + Serial.print(round(60000.0 * midi_ticks_factor[sync] / midi_bpm), DEC); + Serial.println(F("ms")); + Serial.println(F("MIDI-Sync delay: midi_sync_delay_time")); + Serial.print(midi_sync_delay_time, DEC); + Serial.println(F("ms")); +#endif + } + } else + { + uint16_t midi_sync_delay_time = uint16_t(60000.0 * midi_ticks_factor[sync] / seq_bpm); + delay_fx[selected_instance_id]->delay(0, constrain(midi_sync_delay_time, DELAY_TIME_MIN, DELAY_TIME_MAX * 10)); + } + lcd.show(1, 15, 1, "!"); +} +#endif + +void eeprom_update_var(uint16_t pos, uint8_t val, const char* val_string) +{ +#ifdef DEBUG + char tmp[80]; + sprintf(tmp, "EEPROM update '%s' at position %d with value %d.", val_string, pos, val); + Serial.println(tmp); +#endif + EEPROM.update(EEPROM_START_ADDRESS + pos, val); +} + +void string_trim(char *s) +{ + int i; + + while (isspace (*s)) s++; // skip left side white spaces + for (i = strlen (s) - 1; (isspace (s[i])); i--) ; // skip right side white spaces + s[i + 1] = '\0'; +} + +void locate_previous_non_favorite() +{ + //find prev. non fav in current bank + lcd.setCursor(3, 0); + lcd.print("= 0 && configuration.performance.bank[selected_instance_id] >= 0) { + + lcd.setCursor(3, 0); + lcd.print("= 1 && favsearcher < 36); + + // if found, we are done. else quick check in previous banks + + if ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && configuration.performance.voice[selected_instance_id] >= 0 && + configuration.performance.bank[selected_instance_id] >= 0 && favsearcher < 170) + { + configuration.performance.voice[selected_instance_id] = 32; + + do { //seek for previous bank + configuration.performance.bank[selected_instance_id]--; + favsearcher++; + } while (quick_check_favorites_in_bank(configuration.performance.bank[selected_instance_id], selected_instance_id) == false && + favsearcher < 132 && configuration.performance.bank[selected_instance_id] >= 0); + + do { //last try to search if a bank with fav was found + + configuration.performance.voice[selected_instance_id]--; + favsearcher++; + } while ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && configuration.performance.voice[selected_instance_id] >= 1 && favsearcher < 170); + } + } + favsearcher = 0; +} + +void locate_next_favorite() + +{ + + bool RollOver = false; + if (configuration.performance.voice[selected_instance_id] > 30 && configuration.performance.bank[selected_instance_id] >= MAX_BANKS - 1 ) + { //if at end of all banks + configuration.performance.bank[selected_instance_id] = 0; + configuration.performance.voice[selected_instance_id] = 0; + RollOver = true; + + } else if (configuration.performance.voice[selected_instance_id] > 30 && configuration.performance.bank[selected_instance_id] < MAX_BANKS - 1 ) + { //if at end of any other bank + configuration.performance.bank[selected_instance_id]++; + configuration.performance.voice[selected_instance_id] = 0; + } + + if (configuration.performance.voice[selected_instance_id] <= 30 && configuration.performance.bank[selected_instance_id] <= MAX_BANKS ) { + + lcd.setCursor(3, 0); + lcd.print(">SEARCHING"); + + do { //first find next fav in current bank + + if (RollOver == false) configuration.performance.voice[selected_instance_id]++; else RollOver = true; + favsearcher++; + + } while ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && configuration.performance.voice[selected_instance_id] <= 32 && favsearcher < 36); + + // if found, we are done. else quick check in next banks + + if ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && + configuration.performance.bank[selected_instance_id] < MAX_BANKS && favsearcher < 170) + { + configuration.performance.voice[selected_instance_id] = 0; + + do { //seek in next bank + + configuration.performance.bank[selected_instance_id]++; + if ( configuration.performance.bank[selected_instance_id] > MAX_BANKS - 1 && favsearcher < 190) + { + configuration.performance.bank[selected_instance_id] = 0; + configuration.performance.voice[selected_instance_id] = 0; + } + favsearcher++; + } while (quick_check_favorites_in_bank(configuration.performance.bank[selected_instance_id], selected_instance_id) == false && + favsearcher < 132 ); + + if ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && configuration.performance.voice[selected_instance_id] <= 32 && favsearcher < 190) + { + do { //last bank to search if a fav can be found + + configuration.performance.voice[selected_instance_id]++; + favsearcher++; + } while ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == false && favsearcher < 170); + } + } + } + favsearcher = 0; + +} + +void locate_next_non_favorite() +{ + //find next non-fav in current bank + lcd.setCursor(3, 0); + lcd.print(">SEARCHING"); + do { + configuration.performance.voice[selected_instance_id]++; + if (configuration.performance.voice[selected_instance_id] > 31) { + configuration.performance.voice[selected_instance_id] = 0; + //configuration.performance.bank[selected_instance_id]++; + if (configuration.performance.bank[selected_instance_id] > MAX_BANKS - 1) + configuration.performance.bank[selected_instance_id] = 0; + do { //seek for next bank + configuration.performance.bank[selected_instance_id]++; + if (configuration.performance.bank[selected_instance_id] > MAX_BANKS - 1) + configuration.performance.bank[selected_instance_id] = 0; + favsearcher++; + } while (quick_check_favorites_in_bank(configuration.performance.bank[selected_instance_id], selected_instance_id) == true && favsearcher < 132); + } + favsearcher++; + } while ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == true && favsearcher < 170); + favsearcher = 0; +} + +void locate_random_non_favorite() +{ + //find random non-fav + do + { + configuration.performance.voice[selected_instance_id] = random(32); + configuration.performance.bank[selected_instance_id] = random(MAX_BANKS - 1); + favsearcher++; + } while ( check_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], + selected_instance_id) == true && favsearcher < 100); + favsearcher = 0; +} + +bool check_favorite(uint8_t b, uint8_t v, uint8_t instance_id) +{ + b = constrain(b, 0, MAX_BANKS - 1); + v = constrain(v, 0, MAX_VOICES - 1); + char tmp[18]; + File myFav; + if (sd_card > 0) + { + sprintf(tmp, "/%s/%d/%d.fav", FAV_CONFIG_PATH, b, v); +#ifdef DEBUG + Serial.print("check if Voice is a Favorite: "); + Serial.print(tmp); + Serial.println(); +#endif + if (SD.exists(tmp)) + { //is Favorite +#ifdef DEBUG + Serial.println(" - It is in Favorites."); +#endif + return true; + } + else + { // it was not a favorite + +#ifdef DEBUG + Serial.println(" - It is not in Favorites."); +#endif + return false; + } + } + else + return false; +} + +void draw_favorite_icon(uint8_t b, uint8_t v, uint8_t instance_id) +{ + b = constrain(b, 0, MAX_BANKS - 1); + v = constrain(v, 0, MAX_VOICES - 1); + char tmp[18]; + File myFav; + if (sd_card > 0) + { + sprintf(tmp, "/%s/%d/%d.fav", FAV_CONFIG_PATH, b, v); + if (SD.exists(tmp)) + { //is Favorite +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); +#else + lcd.setCursor(13, 0); +#endif + lcd.write(2); //fav symbol + } + else + { // it was not a favorite +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); +#else + lcd.setCursor(13, 0); +#endif + lcd.print(" "); + } + } +} + +bool quick_check_favorites_in_bank(uint8_t b, uint8_t instance_id) +{ + b = constrain(b, 0, MAX_BANKS - 1); + char tmp[18]; + + if (sd_card > 0) + { + sprintf(tmp, "/%s/%d", FAV_CONFIG_PATH, b); +#ifdef DEBUG + Serial.print("check if there is a Favorite in Bank: "); + Serial.print(tmp); + Serial.println(); +#endif + if (SD.exists(tmp) ) + { // this bank HAS at least 1 favorite(s) +#ifdef DEBUG + Serial.println("quickcheck found a FAV in bank!"); +#endif + return (true); + } + else + { // no favorites in bank stored + return (false); +#ifdef DEBUG + Serial.println(" - It is no Favorite in current Bank."); +#endif + } + } + else + return false; +} + +void save_favorite(uint8_t b, uint8_t v, uint8_t instance_id) +{ +#ifdef DEBUG + Serial.println("Starting saving Favorite."); +#endif + b = constrain(b, 0, MAX_BANKS - 1); + v = constrain(v, 0, MAX_VOICES - 1); + char tmp[18]; + char tmpfolder[18]; + File myFav; + uint8_t i = 0, countfavs = 0; + if (sd_card > 0) + { + sprintf(tmp, "/%s/%d/%d.fav", FAV_CONFIG_PATH, b, v); + sprintf(tmpfolder, "/%s/%d", FAV_CONFIG_PATH, b); +#ifdef DEBUG + Serial.println("Save Favorite to SD card..."); + Serial.println(tmp); +#endif + if (!SD.exists(tmp)) + { //create Favorite Semaphore + if (!SD.exists(tmpfolder)) + { + SD.mkdir(tmpfolder); + } + myFav = SD.open(tmp, FILE_WRITE); + myFav.close(); + Serial.println("Favorite saved..."); +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); +#else + lcd.setCursor(13, 0); +#endif + lcd.write(2); //fav symbol +#ifdef DEBUG + Serial.println("Added to Favorites..."); +#endif + } + else + { // delete the file, is no longer a favorite + SD.remove(tmp); +#ifdef DEBUG + Serial.println("Removed from Favorites..."); +#endif + for (i = 0; i < 32; i++) { //if no other favs exist in current bank, remove folder + sprintf(tmp, "/%s/%d/%d.fav", FAV_CONFIG_PATH, b, i); + if (SD.exists(tmp)) countfavs++; + } + if (countfavs == 0) { + sprintf(tmp, "/%s/%d", FAV_CONFIG_PATH, b); + SD.rmdir(tmp); +#ifdef DEBUG + Serial.println("Fav count in bank:"); + Serial.print(countfavs); + Serial.println("Removed folder since no voice in bank flagged as favorite any more"); +#endif + } +#ifdef TESTDISPLAY20x4 + lcd.setCursor(17, 0); +#else + lcd.setCursor(13, 0); +#endif + lcd.print(" "); //remove fav symbol +#ifdef DEBUG + Serial.println("Removed from Favorites..."); +#endif + } + } +} + +char* basename(const char* filename) +{ + char* p = strrchr (filename, '/'); + return p ? p + 1 : (char *) filename; +} +#endif +#endif diff --git a/addon/SD/SEQ/config.h b/addon/SD/SEQ/config.h new file mode 100644 index 0000000..519f2a2 --- /dev/null +++ b/addon/SD/SEQ/config.h @@ -0,0 +1,760 @@ +/* + MicroDexed + + MicroDexed is a port of the Dexed sound engine + (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6/4.x with audio shield. + Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android + + (c)2018-2021 H. Wirtz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this programf; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#pragma once + +#include +#include "midinotes.h" +#include "teensy_board_detection.h" + +// If you want to test the system with Linux and without any keyboard and/or audio equipment, you can do the following: +// 1. In Arduino-IDE enable "Tools->USB-Type->Serial + MIDI + Audio" +// 2. Build the firmware with "MIDI_DEVICE_USB" enabled in config.h. +// 3. Afterconnecting to a Linux system there should be a MIDI an audio device available that is called "MicroMDexed", so you can start the following: +// $ aplaymidi -p 20:0 # e.g. test.mid +// $ vkeybd --addr 20:0 +// $ arecord -f cd -Dhw:1,0 /tmp/.wav +// +// Tools for testing MIDI: https://github.com/gbevin/SendMIDI +// https://github.com/gbevin/ReceiveMIDI +// +// e.g.: +// * sendmidi dev "MicroDexed MIDI" on 80 127 && sleep 1.0 && sendmidi dev "MicroDexed MIDI" off 80 0 +// * sendmidi dev "MicroDexed MIDI" syf addon/SD/90/RitCh1.syx +// * amidi -p hw:2,0,0 -s addon/SD/90/RitCh1.syx +// +// Receiving and storing MIDI SYSEX with Linux: +// amidi -p hw:2,0,0 -d -r /tmp/bkup1.syx +// +// For SYSEX Bank upload via USB: +// sed -i.orig 's/SYSEX_MAX_LEN = 290/SYSEX_MAX_LEN = 4104/' /usr/local/arduino-teensy/hardware/teensy/avr/libraries/USBHost_t36/USBHost_t36.h +// sed -i.orig 's/^#define USB_MIDI_SYSEX_MAX 290/#define USB_MIDI_SYSEX_MAX 4104/' /usr/local/arduino-teensy/hardware/teensy/avr/cores/teensy3/usb_midi.h +// sed -i.orig 's/^#define USB_MIDI_SYSEX_MAX 290/#define USB_MIDI_SYSEX_MAX 4104/' /usr/local/arduino-teensy/hardware/teensy/avr/cores/teensy4/usb_midi.h +//#define USB_MIDI_SYSEX_MAX 4104 + +#define VERSION "1.1.1" + +//************************************************************************************************* +//* DEVICE SETTINGS +//************************************************************************************************* + +//************************************************************************************************* +//* MIDI HARDWARE SETTINGS +//************************************************************************************************* +#define MIDI_DEVICE_DIN Serial1 +#define MIDI_DEVICE_USB 1 +#define MIDI_DEVICE_USB_HOST 1 + +//************************************************************************************************* +//* AUDIO HARDWARE SETTINGS +//************************************************************************************************* +// If nothing is defined Teensy internal DAC is used as audio output device! +// Left and right channel audio signal is presented on pins A21 and A22. +#define AUDIO_DEVICE_USB +#define TEENSY_AUDIO_BOARD +//#define PT8211_AUDIO +//#define TGA_AUDIO_BOARD +//#define TEENSY_DAC +//#define TEENSY_DAC_SYMMETRIC +//#define I2S_AUDIO_ONLY + +//************************************************************************************************* +//* MIDI SOFTWARE SETTINGS +//************************************************************************************************* +#define DEFAULT_MIDI_CHANNEL MIDI_CHANNEL_OMNI +#define SYSEXBANK_DEFAULT 0 +#define SYSEXSOUND_DEFAULT 0 + +//************************************************************************************************* +//* DEBUG OUTPUT SETTINGS +//************************************************************************************************* +#define DEBUG 1 +#define SERIAL_SPEED 230400 +#define SHOW_XRUN 1 +#define SHOW_CPU_LOAD_MSEC 5000 + +//************************************************************************************************* +//* DEXED AND EFFECTS SETTINGS +//************************************************************************************************* +// Number of Dexed instances +#if defined(TEENSY3_6) +#warning >>> Sorry, only one instance possible for Teensy-3.6 +#define NUM_DEXED 1 // 1 or 2 - nothing else! +#else +#define NUM_DEXED 2 // 1 or 2 - nothing else! +#endif + +// FX-CHAIN ENABLE/DISABLE +#define USE_FX 1 + +// NUMBER OF PARALLEL SAMPLEDRUMS +#ifdef TEENSY4 +#define NUM_DRUMS 8 +#else +#define NUM_DRUMS 4 +#endif +// DEFAULT MIDI CHANNEL FOR DRUMSAMPLER +#define DRUM_MIDI_CHANNEL 10 + +// NUMBER OF SAMPLES IN DRUMSET +#ifdef TEENSY4 +#define NUM_DRUMSET_CONFIG 71 +#else +#define NUM_DRUMSET_CONFIG 43 +#endif + +// SEQUENCER + +#ifdef TEENSY4 +#define NUM_SEQ_PATTERN 24 +#define NUM_SEQ_TRACKS 6 +#else +#define NUM_SEQ_PATTERN 10 +#define NUM_SEQ_TRACKS 2 +#endif + +// CHORUS parameters +#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer. +#define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE +#define MOD_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT +#define MOD_FILTER_CUTOFF_HZ 2000 +// SGTL5000 +#ifdef TEENSY_AUDIO_BOARD +#define SGTL5000_AUDIO_ENHANCE 1 +//#define SGTL5000_AUDIO_THRU 1 +#define SGTL5000_HEADPHONE_VOLUME 0.8 +#endif +#if defined(TEENSY4) +#define USE_PLATEREVERB 1 +#endif + +// DELAYTIME +#if NUM_DEXED > 1 +# if defined(TEENSY4) +# define DELAY_MAX_TIME 500 +# else +# define DELAY_MAX_TIME 100 +# endif +#else +# if defined(TEENSY3_6) +# define DELAY_MAX_TIME 400 +# elif defined(TEENSY4) +# define DELAY_MAX_TIME 1000 +# else +# define DELAY_MAX_TIME 200 +# endif +#endif + +//************************************************************************************************* +//* AUDIO SOFTWARE SETTINGS +//************************************************************************************************* +#define SAMPLE_RATE 44100 + +#ifdef USE_FX +#define AUDIO_MEM SAMPLE_RATE * NUM_DEXED * DELAY_MAX_TIME / 128000 + 36 +#else +#define AUDIO_MEM NUM_DEXED * 15 +#endif + +#ifdef TEENSY_AUDIO_BOARD +/* + 13: 3.16 Volts p-p + 14: 2.98 Volts p-p + 15: 2.83 Volts p-p + 16: 2.67 Volts p-p + 17: 2.53 Volts p-p + 18: 2.39 Volts p-p + 19: 2.26 Volts p-p + 20: 2.14 Volts p-p + 21: 2.02 Volts p-p + 22: 1.91 Volts p-p + 23: 1.80 Volts p-p + 24: 1.71 Volts p-p + 25: 1.62 Volts p-p + 26: 1.53 Volts p-p + 27: 1.44 Volts p-p + 28: 1.37 Volts p-p + 29: 1.29 Volts p-p (default) + 30: 1.22 Volts p-p + 31: 1.16 Volts p-p +*/ +#define SGTL5000_LINEOUT_LEVEL 29 +#endif + +//************************************************************************************************* +//* UI +//************************************************************************************************* +#define ENABLE_LCD_UI 1 +#define STANDARD_LCD_I2C +//#define OLED_SPI +//#define TESTDISPLAY20x4 //Currently for testing I2C Display 20x4 aka type "2004" + +// LCD Display +//I2C_DISPLAY only +#ifdef STANDARD_LCD_I2C +#define LCD_I2C_ADDRESS 0x27 +//#define LCD_I2C_ADDRESS 0x3f +//Display size, must be set for U8X8 as well +#ifdef TESTDISPLAY20x4 +#define LCD_cols 20 +#define LCD_rows 4 +#else +#define LCD_cols 16 +#define LCD_rows 2 +#endif + +#define I2C_DISPLAY +// [I2C] SCL: Pin 19, SDA: Pin 18 (https://www.pjrc.com/teensy/td_libs_Wire.html) +//#define LCD_GFX 1 +#endif + +#ifdef OLED_SPI +#define LCD_cols 16 +#define LCD_rows 4 +//enable U8X8 support +#define U8X8_DISPLAY +//enable SPI CS switching +#define DISPLAY_LCD_SPI +#define U8X8_DISPLAY_CLASS U8X8_SSD1322_NHD_256X64_4W_HW_SPI +//#define U8X8_DISPLAY_CLASS U8X8_SSD1306_128X64_NONAME_HW_I2C +#define U8X8_CS_PIN 9 +#define U8X8_DC_PIN 15 +#define U8X8_RESET_PIN 14 +#endif + +#define VOICE_SELECTION_MS 60000 +#define BACK_FROM_VOLUME_MS 2000 +#define MESSAGE_WAIT_TIME 1000 +#define MIDI_DECAY_TIMER 50 + +//************************************************************************************************* +//* HARDWARE SETTINGS +//************************************************************************************************* + +// Teensy Audio Shield +#define SDCARD_AUDIO_CS_PIN 10 +#define SDCARD_AUDIO_MOSI_PIN 7 +#define SDCARD_AUDIO_SCK_PIN 14 +#if defined(ARDUINO_TEENSY41) || defined(TEENSY3_6) // new detection logic to also find on board SD Card from Teensy 4.1 +// Teensy 3.6 & 4.1 internal SD card +#define SDCARD_TEENSY_CS_PIN BUILTIN_SDCARD +#define SDCARD_TEENSY_MOSI_PIN 11 +#define SDCARD_TEENSY_SCK_PIN 13 +#else +#define SDCARD_TEENSY_CS_PIN 10 +#define SDCARD_TEENSY_MOSI_PIN 11 +#define SDCARD_TEENSY_SCK_PIN 13 +#endif + +// Encoder with button +//#define ENCODER_USE_INTERRUPTS +#define NUM_ENCODER 2 +#define ENC_L_PIN_A 3 +#define ENC_L_PIN_B 2 +#define BUT_L_PIN 4 +#if defined(TEENSY3_6) +#define ENC_R_PIN_A 28 +#define ENC_R_PIN_B 29 +#define BUT_R_PIN 30 +#else +#if defined(TEENSY4_0) +#define ENC_R_PIN_A 6 +#define ENC_R_PIN_B 5 +#define BUT_R_PIN 8 +//#define ENC_R_PIN_A 17 +//#define ENC_R_PIN_B 16 +//#define BUT_R_PIN 5 +#else // ARDUINO_TEENSY41 +#define ENC_R_PIN_A 24 +#define ENC_R_PIN_B 5 +#define BUT_R_PIN 9 +#endif +#endif +#define BUT_DEBOUNCE_MS 20 +#define LONG_BUTTON_PRESS 500 + +// Internal timer +#define AUTOSTORE_MS 5000 + +// EEPROM address +#define EEPROM_START_ADDRESS 0xFF + +#define MAX_BANKS 100 +#define MAX_VOICES 32 // voices per bank +#define MAX_FX 99 +#define MAX_PERFORMANCE 99 +#define MAX_VOICECONFIG 99 +#define BANK_NAME_LEN 11 // 10 (plus '\0') +#define VOICE_NAME_LEN 12 // 11 (plus '\0') +#define FILENAME_LEN BANK_NAME_LEN + VOICE_NAME_LEN +#define DRUM_NAME_LEN 21 + +#define FX_CONFIG_PATH "FXCFG" +#define FX_CONFIG_NAME "FXCFG" +#define PERFORMANCE_CONFIG_PATH "PCFG" +#define PERFORMANCE_CONFIG_NAME "PCFG" +#define VOICE_CONFIG_PATH "VCFG" +#define VOICE_CONFIG_NAME "VCFG" + +#define FAV_CONFIG_PATH "FAVCFG" +#define FAV_CONFIG_NAME "FAVCFG" + +#define SEQ_CONFIG_PATH "SEQ" +#define SEQ_CONFIG_NAME "SEQ" + +#define DRUM_CONFIG_PATH "DRM" +#define DRUM_CONFIG_NAME "DRM" + +#define MAX_PERF_MOD 30 + +//************************************************************************************************* +//* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!! +//************************************************************************************************* +#define MAX_DEXED 2 // No! - even don't think about increasing this number! IT _WILL_ PRODUCE MASSIVE PROBLEMS! +#define CONTROL_RATE_MS 50 +#define VOL_MAX_FLOAT 0.95 + +#define EEPROM_MARKER 0x4242 + +#ifndef NUM_DRUMS +#define NUM_DRUMS 0 +#endif + +// MAX_NOTES SETTINGS +// Teensy-4.x settings +#ifdef TEENSY4 +#define MAX_NOTES 32 +#endif + +// Teensy-3.6 settings +#if defined(TEENSY3_6) +# if defined(USE_FX) +# warning >>> With enabled FX a maximum of 13 voices is possible (due to RAM and CPU limitations) +# define MAX_NOTES 12 +# if F_CPU > 180000000 +# error >>> Enabled FX with clockrate more than 180MHz is not useful due to RAM limitations. +# endif +# else +# if F_CPU == 256000000 +# warning >>> Maximum of 22 voices. +# define MAX_NOTES 22 +# elif F_CPU == 240000000 +# warning >>> Maximum of 20 voices. You should consider to use 256MHz overclocking to get a maximum of 22 voices. +# define MAX_NOTES 20 +# elif F_CPU == 216000000 +# warning >>> Maximum of 20 voices. You should consider to use 256MHz overclocking to get a maximum of 22 voices. +# define MAX_NOTES 18 +# elif F_CPU == 192000000 +# warning >>> Maximum of 18 voices. You should consider to use 256MHz overclocking to get a maximum of 22 voices. +# define MAX_NOTES 16 +# elif F_CPU == 180000000 +# warning >>> Maximum of 16 voices. You should consider to use 256MHz overclocking to get a maximum of 24 voices. +# define MAX_NOTES 14 +# else +# error >>> CPU Clock below 180MHz is not supported +# endif +# endif +#endif + +#ifdef TEENSY3_5 +#error >>> Not supported anymore!!! +#endif + +// MIDI +#ifdef MIDI_DEVICE_USB +#define USBCON 1 +#endif + +// Some optimizations +#define USE_TEENSY_DSP 1 + +// HELPER MACROS +#define TIME_MS2SAMPLES(x) floor(uint32_t(x) * AUDIO_SAMPLE_RATE / 1000) * sizeof(int16_t) +#define SAMPLES2TIME_MS(x) float(uint32_t(x) * 1000 / AUDIO_SAMPLE_RATE * sizeof(int16_t) +#define XSTR(x) STR(x) +#define STR(x) #x + +// Modulated delay options +#define MOD_NO_FILTER_OUTPUT 0 +#define MOD_BUTTERWORTH_FILTER_OUTPUT 1 +#define MOD_LINKWITZ_RILEY_FILTER_OUTPUT 2 + +#if defined(TEENSY_DAC_SYMMETRIC) +#define MONO_MIN 1 +#define MONO_MAX 1 +#define MONO_DEFAULT 1 +#else +#define MONO_MIN 0 +#define MONO_MAX 3 +#define MONO_DEFAULT 0 +#endif + +#define MIDI_CONTROLLER_MODE_MAX 2 + +#define VOLUME_MIN 0 +#define VOLUME_MAX 100 +#define VOLUME_DEFAULT 80 +//#define VOLUME_ENC_STEPS 5 + +#define PANORAMA_MIN 0 +#define PANORAMA_MAX 40 +#define PANORAMA_DEFAULT 20 + +#define MIDI_CHANNEL_MIN MIDI_CHANNEL_OMNI +#define MIDI_CHANNEL_MAX 16 +#define MIDI_CHANNEL_DEFAULT MIDI_CHANNEL_OMNI + +#define INSTANCE_LOWEST_NOTE_MIN 21 +#define INSTANCE_LOWEST_NOTE_MAX 108 +#define INSTANCE_LOWEST_NOTE_DEFAULT 21 + +#define INSTANCE_HIGHEST_NOTE_MIN 21 +#define INSTANCE_HIGHEST_NOTE_MAX 108 +#define INSTANCE_HIGHEST_NOTE_DEFAULT 108 + +#define CHORUS_FREQUENCY_MIN 0 +#define CHORUS_FREQUENCY_MAX 100 +#define CHORUS_FREQUENCY_DEFAULT 0 + +#define CHORUS_WAVEFORM_MIN 0 +#define CHORUS_WAVEFORM_MAX 1 +#define CHORUS_WAVEFORM_DEFAULT 0 + +#define CHORUS_DEPTH_MIN 0 +#define CHORUS_DEPTH_MAX 100 +#define CHORUS_DEPTH_DEFAULT 0 + +#define CHORUS_LEVEL_MIN 0 +#define CHORUS_LEVEL_MAX 100 +#define CHORUS_LEVEL_DEFAULT 0 + +#define DELAY_TIME_MIN 0 +#define DELAY_TIME_MAX DELAY_MAX_TIME/10 +#define DELAY_TIME_DEFAULT 0 + +#define DELAY_FEEDBACK_MIN 0 +#define DELAY_FEEDBACK_MAX 100 +#define DELAY_FEEDBACK_DEFAULT 0 + +#define DELAY_LEVEL_MIN 0 +#define DELAY_LEVEL_MAX 100 +#define DELAY_LEVEL_DEFAULT 0 + +#define DELAY_SYNC_MIN 0 +#define DELAY_SYNC_MAX 9 +#define DELAY_SYNC_DEFAULT 0 + +#define REVERB_ROOMSIZE_MIN 0 +#define REVERB_ROOMSIZE_MAX 100 +#define REVERB_ROOMSIZE_DEFAULT 0 + +#define REVERB_DAMPING_MIN 0 +#define REVERB_DAMPING_MAX 100 +#define REVERB_DAMPING_DEFAULT 0 + +#define REVERB_LOWPASS_MIN 0 +#define REVERB_LOWPASS_MAX 100 +#define REVERB_LOWPASS_DEFAULT 0 + +#define REVERB_LODAMP_MIN 0 +#define REVERB_LODAMP_MAX 100 +#define REVERB_LODAMP_DEFAULT 0 + +#define REVERB_HIDAMP_MIN 0 +#define REVERB_HIDAMP_MAX 100 +#define REVERB_HIDAMP_DEFAULT 0 + +#define REVERB_DIFFUSION_MIN 0 +#define REVERB_DIFFUSION_MAX 100 +#define REVERB_DIFFUSION_DEFAULT 0 + +#define REVERB_LEVEL_MIN 0 +#define REVERB_LEVEL_MAX 100 +#define REVERB_LEVEL_DEFAULT 0 + +#define REVERB_SEND_MIN 0 +#define REVERB_SEND_MAX 100 +#define REVERB_SEND_DEFAULT 0 + +#define FILTER_CUTOFF_MIN 0 +#define FILTER_CUTOFF_MAX 100 +#define FILTER_CUTOFF_DEFAULT 0 + +#define FILTER_RESONANCE_MIN 0 +#define FILTER_RESONANCE_MAX 100 +#define FILTER_RESONANCE_DEFAULT 0 + +#define TRANSPOSE_MIN 0 +#define TRANSPOSE_MAX 48 +#define TRANSPOSE_DEFAULT 12 + +#define TUNE_MIN 1 +#define TUNE_MAX 199 +#define TUNE_DEFAULT 100 + +#define SOUND_INTENSITY_MIN 0 +#define SOUND_INTENSITY_MAX 100 +#define SOUND_INTENSITY_DEFAULT 100 + +#define POLYPHONY_MIN 0 +#define POLYPHONY_MAX MAX_NOTES +#define POLYPHONY_DEFAULT MAX_NOTES / NUM_DEXED + +#define MONOPOLY_MIN 0 +#define MONOPOLY_MAX 1 +#define MONOPOLY_DEFAULT 0 + +#define NOTE_REFRESH_MIN 0 +#define NOTE_REFRESH_MAX 1 +#define NOTE_REFRESH_DEFAULT 0 + +#define PB_RANGE_MIN 0 +#define PB_RANGE_MAX 12 +#define PB_RANGE_DEFAULT 1 + +#define PB_STEP_MIN 0 +#define PB_STEP_MAX 12 +#define PB_STEP_DEFAULT 0 + +#define MW_RANGE_MIN 0 +#define MW_RANGE_MAX 99 +#define MW_RANGE_DEFAULT 50 + +#define MW_ASSIGN_MIN 0 +#define MW_ASSIGN_MAX 7 +#define MW_ASSIGN_DEFAULT 0 // Bitmapped: 0: Pitch, 1: Amp, 2: Bias + +#define MW_MODE_MIN 0 +#define MW_MODE_MAX MIDI_CONTROLLER_MODE_MAX +#define MW_MODE_DEFAULT 0 + +#define FC_RANGE_MIN 0 +#define FC_RANGE_MAX 99 +#define FC_RANGE_DEFAULT 50 + +#define FC_ASSIGN_MIN 0 +#define FC_ASSIGN_MAX 7 +#define FC_ASSIGN_DEFAULT 0 // Bitmapped: 0: Pitch, 1: Amp, 2: Bias + +#define FC_MODE_MIN 0 +#define FC_MODE_MAX MIDI_CONTROLLER_MODE_MAX +#define FC_MODE_DEFAULT 0 + +#define BC_RANGE_MIN 0 +#define BC_RANGE_MAX 99 +#define BC_RANGE_DEFAULT 50 + +#define BC_ASSIGN_MIN 0 +#define BC_ASSIGN_MAX 7 +#define BC_ASSIGN_DEFAULT 0 // Bitmapped: 0: Pitch, 1: Amp, 2: Bias + +#define BC_MODE_MIN 0 +#define BC_MODE_MAX MIDI_CONTROLLER_MODE_MAX +#define BC_MODE_DEFAULT 0 + +#define AT_RANGE_MIN 0 +#define AT_RANGE_MAX 99 +#define AT_RANGE_DEFAULT 50 + +#define AT_ASSIGN_MIN 0 +#define AT_ASSIGN_MAX 7 +#define AT_ASSIGN_DEFAULT 0 // Bitmapped: 0: Pitch, 1: Amp, 2: Bias + +#define AT_MODE_MIN 0 +#define AT_MODE_MAX MIDI_CONTROLLER_MODE_MAX +#define AT_MODE_DEFAULT 0 + +#define OP_ENABLED_MIN 0 +#define OP_ENABLED_MAX 0x3f +#define OP_ENABLED_DEFAULT OP_ENABLED_MAX + +#define PORTAMENTO_MODE_MIN 0 +#define PORTAMENTO_MODE_MAX 1 +#define PORTAMENTO_MODE_DEFAULT 0 // 0: Retain, 1: Follow + +#define PORTAMENTO_GLISSANDO_MIN 0 +#define PORTAMENTO_GLISSANDO_MAX 1 +#define PORTAMENTO_GLISSANDO_DEFAULT 0 + +#define PORTAMENTO_TIME_MIN 0 +#define PORTAMENTO_TIME_MAX 99 +#define PORTAMENTO_TIME_DEFAULT 0 + +#define INSTANCES_MIN 1 +#define INSTANCES_MAX NUM_DEXED +#define INSTANCES_DEFAULT 1 + +#define INSTANCE_NOTE_START_MIN MIDI_AIS0 +#define INSTANCE_NOTE_START_MAX MIDI_B7 +#define INSTANCE_NOTE_START_DEFAULT INSTANCE_NOTE_START_MIN + +#define INSTANCE_NOTE_END_MIN MIDI_AIS0 +#define INSTANCE_NOTE_END_MAX MIDI_B7 +#define INSTANCE_NOTE_END_DEFAULT INSTANCE_NOTE_END_MAX + +#define SOFT_MIDI_THRU_MIN 0 +#define SOFT_MIDI_THRU_MAX 1 +#define SOFT_MIDI_THRU_DEFAULT 1 + +#define VELOCITY_LEVEL_MIN 100 +#define VELOCITY_LEVEL_MAX 127 +#define VELOCITY_LEVEL_DEFAULT 100 + +#define PERFORMANCE_NUM_MIN 0 +#define PERFORMANCE_NUM_MAX MAX_PERFORMANCE +#define PERFORMANCE_NUM_DEFAULT -1 + +#define FX_NUM_MIN 0 +#define FX_NUM_MAX MAX_FX +#define FX_NUM_DEFAULT -1 + +#define VOICECONFIG_NUM_MIN 0 +#define VOICECONFIG_NUM_MAX MAX_VOICECONFIG +#define VOICECONFIG_NUM_DEFAULT -1 + +#define EQ_1_MIN 15 +#define EQ_1_MAX 250 +#define EQ_1_DEFAULT 50 + +#define EQ_2_MIN -99 +#define EQ_2_MAX 99 +#define EQ_2_DEFAULT 0 + +#define EQ_3_MIN -99 +#define EQ_3_MAX 99 +#define EQ_3_DEFAULT 0 + +#define EQ_4_MIN -99 +#define EQ_4_MAX 99 +#define EQ_4_DEFAULT 0 + +#define EQ_5_MIN -99 +#define EQ_5_MAX 99 +#define EQ_5_DEFAULT 0 + +#define EQ_6_MIN -99 +#define EQ_6_MAX 99 +#define EQ_6_DEFAULT 0 + +#define EQ_7_MIN 8 +#define EQ_7_MAX 18 +#define EQ_7_DEFAULT 15 + +// Buffer-size define for load/save configuration as JSON + +#define JSON_BUFFER_SIZE 7168 + +// Internal configuration structure +typedef struct dexed_s { + uint8_t lowest_note; + uint8_t highest_note; + uint8_t transpose; + uint8_t tune; + uint8_t sound_intensity; + uint8_t pan; + uint8_t polyphony; + uint8_t velocity_level; + uint8_t monopoly; + uint8_t note_refresh; + uint8_t pb_range; + uint8_t pb_step; + uint8_t mw_range; + uint8_t mw_assign; + uint8_t mw_mode; + uint8_t fc_range; + uint8_t fc_assign; + uint8_t fc_mode; + uint8_t bc_range; + uint8_t bc_assign; + uint8_t bc_mode; + uint8_t at_range; + uint8_t at_assign; + uint8_t at_mode; + uint8_t portamento_mode; + uint8_t portamento_glissando; + uint8_t portamento_time; + uint8_t op_enabled; + uint8_t midi_channel; +} dexed_t; + +typedef struct fx_s { + uint8_t filter_cutoff[MAX_DEXED]; + uint8_t filter_resonance[MAX_DEXED]; + uint8_t chorus_frequency[MAX_DEXED]; + uint8_t chorus_waveform[MAX_DEXED]; + uint8_t chorus_depth[MAX_DEXED]; + uint8_t chorus_level[MAX_DEXED]; + uint8_t delay_time[MAX_DEXED]; + uint8_t delay_feedback[MAX_DEXED]; + uint8_t delay_level[MAX_DEXED]; + uint8_t delay_sync[MAX_DEXED]; + uint8_t reverb_send[MAX_DEXED]; + uint8_t reverb_roomsize; + uint8_t reverb_damping; + uint8_t reverb_lowpass; + uint8_t reverb_lodamp; + uint8_t reverb_hidamp; + uint8_t reverb_diffusion; + uint8_t reverb_level; + uint8_t eq_1; + int8_t eq_2; + int8_t eq_3; + int8_t eq_4; + int8_t eq_5; + int8_t eq_6; + uint8_t eq_7; +} fx_t; + +typedef struct performance_s { + uint8_t bank[MAX_DEXED]; + uint8_t voice[MAX_DEXED]; + int8_t voiceconfig_number[MAX_DEXED]; + int8_t fx_number; +} performance_t; + +typedef struct sys_s { + uint8_t instances; + uint8_t vol; + uint8_t mono; + uint8_t soft_midi_thru; + int8_t performance_number; + uint8_t favorites; +} sys_t; + +typedef struct configuration_s { + sys_t sys; + fx_t fx; + performance_t performance; + dexed_t dexed[MAX_DEXED]; + uint16_t _marker_; +} config_t; + +#if !defined(_MAPFLOAT) +#define _MAPFLOAT +inline float mapfloat(float val, float in_min, float in_max, float out_min, float out_max) +{ + return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} +#endif