Removed old UI code.

Added new UI code based on LiquidMenu.
master
Holger Wirtz 6 years ago
parent 1605a486f0
commit b94ee150fc
  1. 43
      EEPROMAnything.h
  2. 86
      LiquidCrystalPlus_I2C.h
  3. 171
      MicroMDAEPiano.ino
  4. 35
      UI.cpp
  5. 57
      UI.hpp
  6. 23
      config.h
  7. 5
      mdaEPiano.cpp
  8. 2
      mdaEPiano.h

@ -21,26 +21,31 @@
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef UI_H_INCLUDED
#define UI_H_INCLUDED
// Idea from: https://playground.arduino.cc/Code/EEPROMWriteAnything/
/*
#include "config.h"
#include "LiquidCrystalPlus_I2C.h"
#include <Bounce.h>
#include "Encoder4.h"
#include <EEPROM.h>
#include <Arduino.h> // for type definitions
uint32_t crc32(uint8_t* calc_start, uint16_t calc_bytes);
template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
uint8_t* p = (uint8_t*)(const void*)&value;
uint16_t i;
uint32_t checksum=crc32(p+4,sizeof(value)-4);
class UI
*p=checksum;
for (i = 0; i < sizeof(value); i++)
EEPROM.update(ee++, *p++);
return i;
}
template <class T> int EEPROM_readAnything(int ee, T& value)
{
public:
UI();
~UI();
private:
LiquidCrystalPlus_I2C lcd;
Encoder4 enc[2];
int32_t enc_val[2];
Bounce but[2];
uint8_t* p = (uint8_t*)(void*)&value;
unsigned int i;
for (i = 0; i < sizeof(value); i++)
*p++ = EEPROM.read(ee++);
return i;
}
*/
#endif

@ -1,86 +0,0 @@
/*
MicroMDAEPiano
MicroMDAEPiano is a port of the MDA-EPiano sound engine
(https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6 with audio shield.
(c)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 LIQUIDCRYSTALPLUS_I2C_H_INCLUDED
#define LIQUIDCRYSTALPLUS_I2C_H_INCLUDED
#include <LiquidCrystal_I2C.h> // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c
#define STRING_BUF_SIZE 21
class LiquidCrystalPlus_I2C : public LiquidCrystal_I2C
{
public:
using LiquidCrystal_I2C::LiquidCrystal_I2C;
void show(uint8_t y, uint8_t x, uint8_t fs, char *str)
{
_show(y, x, fs, str, false, false);
}
void show(uint8_t y, uint8_t x, uint8_t fs, long num)
{
char _buf10[STRING_BUF_SIZE];
_show(y, x, fs, itoa(num, _buf10, 10), true, true);
}
private:
void _show(uint8_t pos_y, uint8_t pos_x, uint8_t field_size, char *str, bool justify_right, bool fill_zero)
{
{
char tmp[STRING_BUF_SIZE];
char *s = tmp;
uint8_t l = strlen(str);
memset(tmp, 0, sizeof(tmp));
if (fill_zero == true)
memset(tmp, '0', field_size);
else
memset(tmp, 0x20, field_size - 1); // blank
if (l > field_size)
l = field_size;
if (justify_right == true)
s += field_size - l;
strncpy(s, str, l);
setCursor(pos_x, pos_y);
print(tmp);
#ifdef DEBUG
Serial.print(pos_y, DEC);
Serial.print(F("/"));
Serial.print(pos_x, DEC);
Serial.print(F(": ["));
Serial.print(tmp);
Serial.println(F("]"));
#endif
}
}
};
#endif

@ -27,6 +27,7 @@
#include <SPI.h>
#include <MIDI.h>
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include <limits.h>
#include "mdaEPiano.h"
#ifdef USE_XFADE_DATA
@ -38,6 +39,7 @@
#include "Encoder4.h"
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>
#include "UI.hpp"
#include "midi_devices.hpp"
//*************************************************************************************************
@ -102,18 +104,17 @@ float vol = VOLUME;
float vol_right = 1.0;
float vol_left = 1.0;
elapsedMicros fill_audio_buffer;
elapsedMillis control_rate;
elapsedMillis autostore;
const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);
config_t configuration = {0xffff, 0, VOLUME, 0.5f, DEFAULT_MIDI_CHANNEL};
bool eeprom_update_flag = false;
#ifdef SHOW_CPU_LOAD_MSEC
elapsedMillis cpu_mem_millis;
#endif
enum MDA_EP_PARAM { DECAY, RELEASE, HARDNESS, TREBLE, PAN_TREM, LFO_RATE, VELOCITY_SENSE, STEREO, MAX_POLY, TUNE, DETUNE, OVERDRIVE };
LiquidLine welcome_line1(1, 0, "MicroMDAEPiano");
LiquidLine welcome_line2(0, 1, "(c)parasiTstudio");
LiquidScreen welcome_screen(welcome_line1, welcome_line2);
LiquidMenu menu(lcd);
//*************************************************************************************************
//* SETUP FUNCTION
//*************************************************************************************************
@ -121,17 +122,11 @@ LiquidMenu menu(lcd);
void setup()
{
//while (!Serial) ; // wait for Arduino Serial Monitor
Serial.begin(SERIAL_SPEED);
delay(220);
// LCD display setup
lcd.init();
lcd.blink_off();
lcd.cursor_off();
lcd.backlight();
lcd.noAutoscroll();
menu_init();
menu.add_screen(welcome_screen);
Serial.begin(SERIAL_SPEED);
delay(500);
// Encoder setup
enc[0].write(INITIAL_ENC_L_VALUE);
@ -165,12 +160,34 @@ void setup()
#ifdef TEENSY_AUDIO_BOARD
sgtl5000_1.enable();
//sgtl5000_1.dacVolumeRamp();
sgtl5000_1.dacVolumeRampLinear();
sgtl5000_1.dacVolumeRamp();
sgtl5000_1.dacVolume(1.0);
//sgtl5000_1.dacVolumeRampLinear();
sgtl5000_1.unmuteHeadphone();
sgtl5000_1.unmuteLineout();
sgtl5000_1.autoVolumeDisable(); // turn off AGC
sgtl5000_1.volume(1.0, 1.0);
sgtl5000_1.unmuteHeadphone();
sgtl5000_1.volume(0.5, 0.5); // Headphone volume
sgtl5000_1.lineOutLevel(SGTL5000_LINEOUT_LEVEL);
sgtl5000_1.audioPostProcessorEnable();
sgtl5000_1.autoVolumeControl(1, 1, 1, 0.9, 0.01, 0.05);
sgtl5000_1.autoVolumeEnable();
sgtl5000_1.surroundSoundEnable();
sgtl5000_1.surroundSound(7, 3); // Configures virtual surround width from 0 (mono) to 7 (widest). select may be set to 1 (disable), 2 (mono input) or 3 (stereo input).
sgtl5000_1.enhanceBassEnable();
sgtl5000_1.enhanceBass(1.0, 0.2, 1, 2); // Configures the bass enhancement by setting the levels of the original stereo signal and the bass-enhanced mono level which will be mixed together. The high-pass filter may be enabled (0) or bypassed (1).
/* The cutoff frequency is specified as follows:
value frequency
0 80Hz
1 100Hz
2 125Hz
3 150Hz
4 175Hz
5 200Hz
6 225Hz
*/
//sgtl5000_1.eqBands(bass, mid_bass, midrange, mid_treble, treble);
Serial.println(F("Teensy-Audio-Board enabled."));
#elif defined(TGA_AUDIO_BOARD)
wm8731_1.enable();
wm8731_1.volume(1.0);
@ -213,10 +230,12 @@ void setup()
mixer_l.gain(1, 0.3);
AudioInterrupts();
menu.update();
Serial.println(F("<setup end>"));
menu.next_screen();
menu.update();
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
show_cpu_and_mem_usage();
cpu_mem_millis = 0;
@ -287,7 +306,17 @@ void loop()
}
check_midi_devices();
// CONTROL-RATE-EVENT-HANDLING
if (control_rate > CONTROL_RATE_MS)
{
control_rate = 0;
}
}
//*************************************************************************************************
//* PROGRAM FUNCTIONS
@ -419,106 +448,60 @@ bool checkMidiChannel(byte inChannel)
void set_volume(float v, float vr, float vl)
{
vol = v;
vol_right = vr;
vol_left = vl;
EEPROM.update(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR, uint8_t(vol * UCHAR_MAX));
EEPROM.update(EEPROM_OFFSET + EEPROM_VOLUME_RIGHT_ADDR, uint8_t(vol_right * UCHAR_MAX));
EEPROM.update(EEPROM_OFFSET + EEPROM_VOLUME_LEFT_ADDR, uint8_t(vol_left * UCHAR_MAX));
update_eeprom_checksum();
#ifdef DEBUG
uint8_t tmp;
Serial.print(F("Setting volume: VOL="));
Serial.print(v, DEC);
Serial.print(F("["));
tmp = EEPROM.read(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR);
Serial.print(tmp, DEC);
Serial.print(F("/"));
Serial.print(float(tmp) / UCHAR_MAX, DEC);
Serial.print(F("] VOL_L="));
Serial.print(vl, DEC);
Serial.print(F("["));
tmp = EEPROM.read(EEPROM_OFFSET + EEPROM_VOLUME_LEFT_ADDR);
Serial.print(tmp, DEC);
Serial.print(F("/"));
Serial.print(float(tmp) / UCHAR_MAX, DEC);
Serial.print(F("] VOL_R="));
Serial.print(vr, DEC);
Serial.print(F("["));
tmp = EEPROM.read(EEPROM_OFFSET + EEPROM_VOLUME_RIGHT_ADDR);
Serial.print(tmp, DEC);
Serial.print(F("/"));
Serial.print(float(tmp) / UCHAR_MAX, DEC);
Serial.println(F("]"));
#endif
#ifdef TEENSY_AUDIO_BOARD
sgtl5000_1.dacVolume(vol * vol_left, vol * vol_right);
#elif TGA_AUDIO_BOARD
wm8731_1.volume(vol);
#else
volume_r.gain(vr);
volume_l.gain(vl);
#endif
;
}
//*************************************************************************************************
//* EEPROM FUNCTIONS
//*************************************************************************************************
/******************************************************************************
EEPROM HELPER
******************************************************************************/
void initial_values_from_eeprom(void)
{
uint32_t crc_eeprom = read_eeprom_checksum();
uint32_t crc = eeprom_crc32(EEPROM_OFFSET, EEPROM_DATA_LENGTH);
uint32_t checksum;
config_t tmp_conf;
EEPROM_readAnything(EEPROM_START_ADDRESS, tmp_conf);
checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4);
#ifdef DEBUG
Serial.print(F("EEPROM checksum: 0x"));
Serial.print(crc_eeprom, HEX);
Serial.print(tmp_conf.checksum, HEX);
Serial.print(F(" / 0x"));
Serial.print(crc, HEX);
Serial.print(checksum, HEX);
#endif
if (crc_eeprom != crc)
if (checksum != tmp_conf.checksum)
{
#ifdef DEBUG
Serial.print(F(" - mismatch -> initializing EEPROM!"));
#endif
EEPROM.update(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR, uint8_t(vol * UCHAR_MAX));
EEPROM.update(EEPROM_OFFSET + EEPROM_VOLUME_RIGHT_ADDR, uint8_t(vol_right * UCHAR_MAX));
EEPROM.update(EEPROM_OFFSET + EEPROM_VOLUME_LEFT_ADDR, uint8_t(vol_left * UCHAR_MAX));
update_eeprom_checksum();
eeprom_update();
}
else
{
vol = float(EEPROM.read(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR)) / UCHAR_MAX;
vol_right = float(EEPROM.read(EEPROM_OFFSET + EEPROM_VOLUME_RIGHT_ADDR)) / UCHAR_MAX;
vol_left = float(EEPROM.read(EEPROM_OFFSET + EEPROM_VOLUME_LEFT_ADDR)) / UCHAR_MAX;
EEPROM_readAnything(EEPROM_START_ADDRESS, configuration);
Serial.print(F(" - OK, loading!"));
}
#ifdef DEBUG
Serial.println();
#endif
}
uint32_t read_eeprom_checksum(void)
{
return (EEPROM.read(EEPROM_CRC32_ADDR) << 24 | EEPROM.read(EEPROM_CRC32_ADDR + 1) << 16 | EEPROM.read(EEPROM_CRC32_ADDR + 2) << 8 | EEPROM.read(EEPROM_CRC32_ADDR + 3));
}
void update_eeprom_checksum(void)
void eeprom_write(void)
{
write_eeprom_checksum(eeprom_crc32(EEPROM_OFFSET, EEPROM_DATA_LENGTH)); // recalculate crc and write to eeprom
autostore = 0;
eeprom_update_flag = true;
}
void write_eeprom_checksum(uint32_t crc)
void eeprom_update(void)
{
EEPROM.update(EEPROM_CRC32_ADDR, (crc & 0xff000000) >> 24);
EEPROM.update(EEPROM_CRC32_ADDR + 1, (crc & 0x00ff0000) >> 16);
EEPROM.update(EEPROM_CRC32_ADDR + 2, (crc & 0x0000ff00) >> 8);
EEPROM.update(EEPROM_CRC32_ADDR + 3, crc & 0x000000ff);
eeprom_update_flag = false;
configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4);
EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration);
Serial.println(F("Updating EEPROM with configuration data"));
}
uint32_t eeprom_crc32(uint16_t calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc
uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc
{
const uint32_t crc_table[16] =
{
@ -529,20 +512,16 @@ uint32_t eeprom_crc32(uint16_t calc_start, uint16_t calc_bytes) // base code fro
};
uint32_t crc = ~0L;
if (calc_start + calc_bytes > EEPROM.length())
calc_bytes = EEPROM.length() - calc_start;
for (uint16_t index = calc_start ; index < (calc_start + calc_bytes) ; ++index)
for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index)
{
crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4);
crc = ~crc;
}
return (crc);
}
//*************************************************************************************************
//* DEBUG FUNCTIONS
//*************************************************************************************************

@ -1,35 +0,0 @@
/*
MicroMDAEPiano
MicroMDAEPiano is a port of the MDA-EPiano sound engine
(https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6 with audio shield.
(c)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
*/
#include "config.h"
#include "UI.h"
/*
UI::UI()
{
LiquidCrystalPlus_I2C lcd(LCD_I2C_ADDRESS, LCD_CHARS, LCD_LINES);
enc[] = {Encoder4(ENC_L_PIN_A, ENC_L_PIN_B), Encoder4(ENC_R_PIN_A, ENC_R_PIN_B)};
enc_val[] = {INITIAL_ENC_L_VALUE, INITIAL_ENC_R_VALUE};
but[] = {Bounce(BUT_L_PIN, BUT_DEBOUNCE_MS), Bounce(BUT_R_PIN, BUT_DEBOUNCE_MS)};
}
*/

@ -0,0 +1,57 @@
/*
MicroMDAEPiano
MicroMDAEPiano is a port of the MDA-EPiano sound engine
(https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6 with audio shield.
(c)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
*/
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>
#ifndef UI_HPP_INCLUDED
#define UI_HPP_INCLUDED
extern LiquidCrystal_I2C lcd;
LiquidMenu menu(lcd);
// Welcome screen
LiquidLine welcome_line1(1, 0, "MicroMDAEPiano");
LiquidLine welcome_line2(0, 1, "(c)parasiTstudio");
LiquidScreen welcome_screen(welcome_line1, welcome_line2);
// Welcome screen
LiquidLine main_line1(0, 0, "Volume:");
LiquidLine main_line2(0, 1, "Voice");
LiquidScreen main_screen(main_line1, main_line2);
void menu_init(void)
{
// LCD display setup
lcd.init();
lcd.blink_off();
lcd.cursor_off();
lcd.backlight();
lcd.noAutoscroll();
menu.add_screen(welcome_screen);
menu.add_screen(main_screen);
menu.update();
}
#endif

@ -25,6 +25,7 @@
#define CONFIG_H_INCLUDED
#include "midinotes.h"
#include <Arduino.h>
// ATTENTION! For better latency you have to redefine AUDIO_BLOCK_SAMPLES from
// 128 to 64 in <ARDUINO-IDE-DIR>/cores/teensy3/AudioStream.h
@ -102,19 +103,14 @@
#define LCD_LINES 2
// EEPROM address
#define EEPROM_OFFSET 0
#define EEPROM_DATA_LENGTH 5
#define EEPROM_CRC32_ADDR EEPROM.length()-sizeof(uint32_t)
#define EEPROM_BANK_ADDR 0
#define EEPROM_VOICE_ADDR 1
#define EEPROM_MASTER_VOLUME_ADDR 2
#define EEPROM_VOLUME_RIGHT_ADDR 3
#define EEPROM_VOLUME_LEFT_ADDR 4
#define EEPROM_START_ADDRESS 0
//*************************************************************************************************
//* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!!
//*************************************************************************************************
#define CONTROL_RATE_MS 100
// MIDI
#ifdef MIDI_DEVICE_USB
#define USBCON 1
@ -134,4 +130,13 @@
#define NVOICES 32
#endif
// struct for holding the current configuration
struct config_t {
uint32_t checksum;
uint8_t voice;
float vol;
float pan;
uint8_t midi_channel;
};
#endif

@ -112,6 +112,7 @@ mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster)
guiUpdate = 0;
vol = VOLUME;
update();
// suspend();
}
@ -239,8 +240,8 @@ void mdaEPiano::process(int16_t* outputs_r, int16_t* outputs_l)
l = 1.0;
else if (l < -1.0)
l = -1.0;
outputs_l[frame] = static_cast<int16_t>(l * 0x7fff) >> REDUCE_LOUDNESS;
outputs_r[frame] = static_cast<int16_t>(r * 0x7fff) >> REDUCE_LOUDNESS;
outputs_l[frame] = static_cast<int16_t>(l * vol * 0x7fff) >> REDUCE_LOUDNESS;
outputs_r[frame] = static_cast<int16_t>(r * vol * 0x7fff) >> REDUCE_LOUDNESS;
}
if (fabs(tl) < 1.0e-10) tl = 0.0f; //anti-denormal

@ -108,7 +108,7 @@ class mdaEPiano
float treb, tfrq, tl, tr;
float tune, fine, random, stretch, overdrive;
float muff, muffvel, sizevel, velsens, volume, modwhl;
float vol;
uint8_t curProgram;
};

Loading…
Cancel
Save