見出し画像

リズムループを作った

シンプルなリズムループを作ったのでYouTubeに上げました。
https://youtu.be/QskdeS1FKN4


コードはこちらです。

//boot server
s.boot;


//effect
(
~total = Bus.audio(s, 2);
SynthDef(\total, {
	var eff0, eff1, src;
	src = In.ar(~total, 2);
	eff0 = DFM1.ar(src[0], 19000, 0, noiselevel:0.003);
	eff1 = DFM1.ar(src[1], 19000, 0, noiselevel:0.003);
	Out.ar(0, [eff0, eff1]);
}).add;

~rvb = Bus.audio(s, 2);
SynthDef(\fvrb, {
	var eff, src;
	src = In.ar(~rvb, 2);
	eff = FreeVerb2.ar(src[0], src[1], 1.0, 0.55, 0.9);
	eff = LPF.ar(eff, 9000);
	Out.ar(~total, eff);
}).add;
)

//tone
(

//mod
~cof = Bus.control(s, 1);
SynthDef(\cof, {
	arg gate=1;
	var cutoff, env;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.01), gate, doneAction:2);
	cutoff = LFNoise0.kr(120/60/4*3).range(0, 450);
	Out.kr(~cof, cutoff);
}).add;

SynthDef(\bd, {
	arg freq=110;
	var sig, env, env2, amp=1;
	env = EnvGen.kr(Env.perc(0.001, 0.18, 1, -5.0), doneAction:2);
	env2 = EnvGen.kr(Env.perc(0.05, 0.18, 1, -5.0), doneAction:2);
	sig = SinOsc.ar(freq*env*1.2, 0, env);
	sig = sig + VarSaw.ar(freq*env*1.5, 0, 0.65, env);
	sig = Compander.ar(sig, sig, 0.2, 0.1, 0.1).clip(-0.2, 0.2);
	sig = sig + SinOsc.ar(freq/4, 0, env2 * 0.65);
	sig = HPF.ar(sig, 20);
	sig = Pan2.ar(sig, 0) * amp;
	Out.ar(~total, sig);
}).add;

SynthDef(\hh, {
	var sig, env;
	env = EnvGen.kr(Env.perc(0.01, 0.03, 1, -4.0), doneAction:2);
	sig = WhiteNoise.ar(env);
	sig = RLPF.ar(sig, 9000, 0.1, 0.3);
	sig = Pan2.ar(sig, 0.4);
	Out.ar(~total, sig * 0.15);
	Out.ar(~rvb, sig * 0.03);
}).add;

SynthDef(\hh2, {
	var sig, env;
	env = EnvGen.kr(Env.perc(0.015, 0.07, 1, -4.0), doneAction:2);
	sig = WhiteNoise.ar(env);
	sig = RLPF.ar(sig, 9000, 0.2, 0.2);
	sig = Pan2.ar(sig, -0.4);
	Out.ar(~total, sig * 0.2);
	Out.ar(~rvb, sig * 0.03);
}).add;

SynthDef(\sn, {
	arg freq=220;
	var sig, env, amp=0.08;
	env = EnvGen.kr(Env.perc(0.006, 0.07, 1, -3.5), doneAction:2);
	sig = WhiteNoise.ar(env);
	sig = sig + SinOsc.ar(freq/2, 0, env);
	sig = RLPF.ar(sig, 5000, 0.8, 0.4);
	sig = Compander.ar(sig, sig, 0.8, 0.1);
	sig = sig + WhiteNoise.ar(EnvGen.kr(Env.perc(0.15, 0.1, 0.25, -3)));
	sig = Pan2.ar(sig, 0) * amp;
	Out.ar(~total, sig);
	Out.ar(~rvb, sig * 0.03);
}).add;


SynthDef(\bass, {
	arg freq=220, gate=1;
	var sig, env, envf, amp=2;
	// envf = EnvGen.kr(Env.adsr(0.5, 0.5, 1, 0.15));
	env = EnvGen.kr(Env.adsr(0.01, 0.5, 0.7, 0.05), gate, doneAction:2);
	sig = SawDPW.ar([freq, freq/2] + SinOsc.ar(2, 0, 0.2), [0.5, 0.4], [1, 0.35]*env);
	sig = Mix(sig + PinkNoise.ar(0.04));
	sig = RLPFD.ar(sig, freq*2 + SinOsc.kr(2, pi*3/2, 30) + In.kr(~cof).poll, 0.25, 0.9);
	sig = Pan2.ar(sig, 0) * amp;
	Out.ar(~total, sig);
}).add;

SynthDef(\key, {
	arg freq=220, gate=1;
	var sig, env, mod, amp=0.05;
	env = EnvGen.kr(Env.adsr(0.2, 0.4, 0.7, 2.5), gate, doneAction:2);
	mod = SinOsc.kr(XLine.kr(2.5, 900, 3), 0.25, 1, 1);
	sig = SinOsc.ar([freq, freq+3], 0, env).clip(-0.97, 0.97);
	sig = sig* mod;
	sig = Pan2.ar(sig, 0) * amp;
	Out.ar(~total, sig);
	Out.ar(~rvb, sig * 0.5);
}
).add;

SynthDef(\ndl, {
	arg freq=220, gate=1, pan=0;
	var sig, env, amp=0.5;
	env = EnvGen.kr(Env.adsr(0.01, 0.05, 0.6, 0.05), gate, doneAction:2);
	sig = SinOsc.ar(freq, 0, env) * PinkNoise.ar(0.1);
	sig = BPF.ar(sig, 411, 0.8, 1);
	sig = Pan2.ar(sig, pan) * amp;
	Out.ar(~total, sig);
	Out.ar(~rvb, sig * 0.5);
}).add;

SynthDef(\low, {
	arg freq=220, gate=1;
	var sig, env, amp=0.3;
	env = EnvGen.kr(Env.adsr(1, 0, 1.0, 0.05, curve:-20), gate, doneAction:2);
	sig = SawDPW.ar(freq, env);
	sig = RLPFD.ar(sig, 4700 + LFNoise0.kr(2, 100), 0.5, 0.95);
	sig = Pan2.ar(sig, 0) * amp;
	Out.ar(~total, sig);
}).add;


)



//Sequence

(
a = Pbind(
	\instrument, \bd,
	\midinote, Pseq([40, 36, 38, 36], inf),
	\dur, Pseq([1, 1, 1, 1], inf)
);

b = Pbind(
	\instrument, \hh,
	\midinote, Pseq([\, 60], inf),
	\dur, Pseq([0.56, 0.44], inf)
);

c = Pbind(
	\instrument, \hh2,
	\midinote, Pseq([Pseq([\, \, \, 60], 3), Pseq([\, \, \, 60], 1)], inf),
	\dur, Pseq([Pseq([1, 0.5, 0.25, 0.25], 3), Pseq([0.5, 0.5, 0.54, 0.46], 1)], inf)
);


x = 0.025;
d = Pbind(
	\instrument, \sn,
	\midinote, Pseq([\, 44], inf),
	\dur, Pseq([Pseq([1+x], 4), Pseq([1-x], 4)], inf),
);

e = PmonoArtic(
	\bass,
	\midinote, Pseq([
		\, \, 52, 47, \, 40, \, \,
		\, \, 52, 47, \, 40, \, \,
		\, 28, 52, 47, \, 40, \, \,
		\, \, 52, 47, \, 40, \, \
	], inf),
	\dur, Pseq([1, 0.5, 0.25, 0.25, 0.25, 0.5, 0.25, 1], inf),
	\sustain, Pseq([
		1, 0.5, 0.25, 0.17, 0.25, 0.6, 0.24, 1,
		1, 0.5, 0.25, 0.17, 0.25, 0.6, 0.24, 1,
		1, 0.5, 0.25, 0.17, 0.25, 0.6, 0.24, 1,
		1, 0.5, 0.25, 0.17, 0.25, 0.6, 0.24, 1
	], inf)
);

f = Pbind(
	\instrument, \key,
	// \midinote, Pseq([\, \, \, \, [74,63], \, \, \], inf),
	\midinote, Pseq([
		\, \, \, \, [57,66], \, \, \,
		\, \, \, [56,67], \, \, \,\

	], inf),
	\dur, Pseq([1, 1, 1, 0.5, 0.5, 4, 4, 4], inf),
	\sustain, Pseq([1, 1, 1, 0.5, 0.5, 4, 4, 4], inf)
);

g = Pbind(
	\instrument, \ndl,
	\midinote, Pseq([\, 71, \, 71, \, \], inf),
	\dur, Pseq([0.5, 0.5, 0.25, 0.75, 1, 1], inf),
	\sustain, Pseq([0.5, 0.25, 0.25, 0.25, 1, 1], inf),
	\pan, Pseq([-0.8, -0.8, 0.8, 0.8], inf)
);

h = Pbind(
	\instrument, \low,
	\midinote, Pseq([
		\, \, \, \, \, \, \, \, \, \, \, 23,
		\, \, \, \, \, \, 6, \, \, \, \, 35
	], inf),
	\dur, Pseq([0.25, 0.75, 1, 1, 0.5, 0.5], inf),
	\sustain, Pseq([
		0.5, 0.5, 1, 1, 0.5, 0.1,
		0.5, 0.5, 1, 1, 0.5, 0.5,
		0.5, 0.5, 1, 1, 0.5, 0.5,
		0.5, 0.5, 1, 1, 0.5, 0.05
	], inf)
);

i = Pbind(
	\instrument, \cof,
	\midinote, 0,
	\dur, 4,
);

~h00 = Ppar([a,b,c,d,e,f,g,h,i]);
~h01 = Pfx(~h00, \fvrb);
~h02 = Pfx(~h01, \total).play(TempoClock(120/60));

)

オーディオバスを2つ使っています。
ひとつは~rvbで普通にリバーブとして。
もうひとつは~totalです。
~totalにはローパスフィルターを設定していて、全てのSynthDefのアウトを突っ込んでいます。トータルエフェクトのような使い方です。
カットオフは絞っておらず「何かアナログ的な味付けできないかなぁ」と思ってやってみました。意図としては成功しました。これをOFFすると結構クリアな音質になります。

src = In.ar(~total, 2);

このsrcが、~totalというバスに入ってきた信号ですが、次の行のsrc[0]やその次の行のsrc[1]という書き方は見慣れないと思いますので説明を書きます。

※以前Demandの回でも使っていましたが説明は書きませんでした。

このsrcは2chです。
~total = Bus.audio(s, 2);というふうに2と設定していますし、それを受けるInクラスもIn.ar(~total, 2)というふうに2と設定しています。
2ch分の信号をまとめてエフェクトかけるのなら問題ないのですが、LとR別々のパラメータ設定したかったりすることがあります。
そういうときにステレオ信号をLR別々に分離させる必要があります。
(上記コードのFreeverb2のようにインプットのパラメータがL用とR用で別々に用意されているときなど、そうせざるを得ない場合もあります。)

そういうとき
(srcとそのまま書くとLRの2ch分ということになりますが)

src[0]
と書くとsrcのLチャンネル
src[1]
と書くとsrcのRチャンネルを意味します。

SuperColliderでは[角カッコ]でくくると多チャンネルの信号を扱えますが、こんなふうにして任意のモノチャンネルの信号を取り出すことができます。
これは[角カッコ]内に3ch以上の信号があったとしても同じです。

例えば、以下の例は音声チャンネルではないですが、[角カッコ]に入れたフルーツの名前を取り出す例です。

まず下記コードを実行して、~fruitという変数に4つのフルーツの名前を入れます。

~fruit = ["apple", "orange", "grape", "peach"];

次に下記のコードを実行すると0番目のフルーツ名を取り出すことができます。(post windowにappleと表示されます。)

~fruit[0];

[カッコ]内の数字を変えて、~fruit[1];にすればorangeを取り出せますし、~fruit[3];にすればpeachを取り出すことができます。

僕のコードに話を戻しまして・・・
DFM1はモノだからと思いLR別々に処理してOut.ar内で[eff0, eff1]としてまたステレオに戻したのですが、、

SynthDef(\total, {
var eff, src;
src = In.ar(~total, 2);
eff = DFM1.ar([src[0], src[1]], 19000, 0, noiselevel:0.003);;
Out.ar(0, eff);
}).add;

こうやることもできましたね、今考えると。これのほうが一つのDFM1だけで2chを扱えるのでCPUの負荷は低いと思います。

rangeメソッド


LFNoise0.kr(1.5).range(0, 450)
という書き方をしている箇所があります。
これは、1.5HzのLFNoise0を0から450の振幅で発生させる書き方です。

通常LFNoise0の振幅は
LFNoise0.kr(freq, mul)
のmulの部分に書き、しかも音声信号として使う場合はmulは0〜1です。
ですがモジュレータとして使いたい場合のmulは1以上の場合のほうが多いです。
LFNoise0.kr(freq, 450)と書いてもいいのですが、僕はモジュレータとして使う場合はrangeを使って書いておくと数値の設定として見た目でわかりやすいですし、そうすることが多いように思います。

サイン波なんかでも下記のように書くと
SinOsc.ar(1).range(0, 100)
0から100のレンジで1Hzのサイン波が発生します。

{ SinOsc.ar(440, 0, 0.3)!2 }.play;
この440Hzのサイン波に上記のサイン波を足すと

{ SinOsc.ar(440 + SinOsc.ar(1).range(0, 100), 0, 0.3)!2 }.play;

440〜540Hzにゆっくり揺れるサイン波が鳴ります。

{ SinOsc.ar(440 + SinOsc.ar(1).range(60, 100), 0, 0.3)!2 }.play;

こうすると
500〜540Hzにゆっくり揺れるサイン波です。わかりやすいですよね。

{ SinOsc.ar(440 + Saw.ar(1).range(60, 100), 0, 0.3)!2 }.play;

Sawでモジュレートしても全然OKです。書き方は同じです。

僕のコードの例だと、このLFNoise0は~cofというコントロールBusに入れて、\bassのフィルターRLPFD.arのカットオフ周波数に使っています。


このほかは、いろいろとゴチャゴチャやっているように見えますが、その場の思いつきでエディットした結果このようになっていて、特別なことはやっていないと思います。
Pbindなんかは、もう全然整理されてないままです。
\snや\hhなど、ジャストなタイミングで鳴らすまいとする工夫をいろいろやってごちゃごちゃになっています。


<目次へ>
https://note.com/sc3/n/nb08177c4c011


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