この講義の前半はSonic Piを使用してライブコーディングを活用した作曲やパフォーマンスについて学びました。そして中盤から後半にかけて、SuperColliderを使用した音響合成の基礎を学んできました。Sonic Piが和声やリズムや旋律といった音楽のマクロな構造を記述するための言語とすると、SuperColliderは波形単位で音を生成するミクロな構造の創作でした。いよいよ今回からは、Sonic PiとSuperColliderを融合して、音のミクロな構造からマクロな構造まで全てを統合していきます。
今回はまず始めの一歩として、SuperColliderで定義した簡単な楽器定義(SynthDef)を、Sonic Piに読み込んで実際に演奏するところまでを解説します。
スライド資料
サンプルコード
//SuperColliderとSonic Piの連携
//基本形
SynthDef("piTest", {
//出力先のバスを引数で設定
arg out_bus = 0;
//440HzのSin波生成
var mix = SinOsc.ar(440).dup;
//Envelope生成
var env = EnvGen.ar(Env.perc(0.0, 1.0, 1.0), doneAction: 2);
//Envelope適用
mix = mix * env;
Out.ar(out_bus, mix);
}
//ファイルの出力先を指定
).writeDefFile("/Users/tado/Desktop/my-synths");
//音程(note)と音量(amp)を受け取る
SynthDef("piTest", {
//音程と音量を引数を指定
arg note = 52, amp = 1, out_bus = 0;
//音程(MIDI番号)から周波数へ
var freq = note.midicps;
//周波数をSin波に適用
var mix = SinOsc.ar(freq).dup;
var env = EnvGen.ar(Env.perc(0.0, 1.0, 1.0), doneAction: 2);
mix = mix * env;
Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");
//エンベロープとPanを適用
SynthDef("piTest", {
arg out_bus = 0, note = 52, amp = 1, attack = 0, release = 1, pan=0;
var freq = note.midicps;
var mix = SinOsc.ar(freq);
var env = EnvGen.ar(Env.perc(attack, release, 1.0), doneAction: 2);
//Panを適用
mix = Pan2.ar(mix * env, pan);
Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");
//Moog風楽器
SynthDef("piTest", {
arg out_bus = 0, note = 52, amp = 1, attack = 0, release = 1, detune = 1.01, pan=0;
var freq = note.midicps;
var mix = MoogFF.ar(
Pulse.ar([freq,freq*0.5], 0.8),
freq*2.5,
128
);
var env = EnvGen.ar(Env.perc(attack, release, amp), doneAction: 2);
mix = Pan2.ar(mix * env, pan);
Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");
先週学んだSuperColliderで「楽器」を定義する SynthDef を利用して、様々な音響合成の手法について実際に音を聞きながら学んでいきます。まず今回は、ある信号のパラメーターをもう一つの信号で変化(変調)させる「変調合成」という手法について紹介します。変調合成は、信号の何を変調するのかによって、AM(RM)、FMという種類に分けられます。それぞれの変調合成の音色の違いなどに注意しながら、SuperColliderでの実現のやり方を学んでいきましょう。
スライド資料
コードサンプル
// SuperColliderによる音響合成変調合成1- RMとAM
// RM変調
SynthDef("test-rm",{
var car, mod, rm;
mod = SinOsc.ar(880, 0, 1.0);
car = SinOsc.ar([440,442], 0, 0.5);
rm = car * mod;
Out.ar(0, rm);
}).play;
// RM変調2 - マウスでModulatorの周波数を変更
SynthDef("test-rm",{
var car, mod, rm;
mod = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 1.0);
car = SinOsc.ar([440,442], 0, 0.5);
rm = car * mod;
Out.ar(0, rm);
}).play;
// RM変調3 - 2つのModulator
SynthDef("test-rm",{
var car, mod1, mod2, rm;
car = SinOsc.ar(440, 0, 0.5);
mod1 = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 1.0);
mod2 = SinOsc.ar([1/6.1,1/7.9]);
rm = car * (mod1 * mod2);
Out.ar(0, rm);
}).play;
// AM変調
SynthDef("test-am",{
var car, mod, rm;
mod = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 0.5, 0.5);
car = SinOsc.ar([440,442], 0, 0.5);
rm = car * mod;
Out.ar(0, rm);
}).play;
SynthDef.new("test-am",{
var car, mod1, mod2, am;
car = SinOsc.ar(440, 0, 0.5);
mod1 = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 0.5, 0.5);
mod2 = SinOsc.ar([1/8,1/7]);
am = car * (mod1 * mod2);
Out.ar(0, am);
}).play;
// AM + LFNoise
(
SynthDef("rand-am",{
arg freq = 440, amp = 0.5, modFreq = 400;
var car, mod1, mod2, am;
car = SinOsc.ar(freq, 0, amp);
mod1 = SinOsc.ar(LFNoise1.kr(5.reciprocal, modFreq), pi.rand, 0.5, 0.5);
mod2 = SinOsc.ar(LFNoise1.kr([1/8, 1/7])0, 0.5, 0.5);
am = car * (mod1 * mod2);
Out.ar(0, am);
}).add;
)
(
Synth("rand-am", ["freq", 110, "amp", 0.2, "modFreq", 1200]);
Synth("rand-am", ["freq", 220, "amp", 0.2, "modFreq", 200]);
Synth("rand-am", ["freq", 440, "amp", 0.2, "modFreq", 200]);
Synth("rand-am", ["freq", 880, "amp", 0.2, "modFreq", 100]);
Synth("rand-am", ["freq", 1780, "amp", 0.05, "modFreq", 20]);
)
//FM基本
SynthDef("test-fm", {
arg cfreq = 440, mfreq = 111, index = 200;
var car, mod;
mod = SinOsc.ar(mfreq, 0, index);
car = SinOsc.ar([cfreq, cfreq*1.01] + mod, 0, 0.5);
Out.ar(0, car);
}).play;
//FMマウスで操作
SynthDef("test-fm",{
var car, mod;
mod = SinOsc.ar(MouseX.kr(1, 1000, 1), 0,
MouseY.kr(1, 10000, 1));
car = SinOsc.ar([440,442] + mod, 0, 0.5);
Out.ar(0, car);
}).play;
//FM応用
(
SynthDef("fm1", { arg freq = 440, detune = 2, carPartial = 1, modPartial = 1, index = 3, mul = 0.2;
var mod, car;
mod = SinOsc.ar(
[freq, freq+detune] * modPartial, 0,
freq * index * LFNoise1.kr(1/10)
);
car = SinOsc.ar((freq * carPartial) + mod, 0, mul);
Out.ar(0, car);
}).add;
)
(
Synth("fm1", ["modPartial", 2.4]);
Synth("fm1", ["modPartial", 2.401]);
Synth("fm1", ["freq", 110, "modPartial", 3.1213, "index", 10]);
Synth("fm1", ["freq", 220, "modPartial", 10.99, "index", 20]);
)
//FM + エフェクト
(
SynthDef("fm2", { arg bus = 0, freq = 440, detune = 2, carPartial = 1, modPartial = 1, index = 3, mul = 0.1;
var mod, car;
mod = SinOsc.ar(
[freq, freq+detune] * modPartial,
0,
freq * index * LFNoise1.kr(10.reciprocal).abs
);
car = SinOsc.ar((freq * carPartial) + mod, 0, mul);
Out.ar(bus, car);
}).add;
SynthDef("preDelay", { arg inbus = 2;
ReplaceOut.ar(
4,
DelayN.ar(In.ar(inbus, 1), 0.048, 0.048)
)
}).add;
SynthDef("combs", {
ReplaceOut.ar(
6,
Mix.arFill(7, { CombL.ar(In.ar(4, 1), 0.1, LFNoise1.kr(Rand(0, 0.1), 0.04, 0.05), 15) })
)
}).add;
SynthDef("allpass", { arg gain = 0.2;
var source;
source = In.ar(6, 1);
4.do({source = AllpassN.ar(source, 0.050, [Rand(0, 0.05), Rand(0, 0.05)], 1) });
ReplaceOut.ar(8, source * gain)
}).add;
SynthDef("theMixer", { arg gain = 1;
ReplaceOut.ar(
0,
Mix.ar([In.ar(2, 1), In.ar(8, 2)]) * gain
)
}).add;
)
(
Synth("fm2", ["bus", 2, "freq", 440, "modPartial", 2.4]);
Synth("fm2", ["bus", 2, "freq", 448, "modPartial", 2.401]);
Synth.tail(s, "preDelay");
Synth.tail(s, "combs");
Synth.tail(s, "allpass");
Synth.tail(s, "theMixer", ["gain", 0.64]);
)