# Wątki

A więc udało Ci się przygotować zabójczy bassline oraz tłusty beat. W jaki sposób możesz zagrać je w tym samym czasie? Jednym z możliwych rozwiązań jest przeplecenie ich razem ręcznie - najpierw zagrać jakiś bas, potem trochę bębnów, potem znowu bas… Jednakże bardzo szybko chronometraż stanie się czymś, o czym będzie ciężko myśleć, zwłaszcza kiedy zaczniemy wplatać do naszej kompozycji kolejne elementy.

A co, jeśli Sonic Pi mógłby przeplatać różne elementy za Ciebie automagicznie? Takie coś jest możliwe i możesz to robić, używając specjalnego polecenia nazywanego wątkiem - thread.

## Nieskończone Pętle

Aby sprawić, by kolejny przykład był prosty, musisz sobie wyobrazić, jak wygląda ten tłusty beat i zabójczy bassline:

    loop do
      sample :drum_heavy_kick
      sleep 1
    end
    loop do
      use_synth :fm
      play 40, release: 0.2
      sleep 0.5
    end

Jak już wcześniej mówiliśmy, pętle są jak czarne dziury dla naszych programów. Gdy już raz wejdziesz do pętli, nie wyjdziesz z niej nigdy, chyba że naciśniesz przycisk Stop. W jaki zatem sposób możemy zagrać obie pętle jednocześnie? Musimy powiedzieć Sonic Pi, że chcemy rozpocząć coś w tym samym czasie, gdy uruchamiamy pozostały kod. To jest właśnie moment, w którym z pomocą przychodzą nam Wątki (ang. threads).

## Wątki na Ratunek

    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

Jeśli otoczymy pierwszą pętlę blokiem kodu do/end `in_thread`, to w ten sposób powiemy Sonic Pi, żeby uruchomił zawartość tego bloku do/end dokładnie w tym samym czasie, gdy zostają uruchomione kolejne polecenia znajdujące się tuż za blokiem kodu (w tym przypadku jest to druga pętla). Spróbuj uruchomić ten kod, a usłysz jednocześnie bębny oraz bassline, które są przeplecione i grają jednocześnie!

A co teraz, jeśli chcielibyśmy dodać jeszcze jakiś syntezator (synth)? Coś w tym stylu:

    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

Znowu mamy taki sam problem, jak przed chwilą. Pierwsza pętla jest uruchomiona w tym samym momencie co druga pętla, ze względu na to, że użyliśmy polecenia `in_thread`. Jednakże trzecia pętla nigdy nie zostaje uruchomiona. Żeby to naprawić, potrzebujemy kolejnego wątku (thread):

    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

## Uruchamianie w Wątkach

Coś, co może być dla Ciebie zaskakujące, to fakt, że gdy naciskasz przycisk Uruchom, to w rzeczywistości tworzysz nowy wątek do uruchomienia Twojego kodu. Dlatego też, gdy klikniesz ten element wiele razy, dźwięki zaczną nakładać się na siebie. Jako że kolejne uruchomienia same są po prostu wątkami, to dźwięki zostaną dla Ciebie automatycznie poprzeplatane.

## Zasięg

Gdy już nauczysz się, w jaki sposób opanować Sonic Pi, zdobędziesz wiedzę na temat również tego, że wątki są jednym z najważniejszych materiałów używanych do tworzenia Twojej muzyki. Jednym z ważnych zadań, które do nich należą, to izolacja pojęcia aktualnych ustawień od innych wątków. Co to oznacza? Otóż, kiedy zmieniasz syntezatory poleceniem `use_synth`, w rzeczywistości po prostu zmieniasz syntezator dla aktualnego wątku (current thread) - w żadnym innym wątku syntezator się nie zmieni. Zobaczmy te zachowanie w akcji:

    play 50
    sleep 1
    in_thread do
      use_synth :tb303
      play 50
    end
    sleep 1
    play 50

Zauważyłeś, że środkowy dźwięk był inny od pozostałych? Polecenie `use_synth` wpłynęło tylko na to, co zostało uruchomione w wątku, natomiast pozostała, zewnętrzna część kodu została nietknięta.

## Dziedziczenie

Kiedy utworzysz nowy wątek z wykorzystaniem `in_thread`, nowy wątek automatycznie odziedziczy wszystkie aktualne ustawienia z bieżącego wątku. Spójrzmy na taki kod:

    use_synth :tb303
    play 50
    sleep 1
    in_thread do
      play 55
    end

Zauważyłeś, iż druga nuta zostaje zagrana z użyciem syntezatora `:tb303`, mimo to została odtworzona z oddzielnego wątku? Każde ustawienie zmienione przy użyciu różnych funkcji `use_*`, będzie zachowywać się tak samo.

Kiedy są tworzone kolejne wątki, dziedziczą one wszystkie ustawienia ze swoich rodziców, natomiast jakiekolwiek zmiany nie są udostępniane z powrotem.

## Nazywanie Wątków

Finalnie możemy nadawać naszym Wątkom nazwy:

    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

Spójrz na panel z logiem, kiedy uruchomisz ten kod. Czy widzisz, jak w logach przy kolejnych wiadomościach pojawiają się nazwy wątków?

    [Run 36, Time 4.0, Thread :bass]
     |- synth :prophet, {release: 0.6, note: 47}

## Tylko Jeden Wątek na Jedną Nazwę

Ostatnią rzeczą, którą powinieneś wiedzieć o wątkach posiadających swoją nazwę, jest, iż w tym samym czasie może być uruchomiony tylko jeden wątek o tej samej nazwie. Spróbujmy to zbadać. Weźmy pod uwagę następujący kod:

    in_thread do
      loop do
        sample :loop_amen
        sleep sample_duration :loop_amen
      end
    end

Śmiało wklej powyższy kod do obszaru roboczego i naciśnij przycisk Uruchom. Następnie zrób to jeszcze kilka razy. Usłyszysz kakofonię wielu zapętlonych w czasie sampli amen break. Okej, możesz teraz nacisnąć przycisk Stop.

To jest zachowanie, które widzieliśmy już nie raz - jeśli naciśniesz przycisk Uruchom, dźwięk zostanie nałożony na istniejące już dźwięki. Dlatego jeśli masz pętle i naciśniesz przycisk Uruchom trzy razy, to będziesz miał trzy warstwy pętli, które będą grane jednocześnie.

Jednakże w przypadku nazwanych wątków jest inaczej:

    in_thread(name: :amen) do
      loop do
        sample :loop_amen
        sleep sample_duration :loop_amen
      end
    end

Spróbuj teraz dla tego kodu nacisnąć przycisk Uruchom kilkukrotnie. Nie usłyszysz teraz więcej niż jedną pętlę amen na raz. W logach zauważysz również taką wiadomość:

    ==> Skipping thread creation: thread with name :amen already exists.

Sonic Pi mówi Ci, że wątek o nazwie `:amen` już istnieje, nie zostanie więc utworzony kolejny.

Takie zachowanie może się teraz nie wydawać do niczego przydatne - ale stanie się bardzo użyteczne, kiedy zaczniemy kodować na żywo…