見出し画像

SuperColliderからMIDIOutで外部音源(Juno106)を鳴らす


MIDIOutというクラスを使うと、SuperColliderから外部MIDI音源を鳴らせます。
Juno106を鳴らしてみた様子を撮影したので、リンクを貼っておきます。

MIDI INコネクタを装備しているハードウェアシンセなら、どのシンセでも同じことができます。
もちろんソフトシンセでもOKです。

使ったコードはこちらです。
[ex0]

MIDIClient.init;
MIDIClient.destinations;

m = MIDIOut.new(1);
m.latency = 0;

m.allNotesOff(1);

(
t = TempoClock(100/60);
~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);
)



Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 67, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 69, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 66, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 64, 59, 55], inf)).quant_(4);

そんなに行数も多くなく、比較的簡単に実現します。
説明を、以下に書きます。

**
実は動画では、Juno106の出力をSuperColliderにインプットしてSuperCollider内でフィルターとShaperというエフェクトをかけています。それで太っとい音になっています。
そのオーディオ処理の部分で使ったコードはこちらです。

(
~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);
~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);
)

こちらの詳細説明は次回にしようと思います。
今日は「MIDI OUTで外部音源を鳴らす」というところまでの説明です。

*追記(2023.01.23)*
上記のコードの~crvの部分が抜けていたので先ほど追加しておきました。(コピペミスでした、すみません。)
******************


結線


まず前提として、今回の動画のときの僕のMIDI接続は下図のとおりです。(シンプル!)

ESI MIDIMATE eXというケーブル(一方がUSBでもう一方がMIDIコネクタ)を使いました。


MIDIOut


*まめ知識*
ちなみに今回のここから下のコードは全てサーバブートしなくても実行可能です。
SuperCollider内でオーディオ処理をしないのでサーバが必要ないためです。


さて、では、MacBookとJuno106をMIDI接続したら、下記コードでMIDIをイニシャライズします。
[ex1]

MIDIClient.init;

この結果(post windowの表示)でMIDIをやりとりできる機器の確認ができます。
(一度イニシャライズしたら、使えるMIDI機器は下記コードでも確認できます。)
[ex2]

MIDIClient.destinations;

僕は以下のように表示されましたので、MIDIOutとして使えるポートが3つあることがこれでわかります。

<MIDIClient.destinations;実行時の、post windowの結果表示>

この結果表示は、このあと使うポートナンバーとして使われます。
ポートナンバーは
「”IACドライバ", "バス1”」を0
「"ESI MIDIMATE eX", "ポート1"」を1
「"ESI MIDIMATE eX", "ポート2"」を2
と、0からカウントします。
僕は「"ESI MIDIMATE eX", "ポート1"」を使いたいので、ポートナンバーが1ということを覚えておきます。(次のコードで使います。)

**
ESI MIDIMATE eXは、<USB-MIDIコネクタ2口>というタイプの二股ケーブルです。

**
ちなみにIACドライバはMac内でルーティングできるMIDIポートなので、外部音源ではなくソフトシンセを鳴らしたい場合はポートナンバー0を使います。

さて、では、SuperColliderでMIDI OUTポートを作成します。
[ex3]

m = MIDIOut.new(1);

MIDIOut.new(ポートナンバー)を変数mに入れています。
変数は何でもOKです。
これまで同様、「”s”以外のアルファベット1文字」、又は「”~”で始まる任意の文字」です。

*Linuxを使っている方へ*
このポートナンバーの書き方はMacとWindows用だそうです。
Linuxは違う書き方のようですので、詳しくはこちらを参照ください。
https://doc.sccode.org/Classes/MIDIOut.html


これだけでもう音を出すことができます。
いろいろ説明抜きにすると、ここまでのコードは3行ですよね。

ではいよいよ、簡易的に音を鳴らしてみます。
次のコードでノートオン(鍵盤を弾く)、ノートオフ(鍵盤を離す)します。
実行すると外部音源から音が鳴るはずです。
[ex4]

m.noteOn(0, 60);
m.noteOff(0, 60);

MIDIポートmに対して「ノートオンせよ」「ノートオフせよ」と指示しています。

(0, 60)
の0はMIDIチャンネルです。
SuperColliderは0から数え始めるので、0はMIDI ch1で、1はMIDI ch2で、、とひとつずつずれた数字を書く必要があります。
このコードでは0と書いてMIDI ch1を指定しています。

(0, 60)
の60はノートナンバーです。

もうひとつ、ベロシティーのパラメータを加えることもできます。
m.noteOn(0, 60, 64);
m.noteOff(0, 60, 30);
3つ目のパラメータはそれぞれ、ノートオンベロシティー64、ノートオフベロシティー30、という意味です。
Juno106はベロシティー情報を受け付けないので、今回僕はベロシティー値は書きませんでした。
ただ、3つ目のパラメータを書かなければ結局はデフォルト値が送信されるしくみにはなっています。デフォルト値は64です。

ところで、もしm.noteOn実行から音が出るまでのレイテンシー(遅延)が気になるという方がいましたら、下記コードを実行してレイテンシーをゼロにしておきます。
[ex5]

m.latency = 0;

デフォルトでは0.2になっているそうです。
なぜ?と思いますが、その理由に関しては僕はよくわかっていません。
(ヘルプドキュメントにはServer.latencyと合わせるため、と書かれてあります。0.2にしておかないとSynthDefと同時に鳴らしたときズレが生じたりするのかもしれないです。)

m.noteOnを試しているうちに音源が鳴りっぱなしになるようなことがもしあったら、All Notes Off用のコードを実行します。
[ex6]
m.allNotesOff(0);

(これでも収まらなければ、音源側のMIDIパニックボタンを押すか、ハードウェアシンセの電源を一度オフする必要があります。僕はこの動画撮影中に何度かJUNOの電源を入れ直しました。)


Pbindで鳴らす。


Pbindでの鳴らし方は、いつもと変わりありません。
ただ「MIDI OUTポートから鳴らす」ための設定が4つ必要です。
\type,(\midiを指定)
\midicmd,(\noteOnを指定)
\midiout,(MIDIOut.newを入れた変数を指定)
\chan(鳴らすMIDIチャンネルを指定)

以下が動画で使った実際のコードです。
[ex7]

(
t = TempoClock(100/60);
~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);
)

Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 67, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 69, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 66, 59, 55], inf)).quant_(4);
Pdefn(\nt, Pseq([40, 45, 50, 55, 59, 64, 59, 55], inf)).quant_(4);

ノートオンしかありませんが、durやsustainの音長でノートオフされます。

動画内ではこのコードを実行しつつJuno106のつまみをいじっています。
Pbindのシーケンスを止めるにはcommand+ピリオドしてます。
Pdefnの使い方については、こちらを参照ください。

*まめ知識*
これまでPbindの中で\typeを指定したことはありませんが(上記コードでは\typeに\midiを指定しています)、\typeのデフォルト値は実は\noteで、何も指定しなければ\noteだと判断されるようになっています。
なのでこれまで使ってきたPbindの\typeは\noteであり、それが省略されている書き方なのでした。


Pbindで送信できるMIDI信号の種類は他にもあり、興味がある方は
このページ
Available midicmds:
の項目を見てみてください。英語ですがMIDIに接したことがある方ならどういう内容か想像つくのではないかと思います。コントロールナンバーやベンド、アフタータッチなどの送信が可能とあります。


次回は、Juno106の出力をSuperColliderにインプットしてSuperCollider内で音をいじった、オーディオ部分について書きます!


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


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