11.1 MIDI In

# MIDI In

In diesem Abschnitt werden wir lernen einen MIDI-Controller anzuschließen, um Ereignisse an Sonic Pi zu senden, mit denen unsere Synths und Klänge steuern. Besorge dir einen MIDI-Controller, wie z. B. ein Keyboard oder eine Controller-Oberfläche und lass uns handgreiflich werden!


## MIDI-Controller verbinden

Um Informationen von einem externen MIDI-Gerät in Sonic Pi zu bekommen müssen wir es zunächst an unseren Computer anschließen. Normalerweise wird das mittels einer USB-Verbindung sein, ältere Geräte hingegen haben einen 5-Pol-DIN-Stecker für den du Hardwareunterstützung in deinem Computer brauchst (manche Audio-Interfaces bzw. Soundkarten haben MIDI-DIN-Stecker). Nachdem du dein Gerät angeschlossen hast, starte Sonic Pi und wirf einen Blick auf den I/O-Bereich in den Einstellungen. Du solltest dein Gerät dort aufgelistet finden. Falls nicht, klicke auf 'MIDI zurücksetzen' und sieh nach, ob es auftaucht. Wenn du immer noch keinen Eintrag in der Liste findest, ist der nächste Schritt zu versuchen in der MIDI-Konfiguration deines Betriebssystems nachzusehen, um zu sehen ob dein Gerät erkannt wird. Wenn das alles fehlschlägt, kannst du gerne in unserem freundlichen öffentlichen Forum Fragen dazu stellen: https://in-thread.sonic-pi.net

## MIDI-Ereignisse empfangen

Sobald dein Gerät verbunden ist, wird Sonic Pi automatisch Ereignisse empfangen. Du kannst das selbst nachprüfen indem du dein MIDI-Gerät bedienst und auf das Cue-Protokoll unten rechts im Anwendungsfenster unterhalb des Protokolls schaust (falls es nicht sichtbar ist, gehe zu Einstellungen->Editor->Ein-/Ausblenden und aktiviere 'Zeige Cue-Protokoll'). Du wirst einen Datenstrom von Ereignissen sehen wie:

```
/midi:nanokey2_keyboard:0:1/note_off  [55, 64]
/midi:nanokey2_keyboard:0:1/note_on   [53, 102]
/midi:nanokey2_keyboard:0:1/note_off  [57, 64]
/midi:nanokey2_keyboard:0:1/note_off  [53, 64]
/midi:nanokey2_keyboard:0:1/note_on   [57, 87]
/midi:nanokey2_keyboard:0:1/note_on   [55, 81]
/midi:nanokey2_keyboard:0:1/note_on   [53, 96]
/midi:nanokey2_keyboard:0:1/note_off  [55, 64]
```

Wenn du einen Strom von Signalen wie diesen siehst, hast du dein MIDI-Gerät erfolgreich verbunden. Glückwunsch, lass uns schauen, was wir damit machen können!

## MIDI-Time-State

Diese Ereignisse sind in zwei Abschnitte unterteilt. Als Erstes steht da der Name des Ereignisses, wie z. B. `/midi:nanokey2_keyboard:0:1/note_on` und zum Zweiten gibt es die Werte des Ereignisses wie z. B. `[18, 62]`. Interessanterweise sind das die zwei Dinge, die wir brauchen, um Ereignisse in Time-State zu speichern. *Sonic Pi fügt eingehende MIDI-Ereignisse automatisch in Time-State ein*. Das bedeutet du kannst auf den letzten MIDI -Wert mit `get` zugreifen, und auch mit `sync` auf den nächsten MIDI-Wert warten - dabei kannst du alles anwenden, was wir in Abschnitt 10 dieses Tutorials gelernt haben.

## Programm-Code steuern

Nachdem wir jetzt ein MIDI-Gerät verbunden haben, dessen Ereignisse im Cue-Protokoll sehen konnten und wissen, dass unsere Kenntnisse über Time-State alles sind, was wir zum Arbeiten mit Ereignissen brauchen - können wir jetzt anfangen Spaß zu haben. Lass uns ein einfaches MIDI-Piano bauen:

```
live_loop :midi_piano do
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note
end
```

Es passieren einige Dinge im obigen Code, einschließlich einiger Probleme. Zunächst haben wir da einen einfachen `live_loop`, der den Code zwischen dem `do`/`end` Block unendlich wiederholt. Das wurde im Abschnitt 9.2 behandelt. Danach rufen wir `sync` auf, um auf das nächste Time-State-Ereignis zu warten. Wir benutzen eine Zeichenkette, die das MIDI-Signal repräsentiert, nach dem wir suchen (es ist dasselbe, das uns im Cue-Protokoll angezeigt wurde). Achte darauf, wie dir Sonic Pi die vollständige Zeichenkette mit seinem Autovervollständigungssystem erstellt, sodass du sie nicht komplett von Hand eintippen musst. Im Protokoll haben wir gesehen, dass es zwei Werte für jedes MIDI-Note-on-Ereignis gab, also weisen wir das Ergebnis zwei separaten Variablen `note` und `velocity` zu. Schließlich triggern wir den `:piano`-Synth und übergeben unsere Note.

Jetzt probiere du es. Gib den obigen Programm-Code ein, ersetzte in sync den Schlüssel mit einer Zeichenkette, die zu deinem spezifischen MIDI-Gerät passt und klicke auf Ausführen. Hey, und schon hast du ein funktionierendes Klavier! Wahrscheinlich fallen dir jedoch ein paar Probleme auf: Unabhängig davon wie stark du die Tasten anschlägst, klingen die Noten immer gleich laut. Das lässt sich leicht dadurch beheben, dass wir den MIDI-Wert für Velocity (Anschlagstärke) nutzen und zu Lautstärke wandeln. Da MIDI einen Wertebereich von 0-127 hat, müssen wir diese Zahl in einen Wert zwischen 0->1 zu konvertieren, indem wir sie einfach durch 127 teilen:

```
live_loop :midi_piano do
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end
```

Aktualisiere deinen Code und klicke nochmals auf Ausführen. Jetzt wird der Anschlagstärke des Keyboards berücksichtigt. Als nächstes lass uns diese nervige Pause loswerden.

## Latenz entfernen

Bevor wir die Pause entfernen können, müssen wir herausfinden, warum sie da ist. Um alle Synths und Effekte auf einer Vielzahl von unterschiedlich starken CPUs gut getaktet zu halten, setzt Sonic Pi Audio-Ereignisse standardmäßig 0,5 Sekunden *im Voraus* an. (Beachte, dass diese zusätzliche Latenz über die Funktionen `set_sched_ahead_time!` und `use_sched_ahead_time` konfiguriert werden kann). Diese 0,5 Sekunden Latenz werden zu unseren `:piano` Synth-Triggern hinzugefügt, so wie bei allen Synths, die von Sonic Pi getriggert werden. Typischerweise wollen wir diese hinzugefügte Latenz, weil sie bedeutet, dass alle Synths gut getaktet laufen werden. Das ergibt jedoch nur Sinn bei Synths, die von Programm-Code durch `play` und `sleep` getriggert werden. In diesem Fall triggern wir den `:piano`-Synth jedoch tatsächlich mit unserem externen MIDI-Gerät und möchten daher nicht, dass Sonic Pi das Timing für uns steuert. Wir können diese Latenz mit dem Befehl `use_real_time` ausschalten, der für den aktuellen Thread die Latenz ausschaltet. Das bedeutet, dass du den Echtzeitmodus `use_real_time` für Live-Loops verwenden kannst, die ihr Timing mittels `sync` mit externen Geräten synchronisieren, und für alle anderen Live-Loops die normale Latenz behalten kannst. Lass mal sehen:

```
live_loop :midi_piano do
  use_real_time
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end
```

Passe deinen Code entsprechend dem obigen Code an und klicke nochmals auf Ausführen. Jetzt haben wir ein Piano mit niedriger Latenz und variabler Anschlagstärke mit nur 5 Zeilen programmiert. Wenn das nicht einfach war!

## Werte erhalten

Schließlich, da unsere MIDI-Ereignisse direkt in den Time-State gehen, können wir die `get`-Funktion benutzen, um den letzten gesehenen Wert zu erhalten. Dies blockiert nicht den aktuellen Thread und gibt `nil` zurück, wenn es keinen Wert gibt (was du überschreiben kannst, indem du einen Standardwert übergibst - sieh dir dafür die Dokumentation für `get` an). Erinnere dich, dass du `get` in jedem Thread und zu jeder Zeit aufrufen kannst, um den letzten passenden Time-State-Wert zu erhalten. Du kannst sogar `time_warp` benutzen, um in der Zeit zurück zu springen und mit `get` vergangene Events angezeigt zu bekommen ...


## Jetzt hast du die Kontrolle

Das eigentlich Aufregende ist, dass du dieselben Code-Strukturen verwenden kannst, um mittels `sync` und `get` MIDI-Informationen mit jedem beliebigen MIDI-Gerät zu synchronisieren und du mit diesen Werten tun kannst, was du willst. Jetzt kannst du entscheiden, was dein MIDI-Gerät tun wird!
