Tenere traccia del beat

Il mese scorso in questa serie abbiamo parlato in modo approfondito della casualità alla base di Sonic pi. Abbiamo capito come poterla sfruttare in modo deterministico per aggiungere nuovi livelli di controllo del nostro codice. Questo mese continueremo questa analisi approfondendo il sistema di tick di Sonic Pi. Alla fine di questo articolo utilizzerai i tick per i tuoi ritmi e nei tuoi riff per diventare un DJ live coder.

Contrare i battiti

Quando facciamo musica spesso vogliamo che accada qualcosa in base al beat in cui ci troviamo. Sonic Pi ha un sistema di conteggio chiamato tick per avere totale controllo di dove ci troviamo nella battuta e, ovviamente, supporta beat multipli ciascuno col suo tempo.

Diamoci da fare, per avanzare nel beat dobbiamo solo chiamare tick. Apriamo un buffer vuoto, scriviamo il seguente codice e premiamo su Run:

puts tick #=> 0

Ci verrà restituito il beat corrente, quindi 0. Nota come anche premendo Run più volte il risultato sarà sempre 0. Questo perché ad ogni avvio, il beat riparte da 0. Tuttavia, mentre Run è ancora attivo, possiamo avanzare nel beat tutte le volte che vogliamo:

puts tick #=> 0
puts tick #=> 1
puts tick #=> 2

Quando vedi il simbolo #=> alla fine di una riga vuol dire che quella linea di codice restituirà del testo nel log nella parte destra. Per esempio puts foo #=> 0 significa che il codice puts foo scriverà 0 nel log.

Controllare il beat

Abbiamo visto che tick fa due cose: incrementa di uno il beat e restituisce il valore corrente. A volte vogliamo solo vedere il valore corrente senza incrementalo. Possiamo farlo usando look:

puts tick #=> 0
puts tick #=> 1
puts look #=> 1
puts look #=> 1

In questo codice usiamo il tick per aumentare la pulsazione due volte e poi usiamo look, anch’esso due volte. Nel log vedremo questi valori: 0, 1, 1, 1. I primi due tick restituiscono 0 e 1 come ci aspettiamo i due look restituiscono l’ultimo valore due volte, ovvero 1.

Anelli

Quindi ora possiamo avanzare nel tempo con tick e controllare il beat con look. Cosa possiamo fare ancora? Dobbiamo avere qualcosa con cui usare tick. Sonic Pi utilizza gli anelli (ring) per rappresentare i riff, melodie e ritmi e il sistema dei tick è stato pensato per lavorare con essi. Di fatto gli anelli hanno la loro versione di tick che fa due cose. Innanzitutto funziona come un tick normale e incrementa il beat. In secondo luogo guarda il valore del ring utilizzano il valore del beat come indice. Diamo un’occhiata:

puts (ring :a, :b, :c).tick #=> :a

.tick è una versione speciale di tick che ritornerà il primo valore del ring :a. Possiamo prendere ciascun valore del ring chiamando .tick più volte:

puts (ring :a, :b, :c).tick #=> :a
puts (ring :a, :b, :c).tick #=> :b
puts (ring :a, :b, :c).tick #=> :c
puts (ring :a, :b, :c).tick #=> :a
puts look                   #=> 3

Prova a guarda il log e vedrai :a, :b, :c e poi di nuovo :a. Nota come look restituisce 3. Le chiamate a .tick funzionano come normali chiamate di tick, incrementano il beat locale.

Un arpeggiatore con Live Loop

La vera potenza viene fuori quando utilizziamo tick con ring e live_loop. Quando combiniamo queste cose abbiamo tutti gli strumenti per costruite un semplice arpeggiatore. Abbiamo bisogno di quattro cose:

  1. Un anello (ring) che contenga le note che vogliamo ripetere.
  2. Un mezzo per incrementare e ottenere il valore del beat.
  3. La possibilità di suonare una nota basata sul beat corrente.
  4. Una struttura di loop per continuare a ripetere l’arpeggiatore.

Tutti questi concetti possono essere ritrovati in questo codice:

notes = (ring 57, 62, 55, 59, 64)
live_loop :arp do
  use_synth :dpulse
  play notes.tick, release: 0.2
  sleep 0.125
end

Guardiamo ciascuna linea di codice. Per prima cosa definiamo un ring di note che continuerà a suonare. Dopodiché creiamo un live_loop chiamato :arp che continuerà a ripetersi. Ogni volta che si ripete il live_loop, impostiamo il synth per essere :dpulse e poi suonando la nota successiva usando .tick. Ricorda che questo incrementerà il nostro contatore di beat e userà l’ultimo valore di beat come indice nel nostro anello. Alla fine, aspettiamo per 1/8 di beat prima di ricominciare da capo.

Beat multipli simultanei

Una cosa importante da sapere è che i tick valgono localmente nel live_loop. Questo significa che ciascun live_loop ha il suo contatore beat indipendente. Questa cosa è molto più potente che avere un metronomo globale e un beat. Proviamo a vederlo in azione:

notes = (ring 57, 62, 55, 59, 64)
with_fx :reverb do
  live_loop :arp do
    use_synth :dpulse
    play notes.tick + 12, release: 0.1
    sleep 0.125
  end
end
live_loop :arp2 do
  use_synth :dsaw
  play notes.tick - 12, release: 0.2
  sleep 0.75
end

Scontri tra beat

Una cosa che causa confusione con il sistema di tick di Sonic Pi è che le persone vogliono utilizzare il tick in più ring nello stesso live_loop:

use_bpm 300
use_synth :blade
live_loop :foo do
  play (ring :e1, :e2, :e3).tick
  play (scale :e3, :minor_pentatonic).tick
  sleep 1
end

Anche se ciascun live_loop ha il suo beat counter indipendente, stiamo chiamando .tick due volte all’interno dello stesso live_loop. Questo significa che il beat verrà incrementato due volte ogni loop. Questo può generare dei poliritmi interessanti ma spesso non è quello che vogliamo. Ci sono due soluzioni per questo problema. Una è chiamare tickall’inizio del live_loop per poi usare .look per controllare il valore; la seconda è dare un nome a ogni chiamata .tick come, ad esempio .tick(:foo). Sonic Pi creerà e terrà traccia di un contatore di beat per ciascun nome che utilizzerai. In questo modo puoi lavorare con quanti beat tu voglia! Prova a vedere la sezione 9.4 dei tutorial per maggiori informazioni.

Mettiamo tutto insieme

Mettiamo insieme tutto quello che abbiamo imparato su tick, ring e live_loop per un ultimo esempio. Come al solito, non trattarlo come un pezzo finito. Prova a cambiare le cose e a giocare con questo codice per vedere cosa riesci a combinare. Alla prossima…

use_bpm 240
notes = (scale :e3, :minor_pentatonic).shuffle
live_loop :foo do
  use_synth :blade
  with_fx :reverb, reps: 8, room: 1 do
    tick
    co = (line 70, 130, steps: 32).tick(:cutoff)
    play (octs :e3, 3).look, cutoff: co, amp: 2
    play notes.look, amp: 4
    sleep 1
  end
end
live_loop :bar do
  tick
  sample :bd_ada if (spread 1, 4).look
  use_synth :tb303
  co = (line 70, 130, steps: 16).look
  r = (line 0.1, 0.5, steps: 64).mirror.look
  play notes.look, release: r, cutoff: co
  sleep 0.5
end