一度、膨大なコードを書き始めると、それらの構造をより簡単かつ整理された状態で把握できるように、構築しまとめたいと感じることになるでしょう。ファンクション
(関数)はそんなことをとても効果的に成し遂げる方法です。この関数を使うとコードのまとまりに対して名前をつけることも可能になります。早速、見ていきましょう。
define :foo do
play 50
sleep 1
play 55
sleep 2
end
ここではfoo
という名前を付けた新しい関数を定義しています。この章ではすっかりお馴染みのdo/endブロックと、define
という魔法の言葉の後ろに、この関数に付けたい名前を続けています。関数の名前はfoo
である必要はなく、bar
やbaz
といったどんなものでも構いませんが、理想的にはmain_section
やlead_riff
といった何か意味のあるものがよいでしょう。
関数を定義するとき、その名前に:
(コロン)を付加することを忘れないでください。
いったん1つの関数を定義すると、ただ名前を書くことでそれを呼びだすことができます。
define :foo do
play 50
sleep 1
play 55
sleep 0.5
end
foo
sleep 1
2.times do
foo
end
foo
は、イテレーション(反復)ブロックの中からも使えたり、play
やsample
が書けるところであればどこからでも使えます。このことは、楽曲の中で利用可能な意味のある言葉を作り出したり、自己表現したりする優れた方法を提供します。
Run
を超えた関数の利用これまでのところ、Run
ボタンを押すたびに、Sonic Piを完全に白紙の状態から始めたことにして、表示されているBuffer以外のコードは無いものとしていました。これは、別のBufferまたは別のスレッド内のコードを参照できなかったからです。しかし、関数はそれを変えることができます。あなたが関数を定義すると、Sonic Piはそれを覚えることができます。では、ちょっとやってみましょう。まずBufferにあるすべてのコードを消して、次のものに変更します。
foo
Run
ボタンを押して、関数のfoo
が再生されることを確認してください。コードはどこにいったのでしょう? また、Sonic Piは、実行の仕方をどのように知っていたのでしょうか? Sonic PiはBufferを消したあとでも、あなたが打ち込んだ関数を覚えていて、定義した関数をしっかりと再生してみせたのです。この動作はdefine
もしくはdefonce
を使用した時にだけ働く機能です。
最小値と最大値の情報をrrand
へ渡すように、引数を受け取る関数についても興味を持つかもしれません。ちょっと見てみましょう。
define :my_player do |n|
play n
end
my_player 80
sleep 0.5
my_player 90
この例はあまり面白いものではありませんが、ポイントとなる点を示しています。ここでは、引数の付いたmy_player
という名前の関数を、play
の独自のバージョンとして作成しています。
この引数はdefine
で括られたdo/endブロックのdoの後に記述する必要があります。引数は、垂直のバー|
で囲み、複数の引数を扱う場合はカンマ ,
で分割し、引数の名前はどんな言葉でも付けることが出来ます。
この魔法は、define
を使いdo/endブロック内で行われます。また、実行されるための値のような変数名を使うことも出来ます。この例で言うと、n
という値の音符を鳴らしています。引数はコードが起動した際にその領域に記憶されている実際の数値に置き換えられるという約束と考えることができます。あなたが関数を呼び出した際は、この数値を関数に置き換えて実行することが出来るのです。このmy_player 80
というのは、80という音符を鳴らすということです。関数の定義の中で、n
はすぐに80
に置き換えられます。そしてplay n
はplay 80
となるのです。また次にmy_player 90
という関数を呼び出すと、今度はn
が90
に置き換えられ、play n
はplay 90
として再生されるのです。
それではさらにおもしろい例を見てみましょう。
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
ここではrepeats.times do
という行の中で1つの数値のようにrepeats
が使われます。また、play
を呼び出した際の音符の名前と同じようにroot
が使われています。
関数に多くの処理を移動することによって、コードをとても表現力豊かにかつ読み易く書けることがわかりましたね!