1 - Witaj, Kolego :-)

Witaj w Sonic Pi. Mam nadzieję, że jesteś podekscytowany tym, że za chwilę zaczniesz tworzyć zwariowane dźwięki tak samo, jak ja jestem podekscytowany tym, że mogę Ci to pokazać. To będzie naprawdę świetna zabawa, podczas której nauczysz się wszystkiego o muzyce, syntezie, programowaniu, kompozycji, interpretacji oraz wielu innych rzeczach.

Ale zaraz zaraz, gdzie moje maniery! Pozwól, że się przedstawię - jestem Sam Aaron - facet, który stworzył Sonic Pi. Możesz znaleźć mnie na Twitterze pod nickiem @samaaron i będzie mi bardzo miło, 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 spostrzeżenia lub pomysły, jak można ulepszyć Sonic Pi - będę wdzięczny za ich przekazanie - każda informacja zwrotna jest bardzo cenna. Nigdy nie wiadomo, być może Twój pomysł stanie się kolejną niesamowitą funkcją, która wzbogaci Sonic Pi!

Samouczek został podzielony na sekcje, które są pogrupowane według 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ś po prostu zaczął czytać dowolną z sekcji - taką, która wydaje Ci się odpowiednia dla Ciebie. Jeśli uważasz, że czegoś tutaj brakuje, daj mi o tym znać, rozważę dołożenie tego do kolejnej wersji.

Jeszcze jedna sprawa na koniec. Oglądanie innych osób kodujących na żywo jest naprawdę bardzo dobrym sposobem nauki. Regularnie nadaję na żywo na moim kanale http://youtube.com/samaaron, możesz więc wpaść, powiedzieć mi cześć i zadać dowolne pytanie :-)

Dobra, zaczynamy…


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 móc tworzyć muzykę w czasie rzeczywistym, tak samo jak podczas gry na gitarze na żywo. Oznacza to, że dzięki odpowiednim ćwiczeniom i praktyce możesz wykorzystać Sonic Pi do koncertów przed publicznością na żywo.

Uwolnij swój umysł

Zanim przejdziemy do dalszej części samouczka i zaczniemy zgłębiać szczegóły tego, w jaki sposób działa Sonic Pi, chciałbym, abyś mógł przez chwilę poczuć, czym jest Kodowanie na żywo (Live Coding). Nie przejmuj się, jeśli nic nie zrozumiesz 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:

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

A teraz naciśnij przycisk Run - usłyszysz fajne i rytmiczne uderzenia bębna. W każdym momencie możesz zatrzymać dźwięk, naciskając przycisk Stop. Na razie wstrzymaj się i jeszcze tego nie rób… Zamiast tego wykonaj następujące kroki:

Upewnij się, że wciąż słyszysz dźwięk uderzającego bębna Zmień wartość 0.5 znajdującą się przy poleceniu sleep na większą, np. 1. A teraz ponownie naciśnij przycisk Run Zauważ, jak zmieniła się szybkość uderzeń bębna. A teraz… zapamiętaj ten moment, gdyż jest to pierwszy (i prawdopodobnie nie ostatni) raz, kiedy kodujesz na żywo w Sonic Pi…

No dobra, to było całkiem łatwe. Wplećmy do naszego miksu coś jeszcze. 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ę. Zacznij zmieniać liczby - co się stanie, gdy użyjesz dużych, małych lub ujemnych liczb? Zobacz przebieg wydarzeń, gdy zmienisz odrobinę wartość parametru rate: dla sampla :ambi_choir (np. na 0.29). Co się stanie, jeśli wybierzesz naprawdę małą wartość dla parametru sleep? Zobacz, czy uda Ci się uruchomić powyższą pętlę w tak szybkim tempie, że Twój komputer zatrzyma się z powodu błędu, gdyż nie będzie w stanie nadążyć (jeśli to się zdarzy, po prostu wybierz większą wartość dla parametru sleep i ponownie naciśnij przycisk Run).

Spróbuj zrobić komentarz w jednej z linii zawierających polecenie 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 znaku # na początku linii nakazuje komputerowi, aby zignorował daną linię, dzięki temu jej nie słyszymy. Taką linijkę nazywamy komentarzem. W Sonic Pi możemy używać komentarzy do usuwania i dodawania różnych rzeczy do naszej muzyki.

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

Spróbuj zmienić wartość niebieskich wskaźników rate:, aby usłyszeć, jak zmienia się brzmienie sampli. Spróbuj zmieniać wartości parametrów sleep, dzięki czemu usłyszysz, że obie pętle mogą kręcić się z różną szybkością. Spróbuj odkomentować linijkę z samplem (usuń znak #), a usłyszysz dźwięk gitary granej od tyłu. Spróbuj zmieniać niebieską liczbę znajdującą się przy parametrze mix: na wartości pomiędzy 0 (brak dźwięku w naszym utworze) a 1 (brzmienie o normalnej głośności).

Pamiętaj tylko, żeby 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 będziesz znowu gotowy do zabawy od nowa. 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, w którym Twoja ciekawość sprawi, że zaczniesz zastanawiać się, jak to wszystko właściwie działa oraz co innego można jeszcze wyczarować za pomocą Sonic Pi. Jeśli ten moment już nastąpił, to jesteś gotów, aby przejść do dalszej części samouczka.

Więc na co czekasz…


1.2 - Interfejs użytkownika Sonic Pi

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

Interfejs Sonic Pi

A - Kontrola Odtwarzania B - Kontrola Edytora C - Informacje i Pomoc D - Edytor Kodu E - Panel Preferencji (Ustawienia) F - Podgląd Logów G - System Pomocy F - Podgląd Logów I - Cue Viewer

A. Kontrola Odtwarzania

Różowe przyciski zapewniają podstawową kontrolę nad uruchamianiem i zatrzymywaniem dźwięków. Jest przycisk Run (Uruchom), który umożliwia uruchomienie kodu znajdującego się w edytorze. Przycisk Stop (Zatrzymaj) pozwala na zatrzymanie aktualnie uruchomionego kodu. Przycisk Save (Zapisz) służy do zapisywania kodu wpisanego w edytorze do zewnętrznego pliku tekstowego. Przycisk Record (Nagrywaj) umożliwia nagranie aktualnie odtwarzanego dźwięku (w formacie WAV) .

B. Kontrola Edytora

Te pomarańczowe przyciski pozwalają Ci manipulować edytorem kodu. Przyciski Size + i Size - pozwalają Ci zwiększać i zmniejszać tekst.

C. Informacje i Pomoc

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

D. Edytor Kodu

Jest to obszar, w którym będziesz pisał kod oraz komponował i wykonywał muzykę. Jest to prosty edytor tekstowy, gdzie możesz tworzyć, kasować, 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. Na początku może się to wydawać dziwne, ale bardzo szybko zauważysz, że jest to bardzo przydatne. Na przykład - wiesz, że dany tekst jest liczbą, ponieważ ma kolor niebieski.

E. Panel preferencji

Sonic Pi wspiera wiele ustawień, które są dostępne po naciśnięciu przycisku Prefs (ustawienia). Jest to przycisk znajdujący się tuż za przyciskami Info (informacje) i Help (pomoc). Naciśnięcie go spowoduje pokazanie Panelu Ustawień, gdzie istnieje wiele opcji, które można zmieniać. 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 i selektor dźwięku, które są dostępne tylko na platformie Raspberry Pi.

F. Podgląd Logów

Kiedy uruchamiasz swój kod, informacja o tym, co program aktualnie robi, będzie wyświetlana w panelu z logami. 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 on robi.

G. System Pomocy

I na koniec została jedna z najważniejszych części interfejsu Sonic Pi - system pomocy, który pojawia się w dolnym oknie. Może on zostać włączony i wyłączony za pomocą 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, sampli (próbki dźwięków), przykłady, FX (efekty) oraz listę wszystkich funkcji, jakie Sonic Pi udostępnia do tworzenia muzyki.

H. Podgląd Zakresu

Podgląd zakresu pozwala Ci na zobaczenie dźwięków, które słyszysz. Możesz łatwo zauważyć, że dźwięki piły (saw) wyglądają jak piła oraz że podstawowy dźwięk beep jest krzywą sinusoidalną. Możesz też dostrzec różnicę pomiędzy głośnymi i cichymi dźwiękami, obserwując wielkości linii. Możesz bawić się z 3-ma typami zakresów. Domyślny zakres to kombinacja prezentująca lewy i prawy kanał. Drugi zakres to skala stereo, która rysuje oddzielne zakresy dla każdego z kanałów. Na końcu jest krzywa Lissajous, która obrazuje zależność fazową pomiędzy lewym i prawym kanałem oraz pozwala Ci na rysowanie ładnych obrazków za pomocą dźwięku (https://pl.wikipedia.org/wiki/Krzywa_Lissajous).

I. Cue Viewer

All internal and external events (called cues in Sonic Pi) are automatically logged in the Cue Viewer. For example, if you have a MIDI controller connected and press one of its buttons, you’ll see a new cue event in the Cue Viewer telling you the name of the controller and which button you pressed. Once you’ve mastered the basics of making and producing sounds, you’ll start to want to cue sounds or whole sections of sounds based on events such as these. A cue event is just an indication that something happened. For example, every time a live loop spins round, it sends a cue event out which is logged in the Cue Viewer. Also, external events such as MIDI messages from connected MIDI equipment and OSC messages from other programs or computers are also displayed in the Cue Viewer. It is also possible to directly generate cue events using the cue function. Anything that appears in the Cue Viewer can be used to trigger something happening. This is covered in more detail in Sections 10 to 12 of this tutorial.


1.3 - Nauka przez zabawę

Sonic Pi zachęca Cię, abyś uczył się programowania i tworzenia muzyki poprzez zabawę oraz eksperymentowanie. A najważniejsze jest, abyś przy tym dobrze się bawił. Nawet się nie obejrzysz, jak stwierdzisz, że nauczyłeś się programować, komponować i tworzyć muzykę na żywo.

Błędów nie ma

Skoro jesteśmy już przy tym temacie, to pozwól, że dam Ci radę. Coś, czego nauczyłem się przez lata kodowania muzyki na żywo - błędów nie ma, są tylko nowe możliwości. Jest to zdanie, które 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 niespodziewany. Czasami może brzmieć odlotowo - i w takim przypadku po prostu pozwól mu grać. Innym razem zdarzy się, że będzie brzmiał beznadziejnie i totalnie nie będzie pasował do reszty. Ale pamiętaj: to, że się to wydarzyło, jest całkowicie nieistotne - ważne jest to, co zrobisz dalej. Weź to brzmienie, zabaw się nim i przekształć go w coś niesamowitego. Tłum będzie szalał.

Zacznij od czegoś prostego

Zawsze kiedy się czegoś uczysz, istnieje pokusa, żeby robić niesamowite rzeczy tu i teraz. Postaraj się jednak powstrzymać tę chęć i spójrz na nią 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ę ze zrobienia małego kroku w kierunku realizacji wizji istniejącej w Twojej głowie. Gdy już będziesz miał pomysł na 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 w całości pochłonięty tą zabawą i będziesz robić szybkie 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 operowania syntezatorami. Syntezator to taka fajna nazwa dla czegoś, co wytwarza dźwięk. Normalnie są one 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 Sonic Pi. Jeśli tylko będziesz tego chciał, masz do swojej dyspozycji bardzo wyszukane możliwości manipulacji dźwiękiem. Lepiej zapnij pasy…


2.1 - Twoje pierwsze dźwięki

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 jeszcze 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ę? Teraz spróbuj mniejszej liczby:

play 60

Zatem, mniejsze liczby stworzą niższe dźwięki, a większe liczby stworzą wyższe dźwięki. Jak w fortepianie - klawisze po lewej stronie grają niższe nuty, a klawisze po prawej grają wyższe nuty.

Wychodzi na to, że C w czwartej oktawie (C w notacji angielskiej) jest zidentyfikowane jako numer 60. A więc play 60 zagra C z czwartej oktawy. Żeby zagrać następny spod następnego klawisza po prawej, musisz dodać 1 do 60, wpisując play 61, co w tym przypadku oznacza czarny klawisz Cis. Żeby zagrać D, czyli kolejny klawisz na prawo, napisz play 62.

Nie przejmuj się, jeśli nic z tego nie rozumiesz - ja również nie rozumiałem, gdy zaczynałem, dokładnie jak Ty teraz. Wszystko, co się teraz liczy, to to, że wiesz już, że małe liczby generują dźwięki o niskim brzmieniu, a duże liczby generują dźwięki 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, wszystkie dźwięki zagrają w tym samym momencie. Teraz spróbuj sam - które z nich brzmią dobrze razem? 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, a nie obie w tym samym czasie? Nic prostszego, wystarczy, że odczekasz chwilę pomiędzy zagraniem poszczególnych nut. Możesz to zrobić, 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 ona 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 przerwie trwającej jedną sekundę. Co powinniśmy w takim razie zrobić, jeśli chcielibyśmy trochę przyśpieszyć nasze arpeggio? Należy 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 według własnego uznania oraz używając różnych nut.

Jest jeszcze jedna rzecz, którą warto wypróbować. Spróbuj użyć tych, 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. Pokombinuj 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 jej nie znasz - nie potrzebujesz tego, ż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 liczb. Sonic Pi na to pozwala. 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, żeby umieścić dwukropek : tuż przed nazwą Twojej nuty, tak że zmieni ona kolor na różowy. Możesz również zdefiniować oktawę, umieszczając odpowiednią liczbę tuż po jej nazwie:

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ć jej dźwięk o połowę (uzyskanie dźwięku mol), dodaj na końcu niej b, np. play :Eb3.

A teraz zaszalej i spróbuj stworzyć swoje własne melodie.


2.2 - Opcje 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 tym samouczku. Ponadto w systemie pomocy jest obszerna dokumentacja szczegółowo opisująca 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.

Opcje

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

Opcje składają się z dwóch części: nazwy (kontrolowanej opcji) oraz wartości (jaką chcemy ustawić dla podanej opcji). Na przykład możesz mieć opcję, która nazywa się ser: i chciałbyś ustawić jej wartość na 1.

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

play 50, ser: 1

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

Możesz przekazać wiele opcji, oddzielając je przecinkami:

play 50, ser: 1, fasolki: 0.5

Kolejność opcji nie ma znaczenia, poniższy kod też zadziała i da taki sam wynik:

play 50, fasolki: 0.5, ser: 1

Opcje, 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 dla opcji!)

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

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

Wiele poleceń w Sonic Pi akceptuje opcje, warto więc, żebyś poświęcił parę chwil, aby nauczyć się, jak ich używać, dzięki temu będziesz ustawiony! Spróbujmy pobawić się trochę z naszą pierwszą: amp:.

Amplituda

Amplituda jest wielkością, która w świecie komputerów oznacza głośność dźwięku. Wysoka amplituda powoduje głośny dźwięk, a niska amplituda powoduje cichy dźwięk. Jak już wcześniej widziałeś, Sonic Pi używa liczb do reprezentacji czasu oraz nut. W taki sam sposób liczby są używane do reprezentacji wielkości amplitudy (głośności). Amplituda o wartości 0 to cisza (nie słyszysz nic). Natomiast amplituda o wartości 1 oznacza ustawienie głośności na standardowy poziom. Możesz podkręcić głośność wyżej, na 2, 10, 100. Musisz jednak wiedzieć, że gdy całkowita amplituda wszystkich dźwięków stanie się zbyt wysoka, Sonic Pi wykorzysta narzędzie zwane kompresorem, żeby zdusić dźwięk tak, że będzie mieć pewność, iż dźwięk nie jest zbyt głośny dla Twoich uszu. Takie działanie może spowodować, że stanie się on nieczysty i dziwny. Staraj się więc używać niskich wartości dla amplitudy, np. wartości w zakresie pomiędzy 0 a 0.5. Dzięki temu unikniesz mechanizmu kompresji.

Amplituda w górę

Aby zmienić amplitudę dźwięku, możesz użyć opcji amp:. Przykładowo żeby zagrać z głośnością na poziomie 0.5, napisz taki kawałek kodu i uruchom go:

play 60, amp: 0.5

Aby zagrać z podwójną głośnością, przekaż liczbę 2:

play 60, amp: 2

Opcja amp: modyfikuje tylko pojedyncze polecenie play, do którego została przekazana. Zauważ, że w poniższym przykładzie pierwsze wywołanie polecenia play zostanie zagrane z głośnością na poziomie równym połowie standardowej głośności, natomiast drugie zostanie zagrane z głośnością standardową (1):

play 60, amp: 0.5
sleep 0.5
play 65

Nic nie stoi na przeszkodzie, żebyś użył różnych wartości opcji amp: dla każdego 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

Kolejną fajną opcją, z której można korzystać, jest pan:. Kontroluje ona 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 prawą stronę oznacza, że usłyszysz go tylko w prawym głośniku (słuchawce). W naszym przypadku używamy wartości -1 do reprezentacji dźwięku, którego balans został w pełni ustawiony na lewą stronę, 0 dla ustawienia balansu po środku (wartość domyślna) oraz 1 dla dźwięku ustawionego na prawą stronę 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 dźwięk bip z lewego głośnika:

play 60, pan: -1

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

play 60, pan: 1

Na koniec zagrajmy go z powrotem z obu głośników pośrodku (domyślna pozycja):

play 60, pan: 0

Teraz kolej na Ciebie. Spróbuj samodzielnie pobawić się, zmieniając Twoje dźwięki za pomocą opcji amplituda (amp:) i balans (pan:)!


2.3 - Zmienianie Syntezatorów

Do tej pory bawiliśmy się całkiem nieźle, tworząc wiele fajnych dźwięków. Jest jednak bardzo prawdopodobne, że ten podstawowy dźwięk zaczyna Cię już powoli nudzić. Czy to jest wszystko, na co stać Sonic Pi? Przecież kodowanie na żywo na pewno daje dużo więcej możliwości, niż tylko granie jednego prostego dźwięku bip? Owszem, są inne możliwości. W tym rozdziale poznasz fascynującą paletę dźwięków, jaką oferuje Ci Sonic Pi.

Syntezatory

Sonic Pi posiada szeroki wachlarz instrumentów, będących syntezatorami. Zważywszy na to, że sample (próbki) reprezentują nagrane dźwięki, syntezatory mają możliwość generowania nowych dźwięków zależnych 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ł wiele radości podczas poznawania i zabawy nimi. Na początku jednak nauczmy się, jak wybierać aktualnie grający syntezator.

Brzęczące syntezatory saw i prophet

Fajnym dźwiękiem jest saw wave - spróbujmy:

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

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

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

A teraz kilka dźwięków równocześnie (nie ma sleep między kolejnymi wywołaniami play):

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

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

Odkrywanie Syntezatorów

Aby zobaczyć, jakie syntezatory Sonic Pi ma dla Ciebie do zabawy, zerknij na zakładkę Syntezatory w lewym dolnym rogu (pomiędzy Przykładami a Efektami). Znajdziesz ich tam ponad 20 do wyboru. Oto kilka moich ulubionych:

:prophet :dsaw :fm :tb303 :pulse

Teraz pobaw się, zmieniając syntezatory, gdy Twoja muzyka wciąż gra. Próbuj rozerwać się, łącząc ze sobą różne dźwięki, aby tworzyć nowe brzmienia, jak również używając 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ć polecenia sleep, aby kontrolować, kiedy dźwięki zaczynają grać. Nie wiemy jednak jeszcze, w jaki sposób kontrolować długość ich trwania.

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 dźwięku dla amplitudy ADSR (czym jest ADSR dowiesz się za chwilę w kolejnych sekcjach tego rozdziału). Obwiednia amplitudy udostępnia dwa przydatne aspekty kontroli:

kontrolę nad długością trwania dźwięku kontrolę poziomu głośności (amplitudy) dźwięku

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 całego dźwięku.

Amplituda

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 kontrolować głośność tej części, w której go słychać. Jest to analogiczne do sytuacji, w której powiedziałbyś komuś, kiedy powinien zwiększać i zmniejszać głośność wzmacniacza gitarowego. 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 już w poprzedniej sekcji samouczka, amplituda o wartości 0 to cisza, natomiast amplituda o wartości 1 to głośność normalna.

A teraz przyjrzyjmy się kolejno każdej ze składowych obwiedni.

Faza zanikania (z ang. Release Phase)

Jedyną częścią obwiedni dźwięku, która jest domyślnie używana, to faza zwolnienia (release). Odpowiada ona za czas, podczas którego następuje wyciszenie dźwięku. Domyślnie wszystkie syntezatory posiadają czas zanikania amplitudy równy 1. Oznacza to, że trwa to 1 uderzenie (przy domyślnej wartości BPM jest to 1 sekunda):

play 70

Nuta będzie odtwarzana przez 1 sekundę. Weź do ręki stoper i sprawdź :-). Jest to skrót dla dłuższej, bardziej dokładnej wersji:

play 70, release: 1

Zauważ, że brzmienie jest dokładnie takie samo (dźwięk trwa przez jedną sekundę). Jednakże teraz bardzo łatwo możemy zmienić czas trwania przez zmianę wartości opcji release:

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

Czas, podczas którego zmniejsza się głośność dźwięku, to tak zwana faza zanikania (ang. release phase) i domyślnie jest to przejście liniowe (tzn. obniżające się w linii prostej). Poniższy diagram ilustruje je:

release envelope

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

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

Faza narastania (z ang. Attack Phase)

Domyślnie faza ataku jest równa 0 dla wszystkich syntezatorów. Oznacza to, że przejście od amplitudy 0 do amplitudy 1 jest natychmiastowe. Nadaje to syntezatorowi perkusyjne brzmienie na początku. Mimo to może się zdarzyć, że będziesz chciał, aby Twój dźwięk zaczynał brzmieć stopniowo. Aby to zrobić, wystarczy wykorzystać opcję ‘attack:’. Spróbuj użyć takiego stopniowego wejś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 opcji w tym samym czasie. Na przykład dla krótkiej fazy ataku i długiej fazy zanikania spróbuj napisać i uruchomić 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ć opcje 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

Faza podtrzymania (z ang. Sustain Phase)

Oprócz możliwości ustawiania czasu narastania i czasu zanikania dźwięku, możesz również kontrolować fazę podtrzymania (z ang. Sustain Phase). Jest to moment, w którym dźwięk jest utrzymany na pełnej amplitudzie pomiędzy fazami narastania i zanikania.

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

ASR envelope

Czas podtrzymania (ang. sustain) jest bardzo przydatny dla ważnych dźwięków, którym chciałbyś dać pełną obecność w miksie tuż przed wejściem w opcjonalną fazę zanikania. Oczywiście całkowicie dopuszczalne jest ustawienie obu opcji, 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.

Faza opadania (z ang. Decay Phase)

Na sam koniec: dla momentów, gdzie potrzebujesz dodatkowego poziomu kontroli, masz możliwość skorzystania z fazy opadania (ang. decay). Jest to taki moment obwiedni dźwięku, który znajduje się pomiędzy fazą ataku a fazą podtrzymania 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

Poziom opadania

Ostatnia sztuczka polega na tym, że pomimo iż domyślna wartość opcji decay_level: jest taka sama jak wartość opcji sustain_level:, to możesz bezpośrednio zmienić jej wartość, aby mieć pełną kontrolę nad całą obwiednią dźwięku. Pozwala Ci to na tworzenie obwiedni takich, jak poniższa:

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

ASR envelope

Jest również możliwe ustawienie opcji decay_level: na wartość wyższą niż poziom sustain_level::

play 60, attack: 0.1, attack_level: 0.1, decay: 0.2, decay_level: 1, sustain: 0.5, sustain_level: 0.8, release: 1.5

ASR envelope

Obwiednia dźwięku ADSR

Podsumowując, obwiednia dźwięku ADSR w Sonic Pi posiada następujące fazy:

attack - czas narastania amplitudy od wartości 0 do poziomu maksymalnego, którego wysokość jest określana przez opcję attack_level, decay - czas opadania amplitudy od poziomu maksymalnego (attack_level) do poziomu opadania (decay_level), sustain - czas, który jest potrzebny, żeby zmienić poziom głośności dźwięku od wartości określonej przez opcję decay_level do wartości określonej przez opcję sustain_level, release - czas zanikania amplitudy od poziomu podtrzymania (sustain_level) do wartości 0

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 ustawionych na 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, attack_level: 1, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5

Tyle teorii, teraz zabaw się i spróbuj dodać różne obwiednie dźwięku do Twoich melodii…


3 - Sample

Innym świetnym sposobem tworzenia Twojej muzyki jest wykorzystanie nagranych wcześniej dźwięków. Technika ta ma swoje korzenie w muzyce hip hop i 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 stworzyłeś swój pierwszy sampel.

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


3.1 - Uruchamianie Sampli

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

sample :ambi_lunar_land

Sonic Pi posiada wiele sampli, których możesz używać do tworzenia swojej muzyki - 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 oddzielić je od siebie, 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 określa jedynie rozdzielenie wyzwalania poszczególnych dźwięków. Takie podejście pozwala na łatwe nawarstwianie kolejnych dźwięków, tworząc ciekawe efekty nakładania się na siebie.

Odkrywanie Sampli

Są dwa sposoby na odkrywanie wielu 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 reszty gotowców do wyboru. Wypróbuj następujące prefiksy kategorii:

:ambi_ :bass_ :elec_ :perc_ :guit_ :drum_ :misc_ :bd_

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ą taki 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 głośniku:

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

Zauważ, że liczba 0.877 jest połową czasu trwania sampla :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 mówiące 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óc 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, by 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ć opcję rate: do polecenia sample:

sample :ambi_choir, rate: 1

Takie polecenie sprawi, ż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ść 0.5?:

sample :ambi_choir, rate: 0.5

Łał! Co się tutaj dzieje? Otóż dwie rzeczy. Po pierwsze, odtworzenie 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 Break. 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, to wejdziemy na terytorium jungle:

sample :loop_amen, rate: 1.5

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

sample :loop_amen, rate: -1

Łał! Sampel jest odtwarzany od tyłu! A teraz spróbuj sam pokombinować z różnymi samplami, ustawiając im różne tempa. Spróbuj bardzo szybkich temp oraz niewiarygodnie niskich temp. Sprawdź, jak różne i interesujące dźwięki możesz stworzyć.

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łowę 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 została przygotowana 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 definiują 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 mogącego 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:

Podwojenie szybkości odtwarzania skraca o połowę czas odtwarzania, Skrócenie szybkości odtwarzania o połowę podwaja czas odtwarzania, Ustawienie szybkości odtwarzania równej jednej czwartej sprawi, że czas odtwarzania będzie czterokrotnie dłuższy, Ustawienie szybkości odtwarzania na poziomie 1/10 spowoduje, że czas odtwarzania zajmie 10 razy dłużej.

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 takiej sytuacji, ż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)

Miejscem, w którym zachowanie obwiedni ADSR dla sampli różni się od obwiedni dla syntezatorów, jest wartość parametru sustain. Domyślnie 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ły sampel, 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 zaokrą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 pierwsze 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.5s, 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 poprzez manualne ustawienie wartości parametru sustain: na wartość 0:

sample :loop_amen, sustain: 0, release: 0.75

Teraz nasz sampel zostanie zagrany w sumie tylko przez 0.75 sekundy. Używając 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 zachowanie, 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ę czasu. 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ąc obwiednie na sample. Próbuj również zmieniać wartości różnych parametrów obwiedni, aby otrzymać naprawdę ciekawe rezultaty.


3.5 - Kawałki Sampli

Ta sekcja sfinalizuje nasze odkrywanie odtwarzacza sampli dostępnego w Sonic Pi. Zróbmy 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, aby przykładowo zagrać wybraną próbkę 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łoby fajnie, gdybyśmy nie musieli zawsze zaczynać odtwarzania sampla od jego początku? 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ą ćwiartkę 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, by zagrać wybrane kawałki z danego sampla. Co powiesz na wycięcie tylko małego fragmentu 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 wybranych części dźwięku z naszym starym dobrym znajomym parametrem tempa rate:. Przykładowo 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 stworzyć 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 swoje utwory, opierając się tylko i wyłącznie na wbudowanych syntezatorach i samplach, kod to jedyna 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, gdyż 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, AIFF, OGG, OGA albo FLAC, znajdujący się na Twoim komputerze? Jedyne, co musisz zrobić, to przekazać jego ścieżkę do polecenia sample:

# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav"
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav"

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

# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3

3.7 - Paczki z samplami

Uwaga: Ten rozdział samouczka omawia kwestię pracy z dużymi katalogami zawierającymi Twoje sample. Jest to przypadek, w którym pobrałeś lub kupiłeś swoje własne paczki z samplami i chciałbyś ich użyć w Sonic Pi.

Możesz spokojnie pominąć ten rozdział, jeśli wystarcza Ci zestaw sampli domyślnie dostarczonych z Sonic Pi.

Kiedy pracujemy z katalogami zawierającymi duże ilości zewnętrznych sampli, wpisywanie ścieżki do każdego pliku może być bardzo uciążliwe.

Na przykład przypuśćmy, że masz na swoim komputerze następujący folder:

/path/to/my/samples/

Kiedy zajrzymy do tego katalogu, znajdziemy w nim następujące sample:

100_A#_melody1.wav 100_A#_melody2.wav 100_A#_melody3.wav 120_A#_melody4.wav 120_Bb_guit1.wav 120_Bb_piano1.wav

Zazwyczaj, jeśli chcielibyśmy użyć sampla pianino (piano), możemy użyć pełnej ścieżki do danego pliku:

sample "/path/to/my/samples/120_Bb_piano1.wav"

Jeśli chcemy później użyć sampla o brzmieniu gitary (guitar), to też możemy użyć pełnej ścieżki:

sample "/path/to/my/samples/120_Bb_guit.wav"

Jednakże w obu tych przypadkach polecenie sample wymaga od nas, żebyśmy znali nazwy sampli znajdujących się w naszym katalogu. A co, jeśli chcielibyśmy tylko szybko przesłuchać każdy z nich?

Sporządzanie indeksu dla paczki z samplami

Jeśli chcemy pierwszy sampel znajdujący się w danym katalogu, wystarczy, że przekażemy do polecenia sample nazwę tego katalogu oraz indeks 0, tak jak poniżej:

sample "/path/to/my/samples/", 0

Możemy nawet stworzyć skrót do naszego katalogu, używając zmiennej:

samps = "/path/to/my/samples/"
sample samps, 0

Teraz, jeśli chcielibyśmy zagrać drugi sampel z naszego katalogu, wystarczy, że do naszego indeksu dodamy 1:

samps = "/path/to/my/samples/"
sample samps, 1

Zauważ, że nie potrzebujemy znać nazw sampli znajdujących się naszym katalogu - musimy tylko wiedzieć, gdzie znajduje się ten katalog (lub posiadać skrót do niego). Jeśli użyjemy indeksu, który jest większy niż ilość sampli w danym katalogu, to wrócimy znowu do pierwszego sampla, tak samo jak w przypadku pracy z pierścieniami. Dlatego też niezależnie od tego, jakiej liczby użyjemy, to zawsze mamy zagwarantowane, że otrzymamy jakiegoś sampla znajdującego się w naszym katalogu.

Filtrowanie paczek z samplami

Zazwyczaj indeksowanie jest wystarczające, ale czasami potrzebujemy więcej możliwości, aby móc sortować i organizować nasze sample. Na szczęście wiele paczek z samplami umieszcza przydatne informacje w nazwach poszczególnych gotowców. Spójrzmy jeszcze raz na ich nazwy znajdujące się w naszym katalogu:

100_A#_melody1.wav 100_A#_melody2.wav 100_A#_melody3.wav 120_A#_melody4.wav 120_Bb_guit1.wav 120_Bb_piano1.wav

Zauważ, że nazwy plików zawierają całkiem sporo informacji. Po pierwsze mamy informację o tempie sampla wyrażonym w BPM (ilość uderzeń na minutę, z ang. beats per minute). Widać więc, że sampel z dźwiękiem pianina ma 120 BPM, a pozostałe trzy próbki mają po 100 BPM. Ponadto nazwy sampli zawierają informację o tonacji. Sampel z gitarą ma więc tonację B mol (Bb), a pozostałe melodie są w tonacji A fis (A#). Informacje te są bardzo przydatne, gdy chcemy użyć danego sampla w naszym kodzie. Na przykład wiemy, że możemy użyć sampla z pianinem tylko wtedy, gdy nasz kod ma tempo 120 BPM i jest w tonacji B mol (Bb).

Okazuje się, że możemy użyć tej specyficznej konwencji nazewnictwa dla naszych sampli w kodzie, żeby móc filtrować i znajdywać te, których właśnie potrzebujemy. Na przykład jeśli akurat pracujemy w tempie 120 BPM, to możemy odfiltrować tylko takie sample, które posiadają ciąg znaków "120" w następujący sposób:

samps = "/path/to/my/samples/"
sample samps, "120"

Spowoduje to, że zagramy pierwszy pasujący do tego wzorca dźwięk. Jeśli chcemy drugi sampel, który pasuje do tego wzorca, wystarczy, że użyjemy indeksu:

samps = "/path/to/my/samples/"
sample samps, "120", 1

Możemy nawet użyć kilku filtrów jednocześnie. Na przykład jeśli chcemy wszystkie sample, których nazwa pliku zawiera zarówno ciąg znaków "120" oraz "A#", możemy znaleźć je bardzo łatwo, wykorzystując taki kawałek kodu:

samps = "/path/to/my/samples/"
sample samps, "120", "A#"

Oczywiście wciąż możemy dodawać do poleceń sample nasze standardowe opcje:

samps = "/path/to/my/samples/"
sample samps, "120", "Bb", 1, lpf: 70, amp: 2

Źródła

System wstępnego przetwarzania parametrów dla funkcji filtrującej sample rozumie dwa typy informacji: źródła oraz filtry. Źródła są informacją wykorzystywaną do stworzenia listy potencjalnych kandydatów. Źródło może przyjmować 2 formy:

"/ścieżka/do/sampli" - ciąg znaków reprezentujący poprawną ścieżkę do katalogu "/ścieżka/do/sampli/foo.wav" - ciąg znaków reprezentujący poprawną ścieżkę do sampla

Funkcja sample najpierw zbierze wszystkie źródła, a następnie użyje ich do stworzenia dużej listy kandydatów. Lista ta jest konstruowana najpierw poprzez dodanie wszystkich poprawnych ścieżek, następnie zostają dodane wszystkie poprawne pliki o rozszerzeniach .flac, .aif, .aiff, .wav, .wave, które znajdują się w podanych katalogach.

Dla przykładu przyjrzyjmy się następującemu kawałkowi kodu:

samps = "/path/to/my/samples/"
samps2 = "/path/to/my/samples2/"
path = "/path/to/my/samples3/foo.wav"
sample samps, samps2, path, 0

W powyższym przykładzie łączymy wykorzystanie sampli znajdujących się w dwóch katalogach oraz dodanie jednego konkretnego sampla. Jeśli "/path/to/my/samples/" zawiera 3 sample, a "/path/to/my/samples2/" zawiera 12, to mamy w sumie 16 potencjalnych sampli do dodania do naszego indeksu i filtrów (3 + 12 + 1).

Domyślnie, tylko do listy kandydatów zostają dołączone tylko sample znajdujące się w danym katalogu. Czasami może się zdarzyć, że będziesz posiadał wiele zagnieżdżonych katalogów z samplami, które chciałbyś móc przeszukiwać i filtrować. Możesz wykonać wyszukiwanie rekurencyjne wszystkich sampli we wszystkich podfolderach danego katalogu poprzez dodanie na końcu ścieżki **:

samps = "/path/to/nested/samples/**"
sample samps, 0

Przeglądanie i wyszukiwanie sampli wśród wielu katalogów może zająć sporo czasu. Jednakże zawartość wszystkich katalogów jest buforowana, opóźnienie wystąpi więc tylko za pierwszym razem.

Na koniec zauważ, że źródła muszą iść jako pierwsze. Jeśli żadne źródła nie zostaną podane, wtedy zestaw wbudowanych sampli będzie wybrany jako domyślna lista kandydatów, z którymi będziesz pracować.

Filtry

Gdy już masz listę kandydatów, możesz wtedy użyć następującego filtrowania typów, aby ograniczyć wybór:

"foo" Ciągi znaków filtrują podzbiór znaków występujących w danej nazwie pliku (z pominięciem ścieżki katalogu oraz rozszerzenia). /fo[oO]/ Wyrażenie Regularne odfiltruje wszystkie nazwy plików pasujące do podanego wzorca (pomijając ścieżkę do pliku i rozszerzenie). :foo - Słowa kluczowe odfiltrują kandydatów, dla których słowo kluczowe jest dokładnym dopasowaniem do nazwy pliku (bez ścieżki do katalogu i rozszerzenia tego pliku). lambda{|a| ... } - Prócz z jednym argumentem będą traktowane jako kandydat do odfiltrowania lub jako funkcja generującą. Zostanie do niej przekazana lustra aktualnych kandydatów i musi sycić nową listę kandydatów (listę poprawnych ścieżek do plików z samplami). 1 - Liczby spowodują wybranie kandydata pod podanym indeksem (zataczając rundę tak jak pierścień, jeśli będzie to konieczne).

Na przykład możemy odfiltrować wszystkie sample z danego katalogu, które zawierają ciąg znaków "foo" i zagrać pierwszy pasujący sampel z prędkością równej połowie normalnego tempa:

sample "/path/to/samples", "foo", rate: 0.5

Zajrzyj do pomocy, gdzie opisane jest polecenie sample, żeby zobaczyć wiele szczegółowych przykładów użycia. Zwróć uwagę na to, iż kolejność nakładania filtrów ma znaczenie.

Kompozyty (obiekty złożone)

I na koniec chciałbym, żebyś wiedział, że wszędzie tam, gdzie wykorzystujesz źródła i filtry, możesz użyć list. Lista zostanie automatycznie spłaszczona, a jej zawartość zostanie użyta w taki sam sposób jak regularne źródła i filtry. Dlatego też poniższe użycia polecenia sample są semantycznie tożsame:

sample "/path/to/dir", "100", "C#"
sample ["/path/to/dir", "100", "C#"]
sample "/path/to/dir", ["100", "C#"]
sample ["/path/to/dir", ["100", ["C#"]]

Pakowanie

To była zaawansowana sekcja dla osób, które potrzebują potężnego narzędzia do manipulacji paczkami sampli. Nie przejmuj się, jeśli znaczna część tej sekcji jest dla Ciebie niezrozumiała. Bardzo prawdopodobne jest to, że na razie nie będzie Ci to do niczego potrzebne. Jednak będziesz tego wymagał, kiedy nadejdzie odpowiednia pora. Możesz wtedy wrócić do tej sekcji i ponownie przeczytać, w jaki sposób można radzić sobie z dużymi katalogami sampli.


4 - Losowość

Wspaniałym sposobem, aby dodać odrobine intrygi do Twojej muzyki, jest wykorzystanie paru losowych liczb. Sonic Pi posiada kilka 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)

Och, została zagrana losowa 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 naprawdę wynik nie jest losowy, jest pseudo losowy. Sonic Pi wygeneruje dla Ciebie liczby, które wyglądają jak losowe, lecz 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óbuj poniższego kawałka kodu:

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

Tak! Wreszcie uzyskaliśmy losowe dźwięki. W ramach danego uruchomienia kolejnych wywołań funkcji losującej zostaną zwrócone wartości losowe. Jednakż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 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, zatem wybierz różny odsiew dla różnych doświadczeń losowych!

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-ciu 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-ciu innych losowych nut. Zmieniając parametr odsiewu (seed) i słuchając wyników, jakie to spowodowało, możesz w końcu znaleźć taką 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 funkcjom generującym wartości losowe.

choose (wybierz)

Bardzo popularną rzeczą jest wybór losowego obiektu z listy znanych nam obiektów. Przykładowo 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):

87.5054931640625 86.05255126953125 61.77825927734375

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):

88 86 62

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 (kostka do gry)

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 samo 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-ciu 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 oraz 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. Przykładowo 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), ponieważ nie powiedzieliśmy na razie Sonic Pi, co chcielibyśmy zrobić z naszym blokiem zawartym pomiędzy poleceniami do/end. Aby to zrobić, 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 je uruchamiać 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ć kawałek kodu, który chciałbyś powtórzyć kilka razy? Przypuśćmy, ż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? Najprostszą rzeczą, którą 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ć, gdybyś chciał zmienić sampel na :elec_plip? Musiałbyś wtedy znaleźć w kodzie wszystkie miejsca, 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 do 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 do 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żych liczb 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, żeby 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, iż 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 miał zamiar podejmować losowe decyzje i na podstawie ich wyniku 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, a jeśli wypadnie 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:

Postawienie pytania (warunku) Pierwszy wybór kodu do uruchomienia (jeśli odpowiedź na nasze pytanie/warunek brzmi tak) Drugi wybór kodu do uruchomienia (jeśli odpowiedź na nasze pytanie/warunek brzmi nie)

Zazwyczaj w językach programowania pojęcie odpowiedzi “tak” jest reprezentowane przez termin true (prawda), natomiast pojęcie odpowiedzi “nie” - przez 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 przypadku 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ę między 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óżne 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ż wszystkie linijki (oprócz pierwszej) są opatrzone 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 możesz zagrać je w tym samym czasie? Jednym z możliwych rozwiązań jest przeplecenie ich razem ręcznie - najpierw zagrać jakiś bas, potem trochę bębnów, potem znowu bas… Jednakże bardzo szybko chronometraż stanie się czymś, o czym będzie ciężko myśleć, zwłaszcza kiedy zaczniemy wplatać do naszej kompozycji kolejne elementy.

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

Nieskończone Pętle

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

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

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

Wątki na Ratunek

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

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

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

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

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

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
in_thread do
  loop do
    use_synth :fm
    play 40, release: 0.2
    sleep 0.5
  end
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

Uruchamianie w Wątkach

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

Zasięg

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

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

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

Dziedziczenie

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

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

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

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

Nazywanie Wątków

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

in_thread(name: :bass) do
  loop do
    use_synth :prophet
    play chord(:e2, :m7).choose, release: 0.6
    sleep 0.5
  end
end
in_thread(name: :drums) do
  loop do
    sample :elec_snare
    sleep 1
  end
end

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

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

Tylko Jeden Wątek na Jedną Nazwę

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

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

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

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

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

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

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

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

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

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


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, by był on 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 nim podaliśmy nazwę, którą chcemy nadać naszej funkcji. Nie musieliśmy nazywać jej foo, gdyż mogliśmy to zrobić tak, jak tylko mamy na to ochotę, np. bar, baz. Dobrym pomysłem jest nadanie im znaczących coś nazw, 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 Uruchom, 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 Uruchom - 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 jednej przestrzeni roboczej, to i tak będzie on pamiętał, 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 Cię 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 ,. Dla nazw parametrów możesz użyć dowolnego słowa, jakiego chcesz.

Magia dzieje się w środku bloku do/end define. Możesz używać nazw parametrów, tak jakby były prawdziwymi wartościami. W powyższym przykładzie gram nutę n. Możesz patrzeć na parametry jak na swego rodzaju obietnice, które 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ą. Zrobiłem to samo z root dla polecenia play - 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, to tworzenie nazw dla różnych rzeczy. Sonic Pi sprawia, że jest to bardzo łatwe - wpisujesz wybraną przez siebie nazwę, znak równości (=), a następnie rzecz do zapamiętania:

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 on 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ługość 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 wprowadzić zmiany 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 sporo luzu - ale co, gdy właśnie występujesz na scenie? Czasami nie masz tego luksusu, że masz czasu tyle, ile chcesz - zwłaszcza wtedy, 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 nam 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 dobrym powodem do używania zmiennych jest przechwytywanie wyniku wykonania różnych rzeczy. Przykładowo 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 tam, gdzie potrzebujemy użyć długości trwania sampla :loop_amen.

Możliwe, że nawet bardziej ważne jest to, iż 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.

Ostrzeżenie: Zmienne i Wątki

Zmienne są świetne do nadawania rzeczom nazw oraz zapisywania wyników różnych operacji, ale musisz pamiętać, że zazwyczaj powinny być używane tylko lokalnie w ramach jednego wątku. Na przykład, nie rób tego:

a = (ring 6, 5, 4, 3, 2, 1)
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end

W powyższym przykładzie do zmiennej a przypisujemy pierścień liczb a następnie wykorzystujemy go wewnątrz dwóch różnych żywych pętli. W pierwszej pętli co każde pół uderzenia sortujemy pierścień (aby wyglądał następująco (ring 1, 2, 3, 4, 5, 6)) a następnie wyświetlamy jego zawartość w panelu z logami. Gdy uruchomisz kod, zauważysz że lista wyświetlana w logach nie zawsze jest dobrze posortowana!. Może to być dla Ciebie niespodzianką - zwłaszcza, że czasami lista jest wyświetlana jako posortowany zbiór, a czasami nie. To jest tak zwane niedeterministyczne zachowanie i jest wynikiem raczej nieprzyjemnego problemu zwanego wyścigiem. Przyczyną problemu jest fakt, że druga żywa pętla również modyfikuje listę (w tym wypadku tasuje ją) i tak naprawdę w momencie wyświetlenia czasem będzie one posortowana a czasem potasowana. Obie żywe pętle ścigają się aby zrobić coś innego z tą samą zmienną i za każdym razem ‘wygrywa’ inna pętla.

Istnieją dwa rozwiązania tego problemu. Po pierwsze, nie używaj tej samej zmiennej w wielu różnych żywych pętlach lub wątkach. Na przykład, następujący kod zawsze wyświetli posortowaną listę ponieważ każda żywa pętla ma swoją własną, niezależną zmienną:

live_loop :shuffled do
  a = (ring 6, 5, 4, 3, 2, 1)
  a = a.shuffle
  sleep 0.5
end
live_loop :sorted do
  a = (ring 6, 5, 4, 3, 2, 1)
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end

Czasami jednak zdarza się, że chcielibyśmy współdzielić rzeczy pomiędzy różnymi wątkami. Na przykład aktualną tonację, BPM, syntezator (synth), itd. W takich sytuacjach rozwiązaniem jest używanie specjalnego wątkowo-bezpiecznego systemu stanu wykorzystując funkcje get i set. Zostanie to przedyskutowane dalej w sekcji 10.


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 Uruchom. 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.

Jednakż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, który jest aktualnie uruchomiony.

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 do wszystkich innych aktualnie uruchomionych wątków. Domyślnie inne wątki nie są tym zainteresowane i ignorują tę wiadomość, jednakże możesz bardzo łatwo wywołać takie zaintrygowanie za pomocą funkcji sync.

Ważną rzeczą, której należy być świadomym, jest to, że funkcja sync wygląda podobnie 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 funkcji sync nie wiesz, jak długo będziesz chciał poczekać, ponieważ ta funkcja 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 z nich 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 słów - 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 przykładowo 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 kupić. 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 całkowicie na to pozwala. Na koniec 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ć, jak kontrolować ich parametry oraz jak je łączyć 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

Teraz uruchom ten kod, a usłyszysz, jak jest zagrany z nałożonym na niego efektem reverb. Brzmi nieźle, prawda? Wszystko łączy się 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 tych, które już widzieliśmy, gdy korzystaliśmy z poleceń play i sample. Na przykład bardzo fajnym, 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żdżać. Pozwala to na bardzo łatwe łączenie ich ze sobą. Przykładowo 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, a następnie dźwięk z nałożonym echo jest z kolei do efektu reverb.

Możemy używać wielu takich zagnieżdżeń dla 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

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

wobble, reverb, echo, distortion, slicer

A teraz powariuj trochę i dodaj efekty 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 naprawdę bardzo złożonymi bestiami. Ich prostota bardzo często kusi ludzi, by nadużywać 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 jamowania, musisz być wtedy bardzo ostrożny z tym, ile pracy mu zlecisz do wykonania, jeżeli chcesz być pewien, ż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 zagraliśmy nutę 60 z bardzo krótkim czasem zanikania (release), więc jest ona niezwykle krótka. Chcemy również nałożyć na nią efekt reverb, więc opakowaliśmy ją w blok związany z nim. 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ć oddzielny efekt gitarowy 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ętlę wewnątrz bloku with_fx. W ten sposób tworzymy tylko jeden efekt reverb dla wszystkich nut, które zostaną w niej zagrane. 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.

To jest tak często używany wzorzec, że funkcja with_fx posiada dodatkową opcję, która umożliwia nam to samo, ale bez konieczności pisania bloku 16.times:

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

Oba przykłady reps: 16 i 16.times do zachowają się tak samo. Zasadniczo kawałek ` reps: 16 spowoduje powtórzenie kodu znajdującego się w bloku do/end`. Możesz więc używać obu konstrukcji zamiennie i wybrać tę, która odpowiada Ci bardziej.

Pamiętaj jedno - błędów nie ma, są 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łoby super, gdybyś mógł zmieniać parametry dźwięku w trakcie odtwarzania danego dźwięku tak samo, jak możesz naciągnąć struny gitary, gdy jej struny wciąż wibrują?

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 przechwycenia referencji do syntezatora:

s = play 60, release: 5

Mamy tutaj zmienną lokalną s, która reprezentuje syntezator grający nutę 60. Zauważ jednak, że to jest zmienna działająca lokalnie - nie masz do niej dostępu z innych uruchomień takich jak funkcje.

Gdy już mamy zmienną s, możemy zacząć kontrolować ją za pomocą 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 - pozwala nam to na kontrolowanie takich 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. wszystkich 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 wiesz, że nie możesz kontrolować i zmieniać danego parametru, gdy syntezator już wystartuje.


7.2 - Kontrolowanie Efektów

Możliwe jest również kontrolowanie efektów, jednakż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 znajdującymi 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 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, a są to specjalne opcje, które działają tylko wtedy, gdy kontrolujesz syntezatory w taki 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ąc krótszego czasu, np. `note_slide: 0.2’, albo zwolnić je, używając dłuższego czasu przejścia (ślizgania).

Każdy z parametrów, który może być kontrolowany, posiada odpowiadający mu 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ść odpowiadają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 standardowym zestawie narzędzi każdego programisty.

Czasami będziesz chciał reprezentować i używać czegoś więcej niż tylko jednej rzeczy. Na przykład przydatna 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ę z nich tylko jedną prostą - listę.

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


8.1 - Listy

Tutaj 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 zagrać dowolny 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 ją zagrać. 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

Inną 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ż prośba kogoś, abyś otworzył książkę na stronie 23. Czy 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 pytanie: 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 pyta nas o drugi element. Musimy otoczyć go w nawiasy kwadratowe, a ponieważ liczenie zaczynamy od 0, to indeks dla drugiego elementu wynosi 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 sposób mógłbyś wykorzystać je w Twojej kolejnej zabawie kodem. 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 znacznie łatwiejsze do czytania dla innych ludzi). Jakie więc inne akordy wspiera Sonic Pi? Całkiem sporo. Spróbuj tych:

chord(:E3, :m7) chord(:E3, :minor) chord(:E3, :dim7) chord(:E3, :dom7)

Arpeggia

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

play_pattern chord(:E3, :m7)

Okej, to nie jest jakoś bardzo fajne - zostało odtworzone dość wolno. Funkcja play_pattern zagra każdą listę z przekazanej listy, oddzielają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 kawałka 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ę wygodniejszy do napisania i 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 poniższym 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, a 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, są tylko możliwości.


8.4 - Pierścienie

Ciekawym przypadkiem standardowych 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 go utworzyć oraz do tego 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]

Wspaniale, teraz otrzymaliśmy 55 i jeśli dokonamy tego jeszcze raz, otrzymamy liczbę 59. Jednakże jeśli to zrobimy, wyskoczymy poza liczby znajdujące się w naszej liście i otrzymamy nil. A co, jeśli chcieliśmy tylko stworzyć 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 masz możliwość korzystania z 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 innych funkcji, które pozwalają nam na tworzenie pierścieni.

range wymaga, abyś określił punkt startu, końca oraz rozmiar kroku. bools pozwala Ci na użycie wartości 1 i 0, aby treściwie reprezentować wartości logiczne (boolean). knit pozwala Ci na spajanie sekwencji powtarzalnych wartości. spread tworzy pierścień wartości logicznych o rozkładzie euklidesowym.

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


8.5 - Łańcuchy Pierścieni (Ring Chains)

Oprócz konstruktorów takich jak range i spread, innym sposobem tworzenia nowych pierścieni jest manipulowanie i modyfikacja istniejących pierścieni (rings).

Łańcuchy poleceń (Chain Commands)

Aby zbadać ten temat, stwórzmy prosty pierścień:

(ring 10, 20, 30, 40, 50)

Co, jeśli chcielibyśmy otrzymać wszystkie elementy tego pierścienia w odwrotnej kolejności? Wystarczy, że użyjemy w łańcuchu poleceń .reverse, aby wziąć go i odwrócić:

(ring 10, 20, 30, 40, 50).reverse  #=> (ring 50, 40, 30, 20, 10)

A co, jeśli teraz potrzebujemy tylko pierwsze trzy elementy z naszego pierścienia?

(ring 10, 20, 30, 40, 50).take(3)  #=> (ring 10, 20, 30)

I na koniec jeszcze jedno: co, jeśli chcielibyśmy przetasować elementy naszego pierścienia tak, jak tasujemy karty przed grą?

(ring 10, 20, 30, 40, 50).shuffle  #=> (ring 40, 30, 10, 50, 20)

Wielokrotność Łańcuchów

Powyższe polecenia dają bardzo duże możliwości tworzenia nowych pierścieni (rings). Jednakże prawdziwa moc pojawia się dopiero w momencie, gdy połączysz kilka poleceń w jeden łańcuch.

Co powiesz na to, aby najpierw przetasować pierścień, potem usunąć z niego 1 element, i z elementów, które pozostały, wybrać tylko pierwsze 3?

Zróbmy to krok po kroku:

(ring 10, 20, 30, 40, 50) - nasz początkowy pierścień (ring 10, 20, 30, 40, 50).shuffle - tasujemy - (ring 40, 30, 10, 50, 20) (ring 10, 20, 30, 40, 50).shuffle.drop(1) - usuwamy 1-wszy element - (ring 30, 10, 50, 20) (ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3) - pozostawiamy tylko pierwsze 3 - (ring 30, 10, 50)

Widzisz, jak łatwo możemy stworzyć długi łańcuch tych metod, sklejając je po prostu razem? Możemy użyć ich w dowolnej kolejności, na jaką nas tylko najdzie ochota. Dzięki temu mamy bardzo bogatą i potężną paletę sposobów, dzięki którym możemy tworzyć nowe pierścienie z już istniejących.

Niezmienność

Pierścienie posiadają pewną potężną i ważną cechę. Są niezmienne, co oznacza, że gdy raz zostaną już utworzone, to nie mogą zostać zmienione. Z tego wynika, że łańcuchy wywołań metod opisane w tym rozdziale nie zmieniają pierścieni, lecz tworzą nowe pierścienie. Dzięki takiemu podejściu nic nie stoi na przeszkodzie, abyś mógł współdzielić dany pierścień pomiędzy różnymi wątkami i wywoływać na nim łańcuchy metod w ramach jednego wątku, gdyż wiesz, że nie wpłynie to w żaden sposób na jakikolwiek inny wątek, który korzysta z tego samego pierścienia.

Dostępne Łańcuchy Metod

Oto lista metod, które możesz łączyć w łańcuchy wywołań:

.reverse - zwraca odwróconą wersję pierścienia .sort - tworzy posortowaną wersję pierścienia .shuffle - tworzy pierścień z wartościami, które są przetasowane .pick - zwraca pierścień zawierający wyniki pojedynczego uruchomienia funkcji .choose .pick(3) - zwraca pierścień, który zawiera 3 losowo wybrane elementy z oryginalnego pierścienia (działanie analogiczne do funkcji choose) .take(5) - zwraca nowy pierścień, który zawiera tylko 5 pierwszych elementów .drop(3) - zwraca nowy pierścień, który zawiera wszystkie elementy oprócz pierwszych 3 .butlast - zwraca nowy pierścień, który nie zawiera ostatniego elementu .drop_last(3) - zwraca nowy pierścień, który nie zawiera 3 ostatnich elementów .take_last(6)- zwraca nowy pierścień, który posiada tylko 6 ostatnich elementów .stretch(2) - powtarza każdy z elementów w pierścieniu dwukrotnie .repeat(3) - powtarza cały pierścień trzykrotnie .mirror - dodaje pierścień do odwróconej wersji samego siebie .reflect - działa tak samo jak mirror, ale nie powtarza środkowej wartości z pierścienia .scale(2) - zwraca nowy pierścień, do którego zostają załadowane wszystkie elementy po uprzednim przemnożeniu przez 2 (przy założeniu, że pierścień ten zawiera tylko liczby)

Oczywiście metody, które przyjmują jako parametr liczbę, mogą przyjmować też inne liczby! Nie krępuj się więc i spróbuj wywołać metodę .drop(5) zamiast widocznej parę linijek wyżej metody .drop(3). Pozwoli Ci to stworzyć nową listę, która nie będzie zawierała 5 pierwszych elementów.


9 - Kodowanie na żywo

Jednym z najbardziej ekscytujących aspektów Sonic Pi jest to, że możesz tworzyć muzykę poprzez pisanie i modyfikację kodu na żywo, tak samo, jakbyś 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łównym i podstawowym plusem 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

Teraz nauczyliśmy się już wystarczająco dużo, aby rozpocząć prawdziwą zabawę. W tym rozdziale będziemy czerpać ze wszystkich poprzednich i pokażę 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 składników:

Umiejętność pisania kodu, który tworzy dźwięki - JEST! Umiejętność pisania własnych funkcji - JEST! Umiejętność korzystania z (nazwanych) wątków - JEST!

W porząsiu, zaczynamy. Spróbujmy zakodować na żywo nasze pierwsze dźwięki. Najpierw potrzebujemy funkcję zawierającą 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_sound do
  play 50
  sleep 1
end
in_thread(name: :looper) do
  loop do
    my_sound
  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 funkcję 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 chwilę 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 znajdujący się w tutorialu, powinien to być właśnie ten. Jeśli zaznajomiłeś się z poprzednim 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 jamowanie 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.

Łał! Brzmienie zmieniło się automatycznie, bez utraty żadnego uderzenia. To jest Kodowanie na Żywo.

Czemu więc nie spróbować zmienić ten kawałek, aby brzmiał trochę bardziej jak linia basowa? Wystarczy, że wprowadzisz zmiany w kodzie, 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ę nastę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 konkretna ż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 wszystko będzie po prostu działać.

Synchronizacja Żywych Pętli

Jedną z rzeczy, które być może już zauważyłeś, jest 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 jedno okrążenie, generuje nowe zdarzenie cue, nadając mu nazwę taką samą, jaką nadaliśmy żywej pętli. Możemy więc synchronizować 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ć okej:

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 działa perfekcyjnie w czasie - i to wszystko bez zatrzymywania.

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


9.4 - Cykanie

Coś, 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óżnych wariacji 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:

counter = 0
live_loop :arp do
  play (scale :e3, :minor_pentatonic)[counter], release: 0.1
  counter += 1
  sleep 0.125
end

Jest to odpowiednik dla:

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ą funkcję 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 chcesz zrobić coś fantazyjnego z wartością zwracaną przy cyknięciu oraz wtedy, gdy chcesz używać cyknięć do innych rzeczy niż indeksowania elementów pierścieni.

Look (z ang. podejrzeć)

Magiczną rzeczą w cykaniu jest to, że masz możliwość nie tylko zwrócić nowy indeks (albo wartość znajdującą 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, by zobaczyć wiele różnych sposobów na pracę z nim. Jednakże na tę chwilę ważne jest zaznaczenie tego, iż 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. Masz również możliwość uruchomienia polecenia look jako standardowej funkcji lub poprzez dodanie .look na końcu pierścienia.

Nazwane Cyknięcia

Finalnie 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, jednego dla zagrania nuty i drugiego 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 żywych pętli (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óbuj 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 - Stan czasu

Bardzo często przydatne jest posiadanie informacji, która jest współdzielona pomiędzy wieloma wątkami lub żywymi pętlami. Na przykład, chciałbyś współdzielić aktualną gamę, BPM albo może nawet bardziej abstrakcyjne koncepty takie jak aktualna ‘złożoność’ (coś co mógłbyś interpretować na różne sposoby w różnych wątkach). Ponadto nie chcemy także zgubić żadnego z naszych istniejących i deterministycznych mechanizmów gdy to robimy. Innymi słowy, chcielibyśmy być w stanie współdzielić kod z innymi i być stuprocentowo pewnymi tego, że usłyszą to co chcemy gdy go uruchomią. Pod koniec Sekcji 5.6 tego samouczka krótko wyjaśniliśmy dlaczego nie powinniśmy używać zmiennych do współdzielenia informacji pomiędzy różnymi wątkami ze względu na możliwość utraty determinizmu (to z kolei z powodu wyścigu wątków).

Sonic Pi umożliwia rozwiązanie problemu łatwej pracy z globalnymi zmiennymi w deterministyczny sposób poprzez nowatorski system, który nazywa się Stan Czasu. Może to brzmieć trochę skomplikowanie (i rzeczywiście, w Wielkiej Brytanii, programowanie z wykorzystaniem wielu wątków i współdzielonej pamięci to temat na poziomie typowo uniwersyteckim). Jednakże, jak niedługo zobaczysz, dokładnie tak samo jak zagranie twojej pierwszej nuty, Sonic Pi sprawia, że współdzielenie stanu pomiędzy wątkami jest niezwykle łatwe a jednocześnie sprawia, że twoje programy są bezpieczne z punktu widzenia wielowątkowości oraz deterministyczne..

Poznaj get i set


10.1 - Set i Get

Sonic Pi posiada globalny magazyn pamięci nazywany Stanem Czasu. Dwie podstawowe operacje jakie możesz na nim wykonywać to ustawienie informacji (set) oraz pobranie informacji (get). Zanurzmy się głębiej…

Set

Aby dodać jakąś informację do Stanu Czasu musimy zrobić dwie rzeczy:

informacja, którą zamierzamy dodać, unikalna nazwa (klucz) dla naszej informacji.

Na przykład, możemy chcieć zachować liczbę 3000 pod kluczem :intensity (intensywność). Można to zrobić używając funkcji set:

set :intensity, 3000

Możemy użyć dowolnej nazwy dla naszego klucza (key). Jeśli jakaś informacja została już zapisana pod tym kluczem, nasze nowe ustawienie (set) nadpisze je:

set :intensity, 1000
set :intensity, 3000

W powyższym przykładzie, jako że zapisaliśmy obie liczby pod tym samym kluczem, ostanie uruchomienie funkcji set ‘wygrywa’. Wynika z tego, że liczba powiązana z :intensity będzie wynosić 3000 ponieważ pierwsze wywołanie funkcji set zostało efektywnie nadpisane.

Pobierz (Get)

Aby pobrać informację ze Stanu Czasu (Time State) potrzebujemy tylko klucza, którego użyliśmy do ustawienia go za pomocą funkcji set, w naszym przypadku jest to :intensity. Następnie musimy tylko uruchomić polecenie get[:intensity] i będziemy mogli podejrzeć tę wartość poprzez wyświetlenie wyniku w panelu z logami:

print get[:intensity] #=> prints 3000

Zauważ, że odwołanie do get może zwrócić informację która została ustawiona (set) w poprzednim uruchomieniu. Gdy już raz pewna informacja zostanie ustawiona za pomocą polecenia set staje się ona dostępna dopóki nie zostanie nadpisana (dokładnie tak samo jak zmieniliśmy wartość dostępną pod symbolem:intensityz 1000 na 3000 powyżej) lub Sonic PI zostanie zamknięty.

Wiele Wątków

Podstawową korzyścią systemu Stanu Czasu (Time State) jest to, że może być on bezpiecznie używany pomiędzy różnymi wątkami oraz żywymi pętlami. Na przykład, możesz mieć jedną żywą pętlę, która ustawia pewną informację oraz inną, która ją wyciąga:

live_loop :setter do
  set :foo, rrand(70, 130)
  sleep 1
end
live_loop :getter do
  puts get[:foo]
  sleep 0.5
end

Ogromną zaletą korzystania z funkcji set i get w różnych wątkach jest fakt, że zawsze dają one ten sam wynik przy uruchomieniu przycisku ‘Run’. Dalej, spróbuj sam. Sprawdź czy dostaniesz taki sam rezultat w swoich logach:

{run: 0, time: 0.0}
 └─ 125.72265625
{run: 0, time: 0.5}
 └─ 125.72265625
{run: 0, time: 1.0}
 └─ 76.26220703125
{run: 0, time: 1.5}
 └─ 76.26220703125
{run: 0, time: 2.0}
 └─ 114.93408203125
{run: 0, time: 2.5}
 └─ 114.93408203125
{run: 0, time: 3.0}
 └─ 75.6048583984375
{run: 0, time: 3.5}
 └─ 75.6048583984375

Spróbuj uruchomić to kilkukrotnie - zauważ, że za każdym razem wynik jest taki sam. To jest właśnie coś co nazywamy zachowaniem deterministycznym. Jest to bardzo ważne gdy chcemy podzielić się naszą muzyką jako kodem. Zależy nam na tym aby osoba uruchamiająca nasz kod usłyszała dokładnie to co chcieliśmy aby usłyszała (dokładnie tak samo jak z odtworzeniem utworu MP3 czy stream’a z dźwiękiem w internecie brzmi identycznie dla każdego ze słuchaczy).

Prosty Deterministyczny System Stanu

Wcześniej w Sekcji 5.6 rozważaliśmy dlaczego wykorzystywanie zmiennych w różnych wątkach może prowadzić do nieoczekiwanych zachowań. Powoduje to, że nie jesteśmy w stanie wiarygodnie odtworzyć kod taki jak ten:

## An Example of Non-Deterministic Behaviour
## (due to race conditions caused by multiple
## live loops manipulating the same variable
## at the same time).
##  
## If you run this code you'll notice
## that the list that's printed is
## not always sorted!
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end

Spróbujmy zobaczyć jak mogłoby to wyglądać gdybyśmy użyli funkcji get i set:

## An Example of Deterministic Behaviour
## (despite concurrent access of shared state)
## using Sonic Pi's new Time State system.
##
## When this code is executed, the list that's
## printed is always sorted!
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  set :a, get[:a].shuffle
  sleep 0.5
end
live_loop :sorted do
  set :a, get[:a].sort
  sleep 0.5
  puts "sorted: ", get[:a]
end

Zauważ, że ten kod jest prawie identyczny z wersją, w której używaliśmy wcześniej zmiennej. Jednakże, kiedy uruchomisz ten kod, zacznie się on zachowywać tak jakbyś tego oczekiwał od typowego kodu Sonic Pi - w tym wypadku za każdym razem jest wykonywana ta sama rzecz, wszystko dzięki systemowi Stanu Czasu (Time State).

Dlatego, gdy współdzielimy informację pomiędzy różnymi żywymi pętlami i wątkami, używajmy funkcji get i set zamiast zmiennych aby otrzymać deterministyczne i powtarzalne zachowanie.


10.2 - Sync

Sekcja 5.7 wprowadziła funkcje cue i sync, mieliśmy wtedy do czynienia z problemem synchronizacji wątków. To co nie zostało wytłumaczone to fakt, że funkcjonalność ta jest zapewniona przez system Stanu Czasu (Time State). Tak się właśnie dzieje gdyż funkcja set jest w zasadzie wariacją funkcji cue i jest zbudowana na bazie tej samej podstawowej funkcjonalności, która pozwala na umieszczenie informacji w systemie Stanu Czasu. Ponadto, sync jest również zaprojektowany w taki sposób, że działa bezproblemowo z Stanem Czasu - do każdej informacji, którą chcielibyśmy umieścić w Stanie Czasu, możemy się zsynchronizować. Innymi słowy - synchronizujemy się (sync) na zdarzeniach, które będą umieszczone w Stanie Czasu.

Czekając na Zdarzenia

Spróbujmy spojrzeć szybko jak należy używać polecenia sync aby móc poczekać aby nowe zdarzenia zostały dodane do Stanu Czasu (Time State):

in_thread do
  sync :foo
  sample :ambi_lunar_land
end
sleep 2
set :foo, 1

W tym przykładzie najpierw tworzymy wątek, który czeka na zdarzenie :foo aby można go było dodać do Stanu Czasu. Po zadeklarowaniu tego wątku śpimy przez 2 uderzenia i następnie ustawiamy (set) :foo na wartość 1. To z kolei zwalnia sync co pozwala na przeniesienie się do kolejnej linii, w której zostaje wywołany sampel :ambi_lunar_land.

Zauważ, że funkcja sync zawsze czeka na przyszłe zdarzenia, i że zablokuje on aktualny wątek w oczekiwaniu na kolejne zdarzenie. Ponadto, odziedziczy ona czas logiczny wątku, który wywołał ją poprzez funkcję set lub cue, więc może też być używana do synchronizowania czasu.

Przekazywanie wartości w Przyszłość

W przykładzie powyżej nadajemy :foo wartość 1 i nic z nią nie robimy. Możemy właściwie pobrać tę wartość wewnątrz wątku korzystając z sync:

in_thread do
  amp = sync :foo
  sample :ambi_lunar_land, amp: amp
end
sleep 2
set :foo, 0.5

Zauważ, że wartości które są przekazywane do funkcji set i cue muszą być bezpieczne dla wątków - np. niezmienne pierścienie (rings) liczby, symbole lub zamrożone łańcuch znaków (strings). Sonic Pi rzuci błąd jeśli wartość którą próbujesz umieścić w Stanie Czasu (Time State) jest niepoprawna.


10.3 - Dopasowanie do wzorca

Kiedy pobieramy i ustawiamy informacje w Stanie Czasu (Time State), możemy używać bardziej złożonych kluczy niż podstawowe symbole takie jak :foo czy ‘:bar. Możesz także używać ciągów znaków w stylu adresów URL zwanymi ścieżkami, np. “/foo/bar/baz”. Gdy już zaczniemy pracować ze ścieżkami, możemy wtedy zacząć korzystać z wyrafinowanego systemu dopasowania wzorców Sonic Pi aby pobierać (get) i synchronizować (sync`) się z ‘podobnymi’ a niekoniecznie ‘takimi samymi’ ścieżkami. Rzućmy okiem.

Dopasuj dowolny segment w ścieżce

Załóżmy, że chcemy poczekać na kolejne zdarzenie, które posiada trzy segmenty w ścieżce:

sync "/*/*/*"

Spowoduje to dopasowanie do dowolnego zdarzenia w Stanie Czasu posiadającego dokładnie trzy segmenty ścieżki, bez względu na ich nazwy. Na przykład:

cue "/foo/bar/baz" cue "/foo/baz/quux" cue "/eggs/beans/toast" cue "/moog/synths/rule"

Jednakże, nie zostaną dopasowane ścieżki z mniejszą lub większą ilością segmentów. Poniższe nie zostaną dopasowane:

cue "/foo/bar" cue "/foo/baz/quux/quaax" cue "/eggs"

Każda gwiazdka * oznacza dowolną treść. Możemy więc dopasować ścieżki tylko z jednym segmentem używając /* lub ścieżek z pięcioma segmentami używając /*/*/*/*/*

Częściowe dopasowanie segmentów

If we know what the segment is going to start or finish with, we can use a * in addition to a partial segment name. For example: "/foo/b*/baz" will match any path that has three segments, the first of which is foo, the last baz and the middle segment can be anything that starts with b. So, it would match:

cue "/foo/bar/baz" cue "/foo/baz/baz" cue "/foo/beans/baz"

However, it wouldn’t match the following:

cue "/foo/flibble/baz" cue "/foo/abaz/baz" cue "/foo/beans/baz/eggs"

You can also place the * at the start of the segment to specify the last characters of a segment: "/foo/*zz/baz" which will match any 3 segment cue or set where the first segment is foo, the last is baz and the middle segment ends with zz such as "cue "/foo/whizz/baz".

Matching Nested Path Segments

Sometimes you don’t know how many path segments you want to match. In these cases you can use the powerful double star: ** such as "/foo/**/baz" which will match:

cue "/foo/bar/baz" cue "/foo/bar/beans/baz" cue "/foo/baz" cue "/foo/a/b/c/d/e/f/baz"

Matching Single Letters

You can use the ? character to match against a single char such as "/?oo/bar/baz" which will match:

cue "/foo/bar/baz" cue "/goo/bar/baz" cue "/too/bar/baz" cue "/woo/bar/baz"

Matching Multiple Words

If you know that a segment may be one of a select number of words, you can use the { and } matchers to specify a list of choices such as "/foo/{bar,beans,eggs}/quux" which will only match the following:

cue "/foo/bar/quux" cue "/foo/beans/quux" cue "/foo/eggs/quux"

Matching Multiple Letters

Finally, you can match against a selection of letters if you use the [ and ] matchers to specify a list of choices such as "/foo/[abc]ux/baz" which will match only:

cue "/foo/aux/baz" cue "/foo/bux/baz" cue "/foo/cux/baz"

You can also use the - character to specify ranges of letters. For example "/foo/[a-e]ux/baz" which will match only:

cue "/foo/aux/baz" cue "/foo/bux/baz" cue "/foo/cux/baz" cue "/foo/dux/baz" cue "/foo/eux/baz"

Combining Matchers

When calling sync or get you are free to combine matchers in any order you see fit to powerfully match any Time State event created by cue or set. Let’s look at a crazy example:

in_thread do
  sync "/?oo/[a-z]*/**/ba*/{quux,quaax}/"
  sample :loop_amen
end
sleep 1
cue "/foo/beans/a/b/c/d/e/bark/quux/"

OSC Pattern Matching

For those curious, these matching rules are based on the Open Sound Control pattern matching specification which is explained in detail here: http://opensoundcontrol.org/spec-1_0


11 - MIDI

Once you’ve mastered converting code to music, you might wonder - what’s next? Sometimes the constraints of working purely within Sonic Pi’s syntax and sound system can be exciting and put you into a new creative position. However, sometimes it is essential to break out of the code into the real world. We want two extra things:

To be able to convert actions in the real world into Sonic Pi events to code with To be able to use Sonic Pi’s strong timing model and semantics to control and manipulate objects in the real world

Luckily there’s a protocol that’s been around since the 80s that enables exactly this kind of interaction - MIDI. There’s an incredible number of external devices including keyboards, controllers, sequencers, and pro audio software that all support MIDI. We can use MIDI to receive data and also use it to send data.

Sonic Pi provides full support for the MIDI protocol enabling you to connect your live code to the real world. Let’s explore it further…


11.1 - MIDI In

In this section we will learn how to connect a MIDI controller to send events into Sonic Pi to control our synths and sounds. Go and grab a MIDI controller such as a keyboard or control surface and let’s get physical!

Connecting a MIDI Controller

In order to get information from an external MIDI device into Sonic Pi we first need to connect it to our computer. Typically this will be via a USB connection, although older equipment will have a 5-pin DIN connector for which you’ll need hardware support for your computer (for example, some sound cards have MIDI DIN connectors). Once you’ve connected your device, launch Sonic Pi and take a look at the IO section of the Preferences panel. You should see your device listed there. If not, try hitting the ‘Reset MIDI’ button and see if it appears. If you’re still not seeing anything, the next thing to try is to consult your operating system’s MIDI config to see if it sees your device. Failing all that, feel free to ask questions in our friendly forums: https://in-thread.sonic-pi.net

Receiving MIDI Events

Once your device is connected, Sonic Pi will automatically receive events. You can see for yourself by manipulating your MIDI device and looking at the cue logger in the bottom right of the application window below the log (if this isn’t visible go to Preferences->Editor->Show & Hide and enable the ‘Show cue log’ tickbox). You’ll see a stream of events such as:

/midi:nanokey2_keyboard:0:1/note_off  [55, 64]
/midi:nanokey2_keyboard:0:1/note_on   [53, 102]
/midi:nanokey2_keyboard:0:1/note_off  [57, 64]
/midi:nanokey2_keyboard:0:1/note_off  [53, 64]
/midi:nanokey2_keyboard:0:1/note_on   [57, 87]
/midi:nanokey2_keyboard:0:1/note_on   [55, 81]
/midi:nanokey2_keyboard:0:1/note_on   [53, 96]
/midi:nanokey2_keyboard:0:1/note_off  [55, 64]

Once you can see a stream of messages like this, you’ve successfully connected your MIDI device. Congratulations, let’s see what we can do with it!

MIDI Time State

Stan czasu

Kontrolowanie Kodu

Now we’ve connected a MIDI device, seen its events in the cue log and discovered that our knowledge of Time State is all we need to work with the events, we can now start having fun. Let’s build a simple MIDI piano:

live_loop :midi_piano do
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note
end

There’s a few things going on in the code above including some issues. Firstly, we have a simple live_loop which will repeat forever running the code between the do/end block. This was introduced in Section 9.2. Secondly, we’re calling sync to wait for the next matching Time State event. We use a string representing the MIDI message we’re looking for (which is the same as was displayed in the cue logger). Notice that this long string is provided to you by Sonic Pi’s autocompletion system, so you don’t have to type it all out by hand. In the log we saw that there were two values for each MIDI note on event, so we assign the result to two separate variables note and velocity. Finally we trigger the :piano synth passing our note.

Now, you try it. Type in the code above, replace the sync key with a string matching your specific MIDI device and hit Run. Hey presto, you have a working piano! However, you’ll probably notice a couple of problems: firstly all the notes are the same volume regardless of how hard you hit the keyboard. This can be easily fixed by using the velocity MIDI value and converting it to an amplitude. Given that MIDI has a range of 0->127, to convert this number to a value between 0->1 we just need to divide it by 127:

live_loop :midi_piano do
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end

Update the code and hit Run again. Now the velocity of the keyboard is honoured. Next, let’s get rid of that pesky pause.

Removing Latency

Before we can remove the pause, we need to know why it’s there. In order to keep all the synths and FX well-timed across a variety of differently capable CPUs, Sonic Pi schedules the audio in advance by 0.5s by default. (Note that this added latency can be configured via the fns set_sched_ahead_time! and use_sched_ahead_time). This 0.5s latency is being added to our :piano synth triggers as it is added to all synths triggered by Sonic Pi. Typically we really want this added latency as it means all synths will be well timed. However, this only makes sense for synths triggered by code using play and sleep. In this case, we’re actually triggering the :piano synth with our external MIDI device and therefore don’t want Sonic Pi to control the timing for us. We can turn off this latency with the command use_real_time which disables the latency for the current thread. This means you can use real time mode for live loops that have their timing controlled by syncing with external devices, and keep the default latency for all other live loops. Let’s see:

live_loop :midi_piano do
  use_real_time
  note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end

Update your code to match the code above and hit Run again. Now we have a low latency piano with variable velocity coded in just 5 lines. Wasn’t that easy!

Wyciąganie Wartości

Finally, as our MIDI events are going straight into the Time State, we can also use the get fn to retrieve the last seen value. This doesn’t block the current thread and returns nil if there’s no value to be found (which you can override by passing a default value - see the docs for get). Remember that you can call get in any thread at any time to see the latest matching Time State value. You can even use time_warp to jump back in time and call get to see past events…

Now You are in Control

The exciting thing now is that you can now use the same code structures to sync and get MIDI information from any MIDI device and do whatever you want with the values. You can now choose what your MIDI device will do!


11.2 - MIDI Out

In addition to receiving MIDI events we can also send out MIDI events to trigger and control external hardware synths, keyboards and other devices. Sonic Pi provides a full set of fns for sending various MIDI messages such as:

Note on - midi_note_on Note off - midi_note_off Control change - midi_cc Pitch bend - midi_pitch_bend Clock ticks - midi_clock_tick

There are many other supported MIDI messages too - check out the API documentation for all the other fns that start with midi_.

Connecting to a MIDI Device

In order to send a MIDI message to an external device, we must first have connected it. Check out the subsection ‘Connecting a MIDI Controller’ in section 11.1 for further details. Note that if you’re using USB, connecting to a device which you’re sending to (rather than receiving from) is the same procedure. However, if you’re using the classic DIN connectors, make sure you connect to the MIDI out port of your computer. You should see your MIDI device listed in the preferences pane.

Sending MIDI events

The many midi_* fns work just like play, sample and synth in that they send a message at the current (logical) time. For example, to spread out calls to the midi_* fns you need to use sleep just like you did with play. Let’s take a look:

midi_note_on :e3, 50

This will send a MIDI note on event to the connected MIDI device with velocity 50. (Note that Sonic Pi will automatically convert notes in the form :e3 to their corresponding MIDI number such as 52 in this case.)

If your connected MIDI device is a synthesiser, you should be able to hear it playing a note. To disable it use midi_note_off:

midi_note_off :e3

Selecting a MIDI device

By default, Sonic Pi will send each MIDI message to all connected devices on all MIDI channels. This is to make it easy to work with a single connected device without having to configure anything. However, sometimes a MIDI device will treat MIDI channels in a special way (perhaps each note has a separate channel) and also you may wish to connect more than one MIDI device at the same time. In more complicated setups, you may wish to be more selective about which MIDI device receives which message(s) and on which channel.

We can specify which device to send to using the port: opt, using the device name as displayed in the preferences:

midi_note_on :e3, port: "moog_minitaur"

We can also specify which channel to send to using the channel: opt (using a value in the range 1-16):

midi_note_on :e3, channel: 3

Of course we can also specify both at the same time to send to a specific device on a specific channel:

midi_note_on :e3, port: "moog_minitaur", channel: 5

MIDI Studio

Finally, a really fun thing to do is to connect the audio output of your MIDI synthesiser to one of the audio inputs of your soundcard. You can then control your synth with code using the midi_* fns and also manipulate the audio using live_audio and FX:

with_fx :reverb, room: 1 do
  live_audio :moog
end
live_loop :moog_trigger do
  use_real_time
  midi (octs :e1, 3).tick, sustain: 0.1
  sleep 0.125
end

(The fn midi is available as a handy shortcut to sending both note on and note off events with a single command. Check out its documentation for further information).


12 - OSC

In addition to MIDI, another way to get information in and out of Sonic Pi is via the network using a simple protocol called OSC - Open Sound Control. This will let you send messages to and from external programs (both running on your computer and on external computers) which opens up the potential for control way beyond MIDI which has limitations due to its 1980s design.

For example, you could write a program in another programming language which sends and receives OSC (there are OSC libraries for pretty much every common language) and work directly with Sonic Pi. What you can use this for is only limited by your imagination.


12.1 - Receiving OSC

Stan czasu

A Basic OSC Listener

Let’s build a basic OSC listener:

live_loop :foo do
  use_real_time
  a, b, c = sync "/osc/trigger/prophet"
  synth :prophet, note: a, cutoff: b, sustain: c
end

In this example we described an OSC path "/osc*/trigger/prophet" which we’re syncing on. This can be any valid OSC path (all letters and numbers are supported and the / is used like in a URL to break up the path to multiple words). The /osc prefix is added by Sonic Pi to all incoming OSC messages, so we need to send an OSC message with the path /trigger/prophet for our sync to stop blocking and the prophet synth to be triggered.

Sending OSC to Sonic Pi

We can send OSC to Sonic Pi from any programming language that has an OSC library. For example, if we’re sending OSC from Python we might do something like this:

from pythonosc import osc_message_builder
from pythonosc import udp_client
sender = udp_client.SimpleUDPClient('127.0.0.1', 4560)
sender.send_message('/trigger/prophet', [70, 100, 8])

Or, if we’re sending OSC from Clojure we might do something like this from the REPL:

(use 'overtone.core)
(def c (osc-client "127.0.0.1" 4560))
(osc-send c "/trigger/prophet" 70 100 8)

Receiving from External Machines

For security reasons, by default Sonic Pi does not let remote machines send it OSC messages. However, you can enable support for remote machines in Preferences->IO->Network->Receive Remote OSC Messages. Once you’ve enabled this, you can receive OSC messages from any computer on your network. Typically the sending machine will need to know your IP address (a unique identifier for your computer on your network - kind of like a phone number or an email address). You can discover the IP address of your computer by looking at the IO section of the preferences pane. (If your machine happens to have more than one IP address, hovering the mouse over the listed address will pop up with a list of all known addresses).

Note, some programs such as TouchOSC for iPhone and Android support sending OSC as a standard feature. So, once you’re listening to remote machines and know your IP address you can instantly start sending messages from apps like TouchOSC which enable you to build your own custom touch controls with sliders, buttons, dials etc. This can provide you with an enormous range of input options.


12.2 - Sending OSC

In addition to receiving OSC and working with it using Time State, we can also send out OSC messages in time with our music (just like we can send out MIDI messages in time with our music). We just need to know which IP address and port we’re sending to. Let’s give it a try:

use_osc "localhost", 4560
osc "/hello/world"

If you run the code above, you’ll notice that Sonic Pi is sending itself an OSC message! This is because we set the IP address to the current machine and the port to the default OSC in port. This is essentially the same as posting a letter to yourself - the OSC packet is created, leaves Sonic Pi, gets to the network stack of the operating system which then routes the packed back to Sonic Pi and then it’s received as a standard OSC message and is visible in the cue logger as the incoming message /osc:127.0.0.1:4560/hello/world. (Notice how Sonic Pi automatically prefixes all incoming OSC messages with /osc and then the hostname and port of the sender.)

Sending OSC to other programs

Of course, sending OSC messages to ourselves may be fun but it’s not that useful. The real benefit starts when we send messages to other programs:

use_osc "localhost", 123456
osc "/hello/world"

In this case we’re assuming there’s another program on the same machine listening to port 123456. If there is, then it will receive a "/hello/world OSC message with which it can do what it wants.

If our program is running on another machine, we need to know its IP address which we use instead of "localhost":

use_osc "192.168.10.23", 123456
osc "/hello/world"

Now we can send OSC messages to any device reachable to us via our local networks and even the internet!


13 - Multichannel Audio

So far, in terms of sound production, we’ve explored triggering synths and recorded sounds via the fns play, synth and sample. These have then generated audio which has played through our stereo speaker system. However, many computers also have the ability to input sound, perhaps through a microphone, in addition to the ability to send sound out to more than two speakers. Often, this capability is made possible through the use of an external sound card - these are available for all platforms. In this section of the tutorial we’ll take a look at how we can take advantage of these external sound cards and effortlessly work with multiple channels of audio in and out of Sonic Pi.


13.1 - Sound In

One simple (and perhaps familiar) way of accessing sound inputs is using our friend synth by specifying the :sound_in synth:

synth :sound_in

This will operate just like any synth such as synth :dsaw with the exception that the audio generated will be read directly from the first input of your system’s sound card. On laptops, this is typically the built-in microphone, but if you have an external sound card, you can plug any audio input to the first input.

Zwiększanie Czasu Trwania

One thing you might notice is that just like synth :dsaw the :sound_in synth only lasts for 1 beat as it has a standard envelope. If you’d like to keep it open for a little longer, change the ADSR envelope settings. For example the following will keep the synth open for 8 beats before closing the connection:

synth :sound_in, sustain: 8

Dodawanie Efektów

Of course, just like any normal synth, you can easily layer on effects with the FX block:

with_fx :reverb do
  with_fx :distortion do
    synth :sound_in, sustain: 8
  end
end

If you have plugged in a guitar to your first input, you should be able to hear it with distortion and reverb until the synth terminates as expected.

You are free to use the :sound_in synth as many times as you like concurrently (just like you would do with any normal synth). For example, the following will play two :sound_in synths at the same time - one through distortion and one through reverb:

with_fx :distortion do
  synth :sound_in, sustain: 8
end
with_fx :reverb do  
  synth :sound_in, sustain: 8
end

Wiele Wejść

You can select which audio input you want to play with the input: opt. You can also specify a stereo input (two consecutive inputs) using the :sound_in_stereo synth. For example, if you have a sound card with at least three inputs, you can treat the first two as a stereo stream and add distortion and the third as a mono stream and add reverb with the following code:

with_fx :distortion do
  synth :sound_in_stereo, sustain: 8, input: 1
end
with_fx :reverb do  
  synth :sound_in, sustain: 8, input: 3
end

Potential Issues

However, although this is a useful technique, there are a couple of limitations to this approach. Firstly, it only works for a specific duration (due to it having an ADSR envelope) and secondly, there’s no way to switch the FX around once the synth has been triggered. Both of these things are typical requests when working with external audio feeds such as microphones, guitars and external synthesisers. We’ll therefore take a look at Sonic Pi’s solution to the problem of manipulating a (potentially) infinite stream of live audio input: live_audio.


13.2 - Dźwięk Na Żywo

The :sound_in synth as described in the previous section provides a very flexible and familiar method for working with input audio. However, as also discussed it has a few issues when working with a single input of audio as a single instrument (such as a voice or guitar). By far the best approach to working with a single continuous stream of audio is to use live_audio.

A Named Audio Input

live_audio shares a couple of core design constraints with live_loop (hence the similar name). Firstly it must have a unique name and secondly only one live_audio stream with that name may exist at any one time. Let’s take a look:

live_audio :foo

This code will act in a similar fashion to synth :sound_in with some key differences: it runs forever (until you explicitly stop it) and you can move it to new FX contexts dynamically.

Working with FX

On initial triggering live_audio works exactly as you might expect it to work with FX. For example, to start a live audio stream with added reverb simply use a :reverb FX block:

with_fx :reverb do
  live_audio :foo
end

However, given that live_audio runs forever (at least until you stop it) it would be pretty limiting if, like typical synths, the live audio was bound within the :reverb FX for its entire existence. Luckily this is not the case and it was designed to be easy to move between different FX. Let’s try it. Run the code above to hear live audio coming directly from the first input of your sound card. Note, if you’re using a laptop, this will typically be out of your built-in microphone, so it’s recommended to use headphones to stop feedback.

Now, whilst you’re still hearing the audio live from the sound card with reverb, change the code to the following:

with_fx :echo do
  live_audio :foo
end

Now, hit Run, and you’ll immediately hear the audio played through the echo FX and no longer through reverb. If you wanted them both, just edit the code again and hit Run:

with_fx :reverb do
  with_fx :echo do
    live_audio :foo
  end
end

It’s important to point out that you can call live_audio :foo from any thread or live loop and it will move the live audio synth to that thread’s current FX context. You could therefore easily have multiple live loops calling live_audio :foo at different times resulting in the FX context being automatically swapped around for some interesting results.

Stopping live audio

Unlike standard synths, as live_audio has no envelope, it will continue running forever (even if you delete the code, just like a function is still defined in memory if you delete the code in the editor). To stop it, you need to use the :stop arg:

live_audio :foo, :stop

It can easily be restarted by calling it without the :stop arg again:

live_audio :foo

Additionally all running live audio synths are stopped when you hit the global Stop button (as with all other running synths and FX).

Stereo input

With respect to audio channels, by default live_audio acts similarly to the :sound_in synth in that it takes a single mono input stream of audio and converts it to a stereo stream using the specified panning. However, just like :sound_in_stereo it’s also possible to tell live_audio to read two consecutive audio inputs and treat them as the left and right channels directly. This is achieved via the :stereo opt. For example, to treat input 2 as the left signal and input 3 as the right signal, you need to configure the input: opt to 2 and enable stereo mode as follows:

live_audio :foo, stereo: true, input: 2

Note that once you have started a live audio stream in stereo mode, you cannot change it to mono without stopping and starting. Similarly, if you start it in the default mono mode, you can’t switch to stereo without starting and stopping the stream.


13.3 - Sound Out

So far in this section we’ve looked at how to get multiple streams of audio into Sonic Pi - either through the use of the :sound_in synth or via the powerful live_audio system. In addition to working with multiple streams of input audio, Sonic Pi can also output multiple streams of audio. This is achieved via the :sound_out FX.

Output contexts

Let’s quickly recap on how Sonic Pi’s synths and FX output their audio to their current FX context. For example, consider the following:

with_fx :reverb do    # C
  with_fx :echo do    # B
    sample :bd_haus   # A
  end
end

The simplest way to understand what’s happening with the audio stream is to start at the innermost audio context and work our way out. In this case, the innermost context is labelled A and is the :bd_haus sample being triggered. The audio for this goes directly into its context which is B - the :echo FX. This then adds echo to the incoming audio and outputs it to its context which is C - the :reverb FX. This then adds reverb to the incoming audio and outputs to its context which is the top level - the left and right speakers (outputs 1 and 2 in your audio card). The audio flows outwards with a stereo signal all the way through.

Sound Out FX

The above behaviour is true for all synths (including live_audio) and the majority of FX with the exception of :sound_out. The :sound_out FX does two things. Firstly it outputs its audio to its external context as described above. Secondly it also outputs its audio directly to an output on your sound card. Let’s take a look:

with_fx :reverb do      # C
  with_fx :sound_out, output: 3 do # B
    sample :bd_haus     # A
  end
end

In this example, our :bd_haus sample outputs its audio to its external context which is the :sound_out FX. This in turn outputs its audio to its external context the :reverb FX (as expected). However, it also outputs a mono mix to the 3rd output of the system’s soundcard. The audio generated within :sound_out therefore has two destinations - the :reverb FX and audio card output 3.

Mono and Stereo out

As we’ve seen, by default, the :sound_out FX outputs a mono mix of the stereo input to a specific channel in addition to passing the stereo feed to the outer context (as expected). If outputting a mono mix isn’t precisely what you want to do, there are a number of alternative options. Firstly, by using the mode: opt you can choose to output just the left or just the right input signal to the audio card. Or you can use the :sound_out_stereo FX to output to two consecutive sound card outputs. See the function documentation for more information and examples.

Direct Out

As we have also seen, the default behaviour for :sound_out and :sound_out_stereo is to send the audio both to their external context (as is typical of all FX) and to the specified output on your soundcard. However, occasionally you may wish to only send to the output on your soundcard and not to the external context (and therefore not have any chance of the sound being mixed and sent to the standard output channels 1 and 2). This is possible by using the standard FX opt amp: which operates on the audio after the FX has been able to manipulate the audio:

with_fx :sound_out, output: 3, amp: 0 do # B
  sample :loop_amen                      # A
end

In the above example, the :loop_amen sample is sent to its outer context, the :sound_out FX. This then sends a mono mix to audio card output 3 and then multiplies the audio by 0 which essentially silences it. It is this silenced signal which is then sent out to the :sound_out’s outer context which is the standard output. Therefore with this code, the default output channels will not receive any audio, and channel 3 will receive a mono mix of the amen drum break.


14 - Wnioski

Czas na podsumowanie samouczka wprowadzającego do Sonic Pi. Mam nadzieję, ż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łębiej 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ł.

A więc graj, baw się, dziel się twoim 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


- Artykuły z magazynu MagPi

Dodatek A to zbiór wszystkich artykułów o Sonic Pi, które zostały napisane dla magazynu MagPi.

Jak czytać poszczególne tematy

Artykuły te nie zostały napisane, aby czytać je w określonej kolejności czy porządku. Materiał w nich zawarty często pokrywa się z materiałem zawartym w samouczku. Zamiast próbować nauczyć Cię wszystkiego o Sonic Pi, skupia się raczej na specyficznych aspektach aplikacji i stara się opisać je w sposób zabawny i przystępny.

Czytaj magazyn MagPi

Artykuły te możesz przeczytać i obejrzeć w pełnej krasie w darmowej wersji PDF magazynu MagPi, który możesz pobrać tutaj: https://www.raspberrypi.org/magpi/

Zaproponuj temat

Jeśli okaże się, że pośród tych artykułów nie znalazłeś tematu, który Cię interesuje - to czemu nie miałbyś go zaproponować? Najlepszy sposób to napisanie o tym pomyśle do @Sonic Pi. Nigdy nie wiadomo - być może Twoja sugestia będzie głównym tematem kolejnego artykułu!


- Pięć najważniejszych wskazówek

1. Błędów nie ma

Najważniejszą lekcją, jaką powinieneś wynieść z Sonic Pi, jest taka, że tak naprawdę błędów nie ma. Najlepsza metoda nauki to ciągłe próbowanie, próbowanie i próbowanie. Próbuj wielu różnych pomysłów oraz nie przejmuj się tym, czy Twój kod brzmi dobrze czy źle - zacznij eksperymenty z możliwie największą liczbą różnych syntezatorów, nut, efektów (FX) i opcji. Odkryjesz ogrom rzeczy, które spowodują, że będziesz się śmiać. Niektóre będą brzmieć strasznie, a inne będą prawdziwymi perełkami brzmiącymi niesamowicie dobrze. Wystarczy, że pominiesz rzeczy, które Ci się nie podobają i zostawisz tylko te wpadające Ci w ucho. Im więcej ‘błędów’ pozwolisz sobie popełnić, tym szybciej się będziesz uczyć i odkryjesz kod, który oddaje Twoje indywidualne brzmienie.

2. Używaj efektów (FX)

Więc mówisz, że właśnie opanowałeś podstawy Sonic Pi polegające na tworzeniu dźwięków z wykorzystaniem poleceń sample i play? Co dalej? Czy wiedziałeś, że Sonic Pi wspiera ponad 27 efektów studyjnych (FX), które pozwalają na zmianę brzmienia Twojego kodu? Są one niczym ekstrawaganckie filtry obrazów, jakie możesz znaleźć w programach graficznych, z tym że zamiast rozmazywania lub sprawiania, iż coś staje się czarno białe, możesz dodać rzeczy takie jak pogłos (ang. reverb), zniekształcenie (ang. distortion) lub echo do Twoich dźwięków. Pomyśl o tym jak o kablu, który łączy Twoją gitarę z pedałami do efektów, które sam wybrałeś, a następnie prowadzi do wzmacniacza. Na szczęście Sonic Pi sprawia, że używanie efektów jest naprawdę proste i nie wymaga żadnych kabli! Jedyne, co musisz zrobić, to wybrać sekcję Twojego kodu, która powinna być objęta efektem i otoczyć ją kodem FX. Spójrzmy na przykład - powiedzmy, że masz następujący kawałek kodu:

sample :loop_garzul
16.times do
  sample :bd_haus
  sleep 0.5
end

Jeśli chcesz nałożyć efekt na sampel :loop_garzul, wystarczy, że wsadzisz go w blok with_fx w taki sposób:

with_fx :flanger do
  sample :loop_garzul
end
16.times do
  sample :bd_haus
  sleep 0.5
end

A teraz, jeśli chcesz dodać efekt do bębna, to jego też po prostu otocz poleceniem with_fx:

with_fx :flanger do
  sample :loop_garzul
end
with_fx :echo do
  16.times do
    sample :bd_haus
    sleep 0.5
  end
end

Zapamiętaj - możesz otoczyć dowolny kawałek kodu poleceniem with_fx i każdy z tworzonych dźwięków będzie przepuszczony przez ten efekt (FX).

3. Używaj parametrów w Twoich syntezatorach

Jeśli naprawdę chcesz odkryć Twoje własne brzmienie w kodzie, to dość szybko będziesz chciał dowiedzieć się, w jaki sposób zmieniać i kontrolować syntezatory oraz efekty. Na przykład możesz chcieć zmienić czas trwania jakiejś nuty, dodać więcej pogłosu (reverb) lub zmienić odstęp pomiędzy echo. Na szczęście Sonic Pi daje Ci niesamowity poziom kontroli nad tymi aspektami za pomocą rzeczy, które nazywają się parametrami opcjonalnymi, w skrócie opcjami. Rzućmy okiem. Skopiuj poniższy kawałek kodu do buforu i naciśnij przycisk “Run”:

sample :guit_em9

Ooo, przyjemny dźwięk gitary! A teraz spróbujmy się tym pobawić. Co powiesz na zmianę tempa?

sample :guit_em9, rate: 0.5

Hej, czym jest ten kawałek rate: 0.5, który przed chwilą dodałem na końcu? Nazywamy to opcją. Wszystkie syntezatory i efekty w Sonic Pi je wspierają i jest ich bardzo dużo do zabawy. Są również dostępne dla efektów. Spróbuj tego:

with_fx :flanger, feedback: 0.6 do
  sample :guit_em9
end

A teraz spróbuj zwiększyć wartość opcji feedback do 1, aby usłyszeć trochę zwariowanych dźwięków! Zajrzyj do dokumentacji, znajdziesz tam wiele dokładnie opisanych szczegółów, które dotyczą wszystkich dostępnych dla Ciebie opcji.

5. Koduj na żywo

Najlepszym metodą na szybkie eksperymenty i naukę Sonic Pi jest kodowanie na żywo. Pozwala Ci to na uruchomienie jakiegoś kawałka kodu, a następnie na sukcesywne zmienianie i ulepszanie go, gdy ten cały czas gra. Przypuśćmy, że nie wiesz, jak działa opcja cutoff na wybrany przez Ciebie sampel - wystarczy, że zaczniesz się nim bawić. Spróbujmy tego! Skopiuj poniższy kawałek kodu do jednego z Twoich buforów:

live_loop :experiment do
  sample :loop_amen, cutoff: 70
  sleep 1.75
end

Teraz naciśnij przycisk “Run”, a usłyszysz lekko przytłumiony breakbit. Następnie mień wartość opcji cutoff: na 80 i ponownie naciśnij “Run”. Słyszysz różnicę? Spróbuj tego samego dla kolejnych wartości: 90, 100, 110

Gdy raz spróbujesz polecenia live_loop, to już nigdy nie będziesz chciał wrócić. Zawsze, kiedy koduję na żywo na jakiejś imprezie, polegam na poleceniu live_loop tak samo, jak perkusista polega na swoich pałeczkach. Jeśli chcesz dowiedzieć się więcej o kodowaniu na żywo, zajrzyj do rozdziału nr 9 samouczka, który jest wbudowany w Sonic Pi.

5. Surfuj po losowych strumieniach

Jedna z rzeczy, którą uwielbiam robić, to oszukiwanie poprzez wykorzystywanie Sonic Pi, aby komponował melodie za mnie. Bardzo dobrym sposobem jest wykorzystanie do tego celu randomizacji. Może to brzmieć odrobinę skomplikowanie, ale tak naprawdę nie jest. Przyjrzyjmy się temu bliżej - skopiuj poniższy kod do jakiegoś pustego buforu:

live_loop :rand_surfer do
  use_synth :dsaw
  notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
  16.times do
    play notes.choose, release: 0.1, cutoff: rrand(70, 120)
    sleep 0.125
  end
end

Teraz, kiedy włączysz ten kawałek, usłyszysz stały strumień losowych nut z gamy (skali) pentatonicznej e-moll zagranej przez syntezator :dsaw. “Czekaj, czekaj! Przecież to nie jest melodia” Usłyszałem jak krzyczysz! Spokojnie, to pierwsza część magicznej ścieżki. Możemy powiedzieć Sonic Pi, aby zmieniał losowy strumień dźwięków po każdym przebiegu pętli. To jest trochę podobne do sytuacji, w której przenieślibyśmy się w czasie i przestrzeni za pomocą TARDIS’a razem z Doktorem Who. Spróbuj dodać linijkę use_random_seed 1 w pętli live_loop:

live_loop :rand_surfer do
  use_random_seed 1
  use_synth :dsaw
  notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
  16.times do
    play notes.choose, release: 0.1, cutoff: rrand(70, 120)
    sleep 0.125
  end
end

Teraz, przy każdej kolejnej iteracji pętli, losowy strumień jest resetowany. Oznacza to, że za każdym razem losowane są te same nuty. Bułka z masłem! Melodia błyskawiczna. A teraz czas na coś naprawdę ekstra. Zmień wartość przy poleceniu seed na inną liczbę. Powiedzmy 4923. Łał! Kolejna melodia! Wystarczy więc zmienić jedną liczbę, aby móc poznawać tyle kombinacji melodii, ile tylko sobie wyobrazisz. I to jest właśnie magia kodu!


- Kodowanie na żywo

Promienie lasera przecinały smugi dymu, a bas pulsujący z subwoofera przeszywał ciała tłumu na parkiecie. Atmosfera była gorąca, tworzyły ją syntezatory i taniec. W klubie tym było jednak coś dziwnego. Na ścianie, tuż nad głową DJ’a, był wyświetlany jasny, futurystyczny tekst, który bez przerwy się poruszał, zmieniał, tańczył i świecił… Nie były to żadne fantazyjne wizualizacje, tylko Sonic Pi uruchomiony na Raspberry Pi. Osoba okupująca stanowisko DJ’a nie kręciła płytami winylowymi, lecz pisała, edytowała i uruchamiała kod. Na żywo…! To jest właśnie kodowanie na żywo.

Sam Aaron kodujący na żywo

Być może brzmi to jak historia z przyszłości opisująca futurystyczny klub, ale kodowanie muzyki w ten sposób to rosnący trend i często jest opisywany jako kodowanie na żywo (http://toplap.org). Jednym z obecnych kierunków, jaki obrał ruch tworzący muzykę w taki sposób, jest Algorave (http://algorave.com) - wydarzenia, podczas których osoby takie jak ja kodują muzykę do tańca dla ludzi. Jednakże, wcale nie musisz być w klubie, żeby Kodować Na Żywo z Sonic Pi v2.6+, możesz to robić gdziekolwiek tylko Ci się uda zabrać ze sobą swój komputer, parę słuchawek lub głośniki. Kiedy skończysz czytać ten artykuł, będziesz programował swoje własne bity i zmieniał je na żywo. Gdzie pójdziesz - dalej będzie ograniczone tylko Twoją wyobraźnią.

Live Loop (Żywa Pętla)

Kluczem do kodowania na żywo jest okiełznanie polecenia live_loop. Przyjrzyjmy się jednej:

live_loop :beats do
  sample :bd_haus
  sleep 0.5
end

Aby stworzyć żywą pętlę (live_loop), potrzebujemy 4 składników. Pierwszym jest jej nazwa. Nasza pętla live_loop powyżej została nazwana :beats. Masz pełną dowolność w wyborze nazwy dla Twojej pętli ` live_loop. Możesz tutaj szaleć do woli! Bądź kreatywny - często używam nazw, które mówią publiczności coś o tworzonej muzyce. Drugi składnik to słowo kluczowe do pojawiające się tam, gdzie zaczyna się dana pętla live_loop. Trzeci składnik to end, które zaznacza, gdzie nasza pętla live_loop się kończy. Ostatni składnik to ciało żywej pętli live_loop opisujące, co dana pętla będzie powtarzać - kawałek pomiędzy słowami kluczowymi do i end`. W tym przypadku będziemy w koło odtwarzać sampel grający bęben i czekać przez połowę uderzenia. To spowoduje, że usłyszymy przyjemne i regularne uderzenia bębna. Śmiało, skopiuj ten kawałek do pustego buforu w Sonic Pi i naciśnij przycisk Run. Bum, Bum, Bum!.

Redefiniowanie w locie

No dobra, ale co w takim razie jest takiego wyjątkowego w żywej pętli live_loop? Jak do tej pory wygląda to jak zwykła pętla loop, która została wyniesiona na piedestał. Całe piękno pętli live_loop polega na tym, że możemy zmieniać ją w locie. Oznacza to, iż możemy mamy możliwość zmiany jej zachowania. Jest to klucz do kodowania na żywo. Spróbujmy zrobić coś takiego:

live_loop :choral_drone do
  sample :ambi_choir, rate: 0.4
  sleep 1
end

A teraz naciśnij przycisk Run lub wciśnij klawisze alt-r. Słyszysz teraz parę wspaniałych dźwięków chóralnych. A teraz, kiedy pętla wciąż gra, zmień wartości opcji rate z 0.4 na 0.38. Wciśnij Run ponownie. Łał! Zauważyłeś, że chór wybrzmiewa teraz inną nutą? Zmień ją ponownie na wartość 0.4, aby przywrócić wcześniejsze brzmienie. Teraz obniż wartość na 0.2, potem na 0.19 i wróć do 0.4. Widzisz, jak zmiana tylko jednego parametru w locie daje Ci realną kontrolę nad muzyką? Spróbuj teraz pobawić się parametrem rate samodzielnie - wybierz swoje własne wartości. Spróbuj użyć liczb ujemnych, naprawdę bardzo małych wartości oraz dużych. Przyjemnej zabawy!

Spanie (ang. sleep) jest ważne

Jedną z najważniejszych lekcji dotyczących pętli live_loop jest to, że potrzebują one odpoczynku. Przyjrzyjmy się następującej pętli live_loop:

live_loop :infinite_impossibilities do
  sample :ambi_choir
end

Jeśli spróbujesz uruchomić powyższy kawałek kodu, szybko zauważysz, że pętla live_loop zacznie narzekać, że nie spała. To jest miejsce, w którym do akcji wkracza system bezpieczeństwa! Zatrzymaj się na chwilę i zastanów się, czego ten kawałek kodu oczekuje od komputera. Tak jest, prosi komputer, żeby zagrał sampel ambi_hoir nieskończoną ilość razy od razu. Gdyby nie system bezpieczeństwa, to nasz biedny komputer spróbowałby zrobić to, o co go prosimy, w wyniku czego popsułby się i spalił. Pamiętaj więc, Twoje żywe pętle muszą posiadać polecenie sleep.

Łączenie Dźwięków

Muzyka jest pełna rzeczy, które się dzieją w tym samym czasie. Bębny grają, a w tym samym czasie słychać bas, wokal i gitarę… W komputerach nazywamy to współbieżnością, a Sonic Pi pozwala nam na granie różnych dźwięków w tym samym czasie w niesamowicie prosty sposób. Wystarczy, że użyjemy więcej niż jednej pętli live_loop!

live_loop :beats do
  sample :bd_tek
  with_fx :echo, phase: 0.125, mix: 0.4 do
    sample  :drum_cymbal_soft, sustain: 0, release: 0.1
    sleep 0.5
  end
end
live_loop :bass do
  use_synth :tb303
  synth :tb303, note: :e1, release: 4, cutoff: 120, cutoff_attack: 1
  sleep 4
end

Mamy tu dwie pętle live_loop - jedna kręci się szybko, wygrywając rytm, natomiast druga kręci się powoli, tworząc zwariowaną sekcję basową.

Jedną z interesujących rzeczy w używaniu wielu pętli live_loop jest to, że każda z nich zarządza swoim czasem. Oznacza to, iż bardzo łatwo można stworzyć interesujące struktury polirytmiczne, a nawet grać fazami w stylu Stevena Reicha! Spróbuj tego:

# Steve Reich's Piano Phase
notes = (ring :E4, :Fs4, :B4, :Cs5, :D5, :Fs4, :E4, :Cs5, :B4, :Fs4, :D5, :Cs5)
live_loop :slow do
  play notes.tick, release: 0.1
  sleep 0.3
end
live_loop :faster do
  play notes.tick, release: 0.1
  sleep 0.295
end

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

Każdy z tutoriali ma swoje zwieńczenie, którym jest przykład końcowy. Jest to kawałek muzyki reprezentujący wszystkie idee zaprezentowane w danej sekcji. Przeczytaj ten kod i zobacz, czy jesteś w stanie wyobrazić sobie, co ten kod robi. Następnie skopiuj go do czystego buforu w Sonic Pi i naciśnij przycisk Run, aby usłyszeć, jak brzmi w rzeczywistości. Na koniec zmień wybraną przez siebie liczbę albo wykomentuj lub odkomentuj wybrane według własnego uznania linijki kodu. Pomyśl, czy możesz użyć tego kawałka jako punkt wyjściowy dla nowego występu, a co najważniejsze - spróbuj się dobrze bawić. Do zobaczenia następnym razem…

with_fx :reverb, room: 1 do
  live_loop :time do
    synth :prophet, release: 8, note: :e1, cutoff: 90, amp: 3
    sleep 8
  end
end
live_loop :machine do
  sample :loop_garzul, rate: 0.5, finish: 0.25
  sample :loop_industrial, beat_stretch: 4, amp: 1
  sleep 4
end
live_loop :kik do
  sample :bd_haus, amp: 2
  sleep 0.5
end
with_fx :echo do
  live_loop :vortex do
    # use_random_seed 800
    notes = (scale :e3, :minor_pentatonic, num_octaves: 3)
    16.times do
      play notes.choose, release: 0.1, amp: 1.5
      sleep 0.125
    end
  end
end

- Zakodowane bity

Jednym z najbardziej ekscytujących i zawrotnych rozwoju technicznego nowoczesnej muzyki było wynalezienie samplerów - znane jako pudełka pozwalające na nagrywanie i wrzucenie do nich dowolnego dźwięku, który można było potem zmieniać i odtwarzać te dźwięki na wiele ciekawych sposobów. Na przykład mogłeś wziąć jakieś stare nagranie, znaleźć sekcję z solówką na perkusji, nagrać ją na Twoim samplerze, a następnie odtwarzać ją w kółko, zwalniając przy tym tempo tego fragmentu o połowę, aby stworzyć bazę dla Twoich najnowszych bitów. W taki właśnie sposób narodził się wczesny hip-hop i w dzisiejszych czasach prawie niemożliwym jest znalezienie muzyki elektronicznej, która by nie korzystała z sampli w jakimś stopniu. Używanie ich jest naprawdę świetnym sposobem na wprowadzanie nowych i ciekawych elementów do Twoich występów polegających na kodowaniu muzyki na żywo.

Skąd w takim razie możesz wziąć sampler? Właściwie to aktualnie już jeden posiadasz - to Twój komputer Raspberry Pi (albo Mac lub PC)! Aplikacja Sonic Pi posiada swój własny wbudowany, który jest bardzo potężny. Spróbujmy się nim pobawić!

Amen Break

Jeden z najbardziej klasycznych i rozpoznawalnych samplem zawierającym perkusję nazywa się Amen Break. Po raz pierwszy został użyty w roku 1969 w piosence “Amen Brother” (Amen Bracie) przez zespół Winstons jako część solówki na perkusji. Jednakże, od chwili kiedy została odkryta przez wczesnych muzyków tworzących hip-hop w latach 80-tych i użyta w samplerach, zaczęła być bardzo często używana w wielu innych stylach muzycznych np. drum and bass, breakbeat, hardcore techno i breakcore.

Jestem pewien, że będziesz podekscytowany, gdy powiem Ci, że one też są wbudowane w Sonic Pi. Wyczyść bufor i wklej następujący kod:

sample :loop_amen

Naciśnij Run i bum! Słuchasz jednej z najbardziej wpływowych połamanych pętli w historii muzyki tanecznej. Jednakże sampel ten nie zawdzięcza swej sławy jednorazowemu odtworzeniu - został stworzony po to, aby kręcić się w kółko.

Sięgnięcie Po Beat

Zapętlijmy amen break, używając naszego starego dobrego przyjaciela live_loop, wprowadzonego w tym poradniku ostatniego miesiąca:

live_loop :amen_break do
  sample :loop_amen
  sleep 2
end

Okej, więc to jest zapętlone, ale są tutaj irytujące pauzy za każdym razem, gdy ponownie odtwarzany jest sampel. Tak się dzieje, gdyż poprosiliśmy go o uśpienie na ‘2’ uderzenia, a z domyślnym BPM 60. : loop_amen trwa jedynie przez 1.753 uderzenia. Mamy więc ciszę przez 0.247 uderzenia (‘2-1.753 = 0.247’). Mimo krótkiego czasu trwania, jest to jeszcze zauważalne.

Żeby naprawić ten problem, możemy użyć opcji beat_stretch:, aby poprosić Sonic Pi, by rozciągnęło (lub skurczyło) sampel, tak aby wpasował się w określoną liczbę uderzeń (bitów).

Funkcje sample i synth, które są dostępne w Sonic Pi, pozwalają Ci na dużą kontrolę za pomocą opcjonalnych parametrów takich jak amp:, cutoff: czy release:. Jednakże termin parametry opcjonalne jest dosyć długi, więc będziemy używać skróconego terminu opcje, aby było nam wygodniej i łatwiej.

live_loop :amen_break do
  sample :loop_amen, beat_stretch: 2
  sleep 2
end  

Teraz możemy zacząć tańczyć! Aczkolwiek może chcielibyśmy przyśpieszyć trochę tempo lub zwolnić, aby dostosować je do nastroju.

Zabawa z Czasem

Dobrze! Więc co, jeśli chcemy zmienić styl na starą szkołę hip-hop lub breakcore? Jednym z prostszych sposobów jest zabawa z czasem - lub, w innym słowa znaczeniu, bałagan z tempem. Możesz z tego korzystać w Sonic Pi w bardzo łatwy sposób - po prostu dodaj ‘use_bpm’ do Twojej żywej pętli:

live_loop :amen_break do
  use_bpm 30
  sample :loop_amen, beat_stretch: 2
  sleep 2
end 

Zauważ, że w czasie, gdy rapujesz do tych powolnych uderzeń, przy każdym kolejnym obiegu pętli wciąż śpimy przez 2 uderzenia, nasze BPM (z ang. Beats Per Minute - ilość uderzeń na minutę) jest równe 30, a wszystkie dźwięki idealnie mieszczą się w czasie jednej pętli. Opcja beat_stretch współpracuje z aktualnym BPM, aby zapewnić, że wszystko działa tak, jak należy.

A teraz czas na zabawę. Podczas gdy pętla jest wciąż żywa, zmień wartość 30 w linijce use_bpm 30 na 50. Łoooo, wszystko ot tak przyśpiesza, a jednocześnie wciąż mieści się w czasie trwania jednej pętli! Spróbuj pójść jeszcze szybciej - do 80, do 120, a nawet zaszalej i uderz w 200!

Filtrowanie

Potrafimy już wplatać sample do naszych żywych pętli, spójrzmy zatem na jedną z najfajniejszych opcji dostępnych dla syntezatora sample. Pierwszą jest cutoff:, która kontroluje filtr odcięcia samplera. Domyślnie jest ona wyłączona, ale możesz ją bardzo łatwo włączyć:

live_loop :amen_break do
  use_bpm 50
  sample :loop_amen, beat_stretch: 2, cutoff: 70
  sleep 2
end  

Śmiało, spróbuj zmienić wartość opcji cutoff:. Na przykład zwiększ ją do 100, naciśnij przycisk Run, poczekaj, aż aktualna pętla skończy swój przebieg, aby usłyszeć zmianę w dźwięku. Zauważ, że niskie wartości takie jak 50 brzmią łagodnie i basowo, natomiast wyższe wartości takie jak 100 czy 120 pozwalają uzyskać pełniejsze i bardziej zgrzytliwe brzmienie. Dzieje się tak ponieważ opcja cutoff: wycina część dźwięku o wyższych częstotliwościach - tak jak kosiarka ścina trawę. Opcja cutoff: jest jak ustawienie długości - określamy, jaka wysokość trawy ma pozostać po skoszeniu.

Przycinanie

Kolejnym świetnym narzędziem do zabawy jest efekt slicer. Użycie go spowoduje posiekanie dźwięku (z ang. slice - pokroić). Opakujmy linijkę zawierającą polecenie sample w efekt tak jak na poniższym kodzie:

live_loop :amen_break do
  use_bpm 50
  with_fx :slicer, phase: 0.25, wave: 0, mix: 1 do
    sample :loop_amen, beat_stretch: 2, cutoff: 100
  end
  sleep 2
end

Zauważ, jak dźwięki odbijają się po trochu w górę i w dół. (Możesz usłyszeć pierwotne brzmienie bez efektu, zmieniając wartość opcji mix: na 0.) Teraz spróbuj pobawić się opcją phase:. Opowiada ona za tempo (w uderzeniach), z jakim jest aplikowany efekt cięcia. Mniejsze wartości takie jak 0.125 spowodują, że cięcia będą szybsze, natomiast większe wartości takie jak 0.5 będą powodować, że staną się wolniejsze. Zauważ, że zmniejszenie lub zwiększenie o połowę wartości opcji phase: zazwyczaj powoduje fajne brzmienia. Na koniec zmień wartość opcji wave: na 0, 1 lub 2, a usłyszysz, jak zmienia się dźwięk. To są różne barwy dźwięku. 0 to fala piłokształtna (mocne wejście i normalne wyjście), 1 to fala kwadratowa (mocne wejście, mocne wyjście), natomiast 2 to fala trójkątna (normalne wejście, normalne wyjście).

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

Na koniec cofnijmy się w czasie i zanurzmy się ponownie we wczesnej scenie drum and bass miasta Bristol wykorzystując do tego celu przykład z bieżącego miesiąca. Nie przejmuj się zbytnio tym, że nie rozumiesz wszystkiego z tego kawałka kodu, po prostu przepisz go lub przekopiuj i naciśnij przycisk Run, a następnie zacznij kodować na żywo, zmieniając liczby znajdujące się przy opcjach i zobacz, dokąd Cię to zaprowadzi. Pamiętaj tylko, żeby podzielić się tym, co uda Ci się stworzyć! Do zobaczenia następnym razem…

use_bpm 100
live_loop :amen_break do
  p = [0.125, 0.25, 0.5].choose
  with_fx :slicer, phase: p, wave: 0, mix: rrand(0.7, 1) do
    r = [1, 1, 1, -1].choose
    sample :loop_amen, beat_stretch: 2, rate: r, amp: 2
  end
  sleep 2
end
live_loop :bass_drum do
  sample :bd_haus, cutoff: 70, amp: 1.5
  sleep 0.5
end
live_loop :landing do
  bass_line = (knit :e1, 3, [:c1, :c2].choose, 1)
  with_fx :slicer, phase: [0.25, 0.5].choose, invert_wave: 1, wave: 0 do
    s = synth :square, note: bass_line.tick, sustain: 4, cutoff: 60
    control s, cutoff_slide: 4, cutoff: 120
  end
  sleep 4
end

- Riffy Syntezatorów

Niezależnie od tego, czy mamy do czynienia z niepokojącym dryftem dudniących oscylatorów, czy rozstrojonymi uderzeniami dźwięków piły przeszywającej miks, syntezator wiodący odgrywa kluczową rolę w każdym utworze muzyki elektronicznej. W ostatniej edycji tego samouczka z poprzedniego miesiąca omówiliśmy, w jaki sposób możemy kodować nasze bity. W bieżącym numerze omówimy zaś kodowanie trzech podstawowych części riffu syntezatorem - tembr (barwa dźwięku), melodię i rytm.

OK, czas żebyś włączył Twojego Raspberry Pi, odpal Sonic Pi w wersji 2.6+ i zróbmy jakiś hałas!

Możliwości związane z Barwą Dźwięku

Esencją dowolnego riffu opartego o syntezatory jest zmienianie i granie z różnymi barwami dźwięku. W Sonic Pi możemy kontrolować barwę dźwięku na dwa sposoby - wybierając różne syntezatory dla uzyskania diametralnej zmiany oraz poprzez ustawianie różnych wartości opcji danego syntezatora dla otrzymania bardziej subtelnych zmian. Możemy również używać efektów (FX), ale to temat na osobny artykuł…

Spróbujmy stworzyć prostą żywą pętlę, w której będziemy zmieniać aktualny syntezator w trakcie gry:

live_loop :timbre do
  use_synth (ring :tb303, :blade, :prophet, :saw, :beep, :tri).tick
  play :e2, attack: 0, release: 0.5, cutoff: 100
  sleep 0.5
end

Spójrzmy na powyższy kawałek kodu. Cykamy tu przez pierścień z nazwami syntezatorów (iterując w kółko po wszystkich syntezatorach z listy). Przekazujemy nazwy kolejno wybieranych syntezatorów do funkcji use_synth, co powoduje zmianę aktualnego syntezatora przy każdym kolejnym przebiegu żywej pętli. Ponadto gramy nutę :e2 (dźwięk E w drugiej oktawie) z czasem zanikania amplitudy ustawionym na 0.5 uderzenia (przy domyślnym BPM równym 60 jest to pół sekundy) oraz z opcją cutoff: ustawioną na 100.

Zauważ, że każdy z syntezatorów ma zupełnie inne brzmienie, pomimo że wszystkie grają tę samą nutę. Spróbuj teraz poeksperymentować i pobaw się! Zmień czas zanikania amplitudy (opcja release) na wyższe i mniejsze wartości. Na przykład zmień wartości dla opcji attack: i release:, aby zobaczyć, jak wielki wpływ na dźwięk mają różne czasy wejścia/wyjścia. Na koniec zmień opcję cutoff:, aby usłyszeć, jak znaczące na barwę dźwięku ma ustawianie różnych wartości odcięcia (najlepsze są wartości pomiędzy 60 a 130). Widzisz, jak wiele różnych dźwięków możesz stworzyć, zmieniając tylko kilka wartości? Gdy już uda Ci się to opanować, udaj się na zakładkę Syntezatory znajdującą się w systemie pomocy. Zobaczysz tam pełną listę syntezatorów oraz wszystkie indywidualne opcje, jakie są dostępne dla każdego z nich. Powinno dać Ci to wyobrażenie, jak wiele możliwości jest w zasięgu Twoich palców.

Barwa dźwięku

Tembr to nic innego jak wyszukane słowo dla opisania, jakie jest brzmienie dźwięku. Jeśli zagrasz tę samą nutę z innym instrumentem takim jak skrzypce, gitara czy fortepian, wysokość dźwięku (jak wysoki lub niski jest dźwięk) będzie taka sama, za to barwa będzie inna. Ta właściwość dźwięku - ta cecha, która pozwala ci rozróżnić pianino od gitary, to tembr.

Kompozycja Malodyczna

Kolejnym aspektem ważnym dla naszego syntezatora wiodącego jest wybór nut, które chcemy zagrać. Jeśli posiadasz aktualnie fajny pomysł, wtedy możesz po prostu stworzyć pierścień (ring) z Twoich nut i cykać przez nie w kółko:

live_loop :riff do
  use_synth :prophet
  riff = (ring :e3, :e3, :r, :g3, :r, :r, :r, :a3)
  play riff.tick, release: 0.5, cutoff: 80
  sleep 0.25
end

Zdefiniowaliśmy tutaj naszą melodię za pomocą pierścienia, który zawiera w sobie zarówno nuty takie jak :e3, jak i przerwy reprezentowane za pomocą symbolu :r. Następnie wykorzystujemy polecenie .tick, żeby przechodzić kolejno przez każdą z nut, co daje nam powtarzalny riff.

Melodia Automatyczna

Nie zawsze łatwo jest wymyślić ciekawy riff od zera. Zamiast tego często dużo łatwiej jest poprosić Sonic Pi, aby wybrał dla nas losowy riff i użyć tego, który spodoba się nam najbardziej. Aby to osiągnąć, potrzebujemy połączyć trzy rzeczy: pierścienie, losowość oraz losowe ziarna. Spójrzmy na poniższy przykład:

live_loop :random_riff do
  use_synth :dsaw
  use_random_seed 3
  notes = (scale :e3, :minor_pentatonic).shuffle
  play notes.tick, release: 0.25, cutoff: 80
  sleep 0.25
end

Dzieje się tutaj kilka rzeczy - przyjrzyjmy się im po kolei. Na samym początku określamy, że używamy 3-go zestawu losowych ziaren. Co to znaczy? Otóż dość przydatną rzeczą jest możliwość ustawienia określonej wartości dla tych ziaren, dzięki czemu możemy przewidzieć, jaka będzie kolejna losowa wartość. Przy każdym obiegu żywej pętli będzie to taki sam zestaw wartości, jaki ustawiliśmy na początku - zestaw nr 3! Kolejną przydatną rzeczą, którą warto wiedzieć, jest to, że tasowanie pierścienia z nutami działa w taki sam sposób. W powyższym przykładzie prosimy w gruncie rzeczy o ‘trzecie rozdanie’ ze standardowej listy tasowań - które za każdym jest tym samym rozdaniem, gdyż za zawsze tuż przed tasowaniem ustawiamy losowe ziarno na tę samą. Koniec końców tykamy kolejno przez nasze potasowane nuty, aby zagrać riff.

A teraz moment, w którym zaczyna się zabawa. Jeśli zmienimy wartość losowego ziarna na inną liczbę, powiedzmy 3000, otrzymamy zupełnie inne rozdanie nut. Dzięki temu możemy teraz bardzo łatwo odkrywać nowe melodie. Po prostu wybieramy listę nut, które chcemy przetasować (gamy są tutaj dobrym punktem wyjścia), a następnie bierzemy wartość ziarna, według jakiej chcemy tasować. Jeśli dana melodia nam się nie spodoba, wystarczy zmienić jedną z tych dwóch rzeczy i spróbować ponownie. Teraz wystarczy, że będziesz powtarzał te kroki do momentu, aż usłyszysz coś, co Ci się spodoba!

Pseudo Losowość

Losowość Sonic Pi tak naprawdę wcale nie jest losowa tylko pseudo losowa. Wyobraź sobie, że rzucasz kostką do gry 100 razy i zapisujesz wynik każdego rzutu na kartce papieru. Sonic Pi posiada odpowiednik takiej listy wyników, której używa, kiedy prosisz o losową wartość. Zamiast rzucania prawdziwą kostką do gry, po prostu wybiera kolejne wartości z listy. Ustawianie losowego ziarna jest po prostu skokiem do konkretnego miejsca w tej liście.

Znajdź swój Rytm

Kolejnym ważnym aspektem naszego riffu jest rytm - kiedy grać daną nutę, a kiedy nie. Jak widzieliśmy wcześniej, możemy użyć symbolu :r w naszych pierścieniach, aby wypełnić pozostałości. Kolejnym bardzo skutecznym sposobem jest użycie rozpiętości - nauczymy się tego w dalszej części poradnika. Dzisiaj użyjemy losowości, która pomoże nam znaleźć nasz rytm. Zamiast grać każdą nutę, możemy użyć warunku logicznego, aby zagrać ją z zadanym prawdopodobieństwem. Rzućmy okiem:

live_loop :random_riff do
  use_synth :dsaw
  use_random_seed 30
  notes = (scale :e3, :minor_pentatonic).shuffle
  16.times do
    play notes.tick, release: 0.2, cutoff: 90 if one_in(2)
    sleep 0.125
  end
end

Bardzo przydatną i wartą poznania funkcją jest one_in. Zwraca ona prawdę (true) lub fałsz (false) z określonym prawdopodobieństwem. W naszym przypadku używamy wartości 2 więc przeciętnie raz na każde 2 wołania funkcji one_in zostanie zwrócona wartość true (prawda). Innymi słowy, przez 50% czasu będzie zwracała true. Użycie wyższych wartości spowoduje, że wartość false zacznie być zwracana częściej, co wprowadzi więcej wolnej przestrzeni do naszego riffu.

Zauważ, że wraz z poleceniem 16.times dodaliśmy tutaj pewien rodzaj iteracji. Zrobiliśmy tak, ponieważ chcemy tylko zresetować losowe ziarno co każde 16 nut, tak żeby nasz rytm powtarzał się co każde 16 uderzeń. Nie wpłynie to na tasowanie, ponieważ dzieje się to od razu, jak tylko ziarno jest ustawione. Możemy użyć rozmiaru iteracji do zmiany długości trwania rytmu. Spróbuj zmienić liczbę 16 na 8 lub nawet 4 czy 3 i zobacz, jak wpływa to na rytm naszego riffu.

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

No dobrze, to spróbujmy teraz wykorzystać wszystko, czego się nauczyliśmy w naszym finalnym przykładzie. Do zobaczenia w następnym odcinku!

live_loop :random_riff do
  #  uncomment to bring in:
  #  synth :blade, note: :e4, release: 4, cutoff: 100, amp: 1.5
  use_synth :dsaw
  use_random_seed 43
  notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle.take(8)
  8.times do
    play notes.tick, release: rand(0.5), cutoff: rrand(60, 130) if one_in(2)
    sleep 0.125
  end
end
 
live_loop :drums do
  use_random_seed 500
  16.times do
    sample :bd_haus, rate: 2, cutoff: 110 if rand < 0.35
    sleep 0.125
  end
end
 
live_loop :bd do
  sample :bd_haus, cutoff: 100, amp: 3
  sleep 0.5
end

- Acid Bass

Gdy spojrzymy wstecz na historię muzyki elektronicznej, nie sposób jest nie zauważyć ogromnego wpływu, jaki miał na nią malutki syntezator TB-303. Jest to sekretny składnik stojący za oryginalnym brzmieniem acid’owej linii basowej. Te klasycznie piszczące i chlupiące riffy basowe TB-303 można usłyszeć zarówno we wczesnej scenie Chicago House, jak i u bardziej współczesnych artystów takich jak Plastikman, Squarepusher czy Aphex Twin.

Interesujące jest, że firma Roland nigdy nie zamierzała, aby TB-303 był używany do tworzenia muzyki tanecznej. Został pierwotnie stworzony jako narzędzie pomocnicze dla gitarzystów. Wymyślili sobie, że ludzie mogliby programować na nich linię basową, do której posiadaliby możliwość jam’owania. Niestety pojawiło się zbyt wiele problemów: były odrobinę zbyt skomplikowane do zaprogramowania, nie brzmiały zbyt dobrze jako zamiennik gitary basowej oraz kosztowały w zakupie. Aby uciąć straty, Roland przestał je produkować po sprzedaży 10,000 sztuk. Po paru latach kurzenia się na półkach gitarzystów, dosyć szybko zaczęły trafiać na póki second hand’ów. Te samotne i odrzucone TB-303 czekały na odkrycie ich przez nową generację eksperymentatorów, którzy zaczęli ich używać w sposób, jakiego Roland nie przewidział do tworzenia zupełnie nowych zwariowanych dźwięków. Tak narodził się Acid House.

Pomimo że dostanie w swoje ręce oryginalnego egzemplarza TB-303 nie jest zbyt łatwe, to na pewno ucieszy Cię fakt, iż możesz zmienić swój komputer w jeden z nich, korzystając z możliwości, jakie daje Sonic Pi. Spójrz, odpal Sonic Pi, wrzuć ten kawałek kodu do pustego buforu i naciśnij przycisk Run:

use_synth :tb303
play :e1

Błyskawiczna acid’owa linia basowa! Zabawmy się…

Chlupnij Basem

Najpierw zbudujmy żywy arpeggiator, aby sprawić, by było jeszcze ciekawiej. W ostatnim tutorialu dowiedzieliśmy się, jak riffy mogą być po prostu pierścieniami nut, przez które tykamy raz po raz, powtarzając całość od nowa, kiedy tylko dobrniemy do końca. Stwórzmy żywą pętlę robiącą właśnie coś takiego:

use_synth :tb303
live_loop :squelch do
  n = (ring :e1, :e2, :e3).tick
  play n, release: 0.125, cutoff: 100, res: 0.8, wave: 0
  sleep 0.125
end

Przyjrzyjmy się każdej linii.

W pierwszej linii za pomocą funkcji use_synth ustawiamy, aby domyślnym syntezatorem był tb303. W drugiej linii tworzymy żywą pętlę, która po prostu będzie kręciła się w kółko i nazywamy ją :squelch. Trzecia linia jest miejscem, gdzie tworzymy nasz riff - pierścień nut (dźwięk E w 1, 2 i 3 oktawie), przez który po prostu cykamy za pomocą polecenia .tick. Definiujemy n reprezentującą aktualną nutę z naszego riffu. Znak równości mówi, żeby przypisać wartość z prawej strony do nazwy po lewej stronie. W każdym przebiegu pętli będzie to inna wartość. W pierwszym przebiegu n będzie ustawione jako dźwięk :e1. Przy drugiej rundzie będzie to :e2, potem :e3', a potem znowu :e1’, kręcąc się tak bez końca. Linia czwarta to miejsce, gdzie faktycznie uruchamiamy nasz syntezator :tb303. Przekazujemy do niego tutaj kilka interesujących opcji: release:, cutoff:, res: i wave:, które omówimy poniżej. Czwarta linia jest naszym miejscem drzemki (polecenie sleep) - prosimy żywą pętlę, aby kręciła się co każde ‘0.125’ sekundy, co daje nam 8 razy na sekundę przy domyślnym tempie 60 BPM (z ang. Beats Per Minute - uderzenia na minutę). Linia szósta jest miejscem, gdzie żywa pętla ma swój koniec (end). Mówi ona Sonic Pi o miejscu zakończenia żywej pętli.

Podczas gdy wciąż próbujesz połapać się, co jest grane, wpisz powyższy kod i naciśnij przycisk Run. Powinieneś usłyszeć, jak :tb303 wkracza do działania. A teraz moment, w którym coś się dzieje: zacznijmy kodowanie na żywo.

Podczas gdy pętla wciąż się kręci, zmień opcję cutoff: na wartość 110. Teraz ponownie naciśnij przycisk Run. Powinieneś usłyszeć, że dźwięk stał się trochę ostrzejszy i bardziej chlupotliwy. Wprowadź 120 i naciśnij przycisk Run. Teraz 130. Posłuchaj jak wyższe wartości odcięcia (ang. cutoff) powodują, że dźwięk staje się bardziej przeszywający i intensywny. Na koniec, kiedy poczujesz, że masz na to ochotę, obniż wartość do 80. Następnie możesz to powtarzać tyle razy, ile tylko chcesz. Nie przejmuj się, nadal będę tutaj…

Kolejną opcja wartą tego, by się nią pobawić, jest res:. Kontroluje ona poziom rezonansu filtra. Wysoki rezonans jest charakterystyczny dla acid’owych dźwięków basu. Wartość naszego parametru res: wynosi 0.8. Spróbuj podkręcić go do poziomu 0.85, potem do 0.9 i na końcu na 0.95. Możesz zauważyć, że odcięcie (cutoff) na poziomie 110 lub wyższym będzie powodować, że łatwiej uda Ci się dostrzec różnicę dźwięku. Na koniec zaszalej i spróbuj wpisać wartość 0.999, aby uzyskać szalone brzmienia. Przy takim wysokim ustawieniu opcji res: filtr odcięcia (cutoff) będziecie rezonował tak mocno, że zacznie sam tworzyć dźwięk!

Na koniec, aby uzyskać duży wpływ na tembr, spróbuj zmienić opcję wave: na 1. W ten sposób wybieramy źródło oscylatora. Domyślna wartość to 0 i daje w efekcie falę piłokształtną, wartość 1 daje falę pulsującą, a 2 - falę trójkątną.

Naturalnie spróbuj różnych riff’ów, zmieniając nuty w pierścieniu lub nawet wybierając nuty ze skal lub akordów. Zabaw się z Twoim pierwszym acid’owym syntezatorem basu.

Dekonstrukcja TB-303

Konstrukcja oryginalnego TB-303 jest w zasadzie bardzo prosta. Jak możesz zauważyć na poniższym diagramie, składa się on tylko z 4-ech głównych części.

TB-303 Design

Pierwszy to fala oscylatora - podstawowe składniki dźwięku. W tym przypadku mamy do czynienia z falą kwadratową. Następnie mamy obwiednię amplitudy oscylatora, która kontroluje poziom głośności fali kwadratowej na przestrzeni czasu. Można się w Sonic Pi do nich dobrać za pomocą opcji attack:, decay:, sustain: i release: wraz z odpowiednikami odpowiadającymi za ich poziom. Aby uzyskać więcej informacji, przeczytaj sekcję 2.4 zatytułowaną ‘Czas trwania obwiedni dźwięku’, która znajduje się w samouczku wbudowanym w aplikację. Następnie przepuszczamy naszą falę kwadratową opakowaną w obwiednię dźwięku przez filtr rezonansowy niskich tonów. Powoduje to odcięcie wyższych częstotliwości, a jednocześnie dodaje ten fajny efekt rezonansu. To jest moment, w którym zaczyna się robić ciekawie. Wartość odcięcia (cutoff) tego filtra jest również kontrolowana przez jego własną obwiednię! Oznacza to, że mamy niesamowitą kontrolę nad tembrem dźwięku poprzez bawienie się obiema obwiedniami. Przyjrzyjmy się temu bliżej:

use_synth :tb303
with_fx :reverb, room: 1 do
  live_loop :space_scanner do
    play :e1, cutoff: 100, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
    sleep 8
  end
end

W syntezatorze :tb303 dla każdej standardowej opcji obwiedni dźwięku istnieje odpowiednia opcja odcięcia cutoff_. Aby zmienić poziom odcięcia dla fazy ataku, możemy użyć opcji cutoff_attack:. Skopiuj kod powyżej do pustego buforu i naciśnij przycisk Run. Usłyszysz zwariowane dźwięki jodłujące w jedną i w drugą stronę. Teraz zacznij się bawić. Spróbuj zmienić czas trwania cutoff_attack: na 1, a następnie na 0.5. Teraz z kolei spróbuj wartości 8.

Zauważ, że dla uzyskania ekstra atmosfery przepuściłem wszystkie dźwięki przez efekt :reverb - spróbuj innych efektów i przekonaj się, który z nich się tutaj sprawdzi!

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

I na koniec kawałek, który skomponowałem, wykorzystując wszystkie pomysły z tego samouczka. Skopiuj go do pustego buforu, posłuchaj przez chwilę, po czym zacznij kodować na żywo, wprowadzając Twoje własne zmiany. Spróbuj zobaczyć, jakie zwariowane dźwięki możesz uzyskać! Do zobaczenia w kolejnym odcinku…

use_synth :tb303
use_debug false
 
with_fx :reverb, room: 0.8 do
  live_loop :space_scanner do
    with_fx :slicer, phase: 0.25, amp: 1.5 do
      co = (line 70, 130, steps: 8).tick
      play :e1, cutoff: co, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
      sleep 8
    end
  end
 
  live_loop :squelch do
    use_random_seed 3000
    16.times do
      n = (ring :e1, :e2, :e3).tick
      play n, release: 0.125, cutoff: rrand(70, 130), res: 0.9, wave: 1, amp: 0.8
      sleep 0.125
    end
  end
end

- Muzyczny Minecraft

Witam ponownie! W poprzednich tutorialach skupiliśmy się tylko i wyłącznie na muzycznych możliwościach Sonic Pi - zmieniając w ten sposób Twój komputer (np. Raspberry Pi) w gotowy do wystąpień publicznych instrument muzyczny. Do tej pory opanowaliśmy następujące umiejętności:

Kodowania Na Żywo - zmienianie dźwięków w locie Kodowania paru potężnych bitów, Wygenerowania potężnych melodii uzyskanych przy pomocy syntezatorów, Odtworzyliśmy sławne brzmienie acid’owego basu TB-303.

Istnieje znacznie więcej rzeczy, które mógłbym Ci pokazać (i omówimy je w kolejnych edycjach). Jednakże w tym miesiącu spójrzmy na coś, co Sonic Pi potrafi, a Ty prawdopodobnie nawet sobie nie zdawałeś z tego sprawy: kontrolowanie Minecrafta.

Witaj Świecie Minecrafta

OK, zaczynajmy! Włącz Twojego Raspberry Pi, uruchom Minecraft Pi i stwórz nowy świat. Teraz uruchom program i zmień rozmiar oraz ustawienie okien w taki sposób, abyś mógł jednocześnie widzieć Sonic Pi i Minecraft Pi.

W czystym buforze wpisz następujący kod:

mc_message "Hello Minecraft from Sonic Pi!"

A teraz naciśnij przycisk Run. Bum! Twoja wiadomość pojawiła się w Minecraft! Jakie to proste! A teraz przerwij na chwilę czytanie i spróbuj stworzyć swoje własne wiadomości. Milej zabawy!

Screen 0

Teleporter Dźwiękowy

Czas na małe rozpoznanie. Sięgnięcie po myszkę i klawiaturę jest standardową opcją, która umożliwia chodzenie po naszym świecie. To działa, ale jest całkiem wolne i nudne. Byłoby znacznie lepiej, gdybyśmy mieli pewien rodzaj maszyny umożliwiającej teleportację. Dzięki Sonic Pi mamy takie cudo. Spróbuj tego:

mc_teleport 80, 40, 100

Niespodzianka! To była długa droga w górę. Jeśli nie byłeś akurat w trybie latania, wtedy prawdopodobnie spadłeś w dół aż do samej ziemi. Jeśli szybko naciśniesz 2 razy spację, aby wejść w tryb latania i spróbujesz jeszcze raz się przeteleportować, zaczniesz unosić się w miejscu, do którego się przeniosłeś.

Chyba czas na wyjaśnienie, co oznaczają te liczby. Mamy trzy cyfry opisujące koordynaty miejsca w naszym świecie, do którego chcemy się przenieść. Nadamy każdej z liczb nazwę - x, y i z:

x - jak daleko w lewo lub prawo (w naszym przykładzie jest to 80) y - jak wysoko chcemy się znaleźć (w naszym przykładzie jest to 40) z - jak daleko w przód lub do tyłu (w naszym przykładzie 100)

Wybierając różne wartości dla x, y i z, możemy teleportować się gdziekolwiek w naszym świecie. Spróbuj! Wybierz inne liczby i zobacz, gdzie możesz wylądować. Jeśli ekran stanie się czarny, będzie tak, ponieważ przeteleportowałeś się pod ziemię lub w głąb góry. Wystarczy, że wybierzesz po prostu większą wartość y, aby ponownie znaleźć się powyżej gruntu. Eksploruj teren tak długo, aż znajdziesz się w miejscu, które Ci się podoba…

Korzystając z dotychczasowych idei, zbudujmy Dźwiękowy (Sonic) Teleporter, który będzie wydawał fajne dźwięki teleportacji w momencie, gdy będziemy śmigać wskroś świata Minecraft:

mc_message "Preparing to teleport...."
sample :ambi_lunar_land, rate: -1
sleep 1
mc_message "3"
sleep 1
mc_message "2"
sleep 1
mc_message "1"
sleep 1
mc_teleport 90, 20, 10
mc_message "Whoooosh!"

Screen 1

Magiczne Bloki

Teraz, gdy już znalazłeś fajne miejsce, zacznijmy budować. Mógłbyś zrobić to, do czego przywykłeś i zacząć wściekle klikać myszką, aby zacząć umieszczać kolejne bloki pod kursorem. Możesz też użyć magii Sonic Pi. Spróbuj tego:

x, y, z = mc_location
mc_set_block :melon, x, y + 5, z

A teraz spójrz! Na niebie pojawił się melon. Poświęć chwilę, aby przyjrzeć się temu kawałkowi kodu. Co zrobiliśmy? W linii pierwszej przechwyciliśmy aktualne położenie Steve’a jako zmienne x, y i z. Odpowiada to naszym koordynatom, które omówiliśmy już wcześniej. Następnie używamy tych współrzędnych w funkcji mc_set_block, co powoduje umieszczenie wybranego bloku w określonych współrzędnych. Aby zrobić coś wyżej na niebie, wystarczy, że zwiększymy wartość y. I to jest właśnie przyczyna, dla której dodajemy 5. Spróbujmy utworzyć z nich długą ścieżkę:

live_loop :melon_trail do
  x, y, z = mc_location
  mc_set_block :melon, x, y-1, z
  sleep 0.125
end

A teraz przenieś się do Minecraft, upewnij, że jesteś w trybie latania (wciśnij dwa razy spację jeśli nie) i przeleć dookoła po świecie. Spójrz za siebie, aby zobaczyć za sobą ścieżką złożoną z melonowych bloków! Zobacz, jaki rodzaj pokręconych wzorków możesz zrobić na niebie.

Kodowanie Na Żywo z Minecraft

Ci Was, którzy obserwowali ten poradnik przez ostatnich kilka miesięcy, prawdopodobnie czują teraz, że ich umysł za chwilę eksploduje. Ścieżka z melonów wygląda co prawda całkiem ciekawie, ale najbardziej ekscytującą częścią poprzedniego przykładu jest to, że możesz użyć w Minecraft żywej pętli live_loop! Dla tych, co jeszcze nie wiedzą - polecenie live_loop daje Sonic Pi specjalną magiczną zdolność, a nie posiada jej żaden inny język programowania. Pozwala Ci na uruchomienie wielu różnych pętli w tym samym czasie i zmianę ich zachowania w trakcie działania. Dzięki temu są one niewiarygodnie potężne i niesamowicie fantastyczne. Używam polecenia live_loop dostępnego w Sonic Pi do koncertowania na żywo w klubach - DJ’e korzystają z płyt, a ja z żywych pętli (live_loop‘y). Dzisiaj będziemy jednak kodować na żywo zarówno muzykę, jak i Minecraft.

Zaczynajmy. Uruchom powyższy kod i zacznij ponownie kreślić swoją ścieżkę z melonów. Teraz bez zatrzymywania kodu, po prostu zmień polecenie :melon na :brick (cegła) i naciśnij przycisk Run. Hej, zobacz, jak szybko robisz teraz ścianę z cegieł. Jakież to było proste! Wyobrażasz sobie może jakąś melodię, która mogłaby być odtwarzana, gdy to się dzieje? Bułka z masłem! Spróbuj tego:

live_loop :bass_trail do
  tick
  x, y, z = mc_location
  b = (ring :melon, :brick, :glass).look
  mc_set_block b, x, y -1, z
  note = (ring :e1, :e2, :e3).look
  use_synth :tb303
  play note, release: 0.1, cutoff: 70
  sleep 0.125
end

Teraz, podczas gdy wciąż gra muzyka zacznij zmieniać kod. Zmień typy bloku - spróbuj :water (woda), :grass (trawa) albo jakiś inny ulubiony typ bloku. Spróbuj również zmienić wartość odcięcia (cutoff) z 70 na 80 a później na 100. Czyż to nie jest fajne?

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

Screen 2

Spróbujmy połączyć wszystko, co do tej pory widzieliśmy z odrobiną dodatkowej magii. Połączmy naszą zdolność teleportacji z umieszczaniem bloków i muzyki, aby stworzyć Muzyczne Minecraft’owe Video. Nie przejmuj się, jeśli nie wszystko jeszcze rozumiesz, po prostu wpisz ten kawałek i baw się, zmieniając różne wartości, gdy kod jest wciąż uruchomiony. Miłej zabawy i do zobaczenia następnym razem…

live_loop :note_blocks do
  mc_message "This is Sonic Minecraft"
  with_fx :reverb do
    with_fx :echo, phase: 0.125, reps: 32 do
      tick
      x = (range 30, 90, step: 0.1).look
      y = 20
      z = -10
      mc_teleport x, y, z
      ns = (scale :e3, :minor_pentatonic)
      n = ns.shuffle.choose
      bs = (knit :glass, 3, :sand, 1)
      b = bs.look
      synth :beep, note: n, release: 0.1
      mc_set_block b, x+20, n-60+y, z+10
      mc_set_block b, x+20, n-60+y, z-10
      sleep 0.25
    end
  end
end
live_loop :beats do
  sample :bd_haus, cutoff: 100
  sleep 0.5
end

- Bizet’owe Bity

Po naszej krótkiej wycieczce do fantastycznego świata kodowania Minecraft’a z Sonic Pi w ubiegłym miesiącu wróćmy z powrotem do muzyki. Dzisiaj przeniesiemy klasyczną operowy taniec prosto w XXI wiek, używając niesamowitej potęgi kodu.

Skandaliczne i Szkodliwe

Wskoczmy do wehikułu czasu i cofnijmy się do roku 1875. Kompozytor o nazwisku Bizet właśnie skończył jego najnowszą operę Carmen. Niestety, jak to ma zazwyczaj miejsce z wieloma nowymi ekscytującymi utworami, ludzie na początku nie polubili jej wcale, ponieważ była zbyt skandaliczna i inna niż wszystko. Niestety Bizet zmarł dziesięć lat przed jej wielkim międzynarodowym sukcesem. Opera stała się jedną z najsławniejszych i najczęściej granych oper wszech czasów. Z współczuciem dla tej tragedii weźmy jeden z najbardziej znanych motywów z Carmen i przekształćmy go do nowoczesnego formatu muzyki, który również będzie zbyt skandaliczny i inny dla większości ludzi w naszych czasach - muzykę kodowaną na żywo!

Rozszyfrowywanie Habanery

Próba kodowania na żywo całej opery mogłaby być sporym wyzwaniem dla tego poradnika, skupmy się więc na jednej z jej najbardziej popularnych części - sekcja basowa Habanery:

Habanera Riff

Jeśli nie uczyłeś się jeszcze notacji muzycznej, to może to dla Ciebie wyglądać ekstremalnie niezrozumiałe. Jednakże, jako programiści, widzimy notację muzyczną jako kolejną formę kodu - jedyna różnica polega tu na tym, że reprezentuje instrukcje dla muzyka zamiast komputera. Musimy zatem znaleźć sposób na jego rozszyfrowanie go.

Nuty

Nuty są ułożone od lewej do prawej tak samo jak słowa, w tym tekście mają jednak różne wysokości. Wysokość na partyturze reprezentuje wysokość danej nuty. Im wyżej nuta znajduje się na pięciolinii, tym wyższy jest dźwięk tej nuty.

Wiemy już w jaki sposób możemy zmieniać wysokość nut w Sonic Pi - możemy używać dużych lub małych liczb takich jak play 75 czy play 80. Możemy też użyć nazw nut np. play :E lub play :F. Na szczęście każda z pozycji na pięciolinii reprezentuje konkretną nazwę nuty. Zerknij na tą przydatną tabelkę poniżej:

Notes

Przerwy

Nuty są bardzo bogatym i ekspresyjnym sposobem na przedstawianie wielu rzeczy. Skoro tak, to nie powinno Cię zbytnio zdziwić fakt, że nuty potrafią powiedzieć nie tylko jakie nuty powinniśmy zagrać, ale też kiedy ich nie grać. W programowaniu jest to bardzo analogiczne do idei nil lub null - oznacza ona brak wartości. Innymi słowy, moment, w którym nie gramy nuty, jest miejscem, gdzie jej nie ma.

Jeśli przyjrzysz się uważnie nutom, zauważysz, że jest ona aktualnie kombinacją czarnych kropek z liniami reprezentujące nuty do zagrania oraz falujące ogonki, które oznaczają przerwy. Na nasze szczęście Sonic Pi posiada bardzo poręczną reprezentację dla przerw - :r. Jeśli więc uruchomimy polecenie play :r, to zagra on ciszę! Możemy napisać również play :rest, play nil lub play false. Są to analogiczne odpowiedniki dla reprezentacji przerw.

Rytm

Na końcu jest jeszcze jedna rzecz do zrozumienia przy rozszyfrowywaniu nut - czasy ich trwania. Zauważ, że w oryginalnej notacji niektóre są połączone grubymi liniami, które nazywamy belkami. Druga nuta posiada dwie takie belki, co oznacza, że przerwa trwa jedną szesnastą uderzenia (bitu). Inne nuty posiadają pojedyncze belki - trwają one przez jedną ósmą uderzenia. Pozostałe nuty mają dwie falowane belki - one również reprezentują jedną szesnastą uderzenia.

Kiedy próbujemy rozszyfrować i odkrywać nowe rzeczy, bardzo przydatną sztuczką jest robienie wszystkiego tak bardzo analogicznie, jak to jest tylko możliwe, aby móc spróbować i wybadać ew. relacje lub wzorce. Na przykład, kiedy przepisujemy szesnastki, możesz zobaczyć, że nasza notacja zostaje zmieniona w prostą sekwencję nut i przerw.

Habanera Riff 2

Zamiana Habanery na kod

Jesteśmy teraz w stanie zacząć tłumaczyć tę linię basową na kod zrozumiały dla Sonic Pi. Spróbujmy rozszyfrować te noty i przerwy, używając do tego celu pierścienia:

(ring :d, :r, :r, :a, :f5, :r, :a, :r)

Zobaczmy, jak to brzmi. Wrzuć ten kawałek kodu do żywej pętli i zacznij przez niego tykać:

live_loop :habanera do
  play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
  sleep 0.25
end

Fantastycznie, ten natychmiastowo rozpoznawalny riff został przywrócony do życia w Twoich głośnikach. Dotarcie tutaj kosztowało wiele wysiłku, ale opłaciło się - przybij piątkę!

Nastrojowe Syntezatory

Teraz, gdy już mamy linię basową, spróbujmy odtworzyć klimat sceny operowej. Jednym z syntezatorów do wypróbowania to:blade, który jest jednym z wiodących w stylu lat 80-tych. Spróbujmy go użyć z początkową nutą :d i przepuścić przez efekty slicer i reverb:

live_loop :habanera do
  use_synth :fm
  use_transpose -12
  play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
  sleep 0.25
end
with_fx :reverb do
  live_loop :space_light do
    with_fx :slicer, phase: 0.25 do
      synth :blade, note: :d, release: 8, cutoff: 100, amp: 2
    end
    sleep 8
  end
end

A teraz spróbuj z innymi nutami z naszej linii basowej: :a i :f5. Pamiętaj - nie musisz naciskać stop - wystarczy, że zmodyfikujesz kod, podczas gdy muzyka wciąż gra i naciśniesz przycisk Run. Spróbuj również ustawić inne wartości dla opcji phase: np. 0.5, 0.75 czy 1.

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

Na koniec spróbujmy połączyć wszystkie pomysły, tak aby stworzyć nowy remix Habanery. Możesz zauważyć, że dorzuciłem kolejną partię linii basowej jako komentarz. Gdy już wpiszesz to wszystko do świeżego buforu, naciśnij przycisk Run, żeby usłyszeć kompozycję. Teraz, bez naciskania przycisku Stop, odkomentuj drugą linię poprzez usunięcie znaku # i ponownie wciśnij Run - ależ to jest fenomenalne! A teraz zacznij kombinować z tym kodem samodzielnie i baw się dobrze.

use_debug false
bizet_bass = (ring :d, :r, :r, :a, :f5, :r, :a, :r)
#bizet_bass = (ring :d, :r, :r, :Bb, :g5, :r, :Bb, :r)
 
with_fx :reverb, room: 1, mix: 0.3 do
  live_loop :bizet do
    with_fx :slicer, phase: 0.125 do
      synth :blade, note: :d4, release: 8,
        cutoff: 100, amp: 1.5
    end
    16.times do
      tick
      play bizet_bass.look, release: 0.1
      play bizet_bass.look - 12, release: 0.3
      sleep 0.125
    end
  end
end
 
live_loop :ind do
  sample :loop_industrial, beat_stretch: 1,
    cutoff: 100, rate: 1
  sleep 1
end
 
live_loop :drums do
  sample :bd_haus, cutoff: 110
  synth :beep, note: 49, attack: 0,
    release: 0.1
  sleep 0.5
end

- Zostań VJ’em Minecraft’a

Screen 0

Każdy grał w Minecraft’a i każdy z nas budował niesamowite budowle, projektował pomysłowe pułapki, a nawet stworzył wypracowane linie przewozowe kontrolowane za pomocą czerwonych kamieni pełniących rolę przełączników. Ale jak wielu z was korzystało z Minecraft do koncertowania? Założę się, że żaden z Was nie wiedział, iż można użyć Minecraft’a do stworzenia niesamowitych wizualizacji, tak jak to robią profesjonalni VJ’e.

Jeśli Twoim jedynym sposobem na wprowadzanie zmian w świecie Minecraft była myszka, to masz pewnie za sobą ciężki czas zmieniania rzeczy w wystarczająco szybkim czasie. Na szczęście Twoje Raspberry Pi domyślnie jest wyposażone w wersję Minecraft’a, która może być kontrolowana za pomocą kodu. Ponadto posiada ono domyślnie zainstalowaną aplikację Sonic Pi umożliwiającą nie tylko łatwe kodowanie Minecraft’a ale też i sprawiającą, że jest to niesamowicie fajne.

W dzisiejszym artykule pokażemy Ci parę sztuczek i trików, których używaliśmy do występowania w klubach oraz na wydarzeniach muzycznych na całym świecie.

Zaczynajmy…

Pierwsze Kroki

Zacznijmy na rozgrzewkę z czymś prostym, aby odświeżyć sobie podstawy. Najpierw włącz Twojego Raspberry Pi, a następnie uruchom Minecraft’a i Sonic Pi. W Minecraft, stwórz nowy świat, a w Sonic Pi wybierz świeży pusty bufor i wprowadź do niego następujący kod:

mc_message "Let's get started..."

Naciśnij przycisk Run, a zobaczysz wiadomość w oknie Minecraft’a. Dobrze, jesteśmy gotowi, by zacząć, zabawmy się…

Burze Piaskowe

Kiedy używamy Minecraft’a do tworzenia wizualizacji, próbujemy i zastanawiamy się co będzie zarówno wyglądać ciekawie jak i będzie łatwe do wygenerowania za pomocą kodu. Jedną z ciekawych sztuczek jest stworzenie burzy piaskowej poprzez zrzucenie bloków piasku z nieba. Jedyne co do tego jest potrzebne to kilka podstawowych funkcji:

sleep - dla wstawiania przerw pomiędzy akcjami mc_location - aby odczytać naszą aktualną pozycję mc_set_block- aby umieścić bloki piasku w określonej lokalizacji rrand - pozwala nam na wygenerowanie losowych wartość w określonym przedziale live_loop - pozwala nam na ciągłe tworzenie deszczu piasku

Jeśli którakolwiek z wbudowanych funkcji takich jak np. rrand jest dla Ciebie czymś nowym, wystarczy, że wpiszesz te słowo do buforu, ustawisz na nim kursor, a następnie naciśniesz kombinację klawiszy (skrót) Control-i, a spowodujesz, że otworzy się wbudowana dokumentacja. Innym sposobem jest przejście na zakładkę Język w systemie pomocy (przycisk Help), by następnie poszukać bezpośrednio funkcji, o której chcesz poczytać, podczas gdy w międzyczasie możesz robić wiele innych ekscytujących rzeczy (uwaga od tłumacza: niestety na razie wszystkie funkcje są opisane tylko po angielsku).

Spróbujmy sprawić by deszcz był delikatny, zanim rozpętamy sztorm w pełnej jego mocy. Przechwyć swoją aktualną lokalizację i użyj jej, aby stworzyć kilka bloków piasku gdzieś niedaleko na niebie:

x, y, z = mc_location
mc_set_block :sand, x, y + 20, z + 5
sleep 2
mc_set_block :sand, x, y + 20, z + 6
sleep 2
mc_set_block :sand, x, y + 20, z + 7
sleep 2
mc_set_block :sand, x, y + 20, z + 8

Kiedy naciśniesz przycisk Run, być może będziesz musiał rozejrzeć się trochę dookoła, gdyż bloki mogą zacząć spadać za Tobą, a to zależy, w którym kierunku akurat będziesz zwrócony. Nie przejmuj się, jeśli je przegapiłeś, po prostu uruchom ponownie przycisk Run dla kolejnej partii padającego piasku - upewnij się tylko, że patrzysz we właściwą stronę!

Spróbujmy szybko się rozejrzeć, co tutaj się wyprawia. W pierwszej linii przechwyciliśmy aktualne położenie Steve’a jako koordynaty za pomocą funkcji mc_location i zapisaliśmy je w zmiennych x, y i z. Następnie w kolejnych linijkach użyliśmy funkcji mc_set_block, aby umieścić trochę piasku w tym samym miejscu, w którym znajduje się Steve, ale z małymi modyfikacjami. Wybraliśmy takie same wartości dla koordynatu x, parametr y ustawiliśmy na 20 bloków wyżej, a na końcu znacznie większą wartość dla koordynatu z, żeby piasek opadał w pewnej odległości od Steve’a.

A może byś tak wziął ten kod i zaczął się nim bawić sam? Spróbuj dodać kolejne linie, zmienić czasy przerw (sleep), wymieszać piasek (:sand) ze żwirem (:gravel) albo wybrać inne współrzędne. Po prostu eksperymentuj i baw się dobrze!

Żywe Pętle Zdemaskowane

Dobrze, nadszedł czas, aby rozhulać naszą burzę dzięki uwolnieniu pełnej potęgi żywej pętli live_loop - magicznej zdolności Sonic Pi, która ujawnia prawdziwą potęgę kodowania na żywo - zmienianie kodu w locie!

live_loop :sand_storm do
  x, y, z = mc_location
  xd = rrand(-10, 10)
  zd = rrand(-10, 10)
  co = rrand(70, 130)
  synth :cnoise, attack: 0, release: 0.125, cutoff: co
  mc_set_block :sand, x + xd, y+20, z+zd
  sleep 0.125
end

Ale zabawa! Kręcimy się w kółko całkiem szybko (8 razy na sekundę) i w trakcie każdego przebiegu odczytujemy aktualną lokację Steve’a tak samo jak wcześniej, ale tym razem generujemy 3 losowe wartości:

xd - różnica dla x, która będzie między -10 a 10 zd - różnica dla z także między -10 a 10 co - wartość odcięcia dla filtra niskich tonów pomiędzy 70 a 130

Następnie używamy tych wartości w fns synth oraz mc_set_block', co daje nam bloki piasku spadające w losowych miejscach wokół Steve'a razem z perkusyjnym dźwiękiem deszczu podobnym do :cnoise`.

Dla nowych z żywymi pętlami - to jest miejsce, gdzie naprawdę zaczyna się zabawa z Sonic Pi. Spróbuj zmienić wartość uśpienia na 0.25 lub :sand na :gravel:, podczas spadania bloków piasku wokół Steve’a. Następnie naciśnij jeszcze raz przycisk Run. Bułka z masłem! Zmieniło się to bez zatrzymywania uruchomionego kodu! To jest Twoja brama do działania jako prawdziwy VJ. Nie krępuj się zmieniać rzeczy dookoła - jak różne można tworzyć wizualizacje bez zatrzymywania kodu?

Epickie Wzory Bloków

Screen 1

Na końcu innym bardzo dobrym sposobem na generowanie ciekawych wizualizacji jest generowanie ogromnych ozdobionych wzorami ścian i przemieszczanie się w ich kierunku oraz blisko nich. Aby uzyskać taki efekt, musimy zmienić podejście i, zamiast losowego ustawiania bloków, zacząć je układać w sposób uporządkowany. Możemy tego dokonać poprzez zagnieżdżenie dwóch pętli (naciśnij przycisk Help i przejdź w poradniku do sekcji 5.2 zatytułowanej “Iteracja i Pętle”, aby dowiedzieć się więcej o iteracjach). Zabawne polecenie |xd| tuż po poleceniu do oznacza, że przy każdej iteracji do zmiennej xd zostanie przypisana wartość, po której aktualnie iterujemy. Będą to więc kolejno 0, potem 1, potem 2, …., itd. Dzięki podwójnemu zagnieżdżeniu dużej ilości iteracji, tak jak to robimy tutaj, możemy wygenerować wszystkie współrzędne do narysowania kwadratu. Następnie mamy możliwość losowo wybierać typ bloku dla uzyskania ciekawego efektu:

x, y, z = mc_location
bs = (ring :gold, :diamond, :glass)
10.times do |xd|
  10.times do |yd|
    mc_set_block bs.choose, x + xd, y + yd, z
  end
end

Całkiem schludnie. Kiedy czerpiemy radość z zabawy, spróbuj zmienić bs.choose na bs.tick, aby ruszyć z losowego wzoru na bardziej regularny. Zrób to także z typami bloków. Niektórzy z Was będą pewnie chcieli wypróbować to w taki sposób, żeby zmieniały się one automatycznie.

Czas na finał VJ - zmień dwa 10.times na 100.times oraz kliknij Run. Bum! Ogromna gigantyczna ściana zbudowana z losowo rozmieszczonych cegieł. Wyobraź sobie, ile czasu zajęłoby zbudowanie tego za pomocą myszki! Naciśnij dwa razy spację w krótkim odstępie czasu, by wznieść się w powietrze, a następnie zacznij pikować dla paru wspaniałych efektów wizualnych. Nie zatrzymuj tutaj swoich myśli - użyj wyobraźni do wyczarowania naprawdę fajnych pomysłów, a następnie skorzystaj z mocy kodowania Sonic Pi do uczynienia ich prawdziwymi. Kiedy potrenujesz wystarczającą ilość czasu, przyciemnij światło i stwórz pokaz VJ dla Twoich znajomych!


- Surfowanie Po Losowych Strumieniach

W czwartym odcinku tej serii samouczków rzuciliśmy okiem na losowość podczas kodowania paru ciekawych riffów syntezatorów. Biorąc pod uwagę fakt, iż losowość jest ważną częścią mojego życia jako kodujący DJ, pomyślałem, iż przydatne może być bardziej szczegółowe ich wytłumaczenie. Zdobądź więc swoją szczęśliwą czapkę i zasurfujmy kilka losowych strumieni!

Nie istnieje żadna losowość

Pierwszą rzeczą, która na początku może Cię naprawdę zaskoczyć podczas zabawy z funkcjami losowości w Sonic Pi, jest fakt, iż nie są one rzeczywiście losowe. Co to więc oznacza? Dobrze, zróbmy więc kilka testów. Na starcie wyobraź sobie liczbę między 0 oraz 1. Zachowaj ją dla siebie i nie mów mi jej - to będzie na razie Twoja tajemnica. Niech zgadnę… czy to jest 0.321567? Nie? Nonsens, najwidoczniej nie jestem w tym dobry. Daj mi kolejną próbę, lecz teraz zapytajmy Sonic Pi o wybranie numeru tym razem. Uruchom Sonic Pi v2.7+ i poproś o losową liczbę, ale pamiętaj, żeby mi jej nie mówić:

print rand

Teraz dla odkrycia… czy to było 0.75006103515625? Tak! Heh, widzę, że jesteś trochę sceptyczny. Może to był szczęśliwy traf i wcale nie jestem w tym zły? Spróbujmy jeszcze raz. Naciśnij ponownie przycisk Run i zobaczmy, co otrzymaliśmy… Hę? Ponownie 0.75006103515625? To najwidoczniej nie może być losowe! Masz rację.

Co się tutaj dzieje? Fantazyjnym słowem nauki komputerowej jest tutaj determinizm. To po prostu oznacza, iż nic nie staje się przypadkowo i wszystko ma swoją wartość. Twoja wersja Sonic Pi przeznaczona jest do zwracania zawsze wartości 0.75006103515625. To może brzmieć trochę bezużytecznie, jednak zapewniam Cię, iż ma to miano najbardziej potężnej części programu. Jeżeli nad tym spędzisz trochę czasu, nauczysz się polegania na determinizmie natury losowości Sonic Pi jako fundamentu budowania bloków dla Twoich kompozycji i kodowanych na żywo zestawów DJ-ów.

Losowa Melodia

Kiedy Sonic Pi startuje, to właściwie ładuje do pamięci sekwencję 441,000 wstępnie wygenerowanych losowych wartości. Po wywołaniu funkcji losowej jak rand lub rrand, strumień wykorzystywany jest do generowania wyników. Dosłownie każde użycie tych funkcji używa danej wartości - dziesiąte użycie funkcji losowania także użyje dziesiątej wartości ze strumienia. Także za każdym razem, kiedy naciśniesz przycisk Run, jest on resetowany dla tego uruchomienia. Właśnie dzięki temu mogę przewidzieć wynik dla rand i dlaczego ta ‘losowa’ melodia jest za każdym razem taka sama. Każda wersja Sonic Pi wykorzystuje dokładnie ten sam losowy strumień, co odgrywa ważną rolę podczas udostępniania naszych kawałków innym.

Użyjmy zatem tej wiedzy do wygenerowania losowo powtarzanej melodii:

8.times do
 play rrand_i(50, 95)
 sleep 0.125
end

Wpisz ten kod do wolnego bufora i wciśnij Run. Usłyszysz melodię, która składa się z losowych nut z przedziału między 50 a 95. Po jego zakończeniu ponownie to zrób, aby jeszcze raz usłyszeć dokładnie tę samą melodię.

Przydatne Funkcje Randomizacji

Sonic Pi zawiera wiele przydatnych funkcji do działania z losowym strumieniem. Oto lista paru najbardziej użytkowych z nich:

rand - Zwyczajnie zwraca następną wartość w losowym strumieniu rrand - Zwraca losową wartość z danego zakresu rrand_i - Zwraca losową liczbę całkowitą z danego zakresu one_in - Zwraca true lub false z danym prawdopodobieństwem dice - naśladuje rzut kostki i zwraca wartość między 1 a 6 choose - Wybiera losową wartość z listy

Sprawdź ich dokumentację w systemie pomocy dla uzyskania szczegółowych informacji i przykładów.

Resetowanie Strumienia

Kiedy zdolność powtarzania sekwencji wybranych nut jest niezbędna, aby pozwolić Ci odtwarzać riff na parkiecie, to nie może być to dokładnie taki riff, jakiego oczekujesz. Czy nie byłoby to wspaniałe, gdybyśmy mogli wypróbować wielu różnych riffów i wybrać taki, który uważamy za najlepszy? Oto miejsce, gdzie zaczyna się prawdziwa magia.

Możemy ręcznie ustawić strumień z fn use_random_seed. W informatyce losowy seed to punkt początkowy, z którego nowy strumień składający się z losowych wartości może kiełkować i kwitnąć jak prawdziwy kwiat. Spróbujmy tego:

use_random_seed 0
3.times do
  play rrand_i(50, 95)
  sleep 0.125
end

Doskonale, mamy pierwsze trzy nuty powyżej z losowej melodii: 84, 83 oraz 71. Natomiast możemy zmienić teraz seed na cokolwiek innego. Co powiesz na to:

use_random_seed 1
3.times do
  play rrand_i(50, 95)
  sleep 0.125
end

Interesujące, mamy teraz 83, 71 oraz 61. Możesz zauważyć, że pierwsze dwa numery z tej krótkiej listy są takie same jak przedtem - to nie jest przypadkowy zbieg okoliczności.

Pamiętaj, że strumień losowych wartości jest tak naprawdę po prostu olbrzymią listą ‘wylosowanych wcześniej’ wartości. Korzystając z losowego ziarna, powoduje, że po prostu przeskakujemy do pewnego punktu w tej liście. Innym sposobem myślenia o tym to próba wyobrażenia sobie ogromnej, potasowanej zawczasu talii kart. Korzystanie z losowego ziarna (seed) powoduje odcięcie tej talii od pewnego momentu. Fantastyczną rzeczą jest to, iż pozwala nam to na bardzo precyzyjne skakanie po strumieniu losowych wartości, a co za tym idzie, daje nam ogromne możliwości, gdy tworzymy muzykę.

Powtórzmy naszą losową melodię z 8 nut z nowym strumieniem zresetowanej mocy, ale także dajmy ją w żywą pętlę, co pozwoli nam eksperymentować z kodem na żywo podczas jego odtwarzania:

live_loop :random_riff do    
  use_random_seed 0
  8.times do
    play rrand_i(50, 95), release: 0.1
    sleep 0.125
  end
end

Podczas kiedy nadal jest odtwarzany, zmień wartość seed’u z 0 na cokolwiek innego - masz tutaj wolną rękę. Co powiesz na 100, a może skusisz się na 999? Spróbuj swoich własnych wartości, eksperymentuj i baw się z kodem - zobacz, który seed generuje najlepszy Twoim zdaniem riff.

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

W tym miesiącu poradnik był mocno technicznym zanurzeniem się w to, jak w Sonic Pi działa mechanizm losowości. Mam nadzieję, że pozwoliło Ci to na pewne zaznajomienie się, jak działa ta funkcjonalność oraz że będziesz czuł się komfortowo, aby zacząć tworzyć powtarzalne wzorce w Twojej muzyce. Chciałbym zwrócić Twoją uwagę na to, iż możesz używać powtarzalnej losowości gdziekolwiek tylko chcesz. Na przykład możesz losowo różnicować poziom głośności Twoich nut, tempo Twojego rytmu, poziom efektu reverb, aktualny syntezator, poziom opcji mix dla danego efektu itp., itd. W przyszłości pochylimy się nad niektórymi z tych przykładów, ale teraz pozwól, że zostawię Cię z tym krótkim przykładem.

Wpisz następujący kod do czystego bufora, naciśnij Run i następnie zmieniając wartości seed dookoła, naciśnij Run jeszcze raz (kiedy muzyka ciągle jest grana). Odkrywaj różne dźwięki, rytmy i melodie, które możesz stworzyć. Kiedy znajdziesz ten jeden całkiem niezły, zapamiętaj wartość seed, aby móc do niego później powrócić. Gdy na końcu znajdziesz kilka seedów, które Ci się podobają, użyj ich w występie kodowanym na żywo dla Twoich znajomych, przełączając się między Twoimi ulubionymi seedami, by stworzyć cały kawałek.

live_loop :random_riff do
  use_random_seed 10300
  use_synth :prophet
  s = [0.125, 0.25, 0.5].choose
  8.times do
    r = [0.125, 0.25, 1, 2].choose
    n = (scale :e3, :minor).choose
    co = rrand(30, 100)
    play n, release: r, cutoff: co
    sleep s
  end
end
live_loop :drums do
  use_random_seed 2001
  16.times do
    r = rrand(0.5, 10)
    sample :drum_bass_hard, rate: r, amp: rand
    sleep 0.125
  end
end

- Kontroluj Swój Dźwięk

Do tej pory skupialiśmy się w tej serii na tworzeniu dźwięków. Odkryliśmy, że możemy uruchamiać wiele różnych syntezatorów wbudowanych w Sonic Pi z wykorzystaniem poleceń play i synth oraz wiemy, w jaki sposób uruchamiać nagrane wcześniej sample z wykorzystaniem polecenia sample. Zobaczyliśmy również, że możemy na te dźwięki nałożyć efekty studyjne (FX) takie jak reverb czy distortion, wykorzystując do tego polecenie with_fx. Jeśli połączysz to wszystko z niesamowicie dokładnym systemem koordynacji czasu (timing system), jaki posiada Sonic Pi, to daje Ci to szeroki wachlarz dźwięków, bitów i riff’ów. Jednakże gdy raz uruchomisz te pieczołowicie dobierane brzmienia, to nie ma już możliwości, aby cokolwiek zmienić, gdy muzyka już gra, prawda? Błąd! Dzisiaj nauczysz się czegoś bardzo potężnego - jak kontrolować syntezatory, gdy te już wystartowały.

Podstawowy Dźwięk

Stwórzmy prosty, ładny dźwięk. Uruchom Sonic Pi oraz w wolnym buforze wpisz poniższy tekst:

synth :prophet, note: :e1, release: 8, cutoff: 100

Naciśnij teraz przycisk Run, który znajduje się w lewym górnym rogu, by następnie usłyszeć piękny, dudniący dźwięk syntezatora. Śmiało, zrób to jeszcze kilka razy - poczuj ją. Okej, zrobione? Zacznijmy ją kontrolować!

Węzły Syntezatorów (Synth Nodes)

Małą znaną funkcją w Sonic Pi jest to, że polecenia play, synth oraz sample zwracają coś, co nazywamy SynthNode. Obiekt ten reprezentuje grający dźwięk. Możesz przechwycić jeden z tych SynthNodeów, korzystając ze standardowego mechanizmu zmiennych, a następnie kontrolować go w dalszym punkcie czasu. Przykładowo zmieńmy wartość opcji cutoff: po jednym uderzeniu:

sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
control sn, cutoff: 130

Spójrzmy na każdy wiersz:

Najpierw uruchamiamy syntezator :prophet, korzystając tak jak zwykle z funkcji synth. Jednakże przechwytujemy tutaj także wynik tego wywołania i zapisujemy go w zmiennej sn. Moglibyśmy nazwać tą zmienną zupełnie inaczej, np. synth_node lub jane - ta nazwa tak naprawdę nie ma znaczenia. Lecz bardzo ważne jest to, aby wybierać takie nazwy, które będą zrozumiałe i pomocne dla Ciebie podczas Twoich występów oraz dla ludzi czytających Twój kod. Wybrałem nazwę sn, ponieważ jest to bardzo fajny skrót do zapamiętania dla węzła syntezatora (synth node).

W linii drugiej mamy podstawową komendę sleep. Nie robi ona nic specjalnego - tylko pyta komputer o czekanie na jedno uderzenie przed przejściem do następnej linii.

Linia trzecia to miejsce, gdzie rozpoczyna się zabawa z kontrolą. Tutaj używamy funkcji control, by powiedzieć naszemu działającemu SynthNode o zmianie wartości na 130. Kiedy naciśniesz przycisk Run, usłyszysz, że syntezator :prophet gra jak wcześniej, jednak po jednym uderzeniu zmieni dźwięk na znacznie jaśniejszy.

Opcje Z Możliwością Modulacji

Większość opcji syntezatorów i efektów (FX) w Sonic Pi może zostać zmieniona po uruchomieniu. Jednakże nie należą do nich wszystkie. Na przykład opcje attack:, decay:, sustain: i release: dotyczące obwiedni dźwięku mogą być ustawione tylko raz przy uruchomieniu dźwięku. Ocena tego, czy dana opcja może lub nie może być zmieniana, jest prosta - wystarczy otworzyć dokumentację dla danego syntezatora lub efektu, a następnie przewinąć ją w dół do szczegółowej dokumentacji dla każdej z opcji i poszukać fraz “May be changed whilst playing” (dana opcja może być zmieniana w trakcie gry) lub “Can not be changed once set” (nie można jej zmieniać po ustawieniu wartości). Przykładowo dokumentacja dla opcji attack: syntezatora :beep jasno mówi, że nie ma możliwości jej zmiany:

Domyślnie: 0 Wartość musi wynosić 0 lub być wyższa Nie może być zmienione po ustawieniu Skalowanie z bieżącą wartością BPM

Wielokrotne Zmiany

Kiedy syntezator jest uruchomiony, nie masz żadnych ograniczeń, by zmienić to tylko raz - towarzyszy Ci wolny wybór, więc możesz go przemieniać tyle razy, ile masz na to ochotę. Dla przykładu możemy to zrobić z naszym :prophet na mini arpeggiator:

notes = (scale :e3, :minor_pentatonic)
sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
16.times do
  control sn, note: notes.tick
  sleep 0.125
end

W tym kawałku kodu dodaliśmy tylko kilka dodatkowych rzeczy. Najpierw zdefiniowaliśmy nową zmienną o nazwie notes zawierającą nuty, przez które będziemy chcieli iterować (arpeggiator to tylko fantazyjna nazwa dla czegoś, co iteruje przez listę nut w określonym porządku). Następnie zastąpiliśmy nasze pojedyncze wywołania polecenia control wywołaniem go 16 razy w pętli. Przy każdym uruchomieniu polecenia control, tykamy poleceniem :tick przez nasz pierścień z nutami notes, powtarzając go od nowa za każdym razem, gdy dobrniemy do jego końca (dzięki fantastycznym możliwościom pierścieni dostępnych w Sonic Pi). Aby wprowadzić trochę urozmaicenia, spróbuj zamiast polecenia :tick użyć polecenia :choose i zobacz, czy słyszysz różnicę.

Zauważ, że możemy zmienić wiele z nich jednocześnie. Spróbuj to zrobić z linią kontrolną i posłuchaj dla różnicy:

control sn, note: notes.tick, cutoff: rrand(70, 130)

Przesuwne

Kiedy kontrolujemy SynthNode, ten odpowiada dokładnie na czas i natychmiast zmienia wartość opt na nową, niczym wciśnięty przycisk lub śmigający przełącznik odpowiadający na zmianę. Może on brzmieć rytmicznie i perkusyjnie, zwłaszcza gdy opt kieruje aspektem barwy takim jak cutoff:. Jednakże czasami nie chcesz zmiany, która dzieje się od razu. Zamiast tego chciałbyś płynnie przejść z obecnej wartości na nową, jakbyś poruszał suwakiem lub pokrętłem. Oczywiście Sonic Pi może to zrobić, używając _slide:.

Każda opcja, która może być modyfikowana, posiada również specjalną odpowiadającą jej opcję _slide, która pozwala Ci na ustawienie czasu ślizgania. Na przykład opcja amp: posiada amp_slide:, a opcja cutoff: ma cutoff_slide. Te opcje ślizgania działają nieco inaczej niż wszystkie inne, ponieważ mówią one nucie syntezatora, jak powinny się zachowywać, gdy zostaną kontrolowane następnym razem. Spójrz na to:

sn = synth :prophet, note: :e1, release: 8, cutoff: 70, cutoff_slide: 2
sleep 1
control sn, cutoff: 130

Zauważ, że ten przykład jest prawie taki sam jak poprzedni, z tą jednak różnicą, że dodaliśmy opcję cutoff_slide:. Powoduje to, iż następnym razem syntezator ten, będzie miał kontrolowaną opcję cutoff:, przejście z aktualnej wartości do kolejnej zajmie 2 uderzenia. Dlatego, kiedy użyjemy polecenia control, możesz usłyszeć, że odcięcie (cutoff) ślizga się od 70 do 130. Nadaje to temu dźwiękowi bardzo ciekawy i dynamiczny charakter. A teraz spróbuj zmienić czas trwania ślizgu cutoff_slide: na mniejszą wartość, np. 0.5 albo na większą, np. 4, aby zobaczyć, jak zmienia się brzmienie. Pamiętaj, że możesz ślizgać się w ten sposób po każdej modyfikowalnej opcji, a każda wartość opcji _slide: może być całkowicie inna. Możesz więc ślizgać się powoli po filtrze odcięcia (cutoff:), amplituda dźwięku (amp:) może przesuwać się szybko, a zmiana kanału z jednego na drugi (pan:) może być gdzieś pomiędzy, o ile jest to brzmienie, którego właśnie szukasz…

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

Rzućmy okiem na krótki przykład, który demonstruje moc kontrolowania syntezatorów po tym, jak zostały one uruchomione. Zauważ, że możesz także przesuwać FX jak syntezatory, choć korzystając z trochę innej składni. Sprawdź sekcję 7.2 we wbudowanym poradniku, by uzyskać więcej informacji na temat kontroli FX.

Skopiuj kod do czystego bufora i posłuchaj. Nie zatrzymuj się jeszcze na tym etapie - rozpocznij zabawę z kodem. Zmień czas suwaków, nuty, syntezator, FX oraz czas uśpienia. Zauważysz, że możesz go przekształcić w coś zupełnie innego!

live_loop :moon_rise do
  with_fx :echo, mix: 0, mix_slide: 8 do |fx|
    control fx, mix: 1
    notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle
    sn = synth :prophet , sustain: 8, note: :e1, cutoff: 70, cutoff_slide: 8
    control sn, cutoff: 130
    sleep 2
    32.times do
      control sn, note: notes.tick, pan: rrand(-1, 1)
      sleep 0.125
    end
  end
end

- Śledzenie Rytmu

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

Licznik Uderzeń

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

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

puts tick #=> 0

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

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

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

Sprawdzanie Bitu

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

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

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

Pierścienie

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

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

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

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

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

Arpeggiator Żywej Pętli

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

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

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

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

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

Wielokrotne Równoczesne Uderzenia

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

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

Kolidujące Uderzenia

Duża przyczyna zamieszania z systemem cykania Sonic Pi jest wtedy, gdy ludzie chcą użyć go na wielu pierścieniach w tym samym live_loop:

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

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

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

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

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

- Krojenie Sampli

Jakiś czas temu w 3 odcinku serii poradników Sonic Pi dowiedzieliśmy się, w jaki sposób zapętlać, rozciągać i filtrować jeden z najbardziej popularnych sampli drum break’owych w historii - Amen Break. W tym numerze wykonamy kolejny krok i nauczymy się, w jaki sposób możemy go pociąć na kawałki, przetasować je i na koniec skleić ponownie w zupełnie nowy sposób. Nie przejmuj się, jeśli brzmi to dla Ciebie odrobinę zwariowanie. Za chwilę wszystko stanie się jasne i niedługo opanujesz zupełnie nowe narzędzie, którego będziesz używał w swoich kodowanych na żywo setach.

Dźwięk jako Dane

Zanim jednak zaczniemy, poświęćmy krótką chwilę, aby zrozumieć, w jaki sposób pracuje się z samplami. Podejrzewam, że każdy z Was miał już do czynienia z potężnym samplerem Sonic Pi. Jeśli nie - jest to najlepszy moment ku temu! Włącz swojego Raspberry Pi, uruchom Sonic Pi, wybierając go z Menu zawierającego aplikacje związane z programowaniem, wprowadź następujący kawałek kodu do czystego buforu, a następnie naciśnij przycisk Run - usłyszysz nagrany wcześniej beat z perkusją:

sample :loop_amen

Nagranie dźwięku jest prosto reprezentowane jako dane - dużo liczb pomiędzy -1 a 1, które odzwierciedlają szczyty i doliny danej fali dźwięku. Jeśli zagramy te liczby w odwrotnej kolejności, otrzymamy oryginalne brzmienie. Jednakże nic nas nie powstrzymuje przed tym, żeby zagrać je odwrotnie i stworzyć nowe brzmienie, prawda?

Ale w jaki sposób tak naprawdę sample są nagrywane? W sumie jest to dość proste, gdy już zrozumiesz podstawowe prawa, jakimi rządzi się dźwięk. Kiedy wydajesz jakiś dźwięk, na przykład poprzez uderzenie bębna, hałas przemieszcza się przez powietrze w sposób bardzo podobny tego, w jaki faluje tafla jeziora, kiedy wrzucisz do niego kamyk. Kiedy te fale dotrą do Twoich uszu, Twój bębenek porusza się sympatycznie i przetwarza te ruchy na dźwięk, który słyszysz. Jeśli chcemy nagrać i odtworzyć ten dźwięk ponownie, potrzebny jest nam sposób, w który moglibyśmy uchwycić, zapisać i odtworzyć te fale. Jednym ze sposobów jest wykorzystanie mikrofonu, który zachowuje się tak jak bębenek oraz porusza się tam i z powrotem, gdy kolejne fale dźwięku uderzają w niego. Następnie mikrofon konwertuje jego pozycję na małe elektroniczne sygnały, które są następnie mierzone wiele razy na sekundę. Te pomiary są następnie odwzorowane jako seria liczb pomiędzy -1 i 1.

Jeśli chcielibyśmy narysować wykres wizualizujący dźwięk, byłby to prosty graf przedstawiający dane, gdzie x byłoby osią czasu, natomiast aktualna pozycja mikrofonu/głośnika byłaby oznaczona na osi y jako wartość pomiędzy -1 a 1. Możesz zobaczyć przykład takiego grafu na samej górze diagramu.

Granie Wycinka Sampla

Zastanówmy się zatem, w jaki sposób możemy zakodować Sonic Pi, aby zagrało dany sampel od tyłu? Żeby odpowiedzieć na te pytanie, musimy przyjrzeć się opcjom start: i finish:, które są zdefiniowane dla polecenia sample. Pozwalają nam one na kontrolę momentu początku i zakończenia naszego dźwięku za pomocą liczb reprezentujących dźwięk. Wartości te dla obu opcji są reprezentowane jako liczby pomiędzy 0 i 1, gdzie 0 stanowi początek danego sampla, natomiast 1 jest jego końcem. Aby więc zagrać pierwszą połowę sampla Amen Break, wystarczy, że w opcji finish: ustawimy wartość 0.5:

sample :loop_amen, finish: 0.5

Możemy ponadto zdefiniować wartość początku opcją start: dla zagrania jeszcze mniejszego wycinka sampla:

sample :loop_amen, start: 0.25, finish: 0.5

Dla zabawy możesz nawet ustawić opcję finish:, tak aby była przed opcją start:, a spowodujesz, że ta część sampla zostanie zagrana od tyłu:

sample :loop_amen, start: 0.5, finish: 0.25

Zmiana kolejności Odtwarzania Sampla

Teraz, gdy już wiemy, że sampel to nic innego jak tylko lista liczb, które mogą być zagrane w odwróconej kolejności oraz w jaki sposób możemy zagrać określoną część danego sampla, możemy zacząć zabawę w zagranie sampla od tyłu w ‘niewłaściwej` kolejności.

Amen Slices

Spróbujmy wziąć nasz sampel Amen Break, pociąć go na 8 równych kawałków, a następnie przetasować te części. Spójrz na diagram: na samej górze sekcja A) reprezentuje diagram przedstawiający dane naszego oryginalnego sampla. Pocięcie go na 8 kawałków da nam to, co widzimy w sekcji B) - zauważ, że nadaliśmy każdej części inny kolor, abyśmy mogli łatwiej je rozróżnić. Możesz zauważyć, że każdy kawałek ma na górze wartości początku i końca. Na koniec w sekcji C) widzimy jedną z możliwych kombinacji przetasowania tych kawałków. Następnie możemy zagrać te części, aby stworzyć zupełnie nowy beat. Zobacz na poniższy kawałek kodu, który robi te rzeczy:

live_loop :beat_slicer do
  slice_idx = rand_i(8)
  slice_size = 0.125
  s = slice_idx * slice_size
  f = s + slice_size
  sample :loop_amen, start: s, finish: f
  sleep sample_duration :loop_amen, start: s, finish: f
end

wybieramy losowe cięcie do zagrania, co powinno być losową liczbą z zakresu od 0 do 7 (pamiętaj, że zaczynamy liczyć od 0). Sonic Pi posiada bardzo przydatną funkcję, która idealnie nadaje się do tego celu : rand_i(8). Następnie zapisujemy indeks tego losowego wycinka w zmiennej slice_idx. Definiujemy rozmiar dla każdego kawałka (slice_size), który w naszym przypadku ma wielkość 1/8 lub 0.125. Wielkość wycinka slice_size jest nam niezbędna, abyśmy mogli skonwertować nasz indeks slice_idx do wartości pomiędzy 0 a 1, tak żebyśmy użyli go jako nasza opcja startu start:. Aby obliczyć pozycję startu s, mnożymy indeks slice_idx przez wielkość wycinka slice_size. Obliczamy pozycję końcową f poprzez dodanie wielkości wycinka slice_size do pozycji początkowej s. Teraz możemy zagrać wycinek sampla poprzez podłączenie wartości s i f po opcje start: i finish: polecenia sample. Zanim zagramy kolejny kawałek, musimy wiedzieć, jak długo powinniśmy poczekać (sleep) - powinien to być czas równy długości trwania jednego wycinka sampla. Na szczęście Sonic Pi udostępnia nam funkcję sample_duration, akceptującą wszystkie te same opcje, które możemy przekazać do polecenia sample i po prostu zwraca długość trwania. W związku z tym poprzez przekazanie do polecenia sample_duration naszych opcji start: i finish:, możemy łatwo dowiedzieć się, jaki jest czas trwania pojedynczego wycinka sampla. Cały ten kod opakowujemy w żywą pętlę live_loop, dzięki temu w kółko wybieramy kolejne losowe kawałki do zagrania.

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

Spróbujmy teraz połączyć wszystko to, co do tej pory widzieliśmy i stwórzmy finałowy przykład, który zademonstruje, jak możemy wykorzystać podobne podejście do połączenia losowo pociętych beatów z odrobiną basu, aby utworzyć zaczyn ciekawego utworu. Teraz Twoja kolej - użyj poniższego kodu jako punkt wyjściowy i zobacz, czy potrafisz zmienić go po swojemu, aby utworzyć coś nowego…

live_loop :sliced_amen do
  n = 8
  s =  line(0, 1, steps: n).choose
  f = s + (1.0 / n)
  sample :loop_amen, beat_stretch: 2, start: s, finish: f
  sleep 2.0  / n
end
live_loop :acid_bass do
  with_fx :reverb, room: 1, reps: 32, amp: 0.6 do
    tick
    n = (octs :e0, 3).look - (knit 0, 3 * 8, -4, 3 * 8).look
    co = rrand(70, 110)
    synth :beep, note: n + 36, release: 0.1, wave: 0, cutoff: co
    synth :tb303, note: n, release: 0.2, wave: 0, cutoff: co
    sleep (ring 0.125, 0.25).look
  end
end

- Kodowanie Probabilistycznego Sekwencera

W poprzednim odcinku tej serii Sonic Pi odkrywaliśmy niesamowite możliwości randomizacji, aby móc zaprezentować różnorodność, zaskoczenie i zmianę w naszych utworach kodowanych na żywo oraz koncertach. Przykładowo wybieraliśmy losowe nuty z gamy do utworzenia nieskończonej melodii. Dzisiaj nauczymy się nowej techniki, która wykorzystuje randomizację dla rytmu - probabilistyczne uderzenia!

Prawdopodobieństwo

Zanim będziemy mogli zacząć tworzenie nowych beat’ów i syntezowanych rytmów, musimy zrobić szybką wycieczkę w krainę podstaw prawdopodobieństwa. Może to brzmieć odrobinę strasznie i skomplikowanie, ale tak naprawdę to jest to proste jak rzut kostką do gry - serio! Kiedy weźmiesz do ręki standardową kostkę do gry o 6 oczkach i rzucisz ją, to co tak naprawdę się dzieje? Dobrze, najpierw wyrzucisz 1, 2, 3, 4, 5 lub 6 oczek, z czego każda opcja będzie miała takie same szanse powodzenia. Tak naprawdę jeśli wiemy, że mamy do czynienia z kostką o 6 oczkach, to przeciętnie (jeśli będziesz rzucał bardzo wiele razy) powinieneś wyrzucić 1 przynajmniej raz na każde 6 rzutów. Oznacza to, że masz 1/6 szansy na to, aby wyrzucić 1. W Sonic Pi możemy naśladować takie rzuty kostką za pomocą funkcji dice. Spróbujmy rzucić jedną kostką 8 razy:

8.times do
  puts dice
  sleep 1
end

Zauważ, jak w logu są wyświetlane wartości od 1 do 6 - dokładnie tak samo, jak byśmy rzucali prawdziwą kostką do gry.

Losowe Beat’y

A teraz wyobraź sobie, że masz bęben i za każdym, gdy chcesz w niego uderzyć, rzucasz kostką. Jeśli wyrzuciłeś 1 oczko - uderzasz, jeśli wyrzuciłeś cokolwiek innego, nie uderzasz. Masz teraz probabilistyczną maszynę perkusyjną, która pracuje z prawdopodobieństwem 1 na 6! Posłuchajmy, jak to brzmi:

live_loop :random_beat do
  sample :drum_snare_hard if dice == 1
  sleep 0.125
end

Spróbujmy szybko przyjrzeć się każdej linii, aby upewnić się, że wszystko jest jasne i zrozumiałe. Najpierw tworzymy nową żywą pętlę live_loop o nazwie :random_beat, która będzie w kółko powtarzać 2 linie pomiędzy poleceniami do i end. Pierwsza z tych linii to wywołanie polecenia sample, które spowoduje, iż zostanie odtworzony nagrany wcześniej dźwięk (w tym wypadku będzie to :drum_snare_hard). Zauważ jednak, że linia ta ma na końcu specjalną klauzulę if. Oznacza ona, iż dany wiersz zostanie wykonany tylko wtedy, gdy warunek logiczny po prawej stronie jest prawdą i zwróci wartość true. Nasz warunek w tym wypadku to dice == 1. Powoduje to zawołanie naszej funkcji dice, która, jak już widzieliśmy, zwraca wartości pomiędzy 1 a 6. Następnie używamy operatora ==, aby sprawdzić, czy wylosowana wartość to 1. Jeśli tak, to nasze wyrażenie logiczne zwraca wartość true i usłyszymy dźwięk naszego werbla (z ang. snare drum). Jeśli jednak zwrócona wartość to nie 1, wtedy nasze wyrażenie logiczne zwróci wartość false i nasz werbel zostanie ominięty. Druga linia po prostu sprawia, że czekamy 0.125 sekundy, zanim ponownie wykonamy rzut kostką.

Zmienianie Prawdopodobieństwa

Ci z Was, którzy mieli okazję grać w gry fabularne (RPG - z ang. role-playing game), będą zapewne zaznajomieni z wieloma kostkami o dziwnych kształtach, które mają różną ilość oczek. Na przykład istnieje kostka o kształcie czworościanu, która posiada 4 ścianki, a nawet kostka o 20 ściankach w kształcie dwudziestościanu. Liczba ścian kostki zmienia szansę lub prawdopodobieństwo wyrzucenia 1 oczka. Im mniej ścianek, tym większa szansa na to, że wyrzucisz 1 i analogicznie im więcej ścianek, tym prawdopodobieństwo jest mniejsze. Przykładowo, korzystając z kostki o 4 oczkach, mamy szansę jeden do czterech na wyrzucenie liczby 1, a korzystając z kostki z 20 oczkami, jest tylko jedna dwudziesta szansy. Na szczęście Sonic Pi posiada bardzo wygodną funkcję one_in, która została stworzona właśnie do tego celu. Zagrajmy:

live_loop :different_probabilities do
  sample :drum_snare_hard if one_in(6)
  sleep 0.125
end

Uruchom powyższą żywą pętlę, a usłyszysz znany Ci już rytm o losowym brzmieniu. Nie zatrzymuj jednak tego kodu. Zamiast tego, w trakcie działania, zmień wartość 6 na inną, taką na przykład jak 2 lub 20 i naciśnij ponownie przycisk Run. Zauważ, że mniejsze liczby oznaczają, iż werbel będzie brzmiał częściej, a wyższe liczby spowodują, że będziemy go słyszeć rzadziej. Właśnie tworzysz muzykę, korzystając z mechanizmu prawdopodobieństwa!

Łączenie Prawdopodobieństwa

Bardzo ciekawe efekty można uzyskać wtedy, gdy połączymy jednocześnie uruchamianie wielu sampli z różnym prawdopodobieństwem. Na przykład:

live_loop :multi_beat do
  sample :elec_hi_snare if one_in(6)
  sample :drum_cymbal_closed if one_in(2)
  sample :drum_cymbal_pedal if one_in(3)
  sample :bd_haus if one_in(4)
  sleep 0.125
end

A teraz uruchom powyższy kod i zacznij zmieniać prawdopodobieństwa, aby zmienić rytm. Spróbuj również zmieniać sample, żeby utworzyć zupełnie nowe brzmienie. Na przykład spróbuj zmienić sampel :drum_cymbal_closed na :bass_hit_c dla uzyskania ekstra bass’u!

Powtarzalne Rytmy

Następnie możemy użyć naszej starej, dobrej znajomej funkcji use_random_seed, aby zresetować losowy strumień po 8 iteracjach, żeby utworzyć regularny beat. Wpisz następujący kod dla usłyszenia bardziej regularnego i powtarzalnego rytmu. Gdy już usłyszysz beat, spróbuj zmienić wartość ziarna z 1000 na inną liczbę. Zauważ, jak różne liczby będą generowały różne beaty.

live_loop :multi_beat do
  use_random_seed 1000
  8.times do
    sample :elec_hi_snare if one_in(6)
    sample :drum_cymbal_closed if one_in(2)
    sample :drum_cymbal_pedal if one_in(3)
    sample :bd_haus if one_in(4)
    sleep 0.125
  end
end

Kiedy pracuję z tego typu strukturami, staram się zazwyczaj zapamiętać, które ciągi dźwięków brzmią fajnie i staram się je zapisywać. W ten sposób mogę bardzo łatwo odtwarzać moje rytmy w przyszłych wprawkach czy wystąpieniach na żywo.

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

Na koniec możemy wrzucić tu trochę losowego basu, aby nadać mu fajną melodyjny charakter. Zauważ, że tutaj również możemy użyć naszej świeżo odkrytej metody probabilistycznego sekwencjonowania dla naszych syntezatorów - dokładnie w taki sam sposób, jak zrobiliśmy to w przypadku sampli. Nie zostawiaj tego jednak samemu sobie - spróbuj zmieniać liczby i zacznij tworzyć Twoje własne numery, korzystając z mocy probabilistyki!

live_loop :multi_beat do
  use_random_seed 2000
  8.times do
    c = rrand(70, 130)
    n = (scale :e1, :minor_pentatonic).take(3).choose
    synth :tb303, note: n, release: 0.1, cutoff: c if rand < 0.9
    sample :elec_hi_snare if one_in(6)
    sample :drum_cymbal_closed if one_in(2)
    sample :drum_cymbal_pedal if one_in(3)
    sample :bd_haus, amp: 1.5 if one_in(4)
    sleep 0.125
  end
end

- Modulacja Amplitudy

W tym miesiącu zgłębimy jeden z najbardziej potężnych i elastycznych efektów audio dostępnych w Sonic Pi - efekt :slicer. Po przeczytaniu tego artykułu nauczysz się, w jaki sposób manipulować całkowitą głośnością wszystkich części naszego dźwięku kodowanego na żywo w nowe, bardzo potężne sposoby. Pozwoli Ci to na tworzenie nowych struktur rytmicznych i dźwiękowych oraz rozszerzy Twoje możliwości dźwiękowe.

Pokrój tę Amplitudę

Ale co tak właściwie robi efekt :slicer? Jednym ze sposobów na myślenie o nim jest próba wyobrażenia sobie, że ktoś bawi się w kółko poziomem głośności na Twoim TV lub domowym zestawie hi-fi. Za chwilę się temu przyjrzymy, najpierw jednak posłuchajmy niskiego ryku poniższego kodu, który uruchamia syntezator :prophet:

synth :prophet, note: :e1, release: 8, cutoff: 70
synth :prophet, note: :e1 + 4, release: 8, cutoff: 80

A teraz spróbujmy nałożyć na niego efekt :slicer:


with_fx :slicer do
  synth :prophet, note: :e1, release: 8, cutoff: 70
  synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end

Posłuchaj, w jaki sposób efekt slicer przycisza i pogłaśnia dźwięk regularnie w rytm beatu. Zauważ również, jak efekt :slicer wpływa na cały dźwięk, który jest generowany spomiędzy bloku do/end. Możesz kontrolować prędkość, z jaką powoduje on włączanie i wyłączanie dźwięku za pomocą opcji fazy phase:, która kontroluje czas trwania pojedynczej fazy. Domyślnie jest to wartość 0.25, co oznacza, że będzie to miało miejsce 4 razy na sekundę przy domyślnym tempie 60 BPM (ang. Beats Per Minute - ilość uderzeń na minutę). Spróbujmy to przyspieszyć:

with_fx :slicer, phase: 0.125 do
  synth :prophet, note: :e1, release: 8, cutoff: 70
  synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end

A teraz spróbuj samodzielnie użyć innej długości fazy phase:. Spróbuj użyć dłuższych i krótszych wartości. Zobacz, co się stanie, jeśli wybierzesz naprawdę małą liczbę. Spróbuj również użyć innych syntezatorów, np. :beep lub :dsaw oraz innych nut. Zerknij na poniższy diagram, aby zobaczyć, jak różne wartości fazy phase: zmieniają ilość modulacji amplitudy przypadających na jedno uderzenie (beat).

Phase Durations

Czas trwania fazy to długość czasu, jaka jest potrzebna dla jednego włączenia/wyłączenia cyklu. Dlatego też mniejsze wartości spowodują, że efekt FX będzie włączany i wyłączany dużo częściej niż przy ustawieniu większych wartości. Dobrymi wartościami na początek zabawy są 0.125, 0.25, 0.5 i 1.

Kontrola Fal

Domyślnym zachowaniem efektu :slicer jest korzystanie z kwadratowej fali do manipulacji amplitudą na przestrzeni czasu. To właśnie dlatego słyszymy pełną amplitudę naszego dźwięku przez pewien moment, a potem nagle zostaje on całkowicie wyłączony na kolejny moment, potem znowu gra - i tak w kółko. Okazuje się jednak, że fala kwadratowa jest zaledwie jedną z 4 różnych fal, które mogą być używane przez efekt :slicer. Inne fale, z których możemy korzystać, to piła (ang. saw), trójkąt (ang. triangle) i sinusoida. Zerknij na poniższy diagram, aby zobaczyć, jak one wyglądają. Możemy również posłuchać, jak brzmią. Na przykład poniższy kod używa sinusoidy jako fali sterującej. Posłuchaj, jak dźwięk nie jest już włączany i wyłączany nagle, lecz zamiast tego płynnie pojawia się i zanika:

with_fx :slicer, phase: 0.5, wave: 3 do
  synth :dsaw, note: :e3, release: 8, cutoff: 120
  synth :dsaw, note: :e2, release: 8, cutoff: 100
end

Spróbuj pobawić się z różnymi formami fali poprzez zmianę opcji wave: na wartość 0, aby uzyskać falę podobną do piły, 1 dla uzyskania fali o kwadratowym kształcie, 2 dla stworzenia fali trójkątnej oraz 3, aby fala miała kształt sinusoidalny. Zobacz też, jak różne fale brzmią z innymi opcjami, na przykład phase:.

Każda z tych fal może zostać odwrócona za pomocą opcji invert_wave:, która obraca ją wokół osi y. Przykładowo w jednej fazie fala o kształcie piły zazwyczaj zaczyna się wysoko, powoli opada, po czym ponownie wskakuje na szczyt. Ustawiając opcję invert_wave: 1, fala taka zacznie się nisko i najpierw będzie powoli szła w górę do momentu, w którym z powrotem zeskoczy na dół. Oprócz tego możemy kontrolować falę poprzez uruchomienie jej w różnych momentach, korzystając z polecenia phase_offset: - używamy do tego wartości pomiędzy 0 a 1. Bawiąc się i zmieniając wartości opcji phase:, wave:, invert_wave: i phase_offset, możesz znacząco wpłynąć na to, w jaki sposób amplituda jest zmieniana na przestrzeni czasu.

Phase Durations

Ustawianie własnych poziomów

Domyślnie :slicer zmienia się w zakresie amplitudy o wartościach od 1 (pełna głośność) do 0 (cisza). Może to zostać zmienione za pomocą opcji amp_min: (amplituda minimalna) oraz amp_max: (amplituda maksymalna). Możesz z nich skorzystać w połączeniu z falą sinusoidalną, aby stworzyć prosty efekt tremolo:

with_fx :slicer, amp_min: 0.25, amp_max: 0.75, wave: 3, phase: 0.25 do
  synth :saw, release: 8
end

To jest zupełnie tak jak złapanie pokrętła od głośności znajdującego się na Twoim sprzęcie hi-fi i przekręcanie go odrobinę w górę i w dół w taki sposób, że dźwięk ‘drga’ (z ang. wobble) w jedną i drugą stronę.

Prawdopodobieństwa

Jednym z najbardziej potężnych właściwości efektu :slicer jest zdolność do używania prawdopodobieństwa, aby decydowało o tym, kiedy go włączać, a kiedy wyłączać. Zanim :slicer zacznie nową fazę, następuje rzut kostką i w zależności od wyniku albo zostaje użyta określona fala, albo dźwięk pozostanie wyciszony. Posłuchaj:

with_fx :slicer, phase: 0.125, probability: 0.6  do
  synth :tb303, note: :e1, cutoff_attack: 8, release: 8
  synth :tb303, note: :e2, cutoff_attack: 4, release: 8
  synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end

Posłuchaj teraz, jak udało nam się uzyskać bardzo interesujący rytm impulsów. Spróbuj zmienić opcję probability: na inną wartość pomiędzy 0 a 1. Te bliższe zeru spowodują, iż między każdym z dźwięków pojawi się więcej przestrzeni. Będzie to spowodowanie tym, że prawdopodobieństwo tego, iż dźwięki zostaną uruchomione, będzie znacznie większe.

Inną rzeczą godną zanotowania jest to, że system prawdopodobieństwa w efektach (FX) jest dokładnie taki sam jak system randomizacji (losowości), do którego można uzyskać dostęp przez funkcje takie jak rand czy shuffle. Oba są całkowicie przewidywalne. Oznacza to, że za każdym razem, gdy naciśniesz przycisk Run, usłyszysz dokładnie ten sam rytm pulsujący dla danego prawdopodobieństwa. Jeśli chciałbyś to zmienić, to zawsze możesz użyć opcji seed:, aby wybrać inny punkt początkowy dla losowych wartości. Działa to dokładnie tak samo jak funkcja use_random_seed, ale wpływa tylko na ten konkretny efekt.

Na koniec możesz zmienić zmienić pozycję spoczynku dla fali kontrolującej, kiedy test prawdopodobieństwa nie udaje się z wartości 0 na dowolną inną pozycję, wykorzystując opcję prob_pos:

with_fx :slicer, phase: 0.125, probability: 0.6, prob_pos: 1  do
  synth :tb303, note: :e1, cutoff_attack: 8, release: 8
  synth :tb303, note: :e2, cutoff_attack: 4, release: 8
  synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end

Przycinanie Beat’ów

Jedną naprawdę fajną rzeczą jest spróbowanie użycia efektu :slicer do pocięcia beatu perkusyjnego:

with_fx :slicer, phase: 0.125 do
  sample :loop_mika
end

Pozwala nam to na wzięcie dowolnego sampla i stworzenie zupełnie nowego brzmienia rytmicznego, co daje ogromną frajdę. Jednakże jedną rzeczą, o której należy pamiętać, jest to, aby upewnić się, iż tempo sampla pasuje do naszego aktualnego tempa BPM w Sonic Pi. W przeciwnym wypadku nasze cięcia będą brzmieć całkowicie beznadziejnie. Na przykład spróbuj zamienić sampel :loop_mika na loop_amen, aby usłyszeć, jak kiepsko może to brzmieć, kiedy tempo jest niewłaściwe.

Zmiana tempa

Jak już widzieliśmy, zmiana domyślnego tempa BPM z wykorzystaniem polecenia use_bpm spowoduje, że wszystkie czasy odpoczynku (ang. sleep) oraz długość trwania obwiedni dźwięku syntezatorów zwiększą się lub skrócą, aby dopasować się do beatu. Dotyczy to również efektu :slicer, ponieważ długość trwania opcji phase: jest mierzona w beatach, a nie sekundach. Możemy zatem naprawić problem, jaki mamy w pętli loop_amen powyżej poprzez zmianę tempa BPM, tak aby pasowało do naszego sampla:

use_sample_bpm :loop_amen
with_fx :slicer, phase: 0.125 do
  sample :loop_amen
end

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

Spróbujmy zastosować wszystkie te pomysły w finalnym przykładzie, który używa tylko samego efektu :slicer do stworzenia ciekawej kombinacji. Dalej, śmiało - zacznij zmieniać ten kawałek i zrób z niego swój nowy numer!

live_loop :dark_mist do
  co = (line 70, 130, steps: 8).tick
  with_fx :slicer, probability: 0.7, prob_pos: 1 do
    synth :prophet, note: :e1, release: 8, cutoff: co
  end
  
  with_fx :slicer, phase: [0.125, 0.25].choose do
    sample :guit_em9, rate: 0.5
  end
  sleep 8
end
live_loop :crashing_waves do
  with_fx :slicer, wave: 0, phase: 0.25 do
    sample :loop_mika, rate: 0.5
  end
  sleep 16
end

- Pięć Technik Kodowania Na Żywo

W bieżącym numerze tego poradnika o Sonic Pi zobaczymy, w jaki sposób możesz zacząć traktować Sonic Pi jak prawdziwy instrument. Musimy zatem zacząć myśleć o kodzie w zupełnie nowy sposób. Osoby kodujące na żywo myślą o kodzie w sposób podobny do tego, w jaki skrzypkowie myślą o swoich smyczkach. W rzeczy samej tak jak skrzypek potrafi wykorzystać różne techniki smyczkowania, aby stworzyć różne dźwięki (długie powolne ruchy kontra szybkie krótkie pociągnięcia), tak samo my poznamy pięć podstawowych technik kodowania na żywo, które umożliwia Sonic Pi. Pod koniec tego artykułu będziesz mógł samodzielnie ćwiczyć na potrzeby swoich własnych występów przed publicznością.

1. Zapamiętaj Skróty

Pierwszą wskazówką w kodowaniu na żywo z Sonic Pi jest zaczęcie używania skrótów klawiszowych. Na przykład zamiast tracić cenny czas na sięganie po myszkę, przesuwanie ją na przycisk Run i kliknięcie, możesz po prostu nacisnąć jednocześnie przyciski alt i r. Będzie to dużo szybsze i dzięki temu wciąż będziesz miał palce na klawiaturze gotowe do kolejnej edycji kodu. Możesz poznać wszystkie skróty klawiszowe dotyczące przycisków na górze poprzez najechanie na nie myszką i poczekanie chwilę, aż pokaże się opis. Aby zobaczyć pełną listę skrótów klawiszowych, udaj się do sekcji 10.2 samouczka wbudowanego w Sonic Pi.

Jedną z fajniejszych rzeczy, które można zrobić podczas występów na żywo, jest nadanie Twoim ruchom finezji, gdy naciskasz skróty klawiszowe. Na przykład bardzo dobrą rzeczą jest zakomunikowanie publiczności, że zamierzasz wprowadzić zmianę - postaraj się więc ozdobić Twój ruch, gdy naciskasz alt-r dokładnie w taki sam sposób, w jaki zrobiłby to gitarzysta gdy uderza o struny, aby zagrać fantastyczny “akord mocy” (ang. power chord).

2. Układaj Swoje Dźwięki Manualnie

Teraz potrafisz już natychmiast uruchamiać kod za pomocą klawiatury, możesz więc od razu zacząć wykorzystywać tę umiejętność przy drugiej technice polegającej na ręcznym układaniu kolejnej warstwy Twojej kompozycji. Zamiast ‘komponowania’ przy wykorzystaniu wielu poleceń play i sample oddzielonych odwołaniami do sleep, będziemy mieli tylko jedno wywołanie polecenia play, które będziemy manualnie zmieniać, używając polecenia alt-r. Spróbujmy zatem! Wpisz poniższy kod do pustego bufora:

synth :tb303, note: :e2 - 0, release: 12, cutoff: 90

A teraz naciśnij przycisk Run i gdy dźwięk wciąż jeszcze gra, popraw kod, aby dorzucić cztery nuty poprzez zmianę kodu na następujący:

synth :tb303, note: :e2 - 4, release: 12, cutoff: 90

A teraz naciśnij ponownie przycisk Run, aby usłyszeć oba dźwięki grające w tym samym czasie. Dzieje się tak, ponieważ przycisk Run dostępny w Sonic Pi nie czeka w ogóle na zakończenie jakiegokolwiek poprzedniego kodu, lecz zamiast tego uruchamia nasz kod w tym samym czasie. Oznacza to, że możesz ręcznie w bardzo łatwy sposób nawarstwić wiele razy różne dźwięki z małymi lub dużymi zmianami pomiędzy każdym uruchomieniem. Na przykład spróbuj zmienić za jednym razem opcje note: i cutoff:, a następnie odpalić kod ponownie.

Możesz spróbować tej techniki z długimi abstrakcyjnymi samplami. Na przykład:

sample :ambi_lunar_land, rate: 1

Spróbuj zacząć z wyłączonym samplem, a następnie sukcesywnie zmniejszaj o połowę wartości opcji rate: pomiędzy kolejnymi naciśnięciami Run. Zacznij od 1, potem 0.5, 0.25 aż do 0.125 - sprawdź nawet jakieś liczby ujemne, na przykład -0.5. Spróbuj nawarstwić te dźwięki na siebie i zobacz, dokąd uda Ci się to doprowadzić. Na koniec spróbuj dodać jakiś efekt.

Kiedy występujesz na żywo, pracując w ten sposób z prostymi liniami kodu, to publiczność, dla której Sonic Pi jest czymś nowym, ma całkiem niezłą szansę na to, żeby śledzić to, co robisz i kod, który tworzysz, dzięki czemu mogą czytać docierający do nich dźwięk.

3. Opanuj Żywe Pętle (Live Loops)

Kiedy pracujemy z bardziej rytmiczną muzyką, uruchamianie wszystkiego z ręki przy utrzymaniu odpowiedniego tempa może być dosyć trudne, jeśli nie niemożliwe. Zamiast tego dużo lepiej jest skorzystać z żywej pętli live_loop. Pozwala Ci to na powtarzanie Twojego kodu, a jednocześnie masz możliwość edycji i przygotowania go na kolejny przebieg pętli. Ponadto będą one uruchomione w tym samym czasie co inne żywe pętle live_loop - oznacza to, że możesz połączyć je razem ze sobą oraz z manualnym uruchamianiem kodu. Zerknij na sekcję 9.2 wbudowanego samouczka, aby uzyskać więcej informacji o tym, jak możesz pracować z żywymi pętlami.

Kiedy występujesz na żywo, pamiętaj, aby korzystać z dostępnej dla polecenia live_loop opcji sync:. Pozwoli Ci to na naprawienie nieoczekiwanych pomyłek, które powodują zatrzymanie danego kawałka kodu ze względu na błąd. Jeśli posiadasz już opcję sync:, która wskazuje na inną istniejącą i poprawną pętlę live_loop, to możesz szybko naprawić błąd i ponownie uruchomić kod, co pozwoli na zresetowanie całej sytuacji bez utraty choćby jednego beatu.

4. Korzystaj z Głównego Miksera (Master Mixer)

Jednym z najpilniej strzeżonych sekretów Sonic Pi jest to, że posiada on główny mikser, przez który przepływają wszystkie dźwięki. Mikser ten posiada zarówno filtr niskich częstotliwości jak i filtr wysokich częstotliwości. Możesz więc bardzo łatwo wprowadzać globalne modyfikacje dźwięku. Dostęp do głównego miksera uzyskasz za pomocą funkcji set_mixer_control!. Przykładowo, kiedy został uruchomiony kod i odtwarzany jest dźwięk, wprowadź to do zapasowego bufora i naciśnij Run:

set_mixer_control! lpf: 50

Po uruchomieniu tego kodu wszystkie nowe dźwięki będą miały zaaplikowany filtr niskich tonów i w związku z tym zostaną bardziej stłumione. Zauważ, że oznacza to, iż nowe wartości miksera zostaną takie same, dopóki nie zostaną ponownie zmienione. Jeśli jednak chcesz, możesz zawsze zresetować mikser do domyślnego poziomu poprzez użycie reset_mixer!. Kilkoma obecnie wspieranymi opcjami są: pre_amp:, lpf: hpf: oraz amp:. Aby zobaczyć pełną listę dostępnych parametrów, wystarczy, że zajrzysz do wbudowanej dokumentacji dostępnej dla polecenia set_mixer_control!.

Użyj opcji typu *slide, aby zmienić poziom wartości jednej lub wielu opcji w taki sposób, jakbyś używał do tego celu suwaka na mikserze. Posługując się przykładem, żeby powoli przesunąć na mikserze filtr niskich częstotliwości w dół z obecnej wartości do 30, użyj poniższego:

set_mixer_control! lpf_slide: 16, lpf: 30

Po tym przesunięciu możesz szybko wrócić do wyższej wartości za pomocą:

set_mixer_control! lpf_slide: 1, lpf: 130

Kiedy występujesz, często przydatne jest zachowanie czystego bufora do pracy z takim mikserem jak ten.

5. Praktyka

Najważniejszą techniką do nauki żywego kodowania jest praktyka. Tę metodę wykorzystuje wielu profesjonalnych muzyków - grają oni na swoich instrumentach przez kilka godzin dziennie, by stać się coraz to lepszymi twórcami. Trenowanie jest tak samo ważne zarówno dla osoby kodującej na żywo, jak i gitarzysty. Pozwala ono Twoim palcom na zapamiętanie pewnych wzorców, co umożliwia im następnie o wiele płynniejszą pracę. Praktyka daje również możliwości do odkrywania nowych dźwięków i składni kodów.

Podczas występów na żywo zauważysz, że im więcej ćwiczysz, tym łatwiej będzie Ci się rozluźnić na imprezie. Ponadto dzięki praktyce zdobędziesz sporo doświadczenia, które będziesz mógł potem wykorzystać. Także pomoże Ci zrozumieć, które typy zmian będą interesujące oraz czy będą dobrze współgrać z aktualnie grającymi dźwiękami.

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

W tym miesiącu zamiast dawać Ci końcowy przykład, który bardzo dobrze wkomponowywał się w tematy omawiane w danym numerze, proponuję małe wyzwanie. Zobacz, czy jesteś w stanie spędzić cały tydzień, ćwicząc każdego dnia jedną z wymienionych technik. Na przykład jednego dnia ćwicz ręczne uruchamianie kodu, następnego spróbuj popracować z jakąś prostą żywą pętlą live_loop, a kolejnego dnia spróbuj pobawić się z głównym mikserem. Powtórz to raz jeszcze. Nie przejmuj się, jeśli na początku będziesz odczuwać, że idzie to jak po grudzie - po prostu staraj się ćwiczyć, a zanim się obejrzysz, zaczniesz kodować na żywo przed prawdziwą publicznością.


- 8 Wskazówek dotyczących ćwiczenia kodowania na żywo (Live Coding)

W ubiegłym miesiącu mieliśmy okazję poznać pięć ważnych technik, które umożliwiają opanowanie kodowania na żywo (Live Coding) - innymi słowy, dowiedzieliśmy się, w jaki sposób możemy wykorzystać Sonic Pi, aby zastosować do kodu takie same podejście jak do instrumentu muzycznego. Jedną z ważnych koncepcji, które omówiliśmy, była praktyka. W tym miesiącu posuniemy się dalej i głębiej, żeby zrozumieć, dlaczego praktykowanie kodowania na żywo jest takie ważne i w jaki sposób możesz zacząć.

Ćwicz regularnie

Najważniejszą radą, jaką mogę Ci dać, to pilnowanie się, aby ćwiczyć regularnie. Z zasady zazwyczaj ćwiczę ok. 1-2 godzin dziennie, ale dla Ciebie na początek może wystarczyć i 20 minut dziennie. Mało, ale często jest to Twój cel - jeśli więc możesz wygospodarować choćby 10 min, to świetny początek.

Wskazówka #1 - spraw, aby ćwiczenie stało się Twoją rutyną. Znajdź w ciągu dnia dobry moment, który będzie Ci odpowiadał i postaraj się ćwiczyć w tym czasie tak wiele dni w tygodniu, jak tylko możesz. Już niedługo będziesz nie będziesz mógł się doczekać Twojej kolejnej regularnej sesji.

Naucz się pisać bezwzrokowo na klawiaturze

Jeśli zdarzy Ci się oglądać profesjonalnego muzyka występującego na scenie, to na pewno zauważysz kilka rzeczy. Po pierwsze, kiedy grają, nie patrzą na swój instrument. Ich palce, ramiona i ciała wiedzą, które klawisze naciskać, które struny uderzać, w który bęben uderzyć bez nadmiernej konieczności myślenia o tym, jak to zrobić. Nazywa się to “pamięcią mięśniową” i mimo że może to brzmieć jak coś, co mogą robić tylko profesjonaliści - to jest z tym dokładnie tak samo jak wtedy, gdy nauczyłeś się chodzić czy jeździć na rowerze - ćwiczenie poprzez powtarzanie. Osoby kodujące na żywo (Live Coders) używają pamięci mięśniowej, aby zwolnić ich umysły z konieczności myślenia o tym, jak układać swoje palce, dzięki czemu mogą skupić się na muzyce. Nazywa się to pisaniem bezwzrokowym - pisaniem bez konieczności patrzenia na klawiaturę.

Wskazówka #2 - naucz się pisać bez patrzenia na klawiaturę. Istnieje wiele aplikacji, stron, a nawet gier, które pomogą Ci to osiągnąć. Znajdź jedną, która Ci się podoba i trzymaj się jej, dopóki nie będziesz umiał kodować bez konieczności opuszczania wzroku na klawiaturę.

Koduj na stojąco

Ciało muzyka jest przystosowane do grania na swoim instrumencie. Na przykład osoba grająca na trąbce musi być zdolna do porządnego dmuchania, gitarzysta musi umieć złapać gryf z odpowiednią siłą, perkusista musi umieć nieprzerwanie uderzać w bębny przez długi kawałek czasu. A jakie zdolności fizyczne są niezbędne do kodowania na żywo? Dokładnie tak jak DJe, kodujący na żywo zazwyczaj występują na stojąco, a niektórzy nawet tańczą podczas kodowania! Jeśli zaczniesz ćwiczyć kodowanie, siedząc za biurkiem, a następnie będziesz zmuszony, żeby stać podczas imprezy, to na pewno od razu zauważysz różnicę i będzie to dla Ciebie trudne oraz frustrujące.

Wskazówka #3 - stój podczas swoich ćwiczeń. Najprostszą metodą jest użycie do tego wysoko stojącego biurka. Jednakże, jeśli tak jak ja nie posiadasz takiego w domu, jest kilka tańszych opcji. Używam do tego deski do prasowania, która sprawuje się tutaj całkiem nieźle. Inną metodą jest postawienie kilku pudełek lub dużych książek na normalnym biurku i umieszczenie na nich Twojej klawiatury. Pamiętaj tylko o tym, aby się dobrze porozciągać przed ćwiczeniami i spróbować trochę tańczyć podczas sesji. Pamiętaj - nikt nie patrzy, więc baw się, a sprawi to, że na scenie będziesz czuł się dużo bardziej komfortowo.

Ćwicz konfigurację

Większość instrumentów wymaga przygotowania i nastrojenia, zanim będzie można na nich grać. O ile nie jesteś gwiazdą rocka z autobusem pełnym pomocników odpowiadających za sprzęt, to będziesz musiał samodzielnie skonfigurować i podłączyć swój instrument przed imprezą. Często jest to dość stresujący moment i bardzo łatwo wtedy o wystąpienie problemów. Najlepszą metodą na poradzenie sobie z tym jest włączenie procesu ustawiania i podłączania sprzętu do Twoich sesji.

Wskazówka #4 - traktuj ustawianie i podłączanie sprzętu jako bardzo ważną część Twoich ćwiczeń. Na przykład przygotuj sobie pudełko lub torbę, w której możesz trzymać swojego Raspberry Pi, klawiaturę itp. Przed każdą sesją wyjmij wszystkie części, podłącz wszystko i przejdź przez proces uruchomienia aż do momentu, gdy będziesz miał uruchomionego Sonic Pi i będziesz mógł wydawać z niego dźwięki. Kiedy skończysz ćwiczenia, poświęć odpowiednią ilość czasu na ostrożne spakowanie wszystkiego z powrotem do torby. Na początku może Ci to zajmować trochę czasu, ale po praktyce będziesz w stanie przygotować wszystko i spakować z powrotem w niewiarygodnie krótkiej chwili bez konieczności myślenia o tym, co i jak.

Eksperymentuj Muzycznie

Gdy masz już wszystko podłączone i jesteś gotowy, aby zacząć tworzyć muzykę, możesz na początku zastanowić się nad tym, jak z tym wystartować. Jednym z problemów, który dotyka wielu ludzi, jest to, że czasami mają dobry pomysł na to, jaki rodzaj dźwięków chcieliby zacząć tworzyć, ale są sfrustrowani tym, że nie wiedzą, jak je uzyskać. Niektórzy ludzie nie wiedzą nawet, jakiego rodzaju dźwięki chcieliby tworzyć! Pierwsza rzecz to nie należy się tym przejmować - jest to bardzo popularny problem i zdarza się każdemu muzykowi - nawet jeśli ćwiczą już od wielu lat. Dużo ważniejsze jest tworzenie dźwięków, które Ci się nie podobają, aniżeli nie tworzenie żadnych dźwięków.

Wskazówka #5 - postaraj się poświęcić czas na tworzenie dźwięków i muzyki, której nie lubisz. Spróbuj wykorzystać wolną chwilę na poznawanie nowych dźwięków i pomysłów. Nie przejmuj się, że mogą brzmieć kiepsko, jeśli to nie jest styl, którego szukasz. Kiedy eksperymentujesz, w taki sposób zwiększasz szanse na to, że trafisz przypadkiem na dźwięk lub kombinacje dźwięków, które pokochasz! Nawet jeśli 99% dźwięków, które stworzysz, będzie do kitu, to ten 1% może okazać się riffem lub niezłym intro do Twojego nowego kawałka. Zapomnij o rzeczach, które Ci się nie podobają, a zapamiętaj tylko te części, które Ci leżą. Tworząc muzykę za pomocą kodu, jest to nawet łatwiejsze - wystarczy nacisnąć przycisk zapisz (Save)!

Usłysz Kod

Wielu muzyków potrafi spojrzeć zapis nutowy i usłyszeć muzykę w ich głowach bez konieczności jej zagrania. Jest to bardzo przydatna umiejętność i warto ją włączyć do Twoich sesji praktykowania kodowania na żywo. Ważnym punktem jest tu umiejętność pewnego zrozumienia, jak dany kod będzie brzmiał. Nie musisz posiadać zdolności dokładnego słyszenia tego w Twojej głowie, zamiast tego bardzo przydatne jest posiadanie wiedzy o tym, czy ten kod będzie szybki, wolny, głośny, rytmiczny, melodyjny, losowy itp. Naszym ostatecznym celem jest umiejętność odwrócenia tego procesu - tak że gdy usłyszysz w swojej głowie muzykę, to będziesz umiał napisać kod, który będzie brzmiał tak samo. Może Ci to zająć sporo czasu, zanim opanujesz tę umiejętność, ale gdy już Ci się uda, będziesz w stanie improwizować na scenie i wyrażać biegle swoje pomysły.

Wskazówka #6 - napisz pewien kawałek kodu w Sonic Pi, ale nie naciskaj przycisku Run. Zamiast tego spróbuj wyobrazić sobie dźwięk, jaki on wyprodukuje. Następnie naciśnij przycisk Run, posłuchaj i zastanów się nad tym, czy miałeś rację, czy nie. Postaraj się to powtarzać, aż stanie się naturalną częścią Twojego procesu kodowania. Kiedy ćwiczę, zazwyczaj mam dobre rozeznanie w tym, jak będzie brzmiał dany kod. Mimo to wciąż zdarza mi się, że od czasu do czasu jestem zaskoczony i wtedy zatrzymuję się oraz spędzam chwilę czasu, aby zrozumieć, dlaczego się myliłem. Za każdym razem, gdy się to wydarzy, uczę się nowych sztuczek, które pozwalają mi na wyrażanie siebie na nowe sposoby.

Usuń wszelkie rozpraszacze

Dość znanym problemem podczas ćwiczeń jest możliwość rozproszenia się przez inne rzeczy. Ćwiczenie jest bardzo ciężkie i wymaga samodyscypliny niezależnie od gatunku muzycznego, jaki tworzysz - od jazzu poprzez muzykę klasyczną po EDM (ang. Electronic Dance Music - elektroniczna muzyka taneczna). Jeśli borykasz się z tym, żeby zacząć lub zrobić jakiś postęp, to często zbyt łatwo jest przełączyć się na serwis społecznościowy, zacząć grzebać po internecie, itp. Jeśli ustawisz sobie za cel 20 minut ćwiczeń dziennie, bardzo ważne jest, aby spróbować spędzić cały ten czas na byciu tak bardzo produktywnym, jak tylko się da.

Wskazówka #7 - zanim zaczniesz ćwiczyć, postaraj się usunąć wszelkie rzeczy, które Cie rozpraszają. Na przykład odłącz się od internetu, wynieś telefon do innego pokoju i spróbuj ćwiczyć w cichym miejscu, gdzie nikt i nic nie będzie Cię rozpraszać. Spróbuj skupić się na kodowaniu muzyki, a do swoich rozpraszaczy możesz wrócić, kiedy skończysz.

Prowadź dziennik ćwiczeń

Kiedy zaczniesz trenować, często zdasz sobie sprawę z tego, iż Twój umysł jest pełen wielu ekscytujących pomysłów - nowych muzycznych ścieżek, dźwięków czekających na wypróbowanie, świeżych funkcji do wpisania itd. Te myśli są na każdym kroku bardzo interesujące, przez co będziesz chciał zboczyć z wybranej ścieżki i je swobodnie wypróbować. Jest to kolejna forma rozproszenia!

Wskazówka #9 - trzymaj dziennik ćwiczeń tuż przy swojej klawiaturze. Kiedy wpadniesz na nowy ekscytujący pomysł, na chwilę przerwij swoje ćwiczenia, szybko zapisz tę ideę, a następnie zapomnij o niej i wróć do swoich ćwiczeń. Później, gdy już zakończysz ćwiczenia, możesz poświęcić odpowiednią ilość czasu, aby przemyśleć i rozwinąć swoje pomysły.

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

Postaraj się zaplanować sesję, która będzie zawierała tak wiele z tych pomysłów, jak to tylko możliwe. Postaraj się, aby były one tak bardzo fajne i zabawne, ale miej na uwadze to, że część sesji będzie ciężka i będzie sprawiała wrażenie pracy. Jednakże to wszystko będzie tego warte, gdy już uda Ci się stworzyć swój pierwszy kawałek lub będziesz miał za sobą pierwszy publiczny występ. Pamiętaj, trening czyni mistrza!


- Rozciąganie Sampli

Kiedy ludzie odkrywają Sonic Pi, jedną z pierwszych rzeczy, których się uczą, jest to, jak łatwo można z jego pomocą odtwarzać nagrane dźwięki, korzystając z funkcji sample. Na przykład możesz zagrać w pętli industrialny bęben, usłyszeć dźwięk chóru, a nawet dźwięk scratch’ującego winyla za pomocą pojedynczej linii kodu. Niezależnie od tego, wiele z tych osób nie zdaje sobie sprawy z tego, że można zmieniać prędkość, z jaką jest odtwarzany dany sampel, aby uzyskać różne bardzo dobre efekty i równocześnie zupełnie nowy poziom kontroli nad swoimi nagranymi dźwiękami. Nie czekaj więc, tylko odpal swoją kopię Sonic Pi i porozciągajmy jakieś sample!

Spowalnianie Sampli

Aby zmienić tempo odtwarzania sampla, musimy użyć opcji rate::

sample :guit_em9, rate: 1

Jeśli ustawimy wartość opcji rate: jako 1, to sampel zostanie zagrany z normalną szybkością. Jeśli chcemy zagrać go ponownie z prędkością zmniejszoną o połowę, wystarczy, że dla opcji rate: użyjemy wartości 0.5:

sample :guit_em9, rate: 0.5

Zauważ, że odciśnie to na nasz dźwięk dwa efekty. Po pierwsze sampel będzie miał niższą wysokość dźwięku, po drugie zagranie go zajmie dwa razy tyle czasu co normalnie (zerknij na pasek boczny, aby uzyskać wyjaśnienie, dlaczego tak się dzieje). Możemy nawet wybierać coraz mniejsze i mniejsze wartości, zbliżając się do 0, i tak szybkość rate: o wartości 0.25 będzie jedną czwartą prędkości, 0.1 będzie jedną dziesiątą prędkości itd. Spróbuj pobawić się z różnymi niskimi wartościami opcji rate: i zobacz, czy uda Ci się uzyskać bardzo niskie dudnienie.

Przyśpieszanie Sampli

Oprócz możliwości sprawiania, aby dźwięk był dłuższy oraz niższy za pomocą niskich wartości tempa, możemy użyć wyższego tempa w celu skrócenia dźwięku i sprawienia, by był wyższy. Tym razem spróbujmy wziąć na warsztat pętlę z bębnem. Najpierw posłuchaj, jak brzmi ten dźwięk na domyślnym tempie równym 1:

sample :loop_amen, rate: 1

A teraz spróbujmy odrobinę go przyspieszyć:

sample :loop_amen, rate: 1.5

Ha! Właśnie przeszliśmy na inny gatunek muzyczny - z oldschool’owego techno do jungle. Zauważ, że zmieniła się zarówno wysokość każdego uderzenia bębna, jak i cały rytm uległ przyśpieszeniu. Teraz spróbuj wykorzystać jeszcze wyższe tempo i zobacz, jak wysoką i jak krótką pętlę z bębnem uda Ci się stworzyć. Na przykład, jeśli użyjesz tempa o wartości 100, pętla zmieni się w kliknięcie!

Wsteczny Bieg

Teraz jestem pewien, że w tej chwili wielu z Was ma w głowie tę samą rzecz… “A co, jeśli użyjesz minusowej liczby dla tempa?”. Ciekawe pytanie! Pomyślmy zatem o tym przez chwilkę. Jeśli nasza wartość rate: oznacza prędkość, z którą odtwarzany jest dany sampel, czyli 1 - normalna szybkość, pod 2 kryje się podwójna, 0.5 oznacza tempo mniejsze o połowę, to wartość -1 spowoduje, iż dźwięk zostanie zagrany od końca! Wypróbujmy to na “snare”, lecz rozpoczynając od normalnego tempa:

sample :elec_filt_snare, rate: 1

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

sample :elec_filt_snare, rate: -1

Oczywiście możesz zagrać go od końca dwa razy szybciej z wartością -2 albo dwa razy wolniej za pomocą -0.5. Obeznaj się z różnymi minusowymi tempami oraz baw się dobrze! Ten efekt brzmi całkiem zabawnie z samplem :misc_burp!

Próbki, Tempo i Wysokość [Panel Boczny]

Jednym z efektów zmiany tempa sampli jest to, iż szybsze wartości oznaczają wyższą wysokość dźwięku i na odwrót - wolniejsze zaś niższą. Słyszysz go prawdopodobnie codziennie w swoim życiu - wtedy, gdy jeździsz na rowerze lub przechodzisz obok służb na sygnale. Im bliżej dźwięku, tym wysokość jest wyższa, im dalej zaś, tym jest niższa. Nazywa się to efektem Dopplera. Dlaczego tak się dzieje?

Rozważmy prosty sygnał dźwiękowy reprezentowany przez falę sinusoidalną. Jeżeli użyjemy oscyloskopu, by rozrysować dźwięk, zobaczymy coś podobnego do Figury A. Dźwięk z wyższą oktawą reprezentuje Figura B, a z niższą - Figura C. Zauważ to, iż fale wyższych nut są bardziej ściśle oraz niższych - bardziej rozłożone.

Sampel sygnału jest niczym innym jak wiele liczb (x, y, współrzędne), które rozrysowane na grafie odrysowują pierwotne krzywe. Spójrz na figurę D, gdzie każde koło reprezentuje współrzędne. By zamienić je ponownie w dźwięk, komputer pracuje przy każdej wartości x i wysyła odpowiednie wartości y do głośników. Magią jest to, iż tempo, nad którym pracuje maszyna poprzez numery x, nie musi być takie same jak tempo, z którym zostały nagrane. Używając innych słów - przestrzeń (reprezentująca ilość czasu) między każdym kołem może zostać rozciągnięta lub ściśnięta. Więc jeśli komputer przechodzi przez wartość x szybciej niż za pomocą oryginalnego tempa, wpłynie to na efekt zgniatania kół ze sobą, czego rezultatem będzie wyżej brzmiący sygnał. To także uczyni go krótszym, poprzez szybszą pracę przez koła. Zostało to pokazane na Figurze E.

Wreszcie ostatnią rzeczą potrzebną do zrozumienia tego wszystkiego jest matematyk o imieniu Fourier, który udowodnił, że każdy dźwięk to tak naprawdę wiele fal sinusoidalnych połączonych w jedną całość. W związku z tym ściśnięcie i rozciągnięcie każdego nagranego sygnału oznacza wykonanie tej czynności na wielu falach sinusoidalnych - w tym samym czasie i w tej samej formie.

Funkcja Pitch Bending

Jak widzimy, używanie szybszego tempa powoduje, iż dźwięk będzie miał wyższą wysokość i na odwrót - niższe tempo = niższa wysokość. Bardzo prosta i użyteczna sztuczka dotyczy tego, iż wysokość większa o oktawę jest rezultatem podwójnego tempa i na odwrót - wysokość mniejsza o oktawę jest rezultatem dwa razy mniejszego tempa. Melodyjne sample grane jeden obok drugiego brzmią całkiem fajnie:

sample :bass_trance_c, rate: 1
sample :bass_trance_c, rate: 2
sample :bass_trance_c, rate: 0.5

Jednakże co w przypadku, gdy po prostu chcemy zmienić tempo tak, aby wysokość zwiększyła się o jeden półton (jedną nutę na pianinie)? Sonic Pi sprawia, iż jest to banalnie proste - wystarczy użyć parametru rpitch::

sample :bass_trance_c
sample :bass_trance_c, rpitch: 3
sample :bass_trance_c, rpitch: 7

Jeśli spojrzysz na logi po prawej stronie, to zauważysz, iż rpitch: trójki aktualnie odpowiada tempie o wartości 1.1892 i rpitch: siódemki odpowiada tempie o wartości 1.4983. Wreszcie możemy także łączyć ze sobą parametry rate: oraz rpitch::

sample :ambi_choir, rate: 0.25, rpitch: 3
sleep 3
sample :ambi_choir, rate: 0.25, rpitch: 5
sleep 2
sample :ambi_choir, rate: 0.25, rpitch: 6
sleep 1
sample :ambi_choir, rate: 0.25, rpitch: 1

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

Spójrzmy na zwyczajny kawałek, który łączy te pomysły. Skopiuj go do wolnego bufora Sonic Pi, naciśnij play, wsłuchaj się przez chwilę oraz użyj jako punktu startowego dla Twojego własnego kodu. Zobacz, jak zabawna jest kontrola tempa odtwarzanych sampli. Jako ćwiczenie spróbuj nagrać Twoje własne dźwięki i pobaw się z wartością parametru rate:, aby zobaczyć, jak szalone kombinacje możesz stworzyć.

live_loop :beats do
  sample :guit_em9, rate: [0.25, 0.5, -1].choose, amp: 2
  sample :loop_garzul, rate: [0.5, 1].choose
  sleep 8
end
 
live_loop :melody do
  oct = [-1, 1, 2].choose * 12
  with_fx :reverb, amp: 2 do
    16.times do
      n = (scale 0, :minor_pentatonic).choose
      sample :bass_voxy_hit_c, rpitch: n + 4 + oct
      sleep 0.125
    end
  end
end

- Synteza Addytywna

Witaj w pierwszym artykule krótkiej serii na temat użytkowania Sonic Pi w designie dźwięku. Ruszymy w szybką turę różnych technik, z których możesz skorzystać, aby stworzyć własne, unikalne dźwięki. Pierwszą z nich będzie coś, co nosi nazwę syntezy addytywnej. To może brzmieć skomplikowanie, ale jeśli wyjaśnimy po kolei każde słowo, znacznie wręcz wyskoczy samoistnie. Słowo “synteza” oznacza tworzenie muzyki, a “addytywna” - kombinację rzeczy. Addytywna synteza to nic zatem bardziej skomplikowanego jak łączenie istniejących dźwięków, aby stworzyć z nich nowe. Ta technika pochodzi z bardzo dawnych czasów, przykładowo organy w średniowieczu miały wiele różnie brzmiących piszczałek, które można było aktywować lub dezaktywować z pauzami. Wyciągając, ‘dodawano je do miksu’, co powodowało, iż wytworzony dźwięk brzmiał bardziej bogato i złożono. Spójrzmy teraz na to, jak możemy te pauzy wyciągać za pomocą Sonic Pi.

Proste Kompozycje

Rozpocznijmy więc od najbardziej podstawowego dźwięku, który możesz tutaj znaleźć - prostej czystotonowej fali sinusoidalnej:

synth :sine, note: :d3

Teraz spójrzmy na brzmienie w połączeniu z falą kwadratową:

synth :sine, note: :d3
synth :square, note: :d3

Zauważ, jak one się łączą, tworząc całkowicie nowe i bogate dźwięki. Jasne jest dla nas to, iż nie musimy się zatrzymywać na tym etapie - możemy dodać tyle dźwięków, ile tak naprawdę potrzebujemy. Jednak musimy być ostrożni podczas ich łączenia, gdyż to jest tak, jak z łączeniem nowych kolorów - kiedy dodamy ich za dużo, wynikiem będzie brzydki brązowy. Ta sama rzecz dzieje się z dźwiękami - pakowanie za dużej ich liczby do jednego pola spowoduje zamianę w coś niezbyt “zjadliwego”.

Mieszanie

Dodajmy coś, aby dźwięk brzmiał trochę jaśniej. Możemy użyć fali trójkątnej z wyższą oktawą (dla tego wysokiego, jasnego dźwięku), ale tylko grając z amplitudą o wartości 0.4. To tylko dodaje coś ekstra zamiast całkowicie zmienić znaczenie:

synth :sine, note: :d3
synth :square, note: :d3
synth :tri, note: :d4, amp: 0.4

Teraz spróbuj stworzyć swoje własne dźwięki poprzez połączenie dwóch lub większej ilości syntezatorów z różnymi oktawami i aplitudami. Także zauważ to, jak możesz się bawić każdymi ustawieniami parametrów syntezatorów, których źródło muzyki jest wcześniej miksowane w większą ilość ich kombinacji.

Strojenie

Łącząc różne syntezatory, używaliśmy tej samej wysokości lub zmienionej oktawy przez całą naszą drogę. Jak może to zabrzmieć, jeżeli nie będziemy się trzymać tego drugiego parametru, a właśnie wybierzemy troszeczkę wyższą lub niższą nutę? Spróbujmy tego:

detune = 0.7
synth :square, note: :e3
synth :square, note: :e3 + detune

Jeśli rozstroimy nasze fale kwadratowe przez 0.7 nuty usłyszymy coś, co nie brzmi zbyt dobrze, a mówiąc poprawnie - otrzymamy ‘złą’ nutę. Jednakże jeśli przybliżmy się do 0, to dźwięk będzie bardziej i bardziej nieczysty - jak wysokość dźwięku dwóch fal zbliżających się do siebie. Wypróbuj tego! Zmień wartość parametru detune: z 0.7 na 0.5 i wsłuchaj się w nowy dźwięk. Skorzystaj z 0.2, 0.1, 0.05, 0. Za każdym razem, gdy zmieniasz wartość, poświęć chwilę na wysłuchanie i zobacz, czy możesz usłyszeć to, jak dźwięk się zmienia. Zauważ, że niskie rozstrojenie (np. 0.1) wytwarza naprawdę niezły ‘gęsty’ dźwięk z innymi wysokościami każdego z nich - zmieniającymi się w ciekawy, często zaskakujący sposób.

Niektóre z wbudowanych syntezatorów obsługują już opcję rozstrojenia, przez co można z niej korzystać w jednym z nich. Spróbuj zagrać z parametrem detune: - :dsaw, :dpulse oraz :dtri.

Kształtowanie Amplitudy

Kolejnym sposobem na tworzenie naszych dźwięków jest użycie innej obwiedni i ustawień dla każdego wyzwalacza syntezatora. Przykładowo pozwoli Ci to na wymyślenie aspektów perkusyjnej muzyki oraz pierścieni na okres czasu.

detune = 0.1
synth :square, note: :e1, release: 2
synth :square, note: :e1 + detune, amp: 2, release: 2
synth :gnoise, release: 2, amp: 1, cutoff: 60
synth :gnoise, release: 0.5, amp: 1, cutoff: 100
synth :noise, release: 0.2, amp: 1, cutoff: 90

W powyższym przykładzie zmiksowałem hałaśliwy, perkusyjny element wraz z trwałym dudnieniem w tle. Zostało to osiągnięte poprzez użycie dwóch głośnych syntezatorów: jednego ze środkowymi wartościami odcięcia (90 i 100 i krótkim czasem wyzwolenia) oraz drugiego z niską wartością odcięcia (co powoduje, że dźwięk jest mniej chrupki, a także i bardziej burczący).

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

Połączmy wszystkie te techniki, by zobaczyć, jak możemy użyć syntezy addytywnej w celu ponownego stworzenia podstawowego dźwięku dzwonka. Podzieliłem ten przykład na cztery sekcje - pierwszy to ‘uderzenie’, który jest początkiem części dźwięku, zatem używa krótkiej obwiedni (przykładowo release: o wartości około 0.1). Następna z nich to długa sekcja dzwonienia, gdzie używam czystego dźwięku fali sinusoidalnej. Zauważ to, jak często zwiększam nutę w szerokim zakresie 12 oraz 24, które są numerami nut w jednej i drugiej oktawie. Połączyłem także w parę niskie fale sinusoidalne, aby otrzymać trochę basu i głębi. W końcu skorzystałem z define, by ścisnąć mój kod w funkcję służącą do zagrania melodii. Spróbuj stworzyć swoją własną oraz pobaw się z zawartością :bell do chwili, gdy otrzymasz swój własny szalony dźwięk!

Zagrajmy melodię z naszym nowym dzwonkiem!

- Synteza Subtraktywna

Oto drugi z serii artykułów poświęconych designowi dźwięku w Sonic Pi! W poprzednim miesiącu rzuciliśmy okiem na syntezę addytywną, dzięki której odkryliśmy, jak łatwe jest granie wielu dźwięków w tym samym czasie do stworzenia różnorakich kombinacji. Na przykład mogliśmy połączyć różnie brzmiące syntezatory, a nawet te same z nich w różnych wysokościach dźwięku, by zbudować nowy, bardziej złożony dźwięk z prostych składników. W tym miesiącu zajmiemy się świeżą techniką zwaną zwyczajnie syntezą subtraktywną, która bierze złożone dźwięki oraz usuwa niektóre części z nich do utworzenia czegoś całkowicie nowego. Ten sposób jest powiązany z dźwiękiem analogowych syntezatorów z lat 60. oraz 70., ale również z wczesnym renesansem, idąc poprzez popularnych standardy takie jak Eurorack.

Pomimo iż to brzmi jak szczególnie skomplikowana i zaawansowana technika, Sonic Pi sprawia, że jest to zaskakująco proste oraz łatwe - zanurkujmy więc!

Złożone Źródło Sygnału

Dźwięk, który ma pracować dobrze z syntezą subtraktywną, zazwyczaj musi być dość bogaty i ciekawy. To nie oznacza jednak, że potrzebujemy czegoś ogromnie złożonego - w rzeczywistości standardowe fale :square lub :saw w zupełności wystarczą:

synth :saw, note: :e2, release: 4

Zauważ to, iż dźwięk jest całkiem intrygujący oraz zawiera wiele różnych częstotliwości powyżej :e2 (drugi klawisz E na fortepianie), które dodaje się, by utworzyć barwę dźwięku. Jeżeli to na razie nie ma dla Ciebie większego sensu, spróbuj porównać go z :beep:

synth :beep, note: :e2, release: 4

Ze względu na to, iż syntezator :beep jest po prostu falą sinusoidalną, usłyszysz o wiele czystszy ton tylko na :e2 oraz żaden z tych chrupiących/brzęczących dźwięków, z którymi miałeś do czynienia w :saw. To jest brzęczenie i odmiana z czystej fali sinusoidalnej, gdzie możemy grać, kiedy używamy syntezy subtraktywnej.

Filtry

Gdy mamy już nasze pierwotne źródło sygnału, następnym krokiem będzie przejście przez filtr pewnego typu, który zmodyfikuje dźwięk za pomocą usunięcia lub zredukowania jakiejś części. Jeden z najczęstszych filtrów używanych w syntezie subtraktywnej nazywany jest filtrem dolnoprzepustowym. Pozwala on przejść wszystkim niższym częściom dźwięku, lecz redukując przy tym także wyższe. Sonic Pi posiada potężny, ale prosty w obsłudze system FX, który zawiera filtr dolnoprzepustowy o nazwie :lpf. Zabawmy się:

with_fx :lpf, cutoff: 100 do
  synth :saw, note: :e2, release: 4
end

Jeśli wsłuchasz się uważnie, usłyszysz, jak parę z tych brzęczących i chrupiących dźwięków zostało usuniętych. W rzeczywistości wszystkie częstotliwości dźwięku powyżej nuty 100 zostały zredukowane lub usunięte i tylko te niższe są w nim obecne. Spróbuj zamienić parametr cutoff: do niższych nut, przykładowo 70, a następnie 50, by je porównać.

Oczywiście parametr :lpf nie jest jedynym filtrem, którego możesz użyć do kontrolowania źródłem sygnału. Kolejnym równie ważnym FX jest filtr górnoprzepustowy określony jako :hpf. Robi dokładnie to, co :lpf, tylko odwrotnie - pozwala on przejść wszystkim wyższym częściom dźwięku, redukując lub usuwając niższe.

with_fx :hpf, cutoff: 90 do
  synth :saw, note: :e2, release: 4
end

Zauważ, jak dźwięk brzmi teraz bardziej brzęcząco i chrupiąco, a to wszystko z tego powodu, iż niskie częstotliwości zostały usunięte. Pobaw się z wartością cutoff i zobacz, jak niskie wartości pozwalają istnieć oryginalnym częściom basu źródła sygnału oraz jak wysokie wartości zwiększają brzękliwość oraz ciszę.

Low Pass Filter

Filtr dolnoprzepustowy jest ważną częścią narzędzi każdej syntezy subtraktywnej - warto zatem zanurzyć się głębiej, by zobaczyć, jak on działa. Ten diagram pokazuje tę samą falę dźwięku (syntezator :prophet) z różnymi wartościami filtrowania. U góry, w sekcji A, pokazuje falę dźwiękową bez filtrowania. Zauważ, że fala ta jest bardzo punktowa i zawiera wiele ostrych krawędzi. To właśnie one produkują tę chrupiącą/brzęczącą część dźwięku. Sekcja B pokazuje wszystkie filtry dolnoprzepustowe w akcji - fala jest mniej punktowa i bardziej zaokrąglona niż powyżej. Oznacza to, iż jeśli dźwięk posiada mniejszą częstotliwość, daje on bardziej ładne oraz zaokrąglone linie. Sekcja C zawiera filtr dolnoprzepustowy z dość niską wartością funkcji cutoff - im większe częstotliwości zostały usunięte z sygnału, tym skutkuje to bardziej łagodną, zaokrągloną falą. Na końcu rzuć okiem na wielkość formy fali reprezentującej amplitudę, zmniejszającą się podczas przechodzenia od A do C. Synteza subtraktywna działa poprzez usuwanie części sygnału, które oznaczają, iż ogólna amplituda jest redukowana wraz z zwiększaniem się liczby filtrowania.

Modulacja Filtra

Do tej pory tworzyliśmy dość statyczne dźwięki. Używając innych słów - nie zmieniał się on podczas całej drogi jej trwania. Często możesz chcieć trochę ruchu w dźwięku, aby nadać barwie trochę życia. Aby to osiągnąć, możesz skorzystać z filtra modulacji - zmieniając jego ustawienia poprzez czas. Na szczęście Sonic Pi oferuje potężne narzędzie służące do manipulowania parametrami FX. Przykładowo możesz ustawić czas ślizgu dla każdego modulowanego parametru, aby zdefiniować, jak długo powinien on zająć z obecnej wartości do docelowej:

with_fx :lpf, cutoff: 50 do |fx|
  control fx, cutoff_slide: 3, cutoff: 130
  synth :prophet, note: :e2, sustain: 3.5
end

Rzućmy okiem na to, co się tutaj dzieje. Początkowo rozpoczynamy funkcją :lpf jako normalną z początkowym cutoff: o bardzo niskim parametrze 20. Jednakże pierwsza linia kończy się także dziwnym |fx| na końcu. Jest to opcjonalna część składni with_fx, która umożliwia nam na bezpośrednie nazwanie i kontrolowanie syntezatora FX. Linia 2 robi to oraz kontroluje FX, by ustawić parametr cutoff_slide: na 4 i nowy obiekt docelowy cutoff: na 130. FX rozpocznie prześlizg cutoff: z wartości 50 na 130 przez okres 3 uderzeń. Na końcu wyzwalamy sygnał źródłowy syntezatora, przez co możemy usłyszeć efekt modulowanego filtra dolnoprzepustowego.

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

Do czynienia mamy z bardzo podstawowym zjadaczem, co staje się możliwe, gdy używasz filtrów do edycji i zmiany źródła dźwięku. Spróbuj zagrać z wieloma innymi wbudowanymi FX w Sonic Pi, by zobaczyć, jak wiele szalonych dźwięków możesz zaprojektować. Jeżeli brzmi on zbyt statycznie, pamiętaj o tym, iż możesz modulować wybrane opcje, by utworzyć trochę ruchu.

Zakończmy, projektując funkcję, która zagra nowy dźwięk utworzony za pomocą syntezy substraktywnej. Sprawdź, czy możesz ogarnąć to, co się tutaj dzieje - a dla zaawansowanych Czytelników Sonic Pi - zobacz, czy możesz sprawdzić, dlaczego owinąłem wszystko w środku połączenia do at (proszę wysłać rozwiązania do @samaaron na Twitterze w języku angielskim).

define :subt_synth do |note, sus|
  at do
    with_fx :lpf, cutoff: 40, amp: 2 do |fx|
      control fx, cutoff_slide: 6, cutoff: 100
      synth :prophet, note: note, sustain: sus
    end
    with_fx :hpf, cutoff_slide: 0.01 do |fx|
      synth :dsaw, note: note + 12, sustain: sus
      (sus * 8).times do
        control fx, cutoff: rrand(70, 110)
        sleep 0.125
      end
    end
  end
end
subt_synth :e1, 8
sleep 8
subt_synth :e1 - 4, 8

- Creative coding in the classroom with Sonic Pi

(This article was published in issue 9 of the Hello World Magazine)

Code is one of the most creative media that humans have created. The initially obscure symbols of parentheses and lambdas are not just deeply rooted in science and mathematics, they are the closest we have managed to get to casting the same kind of magical spells as Gandalf and Harry Potter. I believe that this provides a powerful means of engagement in our learning spaces. Through the magic of code we are able to conjure up individually meaningful stories and learning experiences.

We are surrounded by magical experiences. From the sleight of hand of a stage magician making the ball disappear into thin air, to the wonder of seeing your favourite band perform on a big stage. It is these “wow” moments that inspire us to pick up a magic book and learn the French Drop or to start jamming power chords on an old guitar. How might we create similarly deep and lasting senses of wonder that will motivate people to practice and learn the fundamentals of programming?

Musical Engines and Notation

The histories of music and computers have been intricately woven together since the inception of computing machines, or “engines” as Charles Babbage’s powerful analytical engine was called. Back in 1842 the Mathematician Ada Lovelace, who worked very closely with Babbage, saw the creative potential of these engines. Whilst these first engines had originally been designed to accurately solve hard maths problems, Ada dreamt about making music with them:

”..the engine might compose elaborate and scientific pieces of music of any degree of complexity or extent.” Ada Lovelace, 1842.

Of course, today in 2019 much of our music, regardless of genre, has either been composed, produced or mastered with a digital computer. Ada’s dream came true. It is even possible to trace the history back even further. If you see coding as the art of writing sequences of special symbols that instruct a computer to do specific things, then musical composition is a very similar practice. In Western music, the symbols are black dots positioned on a stave of lines that tell the musician which notes to play and when. Intriguingly, if we trace the roots of Western music notation back to the Italian Benedictine monk, Guido d’Arezzo, we find that the dots and lines system that modern orchestras use is just one of a number of notation systems he worked on. Some of the others were much closer to what we might now see as code.

Pobierz (Get)

Sonic Pi Performances

Kodowanie na żywo

Sonic Pi has been used to perform in a wide range of venues such as school halls, nightclubs, outdoor stages at musical festivals, college chapels and prestigious music venues. For example the amazing Convo project which brought 1000 children together in the Royal Albert Hall to perform an ambitious new composition by composer Charlotte Harding. The piece was written for traditional instruments, choirs, percussion and Sonic Pi code. The pop-artist Jylda also performed with Sonic Pi in the Sage Gateshead for the Thinking Digital Conference, where she created a unique live-coded improvised remix of her song Reeled.

Sonic Pi in the Royal Albert Hall Sonic Pi used as one of the instruments as part of Convo at the Royal Albert Hall. Photo credit: Pete Jones.

Live coding in the classroom

Sonic Pi is a code-based music creation and performance tool that builds on all of these ideas. Unlike the majority of computing education software, it is both simple enough to use for education and also powerful enough for professionals. It has been used to perform in international music festivals, used to compose in a range of styles from classical, EDM and heavy metal, and was even reviewed in the Rolling Stone magazine. It has a diverse community of over 1.5 million live coders with a variety of backgrounds all learning and sharing their ideas and thoughts through the medium of code. It is free to download for Mac, PC and Raspberry Pi and includes a friendly tutorial that assumes you know nothing about either code or music.

Sonic Pi was initially conceived as a response to the UK’s newly released Computing curriculum in 2014. The goal was to find a motivating and fun way to teach the fundamentals of programming. It turns out that there is a lot in common and it’s huge fun to explain sequencing as melody, iteration as rhythm, conditionals as musical variety. I developed the initial designs and first iterations of the platform with Carrie Anne Philbin, who brought a teacher’s perspective to the project. Since then, Sonic Pi has undergone iterative improvements thanks to the feedback gained from observing learners and collaborating directly with educators in the classroom. A core design philosophy was to never add a feature that couldn’t be easily taught to a 10 year old child. This meant that most ideas had to be heavily refined and reworked until they were simple enough. Making things simple whilst keeping them powerful continues to be the hardest part of the project.

In order to provide the magical motivation, Sonic Pi’s design was never limited to a pure focus on education. Ideally there would be famous musicians and performers using Sonic Pi as a standard instrument alongside guitars, drums, vocals, synths, violins, etc. These performers would then act as motivational role models demonstrating the creative potential of code. For this to be possible sufficient focus and effort therefore had to be placed on making it a powerful instrument whilst still keeping it simple enough for 10 year olds to pick up. In addition to educators, I also worked directly with a variety of different artists in classrooms, art galleries, studios and venues in the early stages of Sonic Pi’s development. This provided essential feedback which enabled Sonic Pi to grow and ultimately flourish as a tool for creative expression.

There were a number of exciting and unexpected side effects of this dual focus on education and professional musicians. Many of the features are beneficial to both groups. For example, a lot of effort has been put into making error messages more friendly and useful (rather than being a huge complicated mess of jargon). This turns out to be very useful when you write a bug while performing in front of thousands of people. Additionally, functionality such as playing studio quality audio samples, adding audio effects, providing access to live audio from the microphone all turn out to make the learning experience more fun, rewarding and ultimately meaningful.

The Sonic Pi community continues to grow and share amazing code compositions, lesson plans, musical algorithms, and much more. Much of this happens on our friendly forum in_thread (in-thread.sonic-pi.net) which is home to a very diverse group of people that includes educators, musicians, programmers, artists and makers. It is a real joy to see people learn to use code to express themselves in new ways and for that in turn to inspire others to do the same.

- Some fun capabilities

From a Computer Science perspective, Sonic Pi provides you with the building blocks to teach you the basics as found in the UK’s curriculum such as sequencing, iteration, conditionals, functions, data structures, algorithms, etc. However, it also builds on a number of important and relevant concepts which have become adopted in mainstream industry such as concurrency, events, pattern matching, distributed computing and determinism - all whilst keeping things simple enough to explain to a 10 year old child.

Pobierz (Get)

play 70

A melody can be constructed with one more command, sleep:

play 72
sleep 0.5
play 75
sleep 0.5
play 79

In this example, we play the note 70 (roughly the 70th note on a piano), wait for 1 second, play note 72, wait for half a second and then play note 75. What’s interesting here is that with just two commands we have access to pretty much all of Western notation (which notes to play and when) and learners can code any melody they’ve ever heard. This leads to huge variety in expressive outcomes whilst focussing on the same computing concept: sequencing in this case.

Taking ideas from the professional music world, we can also play back any recorded sound. Sonic Pi can play any audio file on your computer but also has a number of sounds built-in to make things easy to get started:

sample :loop_amen

This code will play back the drum break which was a pillarstone to early hip-hop, Drum and Bass and Jungle. For example, a number of early hip-hop artists played this drum break back at half speed to give it a more laid-back feeling:

sample :loop_amen, rate: 0.5

In the 90s a number of music scenes burst out of new technology which enabled artists to take drum breaks like this apart and reassemble in a different order. For example:

sample :loop_amen

rand


- 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.


- Korzystanie ze Skrótów Klawiszowych

Sonic Pi jest 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 wtedy, gdy będziesz występować 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. Potrafię pisać na klawiaturze bezwzrokowo (Tobie też polecam się tego nauczyć) i czuję frustrację za każdym razem, kiedy tylko muszę sięgnąć po myszkę, ponieważ to spowalnia moją pracę. W związku z powyższym używam wszystkich tych skrótów w kółko!

Ponadto, jeśli nauczysz się skrótów, zyskasz umiejętność korzystania 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ęściej. 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 z nich 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 trzy 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 Windowsem 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 Windows, 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 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ć. Działają one również bardzo dobrze, kiedy już nauczysz się pisać na klawiaturze bezwzrokowo, jako że używają standardowych liter i nie wymagają od Ciebie, abyś sięgał ręką do myszki lub klawiszy ze strzałkami na Twojej klawiaturze.

Możesz przenieść się do początku linii, naciskają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ąć się 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 aktualnie znajduje się kursor aż do końca linii, używając skrótu C-k.

Elegancki 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.


- Ściągawka Skrótów Klawiszowych

Poniżej dostępne jest podsumowanie najważniejszych skrótów dostępnych w Sonic Pi. Przejrzyj proszę rozdział 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):

C-a oznacza: przytrzymaj klawisz Control, następnie naciśnij klawisz a tak, żeby przez chwilę oba były jednocześnie naciśnięte, po czym je puść. M-r oznacza: przytrzymaj klawisz Meta i następnie naciśnij klawisz r tak, żeby przez chwilę oba były naciśnięte jednocześnie, po czym je puść. S-M-z oznacza: naciśnij i przytrzymaj klawisz Shift, następnie naciśnij i przytrzymaj klawisz Meta i na końcu dołóż do tej kombinacji w tym samym czasie klawisz z, następnie puść wszystkie klawisze. C-M-f oznacza: naciśnij i przytrzymaj klawisz Control, potem naciśnij i przytrzymaj klawisz Meta, po czym na końcu naciśnij do tego jeszcze klawisz f i puść wszystkie klawisze.

Podstawowe Manipulowanie Aplikacją

M-r - Uruchom kod (przycisk Run) M-s - Zatrzymaj kod (przycisk Stop) M-i - Otwórz/Zamknij System Pomocy M-p - Otwórz/Zamknij Ustawienia M-{ - Przejdź do buforu po lewej stronie M-} - Przejdź do buforu po prawej stronie M-+ - Zwiększ rozmiar czcionki w aktualnym buforze M-- - Zmniejsz rozmiar czczionki w aktualnym buforze

Zaznaczanie/Kopiowanie/Wklejanie

M-a - Zaznacz wszystko M-c - Skopiuj zaznaczony obszar, aby móc go wkleić do bufora w innym miejscu M-] - Skopiuj zaznaczony obszar, aby móc go wkleić do bufora w innym miejscu M-x - Wytnij zaznaczony obszar, aby móc wkleić go do bufora w innym miejscu C-] - Wytnij zaznaczony obszar, aby móc wkleić go do bufora w innym miejscu C-k - Wytnij tekst od aktualnej pozycji kursora do końca linii M-v - Wklej zawartość schowka do aktualnego bufora C-y - Wklej zawartość schowka do aktualnego bufora C-SPACE - Ustaw punkt zaznaczenia. Następnie nawiguj po tekście, aby podświetlić tekst do zaznaczenia. Użyj C-g aby wyłączyć/usunąć zaznaczenie.

Manipulacja Tekstu

M-m - Wyrównaj cały tekst w buforze Tab - Popraw wyrównianie/zaznaczenie aktualnej liczby lub pokaż podpowiedzi C-l - Wyśrodkuj edytor M-/ - Dodaj lub usuń znak komentarza (#) na początku aktualnie wybranej (lub wybranych) linii kodu C-t - Transponuj/zamień znaki M-u - Konwertuj następne słowo (lub zaznaczenie) do wielkich liter. M-l - Konwertuj następne słowo (lub zaznaczenie) do małych liter.

Nawigacja

C-a - Przenieś kursor do początku linii C-e - Przenieś kursor na koniec linii C-p - Przenieś kursor do poprzedniej linii C-n - Przenieś kursor do następnej linii C-f - Przenieś kursor o jeden znak do przodu (w prawo) C-b - Przenieś kursor o jeden znak do tyłu (w lewo) M-f - Przenieś kursor do przodu (w prawo) o jedno słowo M-b - Przenieś kursor do tyłu (w lewo) o jedno słowo C-M-n - Przenieś aktualną linie lub zaznaczenie w dół C-M-p - Przenieś aktualną linię lub zaznaczenie do góry S-M-u - Przenieś się do góry o 10 linii S-M-d - Przenieś się w dół o 10 linii M-< - Przenieś się na początek bufora M-> - Przenieś się na koniec bufora

Usuwanie

C-h - Usuń poprzedni znak C-d - Usuń kolejny znak

Zaawansowane Funkcje Edytora

C-i - Pokaż dokumentację dla słowa, na którym znajduje się aktualnie kursor M-z - Wstecz (cofnij zmianę) S-M-z - Redo (powtórz zmianę) C-g - Ucieczka (anulowanie) S-M-f - Otwórz/Zamknij tryb pełnoekranowy S-M-b - Pokaż/Schowaj przyciski S-M-l - Pokaż/Schowaj panel logowania S-M-m - Przełączanie pomiędzy trybem jasnym i ciemnym S-M-s - Zapisz zawartość bufora do pliku S-M-o - Wczytaj zawartość z wybranego pliku do bufora


- 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żywać 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 i 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. Będzie miało ono rozszerzenie WAV, który może być bardzo łatwo zedytowany i skonwertowany do formatu MP3 przez jeden z wielu darmowych programów (spróbuj na przykład aplikacji 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ć.


- 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 telewizora 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ół

Don’t just play on your own - form a live coding band! It’s a lot of fun jamming with others. One person could do beats, another ambient background, etc. Use the live_audio functionality to combine code with traditional instruments such as a guitar or a microphone.

See what interesting combinations of sounds you can create with code.

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 źródł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.


- 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ż tego dokonasz, 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 się 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 w obrębie żywych pętli tworzonych z wykorzystaniem polecenia live_loop. Oznacza to, że jest możliwa 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 wtedy, gdy masz zamiar wykorzystać możliwości dźwiękowe Sonic Pi.

Wspierane API

Na ten moment Sonic Pi wspiera podstawowe bloki oraz manipulacje graczy, które są 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:

Wyświetlanie wiadomości czatowych Ustawianie pozycji gracza Odczyt pozycji gracza Ustawianie typu bloku na podanych współrzędnych Zabieranie typu bloku na podanych współrzędnych

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

Wyświetlanie wiadomości czatowych

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 sprawdź, czy udało Ci się wejść do świata Minecraft i czy 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 oknie Minecraft. Gratulacje, właśnie napisałeś swój pierwszy kod w Minecraft! Prawda, to było proste.

Ustawianie pozycji gracza

Teraz spróbujmy odrobiny magii. Spróbujmy przeteleportować nas w inne miejsce! Sprawdź następujący kod:

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. Więc co to za liczby: 50, 50, 50? Są to współrzędne miejsca, do którego starasz się przeteleportować. Poświęćmy krótką chwilę, aby 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 oznaczają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 trzech cyfr:

Jak daleko od prawej do lewej w naszym świecie - x Jak daleko od przodu do tyłu w naszym świecie - z Jak wysoko znajdujemy się w naszym świecie - y

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, a następnie przełącz się do Sonic Pi. Teraz wpisz następującą linijkę:

puts mc_location

Kiedy uruchomisz przycisk Run, zobaczysz współrzędne Twojego aktualnego położenia wyświetlone w panelu z logami. Zapisz je, a 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ć 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 one działają, programowanie z API oferowanym przez Minecraft będzie dla Ciebie bułką z masłem.

Zbudujmy Coś!

Teraz gdy już wiesz, w jaki sposób znaleźć aktualną pozycję oraz w jaki sposób 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

Haha, to naprawdę była bułka z masłem! Aby obejrzeć swoje dzieło, po prostu przeteleportuj się niedaleko i zerknij na nie:

mc_teleport 35, 50, 60

Teraz obróć się dookoła, a Twoim oczom ukaże się utworzony przez Ciebie 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ąc 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 oddasz się szaleństwu programowania z Minecraft Pi, być może zainteresuje Cię 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