Home    | Software    | Articoli    | Tips'n Tricks    | Contattaci    | Supportaci  
Home arrow Articoli arrow Musica al Computer - Chuck in azione (I)

Musica al Computer - Chuck in azione (I)


Costruiamo un arpeggiatore MIDI

 

Introduzione


ChucK  è , come indicato sul suo sito," un linguaggio di programmazione audio per sintesi , composizione, ed esecuzione  in tempo reale - pienamente supportato su MacOSX, Windows e Linux. ChucK presenta nuovo modello di programmazione bassato sul tempo e concorrente altamente preciso ed espressivo (lo chiamiamo fortemente-temporizzato), un buon livello di controllo dinamico, e l'abilità di aggiungere e modificare al volo. In più, ChucK supporta dispositivi MIDI, OSC, HID, e audio multi canale."

ChucK è estremamente votato alla sperimentazione con sintesi audio e MIDI, ma anche uno strumento potente per  esecuzioni dal vivo.  Questo articolo è un'introduzione all'utilizzo di questo incredibile mezzo e alla sua semplicità di apprendimento. Per provare tutto ciò svilupperemo un semplice arpeggiatore MIDI in poche righe di codice. Lo scopo della serie completa di articoli sarà di costruire una sorta di piattaforma da utilizzare dal vivo o per sperimentazione. 

Prima di iniziare

Dò per scontato che ChucK sia già installato, non importa se da binari o sorgente e che sia già stato testato con uno degli esempi inclusi nella distribuzione. Una nota; lavoro su Linux per cui la sezione seguente circa gli strumenti da usare è un pò specifica per il sistema operativo. Gli utenti Windows/MacOSX non si preoccupino, perchè ChucK è pienamente compatibile con i loro sistemi, e il resto dell'articolo è indipendente dalla piattaforma.

Configurazione suggerita per utenti Linux  (ma per favore leggetela comunque)

 

Utilizzeremo una configurazione software molto semplice. Suggerisco fortemente di usare Jack su alsa, e detto ciò ecco cosa ci serve:

  • Jack (ChucK supporta oss e alsa)
  • qjackctl, un'interfaccia grafica per controllare Jack
  • ChucK, ovviamente, compilato per il vostro sistema audio
  • un sintetizzatore software con supporto MIDI (ZynAddSubFx è favoloso, soprattutto per sperimentare)
  • A tastiera MIDI virtuale (vkeybd ad esempio)

Se già fate musica al computer probabilmente avrete già tutti questi strumenti(e molti altri). Queli suggeriti sono disponibili sulla maggior parte delle distribuzioni Linux senza dover compilare nulla. Naturalmente, se avete esperienza potete usare i software che più vi aggradino, io dò solo alcune linee guida per aiutare i meno esperti. 

Ora, lanciate qjackctl, zynaddsubfx e vkeybd.
Il prossimo passo è di lanciare la macchina virtuale (VM) di ChucK. Da riga di comando:


chuck --loop &

Questo istanzierà la VM e la metterà in attesa di comandi. I successivi comandi verranno eseguiti sulla VM attiva.

 

C'è ancora una cosa da fare, connettere l'uscita audio di ZynAddSubFX al nostro dispositivo alsa_pcm (se non lo è già). Lo facciamo dal pannello "Connection" di qjackctl che, fatto ciò, apparirà più o meno così: 


qjackctl after modification

dove:

  • alsa_pcm sul pannello a sinistra è il nostro dispositivo di ingresso, ad es. un microfono(ignoriamolo per ora)
  • alsa_pcm sul pannello a destra è il nostro dispositivo di uscita(altoparlanti o cuffie)
  • RtApiJack sul lpannello a sinistra è la porta di ingresso di ChucK
  • RtApiJack sul pannello a detra è la porta di uscita di ChucK
  • ZynAddSubFX sul pannello di sinistra è la porta di uscita del nostro sintetizzatore software

 

Scriviamo del codice

ChucK  è un linguaggio orientato agli oggetti, ed include molti utili oggetti pronti da impiegare. Dobbiamo costruire un arpeggiatore MIDI, per cui i primi oggetti che ci servono sono relativi al MIDI. Il comportamento del nostro arpeggiatore sarà il seguente: alla pressione di un tasto sulla tastiera midi, il corrispondente evento midi(note-on) verrà catturato dal programma, che comporrà un arpeggio (utilizando una lista di differenze tonali). La sequenza di note creata verrà rediretta al sintetizzatore software per essere suonata. Cercherò di mantenere il codice il più semplice possibile per focalizzarci solo sui concetti cardine. Apriamo il nostro editor di testo preferito, o lo sperimentale miniAudicle(reperibile dal sito di ChucK) ed iniziamo a scrivere codice:


MidiIn min;
MidiOut mout;
MidiMsg msg;

                
 

Abbiamo appena definito un dispositivo MIDI di ingresso(min), uno di uscita(mout) ed un oggetto messagio MIDI (msg). Ora dobbiamo "aprire" il nostro dispositivo MIDI,mediante il metodo open , che accetta come argomento un numero di dispositivo. Per conoscere il numero di dispositivo che ci interessa, sulla riga di comando scriviamo:

    chuck --probe

Nel mio caso otterrò come risultato:

[chuck]: ------( chuck -- 2 MIDI inputs )------
[chuck]: [0] : "Midi Through Port-0"
[chuck]: [1] : "Virtual Keyboard"
[chuck]:
[chuck]: ------( chuck -- 2 MIDI outputs )-----
[chuck]: [0] : "Midi Through Port-0"
[chuck]: [1] : "ZynAddSubFX"

                 
 

 I numeri in parentesi quadre sono esattamente quello di cui abbiamo bisogno. Quindi il mio dispositivo MIDI di ingresso , "Virtual Keyboard", ha indicativo "1", idem per il mio dispositivo MIDI di uscita "ZunAddSubFX". A questo punto le prossime rige di codice:


min.open(1);
mout.open(1);

                        
 
Sarebbe bene gestire eventuali errori qui ma, come scritto in precedenza, per ora ignoriamo tutto ciò che non sia vitale.

Ora che i nostri canali MIDI sono aperti, dobbiamo gestire i messaggi in arrivo dal nostro dispositivo MIDI  di ingresso (nel nostro caso la tastiera virtuale).Faremo partire un ciclo infinito che attenda messaggi in ingresso, li processi e torni in attesa indefinitamente.


while(true){
min => now;
min.recv(msg);
if(msg.data1 == 144){
spork ~ arpeggio(msg);
}
}

                    
 
La parte "while(true)" è il nostro ciclo condizionale. Per i programmatori non esperti, il ciclo while significa "ripeti ciò che è tra parentesi graffe finchè la condizione rimane rispettata. In questo caso la condizione èp semplicamente vera(true), quindi il ciclo sarà infinito."
Riguardo la prima riga del ciclo: 
     min => now;
necessita un minimo di spiegazione. La parola chiave now è speciale in ChucK. E' una variabile temporale, se modificate avanzerà il tempo di ChucK, quando letta restituirà il tempo corrente di ChucK. 
L'operatore "=>" è onnipresente in ChucK, e può servire a vari scopi a seconda dei suoi operandi. Può servire per assegnare valori, connettere oggetti, effettuare operazioni aritmetiche etc.
Detto ciò, cosa fa la nostra riga di codice? Attenderà un evento MIDI in arrivo dal dispositivo "min". In questo caso "now" è utilizzato per sospendere il ciclo finchè uno specifico evento MIDI si verifichi. Criptico? Non peroccupatevi, l'utilizzo è più semplice della spiegazione.
A questo punto, un evento MIDI raggiunge il dispositivo "min", e ciò significa ad esempio che sulla tastiera midi è stato premuto un tasto.
Riceviamo l'evento e, mediante il metodo recv del dispositivo MidiIn, lo salviamo nel nostro oggetto messaggio MIDI (msg).
Il nostro messaggio conterrà alcuni dati. Le proprietà dell'oggetto MidiMsg con le quali avremo a che fare sono: 
  • data1 - il tipo di evento MIDI
  • data2 - il numero della nota
  • data3 - l'espressività (velocity)
Nell'istruzione "if" ci interessa data1 , dato che dobbiamo gestire solo eventi "KeyOn". Questo perchè un evento MIDI viene generato sia alla pressione sia al rilascio di un tasto. Il numero di evento per la pressione di un tasto è 144, quindi verifichiamo che l'evento ricevuto sia realmente un NoteOn. Se è così possiamo lanciare un nuovo processo. Questo è il significato della linea:
     spork ~ arpeggio(msg);
La parola chiave spork si usa per lanciare un processo all'interno di una VM ChucK attiva. Questi processi si chiamano "shreds".
Il nuovo processo eseguirà una funzione chiamata "arpeggio" (che scriveremo ora), passandole come argomento l'oggetto MidiMsg che contiene i dati ricevuti.
L'uso degli shreds è giustificato dal fatto che abbiamo bisogno di agire in modalità non bloccante. Per spiegarmi meglio:
nel ciclo "while" ,se operiamo in maniera sincrona, alla pressione di un tasto, dovremmo attendere la fine dell'arpeggio prima di poter premere un altro tasto. Lanciando invece l'arpeggio in un processo a parte, asincrono, questo procederà indipendentemente dal ciclo principale quindi, ad esempio, se premessimo un altro tasto mentre l'arpeggio viene eseguito, un nuovo arpeggio verrebbe lanciato in un nuovo processo, consentendoci di udire tutti e due gli arpeggi contemporaneamente. 
 

Bene, abbiamo trattato alcuni concetti base di ChucK.
Ora ci serve una funzione che crei l'effetto di arpeggio, iniziando dalla nota MIDI suonata sulla tastiera e seguendo una progressione di note pre-definite. 

Ecco la nostra funzione:


01: fun void arpeggio(MidiMsg mymsg){
02: MidiMsg message;
03: mymsg.data1 => message.data1;
04: mymsg.data2 => message.data2;
05: mymsg.data3 => message.data3;
06:
07: [0,4,3,4,5,-5,-4,-3] @=> int scale[];
08: for ( 0 => int i; i < scale.cap(); i++){
09: 144 => message.data1;
10: scale[i] +=> message.data2;
11: mout.send(message);
12: 300::ms => now;
13: 128 => message.data1;
14: mout.send(message);
15: }
16: }

                               
 
Notate che i numeri di riga non sono parte del codice; li ho aggiunti per facilitare la spiegazione. 
Sulla riga 1 definiamo una funzione con nome "arpeggio", che ritorni niente(void) e accetti in ingresso oggetti MidiMsg.
Sulle righe 2-5 definiamo un oggetto MidiMsg locale al quale assegnamo i dati del MidiMsg originale, per evitare interferenze con l'oggetto in ingresso.

Poi, alla riga 7 creaiamo una sequenza di interi e assegnamo i valori indicati tra parentesi quadre. Questi altro non sono se non intervalli (distanze tra due note). Chiariamo il concetto:
abbiamo precedentemente visto che la proprietà data2 di MidiMsg contiene il numero della nota. In questa notazione, le note sono divise in semi-toni, quindi aggiungendo 1 ad una nota si ottiene un'altra nota di un semi-tono più alta, aggiungendo 2 si alza di un tono e così via.
Quindi, nella nostra sequenza avremo: nota originale(+0), nota originale + 2 toni (+4), nota originale + 3 toni e mezzo (+4 +3 = +7) etc. 
L'effeto sarà una progressione di nota verso l'alto e poi  ritorno .
Il ciclo for  alla linea 8 serve ad iterare lungo la sequenza (scale.cap() contiene il numero di elementi della sequenza),così che il codice racchiuso tra parentesi graffe venga eseguito per ogni elemento della sequenza. Vediamone nel dettaglio il codice:
Alla riga 9 fisiamo un evento MIDI 144 (NoteOn) per "attivare" il volume della nota(renderla udibile)
Alla riga 10 aggiungiamo ("+=>") al valore originale della nota il valore della sequenza indicato dall'indice(0 la prima volta, 4 la seconda,........., -3 l'ultima)
Alla riga 11 inviamo (send) il MidiMsg con il nuovo valore al nostro dispositivo MidiOut (mout), in modo che la nota venga realmente suonata
Alla riga 12  aspettiamo 300 millisecondi per permettere una durata della nota
Alla riga 13 cambiamo l'evento MIDI a 128 (noteOff)
Alla riga 14 inviamo ancora il MidiMsg again a mout. Questa volta l'evento NoteOff interromperà la nota

e così via finchè  tutta la progressione non sarà stata eseguita.
 
Ora salviamo il file appena editato con un nome, es. "arpeggio.ck", e a riga di comando inseriamo: 

   chuck + percorso_del_file/arpeggio.ck
 
Se tutto è configurato bene, vedremo qualcosa tipo:
[chuck](VM): sporking incoming shred: 1 (arpeggiator.ck)...

                        
 
e premendo un tasto sulla tastiera virtuale dovremmo sentire un arpeggio eseguito dal dispositivo midi di uscita (ZynSuAddFX nel nostro caso).

Una lunga spiegazione per un esempio piuttosto semplice, ma mi piace considerare questa come una immersione in ChucK. Semplicemente giocando con questo esempio sono sicuro che rimarrete meravigliati dall'estensione di possibilità applicative sviluppabili con questo linguaggio/piattaforma.

Fino al prossimo articolo... 

 

 
< Prec.   Pros. >

  Articles RSS feed

Articoli pił recenti
Software pił recenti
   
designed by allmambo.com