#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <TimedBlink.h>
#include <MIDIcontroller.h>
/* ----------------- Pin Connection Notes ----------------
// All V+ is 3.3V unless stated
// OLED
SDA --> GPIO 4
SCL --> GPIO 5
// Switches (NO - connected to GND)
Encoder Switch --> GPIO 6
Footswitch A --> GPIO 7
Footswitch B --> GPIO 8
// LEDs
LED Switch A --> GPIO 9
LED Switch B --> GPIO 10
// Encoder
DT --> GPIO 16
CLK --> GPIO 17
// Pots
Pot X --> GPIO 22
Pot Y --> GPIO 21
Pot Z --> GPIO 20
Pot Mix --> GPIO 19
Pot Vol --> GPIO 18
--------------------- Pin Connection Notes ---------------- */
// OLED
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Pot Pins
#define potXPin A2 // pin34(GP28)
#define potYPin A1 // pin32(GP27)
#define potZPin A0 // pin31(GP26)
// Encoder Pins
const int encPinA = 16;
const int encPinB = 17;
const int encbtnPin = 6;
// Button Pins
#define swAPin 7
#define swBPin 8
// LED Pins
#define swALEDPin 9
#define swBLEDPin 10
TimedBlink monitor1(swALEDPin);
TimedBlink monitor2(swBLEDPin);
// MIDI
byte MIDIchannel = 1;
MIDIenc myEnc(encPinA, encPinB, 24);
MIDIbutton myButton(encbtnPin, 25, LATCH);
// presets 11 options:
// (preset#),(presetName),(algo#),(potX),(potY),(potZ),(potMix),(potVol),(ledAMode),(ledBMode),(Bpm)
const int presetList[] = {1, 0, 1, 25, 45, 55, 60, 60, 1, 2, 85,
2, 1, 2, 51, 41, 0, 60, 60, 0, 2, 120,
3, 2, 3, 34, 60, 78, 60, 60, 0, 1, 51,
4, 3, 4, 27, 32, 22, 60, 60, 0, 1, 62,
5, 4, 5, 18, 95, 82, 60, 60, 0, 1, 70,
6, 5, 6, 100, 24, 45, 60, 60, 0, 1, 90,
7, 6, 7, 67, 78, 120, 60, 60, 0, 1, 155,
8, 7, 8, 21, 40, 25, 60, 60, 0, 1, 180
};
const char *presetNameList[] = {"CavrnSwell", "ModAngel", "Twilight", "Arise", "StndrdRoom", "Bleum", "Higher", "Treetops"};
const char *algoList[] = {"Room", "Hall", "Chamber", "Cavern", "Modulated", "Shimmer", "Pitch", "Duck"};
// Variable Pots in orders of 3 for each algorithm
const char *potList[] = {"Time", "PreD", "Dmpn",
"Time", "PreD", "Dmpn",
"Time", "Bass", "Treb",
"Time", "Bass", "Treb",
"Time", "ModD", "ModR",
"Time", "Ptch", "Amnt",
"Time", "OctD", "OctU",
"Time", "Duck", "Sens"
};
int presetActiveNumber = 4; // Set preset to 1 >> move to last used in future!
int presetActiveAlgo = presetList[(presetActiveNumber*11)-9]; // Current Algorithm
int presetActiveTempo = presetList[(presetActiveNumber*11)-1]; //Current tempo
#define presetActiveName presetNameList[presetActiveNumber - 1] // Get name of Current Preset
// UI
#define potXName potList[(presetActiveAlgo * 3)-3]
#define potYName potList[(presetActiveAlgo * 3)-2]
#define potZName potList[(presetActiveAlgo * 3)-1]
#define potMixName "Mix"
#define potVolName "Vol"
// Pots - Values 0-120
int potXVal = 80;
int potXLastVal = 80;
int potXPresetVal = presetList[(presetActiveNumber*11)-8];
bool potXState = 0; // true if edited, false if saved state
int potYVal = 65;
int potYLastVal = 65;
int potYPresetVal = presetList[(presetActiveNumber*11)-7];
bool potYState = 0; // true if edited, false if saved state
int potZVal = 40;
int potZLastVal = 40;
int potZPresetVal = presetList[(presetActiveNumber*11)-6];
bool potZState = 0; // true if edited, false if saved state
int potMixVal = 60;
int potMixLastVal = 60;
int potMixPresetVal = presetList[(presetActiveNumber*11)-5];
bool potMixState = 0; // true if edited, false if saved state
int potVolVal = 60;
int potVolLastVal = 60;
int potVolPresetVal = presetList[(presetActiveNumber*11)-4];
bool potVolState = 0; // true if edited, false if saved state
int EncSwState = 0;
int EncSwLastState = 0;
int swAState = 0;
int swALastState = 0;
int swBState = 0;
int swBLastState = 0;
const int ledList[] = {swALEDPin, swBLEDPin}; // List all LEDs to iterate
int ledAMode = presetList[(presetActiveNumber*11)-3]; // 0 = off, 1 = on, 2 = Blink(to tempo), 3 = pattern blink(edited)
int ledBMode = presetList[(presetActiveNumber*11)-2];
int currentLED = ledList[0];
int ledDelay = 100; // how long led stays on when in pattern in ms
bool displayChanged = true;
bool buttonChanged = true;
bool potChanged = true;
bool encoderChanged = true;
bool testModeSwitch = 1;
bool ledATempo = false;
bool ledAEdited = false;
bool ledBTempo = false;
bool ledBEdited = false;
// --------- Splash screen for startup
const uint8_t splash_screen1[] = {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x67, 0x00, 0x00, 0xe7, 0x00, 0x00, 0xe7, 0x00, 0x01, 0xc3, 0x80, 0x01, 0xc3, 0x80, 0x01, 0xc3, 0x80, 0x03, 0x81, 0xc0, 0x03, 0x81, 0xc0, 0x03, 0x01, 0xc0, 0x07, 0x3c, 0xe0, 0x07, 0xfe, 0xe0, 0x07, 0xff, 0xf0, 0x0f, 0xc3, 0xf0, 0x0f, 0x80, 0xf0, 0x0e, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void drawStartup() {
display.clearDisplay();
display.drawBitmap(64, 17, splash_screen1, 24, 24, 1);
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(19, 27);
display.println("GRACEFUL");
display.setCursor(85, 27);
display.println("UDIO");
display.setCursor(20, 55);
display.display();
delay(1000);
display.print("initializing");
display.display();
delay(100);
/*
display.print(".");
display.display();
delay(100);
display.print(".");
display.display();
delay(100);
display.print(".");
display.display();
delay(100);
*/
}
// --------- Splash screen for startup
void drawMain() {
// OLED setup for Main operation
display.clearDisplay();
// ---------- Draw Title-Bar ----------
display.setTextColor(WHITE);
display.setTextSize(1);
display.setFont(NULL); //necessary??
display.setCursor(0, 0);
display.println("PRESET");
display.setCursor(38, 0);
display.println(presetActiveNumber);
display.setCursor(54, 0);
display.println("|Alg");
display.setCursor(80, 0);
display.println(presetActiveAlgo);
display.setCursor(86, 0);
display.print("|");
display.print(presetActiveTempo);
display.println("Bpm");
display.setCursor(1, 6);
display.println("---------------------");
// ---------- Preset Name ----------
display.setCursor(3, 13);
display.setTextSize(2);
display.println(presetActiveName);
// ---------- Pot Indicators ----------
display.drawCircle(28, 42, 10, 1); // potX
display.drawCircle(64, 42, 10, 1); // potY
display.drawCircle(100, 42, 10, 1); // potZ
//display.fillCircle(100, 42, 10, 1); // inverted circle color
display.drawLine(28, 42, 36, 40, 1); // potX
display.drawLine(64, 42, 65, 34, 1); // potY
display.drawLine(100, 42, 94, 37, 1); // potZ
//display.drawLine(100, 42, 94, 37, 0); // inverted line color
// ---------- Pot Labels ----------
display.setTextSize(1);
display.setCursor(16, 55);
display.println(potXName);
display.setCursor(53, 55);
display.println(potYName);
display.setCursor(90, 55);
//display.setTextColor(BLACK, WHITE); // inverted text color
display.println(potZName);
display.display();
}
void drawMenu() {
// OLED setup for Menu's
}
// Relays for audio IO
void relayBypass() {
// set relays to True Bypass
}
void relayActive() {
// set relays to Active
}
// MIDI IO
// MIDI IN controller
// MIDI OUT controller
// MIDI Thru controller??
// User IO
// LED controller
void ledTest() {
// set swALEDPin high
digitalWrite(swALEDPin, HIGH);
delay(500);
digitalWrite(swBLEDPin, HIGH);
delay(1000);
digitalWrite(swALEDPin, LOW);
digitalWrite(swBLEDPin, LOW);
delay(1000);
}
void ledModeSet() {
// LED off 0 , LED On 1, LED tempo 2, LED Edited 3
if (ledAMode == 0) {
ledATempo = false;
ledAEdited = false;
digitalWrite(swALEDPin, LOW);
} else if (ledAMode == 1) {
ledATempo = false;
ledAEdited = false;
digitalWrite(swALEDPin, HIGH);
} else if (ledAMode == 2) {
ledATempo = true;
ledAEdited = false;
} else if (ledAMode == 3) {
ledATempo = false;
ledAEdited = true;
}
if (ledBMode == 0) {
ledBTempo = false;
ledBEdited = false;
digitalWrite(swBLEDPin, LOW);
} else if (ledBMode == 1) {
ledBTempo = false;
ledBEdited = false;
digitalWrite(swBLEDPin, HIGH);
} else if (ledBMode == 2) {
ledBTempo = true;
ledBEdited = false;
} else if (ledBMode == 3) {
ledBTempo = false;
ledBEdited = true;
}
}
void ledTempoPattern() {
if (ledATempo == true) {
monitor1.blink();
}
if (ledBTempo == true) {
monitor2.blink();
}
}
void checkIO() {
// Encoder controller
if (encoderChanged == true) {
// read encoder and update
}
// Button/switch Controller (include encoder and tap switches)
if (buttonChanged == true) {
// read buttons and update
}
// Pot Controller
if (potChanged == true) {
// read pots and update
}
}
void presetGet() {
// already have preset number > pull rest of preset info
presetActiveName = presetNameList[presetActiveNumber - 1]; // change later
presetActiveAlgo = presetList[(presetActiveNumber*11)-9];
potXPresetVal = presetList[(presetActiveNumber*11)-8];
potYPresetVal = presetList[(presetActiveNumber*11)-7];
potZPresetVal = presetList[(presetActiveNumber*11)-6];
potMixPresetVal = presetList[(presetActiveNumber*11)-5];
potVolPresetVal = presetList[(presetActiveNumber*11)-4];
ledAMode = presetList[(presetActiveNumber*11)-3];
ledBMode = presetList[(presetActiveNumber*11)-2];
presetActiveTempo = presetList[(presetActiveNumber*11)-1];
// update display and pots
displayChanged = true;
ledModeSet();
// potChanged = true;
}
void checkDisplay() {
if (displayChanged == true) {
drawMain();
displayChanged = false;
}
}
/* void testMode() {
if (testModeSwitch == 1) {
if (presetActiveNumber > 8) {
++presetActiveNumber;
} else if (presetActiveNumber == 8) {
presetActiveNumber = 1;
}
}
} */
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
//relayBypass(); // make sure relays are not active (should default to bypassed electrically)
drawStartup();
pinMode(swALEDPin, OUTPUT);
pinMode(swBLEDPin, OUTPUT);
ledTest();
presetGet();
monitor1.blink(ledDelay,(60000/presetActiveTempo)-ledDelay);
monitor2.blink(ledDelay,(60000/presetActiveTempo)-ledDelay);
//relayActive(); // unlatch relays - if setting 'Active on poweron' is set
}
void loop() {
// Check IO
checkIO(); // test Encoder, Pots, Buttons, MIDI for changes
checkDisplay();
ledTempoPattern();
myEnc.send();
myButton.send();
while(usbMIDI.read()){}
while(MIDI.read()){}
// testMode();
delay(1); // this speeds up the simulation
}