// MIDI RGB Keyboard v4.02.01 - 18.06.2025
// Begonnen am: 01.06.2021
// https://forum.arduino.cc/t/drehgeber-rotary-encoder-ohne-interrupt/497584
// Hinzugefügt: Encoder und Einstellungen
// Akkordtabelle: https://tomplay.com/de/piano-chords/b-major?notation=am
// https://www.ascii-codes.com/
// https://cdn-learn.adafruit.com/downloads/pdf/adafruit-gfx-graphics-library.pdf
// display.cp437(true);
// display.write(167);
// display.ssd1306_command(SSD1306_DISPLAYOFF);
// display.ssd1306_command(SSD1306_DISPLAYON);
// display.fillScreen(SSD1306_BLACK);
// display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Text invertieren
// display.setTextColor(SSD1306_WHITE); // Text normal
// display.ssd1306_command(SSD1306_SETCONTRAS
// Simple Rotary Library:
// SimpleRotary rotary(EncoderPin A, EncderPinB, EncoderButton);
// i = rotary.rotate(); // 1 = CW | 2 = CCW
// i = rotary.push();
// i = rotary.pushLong(1000);
// i = rotary.pushTime();
// i = rotary.pushTime(); if ( i > 1000 ) { ... }
// rotary.resetPush();
// i = rotary.pushType(1000); // 1 = Short | 2 = Long
// Texte für Notenanzeige
const char PROGMEM note01[] = "C";
const char PROGMEM note02[] = "C#";
const char PROGMEM note03[] = "D";
const char PROGMEM note04[] = "D#";
const char PROGMEM note05[] = "E";
const char PROGMEM note06[] = "F";
const char PROGMEM note07[] = "F#";
const char PROGMEM note08[] = "G";
const char PROGMEM note09[] = "G#";
const char PROGMEM note10[] = "A";
const char PROGMEM note11[] = "A#";
const char PROGMEM note12[] = "B";
const char* const notes[] PROGMEM = { note01, note02, note03, note04, note05, note06, note07, note08, note09, note10, note11, note12 };
// Grafiken
const unsigned char iconLogo1[] PROGMEM = /* 128 x 32 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x07, 0xe0, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x07, 0xf0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x0f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x0f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x1f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x1f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x3e, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x3e, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x78, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x3e, 0x7c, 0x00, 0x7c, 0xf8, 0x3f, 0xf8, 0x7e, 0x1f, 0xfe, 0x1f, 0xff, 0x03, 0xff, 0xf8, 0x00, 0x3e, 0x7c, 0x00, 0x7c, 0xf8, 0x3f, 0xf8, 0x7e, 0x3f, 0xff, 0x1f, 0xff, 0x87, 0xff, 0xf8, 0x00, 0x3e, 0x3c, 0x00, 0x78, 0xf8, 0x3f, 0xf8, 0xfc, 0x7f, 0xff, 0x9f, 0xff, 0xc7, 0xff, 0xf8, 0x00, 0x3e, 0x3e, 0x00, 0xf8, 0xf8, 0x3f, 0xf8, 0xfc, 0x7f, 0xff, 0x9f, 0xff, 0xc7, 0xff, 0xf8, 0x00, 0x3e, 0x3e, 0x00, 0xf8, 0xf8, 0x3f, 0xf8, 0xf8, 0x7f, 0x7f, 0x9f, 0x8f, 0xc7, 0xf8, 0x00, 0x00, 0x3e, 0x1e, 0x00, 0xf0, 0xf8, 0x3f, 0xf9, 0xf8, 0x7e, 0x3f, 0x9f, 0x8f, 0xc7, 0xf0, 0x00, 0x00, 0x3e, 0x1f, 0x01, 0xf0, 0xf8, 0x3f, 0xf9, 0xf8, 0x7e, 0x3f, 0x9f, 0x8f, 0xc7, 0xf0, 0x00, 0x00, 0x3e, 0x1f, 0x01, 0xf0, 0xf8, 0x3f, 0xf9, 0xf0, 0x7e, 0x3f, 0x9f, 0x8f, 0xc7, 0xf0, 0x00, 0x00, 0x3e, 0x0f, 0x01, 0xe0, 0xf8, 0x3f, 0xff, 0xf0, 0x7e, 0x3f, 0x9f, 0xff, 0x87, 0xf1, 0xfc, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0xf8, 0x3f, 0xff, 0xe0, 0x7e, 0x3f, 0x9f, 0xff, 0x07, 0xf1, 0xfc, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0xf8, 0x3f, 0xff, 0xe0, 0x7e, 0x3f, 0x9f, 0xfe, 0x07, 0xf1, 0xfc, 0x00, 0x3e, 0x07, 0x83, 0xc0, 0xf8, 0x3f, 0xff, 0xf0, 0x7e, 0x3f, 0x9f, 0xff, 0x07, 0xf1, 0xf8, 0x00, 0x3e, 0x07, 0xc7, 0xc0, 0xf8, 0x3f, 0xf9, 0xf0, 0x7e, 0x3f, 0x9f, 0x9f, 0x87, 0xf1, 0xf8, 0x00, 0x3e, 0x07, 0xc7, 0xc0, 0xf8, 0x3f, 0xf9, 0xf8, 0x7e, 0x3f, 0x9f, 0x9f, 0xc7, 0xf1, 0xf8, 0x00, 0x3e, 0x03, 0xc7, 0x80, 0xf8, 0x3f, 0xf9, 0xf8, 0x7e, 0x3f, 0x9f, 0x9f, 0xc7, 0xf1, 0xf8, 0x00, 0x3e, 0x03, 0xef, 0x80, 0xf8, 0x3f, 0xf9, 0xf8, 0x7e, 0x3f, 0x9f, 0x8f, 0xc7, 0xf1, 0xf8, 0x00, 0x3e, 0x03, 0xef, 0x80, 0xf8, 0x3f, 0xf8, 0xfc, 0x7f, 0x7f, 0x9f, 0x8f, 0xc7, 0xfb, 0xf8, 0x00, 0x3e, 0x01, 0xff, 0x00, 0xf8, 0x3f, 0xf8, 0xfc, 0x7f, 0xff, 0x9f, 0x8f, 0xe7, 0xff, 0xf8, 0x00, 0x3e, 0x01, 0xff, 0x00, 0xf8, 0x3f, 0xf8, 0xfc, 0x7f, 0xff, 0x9f, 0x8f, 0xe7, 0xff, 0xf8, 0x00, 0x3e, 0x00, 0xfe, 0x00, 0xf8, 0x3f, 0xf8, 0x7e, 0x3f, 0xff, 0x1f, 0x87, 0xe3, 0xff, 0xf8, 0x00, 0x3e, 0x00, 0xfe, 0x00, 0xf8, 0x3f, 0xf8, 0x7e, 0x1f, 0xfe, 0x1f, 0x87, 0xe1, 0xff, 0xf8, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const unsigned char iconLogo2[] PROGMEM = /* 128 x 32 */ { 0x00, 0x07, 0xf0, 0x00, 0x01, 0xf0, 0x07, 0xcf, 0x3f, 0xff, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x01, 0xf8, 0x0f, 0xcf, 0x3f, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x01, 0xf8, 0x0f, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xe0, 0x01, 0xfc, 0x1f, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc7, 0xf1, 0xf0, 0x00, 0x3c, 0x1f, 0xc0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x87, 0xf0, 0xf8, 0x01, 0xfe, 0x3f, 0xcf, 0x3c, 0x00, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x07, 0xf0, 0x7c, 0x01, 0xfe, 0x3f, 0xcf, 0x3c, 0x00, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x3c, 0x01, 0xef, 0x7b, 0xcf, 0x3c, 0x00, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x1e, 0x01, 0xef, 0x7b, 0xcf, 0x3c, 0x00, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0e, 0x01, 0xe7, 0xf3, 0xcf, 0x3c, 0x00, 0xf9, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0f, 0x01, 0xe7, 0xf3, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x01, 0xe3, 0xe3, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x01, 0xe3, 0xe3, 0xcf, 0x3f, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0x81, 0xe1, 0xc3, 0xcf, 0x3f, 0xff, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xc0, 0x01, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0x03, 0xe3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0x03, 0xe3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xc0, 0x01, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0x81, 0xe0, 0x00, 0x0f, 0x0f, 0xff, 0xf9, 0xe0, 0x03, 0xcf, 0xff, 0xff, 0x70, 0x00, 0x00, 0x07, 0x01, 0xe0, 0x00, 0x0f, 0x1f, 0xff, 0xf9, 0xe0, 0x03, 0xcf, 0xff, 0xff, 0x70, 0x70, 0x07, 0x07, 0x01, 0xe0, 0x00, 0x0f, 0x3f, 0xff, 0xf9, 0xe0, 0x03, 0xcf, 0xff, 0xff, 0x78, 0xf8, 0x0f, 0x8f, 0x01, 0xe0, 0x00, 0x0f, 0x3f, 0xff, 0xf9, 0xe0, 0x03, 0xcf, 0xff, 0xff, 0x38, 0xf9, 0xcf, 0x8e, 0x01, 0xe0, 0x00, 0x0f, 0x3e, 0x00, 0x01, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x3c, 0x73, 0xe7, 0x1e, 0x01, 0xe0, 0x00, 0x0f, 0x3c, 0xff, 0xf9, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x1e, 0x03, 0xe0, 0x3c, 0x01, 0xe0, 0x00, 0x0f, 0x3c, 0xff, 0xf9, 0xff, 0xff, 0xc0, 0x0f, 0x00, 0x1f, 0x01, 0xc0, 0x7c, 0x01, 0xe0, 0x00, 0x0f, 0x3c, 0xff, 0xf9, 0xff, 0xff, 0xc0, 0x0f, 0x00, 0x0f, 0x80, 0x00, 0xf8, 0x01, 0xe0, 0x00, 0x0f, 0x3c, 0x00, 0x79, 0xff, 0xff, 0xc0, 0x0f, 0x00, 0x07, 0xe0, 0x01, 0xf0, 0x01, 0xf0, 0x00, 0x0f, 0x3e, 0x00, 0xf9, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x03, 0xf8, 0x0f, 0xe0, 0x01, 0xff, 0xff, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xcf, 0x3f, 0xff, 0xf9, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xcf, 0x1f, 0xff, 0xf9, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xcf, 0x0f, 0xff, 0xe1, 0xe0, 0x03, 0xc0, 0x0f, 0x00 };
const unsigned char iconNote[] PROGMEM = /* 14 x 16 */ { 0x00, 0x70, 0x00, 0x78, 0x18, 0x6c, 0x1c, 0x64, 0x1e, 0x64, 0x1b, 0x60, 0x19, 0x60, 0x19, 0x60, 0x18, 0x60, 0x18, 0x60, 0x19, 0xe0, 0x1b, 0xe0, 0x7b, 0xe0, 0xf9, 0xc0, 0xf8, 0x00, 0x70, 0x00 };
const unsigned char iconSettings[] PROGMEM = /* 128 x 32 */ { 0x00, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x07, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x07, 0xe3, 0xc0, 0x3f, 0x98, 0xe0, 0x61, 0xe7, 0xf9, 0xfc, 0xc0, 0x60, 0x0f, 0xc0, 0x7e, 0x03, 0xf3, 0xf0, 0x3f, 0x98, 0xf0, 0x63, 0xf7, 0xf9, 0xfc, 0xc0, 0x60, 0x3f, 0xe0, 0xfc, 0x01, 0xf9, 0xf8, 0x30, 0x18, 0xf0, 0x66, 0x10, 0xc1, 0x80, 0xc0, 0x60, 0x30, 0x20, 0xfc, 0x00, 0xf9, 0xf8, 0x30, 0x18, 0xd8, 0x66, 0x00, 0xc1, 0x80, 0xc0, 0x60, 0x60, 0x00, 0x7c, 0x00, 0xf8, 0xf0, 0x30, 0x18, 0xdc, 0x67, 0x00, 0xc1, 0x80, 0xc0, 0x60, 0x60, 0x00, 0x38, 0xc0, 0xfc, 0xe0, 0x3f, 0x18, 0xcc, 0x63, 0xc0, 0xc1, 0xf8, 0xc0, 0x60, 0x63, 0xe0, 0x38, 0xe1, 0xfc, 0xe0, 0x3f, 0x18, 0xc6, 0x61, 0xe0, 0xc1, 0xf8, 0xc0, 0x60, 0x63, 0xe0, 0x7c, 0xf3, 0xfc, 0xf0, 0x30, 0x18, 0xc7, 0x60, 0x70, 0xc1, 0x80, 0xc0, 0x60, 0x60, 0x60, 0xfc, 0xff, 0xfc, 0xf8, 0x30, 0x18, 0xc3, 0x60, 0x30, 0xc1, 0x80, 0xc0, 0x60, 0x60, 0x60, 0xfc, 0xff, 0xfe, 0x78, 0x30, 0x18, 0xc1, 0xe4, 0x30, 0xc1, 0x80, 0xc0, 0x60, 0x30, 0x60, 0x7e, 0x7f, 0xff, 0x38, 0x3f, 0x98, 0xc1, 0xe7, 0xe0, 0xc1, 0xfc, 0xfe, 0x7f, 0x3f, 0xe6, 0x1e, 0x3f, 0xff, 0x80, 0x3f, 0x98, 0xc0, 0xe3, 0xc0, 0xc1, 0xfc, 0xfe, 0x7f, 0x0f, 0xc6, 0x0f, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xcf, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xe7, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf3, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const unsigned char iconMidi[] PROGMEM = /* 16 x 16 */ { 0x03, 0xc0, 0x0f, 0xf0, 0x1b, 0xd8, 0x33, 0xcc, 0x60, 0x06, 0x40, 0x02, 0xc0, 0x03, 0xd8, 0x1b, 0xd8, 0x1b, 0xc0, 0x03, 0x4c, 0x32, 0x6d, 0xb6, 0x31, 0x8c, 0x18, 0x18, 0x0f, 0xf0, 0x03, 0xc0 };
const unsigned char iconLight[] PROGMEM = /* 16 x 16 */ { 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0c, 0x30, 0x08, 0x10, 0x18, 0x18, 0x10, 0x08, 0xd0, 0x0b, 0x10, 0x08, 0x18, 0x18, 0x0c, 0x30, 0x07, 0xe0, 0x20, 0x04, 0x40, 0x82, 0x00, 0x80};
const unsigned char iconClock[] PROGMEM = /* 16 x 16 */ { 0x03, 0xc0, 0x21, 0x84, 0x2f, 0xf4, 0x3c, 0x3c, 0x30, 0xcc, 0x60, 0xe6, 0x60, 0xf6, 0xc0, 0xfb, 0xc0, 0x03, 0xc0, 0x03, 0x60, 0x06, 0x60, 0x06, 0x30, 0x0c, 0x1c, 0x38, 0x0f, 0xf0, 0x03, 0xc0 };
const unsigned char iconDim[] PROGMEM = /* 16 x 16 */ { 0x03, 0xc0, 0x0f, 0xf0, 0x18, 0x18, 0x31, 0xcc, 0x67, 0xe6, 0x46, 0x72, 0xc8, 0x3b, 0xd0, 0x1b, 0xc0, 0x03, 0xc0, 0x03, 0x40, 0x02, 0x60, 0x06, 0x30, 0x0c, 0x18, 0x18, 0x0f, 0xf0, 0x03, 0xc0 };
const unsigned char iconInfo[] PROGMEM = /* 16 x 16 */ { 0x07, 0xe0, 0x1f, 0xf8, 0x3f, 0x3c, 0x7f, 0x3e, 0x7f, 0xfe, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfc, 0xff, 0x7c, 0xfe, 0x78, 0xfe, 0x38, 0x3c, 0x1f, 0xf8, 0x07, 0xe0 };
const unsigned char iconHue[] PROGMEM = /* 16 x 16 */ { 0x03, 0xc1, 0x0f, 0xf3, 0x1c, 0xff, 0x3c, 0xcf, 0x7e, 0xcd, 0x67, 0xd9, 0xe7, 0xfe, 0xff, 0xfa, 0xff, 0xf2, 0xef, 0xf4, 0xc7, 0xa4, 0x6f, 0x28, 0x7f, 0x50, 0x3f, 0x60, 0x1e, 0x40, 0x0c, 0x00 };
const unsigned char iconSat[] PROGMEM = /* 16 x 16 */ { 0x07, 0xc0, 0x18, 0xf8, 0x20, 0xfc, 0x40, 0xfe, 0x40, 0xfe, 0xc0, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0xc0, 0xff, 0x40, 0xfe, 0x40, 0xfe, 0x20, 0xfc, 0x18, 0xf8, 0x07, 0xe0 };
const unsigned char iconVal[] PROGMEM = /* 16 x 16 */ { 0x01, 0x80, 0x41, 0x82, 0x21, 0x84, 0x10, 0x08, 0x01, 0x80, 0x07, 0xe0, 0x07, 0xe0, 0xef, 0xf7, 0xef, 0xf7, 0x07, 0xe0, 0x07, 0xe0, 0x01, 0x80, 0x10, 0x08, 0x21, 0x84, 0x41, 0x82, 0x01, 0x80 };
const unsigned char iconSave[] PROGMEM = /* 16 x 16 */ { 0x3f, 0xf0, 0x60, 0x18, 0xe1, 0x9c, 0xe1, 0x9e, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xe0, 0x07, 0xef, 0xf7, 0xe0, 0x07, 0xef, 0xf7, 0xe0, 0x07, 0xff, 0xff, 0x7f, 0xfe, 0x3f, 0xfc };
const unsigned char iconUnChecked[] PROGMEM = /* 16 x 16 */ { 0x07, 0xe0, 0x1f, 0xf8, 0x38, 0x1c, 0x70, 0x0e, 0x60, 0x06, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0x60, 0x06, 0x70, 0x0e, 0x38, 0x1c, 0x1f, 0xf8, 0x07, 0xe0 };
const unsigned char iconChecked[] PROGMEM = /* 16 x 16 */ { 0x07, 0xe0, 0x1f, 0xf1, 0x38, 0x03, 0x70, 0x07, 0x60, 0x0e, 0xc0, 0x1c, 0xd8, 0x38, 0xdc, 0x71, 0xce, 0xe3, 0xc7, 0xc3, 0xc3, 0x83, 0x61, 0x06, 0x70, 0x0e, 0x38, 0x1c, 0x1f, 0xf8, 0x07, 0xe0 };
#include "VerySimpleMidi.h"
#include <Wire.h> // I²C Library einbinden
#include <Adafruit_NeoPixel.h> // LED Stripe (WS2812B) ansteuern
#include <Adafruit_GFX.h> // Grefiklibrary f#einbinden
#include <Adafruit_SSD1306.h> // OLED Display einbinden
#include <SimpleRotary.h> // Rotary Encoder einbinden
#include <EEPROM.h> // EEprom Zugriff ermöglichen
#define ver "4.00.02" // Programmversion
#define verDate "08.02.2025"
#define displayAddress 0x3C // OLED 2²C Adrrsse (SCL = A4, SDA = A5)
#define screenWidth 128 // OLED Breite in Pixeln
#define screenHeight 64 // OLED Höhe in Pixeln
#define numLed 61 // Anzahl der LEDs/Tasten + 1
#define ledStripe 5 // LED Steuerpin D5 [5]
#define pinEnableUSB 6 // Update Steuerpin D6 [6] USB = MIDI Daten kommen über CD4066 an den Serial Port | LOW = MIDI Daten
#define pinEncBtn 2 // Encoder Taste D2 [2]
#define pinEncClk 3 // Encoder Clock D3 [3]
#define pinEncDat 4 // Encoder Data D3 [4]
#define pinIntLed 13 // Interne LED für flackerfreie MIDI Anzeige
#define eeH1 0x01 // Speicheradressen im EEprom
#define eeS1 0x02
#define eeV1 0x03
#define eeH2 0x04
#define eeS2 0x05
#define eeV2 0x05
#define eeMidiTranspose 0x12
#define eeLedStripeTimeout 0x13 // Nach x Minuten LED Stripe ausschalten, wenn > 0
byte keysOn[numLed + 1] = { }; // Array zum Speichern der gedrückten Keyboard Tasten
byte midiTranspose = 0; // MIDI Transpose (Notenversatz)
byte ledStripeTimeout = 1; // LED Stripe Timeout (1 . 255 Min), 0 = Immer an
byte keysPressed = 0; // Anzahl gedürckter Tasten
unsigned long ledTime; // MIDI LED Zeit (millis)
unsigned long ledStripeTime; // LED Stripe Leuchtzeit (Millis)
unsigned long lastPixelUpdate; // Zeit des letzten Stripe Uodates (Millis)
boolean ledStripeOn = true; // Sind die LEDs eingeschaltet (Timeout)?
boolean pixelChanged = false; // Wird true, wenn sich der Stripe ändrt
int H1 = 170; // Werte für nicht gedrückte Tasten (H, S, V)
byte S1 = 255;
byte V1 = 100;
int H2 = 230; // LED Werte für gedrückte Tasten (H, S, V)
byte S2 = 255;
byte V2 = 100;
uint32_t RGB1, RGB2; // Umgerechnete RGB Werte der HSV Werte (schneller)
#define OLED_WHITE WHITE
#define OLED_BLACK BLACK
#define OLED_INVERSE SSD1306_INVERSE
byte showMenu = false;
byte menuLevel = 0;
bool encBtnPressedNew = HIGH;
bool encBtnPressedOld = LOW;
byte encButton = LOW;
byte encButtonOld = HIGH;
Adafruit_NeoPixel pixels(numLed, ledStripe, NEO_GRB + NEO_KHZ800); // LED Stripe initialiseren
Adafruit_SSD1306 display(screenWidth, screenHeight, &Wire, -1, 1000000UL, 1000000UL); // Display initialisieren
SimpleRotary Encoder(pinEncDat, pinEncClk, pinEncBtn);
VerySimpleMidi myMidi;
// ################################################## SETUP ##################################################
void setup()
{
Wire.setClock(3400000L);
//EEPROM.update(eeH1 , H1);
//EEPROM.update(eeS1 , S1);
//EEPROM.update(eeV1 , V1);
//EEPROM.update(eeH2 , H2);
//EEPROM.update(eeS2 , S2);
//EEPROM.update(eeV2 , V2);
//EEPROM.update(eeMidiTranspose , midiTranspose);
//EEPROM.update(eeLedStripeTimeout, ledStripeTimeout);
//H1 = EEPROM.read(eeH1);
//S1 = EEPROM.read(eeS1);
//V1 = EEPROM.read(eeV1);
//H2 = EEPROM.read(eeH2);
//S2 = EEPROM.read(eeS2);
//V2 = EEPROM.read(eeV2);
//midiTranspose = EEPROM.read(eeMidiTranspose);
//ledStripeTimeout = EEPROM.read(eeLedStripeTimeout);
;
RGB1 = pixels.ColorHSV(H1 * 256, S1, V1); // RGB Werte für Note Off und Note On
RGB2 = pixels.ColorHSV(H2 * 256, S2, V2); // Spart etwas Zeit beim anzeigen
pinMode(pinIntLed, OUTPUT); // Pin Interne LED
pinMode(pinEnableUSB, OUTPUT); // Seriellen Port aktivieren (KEIN Serieller Betrieb mehr möglich!)
pinMode(ledStripe, OUTPUT); // Datenpin des LED Stripes
pinMode(pinEncBtn, INPUT_PULLUP);
pinMode(pinEncClk, INPUT);
pinMode(pinEncDat, INPUT);
digitalWrite(pinIntLed, HIGH); // Interne LED während der Initialisierung einchalten
digitalWrite(pinEnableUSB, LOW); // Seriellen Port für MIDI deaktivieren (über CD4066), damit Updates möglich sind. LOW = USB | HIGH = MIDI // RS-232 initialisieren (31250 Baud)
while(!display.begin(SSD1306_SWITCHCAPVCC, displayAddress)) // Displayinstanz starten
{
//Serial.println(F("SSD1306 Displayfehler!"));
digitalWrite(pinIntLed, HIGH);
delay(50);
digitalWrite(pinIntLed, LOW);
delay(400);
}
for(byte y = 0; y < 129; y += 2)
{
display.clearDisplay();
display.drawBitmap(128 - y , 0, iconLogo1, screenWidth, 32, OLED_WHITE); // Logo 1 von rechts einblenden
display.drawBitmap(y - 128, 32, iconLogo2, screenWidth, 32, OLED_WHITE); // Logo 2 von links einblenden
display.display();
pixels.setPixelColor(0 + y / 2, RGB1); // Alle Tasten von links mit Farbe 1...
pixels.setPixelColor(61 - y / 2, RGB2); // und von rechts mit Farbe 2 füllen.
pixels.show();
}
// Selbsttest (1 x beim Einschalten)
//for(byte y = 0; y <= numLed; y ++)
//{
// //pixels.setPixelColor(0 + y, pixels.ColorHSV( H1 * 256, S1, V1)); // Alle Tasten von links mit Farbe 1...
// //pixels.setPixelColor(numLed - y, pixels.ColorHSV( H2 * 256, S2, V2)); // und von rechts mit Farbe 2 füllen.
// pixels.setPixelColor(0 + y, RGB1); // Alle Tasten von links mit Farbe 1...
// pixels.setPixelColor(numLed - y, RGB2); // und von rechts mit Farbe 2 füllen.
// pixels.show();
// delay(20);
//}
delay(500);
for(byte x = 0; x < screenHeight; x++)
{
display.drawFastVLine(x + 65, 0, screenHeight, OLED_WHITE);
display.drawFastVLine(x + 64, 0, screenHeight, OLED_BLACK);
display.drawFastVLine(63 - x, 0, screenHeight, OLED_BLACK);
display.drawFastVLine(62 - x, 0, screenHeight, OLED_WHITE);
display.setCursor(18, 6);
display.print(F("v"));
display.print(F(ver));
display.setCursor(5, 27);
display.print(F(verDate));
display.setTextSize(1);
display.setCursor(10, 50);
display.print(F("Copyright by Gucky"));
display.display();
pixels.setBrightness(map(x, 0, 64, V1, 0)); // Helligeit aller LED von 64 bis 0 dimmen.
pixels.show();
//delay(10);
}
display.setCursor(18, 6);
display.print(F("v"));
display.print(F(ver));
display.setCursor(5, 27);
display.print(F(verDate));
display.setTextSize(1);
display.setCursor(10, 50);
display.print(F("Copyright by Gucky"));
display.drawRoundRect(0, 0, screenWidth , screenHeight, 7, OLED_WHITE);
display.display();
delay(500);
pixels.setBrightness(V1); // Alle LEDs auf Helligkeit 1 (NoteOff) setzen
for(byte x = 0; x < numLed; x++)
{
//pixels.setPixelColor((numLed / 2) - x / 2, pixels.ColorHSV( H1 * 256, S1, V1)); // Alle Tasten von links und rechts...
//pixels.setPixelColor((numLed / 2) + x / 2, pixels.ColorHSV( H1 * 256, S1, V1)); // mit Farbe 1 füllen.
pixels.setPixelColor((numLed / 2) - x / 2, RGB1); // Alle Tasten von links und rechts...
pixels.setPixelColor((numLed / 2) + x / 2, RGB1); // mit Farbe RGB1 füllen.
pixels.show();
delay(10);
}
digitalWrite(pinIntLed, HIGH);
digitalWrite(pinEnableUSB, HIGH); // Ab jetzt ist MIDI über den CD4066 auf den seriellen Port (TxD) gelegt.
ledTime = millis();
ledStripeTime = millis();
lastPixelUpdate = millis(); // Die LEDs werden nur alle n ms upgedatet
}
// ################################################## LOOP ##################################################
void loop()
{
byte btn = digitalRead(pinEncBtn); // Seriellen Port aktivieren (KEIN Serieller Betrieb mehr möglich!)
digitalWrite(pinIntLed, !btn);
if(btn == LOW)
ledStripeTime = millis();
if (millis() - lastPixelUpdate >= 50 && pixelChanged) // Wenn sich der Inhalt des LED Arrays geändert hat, ...
{
pixelChanged = false;
pixels.show();
lastPixelUpdate = millis(); // dann LED Stripe alle 20ms aktualisieren
ledStripeTime = millis(); // Nach "NoteOn" oder "NoteOff" Anzeigezeit für LED Strpe neu speichern (Timout resetten)
}
if (millis() - ledTime >= 250 && digitalRead(pinIntLed)) // Wenn interne LED (MIDI Led) leuchtet und 0.5 Sekunden vergangen sind, ...
digitalWrite(pinIntLed, LOW); // LED wieder ausschalten (MIDI Anzeige leuchtet also für 0.5 Sek.).
if (Serial.available()) // Sind Bytes verfügbar?
{
byte inByte = Serial.read(); // Nächstes empfangenes MIDI Byte einlesen
if (myMidi.noteReceived(inByte))
{
if (!digitalRead(pinIntLed)) // Wenn int. LED (MIDI LED) nicht bereits leuchtet, ...
{
digitalWrite(pinIntLed, HIGH); // ... int. LED (MIDI LED) für einschalten.
ledTime = millis(); // Zeit merken
}
if (!ledStripeOn) // Ist LED Stripe ausgeschaltet (nach Timeout)?
powerOnLed(); // Dann zuerst wieder einschalten.
NoteStruct note = myMidi.getNote();
if (note.isNoteOn && note.velocity > 0)
{
keysPressed++; // Zähler für gedrückte Tasten inkrementieren
pixels.setPixelColor(note.key - 36 + midiTranspose, RGB2); // Led Array aktualisieren
}
else
{
if (keysPressed) // Ist die Anzahl gedrückter Tasten > 0?
keysPressed--; // Ja, dann 1 abziehen
pixels.setPixelColor(note.key - 36 + midiTranspose, RGB1); // Led Array aktualisieren
}
pixelChanged = true;
}
}
if(millis() - ledStripeTime >= (ledStripeTimeout * 60000) && ledStripeTimeout && ledStripeOn && !keysPressed) // LEDs nach n Minuten abschalten, wenn LED Timeout (ledStripeTimeout * 60000)erreicht ist, ...
powerOffLed(); // LED Timeout > 0 ist und keine Tasten mehr gedrückt sind
}
/* Alter Loop, kann entfallen, wenn die neue Version mit Library läuft */
void loop_alt()
{
if (millis() - lastPixelUpdate >= 20 && pixelChanged)
{
lastPixelUpdate = millis();
ledStripeTime = millis();
pixelChanged = false;
pixels.show();
}
if(millis() - ledTime >= 250 && digitalRead(pinIntLed)) // Wenn interne LED (MIDI Led) leuchtet, und 250ms vergangen sind, ...
digitalWrite(pinIntLed, LOW);
if(Serial.available() > 2) // Sind 3 Bytes oder mehr verfügbar?
{
byte midiCommand = Serial.read(); // Ja, dann das 1 Byte einlesen...
//byte midiReceiveChannel = (midiCommand & B00001111) + 1; // MIDI Kanal errechnen <== Kann entfallen
//if(midiCommand == 0xFE)
// return;
if(!digitalRead(pinIntLed)) // Wenn int. Led (MIDI Led) nicht bereits leuchtet, ...
{
digitalWrite(pinIntLed, HIGH); // ... int. led (MIDI Led) füe einschalten.
ledTime = millis(); // Zeit merken
}
if(!ledStripeOn) // Ist LED Stripe ausgeschaltet (nach Timeout)?
powerOnLed(); // Dann einschalten.
byte command = midiCommand >> 4; // Ja, dann MIDI Kommando errechnen, ...
byte midiNoteNumber = Serial.read() - 36 + midiTranspose; // ... Byte für Notennummer lesen und Notenwert errechnen...
byte midiVelocity = Serial.read(); // ... und Byte für Velocity lesen
if(command == 9) // Ist command = NoteOn?
{
//keysOn[midiNoteNumber] = true; // Array für gedrückte Tasten aktualisieren
keysPressed++; // Zähler für gedrückte Tasten inkrementieren
//pixels.setPixelColor(midiNoteNumber, pixels.ColorHSV(H2 * 256, S2, V2)); // LED Array aktualisieren (HSV)
pixels.setPixelColor(midiNoteNumber, RGB2); // LED Array aktualisieren (RGB)
pixels.show(); // LEDs aktualisieren
}
else if(command == 8) // Ist Command = NoteOff?
{
//keysOn[midiNoteNumber] = false; // Array für gedrückte Testen aktualisieren
if(keysPressed) // Ist die Anzahl gedrückter Tasten > 0?
keysPressed--; // Ja, dann 1 abziehen
//pixels.setPixelColor(midiNoteNumber, pixels.ColorHSV(H1 * 256, S1, V1)); // Led Array aktualisieren (HSV)
pixels.setPixelColor(midiNoteNumber, RGB1); // Led Array aktualisieren (RGB)
pixels.show(); // LEDs aktualisieren
}
ledStripeTime = millis();
}
/*
static bool drehen, block;
bool M_CLK = digitalRead(pinEncClk);
bool M_DAT = digitalRead(pinEncDat);
bool M_BTN = !digitalRead(pinEncBtn);
if(M_BTN && !block) //Taster
{
block = true;
menuLevel = 0;
}
else if(!M_BTN && block)
block = false;
if (!M_CLK && !drehen) //rechts
{
drehen = true;
if(menuLevel <= 16)
menuLevel++;
else
menuLevel = 1;
}
else if (!M_DAT && !drehen) //links
{
drehen = true;
menuLevel--;
if(menuLevel < 1)
menuLevel = 16;
}
if (M_CLK && M_DAT && drehen) //Grunstellung
drehen = false;
if(menuLevel)
{
for(byte x = 0; x < menuLevel; x++)
pixels.setPixelColor(x, pixels.ColorHSV(70 * 256, 255, 255));
pixels.show();
}
*/
/*
encButton = !digitalRead(pinEncBtn);
if(encButton != encButtonOld)
{
if(encButton)
{
powerOnLed();
menuLevel++;
if(menuLevel >= 16 )
menuLevel = 16;
if(menuLevel)
{
for(byte x = 0; x < menuLevel; x++)
pixels.setPixelColor(x, pixels.ColorHSV(70 * 256, 255, 255));
pixels.show();
}
showMenu = !showMenu;
digitalWrite(pinIntLed, menuLevel);
}
encButtonOld = encButton;
ledStripeTime = millis();
}
*/
if(millis() - ledStripeTime >= (ledStripeTimeout * 5000 /* 60000 */) && ledStripeTimeout && ledStripeOn && keysPressed) // LEDs nach n Minuten abschalten
powerOffLed();
}
void powerOffLed()
{
for(byte x = 0; x <= round(numLed / 2); x++)
{
//pixels.setPixelColor(x , pixels.ColorHSV( H1 * 256, S1, 0)); // ... LED Leiste von links ...
//pixels.setPixelColor(numLed - x, pixels.ColorHSV( H1 * 256, S1, 0)); // ... und rechts zur Mitte hin abschalten.
pixels.setPixelColor(x , 0); // ... LED Leiste von links ...
pixels.setPixelColor(numLed - x, 0); // ... und rechts zur Mitte hin abschalten.
pixels.setBrightness(map(x, 0, round(numLed / 2) * 0.9, V1, 0));
pixels.show();
delay(50); // Kurz warten, um den "Laufeffekt" zu simulieren
}
ledStripeOn = false; // LEDs sind aus
keysPressed = 0;
pixelChanged = false;
}
void powerOnLed()
{
pixels.setBrightness(V1);
for(byte x = 0; x <= round(numLed / 2); x++)
{
//pixels.setPixelColor((numLed / 2) + x, pixels.ColorHSV( H1 * 256, S1, V1));
//pixels.setPixelColor((numLed / 2) - x, pixels.ColorHSV( H1 * 256, S1, V1));
pixels.setPixelColor((numLed / 2) + x, RGB1);
pixels.setPixelColor((numLed / 2) - x, RGB1);
pixels.show();
delay(1);
}
ledStripeOn = true;
pixelChanged = false;
ledStripeTime = millis();
}
// #############################################################################
/*
// MIDI RGB Keyboard v4.02.01 - 09.06.2025
// Begonnen am: 01.06.2021
// Hinzugefügt: Encoder und Einstellungen
#include <Adafruit_NeoPixel.h> // LED Stripe (WS2812B) ansteuern
#include <EEPROM.h> // EEprom Zugriff ermöglichen
#define numLed 61 // Anzahl der LEDs/Tasten + 1
#define ledStripe 5 // LED Steuerpin D5 [5]
#define pinEnableUSB 6 // Update Steuerpin D6 [6] USB = MIDI Daten kommen über CD4066 an den Serial Port | LOW = MIDI Daten
#define pinEncBtn 2 // Encoder Taste D2 [2]
#define pinEncClk 3 // Encoder Clock D3 [3]
#define pinEncDat 4 // Encoder Data D3 [4]
#define pinIntLed 13 // Interne LED für flackerfreie MIDI Anzeige
#define eeH1 0x01 // Speicheradressen im EEprom
#define eeS1 0x02
#define eeV1 0x03
#define eeH2 0x04
#define eeS2 0x05
#define eeV2 0x05
#define eeMidiChannel 0x11
#define eeMidiTranspose 0x12
#define eeLedStripeTimeout 0x13 // Nach x Minuten LED Stripe ausschalten, wenn > 0
//#define eeMidiIn 0x13
byte keysOn[numLed + 1] = { }; // Array zum Speichern der gedrückten Keyboard Tasten
byte midiChannel = 1; // MIDI Kanal (0 = Omni Mode/Alle Kanäle)
byte midiTranspose = 0; // MIDI Transpose (Notenversatz)
byte ledStripeTimeout = 1;
byte keysPressed = 0; // Anzahl gedürckter Tasten
long unsigned ledTime; // MIDI LED Zeit (millis)
long unsigned ledStripeTime; // LED Stripe Leuchtzeit (,illis)
bool ledStripeOn = true; // Sind die LEDs eingeschaltet (Timeout)?
int H1 = 170; // Werte für nicht gedrückte Tasten (H, S, V)
byte S1 = 255;
byte V1 = 255;
int H2 = 230; // LED Werte für gedrückte Tasten (H, S, V)
byte S2 = 255;
byte V2 = 255;
byte showMenu = false;
byte menuLevel = 0;
bool encBtnPressedNew = HIGH;
bool encBtnPressedOld = LOW;
byte encButton = LOW;
byte encButtonOld = HIGH;
Adafruit_NeoPixel pixels(numLed, ledStripe, NEO_GRB + NEO_KHZ800); // LED Stripe initialiseren
// ################################################## SETUP ##################################################
void setup()
{
//EEPROM.update(eeH1 , H1);
//EEPROM.update(eeS1 , S1);
//EEPROM.update(eeV1 , V1);
//EEPROM.update(eeH2 , H2);
//EEPROM.update(eeS2 , S2);
//EEPROM.update(eeV2 , V2);
//EEPROM.update(eeMidiChannel , midiChannel);
//EEPROM.update(eeMidiTranspose , midiTranspose);
//EEPROM.update(eeLedStripeTimeout, ledStripeTimeout);
//H1 = EEPROM.read(eeH1);
//S1 = EEPROM.read(eeS1);
//V1 = EEPROM.read(eeV1);
//H2 = EEPROM.read(eeH2);
//S2 = EEPROM.read(eeS2);
//V2 = EEPROM.read(eeV2);
//midiChannel = EEPROM.read(eeMidiChannel);
//midiTranspose = EEPROM.read(eeMidiTranspose);
//ledStripeTimeout = EEPROM.read(eeLedStripeTimeout);
pinMode(pinIntLed, OUTPUT); // Pin Interne LED
pinMode(pinEnableUSB, OUTPUT); // Seriellen Port aktivieren (KEIN Serieller Betrieb mehr möglich!)
pinMode(ledStripe, OUTPUT); // Datenpin des LED Stripes
pinMode(pinEncBtn, INPUT_PULLUP);
pinMode(pinEncClk, INPUT);
pinMode(pinEncDat, INPUT);
digitalWrite(pinIntLed, HIGH); // Interne LED während der Initialisierung einchalten
digitalWrite(pinEnableUSB, LOW); // Seriellen Port für MIDI deaktivieren (über CD4066), damit Updates möglich sind. LOW = USB | HIGH = MIDI
Serial.begin(31250); // RS-232 initialisieren (31250 Baud)
// Selbsttest (1 x beim Einschalten)
for(byte y = 0; y <= numLed; y ++)
{
pixels.setPixelColor(0 + y, pixels.ColorHSV( H1 * 256, S1, V1)); // Alle Tasten von links mit Farbe 1...
pixels.setPixelColor(numLed - y, pixels.ColorHSV( H2 * 256, S2, V2)); // und von rechts mit Farbe 2 füllen.
pixels.show();
delay(20);
}
delay(500);
for(byte y = 0; y < 33; y++)
{
pixels.setBrightness(map(y, 0, 32, 255, 0)); // Helligeit aller LED von 64 bis 0 dimmen.
pixels.show();
delay(20);
}
delay(500);
pixels.setBrightness(V1); // Alle LEDs auf Helligkeit 1 (aus) setzen
for(byte x = 0; x < numLed; x++)
{
pixels.setPixelColor((numLed / 2) - x / 2, pixels.ColorHSV( H1 * 256, S1, V1)); // Alle Tasten von links und rechts...
pixels.setPixelColor((numLed / 2) + x / 2, pixels.ColorHSV( H1 * 256, S1, V1)); // mit Farbe 1 füllen.
pixels.show();
delay(10);
}
digitalWrite(pinIntLed, HIGH);
digitalWrite(pinEnableUSB, HIGH); // Ab jetzt ist MIDI über den CD4066 auf den seriellen Port (TxD) gelegt.
ledTime = millis();
ledStripeTime = millis();
}
// ################################################## LOOP ##################################################
void loop()
{
if(millis() - ledTime >= 500 && digitalRead(pinIntLed)) // Wenn interne LED (MIDI Led) leuchtet, und 1 Sekunde vergangen ist, ...
digitalWrite(pinIntLed, LOW); // LED wieder ausschalten (MIDI Anzeige leuchtet also für 0.5 Sek.).
if(Serial.available() > 2) // Sind 3 Bytes oder mehr verfügbar?
{
byte midiCommand = Serial.read(); // Ja, dann das 1 Byte einlesen...
byte midiReceiveChannel = (midiCommand & B00001111) + 1; // MIDI Kanal errechnen
if(midiReceiveChannel != midiChannel && midiChannel) // Richtiger MIDI Kanal oder OMNI Mode (Kanal 0)?
{
Serial.flush(); // Nein, dann seriellen Speicher löschen...
return; // ... und nicht reagieren
}
if(!digitalRead(pinIntLed)) // Wenn int. Led (MIDI Led) nicht bereits leuchtet, ...
{
digitalWrite(pinIntLed, HIGH); // ... int. led (MIDI Led) füe einschalten.
ledTime = millis(); // Zeit merken
}
if(!ledStripeOn) // Ist LED Stripe ausgeschaltet (nach Timeout)?
powerOnLed(); // Dann einschalten.
byte command = midiCommand >> 4; // Ja, dann MIDI Kommando errechnen, ...
byte midiNoteNumber = Serial.read() - 36 + midiTranspose; // ... Byte für Notennummer lesen und Notenwert errechnen...
byte midiVelocity = Serial.read(); // ... und Byte für Velocity lesen
if(command == 9) // Ist command = NoteOn?
{
//keysOn[midiNoteNumber] = true; // Array für gedrückte Tasten aktualisieren
keysPressed++; // Zähler für gedrückte Tasten inkrementieren
pixels.setPixelColor(midiNoteNumber, pixels.ColorHSV(H2 * 256, S2, V2)); // Led Array aktualisieren
pixels.show(); // LEDs aktualisieren
}
else if(command == 8) // Ist Command = NoteOff?
{
//keysOn[midiNoteNumber] = false; // Array für gedrückte Testen aktualisieren
if(keysPressed) // Ist die Anzahl gedrückter Tasten > 0?
keysPressed--; // Ja, dann 1 abziehen
pixels.setPixelColor(midiNoteNumber, pixels.ColorHSV(H1 * 256, S1, V1)); // Led Array aktualisieren
pixels.show(); // LEDs aktualisieren
}
ledStripeTime = millis();
}
encButton = digitalRead(pinEncBtn);
if(encButton != encButtonOld)
{
if(!encButton)
{
powerOnLed();
//menuLevel ++;
//showMenu = !showMenu;
}
encButtonOld = encButton;
}
if(millis() - ledStripeTime >= (ledStripeTimeout * 60000) && ledStripeTimeout && ledStripeOn) // LEDs nach n Minuten abschalten
powerOffLed();
}
void powerOffLed()
{
for(byte x = 0; x <= round(numLed / 2); x++)
{
pixels.setPixelColor(x , pixels.ColorHSV( H1 * 256, S1, 0)); // ... LED Leiste von links ...
pixels.setPixelColor(numLed - x, pixels.ColorHSV( H1 * 256, S1, 0)); // ... und rechts zur Mitte hin abschalten.
pixels.show();
delay(50); // Kurz warten, um den "Laufeffekt" zu simulieren
}
ledStripeOn = false; // LEDs sind aus
keysPressed = 0;
}
void powerOnLed()
{
for(byte x = 0; x <= round(numLed / 2); x++)
{
pixels.setPixelColor((numLed / 2) + x, pixels.ColorHSV( H1 * 256, S1, V1));
pixels.setPixelColor((numLed / 2) - x, pixels.ColorHSV( H1 * 256, S1, V1));
pixels.show();
delay(10);
}
ledStripeOn = true;
ledStripeTime = millis();
}
*/60
|30
1
31
50
40
20
10
Enable
USB
MIDI
61 x WS2812B