diff --git a/MicroDexed.ino b/MicroDexed.ino index 145beeb..49551e6 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -614,6 +614,10 @@ void loop() // MIDI input handling check_midi_devices(); + // check encoder + ENCODER[ENC_L].update(); + ENCODER[ENC_R].update(); + // CONTROL-RATE-EVENT-HANDLING if (control_rate > CONTROL_RATE_MS) { diff --git a/UI.hpp b/UI.hpp index 63deae9..8b6fb74 100644 --- a/UI.hpp +++ b/UI.hpp @@ -33,7 +33,8 @@ #include "dexed.h" #include -#include +//#include +#include #define _LCDML_DISP_cols LCD_cols #define _LCDML_DISP_rows LCD_rows @@ -235,8 +236,8 @@ LCDML_createMenu(_LCDML_DISP_cnt); #define g_LCDML_CONTROL_button_long_press LONG_BUTTON_PRESS #define g_LCDML_CONTROL_button_short_press BUT_DEBOUNCE_MS -//#define ENCODER_OPTIMIZE_INTERRUPTS //Only when using pin2/3 (or 20/21 on mega) -Encoder ENCODER[NUM_ENCODER] = {Encoder(ENC_R_PIN_B, ENC_R_PIN_A), Encoder(ENC_L_PIN_B, ENC_L_PIN_A)}; +//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)}; long g_LCDML_CONTROL_button_press_time[NUM_ENCODER] = {0, 0}; bool g_LCDML_CONTROL_button_prev[NUM_ENCODER] = {HIGH, HIGH}; @@ -293,10 +294,10 @@ void setup_ui(void) { void setup_debug_message(void) { // LCD Begin lcd.clear(); - lcd.setCursor(3, 0); - lcd.print(F("DEBUG MODE")); - lcd.setCursor(0, 1); - lcd.print(F("ENABLE CONSOLE!")); + lcd.setCursor(1, 0); + lcd.print(F("* DEBUG MODE *")); + lcd.setCursor(1, 1); + lcd.print(F("ENABLE CONSOLE")); } #endif @@ -307,6 +308,9 @@ void lcdml_menu_control(void) { pinMode(BUT_R_PIN, INPUT_PULLUP); pinMode(BUT_L_PIN, INPUT_PULLUP); + + ENCODER[ENC_L].begin(); + ENCODER[ENC_R].begin(); } if (back_from_volume > BACK_FROM_VOLUME_MS && menu_state == MENU_VOLUME) @@ -444,6 +448,8 @@ void lcdml_menu_control(void) void encoder_right_up(void) { uint8_t instance_id = 0; + int8_t voice_tmp; + uint8_t bank_tmp; if (LCDML.FUNC_getID() > MENU_ID_OF_INSTANCE_2 && LCDML.FUNC_getID() != 255) instance_id = 1; @@ -462,31 +468,32 @@ void encoder_right_up(void) switch (menu_voice) { case MENU_VOICE_BANK: - if (configuration.dexed[instance_id].bank < MAX_BANKS - 1) - { - configuration.dexed[instance_id].bank++; + bank_tmp = constrain(configuration.dexed[instance_id].bank + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + configuration.dexed[instance_id].bank = bank_tmp; #ifdef DISPLAY_LCD_SPI - change_disp_sd(false); + change_disp_sd(false); #endif - load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id); - get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id); + load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id); + get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id); #ifdef DISPLAY_LCD_SPI - change_disp_sd(true); + change_disp_sd(true); #endif - eeprom_write(); - } + eeprom_write(); break; case MENU_VOICE_SOUND: - if (configuration.dexed[instance_id].voice < MAX_VOICES - 1) - configuration.dexed[instance_id].voice++; - else + voice_tmp = configuration.dexed[instance_id].voice + ENCODER[ENC_R].speed(); + if (voice_tmp >= MAX_VOICES && configuration.dexed[instance_id].bank + 1 < MAX_BANKS) { - if (configuration.dexed[instance_id].bank < MAX_BANKS - 1) - { - configuration.dexed[instance_id].bank++; - configuration.dexed[instance_id].voice = 0; - } + voice_tmp %= MAX_VOICES; + configuration.dexed[instance_id].bank++; + configuration.dexed[instance_id].bank = constrain(configuration.dexed[instance_id].bank, 0, MAX_BANKS - 1); + } + else if (voice_tmp >= MAX_VOICES && configuration.dexed[instance_id].bank + 1 >= MAX_BANKS) + { + voice_tmp = MAX_VOICES - 1; } + configuration.dexed[instance_id].voice = voice_tmp; + #ifdef DISPLAY_LCD_SPI change_disp_sd(false); #endif @@ -496,6 +503,7 @@ void encoder_right_up(void) change_disp_sd(true); #endif eeprom_write(); + break; } UI_func_voice_selection(0); break; @@ -505,6 +513,8 @@ void encoder_right_up(void) void encoder_right_down(void) { uint8_t instance_id = 0; + int8_t voice_tmp; + uint8_t bank_tmp; if (LCDML.FUNC_getID() > MENU_ID_OF_INSTANCE_2 && LCDML.FUNC_getID() != 255) instance_id = 1; @@ -523,32 +533,33 @@ void encoder_right_down(void) switch (menu_voice) { case MENU_VOICE_BANK: - if (configuration.dexed[instance_id].bank > 0) - { - configuration.dexed[instance_id].bank--; + bank_tmp = constrain(configuration.dexed[instance_id].bank - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + configuration.dexed[instance_id].bank = bank_tmp; #ifdef DISPLAY_LCD_SPI - change_disp_sd(false); + change_disp_sd(false); #endif - - load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id); - get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id); + load_sysex(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id); + get_voice_names_from_bank(configuration.dexed[instance_id].bank, instance_id); #ifdef DISPLAY_LCD_SPI - change_disp_sd(true); + change_disp_sd(true); #endif - eeprom_write(); - } + eeprom_write(); break; case MENU_VOICE_SOUND: - if (configuration.dexed[instance_id].voice > 0) - configuration.dexed[instance_id].voice--; - else + voice_tmp = configuration.dexed[instance_id].voice - ENCODER[ENC_R].speed(); + if (voice_tmp < 0 && configuration.dexed[instance_id].bank - 1 >= 0) { - if (configuration.dexed[instance_id].bank > 0) - { - configuration.dexed[instance_id].bank--; - configuration.dexed[instance_id].voice = 31; - } + configuration.dexed[instance_id].bank--; + configuration.dexed[instance_id].bank = constrain(configuration.dexed[instance_id].bank, 0, MAX_BANKS - 1); } + else if (voice_tmp < 0 && configuration.dexed[instance_id].bank - 1 <= 0) + { + voice_tmp = 0; + } + if (voice_tmp < 0) + voice_tmp = MAX_VOICES + voice_tmp; + configuration.dexed[instance_id].voice = voice_tmp; + #ifdef DISPLAY_LCD_SPI change_disp_sd(false); #endif @@ -558,6 +569,7 @@ void encoder_right_down(void) change_disp_sd(true); #endif eeprom_write(); + break; } UI_func_voice_selection(0); break; @@ -602,7 +614,7 @@ void encoder_left_up(void) #ifdef DEBUG Serial.println(F("Volume +")); #endif - configuration.vol = constrain(configuration.vol + VOLUME_ENC_STEPS, VOLUME_MIN, VOLUME_MAX); + configuration.vol = constrain(configuration.vol + ENCODER[ENC_L].speed(), VOLUME_MIN, VOLUME_MAX); //eeprom_write(); //set_volume(configuration.vol, configuration.mono); @@ -614,7 +626,7 @@ void encoder_left_down(void) #ifdef DEBUG Serial.println(F("Volume -")); #endif - configuration.vol = constrain(configuration.vol - VOLUME_ENC_STEPS, VOLUME_MIN, VOLUME_MAX); + configuration.vol = constrain(configuration.vol - ENCODER[ENC_L].speed(), VOLUME_MIN, VOLUME_MAX); //eeprom_write(); //set_volume(configuration.vol, configuration.mono); @@ -818,19 +830,9 @@ void UI_func_reverb_roomsize(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.reverb_roomsize < REVERB_ROOMSIZE_MAX) - { - configuration.reverb_roomsize++; - } - } + configuration.reverb_roomsize = constrain(configuration.reverb_roomsize + ENCODER[ENC_R].speed(), REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.reverb_roomsize > REVERB_ROOMSIZE_MIN) - { - configuration.reverb_roomsize--; - } - } + configuration.reverb_roomsize = constrain(configuration.reverb_roomsize - ENCODER[ENC_R].speed(), REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX); freeverb_r.roomsize(mapfloat(configuration.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); freeverb_l.roomsize(mapfloat(configuration.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0)); @@ -864,19 +866,9 @@ void UI_func_reverb_damping(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.reverb_damping < REVERB_DAMPING_MAX) - { - configuration.reverb_damping++; - } - } + configuration.reverb_damping = constrain(configuration.reverb_damping + ENCODER[ENC_R].speed(), REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.reverb_damping > REVERB_DAMPING_MIN) - { - configuration.reverb_damping--; - } - } + configuration.reverb_damping = constrain(configuration.reverb_damping - ENCODER[ENC_R].speed(), REVERB_DAMPING_MIN, REVERB_DAMPING_MAX); freeverb_r.damping(mapfloat(configuration.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0)); freeverb_l.damping(mapfloat(configuration.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0)); @@ -915,20 +907,9 @@ void UI_func_reverb_send(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].reverb_send < REVERB_SEND_MAX) - { - configuration.dexed[instance_id].reverb_send++; - } - } + configuration.dexed[instance_id].reverb_send = constrain(configuration.dexed[instance_id].reverb_send + ENCODER[ENC_R].speed(), REVERB_SEND_MIN, REVERB_SEND_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].reverb_send > REVERB_SEND_MIN) - { - configuration.dexed[instance_id].reverb_send--; - - } - } + configuration.dexed[instance_id].reverb_send = constrain(configuration.dexed[instance_id].reverb_send - ENCODER[ENC_R].speed(), REVERB_SEND_MIN, REVERB_SEND_MAX); reverb_send_mixer_r.gain(instance_id, configuration.dexed[instance_id].reverb_send / 100.0); reverb_send_mixer_l.gain(instance_id, configuration.dexed[instance_id].reverb_send / 100.0); @@ -962,19 +943,9 @@ void UI_func_reverb_level(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.reverb_level < REVERB_LEVEL_MAX) - { - configuration.reverb_level++; - } - } + configuration.reverb_level = constrain(configuration.reverb_level + ENCODER[ENC_R].speed(), REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.reverb_level > REVERB_LEVEL_MIN) - { - configuration.reverb_level--; - } - } + configuration.reverb_level = constrain(configuration.reverb_level - ENCODER[ENC_R].speed(), REVERB_LEVEL_MIN, REVERB_LEVEL_MAX); master_mixer_r.gain(REVERB, mapfloat(configuration.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0)); master_mixer_l.gain(REVERB, mapfloat(configuration.reverb_level, REVERB_LEVEL_MIN, REVERB_LEVEL_MAX, 0.0, 1.0)); @@ -1008,19 +979,9 @@ void UI_func_chorus_frequency(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.chorus_frequency < CHORUS_FREQUENCY_MAX) - { - configuration.chorus_frequency++; - } - } + configuration.chorus_frequency = constrain(configuration.chorus_frequency + ENCODER[ENC_R].speed(), CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.chorus_frequency > CHORUS_FREQUENCY_MIN) - { - configuration.chorus_frequency--; - } - } + configuration.chorus_frequency = constrain(configuration.chorus_frequency - ENCODER[ENC_R].speed(), CHORUS_FREQUENCY_MIN, CHORUS_FREQUENCY_MAX); chorus_modulator.frequency(configuration.chorus_frequency / 10.0); } @@ -1048,23 +1009,11 @@ void UI_func_chorus_waveform(uint8_t param) if (LCDML.FUNC_loop()) // ****** LOOP ********* { if (LCDML.BT_checkEnter()) - { LCDML.FUNC_goBackToMenu(); - } else if (LCDML.BT_checkDown()) - { - if (configuration.chorus_waveform < CHORUS_WAVEFORM_MAX) - { - configuration.chorus_waveform++; - } - } + configuration.chorus_waveform = constrain(configuration.chorus_waveform + 1, CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.chorus_waveform > CHORUS_WAVEFORM_MIN) - { - configuration.chorus_waveform--; - } - } + configuration.chorus_waveform = constrain(configuration.chorus_waveform - 1, CHORUS_WAVEFORM_MIN, CHORUS_WAVEFORM_MAX); lcd.setCursor(0, 1); switch (configuration.chorus_waveform) @@ -1109,19 +1058,9 @@ void UI_func_chorus_depth(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.chorus_depth < CHORUS_DEPTH_MAX) - { - configuration.chorus_depth++; - } - } + configuration.chorus_depth = constrain(configuration.chorus_depth + ENCODER[ENC_R].speed(), CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.chorus_depth > CHORUS_DEPTH_MIN) - { - configuration.chorus_depth--; - } - } + configuration.chorus_depth = constrain(configuration.chorus_depth - ENCODER[ENC_R].speed(), CHORUS_DEPTH_MIN, CHORUS_DEPTH_MAX); chorus_modulator.amplitude(configuration.chorus_depth / 100.0); } @@ -1160,19 +1099,9 @@ void UI_func_chorus_send(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].chorus_send < CHORUS_SEND_MAX) - { - configuration.dexed[instance_id].chorus_send++; - } - } + configuration.dexed[instance_id].chorus_send = constrain(configuration.dexed[instance_id].chorus_send + ENCODER[ENC_R].speed(), CHORUS_SEND_MIN, CHORUS_SEND_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].chorus_send > CHORUS_SEND_MIN) - { - configuration.dexed[instance_id].chorus_send--; - } - } + configuration.dexed[instance_id].chorus_send = constrain(configuration.dexed[instance_id].chorus_send - ENCODER[ENC_R].speed(), CHORUS_SEND_MIN, CHORUS_SEND_MAX); chorus_send_mixer_r.gain(instance_id, configuration.dexed[instance_id].chorus_send / 100.0); chorus_send_mixer_l.gain(instance_id, configuration.dexed[instance_id].chorus_send / 100.0); @@ -1207,19 +1136,9 @@ void UI_func_chorus_level(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.chorus_level < CHORUS_LEVEL_MAX) - { - configuration.chorus_level++; - } - } + configuration.chorus_level = constrain(configuration.chorus_level + ENCODER[ENC_R].speed(), CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.chorus_level > CHORUS_LEVEL_MIN) - { - configuration.chorus_level--; - } - } + configuration.chorus_level = constrain(configuration.chorus_level - ENCODER[ENC_R].speed(), CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX); master_mixer_r.gain(CHORUS, mapfloat(configuration.chorus_level, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 1.0)); master_mixer_l.gain(CHORUS, mapfloat(configuration.chorus_level, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 1.0)); @@ -1253,19 +1172,9 @@ void UI_func_delay_time(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.delay_time < DELAY_TIME_MAX / 10) - { - configuration.delay_time += 1; - } - } + configuration.delay_time = constrain(configuration.delay_time + ENCODER[ENC_R].speed(), DELAY_TIME_MIN, DELAY_TIME_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.delay_time > DELAY_TIME_MIN) - { - configuration.delay_time -= 1; - } - } + configuration.delay_time = constrain(configuration.delay_time - ENCODER[ENC_R].speed(), DELAY_TIME_MIN, DELAY_TIME_MAX); delay_r.delay(0, configuration.delay_time * 10); delay_l.delay(0, configuration.delay_time * 10); @@ -1301,19 +1210,9 @@ void UI_func_delay_feedback(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.delay_feedback < DELAY_FEEDBACK_MAX) - { - configuration.delay_feedback++; - } - } + configuration.delay_feedback = constrain(configuration.delay_feedback + ENCODER[ENC_R].speed(), DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.delay_feedback > DELAY_FEEDBACK_MIN) - { - configuration.delay_feedback--; - } - } + configuration.delay_feedback = constrain(configuration.delay_feedback - ENCODER[ENC_R].speed(), DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); delay_fb_mixer_r.gain(1, configuration.delay_feedback / 100.0); // amount of feedback delay_fb_mixer_l.gain(1, configuration.delay_feedback / 100.0); // amount of feedback @@ -1354,28 +1253,18 @@ void UI_func_delay_send(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].delay_send < DELAY_SEND_MAX) - { - configuration.dexed[instance_id].delay_send++; - } - } + configuration.dexed[instance_id].delay_send = constrain(configuration.dexed[instance_id].delay_send + ENCODER[ENC_R].speed(), DELAY_SEND_MIN, DELAY_SEND_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].delay_send > DELAY_SEND_MIN) - { - configuration.dexed[instance_id].delay_send--; - } - } + configuration.dexed[instance_id].delay_send = constrain(configuration.dexed[instance_id].delay_send - ENCODER[ENC_R].speed(), DELAY_SEND_MIN, DELAY_SEND_MAX); delay_send_mixer_r.gain(instance_id, configuration.dexed[instance_id].delay_send / 100.0); delay_send_mixer_l.gain(instance_id, configuration.dexed[instance_id].delay_send / 100.0); } - - lcd.setCursor(0, 1); - lcd_display_int(configuration.dexed[instance_id].delay_send, 3, true, true, false); } + lcd.setCursor(0, 1); + lcd_display_int(configuration.dexed[instance_id].delay_send, 3, true, true, false); + if (LCDML.FUNC_close()) // ****** STABLE END ********* { // you can here reset some global vars or do nothing @@ -1401,19 +1290,9 @@ void UI_func_delay_level(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.delay_level < DELAY_LEVEL_MAX) - { - configuration.delay_level++; - } - } + configuration.delay_level = constrain(configuration.delay_level + ENCODER[ENC_R].speed(), DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.delay_level > DELAY_LEVEL_MIN) - { - configuration.delay_level--; - } - } + configuration.delay_level = constrain(configuration.delay_level - ENCODER[ENC_R].speed(), DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); master_mixer_r.gain(DELAY, mapfloat(configuration.delay_level, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0)); master_mixer_l.gain(DELAY, mapfloat(configuration.delay_level, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0)); @@ -1428,7 +1307,6 @@ void UI_func_delay_level(uint8_t param) eeprom_write(); } } -#endif void UI_func_filter_cutoff(uint8_t param) { @@ -1453,19 +1331,9 @@ void UI_func_filter_cutoff(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].filter_cutoff < FILTER_CUTOFF_MAX) - { - configuration.dexed[instance_id].filter_cutoff++; - } - } + configuration.dexed[instance_id].filter_cutoff = constrain(configuration.dexed[instance_id].filter_cutoff + ENCODER[ENC_R].speed(), FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].filter_cutoff > FILTER_CUTOFF_MIN) - { - configuration.dexed[instance_id].filter_cutoff--; - } - } + configuration.dexed[instance_id].filter_cutoff = constrain(configuration.dexed[instance_id].filter_cutoff - ENCODER[ENC_R].speed(), FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX); MicroDexed[instance_id]->fx.Cutoff = mapfloat(configuration.dexed[instance_id].filter_cutoff, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0); } @@ -1504,19 +1372,9 @@ void UI_func_filter_resonance(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].filter_resonance < FILTER_RESONANCE_MAX) - { - configuration.dexed[instance_id].filter_resonance++; - } - } + configuration.dexed[instance_id].filter_resonance = constrain(configuration.dexed[instance_id].filter_resonance + ENCODER[ENC_R].speed(), FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].filter_resonance > FILTER_RESONANCE_MIN) - { - configuration.dexed[instance_id].filter_resonance--; - } - } + configuration.dexed[instance_id].filter_resonance = constrain(configuration.dexed[instance_id].filter_resonance - ENCODER[ENC_R].speed(), FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); MicroDexed[instance_id]->fx.Reso = mapfloat(configuration.dexed[instance_id].filter_resonance, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0); } @@ -1531,6 +1389,7 @@ void UI_func_filter_resonance(uint8_t param) eeprom_write(); } } +#endif void UI_func_transpose(uint8_t param) { @@ -1555,19 +1414,9 @@ void UI_func_transpose(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].transpose < TRANSPOSE_MAX) - { - configuration.dexed[instance_id].transpose++; - } - } + configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose + ENCODER[ENC_R].speed(), TRANSPOSE_MIN, TRANSPOSE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].transpose > TRANSPOSE_MIN) - { - configuration.dexed[instance_id].transpose--; - } - } + configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose - ENCODER[ENC_R].speed(), TRANSPOSE_MIN, TRANSPOSE_MAX); MicroDexed[instance_id]->data[DEXED_VOICE_OFFSET + DEXED_TRANSPOSE] = configuration.dexed[instance_id].transpose; MicroDexed[instance_id]->notesOff(); @@ -1609,15 +1458,9 @@ void UI_func_tune(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].tune < TUNE_MAX) - configuration.dexed[instance_id].tune++; - } + configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune + ENCODER[ENC_R].speed(), TUNE_MIN, TUNE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].tune > TUNE_MIN) - configuration.dexed[instance_id].tune--; - } + configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune - ENCODER[ENC_R].speed(), TUNE_MIN, TUNE_MAX); MicroDexed[instance_id]->controllers.masterTune = (int((configuration.dexed[instance_id].tune - 100) / 100.0 * 0x4000) << 11) * (1.0 / 12); MicroDexed[instance_id]->doRefreshVoice(); @@ -1655,21 +1498,11 @@ void UI_func_midi_channel(uint8_t param) LCDML.FUNC_goBackToMenu(); } else if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].midi_channel < MIDI_CHANNEL_MAX) - { - configuration.dexed[instance_id].midi_channel++; - } - } + configuration.dexed[instance_id].midi_channel = constrain(configuration.dexed[instance_id].midi_channel + ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].midi_channel > MIDI_CHANNEL_MIN) - { - configuration.dexed[instance_id].midi_channel--; - } - } - lcd.setCursor(0, 1); + configuration.dexed[instance_id].midi_channel = constrain(configuration.dexed[instance_id].midi_channel - ENCODER[ENC_R].speed(), MIDI_CHANNEL_MIN, MIDI_CHANNEL_MAX); + lcd.setCursor(0, 1); if (configuration.dexed[instance_id].midi_channel == 0) { lcd.print(F("[OMNI]")); @@ -1711,21 +1544,10 @@ void UI_func_sound_intensity(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].sound_intensity < SOUND_INTENSITY_MAX) - { - configuration.dexed[instance_id].sound_intensity++; - } - } + configuration.dexed[instance_id].sound_intensity = constrain(configuration.dexed[instance_id].sound_intensity + ENCODER[ENC_R].speed(), SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].sound_intensity > SOUND_INTENSITY_MIN) - { - configuration.dexed[instance_id].sound_intensity--; - } - } + configuration.dexed[instance_id].sound_intensity = constrain(configuration.dexed[instance_id].sound_intensity - ENCODER[ENC_R].speed(), SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX); - //MicroDexed[instance_id]->fx.Gain = configuration.dexed[instance_id].sound_intensity / 100.0; dexed_level[instance_id]->gain(mapfloat(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0.0, SOUND_INTENSITY_AMP_MAX)); } @@ -1767,19 +1589,9 @@ void UI_func_panorama(uint8_t param) LCDML.FUNC_goBackToMenu(); } else if (LCDML.BT_checkDown() && configuration.mono == 0) - { - if (configuration.dexed[instance_id].pan < PANORAMA_MAX) - { - configuration.dexed[instance_id].pan++; - } - } + configuration.dexed[instance_id].pan = constrain(configuration.dexed[instance_id].pan + ENCODER[ENC_R].speed(), PANORAMA_MIN, PANORAMA_MAX); else if (LCDML.BT_checkUp() && configuration.mono == 0) - { - if (configuration.dexed[instance_id].pan > PANORAMA_MIN) - { - configuration.dexed[instance_id].pan--; - } - } + configuration.dexed[instance_id].pan = constrain(configuration.dexed[instance_id].pan - ENCODER[ENC_R].speed(), PANORAMA_MIN, PANORAMA_MAX); if (configuration.mono == 0) { @@ -1808,23 +1620,12 @@ void UI_func_stereo_mono(uint8_t param) if (LCDML.FUNC_loop()) // ****** LOOP ********* { if (LCDML.BT_checkEnter()) - { LCDML.FUNC_goBackToMenu(); - } else if (LCDML.BT_checkDown()) - { - if (configuration.mono < MONO_MAX) - { - configuration.mono++; - } - } + configuration.mono = constrain(configuration.mono + 1, MONO_MIN, MONO_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.mono > MONO_MIN) - { - configuration.mono--; - } - } + configuration.mono = constrain(configuration.mono - 1, MONO_MIN, MONO_MAX); + lcd.setCursor(0, 1); switch (configuration.mono) { @@ -1878,19 +1679,9 @@ void UI_func_polyphony(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].polyphony < POLYPHONY_MAX) - { - configuration.dexed[instance_id].polyphony++; - } - } + configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony + ENCODER[ENC_R].speed(), POLYPHONY_MIN, POLYPHONY_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].polyphony > POLYPHONY_MIN) - { - configuration.dexed[instance_id].polyphony--; - } - } + configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony - ENCODER[ENC_R].speed(), POLYPHONY_MIN, POLYPHONY_MAX); MicroDexed[instance_id]->setMaxNotes(configuration.dexed[instance_id].polyphony); } @@ -1929,19 +1720,9 @@ void UI_func_engine(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].engine < ENGINE_MAX) - { - configuration.dexed[instance_id].engine++; - } - } + configuration.dexed[instance_id].engine = constrain(configuration.dexed[instance_id].engine + 1, ENGINE_MIN, ENGINE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].engine > ENGINE_MIN) - { - configuration.dexed[instance_id].engine--; - } - } + configuration.dexed[instance_id].engine = constrain(configuration.dexed[instance_id].engine - 1, ENGINE_MIN, ENGINE_MAX); MicroDexed[instance_id]->setEngineType(configuration.dexed[instance_id].engine); } @@ -1991,19 +1772,9 @@ void UI_func_mono_poly(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].monopoly < MONOPOLY_MAX) - { - configuration.dexed[instance_id].monopoly++; - } - } + configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly + 1, MONOPOLY_MIN, MONOPOLY_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].monopoly > MONOPOLY_MIN) - { - configuration.dexed[instance_id].monopoly--; - } - } + configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly - 1, MONOPOLY_MIN, MONOPOLY_MAX); MicroDexed[instance_id]->setMonoMode(!configuration.dexed[instance_id].monopoly); } @@ -2050,19 +1821,9 @@ void UI_func_note_refresh(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].note_refresh < NOTE_REFRESH_MAX) - { - configuration.dexed[instance_id].note_refresh++; - } - } + configuration.dexed[instance_id].note_refresh = constrain(configuration.dexed[instance_id].note_refresh + 1, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].note_refresh > NOTE_REFRESH_MIN) - { - configuration.dexed[instance_id].note_refresh--; - } - } + configuration.dexed[instance_id].note_refresh = constrain(configuration.dexed[instance_id].note_refresh - 1, NOTE_REFRESH_MIN, NOTE_REFRESH_MAX); MicroDexed[instance_id]->setRefreshMode(configuration.dexed[instance_id].note_refresh); } @@ -2109,19 +1870,9 @@ void UI_func_pb_range(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].pb_range < PB_RANGE_MAX) - { - configuration.dexed[instance_id].pb_range++; - } - } + configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range + ENCODER[ENC_R].speed(), PB_RANGE_MIN, PB_RANGE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].pb_range > PB_RANGE_MIN) - { - configuration.dexed[instance_id].pb_range--; - } - } + configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range - ENCODER[ENC_R].speed(), PB_RANGE_MIN, PB_RANGE_MAX); MicroDexed[instance_id]->setPBController(configuration.dexed[instance_id].pb_range, configuration.dexed[instance_id].pb_step); } @@ -2159,19 +1910,9 @@ void UI_func_pb_step(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].pb_step < PB_STEP_MAX) - { - configuration.dexed[instance_id].pb_step++; - } - } + configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step + ENCODER[ENC_R].speed(), PB_STEP_MIN, PB_STEP_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].pb_step > PB_STEP_MIN) - { - configuration.dexed[instance_id].pb_step--; - } - } + configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step - ENCODER[ENC_R].speed(), PB_STEP_MIN, PB_STEP_MAX); MicroDexed[instance_id]->setPBController(configuration.dexed[instance_id].pb_range, configuration.dexed[instance_id].pb_step); } @@ -2210,19 +1951,9 @@ void UI_func_mw_range(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].mw_range < MW_RANGE_MAX) - { - configuration.dexed[instance_id].mw_range++; - } - } + configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range + ENCODER[ENC_R].speed(), MW_RANGE_MIN, MW_RANGE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].mw_range > MW_RANGE_MIN) - { - configuration.dexed[instance_id].mw_range--; - } - } + configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range - ENCODER[ENC_R].speed(), MW_RANGE_MIN, MW_RANGE_MAX); MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign, configuration.dexed[instance_id].mw_mode); } @@ -2261,19 +1992,9 @@ void UI_func_mw_assign(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].mw_assign < MW_ASSIGN_MAX) - { - configuration.dexed[instance_id].mw_assign++; - } - } + configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign + 1, MW_ASSIGN_MIN, MW_ASSIGN_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].mw_assign > MW_ASSIGN_MIN) - { - configuration.dexed[instance_id].mw_assign--; - } - } + configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign - 1, MW_ASSIGN_MIN, MW_ASSIGN_MAX); MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign, configuration.dexed[instance_id].mw_mode); } @@ -2338,19 +2059,9 @@ void UI_func_mw_mode(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].mw_mode < MW_MODE_MAX) - { - configuration.dexed[instance_id].mw_mode++; - } - } + configuration.dexed[instance_id].mw_mode = constrain(configuration.dexed[instance_id].mw_mode + 1, MW_MODE_MIN, MW_MODE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].mw_mode > MW_MODE_MIN) - { - configuration.dexed[instance_id].mw_mode--; - } - } + configuration.dexed[instance_id].mw_mode = constrain(configuration.dexed[instance_id].mw_mode - 1, MW_MODE_MIN, MW_MODE_MAX); MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign, configuration.dexed[instance_id].mw_mode); } @@ -2397,19 +2108,9 @@ void UI_func_fc_range(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].fc_range < FC_RANGE_MAX) - { - configuration.dexed[instance_id].fc_range++; - } - } + configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range + ENCODER[ENC_R].speed(), FC_RANGE_MIN, FC_RANGE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].fc_range > FC_RANGE_MIN) - { - configuration.dexed[instance_id].fc_range--; - } - } + configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range - ENCODER[ENC_R].speed(), FC_RANGE_MIN, FC_RANGE_MAX); MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign, configuration.dexed[instance_id].fc_mode); } @@ -2448,19 +2149,9 @@ void UI_func_fc_assign(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].fc_assign < FC_ASSIGN_MAX) - { - configuration.dexed[instance_id].fc_assign++; - } - } + configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign + 1, FC_ASSIGN_MIN, FC_ASSIGN_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].fc_assign > FC_ASSIGN_MIN) - { - configuration.dexed[instance_id].fc_assign--; - } - } + configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign - 1, FC_ASSIGN_MIN, FC_ASSIGN_MAX); MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign, configuration.dexed[instance_id].fc_mode); } @@ -2525,19 +2216,10 @@ void UI_func_fc_mode(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].fc_mode < FC_MODE_MAX) - { - configuration.dexed[instance_id].fc_mode++; - } - } + configuration.dexed[instance_id].fc_mode = constrain(configuration.dexed[instance_id].fc_mode + 1, FC_MODE_MIN, FC_MODE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].fc_mode > FC_MODE_MIN) - { - configuration.dexed[instance_id].fc_mode--; - } - } + configuration.dexed[instance_id].fc_mode = constrain(configuration.dexed[instance_id].fc_mode - 1, FC_MODE_MIN, FC_MODE_MAX); + MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign, configuration.dexed[instance_id].fc_mode); } @@ -2583,19 +2265,9 @@ void UI_func_bc_range(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].bc_range < BC_RANGE_MAX) - { - configuration.dexed[instance_id].bc_range++; - } - } + configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range + ENCODER[ENC_R].speed(), BC_RANGE_MIN, BC_RANGE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].bc_range > BC_RANGE_MIN) - { - configuration.dexed[instance_id].bc_range--; - } - } + configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range - ENCODER[ENC_R].speed(), BC_RANGE_MIN, BC_RANGE_MAX); MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); } @@ -2634,19 +2306,9 @@ void UI_func_bc_assign(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].bc_assign < BC_ASSIGN_MAX) - { - configuration.dexed[instance_id].bc_assign++; - } - } + configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign + 1, BC_ASSIGN_MIN, BC_ASSIGN_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].bc_assign > BC_ASSIGN_MIN) - { - configuration.dexed[instance_id].bc_assign--; - } - } + configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign - 1, BC_ASSIGN_MIN, BC_ASSIGN_MAX); MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); } @@ -2711,20 +2373,11 @@ void UI_func_bc_mode(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].bc_mode < BC_MODE_MAX) - { - configuration.dexed[instance_id].bc_mode++; - } - } + configuration.dexed[instance_id].bc_mode = constrain(configuration.dexed[instance_id].bc_mode + 1, BC_MODE_MIN, BC_MODE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].bc_mode > BC_MODE_MIN) - { - configuration.dexed[instance_id].bc_mode--; - } - } - MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); + configuration.dexed[instance_id].bc_mode = constrain(configuration.dexed[instance_id].bc_mode - 1, BC_MODE_MIN, BC_MODE_MAX); + + MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign, configuration.dexed[instance_id].bc_mode); } lcd.setCursor(0, 1); @@ -2769,19 +2422,9 @@ void UI_func_at_range(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].at_range < AT_RANGE_MAX) - { - configuration.dexed[instance_id].at_range++; - } - } + configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range + ENCODER[ENC_R].speed(), AT_RANGE_MIN, AT_RANGE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].at_range > AT_RANGE_MIN) - { - configuration.dexed[instance_id].at_range--; - } - } + configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range - ENCODER[ENC_R].speed(), AT_RANGE_MIN, AT_RANGE_MAX); MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); } @@ -2820,19 +2463,9 @@ void UI_func_at_assign(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].at_assign < AT_ASSIGN_MAX) - { - configuration.dexed[instance_id].at_assign++; - } - } + configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign + 1, AT_ASSIGN_MIN, AT_ASSIGN_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].at_assign > AT_ASSIGN_MIN) - { - configuration.dexed[instance_id].at_assign--; - } - } + configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign - 1, AT_ASSIGN_MIN, AT_ASSIGN_MAX); MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); } @@ -2897,20 +2530,11 @@ void UI_func_at_mode(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].at_mode < AT_MODE_MAX) - { - configuration.dexed[instance_id].at_mode++; - } - } + configuration.dexed[instance_id].at_mode = constrain(configuration.dexed[instance_id].at_mode + 1, AT_MODE_MIN, AT_MODE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].at_mode > AT_MODE_MIN) - { - configuration.dexed[instance_id].at_mode--; - } - } - MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); + configuration.dexed[instance_id].at_mode = constrain(configuration.dexed[instance_id].at_mode - 1, AT_MODE_MIN, AT_MODE_MAX); + + MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign, configuration.dexed[instance_id].at_mode); } lcd.setCursor(0, 1); @@ -2955,19 +2579,9 @@ void UI_func_portamento_mode(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].portamento_mode < PORTAMENTO_MODE_MAX) - { - configuration.dexed[instance_id].portamento_mode++; - } - } + configuration.dexed[instance_id].portamento_mode = constrain(configuration.dexed[instance_id].portamento_mode + 1, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].portamento_mode > PORTAMENTO_MODE_MIN) - { - configuration.dexed[instance_id].portamento_mode--; - } - } + configuration.dexed[instance_id].portamento_mode = constrain(configuration.dexed[instance_id].portamento_mode - 1, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); } @@ -3020,19 +2634,9 @@ void UI_func_portamento_glissando(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].portamento_glissando < PORTAMENTO_GLISSANDO_MAX) - { - configuration.dexed[instance_id].portamento_glissando++; - } - } + configuration.dexed[instance_id].portamento_glissando = constrain(configuration.dexed[instance_id].portamento_glissando + 1, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].portamento_glissando > PORTAMENTO_GLISSANDO_MIN) - { - configuration.dexed[instance_id].portamento_glissando--; - } - } + configuration.dexed[instance_id].portamento_glissando = constrain(configuration.dexed[instance_id].portamento_glissando - 1, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); } @@ -3078,19 +2682,9 @@ void UI_func_portamento_time(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].portamento_time < PORTAMENTO_TIME_MAX) - { - configuration.dexed[instance_id].portamento_time++; - } - } + configuration.dexed[instance_id].portamento_time = constrain(configuration.dexed[instance_id].portamento_time + ENCODER[ENC_R].speed(), PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].portamento_time > PORTAMENTO_TIME_MIN) - { - configuration.dexed[instance_id].portamento_time--; - } - } + configuration.dexed[instance_id].portamento_time = constrain(configuration.dexed[instance_id].portamento_time - ENCODER[ENC_R].speed(), PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time); } @@ -3264,19 +2858,9 @@ void UI_func_midi_soft_thru(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.soft_midi_thru < SOFT_MIDI_THRU_MAX) - { - configuration.soft_midi_thru++; - } - } + configuration.soft_midi_thru = constrain(configuration.soft_midi_thru + 1, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.soft_midi_thru > SOFT_MIDI_THRU_MIN) - { - configuration.soft_midi_thru--; - } - } + configuration.soft_midi_thru = constrain(configuration.soft_midi_thru - 1, SOFT_MIDI_THRU_MIN, SOFT_MIDI_THRU_MAX); } lcd.setCursor(0, 1); @@ -3321,19 +2905,9 @@ void UI_func_velocity_level(uint8_t param) else if (LCDML.BT_checkDown() || LCDML.BT_checkUp()) { if (LCDML.BT_checkDown()) - { - if (configuration.dexed[instance_id].velocity_level < VELOCITY_LEVEL_MAX) - { - configuration.dexed[instance_id].velocity_level += 1; - } - } + configuration.dexed[instance_id].velocity_level = constrain(configuration.dexed[instance_id].velocity_level + ENCODER[ENC_R].speed(), VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); else if (LCDML.BT_checkUp()) - { - if (configuration.dexed[instance_id].velocity_level > VELOCITY_LEVEL_MIN) - { - configuration.dexed[instance_id].velocity_level -= 1; - } - } + configuration.dexed[instance_id].velocity_level = constrain(configuration.dexed[instance_id].velocity_level - ENCODER[ENC_R].speed(), VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX); } lcd_display_bar_int("Velocity Lvl", configuration.dexed[instance_id].velocity_level, VELOCITY_LEVEL_MIN, VELOCITY_LEVEL_MAX, 3, false, false, false, false); @@ -3709,7 +3283,7 @@ void lcd_display_bar_int(const char* title, uint32_t value, uint32_t min_value, else { // show only changed value and changed part of the bar - uint8_t ca = float(LCD_cols - 1) / float(max_value) + 1; + uint8_t ca = uint8_t (float(LCD_cols - 1) / float(max_value)) + 1; lcd.setCursor(LCD_cols - (size + 1) + 1, 0); lcd_display_int(value, size, zeros, brackets, sign); diff --git a/config.h b/config.h index b5eeb5e..74d0e81 100644 --- a/config.h +++ b/config.h @@ -297,7 +297,7 @@ enum { DEXED, CHORUS, DELAY, REVERB}; #define VOLUME_MIN 0 #define VOLUME_MAX 100 #define VOLUME_DEFAULT 80 -#define VOLUME_ENC_STEPS 5 +//#define VOLUME_ENC_STEPS 5 #define PANORAMA_MIN 0 #define PANORAMA_MAX 40 diff --git a/third-party/MD_REncoder/ISSUE_TEMPLATE.md b/third-party/MD_REncoder/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..67d2405 --- /dev/null +++ b/third-party/MD_REncoder/ISSUE_TEMPLATE.md @@ -0,0 +1,28 @@ +## IMPORTANT +Before submitting this issue +[ ] Have you tried using the latest version of the library? +[ ] Have you checked this has not already been submitted and/or resolved? +[ ] If you are requesting help a better choice may be the [ Arduino forum](http://forum.arduino.cc/) + +## Subject of the issue +Describe your issue here. + +## Your Environment +**Library Version:** +**Arduino IDE version:** +**Hardware model/type:** +**OS and Version:** + +## Steps to Reproduce +Explain how to reproduce this issue. Please provide working code below to demonstrate the issue. + +## Expected Behaviour +Explain what should happen. + +## Actual Behaviour +Explain what happens instead. Provide log messages if relevant. + +## Code Demonstrating the Issue +```` +Insert your code here. +```` \ No newline at end of file diff --git a/third-party/MD_REncoder/LICENSE b/third-party/MD_REncoder/LICENSE new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/third-party/MD_REncoder/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/third-party/MD_REncoder/PULL_REQUEST.md b/third-party/MD_REncoder/PULL_REQUEST.md new file mode 100644 index 0000000..f66479b --- /dev/null +++ b/third-party/MD_REncoder/PULL_REQUEST.md @@ -0,0 +1,29 @@ +## Proposed changes +Describe the big picture of your changes here to communicate why we should accept this pull request. +- If it fixes a bug or resolves a feature request, be sure to link to that issue. +- If it introduces new functionality, why is this needed? +- If it modifies existing functionality, what makes this better? + +## Types of changes +What types of changes does your code introduce? +Put an `x` in the boxes that apply +[ ] Bugfix (non-breaking change which fixes an issue) +[ ] New feature (non-breaking change which adds functionality) +[ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) + +## Your Environment +**Library Version:** +**Arduino IDE version:** +**Hardware model/type:** +**OS and Version:** + +## Checklist +Put an `x` in the boxes that apply. You can also fill these out after creating the PR. +This is a reminder of what we are expecting before merging your code. +[ ] Code compiles correctly/with no errors +[ ] I have added tests that prove my fix is effective or that my feature works +[ ] I have added or extended necessary documentation (if appropriate) +[ ] Any dependent changes have been merged and published in downstream modules + +## Further comments +If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... \ No newline at end of file diff --git a/third-party/MD_REncoder/README.md b/third-party/MD_REncoder/README.md new file mode 100644 index 0000000..c79a44b --- /dev/null +++ b/third-party/MD_REncoder/README.md @@ -0,0 +1,13 @@ +#MD_REncoder - Rotary Encoder Library + +This is an adaptation of Ben Buxton's excellent [rotary library](http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html) and implements additional features for encoder rotation speed. + +## Features +* Debounce handling with support for high rotation speeds +* Correctly handles direction changes mid-step +* Checks for valid state changes for more robust counting and noise immunity +* Interrupt based or polling in loop() +* Counts full-steps (default) or half-steps +* Calculates speed of rotation + +If you like and use this library please consider making a small donation using [PayPal](https://paypal.me/MajicDesigns/4USD) diff --git a/third-party/MD_REncoder/examples/Polling/Polling.ino b/third-party/MD_REncoder/examples/Polling/Polling.ino new file mode 100644 index 0000000..2a74e77 --- /dev/null +++ b/third-party/MD_REncoder/examples/Polling/Polling.ino @@ -0,0 +1,33 @@ +/* +Rotary Encoder - Polling Example + +The circuit: +* encoder pin A to Arduino pin 2 +* encoder pin B to Arduino pin 3 +* encoder ground pin to ground (GND) +*/ + +#include + +// set up encoder object +MD_REncoder R = MD_REncoder(2, 3); + +void setup() +{ + Serial.begin(57600); + R.begin(); +} + +void loop() +{ + uint8_t x = R.read(); + + if (x) + { + Serial.print(x == DIR_CW ? "\n+1" : "\n-1"); +#if ENABLE_SPEED + Serial.print(" "); + Serial.print(R.speed()); +#endif + } +} \ No newline at end of file diff --git a/third-party/MD_REncoder/keywords.txt b/third-party/MD_REncoder/keywords.txt new file mode 100644 index 0000000..8acf1bd --- /dev/null +++ b/third-party/MD_REncoder/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Classes and datatypes (KEYWORD1) +####################################### +MD_REncoder KEYWORD1 + +####################################### +# Methods and functions (KEYWORD2) +####################################### +begin KEYWORD2 +read KEYWORD2 +speed KEYWORD2 +setPeriod KEYWORD2 + +###################################### +# Constants/defines (LITERAL1) +####################################### +DIR_NONE LITERAL1 +DIR_CW LITERAL1 +DIR_CCW LITERAL1 + diff --git a/third-party/MD_REncoder/library.properties b/third-party/MD_REncoder/library.properties new file mode 100644 index 0000000..48dc9f4 --- /dev/null +++ b/third-party/MD_REncoder/library.properties @@ -0,0 +1,10 @@ +name=MD_REncoder +version=1.0.1 +author=majicDesigns +maintainer=marco_c <8136821@gmail.com> +sentence=Library for Rotary Encoder +paragraph=This is an adaptation of Ben Buxton's excellent rotary library and implements additional features for encoder rotation speed. +category=Sensors +url=https://github.com/MajicDesigns/MD_REncoder +architectures=* +license=LGPL-2.1 diff --git a/third-party/MD_REncoder/src/MD_REncoder.cpp b/third-party/MD_REncoder/src/MD_REncoder.cpp new file mode 100644 index 0000000..e4a3cca --- /dev/null +++ b/third-party/MD_REncoder/src/MD_REncoder.cpp @@ -0,0 +1,151 @@ +/* +MD_REncoder - Library for Rotary Encoders + +See header file for comments + +This version copyright (C) 2014 Marco Colli. All rights reserved. + +Original library copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3. +Contact: bb@cactii.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * \file + * \brief Implements core MD_REncoder class methods + */ +#include + +/* + * The below state table has, for each state (row), the new state + * to set based on the next encoder output. From left to right in, + * the table, the encoder outputs are 00, 01, 10, 11, and the value + * in that position is the new state to set. + */ +#define R_START 0x0 + +#if ENABLE_HALF_STEP +// Use the half-step state table (emits a code at 00 and 11) +#define R_CCW_BEGIN 0x1 +#define R_CW_BEGIN 0x2 +#define R_START_M 0x3 +#define R_CW_BEGIN_M 0x4 +#define R_CCW_BEGIN_M 0x5 + +const unsigned char ttable[][4] = +{ + // 00 01 10 11 + {R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, // R_START (00) + {R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, // R_CCW_BEGIN + {R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, // R_CW_BEGIN + {R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, // R_START_M (11) + {R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, // R_CW_BEGIN_M + {R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW} // R_CCW_BEGIN_M +}; +#else +// Use the full-step state table (emits a code at 00 only) +#define R_CW_FINAL 0x1 +#define R_CW_BEGIN 0x2 +#define R_CW_NEXT 0x3 +#define R_CCW_BEGIN 0x4 +#define R_CCW_FINAL 0x5 +#define R_CCW_NEXT 0x6 + +const unsigned char ttable[][4] = +{ + // 00 01 10 11 + {R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, // R_START + {R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, // R_CW_FINAL + {R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, // R_CW_BEGIN + {R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, // R_CW_NEXT + {R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, // R_CCW_BEGIN + {R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, // R_CCW_FINAL + {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START} // R_CCW_NEXT +}; +#endif + +MD_REncoder::MD_REncoder(uint8_t pinA, uint8_t pinB): +_pinA (pinA), _pinB (pinB), _state(R_START) +#if ENABLE_SPEED +, _period(DEFAULT_PERIOD), _count(0), _spd(0), _timeLast(0) +#endif +{ +} + +void MD_REncoder::begin(void) +{ + pinMode(_pinA, (ENABLE_PULLUPS ? INPUT_PULLUP : INPUT)); + pinMode(_pinB, (ENABLE_PULLUPS ? INPUT_PULLUP : INPUT)); + value=0; + last_dir=DIR_NONE; +} + +void MD_REncoder::update(void) +// Grab state of input pins, determine new state from the pins +// and state table, and return the emit bits (ie the generated event). +{ + uint8_t pinstate = (digitalRead(_pinB) << 1) | digitalRead(_pinA); + + _state = ttable[_state & 0xf][pinstate]; + +#if ENABLE_SPEED + // handle the encoder velocity calc + if (_state & 0x30) _count++; + if (millis() - _timeLast >= _period) + { + _spd = _count * (1000/_period); + _timeLast = millis(); + _count = 0; + } +#endif + + switch(_state & 0x30) + { + case DIR_CW: + value++; + last_dir=DIR_CW; + break; + case DIR_CCW: + last_dir=DIR_CCW; + value--; + break; + } +} + +int32_t MD_REncoder::read_value(void) +{ + return (value); +} + +int8_t MD_REncoder::read(void) +{ + switch(last_dir) + { + case DIR_CW: + last_dir=DIR_NONE; + return(4); + case DIR_CCW: + last_dir=DIR_NONE; + return(-4); + } + return(0); +} + + +void MD_REncoder::write(int32_t v) +{ + value=v; +} diff --git a/third-party/MD_REncoder/src/MD_REncoder.h b/third-party/MD_REncoder/src/MD_REncoder.h new file mode 100644 index 0000000..4a2a7c0 --- /dev/null +++ b/third-party/MD_REncoder/src/MD_REncoder.h @@ -0,0 +1,284 @@ +/** +\mainpage Main Page +Rotary Encoder Library for Arduino +---------------------------------- + +This is an adaptation of Ben Buxton's excellent +[rotary library](http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html) +and implements additional features for encoder rotation speed. + +Original library copyright 2011 Ben Buxton. Licensed under the GNU GPL Version 3. +Contact: bb@cactii.net + +Features +-------- +- Debounce handling with support for high rotation speeds +- Correctly handles direction changes mid-step +- Checks for valid state changes for more robust counting and noise immunity +- Interrupt based or polling in loop() +- Counts full-steps (default) or half-steps +- Calculates speed of rotation + +If you like and use this library please consider making a small donation using [PayPal](https://paypal.me/MajicDesigns/4USD) + +Topics +------ +- \subpage pageBackground +- \subpage pageLibrary + +Revision History +---------------- +Jan 2020 - version 1.0.1 +- Adjusted order of class initializers to fix errors in some compilers + +April 2014 - version 1.0 +- Initial implementation from Ben's code +- Cleaned up some compile issues and added begin() method +- Updated and documented +- Added speed functionality + +Copyright +--------- +This adaptation copyright (C) 2014 Marco Colli. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\page pageBackground Detecting an Encoder's Rotation +_This great explanation is reproduced from Ben Buxton's example code._ + +A typical mechanical rotary encoder emits a two bit gray code on 3 output pins. +Every step in the output (often accompanied by a physical 'click') generates a +specific sequence of output codes on the pins. + +There are 3 pins used for the rotary encoding - one common and two 'bit' pins +(called A and B). + +The following is the typical sequence of codes output when moving from one +step to the next: + +Position | Bit1| Bit2| +--------:|:---:|:---:| +Step1 | 0 | 0 | + 1/4 | 1 | 0 | + 1/2 | 1 | 1 | + 3/4 | 0 | 1 | +Step2 | 0 | 0 | + +From this table, we can see that when moving from one 'click' to the next, +there are 4 changes in the output code. + +- From an initial 0 - 0, Bit1 goes high, Bit0 stays low. +- Then both bits are high, halfway through the step. +- Then Bit1 goes low, but Bit2 stays high. +- Finally at the end of the step, both bits return to 0. + +Detecting the direction is easy - the table simply goes in the other direction +(read up instead of down). + +To decode this, we use a simple state machine. Every time the output code changes, +it follows state, until finally a full steps worth of code is received (in the +correct order). At the final 0-0, it returns a value indicating a step in one +direction or the other. + +It's also possible to use 'half-step' mode. This just emits an event at both the +0-0 and 1-1 positions. This might be useful for some encoders where you want to +detect all positions. In MD_REncoder.h set ENABLE_HALF_STEP to 1 to enable +half-step mode. + +If an invalid state happens (for example we go from '0-1' straight to '1-0'), the +state machine resets to the start until 0-0 and the next valid codes occur. + +The biggest advantage of using a state machine over other algorithms is that this +has inherent debounce built in. Other algorithms emit spurious output with switch +bounce, but this one will simply flip between sub-states until the bounce settles, +then continue along the state machine. A side effect of debounce is that fast +rotations can cause steps to be skipped. By not requiring debounce, fast rotations +can be accurately measured. Another advantage is the ability to properly handle bad +state, such as due to EMI, etc. It is also a lot simpler than others - a static +state table and less than 10 lines of logic. + +\page pageLibrary The REncoder Library + +Compile Time Switches +--------------------- + +ENABLE_HALF_STEP is 0 by default. Set this to 1 to emit codes when the rotary encoder +is at 11 as well as 00. The default is to emit codes only at 00. + +ENABLE_PULLUPS is set to 1 by default. Set this 0 if internal pullup resistors on the +input pins are not required. + +ENABLE_SPEED is set to 1 by default. Set this to 0 to disable the code and storage used to +calculate the speed of the encoder rotation. + +Speed Calculation +----------------- +The number of clicks is accumulated during the period defined by setPeriod(). Once the time +has expired the velocity is calculated in clicks per second by multiplying the number of +clicks by the number of periods in a second. + +speed = ClickCount * (1000 / period) + +*/ +#ifndef _MD_RENCODER_H +#define _MD_RENCODER_H + +#include +/** + * \file + * \brief Main header file for the MD_Parola library + */ + +// Library options +/** + \def ENABLE_HALF_STEP + Set this to 1 to emit codes when the rotary encoder is at 11 as well as 00. + The default is to emit codes only at 00. + */ +#define ENABLE_HALF_STEP 0 + +/** + \def ENABLE_PULLUPS + Set this 0 if internal pullup resistors on the input pins are not required. + */ +#define ENABLE_PULLUPS 1 + +/** + \def ENABLE_SPEED + Set this to 0 to disable the code and storage used to calculate the encoder rotation speed. + */ +#define ENABLE_SPEED 1 + +/** + Set the default sampling period for measuring the speed, in milliseconds. This works best as + a whole fraction of 1000 (ie 100, 200, 500, 1000). Longer periods provide some hysteresis + which is useful when the encoder is being turned by hand. + */ +#define DEFAULT_PERIOD 500 + + +// Direction values returned by read() method +/** + \def DIR_NONE + read() return value - No complete step/movement + */ +#define DIR_NONE 0x00 +/** + \def DIR_CW + read() return value - Clockwise step/movement + */ +#define DIR_CW 0x10 +/** + \def DIR_CCW + read() return value - Counter-clockwise step/movement + */ +#define DIR_CCW 0x20 + +/** + * Core object for the MD_REncoder library + */ +class MD_REncoder +{ + public: + /** + * Class Constructor. + * + * Instantiate a new instance of the class. + * + * \param pinA the pin number for the encoder A output + * \param pinB the pin number for the encoder B output + */ + MD_REncoder(uint8_t pinA, uint8_t pinB); + + /** + * Initialize the object. + * + * Initialize the object data. This will be called to initialize + * new data for the class that cannot be done during the object creation. + */ + void begin(void); + + /** + * Read the direction of rotation. + * + * Read the direction of rotation inferred from the previous state of the + * encoder the current state of the inputs. This method should be called + * on a frequent regular basis to ensure smooth encoder inputs. + * + * \return One of the DIR_NONE, DIR_CW or DIR_CCW. + */ + int32_t read_value(void); + int8_t read(void); + +#if ENABLE_SPEED + /** + * Set the sampling period for the speed detection. + * + * Set the speed sampling interval in milliseconds. The period + * must be greater than 0 and less than 1000. This works best as + * a whole fraction of 1000 (ie 100, 200, 500, 1000). Longer + * periods provide some hysteresis which is useful when the + * encoder is being turned by hand. + * + * \param t time in millisecond between 0 and 1000 inclusive. + */ + inline void setPeriod(uint16_t t) { if ((t != 0) && (t <= 1000)) _period = t; }; + + /** + * Return the speed of the encoder. + * + * Calculate the speed (steps per second) for the encoder. + * The sampling period is set using the setPeriod() method. + * If the encoder is used to enter numbers or scan through menus, the speed + * can be used to accelerate the display (eg, skip larger values for each click). + * + * \return The speed in clicks per second. + */ + inline uint16_t speed(void) + { + if(_spd==0) + return(1); + if(_spd>10) + return(10/1.5+0.5); + + return(float(_spd)/1.5+0.5); + }; + +#endif + + void update(void); + void write(int32_t value); + + private: + // Hardware data + uint8_t _pinA; // pin A number + uint8_t _pinB; // pin B number + + // Encoder value + uint8_t _state; // latest state for the encoder + int32_t value; + int8_t last_dir; + +#if ENABLE_SPEED + // Velocity data + uint16_t _period; // velocity calculation period + uint16_t _count; // running count of encoder clicks + uint16_t _spd; // last calculated speed (no sign) in clicks/second + uint32_t _timeLast; // last time read +#endif +}; + +#endif +