In episodul de luna trecuta am facut o incursiune tehnica in sistemul de randomizare din Sonic Pi. Am explorat cum il putem folosi pentru a adauga un nou nivel de control dinamic in codul nostru intr-un mod determinist. Luna asta vom continua sa studiem detaliile tehnice si ne vom indrepta atentia asupra sistemului de tact unic in Sonic Pi. La sfarsitul acestui articol vei putea sa urmaresti comanzi ritmurile si riff-urile si vei fi cu un pas mai aproape sa devii un DJ care programeaza live.
Cand facem muzica ne dorim adesea sa facem lucruri diferite in functie de masura la care am ajuns. Sonic Pi are un sistem special de contorizare a masurilor, numit ‘tick’, care iti ofera un control precis asupra momentului in care incepe masura si suporta chiar mai multe tempo-uri in paralel.
Sa ne jucam putin, pentru a trece la masura urmatoare trebuie doar sa apelezi ‘.tick’. Deschide un buffer nou si scrie codul de mai jos apoi apasa Run:
puts tick #=> 0
Va fi afisata masura curenta: ‘0’. Poti observa ca daca apesi pe Run de mai multe ori, de fiecare data va returna ‘0’. Asta se intampla deoarece la fiecare Run numaratoarea masurilor incepe de la 0. In timpul rularii insa, putem avansa la urmatoarea masura de cate ori vrem:
puts tick #=> 0
puts tick #=> 1
puts tick #=> 2
De cate ori observi simbolul ‘#=>’ la sfarsitul unei linii de cod, inseamna ca linia va determina scrierea in jurnal a partii care urmeaza. De exemplu, ‘puts foo#=> 0’ inseamna ca instructiunea ‘puts foo’ scrie ‘0’ in jurnal la acel punct din program.
Am vazut ca ‘tick’ face doua lucruri. Incrementeaza (creste cu 1) valoarea masurii curente si returneaza noua valoare. Uneori vrem doar sa vedem valoarea curenta, fara sa trecem la masura urmatoare, ceea ce poate fi realizat cu ajutorul ‘look’:
puts tick #=> 0
puts tick #=> 1
puts look #=> 1
puts look #=> 1
In acest cod generam un tact de 2 ori si afisam valoarea cu ‘.tick’, apoi doar analizam valoarea de 2 ori cu ‘.look’. Vom vedea urmatoarele valori: 0
, 1
, 1
, 1
. Primele 2 utilizari ale functiei ‘tick’ returneaza ‘0’ si apoi ‘1’, cum era de astepta, apoi cele 2 functii ‘look’ returneaza ultima valoare care este ‘1’.
Deci acum putem trece la masura urmatoare folosind ‘tick’ si sa vedem unde am ajuns folosind ‘look’. Ce urmeaza? Trebuie sa avem ceva ce poate fi parcurs pas cu pas. Sonic Pi foloseste liste circulare pentru a reprezenta riff-uri, melodii si ritmuri, iar sistemul de tact a fost gandit special pentru a lucra strans cu acestea. De fapt, listele circulare au propriile versiuni de tip sufix pentru functia ‘tick’, care realizeaza doua lucruri. In primul rand actioneaza ca un tick obisnuit si trec la masura urmatoare, iar in al doilea rand parcurg listele circulare folosind numarul masurii ca index. Sa aruncam o privire:
puts (ring :a, :b, :c).tick #=> :a
‘.tick’ este o versiune speciala de tip sufix a functiei ‘.tick’, care va returna prima valoare din lista ‘:a’. Putem obtine fiecare dintre valorile din lista apeland ‘.tick’ de mai multe ori:
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
Urmareste jurnalul si vei vedea :a
, :b
, :c
si iarasi :a
. Observi ca ‘look’ returneaza valoarea ‘3’. Apelurile ‘.tick’ functioneaza la fel ca cele ale functiei ‘tick’ obisnuite’ - incrementeaza numarul masurii curente.
Adevarata distractie incepe cand combinam ‘tick’ cu listele circulare si cu buclele live. Cand punem aceste lucruri impreuna avem tot ce ne trebuie pentru a construi si a intelege un generatori simplu de arpegii. Avem nevoie de doar patru lucruri:
Toate aceste concepte pot fi intalnite in codul urmator:
notes = (ring 57, 62, 55, 59, 64)
live_loop :arp do
use_synth :dpulse
play notes.tick, release: 0.2
sleep 0.125
end
Sa privim fiecare dintre aceste linii. Mai intai definim lista de note pe care le vom reda in continuu. Apoi cream o bucla live numita ‘:arp’ care se ocupa de repetarea instructiunilor pentru noi. De fiecare data cand intram in bucla algem sintetizatorul ‘:dpulse’ si apoi redam urmatoarea nota din lista cu ajutorul ‘.tick’. Tine minte ca acest lucru va duce la incrementarea numarului masurii curente si va folosi aceasta valoare ca index in lista cu notele. La final asteptam o optime de masura inainte de a relua bucla.
Un lucru important de stiut este ca tactul este local pentru o bucla live. Asta inseamna ca fiecare ‘live_loop’ are propriul contor pentru masura. Acest lucru ne ofera mai multa flexibilitate decat un metronom global si un tempo global. Sa vedem cum functioneaza:
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
O sursa de confuzii si erori in utilizarea sistemului de tact din Sonic Pi este folosirea unui tick pentru mai multe liste in acelasi ‘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
Fiecare ‘live_loop’ are propriul contor pentru masura, dar noi apelam ‘.tick’ de doua ori in cadrul aceleiasi bucle. Asta inseamna ca numarul masurii curente va fi incrementat de doua ori la fiecare trecere. Uneori pot aparea sunete poliritmice interesante, dar nu asta ne dorim in general. Exista doua solutii pentru aceasta problema. O varianta ar fi sa apelam ‘tick’ la inceputul buclei live si apoi sa folosim ‘look’ pentru a vedea care este valoarea curenta. A doua ar fi sa transmitem un nume unic la fiecare dintre cele 2 apeluri ale functiei ‘.tick’, cum ar fi ‘.tick(:foo)’. Sonic Pi va crea si va urmari un contor separat pentru fiecare nume pe care il folosesti. In felul asta poti lucra cu oricate tacturi ai nevoie. Vezi sectiunea 9.4 din tutorial pentru mai multe informatii despre folosirea de nume pentru tacturi.
Sa punem cap la cap cunostintele noastre despre tact, liste circulare si bucle live pentru un exemplu final. Ca de obicei, nu trebuie sa tratezi asta ca pe o bucata finisata. Poti schimba ce doresti ca sa vezi in ce o poti transforma. Ne vedem data viitoare…
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