Śledzenie Rytmu

W poprzednim numerze tego poradnika mieliśmy okazję zgłębiać bardzo techniczne tematy związane z systemem randomizacji, który jest fundamentalną częścią Sonic Pi. Dowiedzieliśmy się, w jaki sposób możemy użyć go, aby wynieść możliwość dynamicznej kontroli nad naszym kodem na zupełnie nowy poziom. W tym miesiącu zamierzamy kontynuować naszą techniczną wycieczkę i zwrócimy naszą uwagę ku unikalnemu systemowi tykania dostępnego w Sonic Pi. Pod koniec tego artykułu będziesz tykał po swojemu poprzez rytmy i riffy, aby stać się DJ’em kodującym na żywo.

Licznik Uderzeń

Podczas tworzenia muzyki często mamy ochotę na zrobienie czegoś innego, w zależności od którego uderzenia to jest. Sonic Pi posiada specjalny system liczenia uderzeń zwany tick. Daje on precyzyjną kontrolę podczas występowania uderzenia, a także i obsługuje wiele uderzeń mających własne tempa.

Zabawmy się - by przyspieszyć uderzanie, musimy tylko wezwać tick. Otwórz czysty bufor, by następnie wpisać poniższy fragment kodu i nacisnąć Run:

puts tick #=> 0

Spowoduje to zwrócenie aktualnego bitu: 0. Zauważ, że nawet gdy naciśniesz kilkukrotnie przycisk Run, to i tak zawsze zostanie zwrócona wartość 0. Dzieje się tak, ponieważ każde uruchomienie spowoduje, że bit zacznie być liczony od 0. Jednakże tak długo, jak nasza muzyka jest uruchomiona, możemy przechodzić do kolejnych uderzeń tak wiele razy, jak tylko chcemy:

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

W każdym miejscu, w którym zobaczysz symbol #=> na końcu danej linii kodu, oznacza to, że linia ta spowoduje zalogowanie tekstu po prawej stronie okna. Na przykład puts foo #=> 0 oznacza, iż kod puts foo wyświetli 0 w logach w danym punkcie programu.

Sprawdzanie Bitu

Widzieliśmy, że tickanie robi dwie rzeczy. Powiększa ono (dodaje jedno) i powraca do obecnego uderzenia. Czasami chcemy tylko spojrzeć na obecne uderzenia bez zwiększania ich ilości. Do tego zadania wykorzystamy polecenie look:

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

W tym kawałku kodu cykniemy nasz bit dwa razy, a następnie dwa razy uruchomimy polecenie look. W logu zobaczymy następujące wartości: 0, 1, 1, 1. Pierwsze dwa tyknięcia (wywołania polecenia tick) zwracają 0, potem 1 tak jak tego oczekujemy, a kolejne dwa polecenia look zwracają po prostu ostatnią wartość bitu dwa razy, co w tym przypadku oznacza 1.

Pierścienie

Teraz możemy więc zwiększać bit z wykorzystaniem polecenia tick i sprawdzać go z wykorzystaniem polecenia look? Co teraz? Potrzebujemy czegoś, przez co moglibyśmy tykać. Sonic Pi wykorzystuje pierścienie do reprezentacji riffów, melodii i rytmów, natomiast system tykania został zaprojektowany z myślą o ścisłej współpracy z nimi. W rzeczywistości pierścienie posiadają swoją własną kropkową wersję polecenia tick, która robi dwie rzeczy. Po pierwsze, zachowuje się tak jak normalne tykanie i powoduje podniesienie wartości aktualnego bitu. Po drugie, przeszukuje wartości pierścienia, wykorzystując dane tyknięcie bitu jako indeks. Spójrzmy na to:

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

Polecenie .tick to specjalna kropkowa wersja polecenia tick, która zwraca w tym przypadku pierwszą wartość z pierścienia - :a. Możemy dostać się do każdej z wartości w pierścieniu przez kilkukrotne wywołanie polecenia .tick:

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

Zwróć uwagę na log, a zauważysz, że zostały wypisane kolejno :a, :b, :c, a potem znowu :a. Zauważ, iż polecenie look zwraca wartość 3. Kolejne uruchomienia polecenia .tick zachowują się dokładnie tak samo jak normalne standardowe wywołania polecenia tick - zwiększają aktualną wartość dla lokalnego wskaźnika bitu.

Arpeggiator Żywej Pętli

Prawdziwą moc zobaczysz, gdy połączysz razem polecenie tick z pierścieniami (ring) i żywymi pętlami (live_loop). Gdy je połączymy, to mamy wszystkie narzędzia, które są potrzebne, aby zbudować i zrozumieć prosty arpeggiator. Potrzebujemy tylko czterech rzeczy:

  1. Pierścień zwracający nuty, przez które będziemy iterować.
  2. Środek, który pozwoli nam na inkrementację i dostęp do aktualnego licznika bitów.
  3. Zdolność do zagrania nuty na podstawie aktualnego bitu.
  4. Struktura pętli zachowująca powtarzanie arpegiatora.

Te pojęcia można znaleźć w poniższym kodzie:

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

Przyjrzyjmy się uważnie każdej z tych linii. Najpierw definiujemy pierścień z naszymi nutami, które będziemy grać w kółko. Następnie tworzymy żywą pętlę live_loop o nazwie :arp kręcącą się dla nas w kółko. Przy każdym kolejnym przebiegu naszej żywej pętli jako aktualny syntezator ustawiamy :dpulse, a następnie gramy kolejną nutę z naszego pierścienia, korzystając z polecenia .tick. Pamiętaj, że spowoduje to, iż nasz licznik bitów będzie się zwiększał i każde jego kolejne użycie będzie korzystało z ostatniego bitu jako indeksu do wyciągania nut z naszego pierścienia. Na koniec chcemy poczekać przez jedną ósmą uderzenia zanim rozpoczniemy kolejny przebieg żywej pętli.

Wielokrotne Równoczesne Uderzenia

Bardzo ważną rzeczą, którą warto wiedzieć, jest to, iż polecenia ticki są lokalne dla danej pętli live_loop. Oznacza to, iż każda żywa pętla live_loop posiada własny niezależny licznik uderzeń. Takie podejście daje o wiele więcej możliwości niż posiadanie jednego globalnego metronomu i bitu. Rzućmy okiem na to, jak to działa w praktyce:

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

Kolidujące Uderzenia

Duża przyczyna zamieszania z systemem cykania Sonic Pi jest wtedy, gdy ludzie chcą użyć go na wielu pierścieniach w tym samym 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

Nawet jeśli każda żywa pętla live_loop posiada swój własny niezależny licznik bitów, to wywołujemy polecenie .tick dwa razy w ramach tej samej żywej pętli. Ta informacja oznacza, że bit zostanie zwiększony dwa razy przy każdej rundzie. Może to spowodować pewne interesujące polirytmie, ale zazwyczaj nie jest to coś, czego byś oczekiwał. Istnieją dwa rozwiązania tego problemu. Pierwsza opcja to manualne uruchomianie polecenia tick na początku każdej żywej pętli live_loop, a następnie korzystanie z polecenia .look, aby odwołać się do aktualnego uderzenia w każdym przebiegu żywej pętli. Drugie rozwiązanie to przekazanie unikalnej nazwy do każdego wywołania polecenia .tick, na przykład .tick(:foo). Sonic Pi stworzy wtedy i będzie śledził oddzielny licznik bitów dla każdej użytej przez Ciebie z nazw. Tym sposobem masz możliwość pracy z tyloma licznikami uderzeń, z iloma będziesz tylko chciał. Aby dowiedzieć się więcej, zwróć uwagę na sekcję poświęconą nazwanym cyknięciom, która jest dostępna w puncie 9.4 samouczka wbudowanego w Sonic Pi.

Połączenie tego wszystkiego w jedną całość

Doprowadźmy tę całą wiedzę na temat tickania, ringów i live_loopów razem do ostatecznego przykładu zabawy. Jak przywykliśmy już do tego, nie traktuj tego jako gotowy kawałek - rozpocznij zmianę wielu rzeczy i baw się z nimi. Za pomocą swojej wyobraźni wyczaruj coś, co Cię zachwyci. Do zobaczenia następnym razem…

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