SuperColliderのエンベロープ、式の評価順、マウスとキーボードの入力、arとkrについてです。
エンベロープ Env, EnvGen
Env でエンベロープを作れます。
test でエンベロープを音としてテストできます。また plot でデフォルトのエンベロープをグラフにします。
Env().test.plot;
デフォルトから変えます。
Env( [0, 1, 0], [0.1, 0.5], [2, \sine] ).test.plot;
Env(レベル, 時間, カーブ) となっています。カーブの種類については Env のヘルプにまとまっています。引数がややこしいですが以下のような意味です。
Env( [点0, 点1, 点2, ...], [点0から点1へ至る時間, 点1から点2へ至る時間, ...] [点0と点1を結ぶ線の種類, 点1と点2を結ぶ線の種類, ...] );
作ったエンベロープをUGenに適用するには EnvGen に入れて引数として渡してやります。
{
var freq = 40;
var pitchShift = 1000;
var detune = 6;
var env = Env(
[0, 1, 0],
[0.1, 1.5],
[2, \sine]
);
var envGen = EnvGen.ar(env, doneAction: 2);
var osc = Array.fill(4, { |index|
Pulse.ar(
freq + (detune * index) + (pitchShift * envGen),
0.5 * envGen,
0.2 * envGen)});
[osc, osc]
}.play;
doneAction: 2 と指定することでエンベロープが終わると同時にシンセをfreeします。この指定がないと演奏を終えたシンセのリソースがサーバ側で確保されたままになりCPUやメモリを圧迫してしまいます。シンセに関するサーバの状態は s.plotTree かCtrl+Alt+TでNode Treeを表示して確認することができます。 2 以外の値についてはヘルプのUGen done-actionsで確認できます。
この他のエンベロープはヘルプのBrowserからUGens > Envelopesとたどればいくつか見つかります。
式の評価とメソッドの中置
sclangでは常に前から順番に計算が行われます。 * や / などを使う時は注意してください。
(1 + 2 * 3).postln; // 9 (1 + (2 * 3)).postln; // 7
Array に対しても直接、演算子がつかえます。
([1, 2, 3] + 4).postln; // [ 5, 6, 7 ] ([-1, 0, 1] > 0).postln; // [ false, false, true ]
引数を2つとるメソッドは中置できます。
(768 gcd: 1024).postln; // 256 gcd(768, 1024).postln; // 256
SynthDef の内部などサーバ側で評価される式は常に浮動小数点数で計算が行われます。 > や < など普段はBooleanを扱う演算は false のとき 0.0, true のとき 1.0 を返すようになります。
マウスとキーボードからの入力
MouseXとMouseYでポインタの位置を使えます。MouseButtonは左クリック(ボタン1)のみに反応しました。以下の例はマウスクリックで音が鳴り、ポインタの位置で音が変化します。
{
var freq = MouseX.kr(100, 800, 1);
var osc = PMOsc.ar(
freq,
freq,
MouseY.kr(0.01, 100, 1),
0,
MouseButton.kr(0, 1, 0));
[osc, osc]
}.play;
KeyStateでキーボードの入力を受け取ります。keycodeの値は環境によって変わるようです。以下の例は私が試した環境ではスペースキーに反応しました。
{ SinOsc.ar(KeyState.kr(65, 100, 200), 0, 1) }.play;
arとkr
arはaudio rateの略でサンプリングレートの解像度で計算することを意味します。krはcontrol rateの意でサンプリングレートの1/64の解像度で計算を行うそうです。
音を計算する時はサンプリング周波数の解像度で計算する必要があるのでarを使います。krは解像度が低くなりますがヘルプの例では変調などに使われています。
以下の例で違いを確認できます。
{
[
SinOsc.ar(Pulse.ar(Pulse.ar(0.5, 0.5, 200), 0.5, 400), 0.5, 0.3),
SinOsc.ar(Pulse.kr(Pulse.kr(0.5, 0.5, 200), 0.5, 400), 0.5, 0.3)
]
}.play;