MIDI mit Arduino

MIDI ist ein Industriestandard für den Austausch musikalischer Steuerinformationen zwischen elektronischen Instrumenten, z.B. Keyboards oder Synthesizern. Mittlerweile ist man nicht mehr auf die 5-poligen MIDI-DIN-Stecker angewiesen sondern kann USB als alternativen Übertragungsweg verwenden. Dies macht den Arduino interessant als MIDI-Controller oder sogar MIDI-fähiges Gerät.

MIDI - Musical Instrument Digital Interface

Der Arduino kann über die seriellen Schnittstelle (USB) Daten an den angeschlossenen PC schicken. Diese können dann als MIDI-Befehle interpretiert werden. Dafür benötigt man eine spezielle Software, z.B. Hairless MIDI. Diese freie/kostenlose Software lädt man sich einfach herunter, packt das Archiv aus und startet die "hairless-midiserial.exe". In "File -> Preferences" muss noch die Baud-Rate auf dieselbe Übertragungsrate des Arduino-Sketches (hier: 9600) eingestellt werden. Nun wird in der Hauptoberfläche des Programms der serielle Port ein verfügbares "MIDI-Out"-Gerät.

Hauptoberfläche von Hairless MIDI
Abb.: Hauptoberfläche von Hairless MIDI

Ex. I: Arduino spielt Note

Verwendete Bauteile

Der folgende Sketch sendet der MIDI-Befehl zum spielen einer einzigen Note.
Wichtig beim Hochladen des Sketches ist, dass in Hairless MIDI der serielle Port deaktiviert ist. Nach dem Hochladen kann dieser dann wieder aktiviert werden.

byte noteON = 144; // note on command

void setup()
{
    // set "Hairless MIDI" to the same baud rate in the preferences
    Serial.begin(9600);
}

void loop()
{
    MIDImessage(noteON, 60, 100);   // turn note on
    delay(300);
    MIDImessage(noteON, 60, 0);     // turn note off (note on with velocity 0)
    delay(200);
}

void MIDImessage(byte command, byte data1, byte data2)
{
    Serial.write(command);
    Serial.write(data1);
    Serial.write(data2);
}
Video: Einzelne Note wird über Arduino -> Hairless MIDI am PC abgespielt.

Ex. II: Arduino spielt Notensequenz

Verwendete Bauteile

Der folgende Sketch lässt über den Arduino MIDI-Befehle für einen Akkord und eine Notensequenz abspielen.

byte noteON  = B10010000;
byte noteOFF = B10000000;

void setup()
{
    // set "Hairless MIDI" to the same baud rate in the preferences
    Serial.begin(9600);
}

void loop()
{
    MIDImessage(noteON, 60, 65);
    MIDImessage(noteON, 63, 65);
    MIDImessage(noteON, 67, 65);
    delay(500);

    MIDImessage(noteOFF, 60, 0);
    MIDImessage(noteON, 61, 65);
    delay(500);

    MIDImessage(noteOFF, 61, 0);
    MIDImessage(noteON, 60, 65);
    delay(500);

    MIDImessage(noteOFF, 60, 0);
    MIDImessage(noteON, 61, 65);
    delay(500);

    MIDImessage(noteOFF, 61, 0);
    MIDImessage(noteON, 60, 65);
    MIDImessage(noteOFF, 63, 0);
    MIDImessage(noteOFF, 67, 0);
    delay(1500);
}

void MIDImessage(byte command, byte data1, byte data2)
{
    Serial.write(command);
    Serial.write(data1);
    Serial.write(data2);
}

So (oder ähnlich) sollte sich das Resultat des obigen Sketches anhören:
(253kB)

Noten

In der MIDI-Spezifikation wird die Note mit der Nummer 60 (dezimal) als "mittleres C" (C4) angegeben, wobei alle anderen Noten dann relativ dazu eingegliedert werden. Die folgende Tabelle gibt die Notenwerten im Einzelnen an. Bei einigen MIDI-Geräten könnte es sein, dass die tiefste Oktave 0 ist, dann wäre das mittlere C dann ein C5. Die tiefste Note auf einem MIDI-Gerät ist jedoch immer ein C.

Oktave C C# D D# E F F# G G# A A# H
-101234567891011
0121314151617181920212223
1242526272829303132333435
2363738394041424344454647
3484950515253545556575859
4606162636465666768697071
5727374757677787980818283
6848586878889909192939495
796979899100101102103104105106107
8108108110111112113114115116117118119
9120121122123124125126127----

Ex. III: Arduino als Controller

Verwendete Bauteile

Der folgende Sketch steuert durch externe Bauteile (Mikrotaster und Potentiometer) das Verhalten des MIDI-Gerätes auf dem PC. In unserem Falle können wir mit dem Mikrotaster die Instrumente durchwählen, das eine Potentiometer steuert die Tonhöhe und das andere Potentiometer den Pitch der Note.

#define PIN_BUTTON               A5
#define PIN_POTENTIOMETER        A4
#define PIN_LINEAR_POTENTIOMETER A3

#define PHASE_PAUSE 0
#define PHASE_PLAY  1

const byte noteON        = B10010000;
const byte noteOFF       = B10000000;
const byte pitchBend     = B11100000;
const byte programChange = B11000000; // changing instrument

const byte noteVelocity = 65;
const int delayNote = 1000;
const int delayPause = 100;

const int potentiometerMaxValue = 675;

int value = 0, oldPitchValue = 0, oldNoteValue = 0;
bool buttonPressed = false;
byte currentNote = 0, currentInstrument = 1, currentPitch = 0, currentPhase = PHASE_PAUSE;
unsigned long lastPhaseChange = 0;

void setup()
{
    // set "Hairless MIDI" to the same baud rate in the preferences
    Serial.begin(9600);
    lastPhaseChange = millis();
}

void loop()
{
    value = analogRead(PIN_BUTTON);
    if (!buttonPressed && value < 10) {
        buttonPressed = true;
        currentInstrument++;
        if (currentInstrument>128) {
            currentInstrument = 1;
        }
        MIDImessage(programChange, currentInstrument, 255);
    }
    if (buttonPressed && value > 500) {
        buttonPressed = false;
    }

    value = analogRead(PIN_POTENTIOMETER);
    if (oldNoteValue!=value) {
        oldNoteValue = value;
        currentNote = map(value, 0, potentiometerMaxValue, 0, 127);
    }

    value = analogRead(PIN_LINEAR_POTENTIOMETER);
    if (oldPitchValue-2 > value || oldPitchValue+2 < value) {
        oldPitchValue = value;
        currentPitch = map(value, 0, potentiometerMaxValue, 0, 127);
        MIDImessage(pitchBend, 0, currentPitch);
    }

    switch(currentPhase) {
        case PHASE_PLAY:
            if (millis() > lastPhaseChange) {
                MIDImessage(noteON, currentNote, noteVelocity);
                lastPhaseChange = millis() + delayNote;
                currentPhase = PHASE_PAUSE;
            }
            break;
        case PHASE_PAUSE:
            if (millis() > lastPhaseChange) {
                MIDImessage(noteOFF, currentNote, 0);
                currentPhase = PHASE_PLAY;
                lastPhaseChange = millis() + delayPause;
            }
            break;
    }
}

void MIDImessage(byte command, byte data1, byte data2)
{
    Serial.write(command);
    if (data1 != 255) {
        Serial.write(data1);
    }
    if (data2 != 255) {
        Serial.write(data2);
    }
}
Video: Demo des Arduino-basierten MIDI-Controllers.

Weiterführendes

zurück