1 - Witaj Kolego :-)

Witaj w Sonic Pi. Mam nadzieję, że jesteś podekscytowany możliwością rozpoczecia tworzenia zwariowanych dźwięków tak samo, jak ja jestem podekcytowany tym, że mogę Ci to pokazać. To będzie naprawdę świetna zabawa, podczas której nauczysz się wszystkiego o muzyce, syntezie, programowaniu, kompozycji, wydajności oraz znacznie więcej.

Ale poczekaj, gdzie moje maniery! Pozwól, że się przedstawię - jestem Sam Aaron - facet, który stworzył Sonic Pi. Możesz znaleść mnie pod nikiem @samaaron na Twitterze i będę bardzo zadowolony jeśli będę mógł powiedzieć Ci cześć. Być może zainteresuje Cię również moja strona Live Coding Performances, gdzie koduję przed publicznością na żywo używając Sonic Pi.

Jeśli masz jakiekolwiek przemyślenia lub pomysły jak można ulepszyć Sonic Pi - będę wdzięczny za ich przekazanie - informacja zwrotna jest bardzo pomocna. Nigdy nie wiadomo, być może twój pomysł może być następnym kolejną wielką funkcjonalnością!

Ten samouczek został podzielony na sekcje, które są pogrupowane wg kategorii. Pomimo, że napisałem go w taki sposób, aby umożliwiał łatwą naukę od początku do końca, to nic nie szkodzi na przeszkodzie abyś abyś po prostu zaczął czytać dowolną z sekcji - taką która wydaje Ci się odpowiednia dla Ciebie. Jeśli uważasz, że czegoś brakuje daj mi o tym znać, rozważę dołożenie tego do kolejnej wersji.

I jeszcze jedno na koniec. Oglądanie innych osób, które kodują na żywo jest naprawdę świetnym sposobem nauki. Regularnie nadaję na żywo na moim kanale livecoding.tv/samaaron, możesz więc wpaść, powiedzieć do mnie cześć i zadać mi wiele pytań :-)

Dobra, zaczynajmy…


1.1 - Kodowanie na żywo

Jednym z najbardziej ekscytujących aspektów Sonic Pi jest to, że pozwala Ci na pisanie i modyfikację kodu na żywo aby tworzyć muzykę w czasie rzeczywistym, tak samo jak w momencie gdy grasz na żywo na gitarze. Oznacza to, że dzięki odpowiednim ćwiczeniom możesz wykorzytać Sonic Pi do koncertów przed publicznością na żywo.

Uwolnij swój umysł

Zanim zagłębimy się dalszą część tego samouczka i zaczniemy zgłębiać szczegóły tego w jaki sposób działa Sonic Pi, chciałbym dać Ci poczuć jak to jest kodowac na żywo. Nie przejmuj się, jeśli nie zrozumiesz zbyt wiele (lub nie zrozumiesz nic) z tego co zobaczysz i zrobisz za chwilę. Po prostu usiądź wygodnie, zapnij pasy i poczuj radość…

Żywa Pętla

Zacznijmy od skopiowania następującego kawałka kodu do pustego buforu powyżej:

live_loop :flibble do
  sample :bd_haus, rate: 1
  sleep 0.5
end

Teraz nacisnij przycisk Run a usłyszysz fajne i szybkie uderzenia bębna. W każdym momencie możesz zatrzymać dźwięk naciskając przycisk Stop . Aczkolwiek nie rób tego jeszcze… Zamiast tego wykonaj kolejne kroki:

  1. Upewnij się, że wciąż słyszysz dźwięk uderzającego bębna.
  2. Zmień wartość znajdującą się przy sleep z wartości `0.5’ na większą, np. 1.
  3. Ponownie naciśnij przycisk Run
  4. Zauważ jak zmieniła się szybkość uderzeń bębna.
  5. Zapamiętaj ten moment, gdyż jest to twój pierwszy raz (i prawdopobnie nie ostatni), kiedy kodujesz na żywo z Sonic Pi…

OK, to było dosyć łatwe. Dodajmy coś innego do naszego miksu. Powyżej linii sample :bd_haus dodaj linijkę sample :ambi_choir, rate: 0.3. Twój kod powinien teraz wyglądać następująco:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
  sample :bd_haus, rate: 1
  sleep 1
end

A teraz czas na zabawę. Zmieniaj liczby - co się stanie jeśli użyjesz dużych wartości, albo co się stanie jeśli użyjesz małych lub ujemnych liczb? Spróbuj zobaczyć co się stanie gdy zmienisz wartość parametru rate: dla sampla :ambi_choir tylko odrobinę (np. na 0.29). Co się stanie jeśli wybierzesz naprawdę małą wartość dla parametru sleep? Zobacz, czy uda Ci się uruchomić to tak szybko, że twój komputer zatrzyma się z powodu błedu, gdyż nie będzie w stanie nadążyć (jeśli to się zdarzy, po prostu wybierz większa wartość dla parametru sleep i ponownie naciśnij przycisk Run).

Spróbuj zrobić komentarz w jednej z linii zawierających sample dodając na początku linii znak #, np.:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
#  sample :bd_haus, rate: 1
  sleep 1
end

Zauważ, że dodanie # na początku linii mówi komputerowi aby zignorował daną linię, dzięki czemu jej nie słyszymy. Taką linijkę nazywamy komentarzem. W Sonic Pi możemy używać komentarzy do usuwania i dodawania różnych rzeczy do naszego miksu/utworu.

Na koniec pozwól mi zostawić Ci coś fajnego do zabawy. Spójrz na kod poniżej i skopiuj go do wolnego i pustego bufora. Teraz, nie próbuj zrozumieć nic więcej niż to, że w tym kodzie są dwie pętle (loops). Oznacza to, że w tym samym czasie dzieją się dwie rzeczy. Teraz, rób to co umiesz najlepiej - eksperymentuj i baw się próbując zmieniać ten kod. Poniżej kilka sugestii co możesz zrobić.

Pamiętaj aby wcisnąć przycisk Run. Dzięki temu usłyszysz zmianę przy kolejnym przebiegu pętli. Jeśli coś pójdzie nie tak i zacznie się kakofonia nie przejmuj się tym. Wystarczy, że naciśniesz przycisk Stop, usuniesz cały kod w buforze,
wkleisz świeżą kopię poniższego kodu i jesteś znowu gotowy do improwizacji. Pamiętaj, człowiek najszybciej uczy się na błędach…

live_loop :guit do
  with_fx :echo, mix: 0.3, phase: 0.25 do
    sample :guit_em9, rate: 0.5
  end
#  sample :guit_em9, rate: -0.5
  sleep 8
end

live_loop :boom do
  with_fx :reverb, room: 1 do
    sample :bd_boom, amp: 10, rate: 1
  end
  sleep 8
end

Baw się i eksperymentuj tym kawałkiem kodu do momentu gdy twoja ciekwość sprawi, że zaczniesz zastanawiać się jak to wszystko właściwie działa oraz co innego można jeszcze wyczarować za pomocą tego narzędzia. Jeśli ten moment już nastąpił to jesteś gotów aby przeczytać ten samouczek do końca.

Więc na co czekasz…


1.2 - Interfejs użytkownika w Sonic Pi

Sonic Pi ma bardzo prosty interfejs umożliwiający kodowanie muzyki. Poświęćmy chwilę na zapoznanie się z nim.

Sonic Pi Interface

A. Kontrola Odtwarzania (Play Controls)

Różowe przyciski są głównymi kontrolerami uruchamiania i zatrzymywania dźwięków. Jest przycisk Run (Start) umożliwiający uruchomienie kodu znajdującego się w edytorze. Przycisk Stop umożliwia zatrzymanie całego uruchomionego kodu. Przycisk Save (Zapisz) służy do zapisywania kodu wpisanego w edytorze do zewnętrznego pliku tekstowego. Przycisk Record (Nagrywaj) umożliwia nagrywanie (w formacie WAV) aktualnie odtwarzanego dźwięku.

B. Kontrola Edytora (Editor Controls)

Pomarańczowe przyciski pozwalają Ci manipulować edytorem kodu. Przyciski Size + (Zwiększ rozmiar) i Size - (Zmniejsz rozmiar) umożliwiają powiększanie i zmniejszanie rozmiaru tekstu (czcionki). Przycisk Align (Wyrównaj) pozwala na uporządkowanie wyglądu twojego kodu tak aby wyglądał bardziej profesjonalnie (poprawia wcięcia).

C. Informacje i Pomoc (Info and Help)

Niebieskie przyciski dają Ci dostęp do informacji, pomocy i ustawień. Naciśnięcie przycisku Info spowoduje otworzenie dodatkowego okna, które zawiera informacje dotyczące Sonic Pi - zespół podstawowy, historia, współtwórcy oraz społeczność. Przycisk Help (Pomoc) otwiera i zamyka system pomocy (F), który właśnie czytasz. Przycisk Prefs (Ustawienia) otwiera i zamyka panel ustawień, który pozwala Ci na kontrolę kilku podstawowych ustawień aplikacji.

D. Edytor Kodu (Code Editor)

Obszar, w którym będziesz pisał swój kod oraz komponował/wykonywał muzykę. Jest to prosty edytor tekstowy, w którym możesz pisać kod, kasować go, wycinać, wklejać, itd. Myśl o nim jako o bardzo prostej wersji edytora Word czy Google Docs. Edytor automatycznie koloruje słowa bazując na ich znaczeniu w kodzie. Może się to wydawać dziwne na początku, ale bardzo szybko zauważysz, że jest to bardzo przydatne. Na przykład - wiesz, że coś dany tekst jest liczbą ponieważ ma kolor niebieski.

E. Panel preferencji (Prefs Panel)

Sonic Pi wspiera wiele ustawień, które są dostępne za pomocą przycisku Preferencje (prefs), który znajduje się tuż za przyciskami Informacje i Pomoc. Naciśnięcie go spowoduje pokazanie panelu ustawień, który zawiera wiele opcji, które można zmianiać. Przykłady takich ustawień to: wymuszenie trybu mono, odwrócone stereo, włączanie i wyłączanie panelu logowania a także suwak głośności selektor dźwięku, które są dostępne tylko na platformie Raspberry Pi.

F. Podgląd Logów (Log Viewer)

Kiedy uruchamiasz swój kod, informacja o tym co program aktualnie robi będzie wyświetlana w panelu podglądu logów. Domyślnie, zobaczysz wiadomość pojawiającą się dla każdego dźwięku, który stworzysz wraz z dokładnym czasem kiedy ten dźwięk został uruchomiony. Jest to bardzo przydatne do debugowania twojego kodu i zrozumienia co twój kod robi.

G. System Pomocy (Help System)

I na samym końcu została jedna z najważniejszych cześci interfejsu Sonic Pi - system pomocy, który pojawia się w dolnym oknie. Może on być włączony i wyłączony za pomocą naciśnięcia niebieskiego przycisku Help (Pomoc). System pomocy zawiera pomoc oraz informacje dotyczące wszystkich aspektów związanych z Sonic Pi włączając w to ten samouczek, listę dostępnych syntezatorów, sample (próbki dźwięków), przykłady, efekty (FX) oraz listę wszystkich funkcji umożliwiających tworzenie muzyki jakie Sonic Pi udostępnia.


1.3 - Nauka przez zabawę

Sonic Pi zachęca abyś poprzez zabawę i eksperymentowanie uczył się jednocześnie programowania i tworzenia muzyki. Najważniejsze jest
abyś się dobrze bawił. W międzyczasie, nawet się nie obejrzysz, a zauważysz, że nauczyłeś się programować, komponowac i “grać” na żywo.

Błędów nie ma

Skoro jesteśmy przy tym temacie, pozwól że dam Ci jedną radę, coś czego nauczyłem się przez lata kodowania muzyki na żywo - błędów nie ma, są tylko nowe możliwości. To jest coś, co często słyszy się w kontekście muzyki z gatunku jazz, ale sprawdza się równie dobrze w odniesieniu do kodowania na żywo. Nie ma znaczenia jak dużo masz doświadczenia - niezależnie czy jesteś całkowitym żółtodziobem, czy zaprawionym w bojach Algorejwerem, na pewno zdarzy Ci się napisać kod, którego wynik po uruchomieniu będzie całkowicie nieprzewidziany. Może to brzmieć niesamowicie fascynująco - i w tym przypadku faktycznie tak jest. Można też, patrząc na to z innej strony, stwierdzić że brzmi to kiepsko i jest całkowicie nie na miejscu. Pamiętaj, to że to się wydarzyło jest całkowicie nieistotne - to co jest naprawdę ważne to co z tym zrobisz dalej. Weź dźwięk, manipuluj nim i przekształć go w coś niesamowitego. Tłum będzie szalał.

Zacznij od czegoś prostego

Zawsze kiedy się uczysz, najbardziej kuszące jest to, że chcesz robić niesamowite rzeczy tu i teraz. Postaraj się jednak powstrzymać te myśli i spójrz na nie jako odległy cel, który uda się się osiągnąć później. Zamiast tego, pomyśl o najprostszej rzeczy jaką potrafisz napisać, która będzie fajna, a jednocześnie sprawi, że będziesz czuł satysfakcję z tego, że jest to mały krok w kierunku wizji, która wypełnia twoją głowę. Gdy już będziesz widział w swojej głowie ten mały krok, spróbuj go wykonać - napisz kawałek kodu, uruchom go, baw się nim i zobacz jakie nowe pomysły przyjdą Ci do głowy. Zobaczysz, niedługo będziesz tak pochłonięty zabawą, że zaczniesz robić prawdziwe postępy.

Nie zapomnij tylko podzielić się swoją pracą z innymi!


2 - Syntezatory

OK, tyle tytułem wstępu - pora zająć się muzyką.

W tym rozdziale poznasz podstawy uruchamiania i manipulowania syntezatorami. Syntezator to taka fajna nazwa dla czegoś co wytwarza dźwięk. Normalnie syntezatory są dość skomplikowane w użyciu. Zwłaszcza syntezatory analogowe zawierają wiele różnych połączeń, kabelków i modułów. Natomiast Sonic Pi oddaje w twoje ręce wiele z tych możliwości
w bardzo prostej i przystępnej formie.

Nie daj się zwieść prostocie interfejsu, który prezentuje Sonic Pi. Masz możliwość zanurzyć się bardzo głęboko. Jeśli to twoja dziłka, to do twojej dyspozycji są bardzo wyszukane możliwości manipulacji dźwiękiem. Zapnij pasy…


2.1 - Twoje pierwsze bipy

Spójrz na poniższy kod:

play 70

To jest miejsce, w którym wszystko się zaczyna. Śmiało, skopiuj powyższy kod i wklej go do edytora kodu na górze aplikacji (duża biała przestrzeń tuż pod przyciskiem Run). Kiedy już to zrobisz, naciśnij przycisk Run…

Bip!

A teraz naciśnij przycisk jescze raz. I jeszcze raz. I jeszcze raz…

Łał, szaleństwo. Jestem pewien, że możesz tak przez cały dzień. Ale poczekaj. Zanim zatracisz się w pętli nieskończonych bipów, spróbuj zmienić liczbę:

play 75

Słyszysz różnicę? OK, teraz spróbuj mniejszej liczby:

play 60

Zauważ, że mniejsze liczby powodują bipy o niższym tonie a większe liczby powodują bipy o wyższym tonie. Tak samo jak na pianinie - klawisze znajdujące się po lewej stronie instrumentu grają nuty o niższym brzmieniu a klawisze znajdujące się po prawej stronie grają nuty o wyższym brzmieniu. I faktycznie tak jest, powyższe liczby odpowiadają nutom na pianinie. Kod play 47 znaczy nic innego jak - zagraj nutę znajdującą się pod 47 klawiszem na pianinie. Oznacza to, że kod play 48 to dźwięk o jedną nutę wyżej (następny klawisz po prawej). Tak się składa, że nuta C w 4-tej oktawie odpowiada liczbie 60. Smiało, spróbuj zagrać ten dźwięk:

play 60.

Nie przejmuj się jeśli nic z tego nie rozumiesz - ja również nie rozumiałem gdy zaczynałem na poczatku tak jak Ty teraz. Wszystko co się teraz liczy to to, że wiesz, że małe liczby powodują bipy o niskim brzmieniu a duże liczby powodują bipy o wyższym brzmieniu.

Akordy

Zagranie nuty jest całkiem fajne, ale zagranie kilku jednocześnie może być jeszcze fajniejsze. Spróbuj:

play 72
play 75
play 79

Super! Zauważ, że kiedy napiszesz kilka razy komendę play, wszytkie dźwięki zagrają w tym samym momencie. Teraz spróbuj sam - które liczby brzmią razem dobrze? Które brzmią okropnie? Eksperymentuj, odkrywaj i przekonaj się na własnej skórze.

Melodia

Granie nut i akordów jest fajne - a co powiesz na zagranie melodii? Co jeśli chciałbyś zagrać jedną nutę po drugiej ale nie w tym samym czasie? Nic prostszego, wystarczy że odczekasz kawałek czasu pomiędzy poszczególnymi nutami używając polecenia sleep:

play 72
sleep 1
play 75
sleep 1
play 79

Cudownie, właśnie stworzyłeś małe arpeggio. No dobrze, ale co oznacza liczba 1 w poleceniu sleep 1? Oznacza to długość trwania odstępu pomiędzy nutami. Zasadniczo oznacza to odstęp o długości jednego uderzenia, ale póki co możesz myśleć o tym jako o przeczekaniu 1-ną sekundę. Co powinniśmy w takim razie zrobić jeśli chcielibyśmy trochę przyśpieszyć nasze arpeggio? Jedyne co musimy zrobić to użyć “krótszych” wartości dla polecenia sleep. Weźmy na przykład połowę, czyli wartość 0.5:

play 72
sleep 0.5
play 75
sleep 0.5
play 79

Zauważ, że arpeggio gra teraz szybciej. Teraz twoja kolej, pobaw się tym kawałkiem kodu zmieniając czasy na takie jak uważasz, tak jak wcześniej spróbuj użyć przy tym różnych nut.

Jest jedna rzecz, którą szczególnie warto wypróbować. Spróbuj użyć nut, które są “pomiędzy” całymi nutami, np. play 52.3, play 52.63. Nie ma absolutnie żadnej konieczności, abyś kurczowo trzymał się standardowych pełnych nut. Kombinuj z różnymi wartościami i baw się dobrze.

Tradycyjne Nazwy Nut

Osoby, które aktualnie znają już trochę notację muzyczną (nie przejmuj się jeśli Ty nie znasz - nie musisz, żeby móc się dobrze bawić) być może będą preferować pisanie melodii przy wykorzystaniu standardowych nazw nut,
np. C lub F# (Fis) zamiast używania liczb. Sonic Pi pozwala na to. Nic nie stoi na przeszkodzie abyś napisał i uruchomił taki kod:

play :C
sleep 0.5
play :D
sleep 0.5
play :E

Pamiętaj tylko, że by umieścić dwukropek : tuż przed nazwą twojej nuty. Spowoduje to, że zmieni ona kolor na różowy. Możesz również zdefiniować oktawę umieszczająć odpowiednią liczbę tuż po nazwie nuty:

play :C3
sleep 0.5
play :D3
sleep 0.5
play :E4

Jeśli chcesz sprawić aby nuta brzmiała o pół tonu wyżej (uzyskanie dźwięku fis), dodaj s tuż za twoją nutą, np. play :Fs3. Analogicznie - jeśli chcesz obniżyć dźwięk nuty o połowę (uzyskanie dźwięku mol), dodaj na końcu twojej nuty b, np. play :Eb3

A teraz czas poszaleć. Możesz zacząć bawić się w tworzenie twoich własnych melodii.


2.2 - Parametry Syntezatorów: Amplituda i Balans

Tak samo jak masz kontrolę nad tym, którą nutę zagrać lub który sampel uruchomić, Sonic Pi udostępnia cały asortyment parametrów umożliwiających kształtowanie i kontrolowanie dźwięków. Wiele z tych parametrów zostanie omówionych w tej części samouczka. Ponadto w systemie pomocy jest obszerna dokumentacja, która szczegółowo opisuje każdy z nich. Tymczasem, przedstawimy dwa najbardziej przydatne: aplituda (amp) i balans (pan). Na początek, zobaczmy czym są te parametry w rzeczywistości.

Parametry

Syntezatory obecne w Sonic Pi wspierają pojęcie parametrów. Parametry to sterowniki, które po przekazaniu do syntezatora play modyfikują i kontrolują różne aspekty odtwarzanego dźwięku. Każdy z syntezatorów posiada własny zestaw parametrów pozwalających na subtelny tuning produkowanego dźwięku. Jednakże, istnieje zestaw parametrów, które są wspólne dla wielu dźwięków. Przykładami takich parametrów są np. amp: czy parametry kopertowe (zostaną omówione w dalszej części samouczka).

Parametry składają się z dwóch podstawowych części: nazwy (kontrolowanego parametru) oraz wartości (na jaką chcemy ustawić dany parametr). Na przykład możesz mieć parametr, który nazywa się ser: i chciałbyś ustawić jego wartość na 1.

Parametry są przekazywane do polecenia play w następujący sposób: najpierw dodajemy tuż za poleceniem przecinek , po nim wpisujemy nazwę parametru, np. amp: (nie zapomnij o dwukropku :) i na końcu po spacji podajemy wartość parametru. Oto przykład:

play 50, ser: 1

(Zauważ, że ser: nie jest poprawnym parametrem, używamy go tutaj tylko jako przykład).

Możesz przekazać wiele parametrów oddzielając je przecinkami:

play 50, ser: 1, fasolki: 0.5

Kolejnośc parametrów nie ma znaczenia, poniższy kod też zadziała:

play 50, fasolki: 0.5, ser: 1

Parametry, które nie są rozpoznawane przez dany syntezator są po prostu ignorowane (tak jak ser i fasolki jak w powyższym przypadku, które są po prostu śmiesznymi nazwami parametrów!).

Jeśli niechcący zdarzy Ci się dwa razy użyć parametru o tej samej nazwie to wygrywa ostani. Na przykład - ostateczna wartość dla parametru fasolki: wyniesie 2 (a nie 0.5):

play 50, fasolki: 0.5, ser: 3, jajka: 0.1, fasolki: 2

Wiele rzeczy w Sonic Pi akceptuje parametry, warto więc poświęcić parę chwil aby nauczyć się jak ich używać, dzięki temu będziesz ustawiony! Spróbujmy pobawić się trochę z naszym pierwszym parametrem: amp:.

Amplituda

Amplituda jest w komputerową miarą reprezentującą głośność dźwięku. Wysoka aplituda powoduję głośny dźwięk a niska aplituda powoduje cichyy dźwięk. Tak samo jak Sonic Pi używa liczb do reprezentacji czasu i nut, tak samo używa ich do reprezentacji wielkości amplitudy. Amplituda o wartości 0 to cisza (nie słyszysz nic). Natomiast amplituda o wartości 1 ustawienie głośności na normalny poziom. Możesz nawet podkręcić na 2, 10, 100. Musisz jednak mieć na uwadze to, że gdy całkowita amplituda wszystkich dźwięków stanie się zbyt wysoka, Sonic Pi wykorzysta narzędzie zwane kompresorem, żeby zdusić je tak, żeby mieć pewność, że dźwięk nie jest zbyt głośny dla twoich uszu. Może to spowodować, że dźwięk stanie się nieczysty i dziwny. Staraj się więc używać niskch aplitud, np. w zakresie od 0 do 0.5, żeby uniknąć kompresji.

Amplituda w górę

Aby zmienić amplitudę dźwięku użyj parametru amp:. Na przykład, aby zagrać z głośnością na poziomie 0.5 użyj takiego kawałka kodu:

play 60, amp: 0.5

Aby zagrać z podwójną głośnością (amplitudą) przekaż parametr 2:

play 60, amp: 2

Parametr amp: modyfikuje tylko wywołanie tego polecenia play, z którym jest powiązany. Tak więc w poniższym przykładzie pierwsze wywołanie polecenia play zostanie zagrane z głośnością na poziomie równym połowie normalnej głośności, natomiast drugie polecenie zostanie zagrane z głośnością domyślną (1):

play 60, amp: 0.5
sleep 0.5
play 65

Nic nie stoi na przeszkodzie, abyś użył różnych wartości parametru amp: dla różnych wywołań polecenia play:

play 50, amp: 0.1
sleep 0.25
play 55, amp: 0.2
sleep 0.25
play 57, amp: 0.4
sleep 0.25
play 62, amp: 1

Balansowanie

Kolejnym fajnym parametrem z którego można korzystać jest pan:. Kontroluje on balans dźwięku w stereo. Balansowanie dźwiękiem w lewą stronę oznacza, że będziesz go słyszał tylko w lewym głośniku (słuchawce). Z kolei balansowanie dźwiękiem na lewą strone oznacza, że będziesz go słyszał tylko w prawym głośniku. W naszym przypadku używamy wartości -1 do reprezentacji dźwięku, którego balans został w pełni przesunięty na lewą stronę, 0 aby dla balansu po środku oraz 1 dla dźwięku po prawej stronie w polu stereo. Naturalnie nic nie stoi na przeszkodzie abyśmy używali dowolnej wartości znajdującej się pomiędzy -1 i 1 w celu dokładnej kontroli “pozycji” naszego dźwięku.

Zagrajmy bip z lewego głośnika:

play 60, pan: -1

A teraz zagrajmy go z prawego głośnika:

play 60, pan: 1

I na końcu zagrajmy z powrotem z obu głośników (domyślna pozycja):

play 60, pan: 0

Teraz kolej na Ciebie. Spróbuj samodzielnie pobawić się zmieniając amplitudę (amp:) i balans (pan:) twoich dźwięków!


2.3 - Przełączanie Syntezatorów

Do tej pory bawiliśmy się całkiem nieźle robiąc wiele fajnych bipów. Jest jednak bardzo prawdopodobne, że podstawowy dźwięk bip zaczyna Cię już powoli nudzić. Czy to jest wszystko co Sonic Pi ma do zaoferowania? Na pewno jest dużo więcej możliwości w kodowaniu na żywo niż tylko granie bipów? Owszem, są inne możliwości i to jest rozdział, w którym poznasz fascynującą paletę dźwięków, jakie Sonic Pi ma do zaoferowania.

Syntezatory

Sonic Pi posiada szeroki wachlarz instrumentów, które nazywa syntezatorami. Zważywszy na to, że sample (próbki) reprezentują nagrane dźwięki, syntezatory mają możliwość generowania nowych dźwięków, które są zależne od tego jak je kontrolujesz (w tym samouczku dowiesz się o tym później). Syntezatory Sonic Pi są bardzo potężne i ekspresyjne. Będziesz miał dużo przyjemności podczas poznawania i zabawy nimi. Na początku jednak nauczmy się jak wybierać aktualnie grający syntezator.

Brzęczące piły i prophety

Fajnym dźwiękiem jest sawdźwięk piły - spróbujmy:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25

A teraz spróbujmy innego dźwięku - syntezatora prophet:

use_synth :prophet
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25

Co powiesz na połączenie dwóch dźwięków. Jeden po drugim:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

A teraz w tym samym czasie:

use_synth :tb303
play 38
sleep 0.25
use_synth :dsaw
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

Zauważ, że polecenie use_synth wywiera wpływ tylko na kolejne wywołania poleceń play. Pomyśl o tym poleceniu jako o dużym przełączniku - kolejne wywołania polecenia play będą odtwarzać dowolny syntezator, który jest w danym momencie wskazany. Możesz zmienić aktualny syntezator na inny używając przełącznika use_synth.

Odkrywanie Syntezatorów (Synths)

Aby zobaczyć jakie syntezatory Sonic Pi ma dla Ciebie do zabawy zerknij na opcję Synth w lewym dolnym rogu (obok Fx). Znajdziesz tam ponad 20 do wyboru. Oto kilka moich ulubionych:

Tera pobaw się zmieniając syntezatory w trakcie odtwarzania twojej muzyki. Próbuj bawić się łącząc ze sobą różne dźwięki aby tworzyć nowe brzmienia jak również używająć różnych syntezatorów w różnych sekcjach twojego utworu.


2.4 - Czas trwania obwiedni dźwięku

W poprzedniej sekcji, zobaczyliśmy w jaki sposób możemy używać komendy sleep aby kontrolować, kiedy dźwięki zaczynają grać. Nie wiemy jednak jeszcze w jaki sposób kontrolować długość trwania naszych dźwięków.

Aby móc korzystać z prostej ale jakże potężnej możliwości kontrolowania długości trwania naszych dźwięków, Sonic Pi udostępnia pojęcie obwiedni dla amplitudy ADSR (czym jest ADSR dowiesz się za chwilę w kolejnych sekcjach). Obwiednia amplitudy udostępnia dwa przydatne aspekty kontroli:

Długość trwania dźwięku (ang. Duration)

Długość trwania mówi o tym jak długo słychać dany dźwięk. Im długość trwania jest większa tym dłużej słyszysz dźwięk. Wszystkie dźwięki w Sonic Pi posiadają kontrolowalną obwiednię amplitudy a całkowita długości trwania tej obwiedni
to długość trwania dźwięku. Dlatego też kontrolując obwiednię kontrolujesz Długość trwania.

Amplituda (ang. Amplitude)

Obwiednia ADSR kontroluje nie tylko długość trwania, lecz pozwala Ci również na precyzyjną kontrolę amplitudy dźwięku. Wszystkie dźwięki zaczynają się i kończą ciszą. Pomiędzy tymi ciszami jest moment podczas, którego słychać dźwięk. Obwiednie pozwalają Ci przesuwać i ustawiać amplitudę tej części, w której słychać dźwięk. Jest to analogiczne do sytuacji, w której powiedziałbyś komuś kiedy powinien zwiększać i zmieniejszać głośność dla jakiegoś utworu muzycznego. Na przykład - możesz poprosić kogoś “zacznij od ciszy, potem powoli zwiększaj poziom głośności, utrzymaj go na tym poziomie przez chwilę po czym szybko wycisz”. Sonic Pi pozwala Ci na zaprogramowanie tego za pomocą obwiedni.

Jak widzieliśmy w poprzedniej sekcji samouczka, amplituda o wartości 0 to cisza, natomiast amplituda o wartości 1 to głośność normalna.

Release Time - czas zanikania amplitudy

Domyślnie wszystkie syntezatory posiadają czas zanikania amplitudy równy 1. Oznacza to, że trwa to 1 uderzenie przed zakończeniem (domyślnie będzie to 1 sekunda). Możemy zmieniać czas trwania tego zanikania za pomocą przekazania do naszego polecenia play parametru release:. Na przykład, aby sprawić by syntezator grał przez 2 uderzenia, dla parametru release: ustawiamy wartość 2:

play 60, release: 2

Możemy też sprawić aby syntezator brzmiał przez bardzo krótką chwilę. Wystarczy użyć bardzo małej wartości dla czasu zanikania amplitudy:

play 60, release: 0.2

W takim razie czym jest długość zanikania amplitudy? Jesto to czas, który jest potrzebny aby dźwięk z maksymalnej amplitudy (zazwyczaj jest to wartość 1) zmniejszył się do amplitudy równej zero. Jest to tak zwana faza zanikania (ang. release phase) i jest to przejście liniowe (tzn. obniżające się w linii prostej). Poniższy diagram ilustruje to przejście:

release envelope

Pionowa linia po lewej stronie diagramu pokazuje, że dźwięk zaczyna się z amplitudą równą 0, ale osiąga pełną głośność momentalnie (jest to faza ataku, omówimy ją za chwilę). Gdy pełna głośność zostanie już osiągnięta następuje zmniejszanie głośności po linii prostej aż do wartości zero i zajmuje to tyle czasu ile zostało ustawione za pomocą parametru zanikania release:. Im czas zanikania jest dłuższy, tym dłuższy będzie czas znikania (wyciszania) dźwięku syntezatora.

Możesz zatem zmieniać długość trwania twoich dźwięków zmieniając czas zanikania. Spróbuj teraz pobawić się dodając do twojej muzyki różne czasy zanikania.

Attack Time - czas narastania amplitudy

Domyślnie, faza ataku jest równa 0 dla wszystkich sytezatorów. Oznacza to, że przejście od amplitudy 0 do aplitudy 1 jest natychmiastowe. Nadaje to syntezatorowi początkowy perkusyjny dźwięk. Mimo to, może się zdarzyć, że będziesz chciał aby twój dźwięk zaczynał brzmieć stopniowo. Aby to zrobić wystarczy wykorzystać parametr ‘attack:’. Spróbuj użyć takiego przejścia w kilku różnych dźwiękach:

play 60, attack: 2
sleep 3
play 65, attack: 0.5

Zauważ, że możesz używać wielu parametrów w tym samym czasie. Na przykład dla krótkiej fazy ataku (attack) i długiej fazy zanikania (release) spróbuj coś takiego:

play 60, attack: 0.7, release: 4

Taka obwiednia z krótką fazą ataku i długą zanikania została zilustrowana na poniższym rysunku:

attack release envelope

Oczywiście, możesz zmieniać parametry według swoich upodobań. Spróbuj teraz długiej fazy ataku i krótkiej fazy zanikania:

play 60, attack: 4, release: 0.7

long attack short release envelope

Na koniec możesz też spróbować ustawić obie wartości dla czasu narastania i zanikania na małe wartości aby uzyskać krótsze dźwięki.

play 60, attack: 0.5, release: 0.5

short attack short release envelope

Sustain Time - czas podtrzymania amplitudy

Oprócz możliwości ustawiania czasu narastania i czasu zanikania dźwięku, możesz również określić czas podtrzymania. Jest to moment, w którym dźwięk jest utrzymany na pełnej aplitudzie pomiędzy fazami narastania i zanikania.

play 60, attack: 0.3, sustain: 1, release: 1

ASR envelope

Czas podtrzymania jest bardzo przydatny dla istotnych dźwięków, którym chciałbyś dać pełną obecność w miksie tuż przed wejściem opcjonalnej fazy zanikania. Oczywiście, całkowicie dopuszczalne jest ustawienie obu parametrów, zarówno fazy ataku jak i fazy zanikania na wartość 0 a także użycie tylko fazy podtrzymania żeby nie mieć absolutnie żadnej
fazy wejścia lub wyjścia dla danego dźwięku. Bądź jednak ostrożny i wiedz, że ustawienie fazy zanikania na 0 może spowodować dziwne kliki w dźwiękach i bardzo często zamiast tego dużo lepiej jest użyć bardzo małej wartości, np. 0.2.

Decay Time - czas opadania amplitudy

Na sam koniec, dla momentów gdzie potrzebujesz dodatkowego poziomu kontroli, masz możliwość skorzystania z fazy opadania. Jest to taki moment w obwiedni dźwięku, który znajduje się pomiędzy fazą ataku a fazą podtrzymania (wybrzmiewania) i określa moment, w którym amplituda spada z poziomu ataku attack_level do poziomu podtrzymania sustain_level. Domyślnym argumentem dla fazy opadania jest 0, natomiast poziomy ataku i podtrzymania posiadają domyślną wartość 1. W związku z tym musisz określić dla nich czas opadania aby uzyskać jakikolwiek efekt:

play 60, attack: 0.1, attack_level: 1, decay: 0.2, sustain_level: 0.4, sustain: 1, release: 0.5

ADSR envelope

Obwiednie ADSR

Obwiednie ADSR

Podsumowując, obwiednie ADSR w Sonic Pi posiadają następujące fazy:

  1. attack - czas narastania amplitudy od zera do poziomu maksymalnego, którego wysokość jest określana przez parametr attack_level.
  2. decay - czas opadania amplitudy od poziomu maksymalnego (attack_level) do poziomu podtrzymania (sustain_level).
  3. sustain - czas podtrzymania dźwięku na poziomie określonym przez parametr sustain_level.
  4. release - czas zanikania amplitudy od poziomu podtrzymania (sustain_level) do zera.

Należy tu zwrócić uwagę na fakt, że całkowita długość trwania dźwięku jest sumą czasu trwania każdej z faz występujących w danym dźwięku. Dlatego też poniższy dźwięk będzie miał długość 0.5 + 1 + 2 + 0.5 = 4 uderzeń:

play 60, attack: 0.5, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5

Tyle teorii, teraz spróbuj sam pobawić się dodając obwiednie do twoich dźwięków…


3 - Sample

Innym świetnym sposobem tworzenia twojej muzyki jest wykorzystanie nagranych wcześniej dźwięków. W wielkiej tradycji hip hopu, takie nagrane wcześniej dźwięki nazywamy samplami. Innymi słowy jeśli weźmiesz mikrofon i nagrasz subtelny dźwięk kropel deszczu uderzających o szybę, to właśnie nagrałeś swój pierwszy sampel.

Sonic Pi pozwala Ci robić wiele fajnych rzeczy z samplami. Poza tym, że na pokładzie jest ponad 90 publicznie dostępnych sampli, które są gotowe abyś zaczął się nimi bawić, to masz też możliwość manipulowania nimi oraz korzystania z twoich własnych. Bierzmy się do zabawy…


3.1 - Wyzwalanie Sampli

Granie prostych dźwięków to dopiero początek. Coś co jest dużo fajniejsze to wyzwalanie nagranych sampli. Spróbuj:

sample :ambi_lunar_land

Sonic Pi posiada wiele sampli, których możesz używać do tworzenia swojej muzyki. Możesz używać ich tak samo jak używasz polecenia `play’. Aby zagrać kilka sampli i nut po prostu napisz je jeden po drugim:

play 36
play 48
sample :ambi_lunar_land
sample :ambi_drone

Jeśli chcesz rozdzielić je w czasie wykorzystaj polecenie sleep:

sample :ambi_lunar_land
sleep 1
play 48
sleep 0.5
play 36
sample :ambi_drone
sleep 1
play 36

Zauważ, że Sonic Pi nie czeka aż dźwięk przestanie grać zanim zacznie grać kolejny dźwięk. Polecenie sleep tylko opisuje rozdzielenie wyzwalania poszczególnych dźwięków. Takie podejście pozwala na łatwe nawarstwianie kolejnych dźwięków, które razem mogą tworzyć ciekawe efekty nakładania się na siebie. W dalszej części tego samouczka pokażemy w jaki sposób można kontrolować długość trwania dźwięków przy użyciu obwiedni.

Odkrywanie Sampli

Są dwa sposoby na odkrywanie wachlarza sampli dostępnych w Sonic Pi. Po pierwsze możesz korzystać z systemu pomocy. Kliknij na sekcję Sample w lewym dolnym menu, wybierz kategorię a zobaczysz listę dostępnych dźwięków.

Alternatywnie możesz skorzystać z systemu autopodpowiadania. Wystarczy, że wpiszesz początek wybranej grupy sampli, np. sample :ambi_ a twoim oczom ukaże się rozwijana lista sampli do wyboru. Wypróbuj następujące prefiksy kategorii:

A teraz zacznij wplatać sample w twoje własne kompozycje!


3.2 - Parametry Sampli: Amp i Pan

Tak samo jak w przypadku Syntezatorów, możemy łatwo kontrolować nasze dźwięki za pomocą parametrów. Sample wspierają takie sam mechanizm parametrów. Przyjrzyjmy się ponownie naszym kolegom amp: i pan:.

Zmiana głośności sampli

Możesz zmieniać głośność sampli dokładnie w taki sam sposób jakiego używałeś dla syntezatorów:

sample :ambi_lunar_land, amp: 0.5

Przesuwanie sampli na różne kanały

Możemy również używać parametru pan: dla sampli. Na przykład, oto jak możemy zagrać breakbeat amen aby brzmiał tylko w lewym głośniku, a potem w połowie czasu, żeby zaczął grać też w prawym glośniku:

sample :loop_amen, pan: -1
sleep 0.877
sample :loop_amen, pan: 1

Zauważ, że liczba 0.877 jest połową czasu trwania pętli loop_amen wyrażoną w sekundach.

Na koniec należy zauważyć, że jeśli ustawisz pewne wartości domyślne syntezatorów za pomocą parametru use_synth_defaults (zostanie on omówiony później), to będą one ignorowane przez polecenie sample.


3.3 - Rozciąganie Sampli

Teraz, gdy już umiemy grać za pomocą różnorodnych syntezatorów i sampli, przyszedł czas aby nauczyć się w jaki sposób można modyfikować syntezatory i sample aby sprawić by muzyka była jeszcze bardziej unikalna i interesująca. Na początek poznajmy możliwość rozciągania (stretch) i ściskania (squash) sampli.

Reprezentacja Sampla

Sample to nagrane dźwięki, które są przechowywane niczym liczby, które mówią o tym jak poruszyć stożek głośnika by zreprodukować dany dźwięk. Stożek głośnika może poruszać się do środka i na zewnątrz, tak samo liczby muszą jedynie przedstawiać jak daleko do środka lub na zewnątrz powinien znajdować się stożek głośnika w danym momencie. Aby móć wiernie odwzorować nagrany dźwięk sampla zazwyczaj potrzeba do tego wiele tysięcy liczb na sekundę! Sonic Pi bierze tę listę liczb i zasila nimi głośniki z odpowiednią prędkością tak aby głośniki twojego komputera poruszały się do przodu i do tyłu w taki właśnie sposób aby zreprodukować dany dźwięk. Mimo to, całkiem fajnie jest zmieniać prędkość z jaką te liczby są przekazywane do głośnika aby w ten sposób zmieniać brzmienie.

Zmiana tempa

Pobawmy się jednym z dźwięków z gatunku ambient: :ambi_choir. Aby zagrać go w domyślnym tempie, możesz przekazać parametr rate: do polecenia sample:

sample :ambi_choir, rate: 1

Takie poleceni sprawia, że sampel zostanie zagrany w normalnym tempie (1), więc póki co nic specjalnego się nie dzieje. Nic jednak nie stoi nam na przeszkodzie abyśmy zmienili tę liczbę na coś innego. Co powiesz na wartośc 0.5:

sample :ambi_choir, rate: 0.5

Łał! Co się tutaj dzieje? Otóż, dwie rzeczy. Po pierwsze, odtworzenie naszego naszego sampla zajmuje drugie tyle czasu. Po drugie, dźwięk jest niższy o oktawę. Przyjrzyjmy się tym dwóm tematom nieco bardziej szczegółowo.

Rozciągamy

Sampel, który jest bardzo fajny do rozciągania i kompresji to Amen beakbit. Przy normalnym tempie, możemy wyobrazić sobie wrzucenie go do utworu drum ‘n’ bass:

sample :loop_amen

Jednak gdy zmienimy tempo możemy bardzo szybko zmienić gatunek. Spróbuj połowy prędkości aby stworzyć oldschool’owy hip hop:

sample :loop_amen, rate: 0.5

Jeśli przyśpieszymy, wejdziemy na terytorium jungle:

sample :loop_amen, rate: 1.5

A teraz nasz ulubiony finalny trik - zobaczmy co się stanie jeśli użyjemy ujemnego tempa:

sample :loop_amen, rate: -1

Łoł! To jest odtwarzane od tyłu! A teraz spróbuj sam pokombinować z różnymi samplami ustawiając je na różne tempa. Spróbuj bardzo szybkich temp. Spróbuj niewiarygodnie niskich temp. Sprawdź jak różne i interesujące dźwięki możesz wyprodukować.

Proste Wyjaśnienie Częstotliwości Próbkowania

Przydatnym sposobem myślenia o samplach jest myślenie o nich jak o sprężynkach. Z tempem (szybkością) odtwarzania jest tak jak ze ściskaniem i rozciąganiem sprężyny. Zagranie sampla w tempie równym 2 spowoduje, że ściśniesz sprężynę do połowy jej normalnej długości. Dlatego też zagranie takiego sampla zajmie o połowę mniej czasu. Jeśli zagrasz sampel w tempie równym połowe normalnego, to wtedy *rozciągasz sprężynę tak, że podwaja swoją długość. W takim przypadku zagranie całego sampla zajmie dwa razy więcej czasu. Im bardziej ściśniesz sprężynę (wyższe tempo), tym stanie się krótsza. Analogicznie, im bardziej rozciągniesz (niższe tempo), tym będzie dłuższa.

Ściskanie sprężyny zwiększa jej gęstość (liczba zwojów na cm) - jest to podobne do tego gdy sampel brzmi na wyższym poziomie (pitch). Rozciąganie zmniejsza gęstość i jest podobne to dźwięku posiadającego niższy poziom (pitch).

Matematyka Stojąca Za Częstotliwością Próbkowania

(Ta sekcja jest udostępniona dla tych osób, które są zainteresowane szczegółami. Jeśli nie jesteś, możesz ją po prostu pominąć…)

Jak zauważyliśmy już powyżej, sampel jest reprezentowany przez wielką, długą listę liczb, które defuniują to w jakiej pozycji powinien znajdować się głośnik w danym momencie czasu. Możemy wziąć te liczby i wykorzystać je do narysowania wykresu graficznego, który mógłby wyglądać bardzo podobnie do tego:

sample graph

Być może widziałeś już podobne obrazki. Nazywa się ją przebiegiem fali sampla. Jest to nic innego jak tylko wykres prezentujący liczby. Zazwyczaj przebieg fali takiej jak ta będzie miał 44100 punktów z danymi na sekundę(jest związane z twierdzeniem Kotelnikowa-Shanona). Więc jeśli sampel trwa przez 2 sekundy, to przebieg fali będzie reprezentowany przez 88200 liczb które przekażemy do głośnika z prędkością 44100 punktów na sekundę. Odtworzenie tego powinno zatem zajęć tylko 1 sekundę. Możemy spróbować również odtworzyć go w tempie o połowę mniejszym, co dałoby wartość 22050 punktów na sekundę i odtworzenie zajęłoby 4 sekundy.

Na czas trwania sampli ma wpływ szybkość odtwarzania:

Możemy przedstawić to za pomocą następującego wzoru:

nowy_czas_trwania_sampla = (1 / tempo) * czas_trwania_sampla

Zmiana szybkości odtwarzania wpływa również na wysokość tonu (pitch) sampla. Częstotliwość lub wysokość tonu widoczna na fali dźwięku jest determinowana przez to jak szybko się ona zmienia w górę i w dół. Nasze mózgi w jakiś sposób zmieniają szybkie ruchy głośnika na wysokie nuty oraz wolne ruchy głośników na niskie nuty. To jest właśnie przyczyną tego, że czasami możesz nawet zobaczyć ruch dużego głośnika basowego gdy wydaje on z siebie super niski bas - w zasadzie to porusza się on wtedy znacznie wolniej w tę i z powrotem niż wtedy gdy głośnik produkuje wyższe dźwięki.

Jeśli weźmie się falę dźwięku i ściśnie się to wtedy będzie się ona poruszać w górę i w dół więcej razy na sekundę. Spowoduje to, że dany dźwięk będzie miał wyższy ton. Oznacza to, że podwojenie ruchów w górę i w dół (oscylacji) zwiększa częstotliwość dwukrotnie. Podsumowując, zagranie twojego sampla z podwójną prędkością spowoduje, że częstotliwość, którą usłyszysz będzie dwa razy wyższa. Analogicznie, obniżenie tempa o połowę spowoduje, że częstotliwość będzie też niższa o połowę. Inne wartości tempa będą będą oddziaływać na częstotliwość odpowiednio.


3.4 - Opakowane Sample

Korzystając z obwiedni ADSR możliwa jest również modyfikacja czasu trwania oraz amplitudy sampli. Jednakże działanie jest w tym przypadku trochę inne niż w przypadku syntezatorów. Obwiednie sampli pozwalają Ci tylko na zmniejszanie amplitudy oraz czasu trwania sampla - natomiast nigdy nie jest możliwe zwiększanie wartości tych parametrów. Sampel przestanie grać gdy się skończy lub gdy zakończy się obwiednia - obojętne co skończy się szybciej. Jeśli więc użyjesz bardzo długiego parametru release:, to nie spowoduje to, że wydłuży się czas odtwarzania sampla.

Obwiednie Amen

Wróćmy do naszego sprawdzonego kolegi Amen Break:

sample :loop_amen

Bez podawania żadnych parametrów słyszymy całego sampla na pełnej głośności. Jeśli chcemy aby dźwięk pojawiał się stopniowo przez 1 sekundę możemy użyć parametru attack::

sample :loop_amen, attack: 1

Jeśli chcemy aby wejście trwało krócej wystarczy, że użyjemy krótszej wartości dla fazy ataku:

sample :loop_amen, attack: 0.3

Automatyczne Podtrzymanie (Auto Sustain)

Miejsce, w kórym zachowanie obwiedni ADSR dla sampli różni się od obwiedni dla syntezatorów jest wartość parametru sustain. Domyśnie w obwiedni syntezatorów, parametr fazy podtrzymania domyślnie otrzymuje wartość 0, o ile nie zmienimy jej ręcznie. W przypadku sampli, faza podtrzymania domyślnie otrzymuje wartość automagiczną - czas potrzebny na odtworzenie pozostałej części sampla. Jest to właśnie przyczyną dla której słyszymy całego sampla kiedy nie ustawimy żadnej wartości dla fazy podtrzymania. Jeśli domyślne wartości dla parametrów ataku, opadania, podtrzymania i zanikania były ustawione na 0 nigdy nie usłyszelibyśmy nawet jednego piknięcia. Sonic Pi sam oblicza jak długi jest czas trwania sampla, obcina fazy ataku, opadania oraz zanikania i używa wyniku jako czasu dla fazy podtrzymania. Jeśli wartości podane dla ataku, opadania lub zanikania po zsumowaniu dają wartość większą od czasu trwania sampla, to faza podtrzymania otrzymuje po prostu wartość 0.

Płynne Zanikanie (Fade Outs)

Aby to zbadać, przyjrzyjmy się bardziej szczegółowo naszej pętli Amen Loop. Jeśli zapytamy Sonic Pi o to jak długo trwa ten sampel:

print sample_duration :loop_amen

To wyświetli liczbę 1.753310657596372 i jest ona długością sampla wyrażoną w sekundach. Dla wygody zaogrąglijmy ją tutaj do wartości 1.75. Teraz, jeśli ustawimy fazę zanikania (release) na wartość 0.75 to wydarzy się coś niespodziewanego:

sample :loop_amen, release: 0.75

Pierwsza sekunda sampla zostanie zagrana z pełną amplitudą po czym zacznie stopniowo zanikać przez okres 0.75 sekundy. To jest właśnie auto sustain w akcji (automatyczne ustawianie czasu trwania dla fazy podtrzymania). Domyślnie, faza zanikania (release) zawsze działa (jest ustawiana) od końca sampla. Jeśli nasz sample trwałby 10.75 sekundy, to najpierw pierwszye 10 sekund zostałoby zagrane z pełną amplitudą, po czym zaczęłoby się stopniowe zanikanie (fade out), trwające przez 0.75s.

Zapamiętaj: domyślnie, faza zanikania (release:) wchodzi pod koniec sampla.

Wejście i Wyjście (Fade In i Fade Out)

Możemy używać jednocześnie parametrów dla ustawiania fazy ataku attack: oraz fazy zanikania release: z wykorzystaniem automatycznego ustawiania fazy podtrzymania (sustain) aby użyć stopniowego pojawienia się i stopniowego zanikania przez cały czas trwania sampla:

sample :loop_amen, attack: 0.75, release: 0.75

Jako, że pełny czas trwania naszego sampla to 1.75s, a nasze fazy ataku i zanikania dają w sumie 1.5 s, to czas trwania fazy podtrzymania (sustain) automagicznie ustawia się na wartość 0.25s. Pozwala nam to na łatwe tworzenie łagodnych wejść i wyjść w samplach.

Sprecyzowana faza podtrzymania (sustain)

Możemy bardzo łatwo przywrócić normalne zachowanie ADSR znane z syntezatorów poprze manualne ustawienie wartości parametru sustain: na wartość 0:

We can easily get back to our normal synth ADSR behaviour by manually setting sustain: to a value such as 0:

sample :loop_amen, sustain: 0, release: 0.75

Teraz nasz sampel zostanie zagrany tylko przez 0.75 sekundy w sumie. Używająć domyślnych wartości dla parametrów ataku attack: i opadania decay: na poziomie 0, sampel przeskakuje bezpośrednio do pełnej amplitudy, przechodzi w fazę podtrzymania na 0s po czym zanika z powrotem do amplitudy równej zero przy czym czas zanikania to 0.75s.

Talerze perkusyjne

Możemy wykorzystać to zachowania aby uzyskać dobry efekt sprawiając, że sample trwające dłużej będą krótsze, bardziej perkusyjne. Przyjrzyjmy się samplowi :drum_cymbal_open:

sample :drum_cymbal_open

Słyszysz dźwięk talerza, który brzmi przez chwilę. Możemy jednak skorzystać z naszej obwiedni aby sprawić by ten dźwięk stał się bardziej perkusyjny:

sample :drum_cymbal_open, attack: 0.01, sustain: 0, release: 0.1

Następnie możesz spróbować zasymulować uderzenie w talerz i stłumienie go poprzez zwiększenie wartości parametru podtrzymania:

sample :drum_cymbal_open, attack: 0.01, sustain: 0.3, release: 0.1

A teraz spróbuj się pobawić nakładająć obwiednie na sample. Próbuj zmieniać wartości różnych parametrów obwiedni aby otrzymać ciekawe rezultaty.


3.5 - Kawałki Sampli

Ta sekcja sfinalizuje nasze odkrywanie odtwarzacza sampli dostępnego w Sonic Pi. Zróbym szybkie podsumowanie. Do tej pory wiemy już w jaki sposób uruchamiać sample:

sample :loop_amen

Następnie dowiedzieliśmy się w jaki sposób można zmieniać parametry sampli, np. w jaki sposób możemy zagrac wybraną próbke w tempie równym połowie normalnego:

sample :loop_amen, rate: 0.5

Kolejną rzeczą jakiej się nauczyliśmy była umiejętność stopniowego wchodzenia sampla (spróbujmy zrobić to dla sampla zagranego w połowie jego normalnego tempa):

sample :loop_amen, rate: 0.5, attack: 1

Dowiedzieliśmy się również, że za pomocą podania konkretnych krótkich wartości dla parametrów podtrzymania sustain: oraz ataku możemy uzyskać perkusyjne brzmienie:

sample :loop_amen, rate: 2, attack: 0.01, sustain: 0, release: 0.35

Jednakże, czy nie było by fajnie gdybyśmy nie musieli zawsze zaczynać odtwarzania sampla od jego początku? Czy nie było by fajnie gdybyśmy nie musieli też zawsze kończyć odtwarzania sampla dopiero w momencie jego końca?

Wybór momentu startu

Możliwe jest wybranie bezwzględnego momentu startu, od którego uruchomimy sampel za pomocą podania liczby o wielkości od 0 do 1, gdzie 0 to początek sampla, 1 oznacza koniec sampla, a 0.5 to połowa sampla. Spróbujmy zagrać tylko drugą połowę sampla amen break:

sample :loop_amen, start: 0.5

A teraz spróbujmy zagrać ostatnią ćwiartke sampla:

sample :loop_amen, start: 0.75

Wybór momentu zakończenia

Analogicznie, jest również możliwy wybór bezwzględnego momentu końca odtwarzania sampla za pomocą wartości pomiędzy 0 a 1. Spróbujmy skończyć sampel amen break w połowie czasu:

sample :loop_amen, finish: 0.5

Ustawianie startu i zakończenia

Nic nam nie stoi na przeszkodzie, abyśmy połączyli oba powyższe parametry aby zagrać wybrane kawałki z danego sampla. Co powiesz na wycięcie tylko małego kawałka ze środka:

sample :loop_amen, start: 0.4, finish: 0.6

Co się stanie jeśli ustawimy moment startu tak aby znajdował się po momencie końca?

sample :loop_amen, start: 0.6, finish: 0.4

Świetnie! Wybrany kawałek jest odtwarzany od końca!

Łączenie z tempem

Możemy teraz połączyć tę nową możliwość odtwarzania wybrancyh części dźwięku z naszym startym dobrym znajomym parametrem tempa rate:. Na przykład, możemy zagrać bardzo mały kawałek ze środka sampla amen break w bardzo wolnym tempie:

sample :loop_amen, start: 0.5, finish: 0.7, rate: 0.2

Łączenie z obwiedniami

Na sam koniec, możemy połączyć wszytkie powyższe możliwości z naszą obwiednią ADSR aby wyprodukować bardzo ciekawe rezultaty:

sample :loop_amen, start: 0.5, finish: 0.8, rate: -0.2, attack: 0.3, release: 1

A teraz idź i spróbuj pobawić się zmieniając sample wykorzystując cały ten kram…


3.6 - Sample Zewnętrzne

Podczas gdy wbudowane sample pomogą Ci zacząć dość szybko, być może chciałbyś poeksperymentować z innymi nagraniami, które posiadasz w swojej bibliotece muzycznej. Sonic Pi całkowicie to wspiera. Zanim jednak pokażemy jak można tego dokonać, przeprowadźmy krótką dyskusję dotyczącą przenośności twoich utworów.

Przenośność

Kiedy komponujesz twoje utwory opierając się tylko i wyłącznie na wbudowanych syntezatorach i samplach, kod jest jedyną rzeczą, która jest niezbędna aby wiernie odtworzyć twoją muzykę. Pomyśl o tym przez chwilę - to jest niesamowite! Prosty kawałek tekstu, który możesz wysłać pocztą lub trzymać jako Gist przedstawia wszystko czego potrzebujesz aby odtworzyć twoje kawałki. Takie podejście sprawia, że dzielenie się tą muzyką z twoimi znajomymi jest naprawdę proste, gdyż jedyne co muszą zrobić to zdobyć kod.

Jednakże, gdy zaczniesz używać swoich własnych sampli, stracisz tę przenośność. Stanie się tak dlatego, że do odtworzenia twojej muzyki inni ludzie będą potrzebować nie tylko twojego kodu, będą potrzebować również twoich sampli. Takie podejście ogranicza innymi możliwość manipulowania, zmieniania i eksperymentowania z twoją pracą. Oczywiście nie powinno to powstrzymać Cię od używania własnych sampli, to tylko coś co musisz wziąć pod uwagę, gdy się na to zdecydujesz.

Sample Lokalne

W jaki sposób możesz więc zagrać dowolny plik WAV lub AIFF, który znajduje się na twoim komputerze? Jedyne co musisz zrobic to przekazać ścieżkę do tego pliku do polecenia sample:

sample "/Users/sam/Desktop/my-sound.wav"

Sonic Pi automatycznie załaduję i zagra wybrany sampel. Możesz również przekazać wszystkie standardowe parametry, które do tej pory przekazywałeś do polecenia sample:

sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3

4 - Losowość

Wspaniałym sposobem aby dodać odrobine intrygi do twojej muzyki, jest wykorzystanie paru losowych liczb. Sonic Pi posiada parę fajnych funkcjonalności, które umożliwiają dodanie przypadkowości do twojej muzyki. Zanim jednak zaczniemy musimy nauczyć się jednej szokującej prawdy: w Soni Pi losowość nie jest tak naprawdę losowa. Co to do diaska znaczy? No cóż, zobaczmy.

Powtarzalność

Bardzo przydatną funkcją do generowania liczb losowych jest rrand, która zwróca losową wartość pomiędzy dwoma liczbami - minimum min i maksimum max. (rrand to skrót od angielskiego ranged random - liczba losowa z określonego przedziału). Spróbujmy zagrać losową nutę:

play rrand(50, 100)

Oh, została zagrana losowa nuta. Zagrana nuta to 77.4407. Fajna liczba losowa pomiędzy 50 a 100. Zaraz zaraz, czy przypadkiem nie zgadłem dokładnej wartości losowej nuty, którą przed chwilą otrzymałeś? Dzieje się tu coś podejrzanego. Spróbuj uruchomić kod ponownie. I co? Znowu została wybrana liczba 77.4407? Toć to nie jest liczba losowa!

Odpowiedzią jest fakt, że tak naprawde wynik nie jest naprawdę losowy, jest pseudo losowy. Sonic Pi wygeneruje dla Ciebie liczby, które wyglądają jak losowe w sposób powtarzalny. Takie podejście jest bardzo przydatne jeśli chcesz być pewny, że muzyka, którą tworzysz na swojej maszynie będzie brzmieć identycznie na każdym innym komputerze - nawet jeśli używasz w swojej kompozycji pewnej losowości.

Oczywiście, jeśli w danym utworze, ta ‘losowo wybrana liczba’ będzie za każdym razem miała wartość 77.4407, to nie będzie to zbyt interesujące. Jednakże jest inaczej. Spróbój poniższego kawałka kodu:

loop do
  play rrand(50, 100)
  sleep 0.5
end 

Tak! Wreszcie uzyskaliśmy losowe dźwieki. W ramach danego uruchomienia kolejnych wywołań funkcji losującej zostaną zwrócone wartości losowe. Jendakże, kolejne uruchomienie spowoduje wyprodukowanie dokładnie takiej samej sekwencji losowych wartości i brzmienie będzie takie same jak przy pierwszym uruchomieniu. To tak jakby cały kod Sonic Pi cofnął się w czasie dokładnie do tego samego punktu za każdym razem gdy zostaje wciśnięty przycisk Run (Uruchom). Toć to Dzien Świstaka dla syntezy muzycznej!

Haunted Bells (Nawiedzone Dzwony)

Piękną ilustracją randomizacji w akcji jest przykład nawiedzonych dzwonów (Haunted Bells), który zapętla sampel :perc_bell nadając mu przy tym losowe tempo (parametr rate) oraz czas przerwy (polecenie sleep) pomiędzy poszczególnymi dźwiękami dzwonów:

loop do
  sample :perc_bell, rate: (rrand 0.125, 1.5)
  sleep rrand(0.2, 2)
end

Losowe odcięcie

Innym ciekawym przykładem losowości jest modyfikacja odcięcia syntezatora losowo. Świetnym syntezatorem, na którym możemy tego spróbować jest syntezator emulujący :tb303:

use_synth :tb303

loop do
  play 50, release: 0.1, cutoff: rrand(60, 120)
  sleep 0.125
end

Losowe zarzewie

A co, jeśli nie podoba Ci się ta konkretna sekwencja liczb losowych, które generuje Sonic Pi? Nic nie stoi na przeszkodzie abyś wybrał inny punkt rozpoczęcia za pomocą polecenia use_random_seed. Domyślną wartością dla funkcji odsiewu (seed?) jest 0, wystarczy więc wybrać inną wartość aby uzyskać inne wartości losowe.

Weźmy pod uwagę poniższy przykład:

5.times do
  play rrand(50, 100)
  sleep 0.5
end

Za każdym razem gdy uruchomisz powyższy kod, usłyszysz sekwencję tych samych 5 nut. Aby uzyskać inną sekwencję wystarczy zmienić wartość odsiewu (?seed):

use_random_seed 40
5.times do
  play rrand(50, 100)
  sleep 0.5
end

Spowoduje to wygenerowanie sekwencji 5 innych losowych nut. Zmieniając parametr odsiewu (?seed) i słuchając wyników jakie to spowodowało, możesz w końcu znaleźć taka sekwencję, która Ci się spodoba - a gdy wtedy podzielisz się nią z innymi, usłyszą oni dokładnie to samo co ty.

A teraz przyjrzyjmy się kilku innym, przydatnym funkcją generującym wartości losowe.

choose (wybierz)

Bardzo popularną rzeczą jest wybór losowego obiektu z listy znanych nam obiektów. Na przykład, mogę chcieć zagrać jedną z następujących nut: 60, 65 lub 72. Żeby to osiągnąć mogę użyć funkcji choose, która pozwala mi na wybór jednego obiektu z istniejącej listy obiektów. Po pierwsze, muszę wsadzić moje liczby (nuty) do listy. Aby tego dokonać wystarczy, że opakujemy nasze liczby w nawiasy kwadratowe i oddzielimy każdą z nich przecinkiem: [60, 65, 72]. Następnie wystarczy przekazać je jako parametr do polecenia choose:

choose([60, 65, 72])

Posłuchajmy zatem jak to brzmi:

loop do
  play choose([60, 65, 72])
  sleep 1
end

rrand

Widzieliśmy już w akcji funkcję rrand, ale spróbujmy uruchomić ją raz jeszcze. Zwraca ona losową liczbę z podanego przedziału, który jest w tym wypadku przedziałem otwartym. Oznacza to, że żadna z podanych liczb jako wartości minimalna i maksymalna nigdy nie zostanie zwrócona - zawsze coś pomiędzy tymi dwoma liczbami. Zwrócona liczba będzie liczbą zmiennoprzecinkową - oznacza to, że nie jest to liczba całkowita tylko ułamek. Oto kilka przykładów liczb zmiennoprzecinkowych zwracanych przez polecenie rrand(20,110):

rrand_i

Sporadycznie może się zdarzyć, że będziesz potrzebował liczbę losową, która jest liczbą całkowitą, a nie zmiennoprzecinkową. W tym przypadku z pomocą przychodzi polecenie rrand_i. Polecenie to działa bardzo podobnie do rrand, z tą jednak różnicą, że może zwracać teź liczbę minimalną i maksymalną z podanego przedziału jako potencjalna wartość losowa (co oznacza, że podawany przedział jest domknięty, a nie otwarty). Poniżej przykłady liczb losowych, które mogą zostać zwrócone przez polecenie rrand_i(20,110):

rand

Te polecenie zwraca losową liczbę zmiennoprzecinkową pomiędzy 0 (przedział domknięty) a maksymalną liczbą, którą podajesz jako parametr (przedział otwarty). Domyślnie (jeśli nie podamy parametru) zostanie zwrócona liczba z przedziału od 0 do 1. Warto zauważyć, że polecenie to może być bardzo użyteczne do ustawiania losowego poziomu poziomu amplitudy amp:

loop do
  play 60, amp: rand
  sleep 0.25
end

rand_i

Przy tym poleceniu mamy relację podobną jak w przypadku poleceń rrand_i i rrand. Polecenie rand_i zwraca losową liczbę całkowitą z zakresu od 0 do maksymalnej wartości, którą podasz.

dice

Czasami chciałbyś zasymulować rzut kostką - jest to specyficzny przypadek dla polecenia rrand_i, dla którego najniższa liczba to zawsze 1. Uruchomienie polecenia rzut kostką dice wymaga abyś podał liczbę oczek na kostce. Standardowa kostka ma 6 oczek, więc polecenie dice(6) zachowa się bardzo podobnie - każde uruchomienie będzie zwracać jedną z wartości 1, 2, 3, 4, 5 lub 6. Jednakże, tak damo jak w grach RPG (role-playing games), może się zdarzyć, że będziesz potrzebować kostki o 4 oczkach, albo o 12, albo o 20 - być może będziesz potrzebować nawet kostki która będzie miała 120 oczek!

one_in

Na koniec może się zdarzyć, że będziesz chciał zasymulować wyrzucenie najlepszego wyniku dla danej kostki, np. 6 oczek dla standardowej kostki. Polecenie one_in zwraca prawdę (true) z prawdopodobieństwem, że zostało wyrzucone jedno oczko. Idąc dalej polecenie one_in(6) zwróci prawdę (true) z prawdopodobieństwem 1 do 6-sciu lub fałsz. Wartości prawda (true) i fałsz (false) są bardzo przydatne przy korzystaniu z polecenie warunkowego if, które omówimy w jednej z kolejnych sekcji tego tutoriala.

A teraz, spróbuj trochę zagmatwać twój kod i muzykę odrobiną losowości!


5 - Konstrukcje Programistyczne

Teraz, kiedy nauczyłeś się podstaw tworzenia dźwięków z wykorzystaniem poleceń play i sample oraz utworzyłeś swoje pierwsze proste melodie i rytmy korzystając z polecenia sleep do tworzenia odstępów między poszczególnymi dźwiękami, zastanawiasz się zapewne co takiego może Ci jeszcze zaoferować świat kodowania…

Dobrze, jesteś przygotowany na ekscytującą ucztę. Okazuje się, że proste konstrukcje programistyczne, takie jak pętle (looping), instrukcje warunkowe, funkcje mogą stać się dla Ciebie niesamowicie potężnymi narzędziami do wyrażenia twoich muzycznych pomysłów.

Zakasaj rękawy i zabieramy się do podstaw…


5.1 - Bloki kodu

Struktura, którą będzie Ci dane zobaczyć w Sonic Pi niezwykle często to blok kodu. Bloki pozwalają nam na robienie wielu przydatnych rzeczy z dużymi kawałkami kodu. Na przykład, w przypadku parametrów syntezatorów i sampli byliśmy w stanie zmieniać coś co działo się w obrębie jednej linii. Jednakże, czasami chcielibyśmy zrobić coś znaczącego dla kilku linii kodu. Na przykład, chcielibyśmy zapętlić coś, potem nałożyć na to efekt reverb, tak, żeby uruchomił się tylko przy 1-wszym przebiegu pętli z wszystkich 5-ciu, itd. Przyjrzyj się poniższemu kawałkowi kodu:

play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62

Abyśmy mogli zrobić coś z kawałkiem kodu, musimy powiedzieć Sonic Pi gdzie zaczyna się i kończy dany blok kodu. Aby określić początek takiego bloku używamy polecenia do, natomiast polecenie end służy do określenia gdzie dany blok się kończy. Na przykład: do

do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Jednakże, nie jest to jeszcze całość i nie zadziała (spróbuj uruchomić powyższy kod a zobaczysz błąd) poneważ nie powiedzieliśmy jeszcze Sonic Pi co chcielibyśmy zrobić z naszym blokiem zawartym pomiędzy poleceniami do/end. Aby powiedzieć Sonic Pi co chcemy zrobić z tym kawałkiem musimy napisać kawałek specjalnego kodu przed poleceniem do. Zobaczysz jeszcze wiele takich różnych specjalnych kawałków kodu w kolejnych sekcjach tego samouczka. Na razie, najważniejsze jest abyś wiedział, że umieszczenie twojego kodu pomiędzy polecenia do i end mówi Sonic Pi, że chciałbyś zrobić z tym kawałkiem kodu coś specjalnego.


5.2 - Iteracja i Pętle

Do tej pory spędziliśmy sporo czasu patrząc na różne dźwięki, które możesz zrobić użyciem bloków play i sample. Nauczyliśmy się również w jaki sposób uruchamiać te dźwięki na przestrzeni czasu używając polecenia sleep.

Jak zapewne już zauważyłeś, przy korzystaniu z tych kilku podstawowych bloków możesz mieć całą masę frajdy. Jednakże, kiedy zaczniesz wykorzystywać możliwości kodu do porządkowania twojej muzyki i kompozycji, twoim oczom ukaże się zupełnie nowy wymiar możliwości i zabawy. W najbliższych kilku sekcjach poznasz kilka z tych potężnych narzędzi. Na początek zaczniemy od iteracji i pętli.

Powtórzenie

Czy zdarzyło ci się napisać kawalek kodu, który chciałbyś powtórzyć kilka razy? Przypuścmy, że napisałeś coś w tym stylu:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Co jeśli chciałeś aby powyższy kawałek powtórzył się 3 razy? Najprostsze co mógłbyś zrobić to po prostu skopiować i wkleić powyższy kawałek kodu trzy razy:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Zobacz ile kodu! Pomyśl, co trzeba by było zrobić, gdybys chciał zmienić sampel na :elec_plip? Musiałbyś wtedy znaleźć w kodzie wszystkie miejca gdzie użyłeś oryginalnego sampla :elec_blup a zmienić je ręcznie. Ale to i tak nic, pomyśl co by było gdybyś chciał powtórzyć oryginalny blok kodu 50 albo 1000 razy? Dopiero teraz byłoby to dużo kodu, bardzo dużo kodu, który musiałbyś zmienić, gdybyć chciał dokonać tak prostej zmiany jak przełączenie się na inny sampel.

Iteracja

W rzeczywistości, powtórzenie kodu powinno być tak proste jak powiedzenie zrób to trzy razy. Dobrze, w dużym stopniu tak jest. Pamiętasz naszego starego dobrego znajomego - blok kodu? Możemy użyć go aby zaznaczyć miejsce początku i końca kodu, który chcielibyśmy powtórzyć 3 razy. Następnie wystarczy, że użyjemy specjalnego kawałka kodu 3.times (3.razy). Zamiast więc napisać zrób to trzy razy, napiszemy 3.times do - to nie jest zbyt trudne. Pamiętaj tylko aby napisać polecenie end na końcu bloku kodu, który zamierzać powtórzyć:

3.times do
  play 50
  sleep 0.5
  sample :elec_blup
  sleep 0.5
  play 62
  sleep 0.25
end

Przyznasz, że takie podejście jest dużo bardziej eleganckie niż kopiowanie i wklejanie! Możemy użyć tego specjalnego polecenia to tworzenia wielu fajnych powtarzających się struktur:

4.times do
  play 50
  sleep 0.5
end

8.times do
  play 55, release: 0.2
  sleep 0.25
end

4.times do
  play 50
  sleep 0.5
end

Zagnieżdżanie Iteracji

Możemy umieszczać jedne iteracje wewnątrz innych iteracji to utworzenia ciekawych wzorców. Na przykład:

4.times do
  sample :drum_heavy_kick
  2.times do
    sample :elec_blip2, rate: 2
    sleep 0.25
  end
  sample :elec_snare
  4.times do
    sample :drum_tom_mid_soft
    sleep 0.125
  end
end

Zapętlanie

Jeśli chcesz powtórzyć coś wiele razy, możesz złapać się na tym, że będziesz podawał naprawdę bardzo duże liczby jako parametr iteracji, na przykład 1000.times do. W takim przypadku zapewne dużo lepiej byłoby poprosić Sonic Pi aby powtarzać dany wzorzec w nieskończoność (a przynajmniej do momentu w którym naciśniesz przycisk Stop aby zatrzymać odtwarzanie!). Spróbujmy zapętlić w nieskończoność sampel Amen Break:

loop do
  sample :loop_amen
  sleep sample_duration :loop_amen
end

Bardzo ważną rzeczą do zapamiętania o pętlach jest to, że dla kodu mają one takie same zachowanie jak czarne dziury. Jak tylko kod raz już wejdzie w daną pętlę może już jej nigdy nie opuścić, chyba że naciśniesz przycisk Stop - nasza pętla będzie się kręcić w kółko w nieskończoność. Oznacza to, że jeśli masz jakiś kod, który jest umieszczony po pętli, to nigdy go nie usłyszysz. Na przykład, talerz, który znajduje się poniżej poniższej pętli nie zostanie zagrany nigdy:

loop do
  play 50
  sleep 1
end

sample :drum_cymbal_open

A teraz, spróbuj poprawić strukturę twojego kodu za pomocą iteracji i pętli!


5.3 - Instrukcje Warunkowe

Bardzo prawdopodobne jest, że często będziesz chciał zagrać nie tylko losową nutę (patrz poprzednia sekcja dot. losowości) lecz również będziesz chciał podejmować losowe decyzje i na podstawie ich wyniku będziesz chciał uruchomić taki lub inny kod. Na przykład, mógłbyś chcieć aby losowo zagrać bęben lub talerz perkusji. Możemy tego dokonać używając polecenia warunkowego if (jeśli).

Rzut Monetą

Spróbujmy rzucić monetą: jeśli (if) wypadnie orzeł, zagraj bęben, jeśli wypadnie reszka reszka (else), zagraj talerz. Proste. Możemy zasymulować rzut monetą wykorzystując naszą funkcję one_in (poznaliśmy ją w sekcji dotyczącej losowości) określając prawdopodobieństwo wyboru 1 z 2: one_in(2). Następnie możemy użyć tego wyniku aby wybrać do zagrania jeden z dwóch kawałków kodu - jeden, który zagra bęben i drugi, który zagra talerz:

loop do

  if one_in(2)
    sample :drum_heavy_kick
  else
    sample :drum_cymbal_closed
  end
  
  sleep 0.5
  
end

Zauważ, że polecenie warunkowe if posiada 3 części:

Zazwyczaj w językach programowania, pojęcie odpowiedzi tak jest reprezentowane przez termin true (prawda), natomiast pojęcie odpowiedzi nie jest reprezentowane przez termin false' (nieprawda, fałsz). Do nas więc należy znalezienie odpowiedniego pytania, którego zadanie zwróci nam odpowiedź true (prawda) lub false (fałsz). W tym wypadku naszym pytaniem jest uruchomienie funkcji one_in`.

Zauważ, że pierwszy wybór jest wpasowany pomiędzy polecenia if (jeśli) a else (w przeciwnym razie), natomiast drugi wybór mieści się pomiędzy poleceniami else i end (koniec). Tak samo jak w przypadku bloków kodu do/end, pomiędzy obiema tymi przestrzeniami możesz napisać wiele linii kodu. Oto przykład:

loop do

  if one_in(2)
    sample :drum_heavy_kick
    sleep 0.5
  else
    sample :drum_cymbal_closed
    sleep 0.25
  end
  
end

Tym razem, w zależności od tego jaka decyzja została wylosowana śpimy (sleep) przez różnie długości czasu.

Proste polecenie if

Czasami chciałbyś wykonać opcjonalnie tylko jedną określoną linię kodu. Aby to osiągnąć wystarczy umieścić polecenie if wraz z naszym pytaniem (warunkiem) na końcu tej linii. Oto przykład:

use_synth :dsaw

loop do
  play 50, amp: 0.3, release: 2
  play 53, amp: 0.3, release: 2 if one_in(2)
  play 57, amp: 0.3, release: 2 if one_in(3)
  play 60, amp: 0.3, release: 2 if one_in(4)
  sleep 1.5
end

Powyższy kod zagra akordy złożone z różnych liczb. Szansa na to, że każda z podanych nut zostanie zagrana jest różna, gdyż każda z linijek (oprócz pierwszej) jest opatrzona warunkiem o różnym prawdopodobieństwie wystąpienia.


5.4 - Wątki

A więc udało Ci się przygotować zabójczy bassline oraz tłusty beat. W jaki sposób udaje Ci się je zagrać w tym samym czasie? Jednym z możliwych rozwiązań jest przeplecenie ich razem ręcznie - najpierw zagrać jakis 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 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, które znajdują 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 Run, to w rzeczywistości tworzysz nowy wątek do uruchomienia twojego kodu. Dlatego też, gdy naciśniesz przycisk uruchom wiele razy to 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, nauczysz się 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 wszsystkie 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ś, że druga nuta zostaje zagrana z użyciem syntezatora :tb303 mimo to, że została zagrana z oddzielnego wątku? Każde ustawienie zmienione przy użyciu różnych funkcji use_* będą 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

Na koniec, 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ę

Jedną ostatnią już rzecz, którą powinieneś wiedzieć o wątkach posiadających swoją nazwę to to, że 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

Sróbuj śmiało wkleić powyższy kod do obszaru roboczego i naciśnij przycisk Run. Następnie naciśnij go jeszcze kilka razy. Usłyszysz kakofonię wielu zapętlonych w czasie sampli Amen Break. Ok, możesz teraz nacisnać przycisk Stop.

To jest zachowanie, które widzieliśmy już nie raz - jeśli naciśniesz przycisk Run, dźwięk zostanie nałożony na istniejące już dźwięki. Dlatego jeśli masz pętle i naciśniesz przycisk Run trzy raz, 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 Run 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 wydawac do niczego przydatne - ale będzie bardzo przydatne kiedy zaczniemy kodować na żywo…


5.5 - Funkcje

Gdy już zaczniesz pisać znaczne ilości kodu, to w pewnym momencie będziesz chciał znaleźć sposób aby uporządkować i poukładać go tak aby był one elegancki i łatwiejszy do zrozumienia. Funkcje są bardzo skutecznym sposobem, który to umożliwia. Pozwalają nam nadać kawałkowi kodu nazwę. Rzućmy na to okiem.

Definiowane Funkcji

define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end

W powyższym przykładzie zdefiniowaliśmy nową funkcję zwaną foo. Zrobiliśmy to używając naszego dobrego znajomego bloku do/end oraz magicznego słowa define, po którym podaliśmy nazwę, którą chcemy nadać naszej funkcji. Nie musieliśmy nazywać jej foo, mogliśmy nazwać ją jak tylko mamy ochotę, np. bar, baz albo idealnie pasowałoby, gdybyśmy nadali jakąs nazwę, która coś znaczy, np. czesc_glowna albo glowna_gitara.

Pamiętaj tylko aby poprzedzić nazwę dwukropkiem : gdy definiujesz nową funkcję.

Uruchamianie Funkcji

Skoro już udało się nam zdefiniować naszą funkcję, możemy uruchomić ją wpisując jej nazwę:

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end

foo

sleep 1

2.times do
  foo
end

Możemy użyć naszej funkcji foo wewnątrz bloku iteracji albo gdziekolwiek indziej, gdzie mogliśmy do tej pory używać polecenia play i sample. Pozwala nam to w bardzo fajny sposób na wyrażanie siebie i na tworzenie nowych słów, które znaczą coś nowego i używanie ich w naszych kompozycjach.

Funkcje są zapamiętywane pomiędzy poszczególnymi uruchomieniami

Jak do tej pory, za każdym razem gdy nacisnąłeś przycisk Run, Sonic Pi zaczynał od czystej tablicy. Nie wiedział nic poza tym co znajduje się aktualnej przestrzeni roboczej. Nie możesz odnosić się do kodu w innych przestrzeniach roboczych lub innym wątku. Możliwość korzystania z funkcji zmienia to. Kiedy zdefiniujesz funkcję, Sonic Pi zapamiętuje ją. Spróbujmy to wykorzystać. Usuń cały kod znajdujący się w twojej aktualnej przestrzeni roboczej i zastąp go następującą linią:

foo

Naciśnij przycisk Run - usłyszysz jak gra twoja funkcja. Skąd się wziął ten kod? Skąd Sonic Pi wiedział co powinien zagrać? Sonic Pi po prostu zapamiętał wcześniej twoją funkcję - więc nawet po tym jak już ją skasujesz z twojej przestrzeni roboczej, to będzie on pamiętał to co wcześniej napisałeś. Ten mechanizm działa tylko z funkcjami stworzonymi z wykorzystaniem polecenia define (oraz defonce).

Funkcje z Parametrami

Być może zainteresuje Cie fakt, że tak samo jak możesz przekazywać wartości minimalną (min) i maksymalną (max) do funkcji rrand, tak samo możesz nauczyć twoją funkcję aby potrafiła przyjmować różne argumenty. Spójrzmy na następujący kod:

define :my_player do |n|
  play n
end

my_player 80
sleep 0.5
my_player 90

Nie jest on za bardzo ekscytujący, ale świetnie przedstawia o co chodzi. Stworzyliśmy naszą własną wersję polecenia play, która przyjmuje parametr i nazwaliśmy ją my_player.

Parametry należy umieścić tuż za poleceniem do bloku kodu define, otoczyć pionowymi kreskami | oraz oddzielić przecinkami ,. Możesz użyć dowolnego słowa jakiego chcesz dla nazw parametrów.

Magia dzieje się w środku bloku do/end define. Możesz używać nazw parametrów tak jak byłyby prawdziwymi wartościami. W powyższym przykładzie gram nutę n. Możesz patrzeć na parametry jak na swego rodzaju obietnice, która mówi o tym, że gdy kod zostanie uruchomiony, to zostaną one zastąpione aktualnymi wartościami. Możesz to zrobić poprzez przekazanie parametru do funkcji gdy ją uruchamiasz. Uruchamiam polecenie my_player 80 aby zagrać nutę 80. Wewnątrz definicji funkcji, n zostanie zamienione na 80, więc polecenie play n przemieni się w play 80. Kiedy uruchomię ją ponownie w taki sposób my_player 90, to teraz n zostanie zastąpione przez 90, więc polecenie play n będzie zmieni się teraz w polecenie play 90.

Przyjrzyjmy się teraz bardziej interesującemu przykładowi:

define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end

chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3

Użyłem tutaj parametru repeats w linii repeats.times do tak jakby był liczbą. Użyłem również parametru root dla polecenia play tak, jakby był normalną nazwą nuty.

Zauważ, że poprzez przeniesienia dużej ilości logiki do funkcji, jesteśmy teraz w stanie napisać coś bardzo ekspresyjnego a zarazem łatwego do przeczytania!


5.6 - Zmienne

Przydatną rzeczą, którą możesz robić w swoim kodzie jest tworzenie nazw dla różnych rzeczy. Sonic Pi sprawia, że jest to bardzo łatwe, wpisujesz nazwę, której chciałbyś użyć, znak równości (=), następnie rzecz, którą chcialbyś zapamiętać:

sample_name = :loop_amen

W powyższym kawałku kodu ‘zapisaliśmy’ wartość symbolu :loop_amen w zmiennej sample_name. Od teraz możemy używać nazwy sample_name wszędzie, gdzie do tej pory użylibyśmy sampla :loop_amen. Na przykład:

sample_name = :loop_amen
sample sample_name

Są trzy podstawowe powody na korzystanie ze zmiennych w Sonic Pi: komunikowanie znaczenia, zarządzanie powtórzeniami oraz przechwytywanie wyników różnych rzeczy.

Komunikowanie Znaczenia

Kiedy piszesz kod łatwo jest myśleć, że jedyne co robisz to mówisz komputerowi jak ma wykonać jakieś rzeczy - tak długo jak komputer rozumie co do niego mówisz to jest w porządku. Jednakże, ważne jest aby pamiętać że nie tylko komputer czyta kod. Inni ludzie również mogą chcieć przeczytać go i spróbować zrozumieć co się w nim dzieje. Ponadto, bardzo prawdopodobne, że Ty również będziesz czytał swój własny kod w przyszłości i próbował zrozumieć o co w nim chodzi. Chociaż w tej chwili jego znaczenie może być dla Ciebie oczywiste - może nie być takie oczywiste dla innych lub nawet dla Ciebie samego w przyszłości!

Jedną z metod, która pomoże innym zrozumieć co twój kod robi jest pisanie komentarzy (co widzieliśmy już we wcześniejszej sekcji tego samouczka). Inną jest używanie takich nazw dla zmiennych, które coś znaczą. Spójrz na poniższy kod:

sleep 1.7533

Dlaczego używa on liczby 1.7533? Skąd wzięła się ta liczba? Co ona oznacza? A teraz, spójrz na poniższy kod:

loop_amen_duration = 1.7533
sleep loop_amen_duration

Teraz, zrozumienie tego co oznacza liczba 1.7533 jest znacznie prostsze: oznacza ona dłuość trwania sampla :loop_amen! Oczywiście, możesz zapytać, dlaczego po prostu nie napisaliśmy:

sleep sample_duration(:loop_amen)

Co, jak najbardziej, jest bardzo fajnym sposobem zakomunikowania intencji zawartych w kodzie.

Zarządzanie Powtórzeniami

Często widzisz dużo powtórzeń w twoim kodzie i kiedy chcesz coś zmienić, musisz zmienić to w wielu miejscach. Spójrz na poniższy kawałek kodu:

sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)

Robiliśmy tutaj sporo rzeczy z samplem :loop_amen! Co jeśli chcielibyśmy usłyszeć, jak ten kawałek kodu brzmi z innym samplem, na przykład :loop_garzul? Musielibyśmy wtedy znaleźć i zamienić wszystkie wystąpienia sampla :loop_amen na :loop_garzul. To może być całkiem w porządku jeśli masz dużo czasu - ale co jeśli właśnie występujesz na scenie? Czasami nie masz tego luksusu, że masz czasu tyle ile chcesz - zwłaszcza gdy chcesz utrzymać ludzi na parkiecie.

A co jeśli powyższy kawałek kodu przepiszemy na coś takiego:

sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)

Teraz, ten kod robi dokładnie to samo co wcześniejszy (spróbuj). Oprócz tego daje na możliwość zmiany tylko jednej linijki z obecnej sample_name = :loop_amen na sample_name = :loop_garzul aby jednocześnie zmienić brzmienie w wielu miejscach dzięki magii zmiennych.

Przechwytywanie Wyników

I na koniec, dobrą powodem do używania zmiennych jest przechwytywanie wyniku wykonania różnych rzeczy. Na przykład, możesz chcieć robić różne rzeczy z długością trwania sampla:

sd = sample_duration(:loop_amen)

Możemy teraz używać zmiennej sd wszędzie gdzie potrzebujemy użyć długości trwania sampla :loop_amen.

Możliwe, że nawet bardziej ważne jest to, że zmienne pozwalają nam na przechwycenie i zapisanie wyniku uruchomienia polecenia play lub sample:

s = play 50, release: 8

Teraz złapaliśmy i zapamiętaliśmy s jako zmienną, co pozwala nam na kontrolę syntezatora w trakcie jego działania:

s = play 50, release: 8
sleep 2
control s, note: 62

Przyjrzymy się bardziej kontrolowaniu syntezatorów w kolejnej sekcji.


5.7 - Synchronizacja Wątków

Skoro osiągnąłeś już wystarczająco zaawansowane umiejętności kodowania na żywo (live coding) wraz z wykorzystaniem jednocześnie funkcji i wątków, na pewno zauważyłeś już, że bardzo łatwo jest popełnić błąd w jednym z wątków co powoduje, że zostaje on zabity. To nie jest wielka rzecz, ponieważ możesz bardzo łatwo zrestartować wątek poprzez ponowne naciśnięcie przycisku Run. Jednakże, kiedy zrestartujesz wątek to wypadnie on teraz z rytmu oryginalnych wątków.

Odziedziczony Czas

Jak już mówiliśmy wcześniej, nowe wątki tworzone z wykorzystaniem polecenia in_thread dziedziczą wszystkie ustawienia z wątku rodzica. W skład tych ustawień wchodzi też aktualny czas. Oznacza to, że wątki pozostają zawsze w korelacji czasowej kiedy zostaną uruchomione jednocześnie.

Jendakże, kiedy uruchomisz samodzielny wątek, rozpoczyna się on ze swoim własnym czasem i jest mało prawdopodobne, że będzie on w synchronizacji z jakimkolwiek innym uruchomionym aktualnie wątkiem.

Cue (Wskazówka) i Sync (Synchronizacja)

Sonic Pi udostępnia rozwiązanie dla tego problemu za pomocą funkcji cue (wskazówka) i sync (synchronizacja).

cue pozwala nam na wysłanie wiadomości o pulsie to wszystkich innych aktualnie uruchomionych wątków. Domyślnie inne wątki nie są tym zainteresowane i ignorują tę wiadomość o pulsie. Jendakże, możesz bardzo łatwo wywołać takie zainteresowanie za pomocą funkcji sync.

Ważną rzeczą, której należy być świadomym jest to, że funkcja sync jest podobna do funkcji sleep w taki sposób, że powstrzymuje ona aktualny wątek od robienia czegokolwiek przez pewien okres czasu. Jednakże, w przypadku funkcji sleep musisz zdefiniować jak długo chcesz poczekać, natomiast w przypadku funkcji sync nie wiesz jak długo będziesz chicał poczekać, ponieważ funkcja sync czeka na następny punkt cue z innego wątku, co może nastąpić szybciej lub później.

Spróbujmy przyjrzeć się temu trochę bardziej dokładnie:

in_thread do
  loop do
    cue :tick
    sleep 1
  end
end

in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end

Mamy tutaj dwa wątki - jeden zachowuje się jak metronom, nie gra żadnych dźwięków tylko wysyła komunikat :tik (cyk) przy każdym uderzeniu. Drugi wątek synchronizuje się natomiast przy otrzymaniu każdej kolejnej wiadomości :tick i kiedy otrzymuje kolejną odziedzicza czas uruchomienia cue i rozpoczyna swoje działanie.

Jako wynik słyszymy sampel :drum_heavy_kick dokładnie w tym samym momencie gdy inny wątek wysyła komunikat :tick, nawet jeśli obydwa wątki nie zostały uruchomione w tym samym czasie.

in_thread do
  loop do
    cue :tick
    sleep 1
  end
end

sleep(0.3)

in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end

Te niegrzeczne polecenie sleep normalnie stworzyłoby drugi wątek, który byłby zupełnie niezsynchronizowany z pierwszym. Jednakże, dzięki użyciu poleceń cue i sync automatycznie synchronizujemy wątki blokując jednocześnie jakiekolwiek nieprzewidziane rozjazdy w czasie.

Nazwy dla komunikatów Cue

Dla nazw twoich komunikatów cue możesz używać dowolnych nazw - może to być nie tylko :tick. Musisz się tylko upewnić, że inne wątki synchronizują się z właściwą nazwą - w przeciwnym wypadku będą czekać w nieskończoność (albo do momentu, w którym naciśniesz przycisk Stop).

Spróbujmy pobawić się z kilkoma komunikatami cue o różnych nazwach:

in_thread do
  loop do 
    cue [:foo, :bar, :baz].choose
    sleep 0.5
  end
end

in_thread do
  loop do 
    sync :foo 
    sample :elec_beep
  end
end

in_thread do
  loop do
    sync :bar
    sample :elec_flip
  end
end

in_thread do
  loop do
    sync :baz
    sample :elec_blup
  end
end

Mamy tutaj główną pętlę cue, która co iterację wysyła komunikat z losową wybraną nazwą punktu cue do synchronizacji - :foo, :bar lub :baz. Następnie mamy trzy wątki z pętlami, które synchronizują się na każdym z tych komunikatów niezależnie i odtwarzają różne sample. Wynikiem tego jest to, że słyszymy dźwięk co każde 0.5 uderzenia jako, że każdy z synchronizowanych (sync) wątków jest wybierany losowo z wątku cue po czym odtwarza swojego sampla.

Oczywiście to wszystko zadziała analogicznie nawet jeśli poukładasz wątki w odwrotnej kolejności jako, że wątek sync będzie po prostu czekał na kolejną wartość wysłaną przez wątek cue.


6 - Studio FX

Jednym z najbardziej satysfakcjonujących aspektów Sonic Pi jest możliwość łatwego dodawania efektów studyjnych do twoich brzmień. Na przykład, być może zdarzy się, że będziesz chciał dodać trochę efektu reverb (pogłos) do pewnych części twojego kawałka, albo trochę echa albo może nawet efektu distort czy wobble do twojej linii basowej.

Sonic Pi udostępnia bardzo prosty a jednocześnie potężny sposób na dodawanie takich efektów (FX). Pozwala on nawet na łączenie ich (możesz więc przepuścić twoje brzmienie kolejno przez efekt distortion/overdrive?, potem przez echo i na końcu przez reverb) i jednocześnie daje Ci możliwość kontrolowania każdego z nich indywidualnie za pomocą parametrów (w podobny sposób do tego w jaki przekazujemy parametry do syntezatorów czy sampli). Możesz nawet modyfikować parametry efektu (FX) gdy wciąż jest uruchomiony. Możesz więc, na przykład, zwiększyć wartość efektu reverb twojej sekcji basowej na przestrzeni całego utworu…

Efekty gitarowe

Jeśli wszystko to brzmi dla ciebie trochę zbyt skomplikowanie, nie przejmuj się. Gdy już trochę się tym pobawisz, wszystko stanie się całkiem jasne. Zanim jednak to nastąpi, wprowadzę prostą analogię do efektów (FX) gitarowych. Istnieje wiele rodzajów takich efektów (FX), które możesz kkupić. Pewne z nich dodają efekt reverb, inne distort, itd. Gitarzyści podłączają swoją gitarę do jednego z efektów (FX), tzw. pedałów gitarowych - np. distortion. Następnie biorą kabel i łączą ten efekt z kolejnym, np. efektem reverb. Na koniec wyjście z efektu reverb może być podłączone do wzmacniacza:

Gitara -> Distortion -> Reverb -> Wzmacniacz

Nazywa się to łączeniem efektów w łańcuch. Sonic Pi wspiera taki właśnie model dla swoich efektów. Dodatkowo, każdy z efektów posiada pokrętła i suwaki pozwalające Ci na kontrolę tego jak mocny ma być efekt distortion, reverb, echo, itd. Sonic Pi wspiera taką kontrolę. Na konic, możesz wyobrazić sobie grającego gitarzystę podczas gdy ktoś inny w tym samym czasie bawi się i kontroluje efekty (FX). Sonic Pi również wspiera taką możliwość - tylko, że zamiast innej osoby do kontrolowania tych efektów, na scenę wkroczy w tym wypadku komputer.

Poznajmy zatem efekty (FX)!


6.1 - Dodawanie Efektów

W tej sekcji przyjrzymy się kilku efektom (FX): reverb i echo. Zobaczymy w jaki sposób ich używać, w jaki sposób kontrolować ich parametry oraz jak łączyć je ze sobą w jeden łańcuch.

System efektów w Sonic Pi korzysta z bloków kodu. Jeśli więc do tej pory nie przeczytałeś jeszcze sekcji 5.1, to teraz jest dobry moment by nadrobić zaległości.

Efekt Reverb

Jeśli chcemy użyć efektu reverb wystarczy, że napiszemy with_fx :reverb jako specjalny kawałek kodu dla naszego bloku do/end:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

A teraz uruchom ten kod a usłyszysz jak jest zagrany z nałożonym na niego efektem reverb. Brzmi nieźle, prawda?! Wszystko brzmi całkiem fajnie z efektem reverb.

A teraz zobaczmy co się wydarzy, gdy umieścimy jakiś dodatkowy kod poza naszym blokiem do/end:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

sleep 1
play 55

Zauważ, że ostania linia play 55 nie jest zagrana z efektem reverb. Dzieje się tak ponieważ znajduje się poza blokiem kodu do/end, więc dzięki temu nie jest objęta efektem reverb.

Analogicznie, jeśli zrobisz jakieś dźwięki przed blokiem do/end, to one również nie będą pod wpływem efektu reverb:

play 55
sleep 1

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

sleep 1
play 55

Efekt Echo

Jest wiele efektów do wyboru. Co powiesz na echo?

with_fx :echo do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Jednym z potężnych aspektów bloków efektów w Sonic Pi jest to, że można do nich przekazywać parametry podobne do parametrów, które już widzieliśmy gdy korzystaliśmy z poleceń play i sample. Na przykład bardzo fajnym parametrem, który nieźle brzmi z efektem echo jest phase:. Reprezentuje on czas trwania danego efektu przez określoną liczbę uderzeń (ile uderzeń trwa efekt). Spróbujmy sprawić aby efekt echo był trochę wolniejszy:

with_fx :echo, phase: 0.5 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Spróbujmy też sprawić aby echo brzmiało szybciej:

with_fx :echo, phase: 0.125 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Sprawmy teraz aby zanikanie echa trwało dłużej ustawiając parametr decay na 8 sekund:

with_fx :echo, phase: 0.5, decay: 8 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Zagnieżdżanie Efektów

Jednym z najbardziej potężnych aspektów bloków zawierających efekty jest to, że możesz je zagnieżdzać. Pozwala to na bardzo łatwe łączenie ich razem. Na przykład, co jeśli chciałeś zagrać kawałek jakiegoś kodu z efektami echo i reverb? Łatwizna, po prostu umieść jeden w drugim:

with_fx :reverb do
  with_fx :echo, phase: 0.5, decay: 8 do
    play 50
    sleep 0.5
    sample :elec_blup
    sleep 0.5
    play 62
  end
end

Pomyśl o przepływie dźwięku ze środka na zewnątrz. Dźwięk z najbardziej wewnętrznego bloku kodu, np. play 50 jest najpierw wysyłany do efektu echo, następnie dźwięk z nałożonym echo jest z kolei wysyłany do efektu reverb.

Możemy używać wielu takich zagnieżdżeń dlo osiągania zwariowanych wyników. Jednakże uważaj, efekty mogą zużywać sporo zasobów. Zagnieżdżając jeden w drugim uruchamiasz wiele efektów na raz. Bądź więc oszczędny z ich używaniem, zwłaszcza na platformach o słabych parametrach (procesor, pamięć, itd.) na przykład takich jak Raspberry Pi.

Odkrywanie Efektów

Sonic Pi posiada wiele wbudowanych efektów, z których możesz korzystać. Aby zobaczyć jakie z nich są dostępne, kliknij na ikonie Fx (efekty) w sekcji pomocy a zobaczysz listę wszystkich dostępnych opcji. Oto kilka moich ulubionych:

A teraz powariuj trochę i dodaj efektów wszędzie gdzie tylko możesz aby stworzyć zdumiewające nowe dźwięki!


6.2 - Efekty w praktyce

Pomimo, że na pierwszy rzut oka wyglądają one na zwodniczo łatwe, to od środka efekty są tak naprawde bardzo złożonymi bestiami. Ich prostota bardzo często kusi ludzi by naduzywać ich w swoich kawałkach. Może to być w porządku jeśli masz dobry i wydajny komputer, ale jeśli - tak jak ja - korzystasz z Raspberry Pi do jam’owania, musisz być wtedy bardzo ostrożny z tym ile pracy mu zlecisz do wykonania, jeśli chcesz być pewny, że beat zachowa swą płynność.

Rozważ taki kawałek kodu:

loop do
  with_fx :reverb do
    play 60, release: 0.1
    sleep 0.125
  end
end

W powyższym kawałku kodu zagraliśmy nutę 60 z bardzo krótkim czasem zanikania (release), więc jest to bardzo krótka nuta. Chemy również nałożyć na nią efekt reverb, więc opakowaliśmy ją w blok reverb. Jak na razie wszystko w porządku. Z wyjątkiem…

Przyjrzyjmy się co ten kod tak naprawdę robi. Na początku mamy pętlę loop co oznacza, że wszystko wewnątrz niej będzie powtarzane w nieskończoność. Następnie mamy blok with_fx. Oznacza to, że utworzymy nowych efekt FX dla każdej iteracji pętli loop. To tak jakbyśmy chcieli mieć odzielny efekt gitarowowy reverb przy każdym jednym uderzeniu w strunę gitary. Fajnie, że możemy tak zrobić, ale nie zawsze jest to coś co chciałbyś osiągnąć. Na przykład, ten kawałek kodu czeka niezła walka aby został on ładnie uruchomiony na Raspberry Pi. Cała praca potrzebna do stworzenia efektu reverb a potem czekanie do momentu,
w którym będzie wymagał zatrzymania i usunięcia jest obsługiwana za Ciebie przez funkcję with_fx, zajmie to jednak sporo mocy
procesora (CPU), która może okazać się bardzo cenna.

A co jeśli sprawimy, by ten kod był bardziej podobny do tradycyjnego zestawu, gdzie nasz gitarzysta posiada tylko jeden efekt reverb i to przez niego przechodzą wszystkie dźwięki? Łatwizna:

with_fx :reverb do
  loop do
    play 60, release: 0.1
    sleep 0.125
  end
end

Umieściliśmy naszą pętęlę wewnątrz bloku with_fx. W ten sposób tworzymy tylko jeden efekt reverb dla wszystkich nut, które zostaną zagrane w naszej pętli. Taki kod jest dużo bardziej wydajny i na pewno będzie działał w porządku na Raspberry Pi.

Kompromisem może też być użycie efektu with_fx wewnątrz pętli loop, ale powyżej iteracji wewnętrznej:

loop do
  with_fx :reverb do
    16.times do
      play 60, release: 0.1
      sleep 0.125
    end
  end
end

W ten sposób przenieśliśmy efekt with_fx na zewnątrz wewnętrznej części pętli loop i teraz tworzymy nowy efekt reverb tylko co 16 zagranych nut.

Pamiętaj jedno - błędów nie ma, sa tylko nowe możliwości. Jednakże, każdy z powyższych podejść będzie miał inne brzmienie oraz inną charakterystykę wydajności. Staraj się więc używać takiego podejścia, które będzie brzmiało najlepiej mając jednocześnie na uwadze fakt pracy z ograniczeniami wydajnościowymi twojego komputera/platformy na której pracujesz.


7 - Kontrola działających dźwięków

Do tej pory dowiedzieliśmy się jak możemy wyzwalać syntezatory i sample oraz w jaki sposób zmieniać ich domyślne parametry takie jak amplituda, kanał, ustawienia obwiedni i inne. Każdy uruchomiony dźwięk jest w zasadzie osobnym dźwiękiem z jego własnym zestawem parametrów ustalonych na czas trwania dźwięku.

Czy nie było by super gdybyś mógł zmieniać parametry dźwięku w trakcie odtwarzania danego dźwięku, tak samo jak możesz naciągnać struny gitary gdy jej struny wciąż wibruja?

Masz szczęście - ten rozdział pokaże Ci dokładnie jak możesz tego dokonać.


7.1 - Kontrolowanie Uruchomionych Syntezatorów

Do tej pory interesowaliśmy się tylko uruchamianiem nowych dźwięków i efektów. Jednakże, Sonic Pi daje nam możliwość manipulacji i kontroli aktualnie uruchomionych dźwięków. Dokonujemy tego używając zmiennych do przechwycenie referencji do syntezatora:

s = play 60, release: 5

Mamy tutaj zmienną lokalną s, która reprezentuje syntezator grający nutę 60. Nuta, która jest zmienną działającą lokalnnie - nie masz do niej dostępu z innych uruchomień takich jak funkcje (?).

Gdy już mamy zmienną s, możemy zacząć kontrolować ją za pomoca funkcji control:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Rzeczą godną zauważenia jest tutaj to, że nie uruchamiamy 4 oddzielnych
syntezatorów - uruchamiamy tylko jeden po czym zmieniamy wysokość tonu 3 razy w trakcie gdy wciąż gra.

Możemy przekazywać dowolne ze standardowych parametrów do polecenia control, możesz więc kontrolować takie rzeczy jak amp:, cutoff: czy pan:.

Parametry Nie Dające Się Kontrolować

Są pewne parametry, które nie mogą być kontrolowane gdy syntezator został już uruchomiony. Dotyczy to m.in. wszytkich parametrów obwiedni ADSR. Możesz samodzielnie sprawdzić, które z parametrów danego syntezatora mogą być kontrolowane zaglądając do systemu pomocy. Jeśli w dokumentacji jest napisane can not be changed once set (nie może być zmieniony gdy już raz został ustawiony), to już wiesz, że nie możesz kontrolować i zmienać danego parametru gdy syntezator już wystartuje.


7.2 - Kontrolowanie Efektów

Możliwe jest również kontrolowanie efektów, jendakże jest ono realizowane w trochę inny sposób:

with_fx :reverb do |r|
  play 50
  sleep 0.5
  control r, mix: 0.7
  play 55
  sleep 1
  control r, mix: 0.9
  sleep 1
  play 62
end

Zamiast używać zmiennej, korzystamy z parametru pomiędzy słupkami znajdujacymi się w bloku kodu do/end. Pomiędzy słupki | wstawiamy
unikalną nazwę dla naszego efektu, dzięki czemu możemy się później do niej odwoływać w danym bloku kodu do/end. Postępowanie w tym przypadku jest identyczne do używania parametrów w funkcjach.

A teraz spróbuj wykorzystać kontrolę nad syntezatorami i efektami!


7.3 - Parametry Przesuwne

Podczas poznawania parametrów syntezatorów i efektów, być może udało Ci się zauważyć, że kilka nazw parametrów ma kończy się na _slide. Być może nawet próbowałeś korzystać z nich i nie zauważyłeś żadnego efektu. Dzieje się tak ponieważ nie są one normalnymi parametrami, są to specjalne parametry, które działają tylko gdy kontrolujesz syntezatory w sposób jaki pokazaliśmy w poprzedniej sekcji.

Przyjrzyjmy się następującemu przykładowi:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

W powyższym przykładzie słyszymy jak wysokość tonu (pitch) zmienia się przy każdym uruchomieniu polecenia control. Może się jednak zdarzyć, że będziemy chcieli aby zmiana tonu nastąpiła w sposób płynny (tak jakbyśmy użyli do tego suwaka). Tak samo jak kontrolujemy zmianę tonu parametrem note:, aby dodać płynne przejście, musimy ustawić na syntezatorze parametr note_slide:

s = play 60, release: 5, note_slide: 1
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Teraz słyszymy, że pomiędzy poszczególnymi wywołaniami poleceń control nuty są “naciągane”. Brzmi to całkiem fajnie, prawda? Możesz przyśpieszyć płynne przejście pomiędzy nutami używająć krótszego czasu, np. `note_slide: 0.2’, albo zwolnić je, używająć dłuższego czasu przejścia (ślizgania).

Każdy z parametrów, który może być kontrolowany posiada odpowiadający my parametr typu _slide, z którego możesz korzystać.

Ślizganie jest lepkie

Gdy już raz ustawimy parametr typu _slide na uruchomionym syntezatorze, to zostanie on zapamiętany i ta wartość będzie wykorzystywana za każdym razem gdy będziesz zmieniał płynnie wartość odpowiedającego mu parametru. Aby zatrzymać płynne przejścia musisz ustawić wartość parametru _slide na 0 przed kolejnym wywołaniem polecenia control.

Płynne Przejścia w Parametrach Efektów

Są również możliwe płynne przejścia dla parametrów efektów:

with_fx :wobble, phase: 1, phase_slide: 5 do |e|
  use_synth :dsaw
  play 50, release: 5
  control e, phase: 0.025
end

Spróbuj teraz pobawić się płynnymi przejściami aby spróbować dokonać płynnych przejść i płynnej kontroli…


8 - Struktury Danych

Struktury danych to bardzo przydatne narzędzie dostępne w standardowm zestawie narzędzi każdego programisty.

Czasami będziesz chciał reprezentować i używać czegoś więcej niż tylko jednej rzeczy. Na przykład, przydatnym może okazać się możliwość posiadania serii nut do zagrania jedna po drugiej. Języki programowania posiadają coś takiego jak struktury danych, które pozwalają Ci robić takie rzeczy.

Istnieje wiele ekscytujących i egzotycznych struktur danych dostępnych dla programistów - a ludzie wciąż wymyślają nowe. Na razie potrzebujemy w zasadzie wziąć pod uwagę tylko jedną prostą strukturę danych - listę.

Przyjrzyjmy się jej bardziej szczegółowo. Skupimy się jej podstawową formą, następnie pokażemy w jaki sposób możemy wykorzystać listy do reprezentacji skal oraz akordów.


8.1 - Listy

W tej sekcji przyjrzymy się bardzo przydatnej strukturze danych - liście. Spotkaliśmy ją na krótko już wcześniej w sekcji poświęconej randomizacji kiedy to wybieraliśmy z listy losowe nuty do zagrania:

play choose([50, 55, 62])

W obecnym rozdziale zobaczymy jak możemy wykorzystać listy również do reprezentacji akordów i skal. Na początku jednak spróbujmy sobie przypomnieć w jaki sposób możemy zagrać akord. Pamiętasz, że jeśli nie użyliśmy polecenia sleep, to wszystkie dźwięki zagrają jednocześnie:

play 52
play 55
play 59

Spróbujmy przyjrzeć się innym sposobom, za pomocą których możemy wyrazić powyższy kod.

Granie Listy

Jedną z opcji jest umieszczenie wszystkich nut w liście [52, 55 , 59]. Nasza poczciwa funkcja play jest wystarczająco bystra by wiedzieć w jaki sposób ma zagrać listę nut. Spróbuj tego:

play [52, 55, 59]

Ooh, taki kod jest dużo przyjemniejszy do czytania. Zagranie listy nut, nie blokuje Ci korzystania z żadnego z parametrów:

play [52, 55, 59], amp: 0.3

Oczywiście, możesz również używać tradycyjnych nazw nut zamiast korzystania z liczb MIDI:

play [:E3, :G3, :B3]

Teraz Ci z Was, który mieli farta i studiowali trochę teorii muzycznej mogą zauważyć, że to jest akord E Minor zagrany na 3-ciej oktawie.

Dostęp do Listy

Innym bardzo przydatną cechą list jest możliwość wyciągnięcia z nich informacji. Może to brzmieć odrobinę dziwnie, ale nie jest to nic bardziej trudnego niż to gdy ktoś prosi Cię o to abyś przeszedł książce na stronę 23. Korzystając z listy, mógłbyś zapytać, jaki element znajduje się na 23 pozycji? Jedyną dziwną rzeczą w programowaniu jest to, że numery takich pozycji (indeksy) zazwyczaj zaczynają się od 0 a nie od 1.

Indeksy w listach nie są odliczane przez 1, 2, 3… Zamiast tego odliczamy 0, 1, 2…

Przyjrzyjmy się temu trochę bardziej. Spójrz na taką listę:

[52, 55, 59]

Nie ma w niej nic specjalnie strasznego. Teraz pytania, jaki jest drugi element w tej liście. Tak, zgadłeś, jest to 55. To było proste. Sprawdźmy, czy możemy poprosić komputer aby odpowiedział nam na to pytanie:

puts [52, 55, 59][1]

Dobrze, to wygląda trochę dziwnie, jeśli jeszcze nigdy nie widziałeś niczego takiego. Zaufaj mi jednak, to nie jest trudne. W powyższej linii są 3 części: słowo puts, nasza lista 52, 55, 59 oraz nasz indeks [1]. Najpierw mówimy puts ponieważ chcemy aby Sonic Pi wyświetlił nam odpowiedź w panelu logowania (po prawej stronie). Następnie, przekazujemy do tego polecenia naszą listę i na końcu nasz indeks, który pyta nas o drugi element. Musimy otoczyć nasz indeks w nawiasy kwadratowe, a ponieważ liczenie zaczynamy od 0, to indeks dla drugiego elementu to 1. Spójrz:

# indeksy:  0   1   2
           [52, 55, 59]

Spróbuj uruchomić kod puts [52, 55, 59][1] a zobaczysz, że liczba 55 pojawi się w panelu logowania. Zmień indeks 1 na inne wartości, spróbuj użyć dłuższych list i pomyśl w jaki sposob mógłbyś użyć listy w twojej kolejnej zabawie kodem. Na przykład, jakie muzyczne struktury mogą być reprezentowane jako seria liczb…


8.2 - Akordy

Sonic Pi posiada wbudowane wsparcie dla nazw akordów, które zwracają listy. Spróbuj sam:

play chord(:E3, :minor)

Teraz, naprawdę zaczynamy dokądś zmierzać. To wygląda dużo ładniej niż czyste listy (i jest dużo łatwiejsze do czytania dla innych ludzi). Jakie więc inne akordy wspiera Sonic Pi? Całkiem sporo. Spróbuj tych:

Arpeggia

Możemy bardzo łatwo zmienić akordy w arpeggia za pomocą funkcji play_pattern:

play_pattern chord(:E3, :m7)

Ok, to nie jest jakoś mocno fajne - zostało zagrane dość wolno. Funkcja play_pattern zagra każdą listę z przekazanej listy odzdzielając każdą nutę uruchomieniem polecenia sleep 1 pomiędzy każdym uruchomieniem funkcji play. Możemy jednak użyć innej funkcji play_pattern_timed aby móc samodzielnie określić timing i przyśpieszyć bieg rzeczy:

play_pattern_timed chord(:E3, :m7), 0.25

Możemy nawet przekazać listę czasów, która zostanie potraktowania jako krąg czasów:

play_pattern_timed chord(:E3, :m13), [0.25, 0.5]

Jest to odpowiednik takiego kwała kodu:

play 52
sleep 0.25
play 55
sleep 0.5
play 59
sleep 0.25
play 62
sleep 0.5
play 66
sleep 0.25
play 69
sleep 0.5
play 73

Który kawałek wydaje Ci się wygodnieszy do napisania, którego byś użył?


8.3 - Skale

Sonic Pi posiada wsparcie dla szerokiego zakresu skal. Co powiesz na to aby zagrać C3 ze skali durowej?

play_pattern_timed scale(:c3, :major), 0.125, release: 0.1

Możemy nawet poprosić o więcej oktaw:

play_pattern_timed scale(:c3, :major, num_octaves: 3), 0.125, release: 0.1

Co powiesz na wszystkie nuty w skali pentatonicznej (pentatonika)?

play_pattern_timed scale(:c3, :major_pentatonic, num_octaves: 3), 0.125, release: 0.1

Losowe nuty

Akordy i skale są świetnym sposobem na ograniczenie wyboru losowego do czegoś sensownego. Spróbuj pobawić się z tym przykładem, który wybiera losowe nuty z akordu E3 moll:

use_synth :tb303
loop do
  play choose(chord(:E3, :minor)), release: 0.3, cutoff: rrand(60, 120)
  sleep 0.25
end

Spróbuj poustawiać inne nazwy akordów oraz inne zakresy odcięcia (cutoff).

Odkrywanie Akordów i Skal

Aby zobaczyć jakie skale i akordy są wspierane przez Sonic Pi kliknij na przycisk Lang znajdujący się po lewej stronie tego samouczka, następnie z listy dostępnych API wybierz pozycję chord (akord) lub scale (skala). W informacjach znajdujących się w głównym panelu, przewiń w dół aż ujrzysz długą listę akordów lub skal (w zależności od tego na którą pozycję patrzysz).

Baw się i pamiętaj: błędów nie ma, sa tylko możliwości.


8.4 - Pierścienie

Ciekawym przypadkiem stanardowych list są pierścienie. Jeśli znasz się trochę na programowaniu, to mogło się zdarzyć, że miałeś do czynienia z buforami cyklicznymi lub tablicami cyklicznymi. Tutaj przyjrzymy się tylko pierścieniowi - jest krótki i prosty.

W poprzedniej sekcji dotyczącej list widzieliśmy w jaki sposób możemy wyciągać z nich elementy korzystając z mechanizmu indeksowania:

puts [52, 55, 59][1]

A co się stanie jeśli chciałbyś pozycję spod indeksu 100? Dobrze, więc na pozycji 100 nie ma żadnego elementu jako, że lista posiada w sobie tylko trzy elementy. Sonic Pi zwróci więc wartość nil co oznacza nic.

Jednakże, biorąc pod uwagę, że masz licznik, taki jak aktualne uderzenie, które nieustannie rośnie. Spróbujmy utworzyć sobie licznik oraz listę:

counter = 0
notes = [52, 55, 59]

Możemy teraz użyć naszego licznika aby dostać się do nuty znajdującej się w naszej liście:

puts notes[counter]

Super, otrzymaliśmy 52. Teraz, spróbujmy zwiększyć nasz licznik i dostać się do kolejnej nuty:

counter = (inc counter)
puts notes[counter]

Super, teraz otrzymaliśmy 55 i jeśli zrobimy to jeszcze raz, to otrzymamy liczbę 59. Jednakże, jeśli zrobimy to kolejny raz, to wyskoczymy poza liczby znajdujące się w naszej liście i otrzymamy nil. A co jeśli chcieliśmy tylko zrobić pętlę, wrócić do początku i zacząć na samym początku listy od nowa? Do tego właśnie służą pierścienie.

Tworzenie Pierścieni

Możemy tworzyć pierścienie na dwa sposoby. Albo użyjemy funkcji ring podając elementy dla danego pierścienia jako parametry:

(ring 52, 55, 59)

Albo możemy wziąć normalną listę i przekształcić ją w pierścień poprzez wysłanie do niej wiadomości .ring:

[52, 55, 59].ring

Indeksowanie Pierścieni

Gdy już masz pierścień, możesz go używać dokładnie w ten sam sposób w jaki używasz normalnej listy z tym jednym wyjątkiem, że możesz używać indeksów ujemnych oraz takich, które są większe niż ilość elementów w danym pierścieniu a będą one powtarzać się cyklicznie i zawsze będą wskazywać na jeden z elementów pierścienia:

(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59

Korzystanie z Pierścieni

Przyjmijmy, że używamy zmiennej do reprezentacji aktualnego numeru uderzenia. Możemy użyć jej jako indeksu w naszym pierścieniu aby wydobywać kolejne nuty do zagrania, czasy zanikania albo cokolwiek innego przydatnego co załadowaliśmy do naszego pierścienia niezależnie od numeru uderzenia (beat) przy którym aktualnie się znajdujemy.

Skale i Akordy są Pierścieniami

Przydatną rzeczą jest wiedza o tym, że listy zwracane przez skale scale oraz akordy chord są również pierścieniami i pozwalają Ci na dostęp do nich z wykorzystaniem bezwzględnych indeksów.

Konstruktory Pierścieni

Oprócz funkcji ring istnieje również kilka innnych funkcji, które pozwalają nam na tworzenie pierścieni.

Przyjrzyj się poszczególnym dokumentacjom dla uzyskania większej ilości informacji.


9 - Kodowanie na Żywo

Jednym z najbardziej ekscytujących aspektów Sonic Pi jest to, że pozwala Ci tworzyć muzykę porzez pisanie i modyfikację kodu na żywo, tak samo jakbys mógł występować na żywo z gitarą. Jedną z zalet takiego podejścia jest to, że powala Ci na otrzymywanie informacji zwrotnej znacznie szybciej niż w sytuacji gdybyś komponował (stwórz prostą pętlę, która będzie się kręcić w kółko i zacznij dopieszczać ją aż zacznie brzmieć idealnie). Główną i podstawową zaletą jest jednak to, że możesz wziąć Sonic Pi ze sobą na scenę i wykorzystać go do występów na żywo.

W tym rozdziale przedstawimy Ci podstawy tego w jaki sposób możesz zmienić twoje statyczne kompozycje w pełne życia występy.

Zapnijcie pasy…


9.1 - Kodowanie na Żywo (Live Coding)

Teraz nauczyliśmy się już wystarczająco dużo aby zacząć prawdziwą zabaę. W tym rozdziale będziemy czerpać ze wszystkich poprzednich i pokażemy Ci w jaki sposób możesz zacząć tworzyć swoje własne kompozycje muzyczne na żywo i zmienić je w występy na żywo. Będziemy do tego potrzebować 3 podstawowych sładników:

W porząsiu, zaczynamy. Spróbujmy zakodować na żywo nasze pierwsze dźwięki. Najpierw potrzebujemy funkcję, która będzie zawierać kod, który chcemy zagrać. Zacznijmy od czegoś prostego. Potrzebujemy również aby każda pętla wywołująca tę funkcję była uruchamiana w nowym wątku:

define :my_loop do
  play 50
  sleep 1
end

in_thread(name: :looper) do
  loop do
    my_loop
  end
end

Jeśli powyższy kawałek kodu wydaje Ci się zbyt skomplikowany, wróć z powrotem i ponownie przeczytaj rozdziały dotyczące funkcji i wątków. Gdy to zrobisz i uda Ci się dobrze zrozumieć te 2 tematy to powyższy kawałek nie powinien sprawić Ci żadnych kłopotów.

To co mamy powyżej to nic innego jak funkcja, która po prostu gra nutę o wartości 50 i następnie czeka 1 uderzenie. W kolejnym kroku mamy definicję wątku nazwanego :looper, który po prostu kręci się w kółko i uruchamia fukcję my_loop.

Gdy uruchomisz ten kod, usłyszysz nutę 50 która powtarza się i gra w kółko…

Spróbujmy coś zmienić

Teraz, czas na moment w którym zaczyna się cała zabawa. W momencie gdy kod jest wciąż uruchomiony, spróbuj zmienić liczbę 50 na inną, powiedzmy 55, następnie naciśnij przycisk Run jeszcze raz. Łał! To się zmieniło! Ten kod żyje!

Nowa warstwa dźwięku nie została dodana ponieważ korzystamy z nazwanych wątków co pozwala tylko na jeden wątek dla jednej nazwy. Ponadto, dźwięk się zmienił ponieważ przedefiniowaliśmy funkcję. Nadaliśmy funkcji :my_loop nową definicję - znaczenie. Kiedy wątek :looper przekręci się po raz kolejny, to w następnej iteracji zostanie zawołana funkcja o nowej definicji.

Spróbuj zmienić ją ponownie, zmień nutę, zmień wartość parametru jaki przekazujemy do funkcji sleep. Co powiesz na dodanie polecenia use_synth? Na przykład, zmieńmy kod w taki sposób:

define :my_loop do
  use_synth :tb303
  play 50, release: 0.3
  sleep 0.25
end

Brzmi to całkiem ciekawie, ale możemy urozmaicić to jeszcze bardziej. Zamiast grać w kółko tę samę nutę, spróbujmy zagrać akord:

define :my_loop do
  use_synth :tb303
  play chord(:e3, :minor), release: 0.3
  sleep 0.5
end

A co powiesz na granie losowych nut z akordu:

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.3
  sleep 0.25
end

Albo użycie losowej wartości dla parametru odcięcia (cutoff):

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

I na sam koniec, dodajmy trochę bębnów:

define :my_loop do
  use_synth :tb303
  sample :drum_bass_hard, rate: rrand(0.5, 2)
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

Teraz zabawa zaczyna być naprawdę ekscytująca!

Jednakże, zanim zamkniesz tutorial i zaczniesz kodować na żywo z wykorzystaniem funkcji i wątków, zatrzymaj się na chwile i przeczytaj kolejny rozdział dotyczący funkcji live_loop, która zmieni twój sposób kodowania w Sonic Pi na zawsze…


9.2 - Żywe Pętle (Live Loops)

Dobrze, ten rozdział to prawdziwa perełka w tym samouczku. Jeśli masz przeczytać tylko jeden rozdział w tym tutorialu, powinien to być właśnie ten rozdział. Jeśli przeczytałeś poprzedni rozdział o Podstawach Kodowania Na Żywo, to live_loop jest prostszą metodą dokonania dokładnie tego samego, ale bez konieczności pisania tak dużej ilości kodu.

Jeśli nie przeczytałeś poprzedniego rozdziału, funkcja live_loop jest najlepszym sposobem na jam’owanie z Sonic Pi.

Zabawmy się. Wpiszmy następujący kod do nowego bufora:

live_loop :foo do
  play 60
  sleep 1
end

Naciśnij przycisk Run. Słyszysz podstawowy bip przy każdym uderzeniu. Nic szczególnego. Powstrzymaj się jednak i nie naciskaj jeszcze przycisku Stop. Zmień wartość 60 na 65 i naciśnij przycisk Run jeszcze raz.

Now press the Run button. You hear a basic beep every beat. Nothing fun there. However, don’t press Stop just yet. Change the 60 to 65 and press Run again.

Łał! Brzmienie zmieniło się automatycznie bez utraty żadnego uderzenia.

Czemu więc nie spróbować zmienić ten kawałek aby brzmiał trochę bardziej jak linia basowa? Wystarczy, że zmienisz kod gdy ten wciąż jest uruchomiony:

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8
  sleep 8
end

I naciśniesz przycisk Run.

Spróbujmy sprawić, aby pojawiła się odrobina odcięcia (cutoff):

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Ponownie naciśnij przycisk Run.

Dodajmy trochę bębnów:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Zmień nutę e1 na c1:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

A teraz przestań słuchać moich propozycji i zacznij bawić się samodzielnie! Miłej zabawy!


9.3 - Wiele Żywych Pętli

Przyjrzyjmy się natępującej żywej pętli:

live_loop :foo do
  play 50
  sleep 1
end

Być może zastanawiałeś się dlaczego konieczna jest nazwa :foo. Nazwa ta jest ważna ponieważ oznacza, że ta konkrenta żywa pętla jest inna od wszystkich innych żywych pętli.

W tym samym czasie nie mogą być uruchomione dwie żywe pętle o tej samej nazwie.

Oznacza to, że jeśli potrzebujemy kilku jednocześnie kręcących się żywych pętli, to po prostu musimy nadać im inne nazwy:

live_loop :foo do
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

live_loop :bar do
  sample :bd_haus
  sleep 0.5
end

Możesz teraz aktualizować i zmieniać każdą z żywych pętli niezależnie i wszystio będzie po prostu działać.

Synchronizacja Żywych Pętli

Jedną z rzeczy, które być może już zauważyłeś to to, że żywe pętle działają automatycznie z mechanizmem punktów cue dla wątków, które poznaliśmy już wcześniej. Za każdym razem, gdy żywa pętla wykona pętlę, generuje nowe zdarzenie cue nadając mu nazwę taką samą jaką nadaliśmy żywej pętli. Możemy więc sychroznizować się z wykorzystaniem funkcji sync na każdym zdarzeniu cue aby upewnić się, że nasze pętle są zsynchronizowane bez konieczności zatrzymywania czegokolwiek.

Spójrzmy na poniższy kod, który został źle zsynchronizowany:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.4
end

live_loop :bar do
  sample :bd_haus
  sleep 1
end

Zobaczmy czy możemy naprawić chronometraż (timing) bez zatrzymywania. Najpierw, naprawmy pętlę :foo tak, aby sprawić, że wartość parametru sleep będzie współczynnikiem liczby 1 - coś jak 0.5 powinno być ok:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end

live_loop :bar do
  sample :bd_haus
  sleep 1
end

To jeszcze nie koniec - powinieneś zauważyć, że uderzenia nie do końca ustawiają się odpowiednio. Dzieje się tak, ponieważ pętle nie są synchronizowane. Spróbujmy to naprawić przez ich synchronizację:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end

live_loop :bar do
  sync :foo
  sample :bd_haus
  sleep 1
end

Łał, teraz wszystko perfekcyjnie w czas - i to wszystko bez zatrzymywania.

A teraz, nie zatrzymuj się i koduj na żywo z wykorzystaniem żywych pętli!


9.4 - Cykanie

Coś na co na pewno będziesz robił dość często podczas kodowania na żywo to iterowanie przez pierścienie. Będziesz wrzucał nuty do pierścieni dla tworzenia melodii, czasów uśpienia dla rytmów, progresji akordów, różne wariacje barw dźwięku, itd.

Cykające Pierścienie

Sonic Pi udostępnia bardzo przydatne narzędzie do pracy z pierścieniami w żywych pętlach live_loop. Nazywa się to systemem cykania. Udostępnia Ci możliwość cykania przez pierścienie. Spójrzmy na następujący przykład:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick, release: 0.1
  sleep 0.125
end

Wzięliśmy tu pentatoniczną skalę E3 moll i cykamy przez każdy jej element. Dokonaliśmy tego przez dodanie polecenia .tick na końcu deklaracji skali. Każde cyknięcie jest lokalne dla danej żywej pętli, więc każda żywa pętla może posiadać swojego własnego niezależnego cykacza:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick, release: 0.1
  sleep 0.125
end

live_loop :arp2 do
  use_synth :dsaw
  play (scale :e2, :minor_pentatonic, num_octaves: 3).tick, release: 0.25
  sleep 0.25
end

Cyknięcie

Możesz również uruchomić polecenie cyknięcia tick jako standardową funkcje i używać zwracanej wartości jako indeksu:

live_loop :arp do
  idx = tick
  play (scale :e3, :minor_pentatonic)[idx], release: 0.1
  sleep 0.125
end

Jednakże, dużo ładniej jest korzystać z polecenia .tick dodanego na końcu. Funkcja tick jest stworzona dla sytuacji gdy chesz zrobić coś fantazyjnego z wartością zwracaną przy cyknięciu oraz gdy chcesz używać cyknięć do innych rzeczy niż indeksowania elementów pierścieni.

Look

Magiczną rzeczą w cykaniu jest to, że możliwe jest nie tylko zwrócenie
nowego indeksu (albo wartości znajdującej się w pierścieniu pod tym indeksem). Mechanizm ten pilnuje też aby przy każdym twoim kolejnym cyknięciu była to kolejna wartość. Zerknij na przykłady znajdujące się w dokumentacji dla polecenia tick aby zobaczyć wiele różnych sposobów na pracę z nim. Jednakże, na tą chwilę, ważne jest aby zaznaczyć, że czasami będziesz chciał po prostu podejrzeć aktualną wartość cyknięcia bez zwiększania jego wartości. Możesz tego dokonać za pomocą funkcji look. Możesz uruchamiać polecenie look jako standardową funkcję lub poprzez dodanie .look na końcu pierścienia.

Nazwane Cyknięcia

Na koniec, czasami będziesz potrzebował więcej niż jednego cykacza dla danej żywej pętli. Można tego dokonać poprzez nadanie twojemu cyknięciu nazwę:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick(:foo), release: 0.1
  sleep (ring 0.125, 0.25).tick(:bar)
end

Powyżej używamy dwóch cykaczy, jeden dla zagrania nuty i drugi dla
odliczania czasu uśpienia. Jako, że oba znajdują się w tej samej żywej pętli, potrzebowaliśmy nadać im unikalne nazwy aby sprawić by były oddzielne. To jest dokładnie taki sam mechanizm jak w przypadku nadawania nazw żywym pętlom (live_loop) - po prostu przekazujemy symbol poprzedzony dwukropkiem :. W powyższym przykładzie nazwaliśmy pierwszego cykacza :foo a drugiego :bar. Jeśli chcemy podejrzeć aktualną wartość, któregoś z nich za pomocą polecenia look, to musimy do polecenia look również przekazać nazwę konkretnego cykacza.

Nie twórz zbyt skomplikowanych rzeczy

Większość mocy zawartej w systemie cykania nie jest przydatna gdy dopiero zaczynasz. Nie próbój i nie ucz się wszystkiego z tego rozdziału. Postaraj skupić się na cykaniu przez pojedynczy pierścień. To powinno dać Ci największą satysfakcję oraz prostotę związaną z cykaniem przez pierścienie w twoich żywych pętlach.

Zerknij do dokumentacji na polecenie tick gdzie znajdziesz wiele przydatnych przykładów. Wesołego cykania!


10 - Niezbędna Wiedza

Ten rozdział obejmie trochę bardzo przydatnej - w zasadzie niezbędnej - wiedzy, która pozwoli Ci na wyciągnięcie maksimum możliwości z Sonic Pi.

Pokażemy tutaj jak wykorzystać wiele skrótów klawiszowych, które są dostępne, w jaki sposób możesz dzielić się swoją pracą a także parę przydatnych sztuczek dotyczących występów z Sonic Pi.


10.1 - Korzystanie ze Skrótów Klawiszowych

Sonic Pi zarówno instrumentem muzycznym jak i środowiskiem programistycznym. Skróty klawiszowe mogą więc sprawić, że granie z Sonic Pi będzie dużo bardziej wydajne i naturalne - zwłaszcza gdy gdy będziesz grać na żywo przed publicznością.

Wiele funkcji Sonic Pi może być kontrolowanych za pomocą klawiatury. Gdy posiądziesz już więcej wprawy w pracy i występach z Sonic Pi, na pewno zaczniesz używać skrótów coraz częściej i częściej. Potrafie pisać na klawiaturze bezwzrokowo (I tobie też polecam sie tego nauczyć) i czuję frustrację za każdym razem kiedy tylko muszę sięgnąć po myszkę ponieważ to mnie spowalnia. W związku z powyższym używam wszystkich tych skrótów w kółko!

Ponadto, jeśli nauczysz się skrótów, nauczysz się korzystać z twojej klawiatury dużo bardziej efektywnie i zaczniesz kodować na żywo niczym profesjonalista w bardzo krótkim czasie.

Jednakże, nie próbuj i nie ucz się ich wszystkich na raz, postaraj się sprawdzić i zapamiętać tylko te, których używasz najczęśniej. Dopiero potem postaraj się regularnie dodawać i ćwiczyć kolejne.

Spójność pomiędzy Platformami

Wyobraź sobie, że uczysz się gry na klarnecie. Zapewne oczekiwałbyś, że wszystkie klarnety będą zapewniały podobną kontrole i palcowanie. Jeśli nie, to potrzebowałbyś sporo czasu za każdym razem gdy przesiadałbyś się pomiędzy różnymi klarnetami i tak naprawdę byłbyś wtedy ograniczony do korzystania tylko z jednego wybranego modelu.

Na nieszczęście 3 podstawowe systemy operacyjne (Linux, Mac OS X i Windows) posiadają swoje własne standardy dla domyślnych akcji takich jak np. kopiuj wklej. Sonic Pi postara się honorować wszystkie te standardy. Jednakże, priorytet został położony na spójność pomiędzy różnymi platformami, na których działa Sonic Pi i jest on ważniejszy niż próby zapewnienia zgodności z poszczególnymi platformami. Oznacza to, że jeśli nauczysz się skrótów klawiszowych gdy będziesz grał na Sonic Pi na Raspberry Pi, to będziesz mógł przenieść się na komputer marki Apple z systemem Mac OS lub peceta z zainstalowanym Windows’em i dalej czuć się jak w domu.

Klawisze Control i Meta

Częścią dotyczącą pojęcia spójności jest nazewnictwo skrótów. W Sonic Pi używamy nazw Control i Meta dla odniesienia się do dwóch podstawowych klawiszy używanych w kombinacjach skrótów. Na wszystkich platformach klawisz Control odnosi się do tego samego przycisku na klawiaturze. Jednakże, w systemach Linux i Window, klawisz Meta oznacza klawisz Alt, podczas gdy w systemie Mac OS klawisz Meta oznacza klawisz Command. Dla zachowania spójności będziemy używali terminu Meta - jedyne co musisz zapamiętać to to, w jaki sposób zmapować ten termin na odpowiedni klawisz dla twojego systemu operacyjnego.

Skróty

Aby dalsze instrukcje były proste i czytelne, będziemy używać skrótu C- dla klawisza Control plus innego klawisza oraz M- dla Meta plus inny klawisz. Na przykład, jeśli skrót klawiszowy wymaga abyś nacisnął razem klawisze Meta i r zapiszemy to jako M-r. Symbol - oznacza po prostu “w tym samym czasie co”.

Przedstawię Ci kilka skrótów klawiszowych, które są dla mnie najbardziej przydatne.

Zatrzymywanie i uruchamianie

Zamiast za każdym razem sięgać po myszkę, aby uruchomić twój kod, możesz po prostu nacisnąć skrót M-r. Podobnie, aby zatrzymać uruchomiony kod możesz nacisnąć M-s.

Nawigacja

Bez skrótów umożliwiających nawigację czuję się naprawdę zagubiony. W związku z tym bardzo zalecam ci spędzić tyle czasu ile potrzeba aby się ich nauczyć. Skróty te działają również bardzo dobrze kiedy już nauczysz się pisać na klawiaturze bezwzrokowo jako, że używają one standardowych liter i nie wymagają od ciebie abyś sięgał ręka do myszki lub klawiszy ze strzałkami na twojej klawiaturze.

Możesz przenieść się do początku linii naciśniskając skrót C-a, aby przenieść się na koniec linii naciśnij C-e, aby przenieść się o 1 linię w górę naciśnij C-p, jedną linię w dół C-n, aby przesunąć sie o jeden znak do przodu użyj C-f, jeden znak do tyłu C-b. Możesz nawet usunąć wszystkie znaki od miejsca, w którym aktualinie znajduje się kursor, aż do końca linii używając skrótu C-k.

Elegacki Kod

Aby automatycznie wyrównać twój kod wystarczy, że naciśniesz M-m.

System Pomocy

Aby pokazać i ukryć system pomocy możesz nacisnąć przycisk M-i. Jednakże, dużo bardziej przydatnym skrótem, który warto znać jest C-i - pozwala on na wyszukanie w systemie pomocy słowa, na którym aktualnie znajduje się kursor i wyświetlenie tego jeśli uda mu się znaleźć cokolwiek. Pomoc błyskawiczna!

Aby zobaczyć pełną listę dostępnych skrótów klawiszowych zajrzyj do rozdziału 10.2 Ściągawka Skrótów Klawiszowych.


10.2 - Ściągawka Skrótów Klawiszowych

Poniżej dostępne jest podsumowanie najważniejszych skrótów dostępnych w Sonic Pi. Przejrzyj proszę rozdzial 10.1 dla uzyskania motywacji i tła.

Konwencje

W poniższej liście używamy następujących konwencji (gdzie Meta oznacza klawisz Alt w systemach Windows/Linux oraz Cmd w systemie Mac OS):

Postawowe Manipulowanie Aplikacją

Zaznaczanie/Kopiowanie/Wklejanie

Manipulacja Tekstu

Nawigacja

Usuwanie

Zaawansowane Funkcje Edytora


10.3 - Udostępnianie

W Sonic Pi chodzi przede wszystkim o udostępnianie i uczenie się od siebie nawzajem.

Gdy już nauczyłeś się w jaki sposób kodować muzykę, udostępnienie twojej kompozycji jest tak łatwe jak wysłanie wiadomości email, która będzie zawierać twój kod. Proszę abyś dzielił się swoim kodem z innymi, dzięki temu będą oni mogli uczyć się z twojej pracy a nawet używac kawałków twojej muzyki do tworzenia nowych mash-up’ów.

Jeśli nie jesteś pewien tego w jaki sposób możesz najlepiej dzielić się twoimi dokonaniami z innymi, to polecam Ci wrzucanie twojego kodu na stronę GitHub natomiast gotową muzykę na stronę SoundCloud. W ten sposób bardzo łatwo uda Ci się zyskać znaczną publiczność.

Kod -> GitHub

GitHub to strona umożliwiająca dzielenie się i pracę nad kodem. Jest ona używana zarówno przez profesjonalnych programistów jak ich artystów w celu udostępniania i współpracy z kodem. Najprostszą metodą aby podzielić się nowym kawałkiem kodu (nawet tym niedokończonym) jest stworzenie Gist’a Gist to bardzo prosty sposób na przesłanie twojego kodu w bardzo prosty sposób, tak żeby inni mogli go zobaczyć, skopiować i dzielić się nim.

Dźwięki -> SoundCloud

Innym bardzo ważnym sposobem na dzielenie się twoją pracą jest nagranie pliku audio i przesłanie go na stronę SoundCloud. Gdy już wrzucisz tam swój kawałek, inni użytkownicy tej strony będą mogli komentować i rozmawiać o twoim dziele. Zalecam również zamieszczenie w opisie linku do Gist’a zawierającego kod źródłowy tego utworu.

Aby nagrać twoją pracę wystarczy, że naciśniesz przycisk Rec znajdujący się w panelu z przyciskami a nagrywanie rozpocznie się natychmiast. Naciśnij więc przycisk Run aby uruchomić twój kod jeśli przypadkiem jeszcze tego nie zrobiłeś. Kiedy skończysz nagranie, naciśnij ponownie migający przycisk Rec a zostaniesz poproszony o podanie nazwy pliku pod jaką ma zostać zapisane twoje nagranie. Zostanie ono zapisane jako plik WAV, który może być bardzo łatwo przeedytowany i skonwertowany do formatu MP3 przez jeden z wielu darmowych programów (spróbuj na przykład programu Audacity).

Nadzieja

Zachęcam Cię abyś dzielił się swoją pracą i naprawdę wierzę w to, że wszyscy razem będziemy się uczyć od siebie nowych sztuczek i trików w Sonic Pi. Jestem bardzo podekscytowany tym co będziesz chciał mi pokazać.


10.4 - Występy Na Scenie

Jednym z najbardziej ekscytujących aspektów Sonic Pi jest fakt, że pozwala Ci na używanie kodu jako instrumentu muzycznego. Oznacza to, że pisanie kodu na żywo może być teraz uznawane jako nowa metoda prezentowania muzyki na scenie.

Nazywamy to Kodowaniem Na Żywo.

Pokaż Swój Ekran

Kiedy kodujesz na żywo polecam Ci abyś pokazał swojej publiczności twój ekran. W przeciwnym przypadku będzie to tak jak granie na gitarze ale chowając swoje palce i struny. Kiedy ćwiczę w domu używam Raspberry Pi i małego mini projektora na ścianie w moim salonie. Możesz użyć twojego TV albo jednego z projektorów, które są dostępne w twojej szkole lub pracy aby dać występ. Spróbuj, to świetna zabawa.

Stwórz Zespół

Nie graj tylko sam - spróbuj stworzyć zespół kodujący na żywo! Granie z innymi daje wiele radości i satysfakcji. Jedna osoba może robić bity, inna podkład w stylu ambient, itd. Spróbuj zobaczyć jakie ciekawe kombinacje dźwięków możecie razem stworzyć.

TOPLAP

Kodowanie na żywo nie jest całkowicie nowe - mała grupa ludzi robi to już od kilku lat, zazwyczaj korzystając z systemów na zamówienie, które zbudowali dla siebie sami. Świetnym miejscem do którego możesz się udać i dowiedzieć się więcej na temat innych osób kodujących na żywo oraz ich systemów jest TOPLAP.

Algorave

Innym świetnym źrodłem dla odkrywania świata kodowania na żywo jest Algorave. Możesz tutaj znaleźć wszystko co dotyczy wszystkich aspektów kodowania na żywo, które są związane z tworzeniem muzyki w klubach.


11 - Minecraft Pi

Sonic Pi wspiera proste API umożliwia interakcję z Minecraft Pi - specjalną edycją gry Minecraft, która jest domyślnie preinstalowana w systemie Raspbian na Raspberry Pi (system operacyjny bazujący na Linuksie).

Brak konieczności importowania bibliotek

Integracja z Minecraft Pi została zaprojektowana aby być szalenie łatwa w użyciu. Wszystko co potrzebujesz zrobić to włączyć Minecraft Pi i stworzyć nowy świat. Gdy już to zrobić możesz dowolnie używać funkcji mc_* tak samo jak używałeś do tej pory poleceń play i synth. Nie ma konieczności importowania czegokolwiek lub instalacji dodatkowych bibliotek - wszystko jest gotowe i działa po wyjęciu z pudełka.

Automatyczne Połączenie

API serwowane przez Minecraft Pi zajmuje się zarządzaniem twoim połączeniem z aplikacją Minecraft Pi. Oznacza to, że nie musisz się przejmować o nic. Jeśli spróbujesz skorzystać z API oferowanego przez Minecraft Pi kiedy gra nie jest włączona, Sonic Pi uprzejmie Cię o tym poinformuje. Podobnie, jeśli zamkniesz Minecraft Pi w momencie kiedy wciąż masz uruchomioną żywą pętlę live_loop, która korzysta z API, żywa pętla zatrzyma sie i uprzejmie poinformuje Cię, że nie może się połączyć. Aby wznowić połączenie wystarczy, że ponownie włączysz Minecraft Pi a Sonic Pi automatycznie wykryje i ponownie utworzy połączenie za Ciebie.

Zaprojektowanie do Kodowania Na Żywo

API oferowane przez Minecraft Pi zostało zaprojektowane w taki sposób, aby pracować bez żadnych problemów o obrębie żywych pętli tworzonych z wykorzystaniem polecenia live_loop. Oznacza to, że jest możliw a synchronizacja zmian w twoim świecie Minecraft Pi ze zmianami dokonywanymi w dźwiękach brzmiących w twoim Sonic Pi. Błyskawiczne nagrania wideo z muzyką bazujące na grze Minecraft! Jeśli jednak zdarzy się, że natrafisz na jakieś problemy, po prostu uruchom ponownie Minecraft Pi i kontynuuj wcześniejszą zabawę. Funkcjonalność automatycznego połączenia Sonic Pi zajmie się wszystkim za Ciebie.

Wymaga Raspberry Pi 2.0

Zalecane jest abyś używał Raspberry Pi 2 jeśli chcesz jednocześnie uruchomić Sonic Pi i Minecraft - zwłaszcza jeśli chcesz wykorzystać możliwości dźwiękowe Sonic Pi.

Wspierane API

Na ten moment, Sonic Pi wspiera podstawowe bloki oraz manipulacje graczy, które sa opisane w rozdziale 11.1. Wsparcie dla zdarzeń zwrotnych wywoływanych przez interakcje gracza w świecie jest planowane na przyszłe wydanie.


11.1 - Podstawowe API oferowane przez Minecraft Pi

Sonic Pi aktualnie wspiera następujące podstawowe interakcje z Minecraft Pi:

Spróbujmy przyjrzeć się każemu z nich po kolei.

Wyświetlanie wiadomości w czacie

Zobaczmy jak łatwo jest kontrolować Minecraft Pi z Sonic Pi. Najpierw, upewnij się, że zarówno Minecraft Pi jak i Sonic Pi są jednocześnie otwarte a także, upewnij się, że udało Ci się wejść do świata Minecraft i możesz się poruszać.

W czystym buforze Sonic Pi po prostu wprowadź poniższy kod:

mc_message "Hello from Sonic Pi"

Kiedy naciśniesz przycisk Run, zobaczysz migającą wiadomość w ekranie Minecraft. Gratulacje, właśnie napisałeś swój pierwszy kod w Minecraft! To było proste, prawda?

Ustawianie pozycji gracza

Teraz, spróbujmy odrobine magii. Spróbujmy przeteleportować nas w inne miejsce. Spróbuj następującego kodu:

mc_teleport 50, 50, 50

Kiedy naciśniesz Run - bum! Zostajesz błyskawicznie przetransportowany w nowe miejsce. Bardzo prawdopodobne jest to, że to gdzieś w powietrzu i spadniesz w dół na suchy ląd lub do wody. Teraz, co to za liczby: 50, 50, 50? Są to współrzędne miejsca do którego starasz się przetleportować. Poświęćmy krótką chwilę żeby dowiedzieć się czym są współrzędne i jak działają, ponieważ są one naprawdę ważne w programowaniu Minecraft.

Współrzędne

Wyobraź sobie mapę piratów z wielkim X oznacającym miejsce jakiegoś skarbu. Dokładna lokalizacja X może być opisana przez podanie dwóch liczb - jak daleko na mapie od lewej do prawej oraz jak daleko od dołu mapy w górę. Na przykład 10cm wszerz i 8cm w górę. Te dwie liczby 10 i 8 to współrzędne. Możesz bardzo łatwo wyobrazić sobie opisywanie sekretnych miejsc ze skarbami za pomocą innej pary liczb. Być może bardzo duża skrzynia złota znajduje się na 2 w poprzek 9 w górę.

Teraz, w Minecraft dwie liczby to za mało. Potrzebujemy także wiedzieć o tym, jak wysoko się znajdujemy. Dlatego też potrzebujemy 3 liczb:

Jeszcze jedna rzecz - zazwyczaj opisujemy te współrzędne w następującej kolejności x, y, z.

Odczytywanie twojej aktualnej lokalizacji

Spróbujmy pobawić się współrzędnymi. Przenieść się do jakiegoś ładnego miejsca na mapie Minecraft następnie przełącz się do Sonic Pi. Teraz wpisz następującą linijkę:

puts mc_location

Kiedy uruchomisz przycis Run zobaczysz współrzędne twojego aktualnego położenia wyświetlone w panelu z logami. Zapisz je, następnie spróbuj przemieścić się do przodu w świecie i spróbuj jeszcze raz. Zauważ, że współrzędne się zmieniły! Teraz, zalecam Ci poświęcić Ci trochę czasu na powtórzenie tego kilka razy - przenieś się gdzieś kawałek w twoim świecie, zerknij na współrzędne i powtórz. Próbuj tego do momentu, w którym poczujesz jak zmieniają się współrzędne gdy się poruszasz. Gdy już zrozumiesz jak działają współrzędne, programowanie z API oferowanym przez Minecraft będzie dla Ciebie bułką z masłem.

Zbudujmy Coś!

Teraz gdy już wiesz w jaki sposob znaleźć aktualną pozycje oraz w jaki sposob możesz się teleportować korzystając z współrzędnych, posiadasz już wszystkie narzędzia, których potrzebujesz aby zacząć budować rzeczy w Minecraft za pomocą kodu. Powiedzmy, że chciałbyś stworzyć blok ze szkła o współrzędnych 40, 50, 60. Proste:

mc_set_block :glass, 40, 50, 60

Tak, tak, to naprawde jest takie proste. Aby obejrzeć swoje dzieło po prostu przeteleportuj się niedaleko i zerknij na nie:

mc_teleport 35, 50, 60

Teraz obróć się i powinieneś zobaczyć twój blok ze szkła. Spróbuj zmienić go w diament:

mc_set_block :diamond, 40, 50, 60

Jeśli patrzyłeś w odpowiednim kierunku to być może nawet zauważyłeś jak zmienił się na twoich oczach! To początek czegoś ekscytującego…

Patrzenie na Bloki

Spróbujmy spojrzeć na ostatnią rzecz zanim zaczniemy coś bardziej angażującego. Podająć zestaw współrzędnych możemy zapytać Minecraft o to jakiego typu jest specyficzny blok. Spróbujmy tego z naszym blokiem diamentu, który stworzyłeś przed chwilą:

puts mc_get_block 40, 50, 60

Łał! To diament (:diamond)!. Spróbuj ponownie zmienić go w szkło i jeszcze raz zapytać o typ - czy teraz pokazał szkło (:glass). Jestem pewien, że tak :-)

Dostępne typy bloków

Zanim udasz oddasz się szaleństwu programowania z Minecraft Pi, być może zainteresuje Cie poniższa lista dostępnych typów bloków:

    :air
    :stone
    :grass
    :dirt
    :cobblestone
    :wood_plank
    :sapling
    :bedrock
    :water_flowing
    :water
    :water_stationary
    :lava_flowing
    :lava
    :lava_stationary
    :sand
    :gravel
    :gold_ore
    :iron_ore
    :coal_ore
    :wood
    :leaves
    :glass
    :lapis
    :lapis_lazuli_block
    :sandstone
    :bed
    :cobweb
    :grass_tall
    :flower_yellow
    :flower_cyan
    :mushroom_brown
    :mushroom_red
    :gold_block
    :gold
    :iron_block
    :iron
    :stone_slab_double
    :stone_slab
    :brick
    :brick_block
    :tnt
    :bookshelf
    :moss_stone
    :obsidian
    :torch
    :fire
    :stairs_wood
    :chest
    :diamond_ore
    :diamond_block
    :diamond
    :crafting_table
    :farmland
    :furnace_inactive
    :furnace_active
    :door_wood
    :ladder
    :stairs_cobblestone
    :door_iron
    :redstone_ore
    :snow
    :ice
    :snow_block
    :cactus
    :clay
    :sugar_cane
    :fence
    :glowstone_block
    :bedrock_invisible
    :stone_brick
    :glass_pane
    :melon
    :fence_gate
    :glowing_obsidian
    :nether_reactor_core

12 - Wnioski

Czas na podsumowanie samouczka wprowadzającego do Sonic Pi. Mam nadziję, że nauczyłeś się czegoś w trakcie jego czytania. Nie przejmuj się jeśli czujesz, że nie wszystko zrozumiałeś - po prostu graj i baw się a na pewno załapiesz kolejne rzeczy w odpowiednim dla siebie czasie. Nie krępuj się i zajrzyj tutaj ponownie jeśli będziesz miał jakieś pytanie, na które odpowiedź znajduje się w jednym z rozdziałów.

Jeśli masz jakiekolwiek pytania, na które nie znalazłeś odpowiedzi w tym samouczku, polecam Ci zajrzeć na forum Sonic Pi i zadać swoje pytanie właśnie tam. Na pewno znajdziesz tam kogoś kto bez problemu i z chęcią poda Ci pomocną dłoń.

I na koniec, zachęcam Cię również abyś przyjrzał się głebiej pozostałej części dokumentacji dostępnej w systemie pomocy. Znajdziesz tam wiele funkcjonalności, które nie zostały omówione w tym samouczku i czekają tam abyś je odkrył.

Tak więc, graj, baw się, dziel się swoim kodem, występuj na żywo przed twoimi znajomymi, pokazuj swój ekran i pamiętaj:

Błędów nie ma, są tylko nowe możliwości.

Sam Aaron