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!