# MIDI in

In deze sectie zullen we leren hoe een MIDI controller events kan sturen naar Sonic Pi, om de synthesizer en geluiden te controleren. Gebruik een MIDI controller zoals een keyboard en steek de handen uit de mouwen!

## Verbinden van een MIDI Controller

Om informatie van een extern MIDI apparaat in te lezen in Sonic Pi zullen we eerst moeten verbinden met onze computer. Dit zal meestal gebeuren via een USB verbinding, alhoewel oudere apparatuur over een 5-pin DIN connector beschikt waarvoor extra computer hardware is benodigd (bijvoorbeeld een geluidskaart). Zodra het apparaat verbonden is kan Sonic Pi worden gestart en het IO venster in het Voorkeuren (‘Preferences’ panel) worden bekeken. Je apparaat zou daar zichtbaar moeten zijn. Indien dit niet het geval is kan geprobeerd worden de ‘Reset MIDI’ knop in te drukken. Indien hierna nog steeds niets gezien kan worden is controleren van de besturingssysteem MIDI configuratie, om te bekijken of hier het apparaat wel tussen staat. Indien dit allemaal niet werkt, voel je vrij om hulp te vragen op onze forums: https://in-thread.sonic-pi.net

## Ontvangen Van MIDI Events

Wanneer je apparaat verbonden is zal Sonic Pi automatisch events ontvangen. Je kunt dit zelf zien door het manipuleren van je MIDI apparaat en de ‘Cue’ logger rechts onderin het venster te bekijken (onder de log). Wanneer dit niet zichtbaar is kan naar Voorkeuren->Editor->Show & Hide genavigeerd worden, waar de ‘Show Cue Log’ checkbox ingeschakeld kan worden. Een opeenvolging van event zoals de volgende is zichtbaar:

    /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]

Als een opeenvolging van berichten zoals deze zichtbaar is, is het MIDI apparaat succesvol verbonden. Gefeliciteerd, laten wij is kijken wat we hiermee kunnen doen!

## MIDI Time State

Deze events kunnen worden gescheiden in twee secties. Enerzijds zijn de namen van events zoals `/midi:nanokey2_keyboard:0:1/note_on` zichtbaar, anderzijds zijn waarden van events zoals `[18, 62]` te zien. Deze twee zaken zijn benodigd om informatie op te slaan binnen Time State. Sonic Pi voert automatisch events afkomstig van MIDI in naar TIme State. Dit betekent dat de laatste MIDI waarden en eveneens `sync` wacht op de volgende MIDI waarde, zoals omschreven in sectie 10 van deze handleiding.

## Besturingscode

Nu een MIDI apparaat is verbonden, zijn diverse events zichtbaar in de `cue log` en kan worden herkend dat onze kennis van Time State alles is wat we nodig hebben om met de events te werken. Nu kunnen we plezier hebben en een eenvoudige MIDI piano maken:

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

Er gebeuren een aantal dingen in de bovenstaande code, waaronder een aantal problemen. Ten eerste beschikken we over een eenvoudige `live_loop` die voortdurend herhaald zal worden tussen de `do` en `end` blokken. Dit werd geïntroduceerd in sectie 9.2. Ten tweede roepen we `sync` aan om te wachten op het volgende matchende Time State event. We gebruiken een string waarde die het MIDI bericht representeerd waar wij op wachten (hetzelfde als in de `Cue Logger`). Merk op dat deze lange string geleverd wordt door Sonic Pi’s automatisch aanvullingen (autocomplete) systeem, waardoor het niet allemaal met de hand getypt hoeft te worden. In de log zagen wij dat er twee waarden voor iedere MIDI noot per event zichtbaar waren, het resultaat kan daarom gedeclareerd worden aan twee variabelen `note` en `velocity`. Tot slot kan de `:piano` synthesizer worden aangeroepen door onze noot.

Nu kun jij het proberen. Type in de bovenstaande code een sync key met een matchende string specifiek voor jouw MIDI apparaat en klik op Run. Nu heb je een werkende piano! Er zullen je echter een aantal problemen opvallen. Ten eerste zijn alle tonen hetzelfde volume ongeacht hoe hard jij op je keyboard drukt. Dit kan eenvoudig worden opgelost door deze `velocity` midi waarde te converteren naar een amplitude. Er is gegeven dat MIDI een bereik heeft van 0->127, om dit te converteren naar een waarde tussen 0 en 1 kan worden gedeeld door 127:

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

Update de code en klik opnieuw op Run. Nu zal de velocity van het keyboard worden gehonoreerd. We kunnen nu die irritante pauze oplossen.

## Verwijderen van Latency

Alvorens we de pauze kunnen verwijderen, moeten wij onderzoeken waarom deze hier is. Om alle synthesizers en effecten goed te timen tussen verschillende capabele processoren (CPU’s) maakt Sonic Pi gebruik van een vertraging van standaard 0.5s. (Merk op dat deze latency geconfigureerd kan worden middels de fns `set_sched_ahead_time!` en `use_sched_ahead_time`). Deze latency van 0.5s wordt toegevoegd aan onze `:piano` synthesizer triggers zoals bij alle synthesizers getriggerd via Sonic Pi. De motivatie voor deze latency is de garantie dat alle events goed worden getimed. Dit heeft alleen uitsluitend nut bij code die gebruik maakt van `play` en `sleep`. In dit geval triggeren wij de `:piano` synthesizer met een extern MIDI apparaat en willen we niet dat Sonic Pi deze timing bepaald voor ons. We kunnen deze latency uitschakelen middels het `use_real_time` commando, die de latency voor de huidige thread zal uitschakelen. Dit betekent dat een real-time mode voor live loops qua timing bestuurd zal worden via `sync`ing met externe apparaten en alle overige loops wel gewoon de standaard latency gebruiken. Laten we hier naar kijken:

    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

Update je code om te matchen met de bovenstaande code en druk opnieuw op Run. We hebben nu een piano met lage latency en variabele velocity gecodeerd in slechts 5 regels. Was dat niet makkelijk!

## Waarden Ophalen

Tot slot zullen onze MIDI events direct naar de Time State gaan, we kunnen eveneens gebruik maken van de `get` fn om de laatst gelezen waarde op te vragen. Dit zal niet de huidige thread blokkeren en geeft `nil` terug indien geen data gevonden kan worden (dit kan worden overschreven met een standaard waarde, zie de documentatie voor `get`). Herinner je dat de aanroep `get` in iedere thread iedere tijd mag plaatsvinden om de laatste matching Time State waarde op te vragen. Zelfs `time_warp` kan worden gebruikt om terug te gaan in de tijd en om via `get` events uit het verleden te bekijken…

## Nu heb jij de Besturing

Het leukste ding om nu te doen is het gebruik maken van code structuren om `sync` en `get` MIDI informatie van iedere MIDI apparaat op te halen. Je kunt nu kiezen wat je MIDI apparaat zal doen!