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!
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
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!
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.
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.
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!
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…
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!