見出し画像

SoundIn と Shaper

SoundInというクラスがありまして、これはMac(やWinなど)のオーディオ入力を受け取るクラスです。
受け取った音をそのまま出力することもできますし、エフェクトなどを通すこともできます。

[ex1]

//まずBoot Serverします。
{Saw.ar(440)}.play;

とするとサイン派が鳴りますが(左チャンネルだけ)、使い方はこれと同じです。
クラスを入れ替えます。

[ex2]

{SoundIn.ar(0)}.play;

とするとMacのオーディオ入力を受け取り、そのまま出力します。

もしパソコンのオーディオ入力を「内臓マイク」にしている場合、上記コードを実行すると周囲の音をマイクが拾ってそのままスピーカーに出力します。
[ex3]

m.meter;

又はcommand+mをすると目で見てわかります。(inputの信号とoutputの信号の振れ方が同じ。)


音がループしてしまう可能性がありますので(スピーカーから出た音をマイクが拾って、それをまたスピーカーが出して、またマイクが拾って・・・ハウリングを起こす)、上記コードを実行するときは出力を小さな音で。又はヘッドフォンをおすすめします。

SoundIn.ar(0)
の部分の0はバスナンバーです。
入力がステレオの場合、0がレフトチャンネルで1がライトチャンネルなので
[ex4]

{SoundIn.ar([0,1])}.play;

とすると、LRからの入力を受け取り出力します。

さて、前回の「SuperColliderからMIDIOutで外部音源(Juno106)を鳴らす」で、Juno106の出力を僕はオーディオインターフェイスに入力していました。

僕はオーディオインターフェイスにAudient iD4mkIIを使っています。
iD4mkIIは、ch1がマイク入力でch2がライン入力なので、Juno106のモノラル出力を2ch目に入力。
[ex5]

{SoundIn.ar(1)}.play;

これでiD4mkIIでJuno106の出力をモニターできるようになりました。
ただ、これだと片チャンだけになってしまうので、Pan2を使ってLRから出るようにしました。
(コードが長くなるのでSynthDefで書きます。)

[ex6]

(
SynthDef(\in_juno, {
	var sig;
	sig = SoundIn.ar(1);
	sig = Pan2.ar(sig, 0);
	Out.ar(0, sig);
}).play;
)

上記コードを実行したあとJuno106を鳴らしつつ下記コードを実行すると・・・
[ex7]

s.record;

入力音がレコーディングされます。
(SuperColliderのレコーディングについての詳細はこちらを参考に。)

前回の動画はこんなふうにレコーディングしました。
(レコーディングしたオーディオをあとで動画に合体しました。)


オーディオデバイスの切替え


ところでちょっと話が逸れますが、SuperColliderでオーディオデバイスを切り替える方法について書いておきます。SounInクラスの入力を、内臓マイク入力にするかオーディオI/Oの入力にするか、という切り替えについてです。

まずこちらのコードを実行します。
[ex8]

Server.default.options.outDevice_("Audient iD4");

そしてブートサーバします。
そうするとSuperColliderの入力先がAudient iD4になります。

もし内臓マイクを使いたい場合は・・・

Server.default.options.outDevice_("Built-in Output");

こちら↑を実行したあとブートサーバするとSuperColliderの入力先が内臓マイクになります。

どのデバイスが使えるか(“ダブルクォーテーョン”内に何と書けるか)は、ブートサーバしたときにpost windowに注目するとわかります。
ブートサーバしたとき、僕の場合は下記のようなデバイス名が表示されます。

これらが使えるデバイスです。
オーディオインターフェイスをつないでいる方はご自身が使えるインターフェイス名が表示されているのではないかと思います。

僕の場合はBlackHoleを指定してもOKってことです。
Server.default.options.inDevice_("BlackHole 16ch");
こうするとSuperColliderの入力先がBlackHole 16chになります。
BlacHoseはMac内のオーディオルーティングユーティリティで、他のソフトの出力をSuperColliderにインプットしたいとき僕はBlackHole 16chを使っています。

先ほどのコードのinDeviceの部分をoutDeviceに書き換えると出力デバイスについても同様に切り替えることができます。
Server.default.options.outDevice_("Audient iD4");
Server.default.options.outDevice_("Built-in Output");
Server.default.options.outDevice_("BlackHole 16ch");


入力音にエフェクトを加える


話を元に戻しまして・・・
[ex6]をplayしておいて、その状態でJuno106をPbindでシーケンスさせるとSuperColliderでJuno106の音をモニタリングできますが、前回の動画のときは入力音にエフェクトを通していました。

[ex9]

(
SynthDef(\in_juno, {
	var sig;
	sig = SoundIn.ar(1);
	sig = RLPFD.ar(sig, MouseY.kr(20, 2000), MouseX.kr(1, 0), 0.8);
	sig = Pan2.ar(sig, 0);
	Out.ar(0, sig);
}).play;
)

こんなふうに、SoundInの信号にフィルターを通しています。
RLPFD(ディストーション付きレゾナンスローパスフィルター)はExtensionのクラスで、パラメータは以下のようになってます。

このRLPFDを他のエフェクト(ディレイでもリバーブでも)に変えてもOKですし、他のエフェクトを追加してもOK、サイン波を掛け算してリングモジュレーションなんかも。入力信号に対していろいろとエフェクトをかけることができます。

そして前回の動画のときはShaperを(RLPFDと直列につないで)使っていました。


Shaper


Shaperは入力信号を大胆に変形させてくれる、とても面白いエフェクトです。
その概念を説明したいのですが、Elli Fieldsteelさんのこの動画がとてもわかりやすいので、リンクを貼ります。

https://youtu.be/7nrUBbmY1hE?list=PLPYzvS8A_rTaNDweXe6PX4CXSGq4iEWYC&t=582

この動画のここ(9’43”)から約3分間くらいの説明が(英語なのですが映像だけ見ていても)素晴らしくわかりやすいです。ぜひぜひ見てください。僕もShperの使い方を覚えたのはこの動画からです。


その一部をスクショしました。

左側のインプット信号(この場合サイン波)を、真ん中のカーブを通すことで右側のような出力波形になる、というのがざっくり説明ですが、この真ん中のカーブを自由に作ることができるのがShaperです。
カーブを複雑にすれば右側の出力波形がより複雑になるのは想像できますし、さらに入力波形をサイン波以外のものにすると・・・もっと出力波形は多彩になります。

真ん中のカーブの作り方の詳細です。
書式的には「Env.new().asSignal」の回で紹介したものと、ほぼほぼ同じです。


Env.new().asSignalは、自分で作ったエンベロープを”1サイクルの波形”として鳴らすことができる方法です。

「ほぼほぼ同じ」と書きました。どう違うかと言いますと。。
Env.new().asSignalのカーブは、こんな感じでした。
[ex10]

(
~bfr1 = Buffer.alloc(s, 2048);
~crv = Env([-1, 1, -1], [0.5, 1.5], [0]).asSignal(1024);
~wt = ~crv.asWavetable;
~bfr1 = ~bfr1.loadCollection(~wt);
)


そしてShaperのカーブはこんな感じに書きます。
[ex11]

(
~crv = Env([-1, 1, -1], [0.5, 1.5], [0]).asSignal(1025);
~wt = ~crv.asWavetableNoWrap;
~bfr2 = Buffer.loadCollection(s, ~wt);
)

*[ex10]と[ex11]はどちらも同じカーブができあがります。

書式は、このまま覚えるか、これをコピペして使っていけばよいと思います。
大事なのはEnv([この中身])の部分なので、ここをいろいろとエディットしてみてください。
どんなカーブになったかプレビューする場合は、~crvの部分をplotします。
[ex12]

~crv.plot;
[ex10] [ex11]

こうしてカーブを作ったら、Shaper内のパラメータとして入れてあげるだけです。
Shaper.ar(~bfr2, sig)という感じに。

Shaperを作ることができたので、サイン波にShaperを通したSynthDefを作って、Pbindでプレイさてみます。
その例がこちらです。
[ex13]

(
//Env
~crv = Env([-1, 1, -1], [0.5, 1.5], [0]).asSignal(1025);
~wt = ~crv.asWavetableNoWrap;
~bfr3 = Buffer.loadCollection(s, ~wt);

//Synth
SynthDef(\shaperTest, {
	arg freq=1, gate=1;
	var sig, env, amp=0.5;
	env = EnvGen.kr(Env.asr(0.01, 1, 0.1), gate, doneAction:2);
	sig = SinOsc.ar(freq);
	sig = Shaper.ar(~bfr3, sig);
	sig = Pan2.ar(sig, 0) * env * amp;
	Out.ar(0, sig);
}).add;

//Pbind
Pbind(
	\instrument, \shaperTest,
	\midinote, Pseq([
		50, 57, 55, 53, 48, 50, 55, 53,
		46, 57, 55, 53, 62, 57, 48, 53
	], inf),
	\dur, 0.5,
	\sustain, 0.5,
).play(TempoClock(150/60));
)

サイン波とは全く違う、倍音を多く含む音色になりました。
いろんなEnvを試してみると楽しいんですが、、、ここでひとつ面白い実験をしてみようと思います。
下記の[ex14]は、[ex13]のどこか1箇所だけの数値を変えたコードです。
1箇所だけなんですが、全然違う音色で鳴ります。
[ex14]

(
//Env
~crv = Env([-1, 1, -1], [0.5, 1.5], [-4]).asSignal(1025);
~wt = ~crv.asWavetableNoWrap;
~bfr3 = Buffer.loadCollection(s, ~wt);

//Synth
SynthDef(\shaperTest, {
	arg freq=1, gate=1;
	var sig, env, amp=0.5;
	env = EnvGen.kr(Env.asr(0.01, 1, 0.1), gate, doneAction:2);
	sig = SinOsc.ar(freq);
	sig = Shaper.ar(~bfr3, sig);
	sig = Pan2.ar(sig, 0) * env * amp;
	Out.ar(0, sig);
}).add;

//Pbind
Pbind(
	\instrument, \shaperTest,
	\midinote, Pseq([
		50, 57, 55, 53, 48, 50, 55, 53,
		46, 57, 55, 53, 62, 57, 48, 53
	], inf),
	\dur, 0.5,
	\sustain, 0.5,
).play(TempoClock(150/60));
)

違うのは1行目のEnv()の3つめのパラメータです。[0]から[-4]に変えています。
このパラメータはエンベロープのカーブです。
[ex13]を実行したあとに~crv.plot;
[ex14]を実行したあとに~crv.plot;
このふたつのプロットを見比べてみるとわかります。
このカーブ値をいろいろと変えるだけでもかなりのバリエーションを作ることができます。


[ex13]
[ex14]


*テスト結果報告*
ちょっと気になって実験しました。
[ex11]はElli Fieldsteelさんの動画で学んだ書き方なんですが、いろいろ試したところ、、、[ex10]の書き方でもShaperで使えるようです。
Envの形が同じだったら、どちらの書き方をしても同じ音になりました。

【訂正】(2023.02.02)
さらに実験を進めたところ、厳密には[ex10]の書き方だとダメでした。
すみません。
[ex10]の書き方でも音は出るのですが、Shaperの変化として正しくないようです。波形ループの時に綺麗にループせず余計な倍音が乗ってしまいます。
音は出るので使えないわけではないですが、どんなカーブを書いても似たような独特な倍音が加わると思います。
 というわけで、Shaperを正しく使うには[ex11]の書き方が良いです。
Osc.arで鳴らす時の波形は[ex10]の書き方で。)


前回使ったコード


さて、さっきの例ではサイン波にShaperを通していますが、オーディオ入力信号にShaperを通してみようという試みが前回のJuno106の動画です。
その時のコードは下記のものでした。
[ex15]

//Envカーブ
(
~crv = Env.new(
	[-1, 0, 1, -1, 0, 1],
	[1, 0.5, 0.1, 0.5, 1],
	[5, -5, 0, -5, 5]
).asSignal(1015);
~crv = ~crv.asWavetableNoWrap;
~bf = Buffer.loadCollection(s, ~crv);
)

//オーディオインにエフェクトをかける
(
SynthDef(\in_juno, {
	arg gate=1;
	var sig, env, amp=1;
	env = EnvGen.kr(Env.asr(0.001, 1, 0.1), gate, doneAction:2);
	sig = SoundIn.ar(1);
	sig = Shaper.ar(~bf, sig)*0.2;
	sig = RLPFD.ar(sig, MouseY.kr(20, 2000), MouseX.kr(1, 0), 0.8);
	sig = Pan2.ar(sig, 0) * env * amp;
	Out.ar(0, sig);
}).add;
)

(
t = TempoClock(100/60);

//Juno106を鳴らすシーケンス
~midi_juno = Pbind(
	\type, \midi,
	\midicmd, \noteOn,
	\midiout, m,
	\chan, 0,
	\midinote, Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 64, 59, 55], inf)),
	\sustain, 0.2,
	\dur, 0.25,
).play(t);

//オーディオインもシーケンスで鳴らしてゲートを与えました。
~aud_juno = Pbind(
	\instrument, \in_juno,
	\midinote, 40,
	\sustain, 0.5,
	\dur, 0.25,
).play(t);
)

これ、いま見直すと.asSignal(1015)になってる・・・ホントは1025にしたかったと思うのですがタイプミスですよね。これ正しく動いていたんだろうか。
さっそく検証してみたところ・・・
1015でも1024でも同じ音が出ました!!
2のx乗にはこだわらなくてもいいのかなぁ…。謎です。


入力信号にShaperを使うのは、リアルタイムにオーディオを変形させるので、処理としてはとても重そうです。
前回の動画内では、テンポが揺れる感じになることもありました。
ちなみに、僕のMacBookは

という感じなので(古っ!)、最近のMacなら全然大丈夫かもしれないです。


今日はSoundIn.arとShaper.arについて、それとオーディオデバイスの切替えについて書きました。
ではまた。


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


この記事が気に入ったらサポートをしてみませんか?