Quindi per il momento hai creato un ritmo coinvolgente e un basso che ti entra dentro. Come puoi fare a suonarli contemporaneamente? Una delle soluzioni è di intrecciarli a mano: suona un po’ di bassi, poi qualche colpo di batteria, poi ancora bassi…Tuttavia, la loro sincronizzazione può diventare presto difficile, specialmente quando cominci ad aggiungere numerosi elementi.
Che ne dici se Sonic Pi intrecciasse i vari strumenti per te, automaticamente? Bene, non ci crederai ma Sonic Pi può farlo per te! E lo può fare utilizzando una funzione speciale chiamata thread, ovvero tessitura.
Per fare un esempio semplice, devi immaginarti che il codice che segue sia un basso che pompa e un ritmo coinvolgente:
loop do
sample :drum_heavy_kick
sleep 1
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Come abbiamo detto in precedenza, gli anelli sono delle specie di buchi neri per il programma. Una volta che entri all’interno di un anello non puoi più uscirne finché non premi stop. Quindi, come facciamo a suonare entrambi gli anelli contemporaneamente? Dobbiamo dire a Sonic Pi che vogliamo iniziare diverse parti di codice nello stesso momento. Questo è quello che fa la funzione thread.
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Abbiamo messo all’interno di una struttura ‘in_thread’, composta da un blocco do/end, il primo anello. Questo comunica a Sonic Pi di eseguire il contenuto di questo blocco esattamente nello stesso momento del codice presente dopo il blocco (che in questo caso è il secondo anello). Prova a eseguirlo e potrai sentire sia la batteria sia il basso contemporaneamente!
Proviamo adesso a inserire un synth all’inizio:
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Ci ritroviamo con lo stesso problema di prima. Il primo anello è suonato contemporaneamente al secondo, grazie a ‘in_thread’. Però il terzo anello non viene mai eseguito. Dobbiamo quindi aggiungere un altro ‘filo’ al tessuto:
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
in_thread do
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Potrebbe sorprenderti il fatto che, quando premi il bottone ‘run’, in realtà stai creando un nuovo filo di codice da eseguire. Questo spiega perché quando premi il tasto più volte, il suono si sovrappone a quello che che è già in esecuzione. Visto che ogni esecuzione è un filo di codice, questi fili vengono intrecciati automaticamente.
Via via che scoprirai tutti i segreti di Sonic Pi, imparerai come questi ‘tessuti’ di suoni sono in realtà i mattoni principali con cui costruire la tua musica. Uno dei compiti principali di questi tessuti è quello di isolare la nozione di impostazioni correnti da quello degli altri orditi. Che cosa significa? Per esempio, quando associ un synth a un blocco utilizzando ‘use_synth’ stai associandolo soltanto a quel blocco e non ad altri. Vediamo un esempio:
play 50
sleep 1
in_thread do
use_synth :tb303
play 50
end
sleep 1
play 50
Hai sentito come il suono di mezzo era differente dagli altri? La funzione ‘use_synth’ aveva effetto soltanto sul blocco in cui era incluso e non sugli altri blocchi all’esterno.
Quando crei un nuovo filone, un nuovo ordito utilizzando ‘in_thread’, quest’ultimo erediterà automaticamente tutte le impostazioni correnti da quello precedente. Prova a dare un’occhiata qui:
use_synth :tb303
play 50
sleep 1
in_thread do
play 55
end
Hai visto che la seconda nota è suonata con il timbro del synth ‘:tb303’ nonostante questo appartenesse a un altro blocco? Qualsiasi impostazione che viene modificata utilizzando la stringa ‘use_*’ si comporterà nello stesso modo.
Quando i fili di codice vengono creati, ereditano tutte le impostazioni dai fili ‘genitori’, ovvero quelli che li hanno generati. Tuttavia, le modifiche effettuate nel codice ‘figlio’ non hanno nessun effetto sui ‘genitori’.
Per concludere, se vogliamo, possiamo dare dei nomi ai nostri fili di codice:
in_thread(name: :bass) do
loop do
use_synth :prophet
play chord(:e2, :m7).choose, release: 0.6
sleep 0.5
end
end
in_thread(name: :drums) do
loop do
sample :elec_snare
sleep 1
end
end
Dai uno sguardo alla sezione di destra quando esegui questo codice. Qui vengono visualizzati tutti i codici eseguiti. Vedi come questo ‘diario’ riporta il nome del filo da noi creato accoppiato con il messaggio?
[Run 36, Time 4.0, Thread :bass]
|- synth :prophet, {release: 0.6, note: 47}
Un’ultima cosa da sapere a proposito dei nomi è che non possono essere eseguiti due fili con lo stesso nome contemporaneamente. Proviamo a dare un’occhiata a questa caratteristica. Leggi il codice seguente:
in_thread do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Vai avanti e incollalo all’interno di una finestra e premi Run. Prova a premerlo ancora un paio di volte. Ascolta per un po’ la cacofonia creata da più campioni ‘amen_break’ che suonano contemporaneamente ma fuori tempo. Bene, adesso puoi premere stop.
Questo è il comportamento che abbiamo osservato numerose volte, ovvero: se premi Run, i suoni si sovrappongono agli altri già in esecuzione. Quindi, se hai un anello e premi Run tre volte, otterrai tre strati di suono che sono eseguiti contemporaneamente.
Con i fili ai quali è stato attribuito un nome, è tutta un’altra cosa:
in_thread(name: :amen) do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Prova a premere Run numerose volte inserendo questo codice. Potrai ascoltare un solo ‘amen_break’. Puoi verificare il perché leggendo nella finestra a destra:
Visualizzerai questo messaggio ==> Skipping thread creation: thread with name :amen already exists.
Sonic Pi, che parla inglese, ti sta dicendo che il filo di codice chiamato ‘:amen’ è già in esecuzione, quindi non ne può creare un altro.
Questo comportamento potrebbe non sembrarti particolarmente utile adesso, ma invece lo sarà quando cominceremo a fare live coding, ovvero a suonare dal vivo…