Catene

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.

Anelli infiniti

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.

La funzione thread viene a salvarci dai buchi neri

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

Avvii come ulteriori fili aggiunti al tessuto sonoro

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.

Influenza del codice

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.

Ereditarietà

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’.

Dare un nome ai diversi fili

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 nome può essere attribuito a un solo filo

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…