/**
Todo: digital pins 2,3,13 and analog pin A3 can be defined as LED-outs to signal the mode we are in
Modus 5 is play music according to the buttons
some variables need to be re-designed as globals etc. and as uint8, for example (the notes...)
*/
// So let's start with the libraries
// For the display:
#include <Adafruit_SSD1306.h>
// set up display
// OLED display dimensions
#define OLED_WIDTH 128
#define OLED_HEIGHT 32
// OLED display address (depends on your display)
#define OLED_ADDRESS 0x3C
// OLED display object
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, OLED_ADDRESS);
// MIDI
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE(); // Create a default MIDI instance
// For the keyboard
// This includes the file pitches.h - it will "translate" Note_** to a frequency.
#include "pitches.h"
//Where does the buzzer connect?
#define SPEAKER_PIN 8
// Where does the rotary encoder connect?
#define ENCODER_CLK A0
#define ENCODER_DT A1
#define ENCODER_SW A2
// Constants for the button pins
const uint8_t buttonPins[] = { 12, 11, 10, 9, 7, 6, 5, 4 };
const int buttonTones[] = {
NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4,
NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5
};
const int numTones = sizeof(buttonPins) / sizeof(buttonPins[0]);
//Here all the variables are defined for the loop-stuff:
int lastClk = HIGH; // used for the rotary encoder
int lastencSW = HIGH; // rotary button
int zaehler = 0; //
String message = " ";
int modus = 0; // Modus to start with
String Modusname ; // welcher Parameter soll mit encoder eingestellt werden?
int rotary = 0; // encoder -1, 0 +1, up, equal, down
int bpm = 120; // Beats per miute - Speed also
float period = 500; // Abstand zwischen Noten - wird aus bpm erechnet
int index = 1; // welche Skala soll gespielt werden?
unsigned long startMillis = millis(); //some global variables available anywhere in the program
unsigned long currentMillis;
int basetone = 60; // MIDI-code for C4
int channel = 1; // MIDI Kanal
String midiNote = ""; //
int midiNummer = 60;
String skalenname = "";
int skala[16]; // = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
int ion_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
int dor_skala[] = {1, 3, 4, 6, 8, 10, 11, 13, 13, 15, 16, 18, 20, 22, 23, 25};
int phy_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
int lyd_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
int mix_skala[] = {1, 3, 5, 6, 8, 10, 11, 13, 13, 15, 17, 18, 20, 22, 23, 25};
int ael_skala[] = {1, 3, 4, 6, 8, 9, 11, 13, 13, 15, 16, 18, 20, 21, 23, 25};
int lok_skala[] = {1, 2, 4, 6, 7, 9, 11, 13, 13, 14, 16, 18, 19, 21, 23, 25};
int i = 0;
int x = 1;
bool increment = true;
int frequ = 440;
bool playing = false;
// Pins für die LEDs
#define pinSpeed 2
#define pinSkala 3
#define pinGrundton 13
#define pinKanal A3
#define pinBeat 13
void setup() {
delay(500);
for (uint8_t i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(SPEAKER_PIN, OUTPUT);
// Initialize OLED display
display.begin(SSD1306_SWITCHCAPVCC);
display.clearDisplay();
oledOut("Starting up");
delay(500);
}
/*
void setup() {
delay(500);
for (uint8_t i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(SPEAKER_PIN, OUTPUT);
// Initialize OLED display
display.begin(SSD1306_SWITCHCAPVCC);
display.clearDisplay();
oledOut("Starting up");
delay(500);
// Now MIDI setup
oledOut(" Setting up MIDI ");
// MIDI_CREATE_DEFAULT_INSTANCE(); // Create a default MIDI instance
MIDI.begin(31250);
MIDI.sendNoteOn(69, 127, 1);
delay(500);
MIDI.sendNoteOn(69, 0, 1);
oledOut("Midi working fine");
delay(500);
// Send Testtone A
// display.clearDisplay();
tone(SPEAKER_PIN, frequ);
oledOut("Testton A");
oledOut2(String(frequ));
delay(500);
noTone(SPEAKER_PIN);
}
*****************************/
void loop() {
// ******************************
// zuerst Auswertung des Encoderschalters
int newencSW = digitalRead(ENCODER_SW);
// Abfrage, ob Schalter gedrückt wurde, um jedesmal den Modus
// um 1 zu erhöhen, dann zurück auf 0.
if (newencSW != lastencSW) {
zaehler = zaehler +1;
for (int ch = 0; ch < 16; ch++) MIDI.sendControlChange(ch, 0xff, 0); // Stop MIDIOutput
noTone(SPEAKER_PIN); // Stop ToneOutput
playing = false; // Nix wird gspüt
if (zaehler >= 2) {
// Modus weiterschalten und derweil seriell ausgeben, es beginnt mit
modus ++;
if (modus >= 5) {modus = 0;}
// Serial.println("Switch is pressed, Modus ist " + String(modus));
// Zum schluss noch Zähler um eins erhöhen
zaehler = 0;
}
lastencSW = newencSW;
}
// dann Auswertung des Drehencoders - ,
// endet mit rotary als -1, 0 oder +1 unterhalb der Abfrage
rotary = 0; // start mit 0
int newClk = digitalRead(ENCODER_CLK);
if (newClk != lastClk) { // wenn geclickt wurde, dann schauennob + oder -
lastClk = newClk;
int dtValue = digitalRead(ENCODER_DT);
if (newClk == LOW && dtValue == HIGH) {
rotary ++;
// Serial.println("Rotated clockwise ⏩ and rotary value is " + String(rotary));
}
if (newClk == LOW && dtValue == LOW) {
rotary --;
}
}
// Auswertung von Modus, wenn Schalter gedrückt worden ist
if(modus == 0) { // Modus 0, also speed
oledOut("Modus Speed");
//case 0:
if (rotary == 1){bpm = bpm +1;}
if (rotary == -1) {bpm = bpm -1;}
oledOut2(String(bpm));
period = 60000/bpm;
// digitalWrite(pinSpeed, HIGH);
// digitalWrite(pinSkala, LOW);
// digitalWrite(pinGrundton, LOW);
// digitalWrite(pinKanal, LOW);
// Geschwindigkeit
}
if(modus == 1) { // Modus 1, also welche Skala
// case 1:
oledOut("Modus Skala");
index = index + rotary;
if (index >= 8){index = 1;}
if (index <= 0){index = 7;}
// digitalWrite(pinSpeed, LOW);
// digitalWrite(pinSkala, HIGH);
// digitalWrite(pinGrundton, LOW);
// digitalWrite(pinKanal, LOW);
//Serial.println("Index der Skala = " +String(index));
//delay(15);
// Tonart
// break;
}
if(modus == 2) { // Modus 2, also welcher Grundton
oledOut("Modus Grundton");
basetone = basetone + rotary;
// digitalWrite(pinSpeed, LOW);
// digitalWrite(pinSkala, LOW);
// digitalWrite(pinGrundton, HIGH);
// digitalWrite(pinKanal, LOW);
}
if(modus == 3) { // Modus 3, also welcher Midikanal
oledOut("Modus Midikanal");
channel = channel + rotary;
if (channel >= 17){channel = 1;}
if (channel <= 0){channel = 16;}
// digitalWrite(pinSpeed, LOW);
// digitalWrite(pinSkala, LOW);
// digitalWrite(pinGrundton, LOW);
// digitalWrite(pinKanal, HIGH);
}
/******************************/
// Wenn encoder_sw gedrückt wird und damit modus in Stellung 5 kommt,
// dann werden die Tasten abgefragt um Musik zu spielen
if (modus == 4){
oledOut("Modus Keys");
int pitch = 0;
for (uint8_t i = 0; i < numTones; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
pitch = buttonTones[i];
if (i == 0){midiNummer = 60;}
if (i == 1){midiNummer = 62;}
if (i == 2){midiNummer = 64;}
if (i == 3){midiNummer = 65;}
if (i == 4){midiNummer = 67;}
if (i == 5){midiNummer = 69;}
if (i == 6){midiNummer = 71;}
if (i == 7){midiNummer = 72;}
}
}
if (pitch) {
if (!playing) {
tone(SPEAKER_PIN, pitch);
MIDI.sendNoteOn(midiNummer, 127, channel);
oledOut(String("Frequency: ") + pitch);
playing = true;
}
} else {
if (playing) {
noTone(SPEAKER_PIN);
MIDI.sendNoteOn(midiNummer, 0, channel);
playing = false;
}
}
} else {
// ***************************************************
// Nun zur Auswahl der Skala:
switch (index) { // Welche Tonart wird gespielt anhängig v index
case 1:
skalenname = "Ionisch (Dur)";
memcpy(skala, ion_skala, sizeof(ion_skala));
break;
case 2:
skalenname = "Dorisch";
memcpy(skala, dor_skala, sizeof(dor_skala));
break;
case 3:
skalenname = "Phyrgisch";
memcpy(skala, phy_skala, sizeof(phy_skala));
break;
case 4:
skalenname = "Lydisch";
memcpy(skala, lyd_skala, sizeof(lyd_skala));
break;
case 5:
skalenname = "Mixolydisch";
memcpy(skala, mix_skala, sizeof(mix_skala));
break;
case 6:
skalenname = "Aeolisch";
memcpy(skala, ael_skala, sizeof(ael_skala));
break;
case 7:
skalenname = "Lokrisch";
memcpy(skala, lok_skala, sizeof(lok_skala));
break;
}
// Und hier jetzt die Ausgabe - abhängig von den millis...
currentMillis = millis(); //get the current time
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
midiNummer = basetone + skala[i] -1; //-1 + skala[i];
Midinummer_Name(); // Name aus Nummer generieren
startMillis = currentMillis; //IMPORTANT to save the start time
Serial.println("BPM = "+ String(bpm) + ", (Period = " + String(period) + "), Skala = " + skalenname + ", Grundton ist " + String(basetone) + ", Note = " + String(midiNummer) + " , " + midiNote + ", Kanal = "+ String(channel));
// MIDI.sendNoteOn(60, 127, 1); // Send a MIDI note on message
// midi.sendNoteOff(60, 0, 1);;
//Serial.println(", " + midiNote + " " + skalenname);
oledOut(String(bpm) + " "+ skalenname + " " + String(midiNummer));
// Jetzt zur nächsten Note der Skala schalten
if (x == 0) {
// Inkrementieren Sie den Zählerwert
x++;
} else if (increment && x < 16) {
// Inkrementieren Sie den Zählerwert
x++;
} else if (!increment && x > 1) {
// Dekrementieren Sie den Zählerwert
x--;
} else {
// Wechseln Sie die Zählerrichtung
increment = !increment;
}
i = x -1;
}
// if (currentMillis - startMillis >= period/100) {
// digitalWrite(pinBeat, HIGH);
// digitalWrite(pinBeat, HIGH);
// digitalWrite(pinBeat, LOW);}
// else {digitalWrite(pinBeat, HIGH);}
// ***************************************************/
}
}
// void output(const char *message) { // besser mit (String message)
void oledOut(String message) {
//Clear OLED display
display.clearDisplay();
// Display current message on OLED
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(message);
display.display();
}
void oledOut2(String message) {
// Clear OLED display
//display.clearDisplay();
// Display current message on OLED
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 9);
display.println(message);
display.display();
}
void Midinummer_Name() { // Aus der Nummer einen Namen machen..
switch (midiNummer) {
case 21:
midiNote = "A0";
frequ = 27;
break;
case 22:
midiNote = "A#0/Bb0";
frequ = 29;
break;
case 23:
midiNote = "B0";
frequ = 31;
break;
case 24:
midiNote = "C1";
frequ = 33;
break;
case 25:
midiNote = "C#1/Db1";
frequ = 35;
break;
case 26:
midiNote = "D1";
frequ = 37;
break;
case 27:
midiNote = "D#1/Eb1";
frequ = 39;
break;
case 28:
midiNote = "E1";
frequ = 41;
break;
case 29:
midiNote = "F1";
frequ = 44;
break;
case 30:
midiNote = "F#1/Gb1";
frequ = 46;
break;
case 31:
midiNote = "G1";
frequ = 49;
break;
case 32:
midiNote = "G#1/Ab1";
frequ = 52;
break;
case 33:
midiNote = "A1";
frequ = 55;
break;
case 34:
midiNote = "A#1/Bb1";
frequ = 58;
break;
case 35:
midiNote = "B1";
frequ = 62;
break;
case 36:
midiNote = "C2";
frequ = 65;
break;
case 37:
midiNote = "C#2/Db2";
frequ = 69;
break;
case 38:
midiNote = "D2";
frequ = 73;
break;
case 39:
midiNote = "D#2/Eb2";
frequ = 78;
break;
case 40:
midiNote = "E2";
frequ = 82;
break;
case 41:
midiNote = "F2";
frequ = 87;
break;
case 42:
midiNote = "F#2/Gb2";
frequ = 93;
break;
case 43:
midiNote = "G2";
frequ = 98;
break;
case 44:
midiNote = "G#2/Ab2";
frequ = 104;
break;
case 45:
midiNote = "A2";
frequ = 110;
break;
case 46:
midiNote = "A#2/Bb2";
frequ = 117;
break;
case 47:
midiNote = "B2";
frequ = 123;
break;
case 48:
midiNote = "C3";
frequ = 131;
break;
case 49:
midiNote = "C#3/Db3";
frequ = 139;
break;
case 50:
midiNote = "D3";
frequ = 147;
break;
case 51:
midiNote = "D#3/Eb3";
frequ = 156;
break;
case 52:
midiNote = "E3";
frequ = 165;
break;
case 53:
midiNote = "F3";
frequ = 175;
break;
case 54:
midiNote = "F#3/Gb3";
frequ = 185;
break;
case 55:
midiNote = "G3";
frequ = 196;
break;
case 56:
midiNote = "G#3/Ab3";
frequ = 208;
break;
case 57:
midiNote = "A3";
frequ = 220;
break;
case 58:
midiNote = "A#3/Bb3";
frequ = 233;
break;
case 59:
midiNote = "B3";
frequ = 247;
break;
case 60:
midiNote = "C4";
frequ = 262;
break;
case 61:
midiNote = "C#4/Db4";
frequ = 277;
break;
case 62:
midiNote = "D4";
frequ = 294;
break;
case 63:
midiNote = "D#4/Eb4";
frequ = 311;
break;
case 64:
midiNote = "E4";
frequ = 330;
break;
case 65:
midiNote = "F4";
frequ = 349;
break;
case 66:
midiNote = "F#4/Gb4";
frequ = 370;
break;
case 67:
midiNote = "G4";
frequ = 392;
break;
case 68:
midiNote = "G#4/Ab4";
frequ = 415;
break;
case 69:
midiNote = "A4";
frequ = 440;
break;
case 70:
midiNote = "A#4/Bb4";
frequ = 466;
break;
case 71:
midiNote = "B4";
frequ = 494;
break;
case 72:
midiNote = "C5";
frequ = 523;
break;
case 73:
midiNote = "C#5/Db5";
frequ = 554;
break;
case 74:
midiNote = "D5";
frequ = 587;
break;
case 75:
midiNote = "D#5/Eb5";
frequ = 622;
break;
case 76:
midiNote = "E5";
frequ = 659;
break;
case 77:
midiNote = "F5";
frequ = 698;
break;
case 78:
midiNote = "F#5/Gb5";
frequ = 740;
break;
case 79:
midiNote = "G5";
frequ = 784;
break;
case 80:
midiNote = "G#5/Ab5";
frequ = 831;
break;
case 81:
midiNote = "A5";
frequ = 880;
break;
case 82:
midiNote = "A#5/Bb5";
frequ = 932;
break;
case 83:
midiNote = "B5";
frequ = 988;
break;
case 84:
midiNote = "C6";
frequ = 1047;
break;
case 85:
midiNote = "C#6/Db6";
frequ = 1109;
break;
case 86:
midiNote = "D6";
frequ = 1175;
break;
case 87:
midiNote = "D#6/Eb6";
frequ = 1245;
break;
case 88:
midiNote = "E6";
frequ = 1319;
break;
case 89:
midiNote = "F6";
frequ = 1397;
break;
case 90:
midiNote = "F#6/Gb6";
frequ = 1480;
break;
case 91:
midiNote = "G";
frequ = 1568;
break;
case 92:
midiNote = "G#6/Ab6";
frequ = 1661;
break;
case 93:
midiNote = "A6";
frequ = 1760;
break;
case 94:
midiNote = "A#6/Bb6";
frequ = 1865;
break;
case 95:
midiNote = "B6";
frequ = 1976;
break;
case 96:
midiNote = "C7";
frequ = 2093;
break;
case 97:
midiNote = "C#7/Db7";
frequ = 2217;
break;
case 98:
midiNote = "D7";
frequ = 2349;
break;
case 99:
midiNote = "D#7/Eb7";
frequ = 2489;
break;
case 100:
midiNote = "E7";
frequ = 2637;
break;
case 101:
midiNote = "F7";
frequ = 2794;
break;
case 102:
midiNote = "F#7/Gb7";
frequ = 2960;
break;
case 103:
midiNote = "G7";
frequ = 3136;
break;
case 104:
midiNote = "G#7/Ab7";
frequ = 3322;
break;
case 105:
midiNote = "A7";
frequ = 3520;
break;
case 106:
midiNote = "A#7/Bb7";
frequ = 3729;
break;
case 107:
midiNote = "B7";
frequ = 3951;
break;
case 108:
midiNote = "C8";
frequ = 4186;
break;
}
}Loading
ssd1306
ssd1306