|
|
|
/*
|
|
|
|
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 <LiquidCrystal_I2C.h>
|
|
|
|
#include <LCDMenuLib2.h>
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#define _LCDML_DISP_cols LCD_cols
|
|
|
|
#define _LCDML_DISP_rows LCD_rows
|
|
|
|
|
|
|
|
#define _LCDML_DISP_cfg_cursor 0x7E // cursor Symbol
|
|
|
|
#define _LCDML_DISP_cfg_scrollbar 1 // enable a scrollbar
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
GLOBAL
|
|
|
|
***********************************************************************/
|
|
|
|
LiquidCrystal_I2C lcd(0x27, _LCDML_DISP_cols, _LCDML_DISP_rows);
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
void lcdml_menu_display(void);
|
|
|
|
void lcdml_menu_clear(void);
|
|
|
|
void lcdml_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_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_back(uint8_t param);
|
|
|
|
void UI_func_goToRootMenu(uint8_t param);
|
|
|
|
|
|
|
|
LCDMenuLib2_menu LCDML_0(255, 0, 0, NULL, NULL); // 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, "Depth", UI_func_chorus_depth);
|
|
|
|
LCDML_add(9, LCDML_0_2_2, 3, "Level", UI_func_chorus_level);
|
|
|
|
LCDML_add(10, LCDML_0_2, 3, "Delay", NULL);
|
|
|
|
LCDML_add(11, LCDML_0_2_3, 1, "Time", UI_func_delay_time);
|
|
|
|
LCDML_add(12, LCDML_0_2_3, 2, "Feedback", UI_func_delay_feedback);
|
|
|
|
LCDML_add(13, LCDML_0_2_3, 3, "Level", UI_func_delay_level);
|
|
|
|
LCDML_add(14, LCDML_0_2, 4, "Filter", NULL);
|
|
|
|
LCDML_add(15, LCDML_0_2_4, 1, "Cutoff", UI_func_filter_cutoff);
|
|
|
|
LCDML_add(16, LCDML_0_2_4, 2, "Resonance", UI_func_filter_resonance);
|
|
|
|
LCDML_add(17, LCDML_0, 3, "Store", NULL);
|
|
|
|
LCDML_add(18, LCDML_0, 4, "System", NULL);
|
|
|
|
LCDML_add(19, LCDML_0, 5, "Info", NULL);
|
|
|
|
|
|
|
|
#define _LCDML_DISP_cnt 19
|
|
|
|
|
|
|
|
// create menu
|
|
|
|
LCDML_createMenu(_LCDML_DISP_cnt);
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
CONTROL
|
|
|
|
***********************************************************************/
|
|
|
|
#define g_LCDML_CONTROL_button_long_press 800 // ms
|
|
|
|
#define g_LCDML_CONTROL_button_short_press 120 // ms
|
|
|
|
|
|
|
|
#define ENCODER_OPTIMIZE_INTERRUPTS //Only when using pin2/3 (or 20/21 on mega)
|
|
|
|
#include <Encoder.h>
|
|
|
|
|
|
|
|
Encoder ENCODER(ENC_R_PIN_B, ENC_R_PIN_A);
|
|
|
|
|
|
|
|
long g_LCDML_CONTROL_button_press_time = 0;
|
|
|
|
bool g_LCDML_CONTROL_button_prev = HIGH;
|
|
|
|
|
|
|
|
void lcdml_menu_control(void)
|
|
|
|
{
|
|
|
|
// If something must init, put in in the setup condition
|
|
|
|
if (LCDML.BT_setup())
|
|
|
|
{
|
|
|
|
//pinMode(ENC_R_PIN_A, INPUT_PULLUP);
|
|
|
|
//pinMode(ENC_R_PIN_B, INPUT_PULLUP);
|
|
|
|
pinMode(BUT_R_PIN, INPUT_PULLUP);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Volatile Variable
|
|
|
|
long g_LCDML_CONTROL_Encoder_position = ENCODER.read();
|
|
|
|
bool button = digitalRead(BUT_R_PIN);
|
|
|
|
|
|
|
|
if (g_LCDML_CONTROL_Encoder_position <= -3) {
|
|
|
|
|
|
|
|
if (!button)
|
|
|
|
{
|
|
|
|
LCDML.BT_left();
|
|
|
|
g_LCDML_CONTROL_button_prev = LOW;
|
|
|
|
g_LCDML_CONTROL_button_press_time = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LCDML.BT_down();
|
|
|
|
}
|
|
|
|
ENCODER.write(g_LCDML_CONTROL_Encoder_position + 4);
|
|
|
|
}
|
|
|
|
else if (g_LCDML_CONTROL_Encoder_position >= 3)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!button)
|
|
|
|
{
|
|
|
|
LCDML.BT_right();
|
|
|
|
g_LCDML_CONTROL_button_prev = LOW;
|
|
|
|
g_LCDML_CONTROL_button_press_time = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LCDML.BT_up();
|
|
|
|
}
|
|
|
|
ENCODER.write(g_LCDML_CONTROL_Encoder_position - 4);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!button && g_LCDML_CONTROL_button_prev) //falling edge, button pressed
|
|
|
|
{
|
|
|
|
g_LCDML_CONTROL_button_prev = LOW;
|
|
|
|
g_LCDML_CONTROL_button_press_time = millis();
|
|
|
|
}
|
|
|
|
else if (button && !g_LCDML_CONTROL_button_prev) //rising edge, button not active
|
|
|
|
{
|
|
|
|
g_LCDML_CONTROL_button_prev = HIGH;
|
|
|
|
|
|
|
|
if (g_LCDML_CONTROL_button_press_time < 0)
|
|
|
|
{
|
|
|
|
g_LCDML_CONTROL_button_press_time = millis();
|
|
|
|
//Reset for left right action
|
|
|
|
}
|
|
|
|
else if ((millis() - g_LCDML_CONTROL_button_press_time) >= g_LCDML_CONTROL_button_long_press)
|
|
|
|
{
|
|
|
|
LCDML.BT_quit();
|
|
|
|
}
|
|
|
|
else if ((millis() - g_LCDML_CONTROL_button_press_time) >= g_LCDML_CONTROL_button_short_press)
|
|
|
|
{
|
|
|
|
LCDML.BT_enter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
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) {
|
|
|
|
lcd.setCursor((_LCDML_DISP_cols - 1), n);
|
|
|
|
lcd.write((uint8_t)0);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
lcd.setCursor((_LCDML_DISP_cols - 1), 0);
|
|
|
|
lcd.write((uint8_t)1);
|
|
|
|
} else if (scrollbar_cur_pos == (scrollbar_max - 1)) {
|
|
|
|
// max pos
|
|
|
|
lcd.setCursor((_LCDML_DISP_cols - 1), (n_max - 1));
|
|
|
|
lcd.write((uint8_t)4);
|
|
|
|
} else {
|
|
|
|
// between
|
|
|
|
lcd.setCursor((_LCDML_DISP_cols - 1), scroll_pos / n_max);
|
|
|
|
lcd.write((uint8_t)(scroll_pos % n_max) + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
MENU
|
|
|
|
***********************************************************************/
|
|
|
|
void UI_func_sound(uint8_t param)
|
|
|
|
{
|
|
|
|
if (LCDML.FUNC_setup()) // ****** SETUP *********
|
|
|
|
{
|
|
|
|
// setup function
|
|
|
|
lcd.setCursor(0, 0);
|
|
|
|
lcd.print(F("Filter Res."));
|
|
|
|
lcd.setCursor(0, 1);
|
|
|
|
lcd.print(F("<valua>"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LCDML.FUNC_loop()) // ****** LOOP *********
|
|
|
|
{
|
|
|
|
if (LCDML.BT_checkAny()) { // 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)
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_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_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(F("LCDMenuLib2"));
|
|
|
|
}
|
|
|
|
|
|
|
|
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_checkAny()) { // 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_screensaver(uint8_t param)
|
|
|
|
{
|
|
|
|
if (LCDML.FUNC_setup()) // ****** SETUP *********
|
|
|
|
{
|
|
|
|
// update LCD content
|
|
|
|
lcd.setCursor(0, 0); // set cursor
|
|
|
|
lcd.print("screensaver"); // print change content
|
|
|
|
lcd.setCursor(0, 1); // set cursor
|
|
|
|
lcd.print("press any key");
|
|
|
|
LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LCDML.FUNC_loop())
|
|
|
|
{
|
|
|
|
if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right)
|
|
|
|
{
|
|
|
|
LCDML.FUNC_goBackToMenu(); // leave this function
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LCDML.FUNC_close())
|
|
|
|
{
|
|
|
|
// The screensaver go to the root menu
|
|
|
|
LCDML.MENU_goRoot();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UI_func_goToRootMenu(uint8_t param)
|
|
|
|
{
|
|
|
|
if (LCDML.FUNC_setup()) // ****** SETUP *********
|
|
|
|
{
|
|
|
|
// go to root and display menu
|
|
|
|
LCDML.MENU_goRoot();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|