見出し画像

13.SuperColliderでモジュレーション


SuperColliderはモジュレーションの自由度がヤバイほど自由です。(日本語になっていない。)
思いつくアイデアの数だけ、やり方が存在すると思いますし、音色のバリエーションもそれだけ生まれます。
今回は、そのうちの少しだけですが、モジュレーションに関することを書いていきます。

題材のコード

実行するとシンプルなサイン波が鳴るこのコードを題材に、モジュレーションを加えていきます。

(
SynthDef(\plain, {
	var sig, freq=440, amp=0.3;
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp)
}).play;
)


変調いろいろ


題材のサイン波のピッチを変調します。
まずはLineを使って。

(
SynthDef(\pitch_mod1, {
	var sig, freq=440, amp=0.3, mod;
	mod = Line.ar(0, 440, 1.0);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

もとのfreq=440にLineを足してます。このLineの設定だと1秒間で0から440に変化するので、sigのサイン波のピッチは440から880に変化することになります。

下記を実行してFreq Analyzerを表示しておくと目で見ても確認できます。

FreqScope.new;

では、変調するピッチが周期的に変化するとどうなるでしょうか。
下記の例ではLine.arをSinOsc.arに置き換えました。

(
SynthDef(\pitch_mod2, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 10);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

modのサイン波は-10〜+10という範囲を1秒周期で繰り返している状態です。
sigのfreq(440)にそれを足しているので、ピッチは周期的に450〜430を繰り返します。

pollメソッドを使うと、それを数値で確かめることができます。

(
SynthDef(\pitch_mod2, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 10);
	sig = SinOsc.ar(freq + mod.poll);
	Out.ar(0, sig!2 * amp)
}).play;
)

.pollは出力する数値をPost windowに表示してくれます。
modの出力-10から+10を繰り返しPost windowに表示しています。
(pollは1秒につき10回の表示なので、ちょっと荒いですが。。)

コードの一部を編集して
SinOsc.ar((freq + mod).poll)
とすることで、サイン波のピッチそのものをPost windowに表示させることもできます。
450〜430であるということがわかると思います。

音としてはいわゆるビブラートっぽい状態です。modのサイン波の周期を1から3か4あたりに変えてみると、よりビブラートのイメージに近くなります。


mulの値について


ところで、これまでのnoteで僕、「mulの値は最大1.0まで。それを超えると音が歪んだり耳を傷めてしまうかも。」と何度か書きましたが、このmodのサイン波のmulは10となっています。これはピッチをモジュレートしているので、モジュレート先のピッチの値に合わせてmulの値を決めたものです。つまりモジュレートする場合はモジュレート先のパラメータに合わせて1.0を超えても大丈夫です。(音量をモジュレートするときだけは要注意です!!)

ただし色々な値で実験するときは、値を少しずつ増やして(減らして)いくなどして慎重に実験することをお勧めします。
とんでもない値を入れて、爆音が鳴ったり高音が鳴ったりして耳(鼓膜)やスピーカーを傷めるのを避けるためです。

話を戻します。
先ほどのmodのサイン波のmulパラメータをガツンと440まで上げてみます。
ピッチを10から-10揺らすのではなく、もっと大きな範囲で揺らす実験です。

(
SynthDef(\pitch_mod4, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 440);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

modの周期をもっと大きな数値(10とか20とか100とか200など)で試すと音色がいろいろと変化します。いわゆるFM変調の状態です。

ではその周期を、連続的に変化させるとどうなるでしょうか。

(
SynthDef(\pitch_mod5, {
	var sig, freq=440, amp=0.3, mod, line;
	line = XLine.ar(1, 440, 10);
	mod = SinOsc.ar(line, 0, 440);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

XLineを使って、周期を1から200まで10秒かけて上げてみました。

line = XLine.ar(1, 440, 10)
の部分を
line = MouseX.kr(1, 440)
に置き換えると、音色変化をマウス位置で確認することもできます。


XLineに関すること


XLineが初めて出てきましたが、LineとXLineの違いは、直線的に変化するかカーブして変化するかの違いです。

Line
XLine

ただ、ここで注意です。
ヘルプファイルによると、XLineでは「パラメータにゼロを使ってはいけない」らしいです。なので
XLine.ar(0, 220, 10)とかはやってはいけない。
なのでもし「0から220」をやりたい場合は、XLine.ar(0.001, 220, 10)などで代用するしかないです。
あとゼロを通過するのもダメらしいので
XLine.ar(-10, 220, 10)とかもNGなので気を付けましょう。
ヘルプファイルにダメと書いているので、僕はやったことありません。
Lineのほうはゼロを使っても大丈夫です。

XLine


FMシンセっぽく


話を戻しまして、ちょっとオマケのコードです。
下記のようにmodの周波数を基音の周波数の整数倍になるようにしてやるとFM音源ぽくエディットできます。ratioの数字を変えて試してみてください。

(
SynthDef(\pitch_fm1, {
	var sig, freq=440, amp=0.3, mod, ratio=4;
	mod = SinOsc.ar(freq * ratio, 0, 220);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

YAMAHAのシンセで言うところの、
キャリアがsigのサイン波で
モジュレータがmodのサイン波、
ratioがRATIO、というイメージですね。
(さらにampがキャリアのOUTPUTでmodの220の部分がモジュレータのOUTPUT)

さらに基音キャリア用とモジュレータ用に別々のエンベロープをつけるともっとFM音源ぽくなります。簡易2オペFMシンセです。
※modの振幅も上げてみました。(1600にしたのは聴いてみてイイ感じだったからです。)この数字をどんどん下げていくとsigをモジュレートしなくなっていくので出音はサイン波に近づいていきます。

(
SynthDef(\pitch_fm2, {
	var sig, freq=440, amp=0.3, mod, ratio=10, env1, env2;
	env1 = EnvGen.kr(Env.perc(0.01, 0.6));
	env2 = EnvGen.kr(Env.perc(0.01, 1.3), doneAction:2);
	mod = SinOsc.ar(freq * ratio, 0, 1600) * env1;
	sig = SinOsc.ar(freq + mod) * env2;
	Out.ar(0, sig!2 * amp)
}).play;
)

これもratioの数字を変えて試してみてください。5.5とか整数倍ではない値にするとちゃんと非整数倍音も発生します。

※doneActionがenv2にしか設定されていないのは、「env1のほうがエンベロープの総尺が短いので、env1にもdoneAction:2を設定してしまうとenv1のエンベロープが終わった時点で(env2のほうはまだ再生中なのに)音が止まってしまうから」です。
EnvGen.krを複数使うコードの場合、doneAction:2はリリースが長い方に設定するのがコツです。


LFOにLFO


ところでモジュレーションといえば、LFOをLFOでモジュレートするのもアリですよね。

(
SynthDef(\pitch_mod6, {
	var sig, freq=440, amp=0.3, mod, sine;
	sine = SinOsc.ar(8, 0, 10);
	mod = SinOsc.ar(1 + sine, 0, 440);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

modのサイン波を違うサイン波でモジュレートするだけで独特なLFO波形になります。
サイン波ではなくSawでも何でも試すことができます。


下記はLFOのレートをEnvGenやLineでモジュレートした例です。

(
SynthDef(\pitch_mod6, {
	var sig, freq=440, amp=0.3, mod, line;
	line = Line.ar(20, 0, 2.5);
	mod = SinOsc.ar(line, 0, line*10);
	sig = SinOsc.ar(freq + mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

同じlineをmodのサイン波のfreqとmulに使用しています。


AM変調とリング変調


パルス波をampに掛け算しました。
最終出力(音量)が変調される例です。

(
SynthDef(\amp_mod1, {
	var sig, freq=440, amp=0.3, mod, env;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = LFPulse.ar(8).lag(0.05);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

LFPulseそのままだとパルスの角(?)がプチプチ言ってしまうのでlagというメソッドを使って角を丸くしています。
(0.05の部分をエディットすると角の丸さを変更できます。)

LFPulseのままだとカクカク
.lagで角を丸くできる


addについて


LFPulse.arはデフォルトでは0〜1の値を繰り返します。なのでampの値を正の値でモジュレートできました。
では、-1〜1の値を繰り返すSinOsc.arでampをモジュレートするとどうなるでしょう。
ちょっとマニアックな話(AM変調やリング変調の話)になりますが、実験してみます。

(
SynthDef(\amp_mod2, {
	var sig, freq=440, amp=0.3, mod, env;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(8, 0, 1, 0);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

普通のSinOsc.arだとこんな感じの音↑になります。
ampを変調しているサイン波が「-1〜1の値を繰り返している」状態です。

さて、同じサイン波を使って「0〜1の値を繰り返している」状態を作って聴き比べたいです。

ここでaddというパラメータが活躍します!
SinOsc.ar(freq: 440.0, phase: 0.0, mul: 1.0, add: 0.0)

addは、サイン波が揺らぐ値の中心値を変更できます。
デフォルトではゼロです。

SinOsc.ar(8, 0, 1, 0)

addパラメータが0


このaddを例えば1にしてやると、中心値が1になります。
SinOsc.ar(8, 0, 1, 1)

addパラメータが1

「0〜2の値を繰り返している」状態のサイン波が出来上がりました。
このようにaddは、その波形(この場合サイン波)が揺らぐ中心値を設定することができます。

さて、「0〜1の値を繰り返す」サイン波で実験したいので、modのサイン波を下記のように設定します。
SinOsc.ar(8, 0, 0.5, 0.5)

addパラメータが0.5でmulパラメータも0.5


(
SynthDef(\amp_mod3, {
	var sig, freq=440, amp=0.3, mod, env;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(8, 0, 0.5, 0.5);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)


\amp_mod2と\amp_mod3では若干音の印象が違います。
ここで、\amp_mod2も\amp_mod3も、どちらもmodのサイン波の周波数を上げてみます。

(
SynthDef(\amp_mod2, {
	var sig, freq=440, amp=0.3, mod, env;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(80, 0, 1, 0);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)
(
SynthDef(\amp_mod3, {
	var sig, freq=440, amp=0.3, mod, env;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(80, 0, 0.5, 0.5);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

両方とも80にしてみると、明らかに両者の音色↑に差が出ます。

もう少しコードを改造して、それぞれmodを基音のサイン波と同じ周波数freqに設定して、ratioを掛け算できるようにしました。

(
SynthDef(\amp_mod2, {
	var sig, freq=440, amp=0.3, mod, env, ratio=3;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(freq*ratio, 0, 1, 0);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)
(
SynthDef(\amp_mod3, {
	var sig, freq=440, amp=0.3, mod, env, ratio=3;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(freq*ratio, 0, 0.5, 0.5);
	sig = SinOsc.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

\amp_mod2の方はmodのサイン波にマイナス値も含んでいるので、もとの波形自体が変化しています。

\amp_mod3の方はmodのサイン波が正の値なので、ただ音量を高速に揺さぶっているだけなのでちゃんと基音も聞こえます。

\amp_mod2がリング変調の状態、
\amp_mod3はAM変調の状態です。

ratioをいろんなパラメータで実験するとさらに面白いです。

あと、変調される側(sig)をサイン波ではなくSawを使ったり、変調する側(mod)も色々と試せます。
音程感のあるものだけでなくSC3には
PinkNoise.ar(1)
BrownNoise.ar(1)
WhiteNoise.ar(1)
といったノイズ系もあります。

(
SynthDef(\amp_mod4, {
	var sig, freq=440, amp=0.3, mod, env, ratio=10;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(freq*ratio, 0, 1, 0);
	// mod = BrownNoise.ar(1, 0);
	sig = Saw.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

(
SynthDef(\amp_mod5, {
	var sig, freq=440, amp=0.3, mod, env, ratio=10;
	env = EnvGen.kr(Env.perc(0.01, 2.0), doneAction:2);
	mod = SinOsc.ar(freq*ratio, 0, 0.5, 0.5);
	// mod = BrownNoise.ar(0.5, 0.5);
	sig = Saw.ar(freq);
	Out.ar(0, sig!2 * amp * mod * env)
}).play;
)

コメントアウトしている行の//を外すと、BrownNoiseで変調します。
※該当する行にカーソルを置いてcommand+/(コマンド&スラッシュ)するとコメントアウトをON/OFFできます。もちろん手で//を消してもOKです。


変調すると面白いパラメータを持ったクラスいろいろ


さて、では続いて、クラス自体に「モジュレートすると面白い」パラメータを持っているものを紹介して終わります。

パルスウィズモジュレーション

(
SynthDef(\pulseWidth, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 0.45, 0.5);
	sig = Pulse.ar(freq, mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

パルス波のパルス幅をサイン波でモジュレートしています。
modのサイン波で0.5を中心値にして-0.45〜+0.45(つまり0.05〜0.95)変化させています。
modのサイン波の1の部分を変えるとLFOの速さが変わります。

ハーモニクス
Blip.arという音源には、「numharm(ハーモニクス数)」というパラメータがあります。

(
SynthDef(\harmonics, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 10, 15);
	sig = Blip.ar(freq, mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

numharmをサイン波でモジュレートしています。
もちろんnumharmはモジュレートせず固定値で使ってもかまいません。
0だと完全に倍音無し(サイン波)になり、数を増やしていくとノコギリ波に近いような音色になります。上限は200ですが、25を超えたあたりから音色のイメージはさほど変わらないしエイリアスノイズも目立つようになってきます。

フェイズモジュレーション
PMOscはPhaseModulationOscillatorで、
PMOsc.ar(キャリア周波数, モジュレータ周波数, phase1, phase2)というパラメータを持っていて、phase1のところ(*注1)を変えてやると音色が劇的に変わります。1個目と2個目の周波数比を変えてやることでも音色は変わるのでFMぽさもあります。
phase1は(*注2)もちろん固定値で使っていいのですが、下記ではphase1もモジュレートしてみました。

(*注1)「phase1, phase2のところ」と書いていたのを「phase1のところ」に修正しました。(2022.11.05)
(*注2)「phase1, phase2は」と書いていたのを「phase1は」に修正しました。(2022.11.05)

(
SynthDef(\pahseMod, {
	var sig, freq=440, amp=0.3, mod, ratio=2, phase=5;
	mod = SinOsc.ar(1, 0, 0.5, 0.5);
	sig = PMOsc.ar(freq, freq*ratio, phase*mod, pi);
	Out.ar(0, sig!2 * amp)
}).play;
)

ratio=2, phase=5
このあたりを変更するといろいろと音色が変わります。
modのサイン波の周波数1を変化させるとLFOの周期が変わります。

フォルマント
Formantはフォルマントを立てたような音がする音源です。

(
SynthDef(\formant, {
	var sig, freq=440, amp=0.3, mod, ratio=3;
	mod = SinOsc.ar(1, 0, ratio);
	sig = Formant.ar(freq, freq*mod, freq);
	Out.ar(0, sig!2 * amp)
}).play;
)

フォルマント周波数をモジュレートしています。
また、ratioの値を変えると大きく音色が変わります。

念のためもう一度書きます(しつこくてすみません。)
これまでの全てに共通して言えることですが、実験で数値を変えるときは「少しずつ変えて結果を聞きながらさらに変える」を繰り返すことを強くおススメします。
たまにとんでもない音(とてつもなく高い音とか)が出てしまうので、スピーカーや耳(鼓膜)を傷めないようにお願いします!

ローパスフィルター
言わずと知れたローパスフィルターです。

(
SynthDef(\cutoff1, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(1, 0, 400);
	sig = Pulse.ar(freq, 0.9);
	sig = RLPF.ar(sig, 400+mod, 0.2);
	Out.ar(0, sig!2 * amp)
}).play;
)

modのサイン波が-400〜+400の範囲で動くので、RLPF.arのカットオフ周波数は(400をプラスしているので)0〜800の値を揺れています。


(
SynthDef(\cutoff2, {
	var sig, freq=440, amp=0.3, mod;
	mod = LFNoise0.ar(20, 400);
	sig = Pulse.ar(freq, 0.9);
	sig = RLPF.ar(sig, 600+mod, 0.2);
	Out.ar(0, sig!2 * amp)
}).play;
)

modの波形を、サイン波ではなくLFNoise0を使うとサンプル&ホールドのような感じになります。
また、少しキャラクターが違うLFNoise1やLFNoise2もありますので試してみてください。

LFNoiseでさっきのFormantを変調すると面白いんじゃないかと思いついてやってみました。

(
SynthDef(\formant, {
	var sig, freq=440, amp=0.3, mod;
	mod = LFNoise2.ar(8, 5);
	sig = Formant.ar(freq*mod, freq*mod, freq*mod);
	Out.ar(0, sig!2 * amp)
}).play;
)

Formant.arの第1パラメータをfreq*modにしているので基音のピッチも一緒に変調されていますが、freqだけに変更すると純粋にフォルマントだけの変調になります。

パンニング
ステレオの回でも書きましたが、Pan2.arの第2パラメータpos(ポジション)は-1(左)〜+1(右)なので、振幅が-1〜+1のサイン波をそのままあてがうことができます。

(
SynthDef(\panning, {
	var sig, freq=440, amp=0.3, mod;
	mod = SinOsc.ar(0.4);
	sig = Pulse.ar(freq);
	sig = Pan2.ar(sig, mod);
	Out.ar(0, sig * amp)
}).play;
)

再生すると、音が中央からはじまってゆっくりとまず右側に向かいます。
これはmodのサイン波が0からはじまってまず+1に向かうからですが、パンニングを逆にしたい場合(中央からはじまって左側に向かわせたい場合)、
mod = SinOsc.ar(0.4).neg;
というようにnegメソッドを使います。negメソッドは出力結果のすべてに-1を掛け算するのでプラスとマイナスが逆になります。
(negはnegative(負)の略です。)

通常のSinOsc
.negしたSinOsc


この応用で、モジュレーションソースとしてLFSawを使う時、逆向きの山のノコギリ波を使いたいと思ったら.negすればOKです。
(下記は.negありなしの比較です。)

{LFSaw.ar(1)}.plot(2);
{LFSaw.ar(1).neg}.plot(2);


といったところで。。。
もうキリがないくらい色々と遊べます。

モジュレーションソース側のクラス(今回のSynthDefでmod = の右側に書かれているもの)の数値の範囲がデフォルトで-1〜+1なのか0〜+1なのかは、結果として出力される音色を大きく左右しますが、それを調べるには僕は.plotしています。

{LFSaw.ar}.plot;

こうすることで、LFSaw.arは-1〜+1であることがわかります。
たいていのものは-1〜+1ですが、LFPulse.arやImpulse.arのようにマイナスの値が(デフォルトでは)無いものもたまにあり、ぱっと見ではわからないし規則性もなさそうです。
plotしなくてもわかる方法を今後見つけたら、ここ(note)に書き残します。
誰かご存知の方がいましたら、教えてください!

では、今日のところは終わりにします。
次回は、SuperCollider上での出音を録音することについて簡単に書きます。


今日のまとめ

pollメソッドで出力値を確認できる
LineとXLineはスロープのカーブの違い
XLineではゼロやゼロを通過する数値を使えない
lagメソッドでパルス波などの波形のカーブを緩やかにできる
addパラメータをエディットすることでSinOsc.arなどの振幅の中心値を変更できる
PinkNoise.ar
BrownNoise.ar
WhiteNoise.ar
Blip.ar
PMOsc.ar
Formant.ar
LFNoise0.ar
LFNoise1.ar
LFNoise2.ar
negメソッドは出力値の全てに-1を掛け算する(プラスがマイナスになり、マイナスがプラスになって出力される)


<目次>にも今回のリンクを作っておきます。https://note.com/sc3/n/nb08177c4c01

いいなと思ったら応援しよう!