ファンクション(関数)

一度、膨大なコードを書き始めると、それらの構造をより簡単かつ整理された状態で把握できるように、構築しまとめたいと感じることになるでしょう。ファンクション(関数)はそんなことをとても効果的に成し遂げる方法です。この関数を使うとコードのまとまりに対して名前をつけることも可能になります。早速、見ていきましょう。

関数の定義

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

ここではfooという名前を付けた新しい関数を定義しています。この章ではすっかりお馴染みのdo/endブロックと、defineという魔法の言葉の後ろに、この関数に付けたい名前を続けています。関数の名前はfooである必要はなく、barbazといったどんなものでも構いませんが、理想的にはmain_sectionlead_riffといった何か意味のあるものがよいでしょう。

関数を定義するとき、その名前に:(コロン)を付加することを忘れないでください。

関数の呼び出し

いったん1つの関数を定義すると、ただ名前を書くことでそれを呼びだすことができます。

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end
foo
sleep 1
2.times do
  foo
end

fooは、イテレーション(反復)ブロックの中からも使えたり、playsampleが書けるところであればどこからでも使えます。このことは、楽曲の中で利用可能な意味のある言葉を作り出したり、自己表現したりする優れた方法を提供します。

複数の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 nplay 80となるのです。また次にmy_player 90という関数を呼び出すと、今度はn90に置き換えられ、play nplay 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が使われています。

関数に多くの処理を移動することによって、コードをとても表現力豊かにかつ読み易く書けることがわかりましたね!