1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
title:: 15
summary:: Mark Polishook tutorial (JP)
categories:: Tutorials>Mark_Polishook_tutorial>Japanese_version
related:: Tutorials/Mark_Polishook_tutorial/00_Introductory_tutorial
section::ルーチンとクロック
クロックは、SuperColliderの中で自動のアルゴリズミックなスケジュ−リングを生成する際に使うメカニズムを提供します。クロックはルーチン、タスク、そしてパターンを再生します。
パターンとタスクはルーチンから作られます。
ルーチンに対する最初のアーギュメント(そして通常は唯一のアーギュメント)は関数です。
これが関数の一例です。
code::
// 関数を実行するには.valueメッセージを送る
f = { "hello, world" };
f.value;
::
これはルーチンの中に関数を配置したものです。.yieldメッセージを送ることで関数の中の式を評価します。
code::
r = Routine({ "hello, world".yield.postln });
::
ルーチンを実行するには、評価して下さい。
code::
// ルーチンを評価するには、.nextメッセージを送る
r.next;
::
もう一度やってみましょう。
code::
r.next;
::
これは一度ルーチンが"yield"(受け渡し)すると、関数の中にさらなるコードがあるか、resetメッセージを受け取らない限り、終了することを示します。
code::
r.reset;
r.next;
::
////////////////////////////////////////////////////////////////////////////////////////////////////
この引用では、ルーチンに.nextメッセージが送られると、3つの表現(文字列)を順番に引き渡すことを引き起こします。例えば、nextメッセージが送られると、文字列が引き渡され、nextメッセージが送られると、文字列が引き渡さるという様にです。
code::
(
r = Routine({
"hello, world".yield;
"what a world".yield;
"i am a world".yield;
});
)
::
上の例での最後の.nextメッセージはnilを返すでしょう。最後の表現が引き渡されると、ルーチンはリセットされるまで常にnilを返します。
code::
r.next;
r.next;
r.next;
r.next;
::
////////////////////////////////////////////////////////////////////////////////////////////////////
このルーチンを.doメッセージを使って書き直すと、loopを作ります。
code::
(
r = Routine({
var array;
array = [ "hello, world", "what a world", "i am a world" ];
3.do({ array.choose.yield })
});
)
::
このdo loopをルーチンの中のループよりももう1回多く実行すると、前の例と同じ様に、3つの文字列とnilを返します。
code::
4.do({ r.next.postln });
::
////////////////////////////////////////////////////////////////////////////////////////////////////
次に、このルーチンを.waitメッセージを含む形で書き直します。.waitメッセージは、その数字が示す秒単位で指定した時間だけ、ルーチンを「プレイ」するクロックを一時停止させます。
code::
(
r = Routine({
var array;
array = [ "hello, world", "what a world", "i am a world" ];
3.do({ 1.wait; array.choose.postln })
});
)
::
以下のコードが示す様に、ルーチンに.resetメッセージを追加します。このようにして、ルーチンは常に再スタートできる様になります。そして、クロックとともにルーチンをプレイします。
以下のコードはSuperColliderがイベントをスケジューリングする時に使用する3つのクロックを示します。
code::
SystemClock.play(r.reset); // 最も正確
AppClock.play(r.reset); // GUIで使用する
TempoClock.new.play(r.reset); // 主に拍でスケジューリングするために使われる
::
////////////////////////////////////////////////////////////////////////////////////////////////////
または、そのプロセスを省略することができ、その場合にはデフォルトとしてTempoClockが使用されます。
code::
r.reset.play;
::
////////////////////////////////////////////////////////////////////////////////////////////////////
section::ルーチンを用いたシンセシスのスケジューリング
ルーチンの中にシンセを入れます。シンセの中のSynthDefが必ずエンベロープを持つ様にし、そのエンベロープのdoneActionパラメータを2にセットします。これによって、エンベロープが終了した後に、そのシンセのために必要とされていたメモリが解放されます。
code::
(
SynthDef("fm2", {
arg bus = 0, freq = 440, carPartial = 1, modPartial = 1, index = 3, mul = 0.2, ts = 1;
// インデックスの値は通常0から24まで
// carPartial :: modPartial => car/mod ratio
var mod;
var car;
mod = SinOsc.ar(
freq * modPartial,
0,
freq * index * LFNoise1.kr(5.reciprocal).abs
);
car = SinOsc.ar(
(freq * carPartial) + mod,
0,
mul
);
Out.ar(
bus,
car * EnvGen.kr(Env.sine(1), doneAction: 2, timeScale: ts)
)
}).add;
)
(
r = Routine({
12.do({
Synth("fm2", [\freq, 400.0.rrand(1200), \carPartial, 0.5.rrand(2), \ts, 0.1.rrand(4)]);
2.wait;
})
});
)
r.reset.play;
::
////////////////////////////////////////////////////////////////////////////////////////////////////
ルーチンの中で引き起こされたシンセを、ルーチンの外側で実行するエコー・エフェクト・ユニットを通してプレイします。
code::
(
SynthDef("echoplex", {
ReplaceOut.ar(
0,
CombN.ar(
In.ar(0, 1),
0.35,
[Rand(0.05, 0.3), Rand(0.05, 0.3)],
// シンセが生成されるたびにランダムな値を生成する
7,
0.5
)
)
}).add;
// ~sourceグループをルートノードの先頭に追加し、~effectsグループをる−とノードの最後に追加する
~source = Group.head(s);
~effect = Group.tail(s);
r = Routine({
// ループはinf.doと同じ。例えば、永遠に実行される無限ループを生成する。
loop({
Synth.head( // ~sourceグループの先頭にシンセを追加する
~source,
"fm2",
[
\outbus, 0, \freq, 400.0.rrand(1200), \modPartial, 0.3.rrand(2.0),
\carPartial, 0.5.rrand(11), \ts, 0.1.rrand(0.2)]
);
2.wait;
})
});
// 2つのechoplexesーこれらを~effectsグループの先頭に順に追加する
Synth.head(~effect, "echoplex");
Synth.head(~effect, "echoplex");
)
// ルーチンをプレイする
r.reset.play;
::
////////////////////////////////////////////////////////////////////////////////////////////////////
|