ChucK入門 #6 - 関数(手続き)を作る
なかなか音を鳴らす、ちょっといじるだけでもずいぶん大変だなあ、という印象を持ったかもしれません。今回は、「音を鳴らす」部分を関数/手続き化しちゃいましょう。
たとえばシンセも、外界から見ると「どの音高を、どの強さで、どの程度の長さで発音するか」などといった、比較的シンプルなパラメータの受け渡しで(一例として)ブラックボックス化出来そうです。
音を鳴らす、という部分を関数化してみましょう。
fun void buzz( float hz ) { SinOsc s => dac; hz => s.freq; SawOsc env; env => blackhole; 0.0 => env.width; 0.8 => env.freq; 1::samp => now; while (true) { env.last() => s.gain; if (env.last() <= 0) { break; } 1::ms => now; } }
はい、関数の宣言は
fun <戻り値の型> 名前( <引数の型> <引数の名前> ... )
となります。上記のソースの例だと 戻り値を持たない(voidの) 1つのfloatの引数を取るbuzzという名前の関数を定義しているわけですね。
中身は…いままでの知識だけで読み解けるでしょうか? while, if あたりの説明はガンガン割愛します。CやJavaなどとも非常に似ていますので・・・。
引数は「周波数」を示していることがわかります。では env というオシレータは何でしょうか。
SawOscはノコギリ波ですが、widthプロパティに0をセットしてやると、ピークから下降してきてゼロクロスするノコギリ波を作ることができるようです。で、whileの中でノコギリ波の出力を、サイン波のオシレータのgainにセットしている・・・。
つまり、SawOscはボリュームに対するエンベロープの役目を果たしています。音が鳴ると同時にボリュームは線形に減衰して、0になったら終了するようになっています。
さて、この関数を呼び出してみましょう
buzz( Std.mtof(60) ); buzz( Std.mtof(64) ); buzz( Std.mtof(67) ); buzz( Std.mtof(71) );
実行してみると、音が4回鳴りましたね?
関数にすることによってスッキリしました!
ところで、Std.mtof って何でしょうか。
Std.mtof()もまた関数です。引数を1つ取り、それはMIDIのノート番号で、戻り値は周波数です。つまり音階を周波数に変換する関数なのです。
60はC音で、1増えると1半音上がりますから、64はE音、67はG音、71はB音となります。
この呼び出しはCM7基本形のアルペジオになっているわけです。
少しずつ、面白くなってきましたね!!