/*****************************************
Well, I try it again.
*****************************************/
///////////// Rotary funktioniert jetzt
// 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
//
// Buttons:
const uint8_t buttonPins[] = { 12, 11, 10, 9, 8, 7, 6, 5 };
//
// LEDs
const uint8_t signalPins[] = {A0, A1, A2, A3};
//
// Encoder library
#include <Encoder.h>
Encoder rotaryEncoder(3, 2);
const int ENCODER_SW = 13; // Button
// int reading_CLK = 0; // variable to store the A reading
// int reading_DT = 0; // variable to store the B reading
// int last_CLK = 0; // variable to store the previous A reading
// int last_DT = 0; // variable to store the previous B reading
//
struct NoteInfo { // Variable, in der sowohl Name als auch Frequenz gespeichert sind.
String name;
int frequency;
};
// Buzzer is connected to
#define SPEAKER_PIN 4 // Wo ist der Buzzer angeschlossen?
//
// Variable
uint16_t frequ = 440; // Freuenz, die am Buzzer ausgegeben wird
// int midiNummer = 60; // Tonhöhennummer, die über MIDI ausgegeben wird
uint8_t channel; // MIDI-Kanal
bool playing = false; // Wird gerade etwas abgespielt?
//
int lastClk = HIGH; // used to read encoder movement
int lastencSW = HIGH; // Switch was pressed
int zaehler = 0; // counter
String message = " "; // no real message
int modus = 0; // Modusnummer, we start with 0
String Modusname ; // welcher Parameter soll mit encoder eingestellt werden?
volatile int rotary = 0;
// int rotary = 0; // encoder unverändert, -1, 0 +1
int bpm = 240; // Beats per miute - Speed also
float period = 250; // 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; // what time is it?
int basetone = 60; // base tone of scale to play
String midiNote = ""; // Name of tone plaid
String skalenname = ""; // Name of scale
float frequency;
// Skalen
int skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int ion_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int dor_skala[] = {1, 3, 4, 6, 8, 10, 11, 13, 13, 15, 16, 18, 20, 22, 23, 25};
const int phy_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int lyd_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int mix_skala[] = {1, 3, 5, 6, 8, 10, 11, 13, 13, 15, 17, 18, 20, 22, 23, 25};
const int ael_skala[] = {1, 3, 4, 6, 8, 9, 11, 13, 13, 15, 16, 18, 20, 21, 23, 25};
const int lok_skala[] = {1, 2, 4, 6, 7, 9, 11, 13, 13, 14, 16, 18, 19, 21, 23, 25};
const int who_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int chr_skala[] = {1, 3, 4, 6, 8, 9, 11, 13, 13, 15, 16, 18, 20, 21, 23, 25};
const int woi_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int whoi_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int whoio_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int hyp_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int hol_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int min_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int mel_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int pel_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
const int phr_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int pla_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int hypo_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int hypol_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int hypophr_skala[] = {1, 2, 4, 6, 8, 9, 11, 13, 13, 14, 16, 18, 20, 21, 23, 25};
const int hypopl_skala[] = {1, 3, 5, 7, 8, 10, 12, 13, 13, 15, 17, 19, 20, 22, 24, 25};
const int hypopel_skala[] = {1, 3, 5, 6, 8, 10, 12, 13, 13, 15, 17, 18, 20, 22, 24, 25};
//
const int NUM_NOTES = 73; // 128;
struct Note {
int midiNumber;
char name[4];
float frequency;
};
bool increment = true;
uint8_t x = 0;
uint8_t i = 0;
void setup() {
// Um die Buttonpins nach Masse zu geschlossen zu detektieren
for (uint8_t i = 0; i < 8; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(ENCODER_SW, INPUT_PULLUP);
pinMode(SPEAKER_PIN, OUTPUT);
// Initialize OLED display
display.begin(SSD1306_SWITCHCAPVCC);
display.clearDisplay();
oledOut("Starting up");
oledOut2("OLED ok");
delay(400);
// Now MIDI setup
oledOut("Start 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);
oledOut2("MIDI ok");
delay(500);
// Send Testtone A
tone(SPEAKER_PIN, frequ);
oledOut("Testton A");
oledOut2(String(frequ));
delay(500);
noTone(SPEAKER_PIN);
delay(100);
//
// CHeck LEDS
// define the first four pins in the signalPins array as output pins
for (int i = 0; i < 5; i++) {
pinMode(signalPins[i], OUTPUT);
}
// turn on and off the output pins one by one
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], HIGH);
oledOut("LED " + String(i + 1)); // Oled output
frequ = 55 * (i + 1); // what frquency
oledOut2(String(frequ)); // Oled output of Frequency
tone(SPEAKER_PIN, frequ); // Make it sound
delay(120); // wait
}
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], LOW);
oledOut("LED " + String(i + 1));
frequ = 440 * (i + 1);
oledOut2(String(frequ));
tone(SPEAKER_PIN, frequ);
delay(120);
}
delay(120);
oledOut("");
noTone(SPEAKER_PIN);
NoteInfo info = getNoteName(50);
tone(SPEAKER_PIN, info.frequency);
// MIDI.sendNoteOn(midiNummer, 100, 1);
oledOut(info.name);
oledOut2(String(info.frequency));
//
//tone(SPEAKER_PIN, notes[50].frequency);
delay(200);
noTone(SPEAKER_PIN);
oledOut("Push Encoder Button");
oledOut2("or the keys");
// delay(200);
// Now in a loop to play the buttons
while (digitalRead(ENCODER_SW) == HIGH) { // until you press Encoder button
keyboard(); // jump into function to play the keyboard
}
oledOut("ok, Main Program now");
delay(200); // wait to switch to speed mode,
}
void loop() {
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;
}
// read rotary encoder and change values
static int oldPosition = 0; // variable to store the previous position of the encoder
int position = rotaryEncoder.read(); // read the current position of the encoder
if (position > oldPosition) { // the encoder was turned right
rotary = 1;
} else if (position < oldPosition) { // the encoder was turned left
rotary = -1;
} else { // the encoder was not turned
rotary = 0;
}
oldPosition = position; // store the current position for the next loop iteration
// 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;
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], LOW);
digitalWrite(signalPins[0], HIGH);
}
// Geschwindigkeit
}
if (modus == 1) { // Modus 1, also welche Skala
// case 1:
// oledOut("Modus Skala");
// oledOut2(skalenname);
index = index + rotary;
if (index >= 8) {
index = 0;
}
if (index < 0) {
index = 7;
}
// 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;
}
for (int i = 0; i < 5; i++)
{ digitalWrite(signalPins[i], LOW);
digitalWrite(signalPins[1], HIGH);
// oledOut(String(index));
// delay(200);
}
}
if (modus == 2) { // Modus 2, also welcher Grundton
// oledOut("Modus Grundton");
basetone = basetone + rotary;
if (basetone > 72) {
basetone = 24;
}
if (basetone < 24) {
basetone = 72;
}
// oledOut2(String(basetone));
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], LOW);
digitalWrite(signalPins[2], HIGH);
}
}
if (modus == 3) { // Modus 3, also welcher Midikanal
// oledOut("Modus Midikanal");
channel = channel + rotary;
// oledOut2(String(channel));
if (channel >= 17) {
channel = 1;
}
if (channel <= 0) {
channel = 16;
}
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], LOW);
digitalWrite(signalPins[3], HIGH);
}
}
if (modus == 4) {
oledOut("Push Encoder Button"); // Show what happens
oledOut2("or the keys"); // and what can be done
for (int i = 0; i < 5; i++) {
digitalWrite(signalPins[i], HIGH);
// digitalWrite(signalPins[4], HIGH);
}
keyboard();
}
/******************************/
//****************************
// 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
{
//****
// oledOut(String(basetone + skala[i] -1));
// delay(200);)
int midiNummer = basetone - 1 + skala[i]; //-1 + skala[i];
NoteInfo info = getNoteName(midiNummer);
noTone(SPEAKER_PIN);
tone(SPEAKER_PIN, info.frequency); // here music is made
MIDI.sendNoteOn(midiNummer, 100, 1);
// Serial.println(info.name + " " + String(info.frequency));
// oledOut(info.name);
// oledOut2(String(info.frequency));
// */
// Midinummer_Name(); // Name aus Nummer generieren
//
startMillis = currentMillis; //IMPORTANT to save the start time
// oledOut(String(midiNummer));
// oledOut(notes[midiNummer].name);
// oledOut("P " + String(i) + " " + String(skala[i])); // + String(basetone + skala[i] -1));
// Serial.println("P " + String(i) + " " + String(skala[i])); // + String(basetone + skala[i] -1));
// MIDI.sendNoteOn(60, 127, 1); // Send a MIDI note on message
// midi.sendNoteOff(60, 0, 1);;
// tone(SPEAKER_PIN, notes[basetone -1 + skala[i]].frequency);
// oledOut2(schwing); // String(bpm) + " " + skalenname + " " + String(midiNummer) + " " + String(basetone) + " " + String(channel));
// 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;
/****/
// oledOut("inside loop");
// oledOut2(String(bpm)+" "+ skalenname);
}
if (currentMillis - startMillis >= period / 100) {
//digitalWrite(pinBeat, HIGH);
// digitalWrite(pinBeat, HIGH);
digitalWrite(signalPins[2], LOW);
}
else {
digitalWrite(signalPins[2], HIGH);
}
/***************************/
}
// here the function that calculates the Name and frequency of a midiNummer
NoteInfo getNoteName(int midiNummer) {
// Calculate the octave
int octave = (midiNummer / 12) - 1;
// Calculate the note number
int note = midiNummer % 12;
// Get the note name
String noteName;
int faktor;
switch (note) {
case 0:
noteName = "C";
faktor = 523.25;
break;
case 1:
noteName = "C#";
faktor = 554.37;
break;
case 2:
noteName = "D";
faktor = 587.33;
break;
case 3:
noteName = "D#";
faktor = 622.25;
break;
case 4:
noteName = "E";
faktor = 659.25;
break;
case 5:
noteName = "F";
faktor = 698.46;
break;
case 6:
noteName = "F#";
faktor = 739.99;
break;
case 7:
noteName = "G";
faktor = 783.99;
break;
case 8:
noteName = "G#";
faktor = 830.61;
break;
case 9:
noteName = "A";
faktor = 880;
break;
case 10:
noteName = "A#";
faktor = 932.33;
break;
case 11:
noteName = "B";
faktor = 987.77;
break;
}
// Calculate the frequency using the provided formula
frequency = faktor * pow(2, octave - 5);
// Alternatively: Calculate 2 raised to a power using bit shifting
// frequency = faktor * (1 << (octave - 5));
// Return the note and frequency
return {noteName + String(octave), frequency};
}
// 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 keyboard() {
int frequ = 0;
int midiNummer;
for (uint8_t i = 0; i < 8; i++) {
if (digitalRead(buttonPins[i]) == LOW) { // if a button is pressed
if (i == 0) {
midiNummer = 60; // select Note to play and Frequency
frequ = 262;
}
if (i == 1) {
midiNummer = 62;
frequ = 294;
}
if (i == 2) {
midiNummer = 64;
frequ = 330;
}
if (i == 3) {
midiNummer = 65;
frequ = 349;
}
if (i == 4) {
midiNummer = 67;
frequ = 392;
}
if (i == 5) {
midiNummer = 69;
frequ = 440;
}
if (i == 6) {
midiNummer = 71;
frequ = 494;
}
if (i == 7) {
midiNummer = 72;
frequ = 523;
}
}
}
if (frequ) { // if Frequency =|= zero
if (!playing) { // and if we are not already playing
tone(SPEAKER_PIN, frequ); // send Frequency to Speaker pin
MIDI.sendNoteOn(midiNummer, 127, channel); // and send MIDI Signal
oledOut(String("Frequency: ") + frequ); // Show what happens on OLED
playing = true; // yes, we play
}
} else { // if Frequency is zero
if (playing) { // and if we are playing
noTone(SPEAKER_PIN); // stop Speaker
MIDI.sendNoteOn(midiNummer, 0, channel); // Stop MIDI Signal
oledOut("Push Encoder Button"); // Show what happens
oledOut2("or the keys"); // and what can be done
playing = false; // and remember nothing is plaid
}
}
}