You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MicroDexed/UI.hpp

1647 lines
42 KiB

/*
MicroDexed
MicroDexed is a port of the Dexed sound engine
(https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6 with audio shield.
Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android
(c)2018,2019 H. Wirtz <wirtz@parasitstudio.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ENABLE_LCD_UI
#ifndef _UI_HPP_
#define _UI_HPP_
#include "config.h"
#include "Disp_Plus.h"
#include "SoftenValue.hpp"
#include "effect_modulated_delay.h"
#include "dexed.h"
#include <LCDMenuLib2.h>
#include <Encoder.h>
#define _LCDML_DISP_cols LCD_cols
#define _LCDML_DISP_rows LCD_rows
#ifdef I2C_DISPLAY
#define _LCDML_DISP_cfg_cursor 0x7E // cursor Symbol
#else
#define _LCDML_DISP_cfg_cursor 0x8d // cursor Symbol
#endif
#define _LCDML_DISP_cfg_scrollbar 1 // enable a scrollbar
extern config_t configuration;
//void set_volume(float v, float p);
extern char bank_names[MAX_BANKS][BANK_NAME_LEN];
extern char bank_name[BANK_NAME_LEN];
extern char voice_name[VOICE_NAME_LEN];
extern char voice_names[MAX_VOICES][VOICE_NAME_LEN];
extern void strip_extension(char* s, char *target);
extern void eeprom_write(void);
extern bool get_voice_names_from_bank(uint8_t b);
extern bool load_sysex(uint8_t b, uint8_t v);
#ifdef DISPLAY_LCD_SPI
extern void change_disp_sd(bool d);
#endif
extern SoftenValue <uint8_t> soften_volume;
extern SoftenValue <uint8_t> soften_filter_res[NUM_DEXED];
extern SoftenValue <uint8_t> soften_filter_cut[NUM_DEXED];
extern AudioEffectDelay delay1;
#ifdef USE_REVERB
extern AudioEffectFreeverbStereo freeverbs1;
#endif
extern AudioEffectModulatedDelay modchorus;
extern AudioSynthWaveform modulator;
extern AudioMixer4 delay_fb_mixer;
extern AudioMixer4 master_mixer_r;
extern AudioMixer4 master_mixer_l;
extern AudioAmplifier volume_r;
extern AudioAmplifier volume_l;
extern Dexed* MicroDexed[NUM_DEXED];
extern void set_volume(uint8_t v, int8_t p);
/***********************************************************************
GLOBAL
************************************************************************/
elapsedMillis back_from_volume;
#ifdef I2C_DISPLAY
#include <LiquidCrystal_I2C.h>
Disp_Plus<LiquidCrystal_I2C> lcd(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows);
#endif
#ifdef U8X8_DISPLAY
#include <U8x8lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
Disp_Plus<U8X8_DISPLAY_CLASS> lcd(/* cs=*/ U8X8_CS_PIN, /* dc=*/ U8X8_DC_PIN, /* reset=*/ U8X8_RESET_PIN);
//Disp_Plus<U8X8_DISPLAY_CLASS> lcd(U8X8_PIN_NONE);
#endif
const uint8_t scroll_bar[5][8] = {
{B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001}, // scrollbar top
{B11111, B11111, B10001, B10001, B10001, B10001, B10001, B10001}, // scroll state 1
{B10001, B10001, B11111, B11111, B10001, B10001, B10001, B10001}, // scroll state 2
{B10001, B10001, B10001, B10001, B11111, B11111, B10001, B10001}, // scroll state 3
{B10001, B10001, B10001, B10001, B10001, B10001, B11111, B11111} // scrollbar bottom
};
enum { ENC_R, ENC_L };
enum { MENU_START, MENU_VOICE, MENU_EDIT, MENU_VOLUME };
enum {MENU_VOICE_BANK, MENU_VOICE_SOUND};
uint8_t menu_state = MENU_START;
uint8_t menu_voice = MENU_VOICE_SOUND;
void lcdml_menu_display(void);
void lcdml_voice_menu_display(void);
void lcdml_menu_clear(void);
void lcdml_menu_control(void);
void encoder_right_up(void);
void encoder_right_down(void);
void encoder_right_button_long(void);
void encoder_right_button_short(void);
void encoder_left_up(void);
void encoder_left_down(void);
void encoder_left_button_long(void);
void encoder_left_button_short(void);
void lcdml_voice_menu_control(void);
void UI_func_sound(uint8_t param);
void UI_func_reverb_roomsize(uint8_t param);
void UI_func_reverb_damping(uint8_t param);
void UI_func_reverb_level(uint8_t param);
void UI_func_chorus_frequency(uint8_t param);
void UI_func_chorus_waveform(uint8_t param);
void UI_func_chorus_depth(uint8_t param);
void UI_func_chorus_level(uint8_t param);
void UI_func_delay_time(uint8_t param);
void UI_func_delay_feedback(uint8_t param);
void UI_func_delay_level(uint8_t param);
void UI_func_filter_cutoff(uint8_t param);
void UI_func_filter_resonance(uint8_t param);
void UI_func_midi_channel(uint8_t param);
void UI_func_loudness(uint8_t param);
void UI_func_panorama(uint8_t param);
void UI_func_stereo_mono(uint8_t param);
void UI_func_polyphony(uint8_t param);
void UI_func_engine(uint8_t param);
void UI_func_information(uint8_t param);
void UI_func_voice_selection(uint8_t param);
void UI_func_volume(uint8_t param);
void UI_func_back(uint8_t param);
void UI_func_goToRootMenu(uint8_t param);
void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign);
void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign);
// normal menu
LCDMenuLib2_menu LCDML_0(255, 0, 0, NULL, NULL); // normal root menu element (do not change)
LCDMenuLib2 LCDML(LCDML_0, _LCDML_DISP_rows, _LCDML_DISP_cols, lcdml_menu_display, lcdml_menu_clear, lcdml_menu_control);
// LCDML_add(id, prev_layer, new_num, lang_char_array, callback_function)
LCDML_add(0, LCDML_0, 1, "Sound", UI_func_sound);
LCDML_add(1, LCDML_0, 2, "Effect", NULL);
LCDML_add(2, LCDML_0_2, 1, "Reverb", NULL);
LCDML_add(3, LCDML_0_2_1, 1, "Roomsize", UI_func_reverb_roomsize);
LCDML_add(4, LCDML_0_2_1, 2, "Damping", UI_func_reverb_damping);
LCDML_add(5, LCDML_0_2_1, 3, "Level", UI_func_reverb_level);
LCDML_add(6, LCDML_0_2, 2, "Chorus", NULL);
LCDML_add(7, LCDML_0_2_2, 1, "Frequency", UI_func_chorus_frequency);
LCDML_add(8, LCDML_0_2_2, 2, "Waveform", UI_func_chorus_waveform);
LCDML_add(9, LCDML_0_2_2, 3, "Depth", UI_func_chorus_depth);
LCDML_add(10, LCDML_0_2_2, 4, "Level", UI_func_chorus_level);
LCDML_add(11, LCDML_0_2, 3, "Delay", NULL);
LCDML_add(12, LCDML_0_2_3, 1, "Time", UI_func_delay_time);
LCDML_add(13, LCDML_0_2_3, 2, "Feedback", UI_func_delay_feedback);
LCDML_add(14, LCDML_0_2_3, 3, "Level", UI_func_delay_level);
LCDML_add(15, LCDML_0_2, 4, "Filter", NULL);
LCDML_add(16, LCDML_0_2_4, 1, "Cutoff", UI_func_filter_cutoff);
LCDML_add(17, LCDML_0_2_4, 2, "Resonance", UI_func_filter_resonance);
LCDML_add(18, LCDML_0, 3, "Store", NULL);
LCDML_add(19, LCDML_0, 4, "System", NULL);
LCDML_add(20, LCDML_0_4, 1, "MIDI Channel", UI_func_midi_channel);
LCDML_add(21, LCDML_0_4, 2, "Loudness", UI_func_loudness);
LCDML_add(22, LCDML_0_4, 3, "Panorama", UI_func_panorama);
LCDML_add(23, LCDML_0_4, 4, "Stereo/Mono", UI_func_stereo_mono);
LCDML_add(24, LCDML_0_4, 5, "Polyphony", UI_func_polyphony);
LCDML_add(25, LCDML_0_4, 6, "Engine", UI_func_engine);
LCDML_add(26, LCDML_0, 5, "Info", UI_func_information);
#define _LCDML_DISP_cnt 26
// create menu
LCDML_createMenu(_LCDML_DISP_cnt);
/***********************************************************************
CONTROL
***********************************************************************/
#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)};
long g_LCDML_CONTROL_button_press_time[NUM_ENCODER] = {0, 0};
bool g_LCDML_CONTROL_button_prev[NUM_ENCODER] = {HIGH, HIGH};
uint8_t g_LCDML_CONTROL_prev[NUM_ENCODER] = {0, 0};
#ifdef U8X8_DISPLAY
const uint8_t * flipped_scroll_bar[5];
uint8_t * rotTile(const uint8_t * tile) {
uint8_t * newt = new uint8_t[8];
for (int x = 0; x < 8; x++) {
uint8_t newb = 0;
for (int y = 0 ; y < 8; y++){
newb |= (tile[y] << x) & 0x80;
newb >>= 1;
}
newt[x] = newb;
}
return newt;
}
#endif
void setup_ui(void){
// LCD Begin
#ifdef I2C_DISPLAY
lcd.init();
lcd.backlight();
lcd.clear();
lcd.blink_off();
lcd.cursor_off();
lcd.backlight();
#else
lcd.begin();
lcd.clear();
lcd.setFont(u8x8_font_amstrad_cpc_extended_f);
#endif
lcd.setCursor(1, 0);
lcd.print("MicroDexed");
lcd.setCursor(0, 1);
lcd.print("(c)parasiTstudio");
#ifdef I2C_DISPLAY
// set special chars for scrollbar
lcd.createChar(0, (uint8_t*)scroll_bar[0]);
lcd.createChar(1, (uint8_t*)scroll_bar[1]);
lcd.createChar(2, (uint8_t*)scroll_bar[2]);
lcd.createChar(3, (uint8_t*)scroll_bar[3]);
lcd.createChar(4, (uint8_t*)scroll_bar[4]);
#else
for (int x=0; x < 5; x++) {
flipped_scroll_bar[x] = rotTile(scroll_bar[x]);
}
#endif
// LCDMenuLib Setup
LCDML_setup(_LCDML_DISP_cnt);
// Enable Menu Rollover
//LCDML.MENU_enRollover();
// Enable Screensaver (screensaver menu function, time to activate in ms)
//LCDML.SCREEN_enable(UI_func_voice_selection, VOICE_SELECTION_MS); // set to 10 seconds
}
void lcdml_menu_control(void)
{
// If something must init, put in in the setup condition
if (LCDML.BT_setup())
{
pinMode(BUT_R_PIN, INPUT_PULLUP);
pinMode(BUT_L_PIN, INPUT_PULLUP);
}
if (back_from_volume > BACK_FROM_VOLUME_MS && menu_state == MENU_VOLUME)
{
UI_func_voice_selection(0);
return;
}
//Volatile Variable
long g_LCDML_CONTROL_Encoder_position[NUM_ENCODER] = {ENCODER[ENC_R].read(), ENCODER[ENC_L].read()};
bool button[NUM_ENCODER] = {digitalRead(BUT_R_PIN), digitalRead(BUT_L_PIN)};
/************************************************************************************
Basic encoder handlying (from LCDMenuLib2
************************************************************************************/
// RIGHT
if (g_LCDML_CONTROL_Encoder_position[ENC_R] <= -3)
{
if (!button[ENC_R])
{
LCDML.BT_left();
g_LCDML_CONTROL_button_prev[ENC_R] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_R] = -1;
}
else
{
encoder_right_up();
}
ENCODER[ENC_R].write(g_LCDML_CONTROL_Encoder_position[ENC_R] + 4);
}
else if (g_LCDML_CONTROL_Encoder_position[ENC_R] >= 3)
{
if (!button[ENC_R])
{
LCDML.BT_right();
g_LCDML_CONTROL_button_prev[ENC_R] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_R] = -1;
}
else
{
encoder_right_down();
}
ENCODER[ENC_R].write(g_LCDML_CONTROL_Encoder_position[ENC_R] - 4);
}
else
{
if (!button[ENC_R] && g_LCDML_CONTROL_button_prev[ENC_R]) //falling edge, button[ENC_R] pressed
{
g_LCDML_CONTROL_button_prev[ENC_R] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_R] = millis();
}
else if (button[ENC_R] && !g_LCDML_CONTROL_button_prev[ENC_R]) //rising edge, button[ENC_R] not active
{
g_LCDML_CONTROL_button_prev[ENC_R] = HIGH;
if (g_LCDML_CONTROL_button_press_time[ENC_R] < 0)
{
g_LCDML_CONTROL_button_press_time[ENC_R] = millis();
//Reset for left right action
}
else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_R]) >= g_LCDML_CONTROL_button_long_press)
{
LCDML.BT_quit();
if (menu_state == MENU_EDIT)
{
LCDML.BT_quit();
}
else if (menu_state == MENU_VOICE)
{
encoder_right_button_long();
}
}
else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_R]) >= g_LCDML_CONTROL_button_short_press)
{
encoder_right_button_short();
}
}
}
// LEFT
if (g_LCDML_CONTROL_Encoder_position[ENC_L] <= -3)
{
if (!button[ENC_L])
{
//LCDML.BT_left();
g_LCDML_CONTROL_button_prev[ENC_L] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_L] = -1;
}
else
{
encoder_left_up();
}
ENCODER[ENC_L].write(g_LCDML_CONTROL_Encoder_position[ENC_L] + 4);
}
else if (g_LCDML_CONTROL_Encoder_position[ENC_L] >= 3)
{
if (!button[ENC_L])
{
//LCDML.BT_right();
g_LCDML_CONTROL_button_prev[ENC_L] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_L] = -1;
}
else
{
encoder_left_down();
}
ENCODER[ENC_L].write(g_LCDML_CONTROL_Encoder_position[ENC_L] - 4);
}
else
{
if (!button[ENC_L] && g_LCDML_CONTROL_button_prev[ENC_L]) //falling edge, button[ENC_L] pressed
{
g_LCDML_CONTROL_button_prev[ENC_L] = LOW;
g_LCDML_CONTROL_button_press_time[ENC_L] = millis();
}
else if (button[ENC_L] && !g_LCDML_CONTROL_button_prev[ENC_L]) //rising edge, button[ENC_L] not active
{
g_LCDML_CONTROL_button_prev[ENC_L] = HIGH;
if (g_LCDML_CONTROL_button_press_time[ENC_L] < 0)
{
g_LCDML_CONTROL_button_press_time[ENC_L] = millis();
//Reset for left right action
}
else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_L]) >= g_LCDML_CONTROL_button_long_press)
{
//LCDML.BT_quit();
encoder_left_button_long();
}
else if ((millis() - g_LCDML_CONTROL_button_press_time[ENC_L]) >= g_LCDML_CONTROL_button_short_press)
{
//LCDML.BT_enter();
encoder_left_button_short();
}
}
}
}
/************************************************************************************
RIGHT Encoder functions
************************************************************************************/
void encoder_right_up(void)
{
switch (menu_state)
{
case MENU_EDIT:
case MENU_VOLUME:
menu_state = MENU_EDIT;
LCDML.BT_down();
break;
case MENU_VOICE:
#ifdef DEBUG
Serial.println(F("State: MENU_VOICE, Encoder left up"));
#endif
switch (menu_voice)
{
case MENU_VOICE_BANK:
if (configuration.bank < MAX_BANKS)
{
configuration.bank++;
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.bank, configuration.voice);
get_voice_names_from_bank(configuration.bank);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
#endif
}
break;
case MENU_VOICE_SOUND:
if (configuration.voice < MAX_VOICES - 1)
configuration.voice++;
else
{
if (configuration.bank < MAX_BANKS)
{
configuration.bank++;
configuration.voice = 0;
}
}
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.bank, configuration.voice);
get_voice_names_from_bank(configuration.bank);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
#endif
eeprom_write();
}
UI_func_voice_selection(0);
break;
}
}
void encoder_right_down(void)
{
switch (menu_state)
{
case MENU_EDIT:
case MENU_VOLUME:
menu_state = MENU_EDIT;
LCDML.BT_up();
break;
case MENU_VOICE:
#ifdef DEBUG
Serial.println(F("State: MENU_VOICE, Encoder left down"));
#endif
switch (menu_voice)
{
case MENU_VOICE_BANK:
if (configuration.bank > 0)
{
configuration.bank--;
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.bank, configuration.voice);
get_voice_names_from_bank(configuration.bank);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
#endif
}
break;
case MENU_VOICE_SOUND:
if (configuration.voice > 0)
configuration.voice--;
else
{
if (configuration.bank > 0)
{
configuration.bank--;
configuration.voice = 31;
}
}
#ifdef DISPLAY_LCD_SPI
change_disp_sd(false);
#endif
load_sysex(configuration.bank, configuration.voice);
get_voice_names_from_bank(configuration.bank);
#ifdef DISPLAY_LCD_SPI
change_disp_sd(true);
#endif
eeprom_write();
}
UI_func_voice_selection(0);
break;
}
}
void encoder_right_button_long(void)
{
#ifdef DEBUG
Serial.println(F("State: MENU_VOICE, button long press"));
#else
;
#endif
}
void encoder_right_button_short(void)
{
#ifdef DEBUG
Serial.println(F("Encoder right short press"));
#endif
if (menu_state == MENU_EDIT)
{
LCDML.BT_enter();
}
else if (menu_state == MENU_VOICE)
{
#ifdef DEBUG
Serial.println(F("State: MENU_VOICE, button short press"));
#endif
if (menu_voice == MENU_VOICE_BANK)
menu_voice = MENU_VOICE_SOUND;
else
menu_voice = MENU_VOICE_BANK;
UI_func_voice_selection(0);
}
}
/************************************************************************************
LEFT Encoder functions
************************************************************************************/
void encoder_left_up(void)
{
#ifdef DEBUG
Serial.println(F("Volume +"));
#endif
if (configuration.vol < VOLUME_MAX)
soften_volume.update(soften_volume.value() + (VOLUME_MAX - VOLUME_MIN) / VOLUME_ENC_STEPS, SOFTEN_VALUE_CHANGE_STEPS);
else
soften_volume.update(VOLUME_MAX, SOFTEN_VALUE_CHANGE_STEPS);
eeprom_write();
UI_func_volume(0);
}
void encoder_left_down(void)
{
#ifdef DEBUG
Serial.println(F("Volume -"));
#endif
if (configuration.vol > VOLUME_MIN)
soften_volume.update(soften_volume.value() - (VOLUME_MAX - VOLUME_MIN) / VOLUME_ENC_STEPS, SOFTEN_VALUE_CHANGE_STEPS);
else
soften_volume.update(VOLUME_MIN, SOFTEN_VALUE_CHANGE_STEPS);
eeprom_write();
UI_func_volume(0);
}
void encoder_left_button_long(void)
{
#ifdef DEBUG
Serial.println(F("Encoder left long press"));
#else
;
#endif
}
void encoder_left_button_short(void)
{
#ifdef DEBUG
Serial.println(F("Encoder left short press"));
#endif
if (menu_state == MENU_EDIT)
{
menu_state = MENU_VOICE;
UI_func_voice_selection(0);
}
else if (menu_state == MENU_VOICE)
{
menu_state = MENU_EDIT;
LCDML.MENU_goRoot();
}
}
/***********************************************************************
DISPLAY
***********************************************************************/
void lcdml_menu_clear(void)
{
lcd.clear();
lcd.setCursor(0, 0);
}
void lcdml_menu_display(void)
{
// update content
// ***************
if (LCDML.DISP_checkMenuUpdate()) {
// clear menu
// ***************
LCDML.DISP_clear();
// declaration of some variables
// ***************
// content variable
char content_text[_LCDML_DISP_cols]; // save the content text of every menu element
// menu element object
LCDMenuLib2_menu *tmp;
// some limit values
uint8_t i = LCDML.MENU_getScroll();
uint8_t maxi = _LCDML_DISP_rows + i;
uint8_t n = 0;
// check if this element has children
if ((tmp = LCDML.MENU_getDisplayedObj()) != NULL)
{
// loop to display lines
do
{
// check if a menu element has a condition and if the condition be true
if (tmp->checkCondition())
{
// check the type off a menu element
if (tmp->checkType_menu() == true)
{
// display normal content
LCDML_getContent(content_text, tmp->getID());
lcd.setCursor(1, n);
lcd.print(content_text);
}
else
{
if (tmp->checkType_dynParam()) {
tmp->callback(n);
}
}
// increment some values
i++;
n++;
}
// try to go to the next sibling and check the number of displayed rows
} while (((tmp = tmp->getSibling(1)) != NULL) && (i < maxi));
}
}
if (LCDML.DISP_checkMenuCursorUpdate())
{
// init vars
uint8_t n_max = (LCDML.MENU_getChilds() >= _LCDML_DISP_rows) ? _LCDML_DISP_rows : (LCDML.MENU_getChilds());
uint8_t scrollbar_min = 0;
uint8_t scrollbar_max = LCDML.MENU_getChilds();
uint8_t scrollbar_cur_pos = LCDML.MENU_getCursorPosAbs();
uint8_t scroll_pos = ((1.*n_max * _LCDML_DISP_rows) / (scrollbar_max - 1) * scrollbar_cur_pos);
// display rows
for (uint8_t n = 0; n < n_max; n++)
{
//set cursor
lcd.setCursor(0, n);
//set cursor char
if (n == LCDML.MENU_getCursorPos()) {
lcd.write(_LCDML_DISP_cfg_cursor);
} else {
lcd.write(' ');
}
// delete or reset scrollbar
if (_LCDML_DISP_cfg_scrollbar == 1) {
if (scrollbar_max > n_max) {
#ifdef I2C_DISPLAY
lcd.setCursor((_LCDML_DISP_cols - 1), n);
lcd.write((uint8_t)0);
#else
lcd.drawTile((_LCDML_DISP_cols - 1), n, 1, flipped_scroll_bar[0]);
lcd.setCursor((_LCDML_DISP_cols), n+1);
#endif
}
else {
lcd.setCursor((_LCDML_DISP_cols - 1), n);
lcd.print(' ');
}
}
}
// display scrollbar
if (_LCDML_DISP_cfg_scrollbar == 1) {
if (scrollbar_max > n_max) {
//set scroll position
if (scrollbar_cur_pos == scrollbar_min) {
// min pos
#ifdef I2C_DISPLAY
lcd.setCursor((_LCDML_DISP_cols - 1), 0);
lcd.write((uint8_t)1);
#else
lcd.drawTile((_LCDML_DISP_cols - 1), 0, 1, flipped_scroll_bar[1]);
lcd.setCursor((_LCDML_DISP_cols), 1);
#endif
} else if (scrollbar_cur_pos == (scrollbar_max - 1)) {
// max pos
#ifdef I2C_DISPLAY
lcd.setCursor((_LCDML_DISP_cols - 1), (n_max - 1));
lcd.write((uint8_t)4);
#else
lcd.drawTile((_LCDML_DISP_cols - 1), (n_max - 1), 1, flipped_scroll_bar[4]);
lcd.setCursor((_LCDML_DISP_cols), (n_max));
#endif
} else {
// between
#ifdef I2C_DISPLAY
lcd.setCursor((_LCDML_DISP_cols - 1), scroll_pos / n_max);
lcd.write((uint8_t)(scroll_pos % n_max) + 1);
#else
lcd.drawTile((_LCDML_DISP_cols - 1), scroll_pos / n_max, 1, flipped_scroll_bar[(scroll_pos % n_max) + 1]);
lcd.setCursor((_LCDML_DISP_cols), (scroll_pos / n_max)+1);
#endif
}
}
}
}
}
/***********************************************************************
MENU
***********************************************************************/
void UI_func_sound(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Sound"));
lcd.setCursor(0, 1);
lcd.print(F("not implemented"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter()) { // check if any button is pressed (enter, up, down, left, right)
// LCDML_goToMenu stops a running menu function and goes to the menu
LCDML.FUNC_goBackToMenu();
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_reverb_roomsize(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Roomsize"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_roomsize < REVERB_ROOMSIZE_MAX)
{
configuration.reverb_roomsize++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_roomsize > REVERB_ROOMSIZE_MIN)
{
configuration.reverb_roomsize--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_roomsize, 3, true, true, false);
freeverbs1.roomsize(configuration.reverb_roomsize / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_reverb_damping(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Damping"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_damping < REVERB_DAMPING_MAX)
{
configuration.reverb_damping++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_damping > REVERB_DAMPING_MIN)
{
configuration.reverb_damping--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_damping, 3, true, true, false);
freeverbs1.damping(configuration.reverb_damping / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_reverb_level(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_level < REVERB_LEVEL_MAX)
{
configuration.reverb_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_level > REVERB_LEVEL_MIN)
{
configuration.reverb_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_level, 3, true, true, false);
master_mixer_r.gain(1, configuration.reverb_level / 100.0);
master_mixer_l.gain(1, configuration.reverb_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_frequency(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Frequency"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_frequency < CHORUS_FREQUENCY_MAX)
{
configuration.chorus_frequency++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_frequency > CHORUS_FREQUENCY_MIN)
{
configuration.chorus_frequency--;
}
}
lcd.setCursor(0, 1);
lcd_display_float(configuration.chorus_frequency / 10.0, 2, 1, false, true, false);
lcd.print(" Hz");
modulator.frequency(configuration.chorus_frequency / 10.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_waveform(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Waveform"));
}
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++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_waveform > CHORUS_WAVEFORM_MIN)
{
configuration.chorus_waveform--;
}
}
lcd.setCursor(0, 1);
switch (configuration.chorus_waveform)
{
case 0:
modulator.begin(WAVEFORM_TRIANGLE);
lcd.print("[TRIANGLE]");
break;
case 1:
modulator.begin(WAVEFORM_SINE);
lcd.print("[SINE ]");
break;
default:
modulator.begin(WAVEFORM_TRIANGLE);
lcd.print("[TRIANGLE]");
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_depth(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Depth"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_depth < CHORUS_DEPTH_MAX)
{
configuration.chorus_depth++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_depth > CHORUS_DEPTH_MIN)
{
configuration.chorus_depth--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.chorus_depth, 3, true, true, false);
modulator.amplitude(configuration.chorus_depth / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_level(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_level < CHORUS_LEVEL_MAX)
{
configuration.chorus_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_level > CHORUS_LEVEL_MIN)
{
configuration.chorus_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.chorus_level, 3, true, true, false);
master_mixer_r.gain(3, configuration.chorus_level / 100.0);
master_mixer_l.gain(3, configuration.chorus_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_time(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Time"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_time < DELAY_TIME_MAX)
{
configuration.delay_time += 10;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_time > DELAY_TIME_MIN)
{
configuration.delay_time -= 10;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_time * 10, 3, true, true, false);
delay1.delay(0, configuration.delay_time * 10);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_feedback(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Feedback"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_feedback < DELAY_FEEDBACK_MAX)
{
configuration.delay_feedback++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_feedback > DELAY_FEEDBACK_MIN)
{
configuration.delay_feedback--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_feedback, 3, true, true, false);
delay_fb_mixer.gain(1, configuration.delay_feedback / 100.0 ); // amount of feedback
delay_fb_mixer.gain(0, 1.0 - configuration.delay_feedback / 100.0); // original signal
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_level(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_level < DELAY_LEVEL_MAX)
{
configuration.delay_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_level > DELAY_LEVEL_MIN)
{
configuration.delay_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_level, 3, true, true, false);
master_mixer_r.gain(2, configuration.delay_level / 100.0);
master_mixer_l.gain(2, configuration.delay_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_filter_cutoff(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Filter Cut-Off"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.filter_cutoff < FILTER_CUTOFF_MAX)
{
configuration.filter_cutoff++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.filter_cutoff > FILTER_CUTOFF_MIN)
{
configuration.filter_cutoff--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.filter_cutoff, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Cutoff = configuration.filter_cutoff / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_filter_resonance(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Filter Resonance"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.filter_resonance < FILTER_RESONANCE_MAX)
{
configuration.filter_resonance++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.filter_resonance > FILTER_RESONANCE_MIN)
{
configuration.filter_resonance--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.filter_resonance, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Reso = configuration.filter_resonance / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_midi_channel(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("MIDI Channel"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.midi_channel < MIDI_CHANNEL_MAX)
{
configuration.midi_channel++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.midi_channel > MIDI_CHANNEL_MIN)
{
configuration.midi_channel--;
}
}
lcd.setCursor(0, 1);
if (configuration.midi_channel == 0)
{
lcd.print(F("[OMNI]"));
}
else
{
lcd_display_int(configuration.midi_channel, 4, false, true, false);
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_loudness(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Loudness"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.loudness < LOUDNESS_MAX)
{
configuration.loudness++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.loudness > LOUDNESS_MIN)
{
configuration.loudness--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.loudness, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Gain = configuration.loudness / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_panorama(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Panorama"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.pan < PANORAMA_MAX)
{
configuration.pan++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.loudness > PANORAMA_MIN)
{
configuration.pan--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.pan, 2, false, true, true);
}
set_volume(configuration.vol, configuration.pan);
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_stereo_mono(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Stereo/Mono"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.mono < MONO_MAX)
{
configuration.mono++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.mono > MONO_MIN)
{
configuration.mono--;
}
}
lcd.setCursor(0, 1);
switch (configuration.mono)
{
case 0:
lcd.print(F("[MONO ]"));
break;
case 1:
lcd.print(F("[STEREO]"));
break;
case 2:
lcd.print(F("[MONO-R]"));
break;
case 3:
lcd.print(F("[MONO-L]"));
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_polyphony(uint8_t param)
{
;
}
void UI_func_engine(uint8_t param)
{
;
}
void UI_func_information(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("MicroDexed"));
lcd.setCursor(0, 1);
lcd.print(VERSION);
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
// loop function, can be run in a loop when LCDML_DISP_triggerMenu(xx) is set
// the quit button works in every DISP function without any checks; it starts the loop_end function
if (LCDML.BT_checkEnter()) { // check if any button is pressed (enter, up, down, left, right)
// LCDML_goToMenu stops a running menu function and goes to the menu
LCDML.FUNC_goBackToMenu();
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_voice_selection(uint8_t param)
{
#ifdef DEBUG
Serial.println(F("UI_func_voice_selection()"));
#endif
menu_state = MENU_VOICE;
strip_extension(bank_names[configuration.bank], bank_name);
//LCDML.DISP_clear();
// display bank and voice number
lcd.show(0, 0, 2, configuration.bank);
lcd.show(1, 0, 2, configuration.voice + 1);
// display names
lcd.show(0, 4, 10, bank_name);
lcd.show(1, 4, 10, voice_names[configuration.voice]);
// display selections
switch (menu_voice)
{
case MENU_VOICE_BANK:
lcd.show(0, 2, 2, " [");
lcd.show(0, 14, 2, "] ");
lcd.show(1, 2, 2, " ");
lcd.show(1, 14, 2, " ");
break;
case MENU_VOICE_SOUND:
lcd.show(0, 2, 2, " ");
lcd.show(0, 14, 2, " ");
lcd.show(1, 2, 2, " [");
lcd.show(1, 14, 2, "] ");
break;
}
for (int x = 2; x < LCD_rows; x++) {
lcd.show(x, 0, LCD_cols+1, " ");
}
}
void UI_func_volume(uint8_t param)
{
#ifdef DEBUG
Serial.println(F("UI_func_volume()"));
#endif
menu_state = MENU_VOLUME;
back_from_volume = 0;
// update LCD content
LCDML.DISP_clear();
lcd.show(0, 0, 8, "Volume: ");
lcd.show(0, 9, 3, configuration.vol);
lcd.setCursor(1, 1);
for (uint8_t i = 0; i < LCD_cols; i++)
{
if (i < int((LCD_cols - 2) * configuration.vol / 100.0))
lcd.print("*");
else
lcd.print(" ");
}
lcd.show(1, 0, 1, "[");
lcd.show(1, 15, 1, "]");
}
void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign)
{
int16_t tmp = 0;
uint16_t p;
if (size < 1)
return;
if (brackets == true)
lcd.print(F("["));
if (sign == true)
{
if (var < 0)
{
lcd.print(F("-"));
var = abs(var);
}
else if (var > 0)
lcd.print(F("+"));
else
lcd.print(F(" "));
}
for (int8_t i = size - 1 ; i >= 0; i--)
{
p = int(pow(10, i));
tmp = int(var / p);
if (tmp == 0)
{
if (zeros == true)
lcd.print(F("0"));
else
lcd.print(F(" "));
}
else
lcd.print(tmp);
var -= (tmp * p);
}
if (brackets == true)
lcd.print(F("]"));
}
void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign)
{
float fraction;
float number;
if (size_number < 1 || size_fraction < 1)
return;
fraction = modff(var, &number);
if (brackets == true)
lcd.print(F("["));
lcd_display_int(int(number), size_number, zeros, false, sign);
lcd.print(F("."));
lcd_display_int(round(fraction * pow(10, size_fraction)), size_fraction, true, false, false);
if (brackets == true)
lcd.print(F("]"));
}
#endif
#endif