In questa sezione impareremo a collegare un controller MIDI per mandare eventi a Sonic Pi per controllare i nostri synths e suoni. Procurati un controller MIDI come una tastiera o una superficie di controllo e andiamo sul fisico!
Per poter ricevere informazioni da un dispositivo MIDI esterno in Sonic Pi dobbiamo innanzitutto collegarlo al nostro computer. Tipicamente questo avviene via USB anche se dispositivi più vecchi possono avere il connettore DIN a 5 pin, per il quale servirà hardware specifico (ad esempio una scheda audio con connettori MIDI DIN). Una volta collegato il dispositivo, lancia Sonic Pi e controlla la sezione IO nel pannello preferenze. Dovresti vedere il tuo dispositivo elencato qui. Se non è così, prova a premere il tasto ‘Reset MIDI’ e controlla se compare. Se ancora non vedi la periferica, la prossima cosa da fare è controllare la configurazione MIDI del tuo sistema operativo e controllare se rileva il tuo dispositivo. Se nessuna di queste cose funziona, sentiti libero di chiedere aiuto nel nostro forum https://in-thread.sonic-pi.net
Una volta che il tuo dispositivo è connesso, Sonic Pi riceverà automaticamente gli eventi. Puoi vederlo da te manipolando il tuo dispositivo MIDI e controllando il cue logger nella sezione inferiore destra della finestra applicazione sotto il registro eventi (se non fosse visibile vai su Preferenze->Editor->Show & Hide e abilita ‘Show cue log’). Vedrai un flusso di eventi come:
/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]
Una volta che riesci a vedere un flusso di dati come questo significa che hai collegato correttamente la tua periferica MIDI. Congratulazioni, ora vediamo cosa ci puoi fare!
Questi eventi si dividono in due sezioni. Prima c’è il nome dell’evento come ad esempio /midi:nanokey2_keyboard:0:1/note_on
seguito dal valore degli eventi come ad esempio [18, 62]
. Nota interessante, queste sono le 2 cose di cui abbiamo bisogno per salvare le informazioni nel Time State. Sonic Pi inserisce automaticamente gli eventi MIDI in ingresso nel Time State. Questo significa che puoi ottenere il valore dell’ultimo evento MIDI e allo stesso tempo aspettare l’evento successivo usando quanto imparato nella sezione 10 di questo tutorial.
Ora che abbiamo connesso un dispositivo MIDI, visto gli eventi nel cue log e scoperto che la conoscenza del Time State è tutto ciò che ci serve per lavorare con gli eventi, possiamo ora cominciare a divertirci. Costruiamo un piano MIDI semplice:
live_loop :midi_piano do
note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
synth :piano, note: note
end
Ci sono alcune cose che succedono nel codice riportato sopra, inclusi alcuni problemi. Innanzitutto abbiamo un semplice live_loop
che si ripete all’infinito eseguendo il codice fra i blocchi do
/end
. Questo è stato introdotto nella sezione 9.2. Secondariamente, stiamo chiamando sync
per attendere il prossimo evento Time State corrispondente. Usiamo una stringa che rappresenta il messaggio MIDI che stiamo cercando (che è lo stesso mostrato nel cue logger). Nota che questa lunga stringa è fornita dal sistema di auto completamento di Sonic Pi, quindi non è necessario digitarla tutta a mano. Nel registro abbiamo visto che c’erano due valori per ogni evento MIDI note, quindi assegnamo il risultato a due diverse variabili note
e velocity
. Infine triggeriamo il synth :piano
passandogli la nostra nota.
Ora prova tu. Modifica il codice sopra, sostituisci la chiave sync con una stringa che corrisponda alla tua specifica periferica MIDI e premi Run. Hey presto, hai un piano funzionante! Tuttavia, probabilmente noterai un paio di problemi: primo, tutte le note escono allo stesso volume indipendentemente dalla forza applicata sulla tastiera. Questo può essere sistemato facilmente usando il valore MIDI velocity e convertendolo in amplitude. Dato che MIDI ha un intervallo di 0->127, per convertire questo numero in un valore compreso fra 0->1 dobbiamo dividerlo per 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
Aggiorna il codice e premi Run di nuovo. Ora la velocity della tastiera dovrebbe essere rispettata. Ora, liberiamoci di quella fastidiosa latenza.
Prima di poter rimuovere la latenza, dobbiamo capire da cosa è causata. Al fine di mantenere tutti i synth e gli effetti ben sincronizzati su tutte le possibili CPU e relative capacità, Sonic Pi programma l’audio in anticipo di 0.5 secondi come valore predefinito. (Notare che questa latenza aggiuntiva può essere configurata attraverso le funzioni set_sched_ahead_time!
e use_sched_ahead_time
). Questa latenza di 0.5s viene aggiunta al nostro synth :piano
perchè viene aggiunta a tutti i synth triggerati da Sonic Pi. Tipicamente desideriamo questa latenza perchè significa avere tutti i synth ben sincronizzati. Tuttavia questo ha senso solo per i synth gestiti a codice usando play
e sleep
. In questo caso stiamo triggerando il synth :piano
con un dispositivo MIDI esterno e di conseguenza non vogliamo che Sonic Pi controlli la sincronizzazione per noi. Possiamo spegnere questa latenza usando il comando use_real_time
che disabilita la latenza per il thread corrente. Questo significa che puoi usare il modo real time per i live loop che hanno la loro sincronizzazione controllata dai sync
con i dispositivi esterni e mantenere la latenza predefinita per tutti gli altri live loop. Vediamo:
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
Aggiorna il tuo codice per allinearlo al codice sopra e premi Run di nuovo. Ora abbiamo un piano a bassa latenza con velocity variabile codificato in appena 5 righe. Facile vero!
Finalmente, ora che i nostri eventi MIDI vanno dritti nel Time State, possiamo anche usare la funziona get
per recuperare l’ultimo messaggio passato. Questo non blocca il thread corrente e restituisce nil
se nessun valore viene trovato (cosa che può essere superata passando un valore di default - vedi la documentazione per get
). Ricorda che puoi chiamare get
in qualunque thread in qualunque momento per vedere l’ultimo evento corrispondente al valore nel Time State. Puoi anche usare time_warp
per tornare indietro nel tempo e chiamare get
per vedere gli eventi passati…
choose (scegli)