シンプルなシンセのシミュレーション(1)
今回(と次回)は、シンプルなシンセのシミュレーションをしようと思います。
たいていのシンセは、[音源]-[フィルター]-[アンプ]という構造をしてると思います。これにLFOやエンベロープ他、各シンセならではのパラメータを駆使して音作りを行なうわけですが、今回は、この最小単位のシンセをSuperColliderで作ってPbindでシーケンスさせることを目標にします。
各パートの役割は以下のような感じだと思います。
では早速、これをSuperColliderでシミュレートします。
「command + b」で、サーバブートしておき、コードを書いていきます。
//ex1
(
{
var wg, amp=0.2;
wg = Saw.ar(220)!2 * amp;
}.play;
)
今回は、音源にSawを使いました。
wgという変数(入れもの)にSaw.arを入れて、playしています。
220という数字は、中央ラの音(440Hz)のオクターブ下です。
そのまま鳴らすと爆音になる(音量がマックスの1になる)ので、ampに0.2を入れて、Saw.ar全体に掛け算しています(0.2の音量で鳴ってくれます)。
!2は、左右のチャンネルから鳴らしたいので、こう書いています。
(!2についての詳細は、03.フィルターの記事にて。)
コードを実行すると(command + Returnすると)音が出ますが、ここまでだとまだフィルターが入ってません。
※音を止めるには「command + ピリオド」です。
フィルターを追加します。
今回は、レゾナンス付きローパスフィルターRLPFを使います。
RLPF.arの、ひとつめのパラメータがインプットさせたい信号ですので、そこにwgを入れます。
//ex2
(
{
var wg, amp=0.2, flt;
wg = Saw.ar(220)!2 * amp;
flt = RLPF.ar(wg, 2000);
}.play;
)
2000は、カットオフ周波数です。(2kHzです。)
お好みの周波数に合わせてOKです。
さて、このex2だと下図のように、信号の流れの最下流がフィルターになってるので、
最下流をアンプ(音量)にしたいです。
(アンプとフィルターが逆になっていても、今のところ出音としては同じですが、フィルターで音作りしたものに対してトータルで音量調整したいので、逆にしておきたい。。)
というわけで、コードに少し手を加えます。
//ex3
(
{
var wg, amp=0.2, flt;
wg = Saw.ar(220)!2;
flt = RLPF.ar(wg, 2000) * amp;
}.play;
)
これで、ノコギリ波をインプットしたフィルターユニットに対して音量調整を行なうかたちになりました。
Pbindでフレーズを鳴らすのが目標なので、この音をSynthDefに入れます。
SynthDefに入れると、音色に名前をつけることができるのと、アウトプットを指定することができます。
さっきのコード(ex3)の以下の3行を、
(
{
}.play;
)
SyntheDefフォーマットの真ん中にコピペする。
(
SynthDef(\synth1, { ←名前をつけられる
Out.ar(0, flt); ←アウトプットを指定できる(今回はデフォルトのゼロ)
}).play;
)
出来上がったSynthDefはこちら。(実行すると音が鳴ります。)
//ex4
(
SynthDef(\synth1, { //synth1とう音色名にしました
var wg, amp=0.2, flt;
wg = Saw.ar(220)!2;
flt = RLPF.ar(wg, 2000) * amp;
Out.ar(0, flt); //fltをデフォルトの0から出力
}).play;
)
次に、アンプエンベロープ(aEnv)を作っておきます。
Pbindで鳴らすには、このSynthDefが鍵盤ON/OFFの情報を受け取れるようになっている必要があるので。
今回はadsrエンベロープを使いました。
ampにアンプエンベロープaEnvを掛けることで、音量変化を実現します。
//ex5
(
SynthDef(\synth1, {
var wg, amp=0.2, flt, aEnv;
aEnv = EnvGen.kr(Env.adsr(0.15, 1.0, 0.6, 0.15), 1, doneAction:2);
wg = Saw.ar(220)!2;
flt = RLPF.ar(wg, 2000) * amp * aEnv;
Out.ar(0, flt);
}).play;
)
doneActionの左側の1は、「鍵盤ON」の意味です。
ここを0にすると「鍵盤OFF」となり、実行しても音は出ません。
(doneAction:2についてはこちらをご覧ください。乱暴な言い方をしてしまえば、エンベロープを作る時はほぼほぼ必ずここにdoneAction:2と書いておく必要があります。次回の記事で例外が出てくる見込みです。そのときにまた説明追記しておこうと思います。)
それではいよいよ、Pbindでシーケンスさせるための最後の工程です。
「鍵盤ON/OFF」のgateと「音程」のfreqをargに登録します。
これでSynthDefの外から(Pbindから)鍵盤ON/OFFと音程をコントロールすることができるようになります。
//ex6
(
SynthDef(\synth1, {
arg gate=1, freq;
var wg, amp=0.2, flt, aEnv;
aEnv = EnvGen.kr(Env.adsr(0.15, 1.0, 0.7, 0.15), gate, doneAction:2);
wg = Saw.ar(freq)!2;
flt = RLPF.ar(wg, 2000) * amp * aEnv;
Out.ar(0, flt);
}).add;
)
//gateのデフォルト値は1(鍵盤ON)を設定しておく必要があります。
そして、今までSynthDefに対して.playしていたのを、.addに置き換えてコードを実行します。
これで、サーバにこのSynthDefが置かれます。
Pbindを実行します。
//ex7
(
Pbind(
\instrument, \synth1,
\midinote, Pseq([59, 66, 69, 66, 73, 59, 64, 66], inf),
\dur, 0.5,
\sustain, 0.1
).play(TempoClock(140/60));
)
サーバに置かれたsynth1という音色に対してmidinoteを指示しています。(各midinoteの鍵盤を弾いている(ON/OFFしている)イメージです。)
フィルターにレゾナンスを設定することもできます。
こんな感じで、RLPF.arに三つ目のパラメータを入力できます。
1がレゾナンスなしで
0がレゾナンスMAXです。
(ex6では、パラメータを入れなかったので、デフォルトの1で処理されていました。)
実際のシンセならば、フィルターにもエンベロープをあてたり、ピッチにLFO(ビブラート)をあてたりしたいところです。
次回、そのあたりの機能を追加していこうと思います。
ちなみに、ex6のコードは、下記のように書いても全く同じ意味で同じ信号の流れです。
//ex8
(
SynthDef(\synth1, {
arg gate=1, freq;
var wg, amp=0.2, flt, aEnv;
aEnv = EnvGen.kr(Env.adsr(0.15, 1.0, 0.7, 0.15), gate, doneAction:2);
wg = Saw.ar(freq)!2;
wg = RLPF.ar(wg, 2000) * amp * aEnv;
Out.ar(0, wg);
}).add;
)
SuperColliderのコード上の「=(イコール)」は「=を挟んで左と右が同等」という意味ではなく「左側の入れ物に、右のものを入れる」という意味なので。(このあたりピンと来ない人は、こちらの記事をぜひ読んでみてください)
今回は音源・フィルター・アンプ、の役割をわかりやすくコードにしたかったので、ex6のようにwg/flt/ampが文字で見えるかたちにしました。
<目次へ>
https://note.com/sc3/n/nb08177c4c011