diff --git a/LiquidCrystalPlus_I2C.h b/Disp_Plus.h similarity index 81% rename from LiquidCrystalPlus_I2C.h rename to Disp_Plus.h index 6c8cd33..ae73c13 100644 --- a/LiquidCrystalPlus_I2C.h +++ b/Disp_Plus.h @@ -23,20 +23,19 @@ */ -#include // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c - -#ifndef LIQUIDCRYSTALPLUS_I2C_H_INCLUDED -#define LIQUIDCRYSTALPLUS_I2C_H_INCLUDED +#ifndef DISP_PLUS_H_INCLUDED +#define DISP_PLUS_H_INCLUDED #define STRING_BUFFER_SIZE 21 -class LiquidCrystalPlus_I2C : public LiquidCrystal_I2C +template +class Disp_Plus : public T { public: - using LiquidCrystal_I2C::LiquidCrystal_I2C; + using T::T; - void show(uint8_t y, uint8_t x, uint8_t fs, char *str) + void show(uint8_t y, uint8_t x, uint8_t fs, const char *str) { _show(y, x, fs, str, false, false); } @@ -49,7 +48,7 @@ class LiquidCrystalPlus_I2C : public LiquidCrystal_I2C } private: - void _show(uint8_t pos_y, uint8_t pos_x, uint8_t field_size, char *str, bool justify_right, bool fill_zero) + void _show(uint8_t pos_y, uint8_t pos_x, uint8_t field_size, const char *str, bool justify_right, bool fill_zero) { { char tmp[STRING_BUFFER_SIZE]; @@ -70,8 +69,9 @@ class LiquidCrystalPlus_I2C : public LiquidCrystal_I2C strncpy(s, str, l); - setCursor(pos_x, pos_y); - print(tmp); + //setCursor(pos_x * getMaxCharWidth(), pos_y * getMaxCharHeight()); + this->setCursor(pos_x, pos_y ); + this->print(tmp); #ifdef DEBUG Serial.print(pos_y, DEC); diff --git a/MicroDexed.ino b/MicroDexed.ino index ad0639f..80b17da 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -30,7 +30,6 @@ #include #include #include -#include "UI.hpp" #include "EEPROMAnything.h" #include "midi_devices.hpp" #include "dexed.h" @@ -39,6 +38,7 @@ #include "effect_stereo_mono.h" #include "PluginFx.h" #include "SoftenValue.hpp" +#include "UI.hpp" AudioPlayQueue queue1; AudioAnalyzePeak peak1; @@ -50,6 +50,9 @@ AudioMixer4 master_mixer_r; AudioMixer4 master_mixer_l; AudioAmplifier volume_r; AudioAmplifier volume_l; +#if defined(AUDIO_DEVICE_USB) +AudioOutputUSB usb1; +#endif AudioEffectStereoMono stereomono1; AudioConnection patchCord0(queue1, peak1); AudioConnection patchCord1(queue1, 0, delay_fb_mixer, 0); @@ -79,37 +82,41 @@ AudioConnection patchCord17(delay1, 0, master_mixer_r, 2); AudioConnection patchCord18(delay1, 0, master_mixer_l, 2); AudioConnection patchCord19(master_mixer_r, volume_r); AudioConnection patchCord20(master_mixer_l, volume_l); + AudioConnection patchCord21(volume_r, 0, stereomono1, 0); AudioConnection patchCord22(volume_l, 0, stereomono1, 1); -#ifdef MIDI_DEVICE_USB -AudioOutputUSB usb1; +#ifdef AUDIO_DEVICE_USB AudioConnection patchCord23(stereomono1, 0, usb1, 0); AudioConnection patchCord24(stereomono1, 1, usb1, 1); #endif #if defined(TEENSY_AUDIO_BOARD) AudioOutputI2S i2s1; AudioConnection patchCord25(stereomono1, 0, i2s1, 0); -AudioConnection patchCord26(stereomono1, 1, i2s1, 1); +AudioConnection patchCord26(stereomono1, 0, i2s1, 1); AudioControlSGTL5000 sgtl5000_1; -#elif defined(TGA_AUDIO_BOARD) +#elif defined (I2S_AUDIO_ONLY) AudioOutputI2S i2s1; AudioConnection patchCord27(stereomono1, 0, i2s1, 0); -AudioConnection patchCord28(stereomono1, 1, i2s1, 1); +AudioConnection patchCord28(stereomono1, 0, i2s1, 1); +#elif defined(TGA_AUDIO_BOARD) +AudioOutputI2S i2s1; +AudioConnection patchCord29(stereomono1, 0, i2s1, 0); +AudioConnection patchCord30(stereomono1, 1, i2s1, 1); AudioControlWM8731master wm8731_1; #elif defined(PT8211_AUDIO) AudioOutputPT8211 pt8211_1; -AudioConnection patchCord29(stereomono1, 0, pt8211_1, 0); -AudioConnection patchCord30(stereomono1, 1, pt8211_1, 1); +AudioConnection patchCord31(stereomono1, 0, pt8211_1, 0); +AudioConnection patchCord32(stereomono1, 1, pt8211_1, 1); #elif defined(TEENSY_DAC_SYMMETRIC) AudioOutputAnalogStereo dacOut; AudioMixer4 invMixer; -AudioConnection patchCord31(stereomono1, 0, dacOut , 0); -AudioConnection patchCord32(stereomono1, 1, invMixer, 0); -AudioConnection patchCord33(invMixer, 0, dacOut , 1); +AudioConnection patchCord33(stereomono1, 0, dacOut , 0); +AudioConnection patchCord34(stereomono1, 1, invMixer, 0); +AudioConnection patchCord35(invMixer, 0, dacOut , 1); #else AudioOutputAnalogStereo dacOut; -AudioConnection patchCord34(stereomono1, 0, dacOut, 0); -AudioConnection patchCord35(stereomono1, 1, dacOut, 1); +AudioConnection patchCord36(stereomono1, 0, dacOut, 0); +AudioConnection patchCord37(stereomono1, 1, dacOut, 1); #endif Dexed* MicroDexed[NUM_DEXED]; @@ -166,42 +173,29 @@ short delayline[MOD_DELAY_SAMPLE_BUFFER]; /*********************************************************************** LCDMenuLib2 ***********************************************************************/ -extern LiquidCrystalPlus_I2C lcd; extern LCDMenuLib2 LCDML; extern uint8_t menu_state; #endif +#ifdef DISPLAY_LCD_SPI +void change_disp_sd(bool disp) +{ + digitalWrite(SDCARD_CS_PIN, disp); + digitalWrite(U8X8_CS_PIN, !disp); +} +#endif + void setup() { //while (!Serial) ; // wait for Arduino Serial Monitor Serial.begin(SERIAL_SPEED); - +#ifdef DISPLAY_LCD_SPI + pinMode(SDCARD_CS_PIN, OUTPUT); + pinMode(U8X8_CS_PIN, OUTPUT); +#endif + #ifdef ENABLE_LCD_UI - // 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"); - - // 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_voice_selection, VOICE_SELECTION_MS); // set to 10 seconds + setup_ui(); #else Serial.println(F("NO LCD DISPLAY ENABLED!")); #endif @@ -263,6 +257,8 @@ void setup() wm8731_1.enable(); wm8731_1.volume(1.0); Serial.println(F("TGA board enabled.")); +#elif defined(I2S_AUDIO_ONLY) + Serial.println(F("I2S enabled.")); #elif defined(PT8211_AUDIO) Serial.println(F("PT8211 enabled.")); #elif defined(TEENSY_DAC_SYMMETRIC) @@ -273,8 +269,13 @@ void setup() #endif // start SD card +#ifndef __IMXRT1062__ SPI.setMOSI(SDCARD_MOSI_PIN); SPI.setSCK(SDCARD_SCK_PIN); +#endif +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif if (!SD.begin(SDCARD_CS_PIN)) { Serial.println(F("SD card not accessable.")); @@ -313,7 +314,9 @@ void setup() // load default SYSEX data load_sysex(configuration.bank, configuration.voice); } - +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif // Init effects if (!modchorus.begin(delayline, MOD_DELAY_SAMPLE_BUFFER)) { Serial.println(F("AudioEffectModulatedDelay - right channel begin failed")); @@ -687,7 +690,13 @@ void handleProgramChange(byte inChannel, byte inProgram) { if (inProgram < MAX_VOICES) { +#ifdef DISPLAY_LCD_SPI + change_disp_sd(false); +#endif load_sysex(configuration.bank, inProgram); +#ifdef DISPLAY_LCD_SPI + change_disp_sd(true); +#endif } } diff --git a/UI.hpp b/UI.hpp index 466f75c..58c1731 100644 --- a/UI.hpp +++ b/UI.hpp @@ -27,7 +27,7 @@ #define _UI_HPP_ #include "config.h" -#include "LiquidCrystalPlus_I2C.h" +#include "Disp_Plus.h" #include "SoftenValue.hpp" #include "effect_modulated_delay.h" #include "dexed.h" @@ -38,7 +38,11 @@ #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; @@ -51,6 +55,9 @@ 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 soften_volume; extern SoftenValue soften_filter_res[NUM_DEXED]; extern SoftenValue soften_filter_cut[NUM_DEXED]; @@ -73,7 +80,22 @@ extern void set_volume(uint8_t v, int8_t p); ************************************************************************/ elapsedMillis back_from_volume; -LiquidCrystalPlus_I2C lcd(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows); +#ifdef I2C_DISPLAY +#include +Disp_Plus lcd(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows); +#endif + +#ifdef U8X8_DISPLAY +#include +#ifdef U8X8_HAVE_HW_SPI +#include +#endif +#ifdef U8X8_HAVE_HW_I2C +#include +#endif +Disp_Plus lcd(/* cs=*/ U8X8_CS_PIN, /* dc=*/ U8X8_DC_PIN, /* reset=*/ U8X8_RESET_PIN); +//Disp_Plus lcd(U8X8_PIN_NONE); +#endif const uint8_t scroll_bar[5][8] = { {B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001}, // scrollbar top @@ -88,7 +110,6 @@ 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); @@ -129,6 +150,7 @@ 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); @@ -179,6 +201,63 @@ 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 @@ -347,8 +426,15 @@ void encoder_right_up(void) 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: @@ -362,9 +448,16 @@ void encoder_right_up(void) 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; @@ -390,8 +483,16 @@ void encoder_right_down(void) 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: @@ -405,8 +506,15 @@ void encoder_right_down(void) 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); @@ -586,8 +694,13 @@ void lcdml_menu_display(void) // 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); @@ -602,16 +715,31 @@ void lcdml_menu_display(void) //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 } } } @@ -1421,6 +1549,9 @@ void UI_func_voice_selection(uint8_t param) 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) diff --git a/config.h b/config.h index 896d7eb..d686b9a 100644 --- a/config.h +++ b/config.h @@ -45,19 +45,21 @@ //************************************************************************************************* // MIDI -//#define MIDI_DEVICE_DIN Serial1 -#define MIDI_DEVICE_USB 1 -#define MIDI_DEVICE_USB_HOST 1 -#define MIDI_DEVICE_NUMBER 0 +#define MIDI_DEVICE_DIN Serial1 +//#define AUDIO_DEVICE_USB +//#define MIDI_DEVICE_USB 1 +//#define MIDI_DEVICE_USB_HOST 1 +//#define MIDI_DEVICE_NUMBER 0 // AUDIO // If nothing is defined Teensy internal DAC is used as audio output device! -// Left and right channel audio signal is presented on pins A21 and A22. +// Left and right channel audio signal is presented on pins A21 and A22.//#define AUDIO_DEVICE_USB //#define TEENSY_DAC //#define TEENSY_DAC_SYMMETRIC //#define TEENSY_AUDIO_BOARD +#define I2S_AUDIO_ONLY //#define TGA_AUDIO_BOARD -#define PT8211_AUDIO +//#define PT8211_AUDIO //************************************************************************************************* //* MIDI SETTINGS @@ -109,9 +111,28 @@ //* UI //************************************************************************************************* #define ENABLE_LCD_UI 1 -#define LCD_I2C_ADDRESS 0x27 +// LCD Display +//I2C_DISPLAY only +//#define LCD_I2C_ADDRESS 0x27 +#define LCD_I2C_ADDRESS 0x3f +//Display size, must be set for U8X8 as well #define LCD_cols 16 -#define LCD_rows 2 +//#define LCD_rows 2 +#define LCD_rows 4 + +//enable U8X8 support +#define U8X8_DISPLAY +//enable SPI CS switching +#define DISPLAY_LCD_SPI +#define U8X8_DISPLAY_CLASS U8X8_SSD1322_NHD_256X64_4W_HW_SPI +//#define U8X8_DISPLAY_CLASS U8X8_SSD1306_128X64_NONAME_HW_I2C +#define U8X8_CS_PIN 9 +#define U8X8_DC_PIN 15 +#define U8X8_RESET_PIN 14 +//Standard 16x2 LCD display (SPI/PCF8874) +//#define I2C_DISPLAY +// [I2C] SCL: Pin 19, SDA: Pin 18 (https://www.pjrc.com/teensy/td_libs_Wire.html) +//#define LCD_GFX 1 #define CONTROL_RATE_MS 50 #define BACK_FROM_VOLUME_MS 1000 @@ -120,7 +141,8 @@ //* DEBUG OUTPUT SETTINGS //************************************************************************************************* #define DEBUG 1 -#define SERIAL_SPEED 38400 +//#define SERIAL_SPEED 38400 +#define SERIAL_SPEED 9600 #define SHOW_XRUN 1 #define SHOW_CPU_LOAD_MSEC 5000 @@ -134,7 +156,8 @@ //#define SDCARD_SCK_PIN 14 #define SGTL5000_LINEOUT_LEVEL 29 // Teensy 3.5 & 3.6 SD card -#define SDCARD_CS_PIN BUILTIN_SDCARD +//#define SDCARD_CS_PIN BUILTIN_SDCARD +#define SDCARD_CS_PIN 10 #define SDCARD_MOSI_PIN 11 // not actually used #define SDCARD_SCK_PIN 13 // not actually used @@ -144,19 +167,16 @@ #define ENC_L_PIN_A 3 #define ENC_L_PIN_B 2 #define BUT_L_PIN 4 -#define ENC_R_PIN_A 28 -#define ENC_R_PIN_B 29 -#define BUT_R_PIN 30 +//#define ENC_R_PIN_A 28 +//#define ENC_R_PIN_B 29 +//#define BUT_R_PIN 30 +#define ENC_R_PIN_A 6 +#define ENC_R_PIN_B 5 +#define BUT_R_PIN 8 #define BUT_DEBOUNCE_MS 20 #define LONG_BUTTON_PRESS 500 -// LCD Display -#define I2C_DISPLAY 1 -// [I2C] SCL: Pin 19, SDA: Pin 18 (https://www.pjrc.com/teensy/td_libs_Wire.html) -//#define LCD_GFX 1 -#define LCD_I2C_ADDRESS 0x27 -#define LCD_CHARS 16 -#define LCD_LINES 2 + // Internal timer #define AUTOSTORE_MS 5000 @@ -179,6 +199,13 @@ #ifdef MIDI_DEVICE_USB #define USBCON 1 #endif + +#if defined(__IMXRT1062__) //Teensy-4.0 +#undef MIDI_DEVICE_USB_HOST +#undef MIDI_DEVICE_USB +#define MAX_NOTES 16 +#endif + #if defined(__MK66FX1M0__) // Teensy-3.6 // Teensy-3.6 settings #define MIDI_DEVICE_USB_HOST 1 @@ -187,12 +214,15 @@ #else #define MAX_NOTES 14 #endif -#else +#endif + +#if defined (__MK64FX512__) // Teensy-3.5 settings #undef MIDI_DEVICE_USB_HOST #define MAX_NOTES 11 #undef USE_REVERB #endif + #define TRANSPOSE_FIX 24 // Audio