Storing current state of LCDMenuLib2 integration.

pull/3/head
Holger Wirtz 5 years ago
parent 6049fa6e91
commit 3599442a2c
  1. 199
      MicroDexed.ino
  2. 378
      UI.hpp
  3. 5
      config.h

@ -23,18 +23,21 @@
*/
#include "config.h"
#include <limits.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <MIDI.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <LCDMenuLib2.h>
#include "EEPROMAnything.h"
#include "midi_devices.hpp"
#include <limits.h>
#include "dexed.h"
#include "dexed_sysex.h"
#include "PluginFx.h"
#include "UI.hpp"
AudioPlayQueue queue1;
AudioAnalyzePeak peak1;
@ -105,13 +108,19 @@ value_change_t soften_volume = {0.0, 0};
value_change_t soften_filter_res = {0.0, 0};
value_change_t soften_filter_cut = {0.0, 0};
/***********************************************************************
LCDMenuLib2
***********************************************************************/
extern LiquidCrystal_I2C lcd;
extern LCDMenuLib2 LCDML;
void setup()
{
//while (!Serial) ; // wait for Arduino Serial Monitor
Serial.begin(SERIAL_SPEED);
delay(220);
Serial.println(F("MicroDexed based on https://github.com/asb2m10/dexed"));
Serial.println(F("(c)2018,2019 H. Wirtz <wirtz@parasitstudio.de>"));
Serial.println(F("https://codeberg.org/dcoredump/MicroDexed"));
@ -247,6 +256,34 @@ void setup()
#endif
AudioInterrupts();
// LCD Begin
lcd.init();
lcd.backlight();
lcd.clear();
lcd.blink_off();
lcd.cursor_off();
lcd.backlight();
lcd.setCursor(1, 0);
lcd.print("MicroDexed");
lcd.setCursor(0, 1);
lcd.print("(c)parasiTstudio");
delay(1000);
// 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]);
// 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_screensaver, 10000); // set to 10 seconds
Serial.println(F("<setup end>"));
}
@ -255,101 +292,107 @@ void loop()
int16_t* audio_buffer; // pointer to AUDIO_BLOCK_SAMPLES * int16_t
const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);
// Main sound calculation
if (queue1.available() && fill_audio_buffer > audio_block_time_us - 10)
while (42 == 42)
{
fill_audio_buffer = 0;
audio_buffer = queue1.getBuffer();
elapsedMicros t1;
dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer);
if (t1 > audio_block_time_us) // everything greater 2.9ms is a buffer underrun!
xrun++;
if (t1 > render_time_max)
render_time_max = t1;
if (peak1.available())
// Main sound calculation
if (queue1.available() && fill_audio_buffer > audio_block_time_us - 10)
{
if (peak1.read() > 0.99)
peak++;
}
fill_audio_buffer = 0;
audio_buffer = queue1.getBuffer();
elapsedMicros t1;
dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer);
if (t1 > audio_block_time_us) // everything greater 2.9ms is a buffer underrun!
xrun++;
if (t1 > render_time_max)
render_time_max = t1;
if (peak1.available())
{
if (peak1.read() > 0.99)
peak++;
}
#ifndef TEENSY_AUDIO_BOARD
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
audio_buffer[i] *= configuration.vol;
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
audio_buffer[i] *= configuration.vol;
#endif
queue1.playBuffer();
}
queue1.playBuffer();
}
// EEPROM update handling
if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true)
{
// only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore
eeprom_update();
}
// EEPROM update handling
if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true)
{
// only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore
eeprom_update();
}
// MIDI input handling
check_midi_devices();
// MIDI input handling
check_midi_devices();
// CONTROL-RATE-EVENT-HANDLING
if (control_rate > CONTROL_RATE_MS)
{
control_rate = 0;
// CONTROL-RATE-EVENT-HANDLING
if (control_rate > CONTROL_RATE_MS)
{
// LCD Menu
LCDML.loop();
// Shutdown unused voices
active_voices = dexed->getNumNotesPlaying();
control_rate = 0;
// check for value changes
if (soften_volume.steps > 0)
{
// soften volume value
soften_volume.steps--;
set_volume(configuration.vol + soften_volume.diff, configuration.pan);
// Shutdown unused voices
active_voices = dexed->getNumNotesPlaying();
// check for value changes
if (soften_volume.steps > 0)
{
// soften volume value
soften_volume.steps--;
set_volume(configuration.vol + soften_volume.diff, configuration.pan);
#ifdef DEBUG
Serial.print(F("Volume: "));
Serial.print(configuration.vol, 5);
Serial.print(F(" Volume step: "));
Serial.print(soften_volume.steps);
Serial.print(F(" Volume diff: "));
Serial.println(soften_volume.diff, 5);
Serial.print(F("Volume: "));
Serial.print(configuration.vol, 5);
Serial.print(F(" Volume step: "));
Serial.print(soften_volume.steps);
Serial.print(F(" Volume diff: "));
Serial.println(soften_volume.diff, 5);
#endif
}
if (soften_filter_res.steps > 0)
{
// soften filter resonance value
soften_filter_res.steps--;
dexed->fx.Reso = dexed->fx.Reso + soften_filter_res.diff;
}
if (soften_filter_res.steps > 0)
{
// soften filter resonance value
soften_filter_res.steps--;
dexed->fx.Reso = dexed->fx.Reso + soften_filter_res.diff;
#ifdef DEBUG
Serial.print(F("Filter-Resonance: "));
Serial.print(dexed->fx.Reso, 5);
Serial.print(F(" Filter-Resonance step: "));
Serial.print(soften_filter_res.steps);
Serial.print(F(" Filter-Resonance diff: "));
Serial.println(soften_filter_res.diff, 5);
Serial.print(F("Filter-Resonance: "));
Serial.print(dexed->fx.Reso, 5);
Serial.print(F(" Filter-Resonance step: "));
Serial.print(soften_filter_res.steps);
Serial.print(F(" Filter-Resonance diff: "));
Serial.println(soften_filter_res.diff, 5);
#endif
}
if (soften_filter_cut.steps > 0)
{
// soften filter cutoff value
soften_filter_cut.steps--;
dexed->fx.Cutoff = dexed->fx.Cutoff + soften_filter_cut.diff;
}
if (soften_filter_cut.steps > 0)
{
// soften filter cutoff value
soften_filter_cut.steps--;
dexed->fx.Cutoff = dexed->fx.Cutoff + soften_filter_cut.diff;
#ifdef DEBUG
Serial.print(F("Filter-Cutoff: "));
Serial.print(dexed->fx.Cutoff, 5);
Serial.print(F(" Filter-Cutoff step: "));
Serial.print(soften_filter_cut.steps);
Serial.print(F(" Filter-Cutoff diff: "));
Serial.println(soften_filter_cut.diff, 5);
Serial.print(F("Filter-Cutoff: "));
Serial.print(dexed->fx.Cutoff, 5);
Serial.print(F(" Filter-Cutoff step: "));
Serial.print(soften_filter_cut.steps);
Serial.print(F(" Filter-Cutoff diff: "));
Serial.println(soften_filter_cut.diff, 5);
#endif
}
}
}
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC)
{
cpu_mem_millis -= SHOW_CPU_LOAD_MSEC;
show_cpu_and_mem_usage();
}
if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC)
{
cpu_mem_millis -= SHOW_CPU_LOAD_MSEC;
show_cpu_and_mem_usage();
}
#endif
}
}
/******************************************************************************

378
UI.hpp

@ -0,0 +1,378 @@
/*
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
*/
#ifndef _UI_HPP_
#define _UI_HPP_
#include <LiquidCrystal_I2C.h>
#include <LCDMenuLib2.h>
#include "Arduino.h"
#define _LCDML_DISP_cols 16
#define _LCDML_DISP_rows 2
#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_information(uint8_t param);
void UI_func_screensaver(uint8_t param);
void UI_func_test(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, "Information", UI_func_information);
LCDML_add(1, LCDML_0, 2, "Test", UI_func_test);
LCDML_add(2, LCDML_0, 3, "Screensaver", UI_func_screensaver);
#define _LCDML_DISP_cnt 2
// 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_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_test(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// update LCD content
lcd.setCursor(0, 0); // set cursor
lcd.print("TEST"); // print change content
lcd.setCursor(0, 1); // set cursor
lcd.print("TEST123");
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_back(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// end function and go an layer back
LCDML.FUNC_goBackToMenu(1); // leave this function and go a layer back
}
}*/
void UI_func_goToRootMenu(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// go to root and display menu
LCDML.MENU_goRoot();
}
}
#endif

@ -38,7 +38,7 @@
// $ aplaymidi -p 20:0 <MIDI-File> # e.g. test.mid
// $ arecord -f cd -Dhw:1,0 /tmp/bla.wav
#define VERSION "0.9.5"
#define VERSION "0.9.6"
//*************************************************************************************************
//* DEVICE SETTINGS
@ -101,8 +101,7 @@
//*************************************************************************************************
//* UI AND DATA-STORE SETTINGS
//*************************************************************************************************
#define CONTROL_RATE_MS 50
#define TIMER_UI_HANDLING_MS 100
#define CONTROL_RATE_MS 10
//*************************************************************************************************
//* DEBUG OUTPUT SETTINGS

Loading…
Cancel
Save