Witaj w Sonic Pi. Mam nadzieję, że jesteś podekscytowany możliwością rozpoczęcia tworzenia zwariowanych dźwięków tak samo, jak ja jestem podekcytowany tym, że mogę Ci to pokazać. To będzie naprawdę świetna zabawa, podczas której nauczysz się wszystkiego o muzyce, syntezie, programowaniu, kompozycji, wydajności i 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 pod nikiem @samaaron na Twitterze 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 i pomysły dotyczące tego jak można ulepszyć Sonic Pi - będę wdzięczny za ich przekazanie - każda informacja zwrotna jest bardzo pomocna. Nigdy nie wiadomo, być może twój pomysł stanie się kolejną epicką funkcją, która wzbogaci Sonic Pi!
Ten samouczek został podzielony na sekcje, które są pogrupowane wg kategorii. Pomimo, że napisałem go w taki sposób, aby umożliwiał łatwą naukę od początku do końca, to nic nie szkodzi na przeszkodzie abyś abyś po prostu zaczął czytać dowolną z sekcji - taką która wydaje Ci się odpowiednia dla Ciebie. Jeśli uważasz, że czegoś tutaj brakuje daj mi o tym znać, rozważę dołożenie tego do kolejnej wersji.
Jeszcze jedna rzecz na koniec. Oglądanie innych osób kodujących na żywo jest naprawdę bardzo dobrym sposobem nauki. Regularnie nadaję na żywo na moim kanale livecoding.tv/samaaron, możesz więc wpaść, powiedzieć mi cześć i zadać mi dowolne pytanie :-)
Dobra, czas zacząć przygodę…
Jednym z najbardziej ekscytujących aspektów Sonic Pi jest to, że pozwala Ci na pisanie i modyfikację kodu na żywo aby tworzyć muzykę w czasie rzeczywistym, tak samo jak w momencie gdy grasz na żywo na gitarze. Oznacza to, że dzięki odpowiednim ćwiczeniom możesz wykorzytać Sonic Pi do koncertów przed publicznością na żywo.
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 Live Coding (kodowanie na żywo). 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ść…
Zacznijmy od skopiowania następującego kawałka kodu do pustego buforu powyżej:
live_loop :flibble do
sample :bd_haus, rate: 1
sleep 0.5
end
Teraz nacisnij przycisk Run
a usłyszysz fajne i szybkie
uderzenia bębna. W każdym momencie możesz zatrzymać dźwięk naciskając
przycisk Stop
. Aczkolwiek nie rób tego jeszcze… Zamiast tego wykonaj
następujące kroki:
sleep
z wartości `0.5’ na
większą, np. 1.Run
OK, to było dosyć łatwe. Dodajmy do naszego miksu coś innego. 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 wartości, co się stanie gdy użyjesz małych lub ujemnych liczb?
Spróbuj zobaczyć co się stanie gdy zmienisz wartość parametru rate:
dla
sampla :ambi_choir
tylko odrobinę (np. na 0.29). Co się stanie jeśli
wybierzesz naprawdę małą wartość dla parametru sleep
? Zobacz, czy uda Ci się
uruchomić powyższą pętlę tak szybko, że twój komputer zatrzyma się z powodu błedu,
gdyż nie będzie w stanie nadążyć (jeśli to się zdarzy, po prostu wybierz
większa wartość dla parametru sleep
i ponownie naciśnij przycisk Run
).
Spróbuj zrobić komentarz w jednej z linii zawierających sample
dodając na
początku linii znak #
, np.:
live_loop :flibble do
sample :ambi_choir, rate: 0.3
# sample :bd_haus, rate: 1
sleep 1
end
Zauważ, że dodanie znaku #
na początku linii mówi komputerowi aby zignorował
daną linię, dzięki czemu jej nie słyszymy. Taką linijkę nazywamy komentarzem.
W Sonic Pi możemy używać komentarzy do usuwania i dodawania różnych rzeczy do
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 niż to, że w tym kodzie są dwie pętle (live_loop
). Oznacza to,
że w tym samym czasie dzieją się dwie rzeczy. Teraz, rób to co umiesz najlepiej
- eksperymentuj i baw się próbując zmieniać ten kod. Oto kilka sugestii
co możesz zrobić:
rate:
aby usłyszeć zmianę
w dźwiękach poszczególnych sampli.sleep
dzięki czemu usłyszysz, że obie
pętle mogą kręcić się z różną szybkością.#
) a usłyszysz dźwięk
gitary granej od tyłu.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 aby wcisnąć przycisk Run
. Dzięki temu usłyszysz zmianę przy kolejnym
przebiegu pętli. Jeśli coś pójdzie nie tak i zacznie się kakofonia nie przejmuj
się tym. Wystarczy, że naciśniesz przycisk Stop
, usuniesz cały kod w buforze,
wkleisz świeżą kopię poniższego kodu i jesteś znowu gotowy do improwizacji. Pamiętaj,
człowiek najszybciej uczy się na błędach…
live_loop :guit do
with_fx :echo, mix: 0.3, phase: 0.25 do
sample :guit_em9, rate: 0.5
end
# sample :guit_em9, rate: -0.5
sleep 8
end
live_loop :boom do
with_fx :reverb, room: 1 do
sample :bd_boom, amp: 10, rate: 1
end
sleep 8
end
Baw się i eksperymentuj tym kawałkiem kodu do momentu, 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…
Sonic Pi ma bardzo prosty interfejs umożliwiający kodowanie muzyki. Poświęćmy chwilę na zapoznanie się z nim.
Różowe przyciski są głównymi kontrolerami uruchamiania i zatrzymywania dźwięków. Jest przycisk Run (Start) umożliwiający uruchomienie kodu znajdującego się w edytorze. Przycisk Stop umożliwia zatrzymanie całego uruchomionego kodu. Przycisk Save (Zapisz) służy do zapisywania kodu wpisanego w edytorze do zewnętrznego pliku tekstowego. Przycisk Record (Nagrywaj) umożliwia nagrywanie (w formacie WAV) aktualnie odtwarzanego dźwięku.
Pomarańczowe przyciski pozwalają Ci manipulować edytorem kodu. Przyciski Size + (Zwiększ rozmiar) i Size - (Zmniejsz rozmiar) umożliwiają powiększanie i zmniejszanie rozmiaru tekstu (czcionki). Przycisk Align (Wyrównaj) pozwala na uporządkowanie wyglądu twojego kodu tak aby wyglądał bardziej profesjonalnie (poprawia wcięcia).
Niebieskie przyciski dają Ci dostęp do informacji, pomocy i ustawień. Naciśnięcie przycisku Info spowoduje otworzenie dodatkowego okna, które zawiera informacje dotyczące Sonic Pi - zespół podstawowy, historia, współtwórcy oraz społeczność. Przycisk Help (Pomoc) otwiera i zamyka system pomocy (F), który właśnie czytasz. Przycisk Prefs (Ustawienia) otwiera i zamyka panel ustawień, który pozwala Ci na kontrolę kilku podstawowych ustawień aplikacji.
Obszar, w którym będziesz pisał swój kod oraz komponował/wykonywał muzykę. Jest to prosty edytor tekstowy, w którym możesz pisać kod, kasować go, wycinać, wklejać, itd. Myśl o nim jako o bardzo prostej wersji edytora Word czy Google Docs. Edytor automatycznie koloruje słowa bazując na ich znaczeniu w kodzie. Może się to wydawać dziwne na początku, ale bardzo szybko zauważysz, że jest to bardzo przydatne. Na przykład - wiesz, że coś dany tekst jest liczbą ponieważ ma kolor niebieski.
Sonic Pi wspiera wiele ustawień, które są dostępne za pomocą przycisku Preferencje (prefs), który znajduje się tuż za przyciskami Informacje i Pomoc. Naciśnięcie go spowoduje pokazanie panelu ustawień, który zawiera wiele opcji, które można zmianiać. Przykłady takich ustawień to: wymuszenie trybu mono, odwrócone stereo, włączanie i wyłączanie panelu logowania a także suwak głośności selektor dźwięku, które są dostępne tylko na platformie Raspberry Pi.
Kiedy uruchamiasz swój kod, informacja o tym co program aktualnie robi będzie wyświetlana w panelu podglądu logów. Domyślnie, zobaczysz wiadomość pojawiającą się dla każdego dźwięku, który stworzysz wraz z dokładnym czasem kiedy ten dźwięk został uruchomiony. Jest to bardzo przydatne do debugowania twojego kodu i zrozumienia co twój kod robi.
I na samym końcu została jedna z najważniejszych cześci interfejsu Sonic Pi - system pomocy, który pojawia się w dolnym oknie. Może on być włączony i wyłączony za pomocą naciśnięcia niebieskiego przycisku Help (Pomoc). System pomocy zawiera pomoc oraz informacje dotyczące wszystkich aspektów związanych z Sonic Pi włączając w to ten samouczek, listę dostępnych syntezatorów, sample (próbki dźwięków), przykłady, efekty (FX) oraz listę wszystkich funkcji umożliwiających tworzenie muzyki jakie Sonic Pi udostępnia.
Sonic Pi zachęca abyś poprzez zabawę i eksperymentowanie uczył się
jednocześnie programowania i tworzenia muzyki. Najważniejsze jest
abyś się dobrze bawił. W międzyczasie, nawet się nie obejrzysz,
a zauważysz, że nauczyłeś się programować, komponowac i “grać” na żywo.
Skoro jesteśmy przy tym temacie, pozwól że dam Ci jedną radę, coś czego nauczyłem się przez lata kodowania muzyki na żywo - błędów nie ma, są tylko nowe możliwości. To jest coś, co często słyszy się w kontekście muzyki z gatunku jazz, ale sprawdza się równie dobrze w odniesieniu do kodowania na żywo. Nie ma znaczenia jak dużo masz doświadczenia - niezależnie czy jesteś całkowitym żółtodziobem, czy zaprawionym w bojach Algorejwerem, na pewno zdarzy Ci się napisać kod, którego wynik po uruchomieniu będzie całkowicie nieprzewidziany. Może to brzmieć niesamowicie fascynująco - i w tym przypadku faktycznie tak jest. Można też, patrząc na to z innej strony, stwierdzić że brzmi to kiepsko i jest całkowicie nie na miejscu. Pamiętaj, to że to się wydarzyło jest całkowicie nieistotne - to co jest naprawdę ważne to co z tym zrobisz dalej. Weź dźwięk, manipuluj nim i przekształć go w coś niesamowitego. Tłum będzie szalał.
Zawsze kiedy się uczysz, najbardziej kuszące jest to, że chcesz robić niesamowite rzeczy tu i teraz. Postaraj się jednak powstrzymać te myśli i spójrz na nie jako odległy cel, który uda się się osiągnąć później. Zamiast tego, pomyśl o najprostszej rzeczy jaką potrafisz napisać, która będzie fajna, a jednocześnie sprawi, że będziesz czuł satysfakcję z tego, że jest to mały krok w kierunku wizji, która wypełnia twoją głowę. Gdy już będziesz widział w swojej głowie ten mały krok, spróbuj go wykonać - napisz kawałek kodu, uruchom go, baw się nim i zobacz jakie nowe pomysły przyjdą Ci do głowy. Zobaczysz, niedługo będziesz tak pochłonięty zabawą, że zaczniesz robić prawdziwe postępy.
Nie zapomnij tylko podzielić się swoją pracą z innymi!
OK, tyle tytułem wstępu - pora zająć się muzyką.
W tym rozdziale poznasz podstawy uruchamiania i manipulowania
syntezatorami. Syntezator to taka fajna nazwa dla czegoś co wytwarza
dźwięk. Normalnie syntezatory są dość skomplikowane w użyciu. Zwłaszcza
syntezatory analogowe zawierają wiele różnych połączeń, kabelków
i modułów. Natomiast Sonic Pi oddaje w twoje ręce wiele z tych możliwości
w bardzo prostej i przystępnej formie.
Nie daj się zwieść prostocie interfejsu, który prezentuje Sonic Pi. Masz możliwość zanurzyć się bardzo głęboko. Jeśli to twoja dziłka, to do twojej dyspozycji są bardzo wyszukane możliwości manipulacji dźwiękiem. Zapnij pasy…
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…
A teraz naciśnij przycisk jescze raz. I jeszcze raz. I jeszcze raz…
Łał, szaleństwo. Jestem pewien, że możesz tak przez cały dzień. Ale poczekaj. Zanim zatracisz się w pętli nieskończonych bipów, spróbuj zmienić liczbę:
play 75
Słyszysz różnicę? OK, teraz spróbuj mniejszej liczby:
play 60
Zauważ, że mniejsze liczby powodują bipy o niższym tonie a większe liczby
powodują bipy o wyższym tonie. Tak samo jak na pianinie - klawisze
znajdujące się po lewej stronie instrumentu grają nuty o niższym brzmieniu
a klawisze znajdujące się po prawej stronie grają nuty o wyższym brzmieniu.
I faktycznie tak jest, powyższe liczby odpowiadają nutom na pianinie.
Kod play 47
znaczy nic innego jak - zagraj nutę znajdującą się pod
47 klawiszem na pianinie. Oznacza to, że kod play 48
to dźwięk o jedną
nutę wyżej (następny klawisz po prawej). Tak się składa, że nuta C w 4-tej
oktawie odpowiada liczbie 60. Smiało, spróbuj zagrać ten dźwięk:
play 60
.
Nie przejmuj się jeśli nic z tego nie rozumiesz - ja również nie rozumiałem gdy zaczynałem na poczatku tak jak Ty teraz. Wszystko co się teraz liczy to to, że wiesz, że małe liczby powodują bipy o niskim brzmieniu a duże liczby powodują bipy o wyższym brzmieniu.
Zagranie nuty jest całkiem fajne, ale zagranie kilku jednocześnie może być jeszcze fajniejsze. Spróbuj:
play 72
play 75
play 79
Super! Zauważ, że kiedy napiszesz kilka razy komendę play
, wszytkie dźwięki
zagrają w tym samym momencie. Teraz spróbuj sam - które liczby brzmią razem
dobrze? Które brzmią okropnie? Eksperymentuj, odkrywaj i przekonaj się
na własnej skórze.
Granie nut i akordów jest fajne - a co powiesz na zagranie melodii?
Co jeśli chciałbyś zagrać jedną nutę po drugiej ale nie w tym samym
czasie? Nic prostszego, wystarczy że odczekasz kawałek czasu pomiędzy
poszczególnymi nutami używając polecenia sleep
:
play 72
sleep 1
play 75
sleep 1
play 79
Cudownie, właśnie stworzyłeś małe arpeggio. No dobrze, ale co oznacza liczba
1
w poleceniu sleep 1
? Oznacza to długość trwania odstępu pomiędzy
nutami. Zasadniczo oznacza to odstęp o długości jednego uderzenia,
ale póki co możesz myśleć o tym jako o przeczekaniu 1-ną sekundę.
Co powinniśmy w takim razie zrobić jeśli chcielibyśmy trochę przyśpieszyć
nasze arpeggio? Jedyne co musimy zrobić to użyć “krótszych” wartości
dla polecenia sleep. Weźmy na przykład połowę, czyli wartość 0.5
:
play 72
sleep 0.5
play 75
sleep 0.5
play 79
Zauważ, że arpeggio gra teraz szybciej. Teraz twoja kolej, pobaw się tym kawałkiem kodu zmieniając czasy na takie jak uważasz, tak jak wcześniej spróbuj użyć przy tym różnych nut.
Jest jedna rzecz, którą szczególnie warto wypróbować. Spróbuj użyć nut, które
są “pomiędzy” całymi nutami, np. play 52.3
, play 52.63
. Nie ma absolutnie
żadnej konieczności, abyś kurczowo trzymał się standardowych pełnych nut.
Kombinuj z różnymi wartościami i baw się dobrze.
Osoby, które aktualnie znają już trochę notację muzyczną (nie przejmuj
się jeśli Ty nie znasz - nie musisz, żeby móc się dobrze bawić) być może
będą preferować pisanie melodii przy wykorzystaniu standardowych nazw nut,
np. C lub F# (Fis) zamiast używania liczb. Sonic Pi pozwala na to. Nic
nie stoi na przeszkodzie abyś napisał i uruchomił taki kod:
play :C
sleep 0.5
play :D
sleep 0.5
play :E
Pamiętaj tylko, że by umieścić dwukropek :
tuż przed nazwą twojej nuty.
Spowoduje to, że zmieni ona kolor na różowy. Możesz również zdefiniować
oktawę umieszczająć odpowiednią liczbę tuż po nazwie nuty:
play :C3
sleep 0.5
play :D3
sleep 0.5
play :E4
Jeśli chcesz sprawić aby nuta brzmiała o pół tonu wyżej (uzyskanie dźwięku
fis), dodaj s
tuż za twoją nutą, np. play :Fs3
. Analogicznie - jeśli
chcesz obniżyć dźwięk nuty o połowę (uzyskanie dźwięku mol), dodaj na końcu
twojej nuty b
, np. play :Eb3
A teraz czas poszaleć. Możesz zacząć bawić się w tworzenie twoich własnych melodii.
Tak samo jak masz kontrolę nad tym, którą nutę zagrać lub który sampel uruchomić, Sonic Pi udostępnia cały asortyment parametrów umożliwiających kształtowanie i kontrolowanie dźwięków. Wiele z tych parametrów zostanie omówionych w tej części samouczka. Ponadto w systemie pomocy jest obszerna dokumentacja, która szczegółowo opisuje każdy z nich. Tymczasem, przedstawimy dwa najbardziej przydatne: aplituda (amp) i balans (pan). Na początek, zobaczmy czym są te parametry w rzeczywistości.
Syntezatory obecne w Sonic Pi wspierają pojęcie parametrów. Parametry to
sterowniki, które po przekazaniu do syntezatora play
modyfikują
i kontrolują różne aspekty odtwarzanego dźwięku. Każdy z syntezatorów
posiada własny zestaw parametrów pozwalających na subtelny tuning
produkowanego dźwięku. Jednakże, istnieje zestaw parametrów, które
są wspólne dla wielu dźwięków. Przykładami takich parametrów są np. amp:
czy parametry kopertowe (zostaną omówione w dalszej części samouczka).
Parametry składają się z dwóch podstawowych części: nazwy (kontrolowanego
parametru) oraz wartości (na jaką chcemy ustawić dany parametr).
Na przykład możesz mieć parametr, który nazywa się ser:
i chciałbyś
ustawić jego wartość na 1
.
Parametry są przekazywane do polecenia play
w następujący sposób:
najpierw dodajemy tuż za poleceniem przecinek ,
po nim wpisujemy nazwę
parametru, np. amp:
(nie zapomnij o dwukropku :
) i na końcu po spacji
podajemy wartość parametru. Oto przykład:
play 50, ser: 1
(Zauważ, że ser:
nie jest poprawnym parametrem, używamy go tutaj tylko
jako przykład).
Możesz przekazać wiele parametrów oddzielając je przecinkami:
play 50, ser: 1, fasolki: 0.5
Kolejnośc parametrów nie ma znaczenia, poniższy kod też zadziała:
play 50, fasolki: 0.5, ser: 1
Parametry, które nie są rozpoznawane przez dany syntezator są po prostu
ignorowane (tak jak ser
i fasolki
jak w powyższym przypadku, które są
po prostu śmiesznymi nazwami parametrów!).
Jeśli niechcący zdarzy Ci się dwa razy użyć parametru o tej samej nazwie
to wygrywa ostani. Na przykład - ostateczna wartość dla parametru fasolki:
wyniesie 2 (a nie 0.5):
play 50, fasolki: 0.5, ser: 3, jajka: 0.1, fasolki: 2
Wiele rzeczy w Sonic Pi akceptuje parametry, warto więc poświęcić parę
chwil aby nauczyć się jak ich używać, dzięki temu będziesz ustawiony!
Spróbujmy pobawić się trochę z naszym pierwszym parametrem: amp:
.
Amplituda jest w komputerową miarą reprezentującą głośność dźwięku. Wysoka aplituda powoduję głośny dźwięk a niska aplituda powoduje cichyy dźwięk. Tak samo jak Sonic Pi używa liczb do reprezentacji czasu i nut, tak samo używa ich do reprezentacji wielkości amplitudy. Amplituda o wartości 0 to cisza (nie słyszysz nic). Natomiast amplituda o wartości 1 ustawienie głośności na normalny poziom. Możesz nawet podkręcić na 2, 10, 100. Musisz jednak mieć na uwadze to, że gdy całkowita amplituda wszystkich dźwięków stanie się zbyt wysoka, Sonic Pi wykorzysta narzędzie zwane kompresorem, żeby zdusić je tak, żeby mieć pewność, że dźwięk nie jest zbyt głośny dla twoich uszu. Może to spowodować, że dźwięk stanie się nieczysty i dziwny. Staraj się więc używać niskch aplitud, np. w zakresie od 0 do 0.5, żeby uniknąć kompresji.
Aby zmienić amplitudę dźwięku użyj parametru amp:
. Na przykład,
aby zagrać z głośnością na poziomie 0.5 użyj takiego kawałka kodu:
play 60, amp: 0.5
Aby zagrać z podwójną głośnością (amplitudą) przekaż parametr 2:
play 60, amp: 2
Parametr amp:
modyfikuje tylko wywołanie tego polecenia play
, z którym
jest powiązany. Tak więc w poniższym przykładzie pierwsze wywołanie polecenia
play zostanie zagrane z głośnością na poziomie równym połowie normalnej
głośności, natomiast drugie polecenie zostanie zagrane z głośnością
domyślną (1):
play 60, amp: 0.5
sleep 0.5
play 65
Nic nie stoi na przeszkodzie, abyś użył różnych wartości parametru amp:
dla różnych wywołań polecenia play:
play 50, amp: 0.1
sleep 0.25
play 55, amp: 0.2
sleep 0.25
play 57, amp: 0.4
sleep 0.25
play 62, amp: 1
Kolejnym fajnym parametrem z którego można korzystać jest pan:
. Kontroluje
on balans dźwięku w stereo. Balansowanie dźwiękiem w lewą stronę oznacza,
że będziesz go słyszał tylko w lewym głośniku (słuchawce). Z kolei
balansowanie dźwiękiem na lewą strone oznacza, że będziesz go słyszał tylko
w prawym głośniku. W naszym przypadku używamy wartości -1 do reprezentacji
dźwięku, którego balans został w pełni przesunięty na lewą stronę, 0 aby
dla balansu po środku oraz 1 dla dźwięku po prawej stronie w polu stereo.
Naturalnie nic nie stoi na przeszkodzie abyśmy używali dowolnej wartości
znajdującej się pomiędzy -1 i 1 w celu dokładnej kontroli “pozycji” naszego
dźwięku.
Zagrajmy bip z lewego głośnika:
play 60, pan: -1
A teraz zagrajmy go z prawego głośnika:
play 60, pan: 1
I na końcu zagrajmy z powrotem z obu głośników (domyślna pozycja):
play 60, pan: 0
Teraz kolej na Ciebie. Spróbuj samodzielnie pobawić się zmieniając amplitudę (amp:) i balans (pan:) twoich dźwięków!
Do tej pory bawiliśmy się całkiem nieźle robiąc wiele fajnych bipów. Jest jednak bardzo prawdopodobne, że podstawowy dźwięk bip zaczyna Cię już powoli nudzić. Czy to jest wszystko co Sonic Pi ma do zaoferowania? Na pewno jest dużo więcej możliwości w kodowaniu na żywo niż tylko granie bipów? Owszem, są inne możliwości i to jest rozdział, w którym poznasz fascynującą paletę dźwięków, jakie Sonic Pi ma do zaoferowania.
Sonic Pi posiada szeroki wachlarz instrumentów, które nazywa syntezatorami. Zważywszy na to, że sample (próbki) reprezentują nagrane dźwięki, syntezatory mają możliwość generowania nowych dźwięków, które są zależne od tego jak je kontrolujesz (w tym samouczku dowiesz się o tym później). Syntezatory Sonic Pi są bardzo potężne i ekspresyjne. Będziesz miał dużo przyjemności podczas poznawania i zabawy nimi. Na początku jednak nauczmy się jak wybierać aktualnie grający syntezator.
Fajnym dźwiękiem jest sawdźwięk piły - spróbujmy:
use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25
A teraz spróbujmy innego dźwięku - syntezatora prophet:
use_synth :prophet
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25
Co powiesz na połączenie dwóch dźwięków. Jeden po drugim:
use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25
A teraz w tym samym czasie:
use_synth :tb303
play 38
sleep 0.25
use_synth :dsaw
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25
Zauważ, że polecenie use_synth
wywiera wpływ tylko na kolejne wywołania
poleceń play
. Pomyśl o tym poleceniu jako o dużym przełączniku - kolejne
wywołania polecenia play
będą odtwarzać dowolny syntezator, który jest
w danym momencie wskazany. Możesz zmienić aktualny syntezator na inny
używając przełącznika use_synth
.
Aby zobaczyć jakie syntezatory Sonic Pi ma dla Ciebie do zabawy zerknij na opcję Synth w lewym dolnym rogu (obok Fx). Znajdziesz tam ponad 20 do wyboru. Oto kilka moich ulubionych:
:prophet
:dsaw
:fm
:tb303
:pulse
Tera pobaw się zmieniając syntezatory w trakcie odtwarzania twojej muzyki. Próbuj bawić się łącząc ze sobą różne dźwięki aby tworzyć nowe brzmienia jak również używająć różnych syntezatorów w różnych sekcjach twojego utworu.
W poprzedniej sekcji, zobaczyliśmy w jaki sposób możemy używać komendy
sleep
aby kontrolować, kiedy dźwięki zaczynają grać. Nie wiemy jednak
jeszcze w jaki sposób kontrolować długość trwania naszych dźwięków.
Aby móc korzystać z prostej ale jakże potężnej możliwości kontrolowania długości trwania naszych dźwięków, Sonic Pi udostępnia pojęcie obwiedni dla amplitudy ADSR (czym jest ADSR dowiesz się za chwilę w kolejnych sekcjach). Obwiednia amplitudy udostępnia dwa przydatne aspekty kontroli:
Długość trwania 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.
Obwiednia ADSR kontroluje nie tylko długość trwania, lecz pozwala Ci również na precyzyjną kontrolę amplitudy dźwięku. Wszystkie dźwięki zaczynają się i kończą ciszą. Pomiędzy tymi ciszami jest moment podczas, którego słychać dźwięk. Obwiednie pozwalają Ci przesuwać i ustawiać amplitudę tej części, w której słychać dźwięk. Jest to analogiczne do sytuacji, w której powiedziałbyś komuś kiedy powinien zwiększać i zmieniejszać głośność dla jakiegoś utworu muzycznego. Na przykład - możesz poprosić kogoś “zacznij od ciszy, potem powoli zwiększaj poziom głośności, utrzymaj go na tym poziomie przez chwilę po czym szybko wycisz”. Sonic Pi pozwala Ci na zaprogramowanie tego za pomocą obwiedni.
Jak widzieliśmy w poprzedniej sekcji samouczka, amplituda o wartości 0 to cisza, natomiast amplituda o wartości 1 to głośność normalna.
Domyślnie wszystkie syntezatory posiadają czas zanikania amplitudy równy 1. Oznacza to,
że trwa to 1 uderzenie przed zakończeniem (domyślnie będzie to 1 sekunda). Możemy
zmieniać czas trwania tego zanikania za pomocą przekazania do naszego polecenia play
parametru release:
. Na przykład, aby sprawić by syntezator grał przez 2 uderzenia, dla parametru
release:
ustawiamy wartość 2
:
play 60, release: 2
Możemy też sprawić aby syntezator brzmiał przez bardzo krótką chwilę. Wystarczy użyć bardzo małej wartości dla czasu zanikania amplitudy:
play 60, release: 0.2
W takim razie czym jest długość zanikania amplitudy? Jesto to czas, który jest potrzebny aby dźwięk z maksymalnej amplitudy (zazwyczaj jest to wartość 1) zmniejszył się do amplitudy równej zero. Jest to tak zwana faza zanikania (ang. release phase) i jest to przejście liniowe (tzn. obniżające się w linii prostej). Poniższy diagram ilustruje to przejście:
Pionowa linia po lewej stronie diagramu pokazuje, że dźwięk zaczyna się
z amplitudą równą 0, ale osiąga pełną głośność momentalnie (jest to faza
ataku, omówimy ją za chwilę). Gdy pełna głośność zostanie już osiągnięta
następuje zmniejszanie głośności po linii prostej aż do wartości zero
i zajmuje to tyle czasu ile zostało ustawione za pomocą parametru zanikania
release:
. Im czas zanikania jest dłuższy, tym dłuższy będzie czas znikania
(wyciszania) dźwięku syntezatora.
Możesz zatem zmieniać długość trwania twoich dźwięków zmieniając czas zanikania. Spróbuj teraz pobawić się dodając do twojej muzyki różne czasy zanikania.
Domyślnie, faza ataku jest równa 0 dla wszystkich sytezatorów. Oznacza to, że przejście od amplitudy 0 do aplitudy 1 jest natychmiastowe. Nadaje to syntezatorowi początkowy perkusyjny dźwięk. Mimo to, może się zdarzyć, że będziesz chciał aby twój dźwięk zaczynał brzmieć stopniowo. Aby to zrobić wystarczy wykorzystać parametr ‘attack:’. Spróbuj użyć takiego przejścia w kilku różnych dźwiękach:
play 60, attack: 2
sleep 3
play 65, attack: 0.5
Zauważ, że możesz używać wielu parametrów w tym samym czasie. Na przykład dla krótkiej fazy ataku (attack) i długiej fazy zanikania (release) spróbuj coś takiego:
play 60, attack: 0.7, release: 4
Taka obwiednia z krótką fazą ataku i długą zanikania została zilustrowana na poniższym rysunku:
Oczywiście, możesz zmieniać parametry według swoich upodobań. Spróbuj teraz długiej fazy ataku i krótkiej fazy zanikania:
play 60, attack: 4, release: 0.7
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
Oprócz możliwości ustawiania czasu narastania i czasu zanikania dźwięku, możesz również określić czas podtrzymania. Jest to moment, w którym dźwięk jest utrzymany na pełnej aplitudzie pomiędzy fazami narastania i zanikania.
play 60, attack: 0.3, sustain: 1, release: 1
Czas podtrzymania jest bardzo przydatny dla istotnych dźwięków, którym
chciałbyś dać pełną obecność w miksie tuż przed wejściem opcjonalnej fazy
zanikania. Oczywiście, całkowicie dopuszczalne jest ustawienie obu
parametrów, zarówno fazy ataku jak i fazy zanikania na wartość 0
a także użycie tylko fazy podtrzymania żeby nie mieć absolutnie żadnej
fazy wejścia lub wyjścia dla danego dźwięku. Bądź jednak ostrożny i wiedz,
że ustawienie fazy zanikania na 0 może spowodować dziwne kliki w dźwiękach
i bardzo często zamiast tego dużo lepiej jest użyć bardzo małej wartości,
np. 0.2.
Na sam koniec, dla momentów gdzie potrzebujesz dodatkowego poziomu kontroli,
masz możliwość skorzystania z fazy opadania. Jest to taki moment w obwiedni dźwięku,
który znajduje się pomiędzy fazą ataku a fazą podtrzymania (wybrzmiewania)
i określa moment, w którym amplituda spada z poziomu ataku attack_level
do poziomu
podtrzymania sustain_level
. Domyślnym argumentem dla fazy opadania jest 0, natomiast
poziomy ataku i podtrzymania posiadają domyślną wartość 1. W związku z tym musisz
określić dla nich czas opadania aby uzyskać jakikolwiek efekt:
play 60, attack: 0.1, attack_level: 1, decay: 0.2, sustain_level: 0.4, sustain: 1, release: 0.5
Podsumowując, obwiednie ADSR w Sonic Pi posiadają następujące fazy:
attack_level
.attack_level
)
do poziomu podtrzymania (sustain_level
).sustain_level
.sustain_level
) do zera.Należy tu zwrócić uwagę na fakt, że całkowita długość trwania dźwięku jest sumą czasu trwania każdej z faz występujących w danym dźwięku. Dlatego też poniższy dźwięk będzie miał długość 0.5 + 1 + 2 + 0.5 = 4 uderzeń:
play 60, attack: 0.5, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5
Tyle teorii, teraz spróbuj sam pobawić się dodając obwiednie do twoich dźwięków…
Innym świetnym sposobem tworzenia twojej muzyki jest wykorzystanie nagranych wcześniej dźwięków. W wielkiej tradycji hip hopu, takie nagrane wcześniej dźwięki nazywamy samplami. Innymi słowy jeśli weźmiesz mikrofon i nagrasz subtelny dźwięk kropel deszczu uderzających o szybę, to właśnie nagrałeś swój pierwszy sampel.
Sonic Pi pozwala Ci robić wiele fajnych rzeczy z samplami. Poza tym, że na pokładzie jest ponad 90 publicznie dostępnych sampli, które są gotowe abyś zaczął się nimi bawić, to masz też możliwość manipulowania nimi oraz korzystania z twoich własnych. Bierzmy się do zabawy…
Granie prostych dźwięków to dopiero początek. Coś co jest dużo fajniejsze to wyzwalanie nagranych sampli. Spróbuj:
sample :ambi_lunar_land
Sonic Pi posiada wiele sampli, których możesz używać do tworzenia swojej muzyki. Możesz używać ich tak samo jak używasz polecenia `play’. Aby zagrać kilka sampli i nut po prostu napisz je jeden po drugim:
play 36
play 48
sample :ambi_lunar_land
sample :ambi_drone
Jeśli chcesz rozdzielić je w czasie wykorzystaj polecenie sleep
:
sample :ambi_lunar_land
sleep 1
play 48
sleep 0.5
play 36
sample :ambi_drone
sleep 1
play 36
Zauważ, że Sonic Pi nie czeka aż dźwięk przestanie grać zanim zacznie
grać kolejny dźwięk. Polecenie sleep
tylko opisuje rozdzielenie
wyzwalania poszczególnych dźwięków. Takie podejście pozwala na łatwe
nawarstwianie kolejnych dźwięków, które razem mogą tworzyć ciekawe
efekty nakładania się na siebie. W dalszej części tego samouczka
pokażemy w jaki sposób można kontrolować długość trwania dźwięków
przy użyciu obwiedni.
Są dwa sposoby na odkrywanie wachlarza sampli dostępnych w Sonic Pi. Po pierwsze możesz korzystać z systemu pomocy. Kliknij na sekcję Sample w lewym dolnym menu, wybierz kategorię a zobaczysz listę dostępnych dźwięków.
Alternatywnie możesz skorzystać z systemu autopodpowiadania. Wystarczy,
że wpiszesz początek wybranej grupy sampli, np. sample :ambi_
a twoim
oczom ukaże się rozwijana lista sampli do wyboru. Wypróbuj następujące
prefiksy kategorii:
:ambi_
:bass_
:elec_
:perc_
:guit_
:drum_
:misc_
:bd_
A teraz zacznij wplatać sample w twoje własne kompozycje!
Tak samo jak w przypadku Syntezatorów, możemy łatwo kontrolować
nasze dźwięki za pomocą parametrów. Sample wspierają takie sam
mechanizm parametrów. Przyjrzyjmy się ponownie naszym kolegom
amp:
i pan:
.
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
Możemy również używać parametru pan:
dla sampli. Na przykład,
oto jak możemy zagrać breakbeat amen aby brzmiał tylko w lewym
głośniku, a potem w połowie czasu, żeby zaczął grać też w prawym
glośniku:
sample :loop_amen, pan: -1
sleep 0.877
sample :loop_amen, pan: 1
Zauważ, że liczba 0.877 jest połową czasu trwania pętli loop_amen
wyrażoną w sekundach.
Na koniec należy zauważyć, że jeśli ustawisz pewne wartości domyślne
syntezatorów za pomocą parametru use_synth_defaults
(zostanie on
omówiony później), to będą one ignorowane przez polecenie sample
.
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.
Sample to nagrane dźwięki, które są przechowywane niczym liczby, które mówią o tym jak poruszyć stożek głośnika by zreprodukować dany dźwięk. Stożek głośnika może poruszać się do środka i na zewnątrz, tak samo liczby muszą jedynie przedstawiać jak daleko do środka lub na zewnątrz powinien znajdować się stożek głośnika w danym momencie. Aby móć wiernie odwzorować nagrany dźwięk sampla zazwyczaj potrzeba do tego wiele tysięcy liczb na sekundę! Sonic Pi bierze tę listę liczb i zasila nimi głośniki z odpowiednią prędkością tak aby głośniki twojego komputera poruszały się do przodu i do tyłu w taki właśnie sposób aby zreprodukować dany dźwięk. Mimo to, całkiem fajnie jest zmieniać prędkość z jaką te liczby są przekazywane do głośnika aby w ten sposób zmieniać brzmienie.
Pobawmy się jednym z dźwięków z
gatunku ambient:
:ambi_choir
. Aby zagrać go w domyślnym tempie, możesz przekazać
parametr rate:
do polecenia sample:
sample :ambi_choir, rate: 1
Takie poleceni sprawia, że sampel zostanie zagrany w normalnym tempie
(1), więc póki co nic specjalnego się nie dzieje. Nic jednak nie stoi
nam na przeszkodzie abyśmy zmienili tę liczbę na coś innego. Co
powiesz na wartośc 0.5
:
sample :ambi_choir, rate: 0.5
Łał! Co się tutaj dzieje? Otóż, dwie rzeczy. Po pierwsze, odtworzenie naszego naszego sampla zajmuje drugie tyle czasu. Po drugie, dźwięk jest niższy o oktawę. Przyjrzyjmy się tym dwóm tematom nieco bardziej szczegółowo.
Sampel, który jest bardzo fajny do rozciągania i kompresji to Amen beakbit. Przy normalnym tempie, możemy wyobrazić sobie wrzucenie go do utworu drum ‘n’ bass:
sample :loop_amen
Jednak gdy zmienimy tempo możemy bardzo szybko zmienić gatunek. Spróbuj połowy prędkości aby stworzyć oldschool’owy hip hop:
sample :loop_amen, rate: 0.5
Jeśli przyśpieszymy, wejdziemy na terytorium jungle:
sample :loop_amen, rate: 1.5
A teraz nasz ulubiony finalny trik - zobaczmy co się stanie jeśli użyjemy ujemnego tempa:
sample :loop_amen, rate: -1
Łoł! To jest odtwarzane od tyłu! A teraz spróbuj sam pokombinować z różnymi samplami ustawiając je na różne tempa. Spróbuj bardzo szybkich temp. Spróbuj niewiarygodnie niskich temp. Sprawdź jak różne i interesujące dźwięki możesz wyprodukować.
Przydatnym sposobem myślenia o samplach jest myślenie o nich jak o sprężynkach. Z tempem (szybkością) odtwarzania jest tak jak ze ściskaniem i rozciąganiem sprężyny. Zagranie sampla w tempie równym 2 spowoduje, że ściśniesz sprężynę do połowy jej normalnej długości. Dlatego też zagranie takiego sampla zajmie o połowę mniej czasu. Jeśli zagrasz sampel w tempie równym połowe normalnego, to wtedy *rozciągasz sprężynę tak, że podwaja swoją długość. W takim przypadku zagranie całego sampla zajmie dwa razy więcej czasu. Im bardziej ściśniesz sprężynę (wyższe tempo), tym stanie się krótsza. Analogicznie, im bardziej rozciągniesz (niższe tempo), tym będzie dłuższa.
Ściskanie sprężyny zwiększa jej gęstość (liczba zwojów na cm) - jest to podobne do tego gdy sampel brzmi na wyższym poziomie (pitch). Rozciąganie zmniejsza gęstość i jest podobne to dźwięku posiadającego niższy poziom (pitch).
(Ta sekcja jest udostępniona dla tych osób, które są zainteresowane szczegółami. Jeśli nie jesteś, możesz ją po prostu pominąć…)
Jak zauważyliśmy już powyżej, sampel jest reprezentowany przez wielką, długą listę liczb, które defuniują to w jakiej pozycji powinien znajdować się głośnik w danym momencie czasu. Możemy wziąć te liczby i wykorzystać je do narysowania wykresu graficznego, który mógłby wyglądać bardzo podobnie do tego:
Być może widziałeś już podobne obrazki. Nazywa się ją przebiegiem fali sampla. Jest to nic innego jak tylko wykres prezentujący liczby. Zazwyczaj przebieg fali takiej jak ta będzie miał 44100 punktów z danymi na sekundę(jest związane z twierdzeniem Kotelnikowa-Shanona). Więc jeśli sampel trwa przez 2 sekundy, to przebieg fali będzie reprezentowany przez 88200 liczb które przekażemy do głośnika z prędkością 44100 punktów na sekundę. Odtworzenie tego powinno zatem zajęć tylko 1 sekundę. Możemy spróbować również odtworzyć go w tempie o połowę mniejszym, co dałoby wartość 22050 punktów na sekundę i odtworzenie zajęłoby 4 sekundy.
Na czas trwania sampli ma wpływ szybkość odtwarzania:
Możemy przedstawić to za pomocą następującego wzoru:
nowy_czas_trwania_sampla = (1 / tempo) * czas_trwania_sampla
Zmiana szybkości odtwarzania wpływa również na wysokość tonu (pitch) sampla. Częstotliwość lub wysokość tonu widoczna na fali dźwięku jest determinowana przez to jak szybko się ona zmienia w górę i w dół. Nasze mózgi w jakiś sposób zmieniają szybkie ruchy głośnika na wysokie nuty oraz wolne ruchy głośników na niskie nuty. To jest właśnie przyczyną tego, że czasami możesz nawet zobaczyć ruch dużego głośnika basowego gdy wydaje on z siebie super niski bas - w zasadzie to porusza się on wtedy znacznie wolniej w tę i z powrotem niż wtedy gdy głośnik produkuje wyższe dźwięki.
Jeśli weźmie się falę dźwięku i ściśnie się to wtedy będzie się ona poruszać w górę i w dół więcej razy na sekundę. Spowoduje to, że dany dźwięk będzie miał wyższy ton. Oznacza to, że podwojenie ruchów w górę i w dół (oscylacji) zwiększa częstotliwość dwukrotnie. Podsumowując, zagranie twojego sampla z podwójną prędkością spowoduje, że częstotliwość, którą usłyszysz będzie dwa razy wyższa. Analogicznie, obniżenie tempa o połowę spowoduje, że częstotliwość będzie też niższa o połowę. Inne wartości tempa będą będą oddziaływać na częstotliwość odpowiednio.
Korzystając z obwiedni ADSR możliwa jest również modyfikacja czasu trwania
oraz amplitudy sampli. Jednakże działanie jest w tym przypadku trochę
inne niż w przypadku syntezatorów. Obwiednie sampli pozwalają Ci tylko
na zmniejszanie amplitudy oraz czasu trwania sampla - natomiast nigdy
nie jest możliwe zwiększanie wartości tych parametrów. Sampel przestanie
grać gdy się skończy lub gdy zakończy się obwiednia - obojętne co skończy
się szybciej. Jeśli więc użyjesz bardzo długiego parametru release:
,
to nie spowoduje to, że wydłuży się czas odtwarzania sampla.
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
Miejsce, w kórym zachowanie obwiedni ADSR dla sampli różni się od obwiedni dla syntezatorów jest wartość parametru sustain. Domyśnie w obwiedni syntezatorów, parametr fazy podtrzymania domyślnie otrzymuje wartość 0, o ile nie zmienimy jej ręcznie. W przypadku sampli, faza podtrzymania domyślnie otrzymuje wartość automagiczną - czas potrzebny na odtworzenie pozostałej części sampla. Jest to właśnie przyczyną dla której słyszymy całego sampla kiedy nie ustawimy żadnej wartości dla fazy podtrzymania. Jeśli domyślne wartości dla parametrów ataku, opadania, podtrzymania i zanikania były ustawione na 0 nigdy nie usłyszelibyśmy nawet jednego piknięcia. Sonic Pi sam oblicza jak długi jest czas trwania sampla, obcina fazy ataku, opadania oraz zanikania i używa wyniku jako czasu dla fazy podtrzymania. Jeśli wartości podane dla ataku, opadania lub zanikania po zsumowaniu dają wartość większą od czasu trwania sampla, to faza podtrzymania otrzymuje po prostu wartość 0.
Aby to zbadać, przyjrzyjmy się bardziej szczegółowo naszej pętli Amen Loop. Jeśli zapytamy Sonic Pi o to jak długo trwa ten sampel:
print sample_duration :loop_amen
To wyświetli liczbę 1.753310657596372
i jest ona długością sampla wyrażoną
w sekundach. Dla wygody zaogrąglijmy ją tutaj do wartości 1.75
. Teraz,
jeśli ustawimy fazę zanikania (release) na wartość 0.75
to wydarzy się
coś niespodziewanego:
sample :loop_amen, release: 0.75
Pierwsza sekunda sampla zostanie zagrana z pełną amplitudą po czym zacznie stopniowo zanikać przez okres 0.75 sekundy. To jest właśnie auto sustain w akcji (automatyczne ustawianie czasu trwania dla fazy podtrzymania). Domyślnie, faza zanikania (release) zawsze działa (jest ustawiana) od końca sampla. Jeśli nasz sample trwałby 10.75 sekundy, to najpierw pierwszye 10 sekund zostałoby zagrane z pełną amplitudą, po czym zaczęłoby się stopniowe zanikanie (fade out), trwające przez 0.75s.
Zapamiętaj: domyślnie, faza zanikania (release:
) wchodzi pod koniec
sampla.
Możemy używać jednocześnie parametrów dla ustawiania fazy ataku attack:
oraz fazy zanikania release:
z wykorzystaniem automatycznego ustawiania
fazy podtrzymania (sustain) aby użyć stopniowego pojawienia się i stopniowego
zanikania przez cały czas trwania sampla:
sample :loop_amen, attack: 0.75, release: 0.75
Jako, że pełny czas trwania naszego sampla to 1.75s, a nasze fazy ataku i zanikania dają w sumie 1.5 s, to czas trwania fazy podtrzymania (sustain) automagicznie ustawia się na wartość 0.25s. Pozwala nam to na łatwe tworzenie łagodnych wejść i wyjść w samplach.
Możemy bardzo łatwo przywrócić normalne zachowanie ADSR znane z syntezatorów
poprze manualne ustawienie wartości parametru sustain:
na wartość 0:
We can easily get back to our normal synth ADSR behaviour by manually
setting sustain:
to a value such as 0:
sample :loop_amen, sustain: 0, release: 0.75
Teraz nasz sampel zostanie zagrany tylko przez 0.75 sekundy w sumie.
Używająć domyślnych wartości dla parametrów ataku attack:
i opadania
decay:
na poziomie 0, sampel przeskakuje bezpośrednio do pełnej amplitudy,
przechodzi w fazę podtrzymania na 0s po czym zanika z powrotem do
amplitudy równej zero przy czym czas zanikania to 0.75s.
Możemy wykorzystać to zachowania aby uzyskać dobry efekt sprawiając, że
sample trwające dłużej będą krótsze, bardziej perkusyjne. Przyjrzyjmy
się samplowi :drum_cymbal_open
:
sample :drum_cymbal_open
Słyszysz dźwięk talerza, który brzmi przez chwilę. Możemy jednak skorzystać z naszej obwiedni aby sprawić by ten dźwięk stał się bardziej perkusyjny:
sample :drum_cymbal_open, attack: 0.01, sustain: 0, release: 0.1
Następnie możesz spróbować zasymulować uderzenie w talerz i stłumienie go poprzez zwiększenie wartości parametru podtrzymania:
sample :drum_cymbal_open, attack: 0.01, sustain: 0.3, release: 0.1
A teraz spróbuj się pobawić nakładająć obwiednie na sample. Próbuj zmieniać wartości różnych parametrów obwiedni aby otrzymać ciekawe rezultaty.
Ta sekcja sfinalizuje nasze odkrywanie odtwarzacza sampli dostępnego w Sonic Pi. Zróbym szybkie podsumowanie. Do tej pory wiemy już w jaki sposób uruchamiać sample:
sample :loop_amen
Następnie dowiedzieliśmy się w jaki sposób można zmieniać parametry sampli, np. w jaki sposób możemy zagrac wybraną próbke w tempie równym połowie normalnego:
sample :loop_amen, rate: 0.5
Kolejną rzeczą jakiej się nauczyliśmy była umiejętność stopniowego wchodzenia sampla (spróbujmy zrobić to dla sampla zagranego w połowie jego normalnego tempa):
sample :loop_amen, rate: 0.5, attack: 1
Dowiedzieliśmy się również, że za pomocą podania konkretnych krótkich
wartości dla parametrów podtrzymania sustain:
oraz ataku możemy
uzyskać perkusyjne brzmienie:
sample :loop_amen, rate: 2, attack: 0.01, sustain: 0, release: 0.35
Jednakże, czy nie było by fajnie gdybyśmy nie musieli zawsze zaczynać odtwarzania sampla od jego początku? Czy nie było by fajnie gdybyśmy nie musieli też zawsze kończyć odtwarzania sampla dopiero w momencie jego końca?
Możliwe jest wybranie bezwzględnego momentu startu, od którego uruchomimy sampel za pomocą podania liczby o wielkości od 0 do 1, gdzie 0 to początek sampla, 1 oznacza koniec sampla, a 0.5 to połowa sampla. Spróbujmy zagrać tylko drugą połowę sampla amen break:
sample :loop_amen, start: 0.5
A teraz spróbujmy zagrać ostatnią ćwiartke sampla:
sample :loop_amen, start: 0.75
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
Nic nam nie stoi na przeszkodzie, abyśmy połączyli oba powyższe parametry aby zagrać wybrane kawałki z danego sampla. Co powiesz na wycięcie tylko małego kawałka ze środka:
sample :loop_amen, start: 0.4, finish: 0.6
Co się stanie jeśli ustawimy moment startu tak aby znajdował się po momencie końca?
sample :loop_amen, start: 0.6, finish: 0.4
Świetnie! Wybrany kawałek jest odtwarzany od końca!
Możemy teraz połączyć tę nową możliwość odtwarzania wybrancyh części dźwięku
z naszym startym dobrym znajomym parametrem tempa rate:
. Na przykład, możemy
zagrać bardzo mały kawałek ze środka sampla amen break w bardzo wolnym tempie:
sample :loop_amen, start: 0.5, finish: 0.7, rate: 0.2
Na sam koniec, możemy połączyć wszytkie powyższe możliwości z naszą obwiednią ADSR aby wyprodukować bardzo ciekawe rezultaty:
sample :loop_amen, start: 0.5, finish: 0.8, rate: -0.2, attack: 0.3, release: 1
A teraz idź i spróbuj pobawić się zmieniając sample wykorzystując cały ten kram…
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.
Kiedy komponujesz twoje utwory opierając się tylko i wyłącznie na wbudowanych syntezatorach i samplach, kod jest jedyną rzeczą, która jest niezbędna aby wiernie odtworzyć twoją muzykę. Pomyśl o tym przez chwilę - to jest niesamowite! Prosty kawałek tekstu, który możesz wysłać pocztą lub trzymać jako Gist przedstawia wszystko czego potrzebujesz aby odtworzyć twoje kawałki. Takie podejście sprawia, że dzielenie się tą muzyką z twoimi znajomymi jest naprawdę proste, gdyż jedyne co muszą zrobić to zdobyć kod.
Jednakże, gdy zaczniesz używać swoich własnych sampli, stracisz tę przenośność. Stanie się tak dlatego, że do odtworzenia twojej muzyki inni ludzie będą potrzebować nie tylko twojego kodu, będą potrzebować również twoich sampli. Takie podejście ogranicza innymi możliwość manipulowania, zmieniania i eksperymentowania z twoją pracą. Oczywiście nie powinno to powstrzymać Cię od używania własnych sampli, to tylko coś co musisz wziąć pod uwagę, gdy się na to zdecydujesz.
W jaki sposób możesz więc zagrać dowolny plik WAV lub AIFF, który
znajduje się na twoim komputerze? Jedyne co musisz zrobic to przekazać
ścieżkę do tego pliku do polecenia sample
:
sample "/Users/sam/Desktop/my-sound.wav"
Sonic Pi automatycznie załaduję i zagra wybrany sampel. Możesz również
przekazać wszystkie standardowe parametry, które do tej pory przekazywałeś
do polecenia sample
:
sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3
Wspaniałym sposobem aby dodać odrobine intrygi do twojej muzyki, jest wykorzystanie paru losowych liczb. Sonic Pi posiada parę fajnych funkcjonalności, które umożliwiają dodanie przypadkowości do twojej muzyki. Zanim jednak zaczniemy musimy nauczyć się jednej szokującej prawdy: w Soni Pi losowość nie jest tak naprawdę losowa. Co to do diaska znaczy? No cóż, zobaczmy.
Bardzo przydatną funkcją do generowania liczb losowych jest rrand
, która
zwróca losową wartość pomiędzy dwoma liczbami - minimum min i maksimum
max. (rrand
to skrót od angielskiego ranged random - liczba losowa
z określonego przedziału). Spróbujmy zagrać losową nutę:
play rrand(50, 100)
Oh, została zagrana losowa nuta. Zagrana nuta to 77.4407
. Fajna liczba
losowa pomiędzy 50 a 100. Zaraz zaraz, czy przypadkiem nie zgadłem dokładnej
wartości losowej nuty, którą przed chwilą otrzymałeś? Dzieje się tu coś
podejrzanego. Spróbuj uruchomić kod ponownie. I co? Znowu została wybrana
liczba 77.4407
? Toć to nie jest liczba losowa!
Odpowiedzią jest fakt, że tak naprawde wynik nie jest naprawdę losowy, jest pseudo losowy. Sonic Pi wygeneruje dla Ciebie liczby, które wyglądają jak losowe w sposób powtarzalny. Takie podejście jest bardzo przydatne jeśli chcesz być pewny, że muzyka, którą tworzysz na swojej maszynie będzie brzmieć identycznie na każdym innym komputerze - nawet jeśli używasz w swojej kompozycji pewnej losowości.
Oczywiście, jeśli w danym utworze, ta ‘losowo wybrana liczba’ będzie
za każdym razem miała wartość 77.4407
, to nie będzie to zbyt interesujące.
Jednakże jest inaczej. Spróbój poniższego kawałka kodu:
loop do
play rrand(50, 100)
sleep 0.5
end
Tak! Wreszcie uzyskaliśmy losowe dźwieki. W ramach danego uruchomienia kolejnych wywołań funkcji losującej zostaną zwrócone wartości losowe. Jendakże, kolejne uruchomienie spowoduje wyprodukowanie dokładnie takiej samej sekwencji losowych wartości i brzmienie będzie takie same jak przy pierwszym uruchomieniu. To tak jakby cały kod Sonic Pi cofnął się w czasie dokładnie do tego samego punktu za każdym razem gdy zostaje wciśnięty przycisk Run (Uruchom). Toć to Dzien Świstaka dla syntezy muzycznej!
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
Innym ciekawym przykładem losowości jest modyfikacja odcięcia
syntezatora losowo. Świetnym syntezatorem, na którym możemy tego
spróbować jest syntezator emulujący :tb303
:
use_synth :tb303
loop do
play 50, release: 0.1, cutoff: rrand(60, 120)
sleep 0.125
end
A co, jeśli nie podoba Ci się ta konkretna sekwencja liczb losowych,
które generuje Sonic Pi? Nic nie stoi na przeszkodzie abyś wybrał
inny punkt rozpoczęcia za pomocą polecenia use_random_seed
. Domyślną
wartością dla funkcji odsiewu (seed?) jest 0, wystarczy więc wybrać
inną wartość aby uzyskać inne wartości losowe.
Weźmy pod uwagę poniższy przykład:
5.times do
play rrand(50, 100)
sleep 0.5
end
Za każdym razem gdy uruchomisz powyższy kod, usłyszysz sekwencję tych samych 5 nut. Aby uzyskać inną sekwencję wystarczy zmienić wartość odsiewu (?seed):
use_random_seed 40
5.times do
play rrand(50, 100)
sleep 0.5
end
Spowoduje to wygenerowanie sekwencji 5 innych losowych nut. Zmieniając parametr odsiewu (?seed) i słuchając wyników jakie to spowodowało, możesz w końcu znaleźć taka sekwencję, która Ci się spodoba - a gdy wtedy podzielisz się nią z innymi, usłyszą oni dokładnie to samo co ty.
A teraz przyjrzyjmy się kilku innym, przydatnym funkcją generującym wartości losowe.
Bardzo popularną rzeczą jest wybór losowego obiektu z listy znanych nam
obiektów. Na przykład, mogę chcieć zagrać jedną z następujących nut:
60, 65 lub 72. Żeby to osiągnąć mogę użyć funkcji choose
, która pozwala
mi na wybór jednego obiektu z istniejącej listy obiektów. Po pierwsze,
muszę wsadzić moje liczby (nuty) do listy. Aby tego dokonać wystarczy,
że opakujemy nasze liczby w nawiasy kwadratowe i oddzielimy każdą z nich
przecinkiem: [60, 65, 72]
. Następnie wystarczy przekazać je jako
parametr do polecenia choose
:
choose([60, 65, 72])
Posłuchajmy zatem jak to brzmi:
loop do
play choose([60, 65, 72])
sleep 1
end
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)
:
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)
:
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
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.
Czasami chciałbyś zasymulować rzut kostką - jest to specyficzny przypadek
dla polecenia rrand_i
, dla którego najniższa liczba to zawsze 1. Uruchomienie
polecenia rzut kostką dice
wymaga abyś podał liczbę oczek na kostce. Standardowa
kostka ma 6 oczek, więc polecenie dice(6)
zachowa się bardzo podobnie -
każde uruchomienie będzie zwracać jedną z wartości 1, 2, 3, 4, 5 lub 6. Jednakże,
tak damo jak w grach RPG (role-playing games), może się zdarzyć, że będziesz
potrzebować kostki o 4 oczkach, albo o 12, albo o 20 - być może będziesz
potrzebować nawet kostki która będzie miała 120 oczek!
Na koniec może się zdarzyć, że będziesz chciał zasymulować wyrzucenie
najlepszego wyniku dla danej kostki, np. 6 oczek dla standardowej kostki.
Polecenie one_in
zwraca prawdę (true) z prawdopodobieństwem, że zostało
wyrzucone jedno oczko. Idąc dalej polecenie one_in(6)
zwróci prawdę (true)
z prawdopodobieństwem 1 do 6-sciu lub fałsz. Wartości prawda (true)
i fałsz (false) są bardzo przydatne przy korzystaniu z polecenie warunkowego
if
, które omówimy w jednej z kolejnych sekcji tego tutoriala.
A teraz, spróbuj trochę zagmatwać twój kod i muzykę odrobiną losowości!
Teraz, kiedy nauczyłeś się podstaw tworzenia dźwięków z wykorzystaniem
poleceń play
i sample
oraz utworzyłeś swoje pierwsze proste melodie
i rytmy korzystając z polecenia sleep
do tworzenia odstępów między
poszczególnymi dźwiękami, zastanawiasz się zapewne co takiego może Ci
jeszcze zaoferować świat kodowania…
Dobrze, jesteś przygotowany na ekscytującą ucztę. Okazuje się, że proste konstrukcje programistyczne, takie jak pętle (looping), instrukcje warunkowe, funkcje mogą stać się dla Ciebie niesamowicie potężnymi narzędziami do wyrażenia twoich muzycznych pomysłów.
Zakasaj rękawy i zabieramy się do podstaw…
Struktura, którą będzie Ci dane zobaczyć w Sonic Pi niezwykle często to blok kodu. Bloki pozwalają nam na robienie wielu przydatnych rzeczy z dużymi kawałkami kodu. Na przykład, w przypadku parametrów syntezatorów i sampli byliśmy w stanie zmieniać coś co działo się w obrębie jednej linii. Jednakże, czasami chcielibyśmy zrobić coś znaczącego dla kilku linii kodu. Na przykład, chcielibyśmy zapętlić coś, potem nałożyć na to efekt reverb, tak, żeby uruchomił się tylko przy 1-wszym przebiegu pętli z wszystkich 5-ciu, itd. Przyjrzyj się poniższemu kawałkowi kodu:
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
Abyśmy mogli zrobić coś z kawałkiem kodu, musimy powiedzieć Sonic Pi gdzie
zaczyna się i kończy dany blok kodu. Aby określić początek takiego bloku
używamy polecenia do, natomiast polecenie end służy do określenia gdzie
dany blok się kończy. Na przykład:
do
do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Jednakże, nie jest to jeszcze całość i nie zadziała (spróbuj uruchomić
powyższy kod a zobaczysz błąd) poneważ nie powiedzieliśmy jeszcze Sonic Pi
co chcielibyśmy zrobić z naszym blokiem zawartym pomiędzy poleceniami
do/end. Aby powiedzieć Sonic Pi co chcemy zrobić z tym kawałkiem musimy
napisać kawałek specjalnego kodu przed poleceniem do
. Zobaczysz jeszcze
wiele takich różnych specjalnych kawałków kodu w kolejnych sekcjach tego
samouczka. Na razie, najważniejsze jest abyś wiedział, że umieszczenie twojego
kodu pomiędzy polecenia do
i end
mówi Sonic Pi, że chciałbyś zrobić
z tym kawałkiem kodu coś specjalnego.
Do tej pory spędziliśmy sporo czasu patrząc na różne dźwięki, które
możesz zrobić użyciem bloków play
i sample
. Nauczyliśmy się również
w jaki sposób uruchamiać te dźwięki na przestrzeni czasu używając
polecenia sleep
.
Jak zapewne już zauważyłeś, przy korzystaniu z tych kilku podstawowych bloków możesz mieć całą masę frajdy. Jednakże, kiedy zaczniesz wykorzystywać możliwości kodu do porządkowania twojej muzyki i kompozycji, twoim oczom ukaże się zupełnie nowy wymiar możliwości i zabawy. W najbliższych kilku sekcjach poznasz kilka z tych potężnych narzędzi. Na początek zaczniemy od iteracji i pętli.
Czy zdarzyło ci się napisać kawalek kodu, który chciałbyś powtórzyć kilka razy? Przypuścmy, że napisałeś coś w tym stylu:
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
Co jeśli chciałeś aby powyższy kawałek powtórzył się 3 razy? Najprostsze co mógłbyś zrobić to po prostu skopiować i wkleić powyższy kawałek kodu trzy razy:
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
Zobacz ile kodu! Pomyśl, co trzeba by było zrobić, gdybys chciał zmienić
sampel na :elec_plip
? Musiałbyś wtedy znaleźć w kodzie wszystkie miejca
gdzie użyłeś oryginalnego sampla :elec_blup
a zmienić je ręcznie.
Ale to i tak nic, pomyśl co by było gdybyś chciał powtórzyć oryginalny
blok kodu 50 albo 1000 razy? Dopiero teraz byłoby to dużo kodu, bardzo
dużo kodu, który musiałbyś zmienić, gdybyć chciał dokonać tak prostej
zmiany jak przełączenie się na inny sampel.
W rzeczywistości, powtórzenie kodu powinno być tak proste jak powiedzenie
zrób to trzy razy. Dobrze, w dużym stopniu tak jest. Pamiętasz naszego
starego dobrego znajomego - blok kodu? Możemy użyć go aby zaznaczyć
miejsce początku i końca kodu, który chcielibyśmy powtórzyć 3 razy. Następnie
wystarczy, że użyjemy specjalnego kawałka kodu 3.times
(3.razy).
Zamiast więc napisać zrób to trzy razy, napiszemy 3.times do
- to nie
jest zbyt trudne. Pamiętaj tylko aby napisać polecenie end
na końcu
bloku kodu, który zamierzać powtórzyć:
3.times do
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
end
Przyznasz, że takie podejście jest dużo bardziej eleganckie niż kopiowanie i wklejanie! Możemy użyć tego specjalnego polecenia to tworzenia wielu fajnych powtarzających się struktur:
4.times do
play 50
sleep 0.5
end
8.times do
play 55, release: 0.2
sleep 0.25
end
4.times do
play 50
sleep 0.5
end
Możemy umieszczać jedne iteracje wewnątrz innych iteracji to utworzenia ciekawych wzorców. Na przykład:
4.times do
sample :drum_heavy_kick
2.times do
sample :elec_blip2, rate: 2
sleep 0.25
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
Jeśli chcesz powtórzyć coś wiele razy, możesz złapać się na tym, że będziesz
podawał naprawdę bardzo duże liczby jako parametr iteracji, na przykład
1000.times do
. W takim przypadku zapewne dużo lepiej byłoby poprosić
Sonic Pi aby powtarzać dany wzorzec w nieskończoność (a przynajmniej do
momentu w którym naciśniesz przycisk Stop aby zatrzymać odtwarzanie!).
Spróbujmy zapętlić w nieskończoność sampel Amen Break:
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
Bardzo ważną rzeczą do zapamiętania o pętlach jest to, że dla kodu mają one takie same zachowanie jak czarne dziury. Jak tylko kod raz już wejdzie w daną pętlę może już jej nigdy nie opuścić, chyba że naciśniesz przycisk Stop - nasza pętla będzie się kręcić w kółko w nieskończoność. Oznacza to, że jeśli masz jakiś kod, który jest umieszczony po pętli, to nigdy go nie usłyszysz. Na przykład, talerz, który znajduje się poniżej poniższej pętli nie zostanie zagrany nigdy:
loop do
play 50
sleep 1
end
sample :drum_cymbal_open
A teraz, spróbuj poprawić strukturę twojego kodu za pomocą iteracji i pętli!
Bardzo prawdopodobne jest, że często będziesz chciał zagrać nie tylko
losową nutę (patrz poprzednia sekcja dot. losowości) lecz również
będziesz chciał podejmować losowe decyzje i na podstawie ich wyniku będziesz
chciał uruchomić taki lub inny kod. Na przykład, mógłbyś chcieć aby
losowo zagrać bęben lub talerz perkusji. Możemy tego dokonać używając
polecenia warunkowego if
(jeśli).
Spróbujmy rzucić monetą: jeśli (if) wypadnie orzeł, zagraj bęben, jeśli
wypadnie reszka reszka (else), zagraj talerz. Proste. Możemy zasymulować
rzut monetą wykorzystując naszą funkcję one_in
(poznaliśmy ją w sekcji
dotyczącej losowości) określając prawdopodobieństwo wyboru 1 z 2: one_in(2)
.
Następnie możemy użyć tego wyniku aby wybrać do zagrania jeden z dwóch
kawałków kodu - jeden, który zagra bęben i drugi, który zagra talerz:
loop do
if one_in(2)
sample :drum_heavy_kick
else
sample :drum_cymbal_closed
end
sleep 0.5
end
Zauważ, że polecenie warunkowe if
posiada 3 części:
Zazwyczaj w językach programowania, pojęcie odpowiedzi tak jest
reprezentowane przez termin true
(prawda), natomiast pojęcie
odpowiedzi nie jest reprezentowane przez termin false' (nieprawda,
fałsz). Do nas więc należy znalezienie odpowiedniego pytania, którego
zadanie zwróci nam odpowiedź
true (prawda) lub
false (fałsz).
W tym wypadku naszym pytaniem jest uruchomienie funkcji
one_in`.
Zauważ, że pierwszy wybór jest wpasowany pomiędzy polecenia if
(jeśli)
a else
(w przeciwnym razie), natomiast drugi wybór mieści się pomiędzy
poleceniami else
i end
(koniec). Tak samo jak w przypadku bloków
kodu do/end, pomiędzy obiema tymi przestrzeniami możesz napisać wiele
linii kodu. Oto przykład:
loop do
if one_in(2)
sample :drum_heavy_kick
sleep 0.5
else
sample :drum_cymbal_closed
sleep 0.25
end
end
Tym razem, w zależności od tego jaka decyzja została wylosowana
śpimy (sleep
) przez różnie długości czasu.
Czasami chciałbyś wykonać opcjonalnie tylko jedną określoną linię kodu.
Aby to osiągnąć wystarczy umieścić polecenie if
wraz z naszym pytaniem
(warunkiem) na końcu tej linii. Oto przykład:
use_synth :dsaw
loop do
play 50, amp: 0.3, release: 2
play 53, amp: 0.3, release: 2 if one_in(2)
play 57, amp: 0.3, release: 2 if one_in(3)
play 60, amp: 0.3, release: 2 if one_in(4)
sleep 1.5
end
Powyższy kod zagra akordy złożone z różnych liczb. Szansa na to, że każda z podanych nut zostanie zagrana jest różna, gdyż każda z linijek (oprócz pierwszej) jest opatrzona warunkiem o różnym prawdopodobieństwie wystąpienia.
A więc udało Ci się przygotować zabójczy bassline oraz tłusty beat. W jaki sposób udaje Ci się je zagrać w tym samym czasie? Jednym z możliwych rozwiązań jest przeplecenie ich razem ręcznie - najpierw zagrać jakis bas, potem trochę bębnów, potem znowu bas… Jednakże, bardzo szybko chronometraż stanie się czymś, o czym będzie ciężko myśleć, zwłaszcza kiedy zaczniemy wplatać do naszej kompozycji kolejne elementy.
A co jeśli Sonic Pi mógłby przeplatać różne elementy za Ciebie automagicznie? Takie coś jest możliwe i możesz to robić używając specjalnego polecenia nazywanego wątkiem - thread.
Aby sprawić by kolejny przykład był prosty, musisz sobie wyobrazić jak
wygląda ten tłusty beat i zabójczy bassline:
loop do
sample :drum_heavy_kick
sleep 1
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Jak już wcześniej mówiliśmy, pętle są jak czarne dziury dla naszych programów. Gdy już raz wejdziesz do pętli nie wyjdziesz z niej nigdy, chyba że naciśniesz Stop. W jaki zatem sposób możemy zagrać obie pętle jednocześnie? Musimy powiedzieć Sonic Pi, że chcemy rozpocząć coś w tym samym czasie gdy uruchamiamy pozostały kod. To jest właśnie moment, w którym z pomocą przychodzą nam Wątki (ang. threads).
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Jeśli otoczymy pierwszą pętlę blokiem kodu do/end in_thread
, to w ten
sposób powiemy Sonic Pi żeby uruchomił zawartość tego bloku do/end
dokładnie w tym samym czasie, gdy zostają uruchomione kolejne polecenia,
które znajdują się tuż za blokiem kodu (w tym przypadku jest to druga pętla).
Spróbuj uruchomić ten kod a usłysz jednocześnie bębny oraz bassline, które
są przeplecione i grają jednocześnie!
A co teraz, jeśli chcielibyśmy dodać jeszcze jakiś syntezator (synth). Coś w tym stylu:
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Znowu mamy taki sam problem jak przed chwilą. Pierwsza pętla jest uruchomiona
w tym samym momencie co druga pętla ze względu na to, że użyliśmy polecenia
in_thread
. Jednakże, trzecia pętla nigdy nie zostaje uruchomiona. Żeby to
naprawić potrzebujemy kolejnego wątku (thread):
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
in_thread do
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Coś co może być dla Ciebie zaskakujące, to fakt, że gdy naciskasz przycisk Run, to w rzeczywistości tworzysz nowy wątek do uruchomienia twojego kodu. Dlatego też, gdy naciśniesz przycisk uruchom wiele razy to dźwięki zaczną nakładać się na siebie. Jako, że kolejne uruchomienia same są po prostu wątkami, to dźwięki zostaną dla Ciebie automatycznie poprzeplatane.
Gdy już nauczysz się w jaki sposób opanować Sonic Pi, nauczysz się również
tego, że wątki są jednym z najważniejszych materiałów używanych do
tworzenia twojej muzyki. Jednym z ważnych zadań, które do nich należą
to izolacja pojęcia aktualnych ustawień od innych wątków. Co to oznacza?
Otóż, kiedy zmieniasz syntezatory poleceniem use_synth
w rzeczywistości
po prostu zmieniasz syntezator dla aktualnego wątku (current thread)
- w żadnym innym wątku syntezator się nie zmieni. Zobaczmy te zachowanie
w akcji:
play 50
sleep 1
in_thread do
use_synth :tb303
play 50
end
sleep 1
play 50
Zauważyłeś, że środkowy dźwięk był inny od pozostałych? Polecenie
use_synth
wpłynęło tylko na to co zostało uruchomione w wątku, natomiast
pozostała, zewnętrzna część kodu została nietknięta.
Kiedy utworzysz nowy wątek z wykorzystaniem in_thread
, nowy wątek
automatycznie odziedziczy wszsystkie aktualne ustawienia z bieżącego
wątku. Spójrzmy na taki kod:
use_synth :tb303
play 50
sleep 1
in_thread do
play 55
end
Zauważyłeś, że druga nuta zostaje zagrana z użyciem syntezatora :tb303
mimo to, że została zagrana z oddzielnego wątku? Każde ustawienie
zmienione przy użyciu różnych funkcji use_*
będą zachowywać się tak samo.
Kiedy są tworzone kolejne wątki, dziedziczą one wszystkie ustawienia ze swoich rodziców, natomiast jakiekolwiek zmiany nie są udostępniane z powrotem.
Na koniec, możemy nadawać naszym Wątkom nazwy:
in_thread(name: :bass) do
loop do
use_synth :prophet
play chord(:e2, :m7).choose, release: 0.6
sleep 0.5
end
end
in_thread(name: :drums) do
loop do
sample :elec_snare
sleep 1
end
end
Spójrz na panel z logiem kiedy uruchomisz ten kod. Czy widzisz jak w logach przy kolejnych wiadomościach pojawiają się nazwy wątków?
[Run 36, Time 4.0, Thread :bass]
|- synth :prophet, {release: 0.6, note: 47}
Jedną ostatnią już rzecz, którą powinieneś wiedzieć o wątkach posiadających swoją nazwę to to, że w tym samym czasie może być uruchomiony tylko jeden wątek o tej samej nazwie. Spróbujmy to zbadać. Weźmy pod uwagę następujący kod:
in_thread do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Sróbuj śmiało wkleić powyższy kod do obszaru roboczego i naciśnij przycisk Run. Następnie naciśnij go jeszcze kilka razy. Usłyszysz kakofonię wielu zapętlonych w czasie sampli Amen Break. Ok, możesz teraz nacisnać przycisk Stop.
To jest zachowanie, które widzieliśmy już nie raz - jeśli naciśniesz przycisk Run, dźwięk zostanie nałożony na istniejące już dźwięki. Dlatego jeśli masz pętle i naciśniesz przycisk Run trzy raz, to będziesz miał trzy warstwy pętli, które będą grane jednocześnie.
Jednakże, w przypadku nazwanych wątków jest inaczej:
in_thread(name: :amen) do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Spróbuj teraz dla tego kodu nacisnąć przycisk Run kilkukrotnie. Nie usłyszysz teraz więcej niż jedną pętlę amen na raz. W logach zauważysz również taką wiadomość:
==> Skipping thread creation: thread with name :amen already exists.
Sonic Pi mówi Ci, że wątek o nazwie :amen
już istnieje, nie zostanie
więc utworzony kolejny.
Takie zachowanie może się teraz nie wydawac do niczego przydatne - ale będzie bardzo przydatne kiedy zaczniemy kodować na żywo…
Gdy już zaczniesz pisać znaczne ilości kodu, to w pewnym momencie będziesz chciał znaleźć sposób aby uporządkować i poukładać go tak aby był one elegancki i łatwiejszy do zrozumienia. Funkcje są bardzo skutecznym sposobem, który to umożliwia. Pozwalają nam nadać kawałkowi kodu nazwę. Rzućmy na to okiem.
define :foo do
play 50
sleep 1
play 55
sleep 2
end
W powyższym przykładzie zdefiniowaliśmy nową funkcję zwaną foo
. Zrobiliśmy
to używając naszego dobrego znajomego bloku do/end oraz magicznego słowa
define
, po którym podaliśmy nazwę, którą chcemy nadać naszej funkcji.
Nie musieliśmy nazywać jej foo
, mogliśmy nazwać ją jak tylko mamy ochotę,
np. bar
, baz
albo idealnie pasowałoby, gdybyśmy nadali jakąs nazwę,
która coś znaczy, np. czesc_glowna
albo glowna_gitara
.
Pamiętaj tylko aby poprzedzić nazwę dwukropkiem :
gdy definiujesz nową
funkcję.
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.
Jak do tej pory, za każdym razem gdy nacisnąłeś przycisk Run, Sonic Pi zaczynał od czystej tablicy. Nie wiedział nic poza tym co znajduje się aktualnej przestrzeni roboczej. Nie możesz odnosić się do kodu w innych przestrzeniach roboczych lub innym wątku. Możliwość korzystania z funkcji zmienia to. Kiedy zdefiniujesz funkcję, Sonic Pi zapamiętuje ją. Spróbujmy to wykorzystać. Usuń cały kod znajdujący się w twojej aktualnej przestrzeni roboczej i zastąp go następującą linią:
foo
Naciśnij przycisk Run - usłyszysz jak gra twoja funkcja. Skąd się wziął
ten kod? Skąd Sonic Pi wiedział co powinien zagrać? Sonic Pi po prostu
zapamiętał wcześniej twoją funkcję - więc nawet po tym jak już ją skasujesz
z twojej przestrzeni roboczej, to będzie on pamiętał to co wcześniej
napisałeś. Ten mechanizm działa tylko z funkcjami stworzonymi z wykorzystaniem
polecenia define
(oraz defonce
).
Być może zainteresuje Cie fakt, że tak samo jak możesz przekazywać wartości
minimalną (min) i maksymalną (max) do funkcji rrand
, tak samo możesz nauczyć
twoją funkcję aby potrafiła przyjmować różne argumenty. Spójrzmy na następujący
kod:
define :my_player do |n|
play n
end
my_player 80
sleep 0.5
my_player 90
Nie jest on za bardzo ekscytujący, ale świetnie przedstawia o co chodzi.
Stworzyliśmy naszą własną wersję polecenia play
, która przyjmuje
parametr i nazwaliśmy ją my_player
.
Parametry należy umieścić tuż za poleceniem do
bloku kodu define
,
otoczyć pionowymi kreskami |
oraz oddzielić przecinkami ,
. Możesz
użyć dowolnego słowa jakiego chcesz dla nazw parametrów.
Magia dzieje się w środku bloku do/end define
. Możesz używać nazw
parametrów tak jak byłyby prawdziwymi wartościami. W powyższym przykładzie
gram nutę n
. Możesz patrzeć na parametry jak na swego rodzaju obietnice,
która mówi o tym, że gdy kod zostanie uruchomiony, to zostaną one zastąpione
aktualnymi wartościami. Możesz to zrobić poprzez przekazanie parametru
do funkcji gdy ją uruchamiasz. Uruchamiam polecenie my_player 80
aby
zagrać nutę 80. Wewnątrz definicji funkcji, n
zostanie zamienione na 80,
więc polecenie play n
przemieni się w play 80
. Kiedy uruchomię ją
ponownie w taki sposób my_player 90
, to teraz n
zostanie zastąpione
przez 90, więc polecenie play n
będzie zmieni się teraz w polecenie
play 90
.
Przyjrzyjmy się teraz bardziej interesującemu przykładowi:
define :chord_player do |root, repeats|
repeats.times do
play chord(root, :minor), release: 0.3
sleep 0.5
end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3
Użyłem tutaj parametru repeats
w linii repeats.times do
tak jakby
był liczbą. Użyłem również parametru root
dla polecenia play
tak,
jakby był normalną nazwą nuty.
Zauważ, że poprzez przeniesienia dużej ilości logiki do funkcji, jesteśmy teraz w stanie napisać coś bardzo ekspresyjnego a zarazem łatwego do przeczytania!
Przydatną rzeczą, którą możesz robić w swoim kodzie jest tworzenie
nazw dla różnych rzeczy. Sonic Pi sprawia, że jest to bardzo łatwe,
wpisujesz nazwę, której chciałbyś użyć, znak równości (=
), następnie
rzecz, którą chcialbyś zapamiętać:
sample_name = :loop_amen
W powyższym kawałku kodu ‘zapisaliśmy’ wartość symbolu :loop_amen
w zmiennej sample_name
. Od teraz możemy używać nazwy sample_name
wszędzie, gdzie do tej pory użylibyśmy sampla :loop_amen
. Na przykład:
sample_name = :loop_amen
sample sample_name
Są trzy podstawowe powody na korzystanie ze zmiennych w Sonic Pi: komunikowanie znaczenia, zarządzanie powtórzeniami oraz przechwytywanie wyników różnych rzeczy.
Kiedy piszesz kod łatwo jest myśleć, że jedyne co robisz to mówisz komputerowi jak ma wykonać jakieś rzeczy - tak długo jak komputer rozumie co do niego mówisz to jest w porządku. Jednakże, ważne jest aby pamiętać że nie tylko komputer czyta kod. Inni ludzie również mogą chcieć przeczytać go i spróbować zrozumieć co się w nim dzieje. Ponadto, bardzo prawdopodobne, że Ty również będziesz czytał swój własny kod w przyszłości i próbował zrozumieć o co w nim chodzi. Chociaż w tej chwili jego znaczenie może być dla Ciebie oczywiste - może nie być takie oczywiste dla innych lub nawet dla Ciebie samego w przyszłości!
Jedną z metod, która pomoże innym zrozumieć co twój kod robi jest pisanie komentarzy (co widzieliśmy już we wcześniejszej sekcji tego samouczka). Inną jest używanie takich nazw dla zmiennych, które coś znaczą. Spójrz na poniższy kod:
sleep 1.7533
Dlaczego używa on liczby 1.7533
? Skąd wzięła się ta liczba? Co ona
oznacza? A teraz, spójrz na poniższy kod:
loop_amen_duration = 1.7533
sleep loop_amen_duration
Teraz, zrozumienie tego co oznacza liczba 1.7533
jest znacznie prostsze:
oznacza ona dłuość trwania sampla :loop_amen
! Oczywiście, możesz zapytać,
dlaczego po prostu nie napisaliśmy:
sleep sample_duration(:loop_amen)
Co, jak najbardziej, jest bardzo fajnym sposobem zakomunikowania intencji zawartych w kodzie.
Często widzisz dużo powtórzeń w twoim kodzie i kiedy chcesz coś zmienić, musisz zmienić to w wielu miejscach. Spójrz na poniższy kawałek kodu:
sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)
Robiliśmy tutaj sporo rzeczy z samplem :loop_amen
! Co jeśli
chcielibyśmy usłyszeć, jak ten kawałek kodu brzmi z innym samplem,
na przykład :loop_garzul
? Musielibyśmy wtedy znaleźć i zamienić
wszystkie wystąpienia sampla :loop_amen
na :loop_garzul
. To może
być całkiem w porządku jeśli masz dużo czasu - ale co jeśli właśnie
występujesz na scenie? Czasami nie masz tego luksusu, że masz czasu
tyle ile chcesz - zwłaszcza gdy chcesz utrzymać ludzi na parkiecie.
A co jeśli powyższy kawałek kodu przepiszemy na coś takiego:
sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)
Teraz, ten kod robi dokładnie to samo co wcześniejszy (spróbuj). Oprócz
tego daje na możliwość zmiany tylko jednej linijki z obecnej
sample_name = :loop_amen
na sample_name = :loop_garzul
aby
jednocześnie zmienić brzmienie w wielu miejscach dzięki magii zmiennych.
I na koniec, dobrą powodem do używania zmiennych jest przechwytywanie wyniku wykonania różnych rzeczy. Na przykład, możesz chcieć robić różne rzeczy z długością trwania sampla:
sd = sample_duration(:loop_amen)
Możemy teraz używać zmiennej sd
wszędzie gdzie potrzebujemy użyć
długości trwania sampla :loop_amen
.
Możliwe, że nawet bardziej ważne jest to, że zmienne pozwalają nam
na przechwycenie i zapisanie wyniku uruchomienia polecenia play
lub sample
:
s = play 50, release: 8
Teraz złapaliśmy i zapamiętaliśmy s
jako zmienną, co pozwala nam
na kontrolę syntezatora w trakcie jego działania:
s = play 50, release: 8
sleep 2
control s, note: 62
Przyjrzymy się bardziej kontrolowaniu syntezatorów w kolejnej sekcji.
Skoro osiągnąłeś już wystarczająco zaawansowane umiejętności kodowania na żywo (live coding) wraz z wykorzystaniem jednocześnie funkcji i wątków, na pewno zauważyłeś już, że bardzo łatwo jest popełnić błąd w jednym z wątków co powoduje, że zostaje on zabity. To nie jest wielka rzecz, ponieważ możesz bardzo łatwo zrestartować wątek poprzez ponowne naciśnięcie przycisku Run. Jednakże, kiedy zrestartujesz wątek to wypadnie on teraz z rytmu oryginalnych wątków.
Jak już mówiliśmy wcześniej, nowe wątki tworzone z wykorzystaniem polecenia
in_thread
dziedziczą wszystkie ustawienia z wątku rodzica. W skład
tych ustawień wchodzi też aktualny czas. Oznacza to, że wątki pozostają
zawsze w korelacji czasowej kiedy zostaną uruchomione jednocześnie.
Jendakże, kiedy uruchomisz samodzielny wątek, rozpoczyna się on ze swoim własnym czasem i jest mało prawdopodobne, że będzie on w synchronizacji z jakimkolwiek innym uruchomionym aktualnie wątkiem.
Sonic Pi udostępnia rozwiązanie dla tego problemu za pomocą funkcji
cue
(wskazówka) i sync
(synchronizacja).
cue
pozwala nam na wysłanie wiadomości o pulsie to wszystkich innych
aktualnie uruchomionych wątków. Domyślnie inne wątki nie są tym zainteresowane
i ignorują tę wiadomość o pulsie. Jendakże, możesz bardzo łatwo wywołać
takie zainteresowanie za pomocą funkcji sync
.
Ważną rzeczą, której należy być świadomym jest to, że funkcja sync
jest podobna do funkcji sleep
w taki sposób, że powstrzymuje ona
aktualny wątek od robienia czegokolwiek przez pewien okres czasu.
Jednakże, w przypadku funkcji sleep
musisz zdefiniować jak długo
chcesz poczekać, natomiast w przypadku funkcji sync
nie wiesz jak
długo będziesz chicał poczekać, ponieważ funkcja sync
czeka na
następny punkt cue
z innego wątku, co może nastąpić szybciej lub
później.
Spróbujmy przyjrzeć się temu trochę bardziej dokładnie:
in_thread do
loop do
cue :tick
sleep 1
end
end
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Mamy tutaj dwa wątki - jeden zachowuje się jak metronom, nie gra żadnych
dźwięków tylko wysyła komunikat :tik
(cyk) przy każdym uderzeniu. Drugi
wątek synchronizuje się natomiast przy otrzymaniu każdej kolejnej wiadomości
:tick
i kiedy otrzymuje kolejną odziedzicza czas uruchomienia cue
i rozpoczyna swoje działanie.
Jako wynik słyszymy sampel :drum_heavy_kick
dokładnie w tym samym momencie
gdy inny wątek wysyła komunikat :tick
, nawet jeśli obydwa wątki nie
zostały uruchomione w tym samym czasie.
in_thread do
loop do
cue :tick
sleep 1
end
end
sleep(0.3)
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Te niegrzeczne polecenie sleep
normalnie stworzyłoby drugi wątek,
który byłby zupełnie niezsynchronizowany z pierwszym. Jednakże, dzięki
użyciu poleceń cue
i sync
automatycznie synchronizujemy wątki blokując
jednocześnie jakiekolwiek nieprzewidziane rozjazdy w czasie.
Dla nazw twoich komunikatów cue
możesz używać dowolnych nazw - może to
być nie tylko :tick
. Musisz się tylko upewnić, że inne wątki
sync
hronizują 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
.
Jednym z najbardziej satysfakcjonujących aspektów Sonic Pi jest możliwość łatwego dodawania efektów studyjnych do twoich brzmień. Na przykład, być może zdarzy się, że będziesz chciał dodać trochę efektu reverb (pogłos) do pewnych części twojego kawałka, albo trochę echa albo może nawet efektu distort czy wobble do twojej linii basowej.
Sonic Pi udostępnia bardzo prosty a jednocześnie potężny sposób na dodawanie takich efektów (FX). Pozwala on nawet na łączenie ich (możesz więc przepuścić twoje brzmienie kolejno przez efekt distortion/overdrive?, potem przez echo i na końcu przez reverb) i jednocześnie daje Ci możliwość kontrolowania każdego z nich indywidualnie za pomocą parametrów (w podobny sposób do tego w jaki przekazujemy parametry do syntezatorów czy sampli). Możesz nawet modyfikować parametry efektu (FX) gdy wciąż jest uruchomiony. Możesz więc, na przykład, zwiększyć wartość efektu reverb twojej sekcji basowej na przestrzeni całego utworu…
Jeśli wszystko to brzmi dla ciebie trochę zbyt skomplikowanie, nie przejmuj się. Gdy już trochę się tym pobawisz, wszystko stanie się całkiem jasne. Zanim jednak to nastąpi, wprowadzę prostą analogię do efektów (FX) gitarowych. Istnieje wiele rodzajów takich efektów (FX), które możesz kkupić. Pewne z nich dodają efekt reverb, inne distort, itd. Gitarzyści podłączają swoją gitarę do jednego z efektów (FX), tzw. pedałów gitarowych - np. distortion. Następnie biorą kabel i łączą ten efekt z kolejnym, np. efektem reverb. Na koniec wyjście z efektu reverb może być podłączone do wzmacniacza:
Gitara -> Distortion -> Reverb -> Wzmacniacz
Nazywa się to łączeniem efektów w łańcuch. Sonic Pi wspiera taki właśnie model dla swoich efektów. Dodatkowo, każdy z efektów posiada pokrętła i suwaki pozwalające Ci na kontrolę tego jak mocny ma być efekt distortion, reverb, echo, itd. Sonic Pi wspiera taką kontrolę. Na konic, możesz wyobrazić sobie grającego gitarzystę podczas gdy ktoś inny w tym samym czasie bawi się i kontroluje efekty (FX). Sonic Pi również wspiera taką możliwość - tylko, że zamiast innej osoby do kontrolowania tych efektów, na scenę wkroczy w tym wypadku komputer.
Poznajmy zatem efekty (FX)!
W tej sekcji przyjrzymy się kilku efektom (FX): reverb i echo. Zobaczymy w jaki sposób ich używać, w jaki sposób kontrolować ich parametry oraz jak łączyć je ze sobą w jeden łańcuch.
System efektów w Sonic Pi korzysta z bloków kodu. Jeśli więc do tej pory nie przeczytałeś jeszcze sekcji 5.1, to teraz jest dobry moment by nadrobić zaległości.
Jeśli chcemy użyć efektu reverb wystarczy, że napiszemy with_fx :reverb
jako specjalny kawałek kodu dla naszego bloku do/end:
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
A teraz uruchom ten kod a usłyszysz jak jest zagrany z nałożonym na niego efektem reverb. Brzmi nieźle, prawda?! Wszystko brzmi całkiem fajnie z efektem reverb.
A teraz zobaczmy co się wydarzy, gdy umieścimy jakiś dodatkowy kod poza naszym blokiem do/end:
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
sleep 1
play 55
Zauważ, że ostania linia play 55
nie jest zagrana z efektem reverb.
Dzieje się tak ponieważ znajduje się poza blokiem kodu do/end, więc
dzięki temu nie jest objęta efektem reverb.
Analogicznie, jeśli zrobisz jakieś dźwięki przed blokiem do/end, to one również nie będą pod wpływem efektu reverb:
play 55
sleep 1
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
sleep 1
play 55
Jest wiele efektów do wyboru. Co powiesz na echo?
with_fx :echo do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Jednym z potężnych aspektów bloków efektów w Sonic Pi jest to, że można
do nich przekazywać parametry podobne do parametrów, które już widzieliśmy
gdy korzystaliśmy z poleceń play
i sample
. Na przykład bardzo fajnym
parametrem, który nieźle brzmi z efektem echo jest phase:
. Reprezentuje
on czas trwania danego efektu przez określoną liczbę uderzeń (ile uderzeń trwa efekt).
Spróbujmy sprawić aby efekt echo był trochę wolniejszy:
with_fx :echo, phase: 0.5 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Spróbujmy też sprawić aby echo brzmiało szybciej:
with_fx :echo, phase: 0.125 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Sprawmy teraz aby zanikanie echa trwało dłużej ustawiając parametr
decay
na 8 sekund:
with_fx :echo, phase: 0.5, decay: 8 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Jednym z najbardziej potężnych aspektów bloków zawierających efekty jest to, że możesz je zagnieżdzać. Pozwala to na bardzo łatwe łączenie ich razem. Na przykład, co jeśli chciałeś zagrać kawałek jakiegoś kodu z efektami echo i reverb? Łatwizna, po prostu umieść jeden w drugim:
with_fx :reverb do
with_fx :echo, phase: 0.5, decay: 8 do
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
end
end
Pomyśl o przepływie dźwięku ze środka na zewnątrz. Dźwięk z najbardziej
wewnętrznego bloku kodu, np. play 50
jest najpierw wysyłany do
efektu echo, następnie dźwięk z nałożonym echo jest z kolei wysyłany
do efektu reverb.
Możemy używać wielu takich zagnieżdżeń dlo osiągania zwariowanych wyników. Jednakże uważaj, efekty mogą zużywać sporo zasobów. Zagnieżdżając jeden w drugim uruchamiasz wiele efektów na raz. Bądź więc oszczędny z ich używaniem, zwłaszcza na platformach o słabych parametrach (procesor, pamięć, itd.) na przykład takich jak Raspberry Pi.
Sonic Pi posiada wiele wbudowanych efektów, z których możesz korzystać. Aby zobaczyć jakie z nich są dostępne, kliknij na ikonie Fx (efekty) w sekcji pomocy a zobaczysz listę wszystkich dostępnych opcji. Oto kilka moich ulubionych:
A teraz powariuj trochę i dodaj efektów wszędzie gdzie tylko możesz aby stworzyć zdumiewające nowe dźwięki!
Pomimo, że na pierwszy rzut oka wyglądają one na zwodniczo łatwe, to od środka efekty są tak naprawde bardzo złożonymi bestiami. Ich prostota bardzo często kusi ludzi by naduzywać ich w swoich kawałkach. Może to być w porządku jeśli masz dobry i wydajny komputer, ale jeśli - tak jak ja - korzystasz z Raspberry Pi do jam’owania, musisz być wtedy bardzo ostrożny z tym ile pracy mu zlecisz do wykonania, jeśli chcesz być pewny, że beat zachowa swą płynność.
Rozważ taki kawałek kodu:
loop do
with_fx :reverb do
play 60, release: 0.1
sleep 0.125
end
end
W powyższym kawałku kodu zagraliśmy nutę 60 z bardzo krótkim czasem zanikania (release), więc jest to bardzo krótka nuta. Chemy również nałożyć na nią efekt reverb, więc opakowaliśmy ją w blok reverb. Jak na razie wszystko w porządku. Z wyjątkiem…
Przyjrzyjmy się co ten kod tak naprawdę robi. Na początku mamy
pętlę loop
co oznacza, że wszystko wewnątrz niej będzie powtarzane
w nieskończoność. Następnie mamy blok with_fx
. Oznacza to, że utworzymy
nowych efekt FX dla każdej iteracji pętli loop
. To tak jakbyśmy
chcieli mieć odzielny efekt gitarowowy reverb przy każdym jednym uderzeniu
w strunę gitary. Fajnie, że możemy tak zrobić, ale nie zawsze jest to
coś co chciałbyś osiągnąć. Na przykład, ten kawałek kodu czeka niezła
walka aby został on ładnie uruchomiony na Raspberry Pi. Cała praca
potrzebna do stworzenia efektu reverb a potem czekanie do momentu,
w którym będzie wymagał zatrzymania i usunięcia jest obsługiwana
za Ciebie przez funkcję with_fx
, zajmie to jednak sporo mocy
procesora (CPU), która może okazać się bardzo cenna.
A co jeśli sprawimy, by ten kod był bardziej podobny do tradycyjnego zestawu, gdzie nasz gitarzysta posiada tylko jeden efekt reverb i to przez niego przechodzą wszystkie dźwięki? Łatwizna:
with_fx :reverb do
loop do
play 60, release: 0.1
sleep 0.125
end
end
Umieściliśmy naszą pętęlę wewnątrz bloku with_fx
. W ten sposób
tworzymy tylko jeden efekt reverb dla wszystkich nut, które zostaną
zagrane w naszej pętli. Taki kod jest dużo bardziej wydajny i na pewno
będzie działał w porządku na Raspberry Pi.
Kompromisem może też być użycie efektu with_fx
wewnątrz pętli loop,
ale powyżej iteracji wewnętrznej:
loop do
with_fx :reverb do
16.times do
play 60, release: 0.1
sleep 0.125
end
end
end
W ten sposób przenieśliśmy efekt with_fx
na zewnątrz wewnętrznej części
pętli loop
i teraz tworzymy nowy efekt reverb tylko co 16 zagranych
nut.
Pamiętaj jedno - błędów nie ma, sa tylko nowe możliwości. Jednakże, każdy z powyższych podejść będzie miał inne brzmienie oraz inną charakterystykę wydajności. Staraj się więc używać takiego podejścia, które będzie brzmiało najlepiej mając jednocześnie na uwadze fakt pracy z ograniczeniami wydajnościowymi twojego komputera/platformy na której pracujesz.
Do tej pory dowiedzieliśmy się jak możemy wyzwalać syntezatory i sample oraz w jaki sposób zmieniać ich domyślne parametry takie jak amplituda, kanał, ustawienia obwiedni i inne. Każdy uruchomiony dźwięk jest w zasadzie osobnym dźwiękiem z jego własnym zestawem parametrów ustalonych na czas trwania dźwięku.
Czy nie było by super gdybyś mógł zmieniać parametry dźwięku w trakcie odtwarzania danego dźwięku, tak samo jak możesz naciągnać struny gitary gdy jej struny wciąż wibruja?
Masz szczęście - ten rozdział pokaże Ci dokładnie jak możesz tego dokonać.
Do tej pory interesowaliśmy się tylko uruchamianiem nowych dźwięków i efektów. Jednakże, Sonic Pi daje nam możliwość manipulacji i kontroli aktualnie uruchomionych dźwięków. Dokonujemy tego używając zmiennych do przechwycenie referencji do syntezatora:
s = play 60, release: 5
Mamy tutaj zmienną lokalną s
, która reprezentuje syntezator
grający nutę 60. Nuta, która jest zmienną działającą lokalnnie
- nie masz do niej dostępu z innych uruchomień takich jak funkcje (?).
Gdy już mamy zmienną s
, możemy zacząć kontrolować ją za pomoca
funkcji control
:
s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
Rzeczą godną zauważenia jest tutaj to, że nie uruchamiamy 4 oddzielnych
syntezatorów - uruchamiamy tylko jeden po czym zmieniamy wysokość tonu
3 razy w trakcie gdy wciąż gra.
Możemy przekazywać dowolne ze standardowych parametrów do polecenia
control
, możesz więc kontrolować takie rzeczy jak amp:
, cutoff:
czy pan:
.
Są pewne parametry, które nie mogą być kontrolowane gdy syntezator został już uruchomiony. Dotyczy to m.in. wszytkich parametrów obwiedni ADSR. Możesz samodzielnie sprawdzić, które z parametrów danego syntezatora mogą być kontrolowane zaglądając do systemu pomocy. Jeśli w dokumentacji jest napisane can not be changed once set (nie może być zmieniony gdy już raz został ustawiony), to już wiesz, że nie możesz kontrolować i zmienać danego parametru gdy syntezator już wystartuje.
Możliwe jest również kontrolowanie efektów, jendakże jest ono realizowane w trochę inny sposób:
with_fx :reverb do |r|
play 50
sleep 0.5
control r, mix: 0.7
play 55
sleep 1
control r, mix: 0.9
sleep 1
play 62
end
Zamiast używać zmiennej, korzystamy z parametru pomiędzy słupkami
znajdujacymi się w bloku kodu do/end. Pomiędzy słupki |
wstawiamy
unikalną nazwę dla naszego efektu, dzięki czemu możemy się później
do niej odwoływać w danym bloku kodu do/end. Postępowanie w tym
przypadku jest identyczne do używania parametrów w funkcjach.
A teraz spróbuj wykorzystać kontrolę nad syntezatorami i efektami!
Podczas poznawania parametrów syntezatorów i efektów, być może udało
Ci się zauważyć, że kilka nazw parametrów ma kończy się na _slide
.
Być może nawet próbowałeś korzystać z nich i nie zauważyłeś żadnego
efektu. Dzieje się tak ponieważ nie są one normalnymi parametrami,
są to specjalne parametry, które działają tylko gdy kontrolujesz
syntezatory w sposób jaki pokazaliśmy w poprzedniej sekcji.
Przyjrzyjmy się następującemu przykładowi:
s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
W powyższym przykładzie słyszymy jak wysokość tonu (pitch) zmienia się
przy każdym uruchomieniu polecenia control
. Może się jednak zdarzyć,
że będziemy chcieli aby zmiana tonu nastąpiła w sposób płynny (tak jakbyśmy
użyli do tego suwaka). Tak samo jak kontrolujemy zmianę tonu parametrem
note:
, aby dodać płynne przejście, musimy ustawić na syntezatorze parametr
note_slide
:
s = play 60, release: 5, note_slide: 1
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
Teraz słyszymy, że pomiędzy poszczególnymi wywołaniami poleceń
control
nuty są “naciągane”. Brzmi to całkiem fajnie, prawda?
Możesz przyśpieszyć płynne przejście pomiędzy nutami używająć
krótszego czasu, np. `note_slide: 0.2’, albo zwolnić je, używająć
dłuższego czasu przejścia (ślizgania).
Każdy z parametrów, który może być kontrolowany posiada odpowiadający
my parametr typu _slide
, z którego możesz korzystać.
Gdy już raz ustawimy parametr typu _slide
na uruchomionym
syntezatorze, to zostanie on zapamiętany i ta wartość będzie wykorzystywana
za każdym razem gdy będziesz zmieniał płynnie wartość odpowiedającego
mu parametru. Aby zatrzymać płynne przejścia musisz ustawić wartość
parametru _slide
na 0 przed kolejnym wywołaniem polecenia control
.
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…
Struktury danych to bardzo przydatne narzędzie dostępne w standardowm zestawie narzędzi każdego programisty.
Czasami będziesz chciał reprezentować i używać czegoś więcej niż tylko jednej rzeczy. Na przykład, przydatnym może okazać się możliwość posiadania serii nut do zagrania jedna po drugiej. Języki programowania posiadają coś takiego jak struktury danych, które pozwalają Ci robić takie rzeczy.
Istnieje wiele ekscytujących i egzotycznych struktur danych dostępnych dla programistów - a ludzie wciąż wymyślają nowe. Na razie potrzebujemy w zasadzie wziąć pod uwagę tylko jedną prostą strukturę danych - listę.
Przyjrzyjmy się jej bardziej szczegółowo. Skupimy się jej podstawową formą, następnie pokażemy w jaki sposób możemy wykorzystać listy do reprezentacji skal oraz akordów.
W tej sekcji przyjrzymy się bardzo przydatnej strukturze danych - liście. Spotkaliśmy ją na krótko już wcześniej w sekcji poświęconej randomizacji kiedy to wybieraliśmy z listy losowe nuty do zagrania:
play choose([50, 55, 62])
W obecnym rozdziale zobaczymy jak możemy wykorzystać listy również
do reprezentacji akordów i skal. Na początku jednak spróbujmy sobie
przypomnieć w jaki sposób możemy zagrać akord. Pamiętasz, że jeśli
nie użyliśmy polecenia sleep
, to wszystkie dźwięki zagrają
jednocześnie:
play 52
play 55
play 59
Spróbujmy przyjrzeć się innym sposobom, za pomocą których możemy wyrazić powyższy kod.
Jedną z opcji jest umieszczenie wszystkich nut w liście [52, 55 , 59]
.
Nasza poczciwa funkcja play
jest wystarczająco bystra by wiedzieć
w jaki sposób ma zagrać listę nut. Spróbuj tego:
play [52, 55, 59]
Ooh, taki kod jest dużo przyjemniejszy do czytania. Zagranie listy nut, nie blokuje Ci korzystania z żadnego z parametrów:
play [52, 55, 59], amp: 0.3
Oczywiście, możesz również używać tradycyjnych nazw nut zamiast korzystania z liczb MIDI:
play [:E3, :G3, :B3]
Teraz Ci z Was, który mieli farta i studiowali trochę teorii muzycznej mogą zauważyć, że to jest akord E Minor zagrany na 3-ciej oktawie.
Innym bardzo przydatną cechą list jest możliwość wyciągnięcia z nich informacji. Może to brzmieć odrobinę dziwnie, ale nie jest to nic bardziej trudnego niż to gdy ktoś prosi Cię o to abyś przeszedł książce na stronę 23. Korzystając z listy, mógłbyś zapytać, jaki element znajduje się na 23 pozycji? Jedyną dziwną rzeczą w programowaniu jest to, że numery takich pozycji (indeksy) zazwyczaj zaczynają się od 0 a nie od 1.
Indeksy w listach nie są odliczane przez 1, 2, 3… Zamiast tego odliczamy 0, 1, 2…
Przyjrzyjmy się temu trochę bardziej. Spójrz na taką listę:
[52, 55, 59]
Nie ma w niej nic specjalnie strasznego. Teraz pytania, jaki jest
drugi element w tej liście. Tak, zgadłeś, jest to 55
. To było proste.
Sprawdźmy, czy możemy poprosić komputer aby odpowiedział nam na
to pytanie:
puts [52, 55, 59][1]
Dobrze, to wygląda trochę dziwnie, jeśli jeszcze nigdy nie widziałeś
niczego takiego. Zaufaj mi jednak, to nie jest trudne. W powyższej linii
są 3 części: słowo puts
, nasza lista 52, 55, 59
oraz nasz indeks
[1]
. Najpierw mówimy puts
ponieważ chcemy aby Sonic Pi wyświetlił
nam odpowiedź w panelu logowania (po prawej stronie). Następnie, przekazujemy
do tego polecenia naszą listę i na końcu nasz indeks, który pyta nas
o drugi element. Musimy otoczyć nasz indeks w nawiasy kwadratowe,
a ponieważ liczenie zaczynamy od 0
, to indeks dla drugiego elementu
to 1
. Spójrz:
# indeksy: 0 1 2
[52, 55, 59]
Spróbuj uruchomić kod puts [52, 55, 59][1]
a zobaczysz, że liczba
55
pojawi się w panelu logowania. Zmień indeks 1
na inne wartości,
spróbuj użyć dłuższych list i pomyśl w jaki sposob mógłbyś użyć listy
w twojej kolejnej zabawie kodem. Na przykład, jakie muzyczne struktury
mogą być reprezentowane jako seria liczb…
Sonic Pi posiada wbudowane wsparcie dla nazw akordów, które zwracają listy. Spróbuj sam:
play chord(:E3, :minor)
Teraz, naprawdę zaczynamy dokądś zmierzać. To wygląda dużo ładniej niż czyste listy (i jest dużo łatwiejsze do czytania dla innych ludzi). Jakie więc inne akordy wspiera Sonic Pi? Całkiem sporo. Spróbuj tych:
chord(:E3, :m7)
chord(:E3, :minor)
chord(:E3, :dim7)
chord(:E3, :dom7)
Możemy bardzo łatwo zmienić akordy w arpeggia za pomocą funkcji
play_pattern
:
play_pattern chord(:E3, :m7)
Ok, to nie jest jakoś mocno fajne - zostało zagrane dość wolno. Funkcja
play_pattern
zagra każdą listę z przekazanej listy odzdzielając każdą
nutę uruchomieniem polecenia sleep 1
pomiędzy każdym uruchomieniem
funkcji play
. Możemy jednak użyć innej funkcji play_pattern_timed
aby móc samodzielnie określić timing i przyśpieszyć bieg rzeczy:
play_pattern_timed chord(:E3, :m7), 0.25
Możemy nawet przekazać listę czasów, która zostanie potraktowania jako krąg czasów:
play_pattern_timed chord(:E3, :m13), [0.25, 0.5]
Jest to odpowiednik takiego kwała kodu:
play 52
sleep 0.25
play 55
sleep 0.5
play 59
sleep 0.25
play 62
sleep 0.5
play 66
sleep 0.25
play 69
sleep 0.5
play 73
Który kawałek wydaje Ci się wygodnieszy do napisania, którego byś użył?
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
Akordy i skale są świetnym sposobem na ograniczenie wyboru losowego do czegoś sensownego. Spróbuj pobawić się z tym przykładem, który wybiera losowe nuty z akordu E3 moll:
use_synth :tb303
loop do
play choose(chord(:E3, :minor)), release: 0.3, cutoff: rrand(60, 120)
sleep 0.25
end
Spróbuj poustawiać inne nazwy akordów oraz inne zakresy odcięcia (cutoff).
Aby zobaczyć jakie skale i akordy są wspierane przez Sonic Pi kliknij na przycisk Lang znajdujący się po lewej stronie tego samouczka, następnie z listy dostępnych API wybierz pozycję chord (akord) lub scale (skala). W informacjach znajdujących się w głównym panelu, przewiń w dół aż ujrzysz długą listę akordów lub skal (w zależności od tego na którą pozycję patrzysz).
Baw się i pamiętaj: błędów nie ma, sa tylko możliwości.
Ciekawym przypadkiem stanardowych list są pierścienie. Jeśli znasz się trochę na programowaniu, to mogło się zdarzyć, że miałeś do czynienia z buforami cyklicznymi lub tablicami cyklicznymi. Tutaj przyjrzymy się tylko pierścieniowi - jest krótki i prosty.
W poprzedniej sekcji dotyczącej list widzieliśmy w jaki sposób możemy wyciągać z nich elementy korzystając z mechanizmu indeksowania:
puts [52, 55, 59][1]
A co się stanie jeśli chciałbyś pozycję spod indeksu 100
? Dobrze, więc
na pozycji 100 nie ma żadnego elementu jako, że lista posiada w sobie
tylko trzy elementy. Sonic Pi zwróci więc wartość nil
co oznacza nic.
Jednakże, biorąc pod uwagę, że masz licznik, taki jak aktualne uderzenie, które nieustannie rośnie. Spróbujmy utworzyć sobie licznik oraz listę:
counter = 0
notes = [52, 55, 59]
Możemy teraz użyć naszego licznika aby dostać się do nuty znajdującej się w naszej liście:
puts notes[counter]
Super, otrzymaliśmy 52
. Teraz, spróbujmy zwiększyć nasz licznik
i dostać się do kolejnej nuty:
counter = (inc counter)
puts notes[counter]
Super, teraz otrzymaliśmy 55
i jeśli zrobimy to jeszcze raz, to otrzymamy
liczbę 59
. Jednakże, jeśli zrobimy to kolejny raz, to wyskoczymy poza
liczby znajdujące się w naszej liście i otrzymamy nil
. A co jeśli
chcieliśmy tylko zrobić pętlę, wrócić do początku i zacząć na samym początku
listy od nowa? Do tego właśnie służą pierścienie.
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
Gdy już masz pierścień, możesz go używać dokładnie w ten sam sposób w jaki używasz normalnej listy z tym jednym wyjątkiem, że możesz używać indeksów ujemnych oraz takich, które są większe niż ilość elementów w danym pierścieniu a będą one powtarzać się cyklicznie i zawsze będą wskazywać na jeden z elementów pierścienia:
(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59
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.
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.
Oprócz funkcji ring
istnieje również kilka innnych funkcji, które
pozwalają nam na tworzenie pierścieni.
range
wymaga abyś określił punkt startu, końca oraz rozmiar krokubools
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ścispread
tworzy pierścień wartości logicznych o rozkładzie EuklidesowymPrzyjrzyj się poszczególnym dokumentacjom dla uzyskania większej ilości informacji.
Jednym z najbardziej ekscytujących aspektów Sonic Pi jest to, że pozwala Ci tworzyć muzykę porzez pisanie i modyfikację kodu na żywo, tak samo jakbys mógł występować na żywo z gitarą. Jedną z zalet takiego podejścia jest to, że powala Ci na otrzymywanie informacji zwrotnej znacznie szybciej niż w sytuacji gdybyś komponował (stwórz prostą pętlę, która będzie się kręcić w kółko i zacznij dopieszczać ją aż zacznie brzmieć idealnie). Główną i podstawową zaletą jest jednak to, że możesz wziąć Sonic Pi ze sobą na scenę i wykorzystać go do występów na żywo.
W tym rozdziale przedstawimy Ci podstawy tego w jaki sposób możesz zmienić twoje statyczne kompozycje w pełne życia występy.
Zapnijcie pasy…
Teraz nauczyliśmy się już wystarczająco dużo aby zacząć prawdziwą zabaę. W tym rozdziale będziemy czerpać ze wszystkich poprzednich i pokażemy Ci w jaki sposób możesz zacząć tworzyć swoje własne kompozycje muzyczne na żywo i zmienić je w występy na żywo. Będziemy do tego potrzebować 3 podstawowych sładników:
W porząsiu, zaczynamy. Spróbujmy zakodować na żywo nasze pierwsze dźwięki. Najpierw potrzebujemy funkcję, która będzie zawierać kod, który chcemy zagrać. Zacznijmy od czegoś prostego. Potrzebujemy również aby każda pętla wywołująca tę funkcję była uruchamiana w nowym wątku:
define :my_loop do
play 50
sleep 1
end
in_thread(name: :looper) do
loop do
my_loop
end
end
Jeśli powyższy kawałek kodu wydaje Ci się zbyt skomplikowany, wróć z powrotem i ponownie przeczytaj rozdziały dotyczące funkcji i wątków. Gdy to zrobisz i uda Ci się dobrze zrozumieć te 2 tematy to powyższy kawałek nie powinien sprawić Ci żadnych kłopotów.
To co mamy powyżej to nic innego jak funkcja, która po prostu gra nutę
o wartości 50 i następnie czeka 1 uderzenie. W kolejnym kroku mamy
definicję wątku nazwanego :looper
, który po prostu kręci się w kółko
i uruchamia fukcję my_loop
.
Gdy uruchomisz ten kod, usłyszysz nutę 50 która powtarza się i gra w kółko…
Teraz, czas na moment w którym zaczyna się cała zabawa. W momencie gdy kod jest wciąż uruchomiony, spróbuj zmienić liczbę 50 na inną, powiedzmy 55, następnie naciśnij przycisk Run jeszcze raz. Łał! To się zmieniło! Ten kod żyje!
Nowa warstwa dźwięku nie została dodana ponieważ korzystamy z nazwanych
wątków co pozwala tylko na jeden wątek dla jednej nazwy. Ponadto,
dźwięk się zmienił ponieważ przedefiniowaliśmy funkcję. Nadaliśmy
funkcji :my_loop
nową definicję - znaczenie. Kiedy wątek :looper
przekręci się po raz kolejny, to w następnej iteracji zostanie zawołana
funkcja o nowej definicji.
Spróbuj zmienić ją ponownie, zmień nutę, zmień wartość parametru jaki
przekazujemy do funkcji sleep. Co powiesz na dodanie polecenia use_synth
?
Na przykład, zmieńmy kod w taki sposób:
define :my_loop do
use_synth :tb303
play 50, release: 0.3
sleep 0.25
end
Brzmi to całkiem ciekawie, ale możemy urozmaicić to jeszcze bardziej. Zamiast grać w kółko tę samę nutę, spróbujmy zagrać akord:
define :my_loop do
use_synth :tb303
play chord(:e3, :minor), release: 0.3
sleep 0.5
end
A co powiesz na granie losowych nut z akordu:
define :my_loop do
use_synth :tb303
play choose(chord(:e3, :minor)), release: 0.3
sleep 0.25
end
Albo użycie losowej wartości dla parametru odcięcia (cutoff):
define :my_loop do
use_synth :tb303
play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
sleep 0.25
end
I na sam koniec, dodajmy trochę bębnów:
define :my_loop do
use_synth :tb303
sample :drum_bass_hard, rate: rrand(0.5, 2)
play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
sleep 0.25
end
Teraz zabawa zaczyna być naprawdę ekscytująca!
Jednakże, zanim zamkniesz tutorial i zaczniesz kodować na żywo
z wykorzystaniem funkcji i wątków, zatrzymaj się na chwile i przeczytaj
kolejny rozdział dotyczący funkcji live_loop
, która zmieni twój sposób
kodowania w Sonic Pi na zawsze…
Dobrze, ten rozdział to prawdziwa perełka w tym samouczku. Jeśli
masz przeczytać tylko jeden rozdział w tym tutorialu, powinien to
być właśnie ten rozdział. Jeśli przeczytałeś poprzedni rozdział
o Podstawach Kodowania Na Żywo, to live_loop
jest prostszą metodą
dokonania dokładnie tego samego, ale bez konieczności pisania
tak dużej ilości kodu.
Jeśli nie przeczytałeś poprzedniego rozdziału, funkcja live_loop
jest najlepszym sposobem na jam’owanie z Sonic Pi.
Zabawmy się. Wpiszmy następujący kod do nowego bufora:
live_loop :foo do
play 60
sleep 1
end
Naciśnij przycisk Run. Słyszysz podstawowy bip przy każdym uderzeniu.
Nic szczególnego. Powstrzymaj się jednak i nie naciskaj jeszcze przycisku
Stop. Zmień wartość 60
na 65
i naciśnij przycisk Run jeszcze raz.
Now press the Run button. You hear a basic beep every beat. Nothing
fun there. However, don’t press Stop just yet. Change the 60
to 65
and press Run again.
Łał! Brzmienie zmieniło się automatycznie bez utraty żadnego uderzenia.
Czemu więc nie spróbować zmienić ten kawałek aby brzmiał trochę bardziej jak linia basowa? Wystarczy, że zmienisz kod gdy ten wciąż jest uruchomiony:
live_loop :foo do
use_synth :prophet
play :e1, release: 8
sleep 8
end
I naciśniesz przycisk Run.
Spróbujmy sprawić, aby pojawiła się odrobina odcięcia (cutoff):
live_loop :foo do
use_synth :prophet
play :e1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
Ponownie naciśnij przycisk Run.
Dodajmy trochę bębnów:
live_loop :foo do
sample :loop_garzul
use_synth :prophet
play :e1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
Zmień nutę e1
na c1
:
live_loop :foo do
sample :loop_garzul
use_synth :prophet
play :c1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
A teraz przestań słuchać moich propozycji i zacznij bawić się samodzielnie! Miłej zabawy!
Przyjrzyjmy się natępującej żywej pętli:
live_loop :foo do
play 50
sleep 1
end
Być może zastanawiałeś się dlaczego konieczna jest nazwa :foo
. Nazwa
ta jest ważna ponieważ oznacza, że ta konkrenta żywa pętla jest inna od wszystkich
innych żywych pętli.
W tym samym czasie nie mogą być uruchomione dwie żywe pętle o tej samej nazwie.
Oznacza to, że jeśli potrzebujemy kilku jednocześnie kręcących się żywych pętli, to po prostu musimy nadać im inne nazwy:
live_loop :foo do
use_synth :prophet
play :c1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
live_loop :bar do
sample :bd_haus
sleep 0.5
end
Możesz teraz aktualizować i zmieniać każdą z żywych pętli niezależnie i wszystio będzie po prostu działać.
Jedną z rzeczy, które być może już zauważyłeś to to, że żywe pętle
działają automatycznie z mechanizmem punktów cue dla wątków, które
poznaliśmy już wcześniej. Za każdym razem, gdy żywa pętla wykona pętlę,
generuje nowe zdarzenie cue
nadając mu nazwę taką samą jaką nadaliśmy
żywej pętli. Możemy więc sychroznizować się z wykorzystaniem funkcji
sync
na każdym zdarzeniu cue
aby upewnić się, że nasze pętle
są zsynchronizowane bez konieczności zatrzymywania czegokolwiek.
Spójrzmy na poniższy kod, który został źle zsynchronizowany:
live_loop :foo do
play :e4, release: 0.5
sleep 0.4
end
live_loop :bar do
sample :bd_haus
sleep 1
end
Zobaczmy czy możemy naprawić chronometraż (timing) bez zatrzymywania. Najpierw,
naprawmy pętlę :foo
tak, aby sprawić, że wartość parametru sleep będzie
współczynnikiem liczby 1 - coś jak 0.5
powinno być ok:
live_loop :foo do
play :e4, release: 0.5
sleep 0.5
end
live_loop :bar do
sample :bd_haus
sleep 1
end
To jeszcze nie koniec - powinieneś zauważyć, że uderzenia nie do końca ustawiają się odpowiednio. Dzieje się tak, ponieważ pętle nie są synchronizowane. Spróbujmy to naprawić przez ich synchronizację:
live_loop :foo do
play :e4, release: 0.5
sleep 0.5
end
live_loop :bar do
sync :foo
sample :bd_haus
sleep 1
end
Łał, teraz wszystko perfekcyjnie w czas - i to wszystko bez zatrzymywania.
A teraz, nie zatrzymuj się i koduj na żywo z wykorzystaniem żywych pętli!
Coś na co na pewno będziesz robił dość często podczas kodowania na żywo to iterowanie przez pierścienie. Będziesz wrzucał nuty do pierścieni dla tworzenia melodii, czasów uśpienia dla rytmów, progresji akordów, różne wariacje barw dźwięku, itd.
Sonic Pi udostępnia bardzo przydatne narzędzie do pracy z pierścieniami
w żywych pętlach live_loop
. Nazywa się to systemem cykania. Udostępnia
Ci możliwość cykania przez pierścienie. Spójrzmy na następujący przykład:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick, release: 0.1
sleep 0.125
end
Wzięliśmy tu pentatoniczną skalę E3 moll i cykamy przez każdy jej element.
Dokonaliśmy tego przez dodanie polecenia .tick
na końcu deklaracji skali.
Każde cyknięcie jest lokalne dla danej żywej pętli, więc każda żywa pętla
może posiadać swojego własnego niezależnego cykacza:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick, release: 0.1
sleep 0.125
end
live_loop :arp2 do
use_synth :dsaw
play (scale :e2, :minor_pentatonic, num_octaves: 3).tick, release: 0.25
sleep 0.25
end
Możesz również uruchomić polecenie cyknięcia tick
jako standardową funkcje
i używać zwracanej wartości jako indeksu:
live_loop :arp do
idx = tick
play (scale :e3, :minor_pentatonic)[idx], release: 0.1
sleep 0.125
end
Jednakże, dużo ładniej jest korzystać z polecenia .tick
dodanego na końcu.
Funkcja tick
jest stworzona dla sytuacji gdy chesz zrobić coś fantazyjnego
z wartością zwracaną przy cyknięciu oraz gdy chcesz używać cyknięć
do innych rzeczy niż indeksowania elementów pierścieni.
Magiczną rzeczą w cykaniu jest to, że możliwe jest nie tylko zwrócenie
nowego indeksu (albo wartości znajdującej się w pierścieniu pod tym
indeksem). Mechanizm ten pilnuje też aby przy każdym twoim kolejnym
cyknięciu była to kolejna wartość. Zerknij na przykłady znajdujące się
w dokumentacji dla polecenia tick
aby zobaczyć wiele różnych sposobów
na pracę z nim. Jednakże, na tą chwilę, ważne jest aby zaznaczyć, że czasami
będziesz chciał po prostu podejrzeć aktualną wartość cyknięcia bez zwiększania
jego wartości. Możesz tego dokonać za pomocą funkcji look
. Możesz uruchamiać
polecenie look
jako standardową funkcję lub poprzez dodanie .look
na końcu pierścienia.
Na koniec, czasami będziesz potrzebował więcej niż jednego cykacza dla danej żywej pętli. Można tego dokonać poprzez nadanie twojemu cyknięciu nazwę:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick(:foo), release: 0.1
sleep (ring 0.125, 0.25).tick(:bar)
end
Powyżej używamy dwóch cykaczy, jeden dla zagrania nuty i drugi dla
odliczania czasu uśpienia. Jako, że oba znajdują się w tej samej żywej pętli,
potrzebowaliśmy nadać im unikalne nazwy aby sprawić by były oddzielne.
To jest dokładnie taki sam mechanizm jak w przypadku nadawania nazw
żywym pętlom (live_loop
) - po prostu przekazujemy symbol poprzedzony
dwukropkiem :
. W powyższym przykładzie nazwaliśmy pierwszego
cykacza :foo
a drugiego :bar
. Jeśli chcemy podejrzeć aktualną
wartość, któregoś z nich za pomocą polecenia look
, to musimy
do polecenia look
również przekazać nazwę konkretnego cykacza.
Większość mocy zawartej w systemie cykania nie jest przydatna gdy dopiero zaczynasz. Nie próbój i nie ucz się wszystkiego z tego rozdziału. Postaraj skupić się na cykaniu przez pojedynczy pierścień. To powinno dać Ci największą satysfakcję oraz prostotę związaną z cykaniem przez pierścienie w twoich żywych pętlach.
Zerknij do dokumentacji na polecenie tick
gdzie znajdziesz wiele
przydatnych przykładów. Wesołego cykania!
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.
Sonic Pi zarówno instrumentem muzycznym jak i środowiskiem programistycznym. Skróty klawiszowe mogą więc sprawić, że granie z Sonic Pi będzie dużo bardziej wydajne i naturalne - zwłaszcza gdy gdy będziesz grać na żywo przed publicznością.
Wiele funkcji Sonic Pi może być kontrolowanych za pomocą klawiatury. Gdy posiądziesz już więcej wprawy w pracy i występach z Sonic Pi, na pewno zaczniesz używać skrótów coraz częściej i częściej. Potrafie pisać na klawiaturze bezwzrokowo (I tobie też polecam sie tego nauczyć) i czuję frustrację za każdym razem kiedy tylko muszę sięgnąć po myszkę ponieważ to mnie spowalnia. W związku z powyższym używam wszystkich tych skrótów w kółko!
Ponadto, jeśli nauczysz się skrótów, nauczysz się korzystać z twojej klawiatury dużo bardziej efektywnie i zaczniesz kodować na żywo niczym profesjonalista w bardzo krótkim czasie.
Jednakże, nie próbuj i nie ucz się ich wszystkich na raz, postaraj się sprawdzić i zapamiętać tylko te, których używasz najczęśniej. Dopiero potem postaraj się regularnie dodawać i ćwiczyć kolejne.
Wyobraź sobie, że uczysz się gry na klarnecie. Zapewne oczekiwałbyś, że wszystkie klarnety będą zapewniały podobną kontrole i palcowanie. Jeśli nie, to potrzebowałbyś sporo czasu za każdym razem gdy przesiadałbyś się pomiędzy różnymi klarnetami i tak naprawdę byłbyś wtedy ograniczony do korzystania tylko z jednego wybranego modelu.
Na nieszczęście 3 podstawowe systemy operacyjne (Linux, Mac OS X i Windows) posiadają swoje własne standardy dla domyślnych akcji takich jak np. kopiuj wklej. Sonic Pi postara się honorować wszystkie te standardy. Jednakże, priorytet został położony na spójność pomiędzy różnymi platformami, na których działa Sonic Pi i jest on ważniejszy niż próby zapewnienia zgodności z poszczególnymi platformami. Oznacza to, że jeśli nauczysz się skrótów klawiszowych gdy będziesz grał na Sonic Pi na Raspberry Pi, to będziesz mógł przenieść się na komputer marki Apple z systemem Mac OS lub peceta z zainstalowanym Windows’em i dalej czuć się jak w domu.
Częścią dotyczącą pojęcia spójności jest nazewnictwo skrótów. W Sonic Pi używamy nazw Control i Meta dla odniesienia się do dwóch podstawowych klawiszy używanych w kombinacjach skrótów. Na wszystkich platformach klawisz Control odnosi się do tego samego przycisku na klawiaturze. Jednakże, w systemach Linux i Window, klawisz Meta oznacza klawisz Alt, podczas gdy w systemie Mac OS klawisz Meta oznacza klawisz Command. Dla zachowania spójności będziemy używali terminu Meta - jedyne co musisz zapamiętać to to, w jaki sposób zmapować ten termin na odpowiedni klawisz dla twojego systemu operacyjnego.
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.
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
.
Bez skrótów umożliwiających nawigację czuję się naprawdę zagubiony. W związku z tym bardzo zalecam ci spędzić tyle czasu ile potrzeba aby się ich nauczyć. Skróty te działają również bardzo dobrze kiedy już nauczysz się pisać na klawiaturze bezwzrokowo jako, że używają one standardowych liter i nie wymagają od ciebie abyś sięgał ręka do myszki lub klawiszy ze strzałkami na twojej klawiaturze.
Możesz przenieść się do początku linii naciśniskając skrót C-a
,
aby przenieść się na koniec linii naciśnij C-e
, aby przenieść się
o 1 linię w górę naciśnij C-p
, jedną linię w dół C-n
, aby przesunąć
sie o jeden znak do przodu użyj C-f
, jeden znak do tyłu C-b
. Możesz
nawet usunąć wszystkie znaki od miejsca, w którym aktualinie znajduje się
kursor, aż do końca linii używając skrótu C-k
.
Aby automatycznie wyrównać twój kod wystarczy, że naciśniesz M-m
.
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.
Poniżej dostępne jest podsumowanie najważniejszych skrótów dostępnych w Sonic Pi. Przejrzyj proszę rozdzial 10.1 dla uzyskania motywacji i tła.
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.M-r
- Uruchom kod (przycisk Run)M-s
- Zatrzymaj przycisk (przycisk Stop)M-i
- Otwórz/Zamknij System PomocyM-p
- Otwórz/Zamknij UstawieniaM-{
- Przejdź do buforu po lewej stronieM-}
- Przejdź do buforu po prawej stronieM-+
- Zwiększ rozmiar czcionki w aktualnym buforzeM--
- Zmniejsz rozmiar czczionki w aktualnym buforzeM-a
- Zaznacz wszystkoM-c
- Skopiuj zaznaczony obszar aby móc go wkleić do bufora w innym miejscuM-]
- Skopiuj zaznaczony obszar aby móc go wkleić do bufora w innym miejscuM-x
- Wytnij zaznaczony obszar aby móc wkleić go do bufora w innym miejscuC-]
- Wytnij zaznaczony obszar aby móc wkleić go do bufora w innym miejscuC-k
- Wytnij tekst od aktualnej pozycji kursora do końca liniiM-v
- Wklej zawartość schowka do aktualnego buforaC-y
- Wklej zawartość schowka do aktualnego buforaC-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.M-m
- Wyrównaj cały tekst w buforzeTab
- Popraw wyrównianie/zaznaczenie aktualnej liczby lub pokaż podpowiedziC-l
- Wyśrodkuj edytorC-t
- Transponuj/zamień znakiM-u
- Konwertuj następne słowo (lub zaznaczenie) do wielkich literM-l
- Konwertuj następne słowo (lub zaznaczenie) do małych literC-a
- Przenieś kursor do początku liniiC-e
- Przenieś kursor na koniec liniiC-p
- Przenieś kursor do poprzedniej liniiC-n
- Przenieś kursor do następnej liniiC-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łowoM-b
- Przenieś kursor do tyłu (w lewo) o jedno słowoC-M-n
- Przenieś aktualną linie lub zaznaczenie w dółC-M-p
- Przenieś aktualną linię lub zaznaczenie do góryS-M-u
- Przenieś się do góry o 10 liniiS-M-d
- Przenieś się w dół o 10 liniiM-<
- Przenieś się na początek buforaM->
- Przenieś się na koniec buforaC-h
- Usuń poprzedni znakC-d
- Usuń kolejny znakC-i
- Pokaż dokumentację dla słowa, na którym znajduje się aktualnie kursorM-z
- Wstecz (cofnij zmianę)S-M-z
- Redo (powtórz zmianę)C-g
- Ucieczka (anulowanie)S-M-f
- Otwórz/Zamknij tryb pełnoekranowyS-M-b
- Pokaż/Showaj przyciskiS-M-l
- Pokaż/Schowaj panel logowaniaS-M-m
- Przełączanie pomiędzy trybem jasnym i ciemnymW Sonic Pi chodzi przede wszystkim o udostępnianie i uczenie się od siebie nawzajem.
Gdy już nauczyłeś się w jaki sposób kodować muzykę, udostępnienie twojej kompozycji jest tak łatwe jak wysłanie wiadomości email, która będzie zawierać twój kod. Proszę abyś dzielił się swoim kodem z innymi, dzięki temu będą oni mogli uczyć się z twojej pracy a nawet używac kawałków twojej muzyki do tworzenia nowych mash-up’ów.
Jeśli nie jesteś pewien tego w jaki sposób możesz najlepiej dzielić się twoimi dokonaniami z innymi, to polecam Ci wrzucanie twojego kodu na stronę GitHub natomiast gotową muzykę na stronę SoundCloud. W ten sposób bardzo łatwo uda Ci się zyskać znaczną publiczność.
GitHub to strona umożliwiająca dzielenie się i pracę nad kodem. Jest ona używana zarówno przez profesjonalnych programistów jak ich artystów w celu udostępniania i współpracy z kodem. Najprostszą metodą aby podzielić się nowym kawałkiem kodu (nawet tym niedokończonym) jest stworzenie Gist’a Gist to bardzo prosty sposób na przesłanie twojego kodu w bardzo prosty sposób, tak żeby inni mogli go zobaczyć, skopiować i dzielić się nim.
Innym bardzo ważnym sposobem na dzielenie się twoją pracą jest nagranie pliku audio i przesłanie go na stronę SoundCloud. Gdy już wrzucisz tam swój kawałek, inni użytkownicy tej strony będą mogli komentować i rozmawiać o twoim dziele. Zalecam również zamieszczenie w opisie linku do Gist’a zawierającego kod źródłowy tego utworu.
Aby nagrać twoją pracę wystarczy, że naciśniesz przycisk Rec
znajdujący
się w panelu z przyciskami a nagrywanie rozpocznie się natychmiast.
Naciśnij więc przycisk Run
aby uruchomić twój kod jeśli przypadkiem
jeszcze tego nie zrobiłeś. Kiedy skończysz nagranie, naciśnij ponownie
migający przycisk Rec
a zostaniesz poproszony o podanie nazwy pliku
pod jaką ma zostać zapisane twoje nagranie. Zostanie ono zapisane
jako plik WAV, który może być bardzo łatwo przeedytowany i skonwertowany
do formatu MP3 przez jeden z wielu darmowych programów (spróbuj na przykład
programu Audacity).
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ć.
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.
Kiedy kodujesz na żywo polecam Ci abyś pokazał swojej publiczności twój ekran. W przeciwnym przypadku będzie to tak jak granie na gitarze ale chowając swoje palce i struny. Kiedy ćwiczę w domu używam Raspberry Pi i małego mini projektora na ścianie w moim salonie. Możesz użyć twojego TV albo jednego z projektorów, które są dostępne w twojej szkole lub pracy aby dać występ. Spróbuj, to świetna zabawa.
Nie graj tylko sam - spróbuj stworzyć zespół kodujący na żywo! Granie z innymi daje wiele radości i satysfakcji. Jedna osoba może robić bity, inna podkład w stylu ambient, itd. Spróbuj zobaczyć jakie ciekawe kombinacje dźwięków możecie razem stworzyć.
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.
Innym świetnym źrodłem dla odkrywania świata kodowania na żywo jest Algorave. Możesz tutaj znaleźć wszystko co dotyczy wszystkich aspektów kodowania na żywo, które są związane z tworzeniem muzyki w klubach.
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).
Integracja z Minecraft Pi została zaprojektowana aby być szalenie
łatwa w użyciu. Wszystko co potrzebujesz zrobić to włączyć Minecraft Pi
i stworzyć nowy świat. Gdy już to zrobić możesz dowolnie używać funkcji
mc_*
tak samo jak używałeś do tej pory poleceń play
i synth
. Nie
ma konieczności importowania czegokolwiek lub instalacji dodatkowych
bibliotek - wszystko jest gotowe i działa po wyjęciu z pudełka.
API serwowane przez Minecraft Pi zajmuje się zarządzaniem twoim połączeniem
z aplikacją Minecraft Pi. Oznacza to, że nie musisz się przejmować o nic.
Jeśli spróbujesz skorzystać z API oferowanego przez Minecraft Pi kiedy
gra nie jest włączona, Sonic Pi uprzejmie Cię o tym poinformuje. Podobnie,
jeśli zamkniesz Minecraft Pi w momencie kiedy wciąż masz uruchomioną
żywą pętlę live_loop
, która korzysta z API, żywa pętla zatrzyma sie
i uprzejmie poinformuje Cię, że nie może się połączyć. Aby wznowić
połączenie wystarczy, że ponownie włączysz Minecraft Pi a Sonic Pi
automatycznie wykryje i ponownie utworzy połączenie za Ciebie.
API oferowane przez Minecraft Pi zostało zaprojektowane w taki sposób,
aby pracować bez żadnych problemów o obrębie żywych pętli tworzonych
z wykorzystaniem polecenia live_loop
. Oznacza to, że jest możliw a
synchronizacja zmian w twoim świecie Minecraft Pi ze zmianami dokonywanymi
w dźwiękach brzmiących w twoim Sonic Pi. Błyskawiczne nagrania wideo
z muzyką bazujące na grze Minecraft! Jeśli jednak zdarzy się, że natrafisz
na jakieś problemy, po prostu uruchom ponownie Minecraft Pi i kontynuuj
wcześniejszą zabawę. Funkcjonalność automatycznego połączenia Sonic Pi
zajmie się wszystkim za Ciebie.
Zalecane jest abyś używał Raspberry Pi 2 jeśli chcesz jednocześnie uruchomić Sonic Pi i Minecraft - zwłaszcza jeśli chcesz wykorzystać możliwości dźwiękowe Sonic Pi.
Na ten moment, Sonic Pi wspiera podstawowe bloki oraz manipulacje graczy, które sa opisane w rozdziale 11.1. Wsparcie dla zdarzeń zwrotnych wywoływanych przez interakcje gracza w świecie jest planowane na przyszłe wydanie.
Sonic Pi aktualnie wspiera następujące podstawowe interakcje z Minecraft Pi:
Spróbujmy przyjrzeć się każemu z nich po kolei.
Zobaczmy jak łatwo jest kontrolować Minecraft Pi z Sonic Pi. Najpierw, upewnij się, że zarówno Minecraft Pi jak i Sonic Pi są jednocześnie otwarte a także, upewnij się, że udało Ci się wejść do świata Minecraft i możesz się poruszać.
W czystym buforze Sonic Pi po prostu wprowadź poniższy kod:
mc_message "Hello from Sonic Pi"
Kiedy naciśniesz przycisk Run, zobaczysz migającą wiadomość w ekranie Minecraft. Gratulacje, właśnie napisałeś swój pierwszy kod w Minecraft! To było proste, prawda?
Teraz, spróbujmy odrobine magii. Spróbujmy przeteleportować nas w inne miejsce. Spróbuj następującego kodu:
mc_teleport 50, 50, 50
Kiedy naciśniesz Run - bum! Zostajesz błyskawicznie przetransportowany
w nowe miejsce. Bardzo prawdopodobne jest to, że to gdzieś w powietrzu
i spadniesz w dół na suchy ląd lub do wody. Teraz, co to za liczby:
50, 50, 50
? Są to współrzędne miejsca do którego starasz się
przetleportować. Poświęćmy krótką chwilę żeby dowiedzieć się czym są
współrzędne i jak działają, ponieważ są one naprawdę ważne w programowaniu
Minecraft.
Wyobraź sobie mapę piratów z wielkim X
oznacającym miejsce jakiegoś
skarbu. Dokładna lokalizacja X
może być opisana przez podanie
dwóch liczb - jak daleko na mapie od lewej do prawej oraz jak daleko
od dołu mapy w górę. Na przykład 10cm
wszerz i 8cm
w górę. Te dwie
liczby 10
i 8
to współrzędne. Możesz bardzo łatwo wyobrazić sobie
opisywanie sekretnych miejsc ze skarbami za pomocą innej pary liczb.
Być może bardzo duża skrzynia złota znajduje się na 2
w poprzek
9
w górę.
Teraz, w Minecraft dwie liczby to za mało. Potrzebujemy także wiedzieć o tym, jak wysoko się znajdujemy. Dlatego też potrzebujemy 3 liczb:
x
z
y
Jeszcze jedna rzecz - zazwyczaj opisujemy te współrzędne w następującej
kolejności x
, y
, z
.
Spróbujmy pobawić się współrzędnymi. Przenieść się do jakiegoś ładnego miejsca na mapie Minecraft następnie przełącz się do Sonic Pi. Teraz wpisz następującą linijkę:
puts mc_location
Kiedy uruchomisz przycis Run zobaczysz współrzędne twojego aktualnego położenia wyświetlone w panelu z logami. Zapisz je, następnie spróbuj przemieścić się do przodu w świecie i spróbuj jeszcze raz. Zauważ, że współrzędne się zmieniły! Teraz, zalecam Ci poświęcić Ci trochę czasu na powtórzenie tego kilka razy - przenieś się gdzieś kawałek w twoim świecie, zerknij na współrzędne i powtórz. Próbuj tego do momentu, w którym poczujesz jak zmieniają się współrzędne gdy się poruszasz. Gdy już zrozumiesz jak działają współrzędne, programowanie z API oferowanym przez Minecraft będzie dla Ciebie bułką z masłem.
Teraz gdy już wiesz w jaki sposob znaleźć aktualną pozycje oraz w jaki
sposob możesz się teleportować korzystając z współrzędnych, posiadasz
już wszystkie narzędzia, których potrzebujesz aby zacząć budować rzeczy
w Minecraft za pomocą kodu. Powiedzmy, że chciałbyś stworzyć blok ze szkła
o współrzędnych 40
, 50
, 60
. Proste:
mc_set_block :glass, 40, 50, 60
Tak, tak, to naprawde jest takie proste. Aby obejrzeć swoje dzieło po prostu przeteleportuj się niedaleko i zerknij na nie:
mc_teleport 35, 50, 60
Teraz obróć się i powinieneś zobaczyć twój blok ze szkła. Spróbuj zmienić go w diament:
mc_set_block :diamond, 40, 50, 60
Jeśli patrzyłeś w odpowiednim kierunku to być może nawet zauważyłeś jak zmienił się na twoich oczach! To początek czegoś ekscytującego…
Spróbujmy spojrzeć na ostatnią rzecz zanim zaczniemy coś bardziej angażującego. Podająć zestaw współrzędnych możemy zapytać Minecraft o to jakiego typu jest specyficzny blok. Spróbujmy tego z naszym blokiem diamentu, który stworzyłeś przed chwilą:
puts mc_get_block 40, 50, 60
Łał! To diament (:diamond
)!. Spróbuj ponownie zmienić go w szkło
i jeszcze raz zapytać o typ - czy teraz pokazał szkło (:glass
).
Jestem pewien, że tak :-)
Zanim udasz oddasz się szaleństwu programowania z Minecraft Pi, być może zainteresuje Cie poniższa lista dostępnych typów bloków:
:air
:stone
:grass
:dirt
:cobblestone
:wood_plank
:sapling
:bedrock
:water_flowing
:water
:water_stationary
:lava_flowing
:lava
:lava_stationary
:sand
:gravel
:gold_ore
:iron_ore
:coal_ore
:wood
:leaves
:glass
:lapis
:lapis_lazuli_block
:sandstone
:bed
:cobweb
:grass_tall
:flower_yellow
:flower_cyan
:mushroom_brown
:mushroom_red
:gold_block
:gold
:iron_block
:iron
:stone_slab_double
:stone_slab
:brick
:brick_block
:tnt
:bookshelf
:moss_stone
:obsidian
:torch
:fire
:stairs_wood
:chest
:diamond_ore
:diamond_block
:diamond
:crafting_table
:farmland
:furnace_inactive
:furnace_active
:door_wood
:ladder
:stairs_cobblestone
:door_iron
:redstone_ore
:snow
:ice
:snow_block
:cactus
:clay
:sugar_cane
:fence
:glowstone_block
:bedrock_invisible
:stone_brick
:glass_pane
:melon
:fence_gate
:glowing_obsidian
:nether_reactor_core
Czas na podsumowanie samouczka wprowadzającego do Sonic Pi. Mam nadziję, że nauczyłeś się czegoś w trakcie jego czytania. Nie przejmuj się jeśli czujesz, że nie wszystko zrozumiałeś - po prostu graj i baw się a na pewno załapiesz kolejne rzeczy w odpowiednim dla siebie czasie. Nie krępuj się i zajrzyj tutaj ponownie jeśli będziesz miał jakieś pytanie, na które odpowiedź znajduje się w jednym z rozdziałów.
Jeśli masz jakiekolwiek pytania, na które nie znalazłeś odpowiedzi w tym samouczku, polecam Ci zajrzeć na forum Sonic Pi i zadać swoje pytanie właśnie tam. Na pewno znajdziesz tam kogoś kto bez problemu i z chęcią poda Ci pomocną dłoń.
I na koniec, zachęcam Cię również abyś przyjrzał się głebiej pozostałej części dokumentacji dostępnej w systemie pomocy. Znajdziesz tam wiele funkcjonalności, które nie zostały omówione w tym samouczku i czekają tam abyś je odkrył.
Tak więc, graj, baw się, dziel się swoim kodem, występuj na żywo przed twoimi znajomymi, pokazuj swój ekran i pamiętaj:
Błędów nie ma, są tylko nowe możliwości.