動的なSynthDefの定義
これまで、SynthDefは事前に定義を済ませておくものと考えていた。つまりシンセの設計はSynthDefによって予め確定しており、引数で振る舞いを変えるという考え方だ。
以下のExample 1では、SynthDef(\perc)でシンセの設計を確定し、loopごとに音高(pch)、持続(dur)、定位(pan)、間隔(itv)、反復(rep)を決定しつつ、Synth(\perc)を演奏している。
// Example 1
(
SynthDef(\perc, {|pch, dur, pan|
var frq, env, sig;
frq = pch.midicps;
env = Env.perc(0.01, dur, 0.2).ar(2);
sig = SinOsc.ar(frq);
sig = Pan2.ar(sig, pan, env);
Out.ar(0, sig);
}).add;
Tdef(\perc_play, {
loop {
var pch = rrand(48, 72.0);
var dur = exprand(0.01, 1);
var pan = rrand(-1, 1.0);
var itv = exprand(0.05, 0.2);
var rep = rrand(1, 10);
// dur = 0.5; itv = 1; // See Ugens
rep.do {
s.bind { Synth(\perc, [pch:pch, dur:dur, pan:pan]) };
itv.wait;
};
};
}).play;
)
ここで、SynthDef(\perc)を拡張して複数のエンベロープや波形を選べるようにしたいとする。まずSelectを使う方法が考えられるが、選択の有無にかかわらず第2引数(array)の中の全てのUGenが立ち上がるため、CPUに負荷がかかると思われる。
// Example 2
(
SynthDef(\perc, {|pch, dur, pan, esel, wsel|
var frq, env, sig;
frq = pch.midicps;
env = Select.ar(esel, [
Env.perc(dur, 0.01, 0.2).ar(2),
Env.perc(0.01, dur, 0.2).ar(2)
]);
sig = Select.ar(wsel, [
SinOsc.ar(frq),
LFTri.ar(frq),
LFSaw.ar(frq),
LFPulse.ar(frq)
]);
sig = Pan2.ar(sig, pan, env);
Out.ar(0, sig);
}).add;
Tdef(\perc_play, {
loop {
var pch = rrand(48, 72.0);
var dur = exprand(0.01, 1);
var pan = rrand(-1, 1.0);
var esel = 2.rand;
var wsel = 4.rand;
var itv = exprand(0.05, 0.2);
var rep = rrand(1, 10);
// dur = 0.5; itv = 1; // See Ugens
rep.do {
s.bind { Synth(\perc, [pch:pch, dur:dur, pan:pan, esel:esel, wsel:wsel]) };
itv.wait;
};
};
}).play;
)
実行中のUGenの数はSCIDE右下のステータスバーの「~u」で確認できる。上の2例のTdef(\perc_play)で、コメントアウトした行をアンコメントすると、一音ごとのUGenの数が確認できるが、Example 1では6u、Example 2では12uと表示される。
さて、ここまではSynthDefを静的に使用していたが、動的な使用、つまり演奏の最中に都度、定義し直すということを考える。Example 3ではSynthDefがTdefの中に入っており、loopごとにSynthDef(\perc)が再定義される仕組みだ。音高等のパラメータは引数ではなく変数で直接与える。
// Example 3
(
Tdef(\perc_play, {
loop {
var pch = rrand(48, 72.0);
var dur = exprand(0.01, 1);
var pan = rrand(-1, 1.0);
var esel = 2.rand;
var wsel = 4.rand;
var itv = exprand(0.05, 0.2);
var rep = rrand(1, 10);
// dur = 0.5; itv = 1; // See Ugens
SynthDef(\perc, {
var frq, env, sig;
frq = pch.midicps;
env = Select.ar(esel, [
Env.perc(dur, 0.01, 0.2).ar(2),
Env.perc(0.01, dur, 0.2).ar(2)
]);
sig = Select.ar(wsel, [
SinOsc.ar(frq),
LFTri.ar(frq),
LFSaw.ar(frq),
LFPulse.ar(frq)
]);
sig = Pan2.ar(sig, pan, env);
Out.ar(0, sig);
}).add;
rep.do{
s.bind { Synth(\perc) };
itv.wait;
};
};
}).play;
)
Example 2と同じくSynthDef(\perc)はSelectを使用しているため、第2引数の全てのUGenが立ち上がる。コメントアウト行をアンコメントするとステータスバーに10uと表示される。
Example 4ではSelectの代わりに条件分岐switchを用いている。この場合、SynthDef(\perc)には選択肢の中のいずれか一つのUGenだけが書き込まれる。コメントアウト行をアンコメントするとステータスバーに4uと表示される。
// Example 4
(
Tdef(\perc_play, {
loop {
var pch = rrand(48, 72.0);
var dur = exprand(0.01, 1);
var pan = rrand(-1, 1.0);
var esel = 2.rand;
var wsel = 4.rand;
var itv = exprand(0.05, 0.2);
var rep = rrand(1, 10);
// dur = 0.5; itv = 1; // See Ugens
SynthDef(\perc, {
var frq, env, sig;
frq = pch.midicps;
env =
switch ( esel )
{ 0 } { Env.perc(dur, 0.01, 0.2).ar(2) }
{ Env.perc(0.01, dur, 0.2).ar(2) };
sig =
switch ( wsel )
{ 0 } { SinOsc.ar(frq) }
{ 1 } { LFTri.ar(frq) }
{ 2 } { LFSaw.ar(frq) }
{ LFPulse.ar(frq) };
sig = Pan2.ar(sig, pan, env);
Out.ar(0, sig);
}).add;
rep.do{
s.bind { Synth(\perc) };
itv.wait;
};
};
}).play;
)
Tdef(\perc_play).stop;
ところで、Example 3,4ではUGenの数は記述の通りであり、Example 1,2はそれより2つ多い。
この記事が気に入ったらサポートをしてみませんか?