はじめに
TidalCyclesはライブコーディングによって音やリズムを生成できるオープンソースのソフトウェアで、これによって複雑なリズムパターンをコードベースで実験・楽曲制作・ライブパフォーマンスが可能です。
ライブパフォーマンスにおける課題
自分はライブでSuperColliderによってシンセを作ってソフトウェアとしての楽器を制作したり、SuperColliderで作成したシンセをTidalCyclesから呼び出してライブパフォーマンスをすることが多いです。
TidalCyclesはコードベースのため記録しやすさがあったり、細かいパラメータをいじりやすいためとても重宝しています。
一方で、最近では1~2時間の長時間にわたるライブパフォーマンスをすることがあり、いまどのサイクル(orbit)からどの音を出しているのかわからなくなることがあります。
(Tidalは特別な設定をしない限りすべてのorbitから出る音は2chになるため)
現状これを一番良い方法で解決できる方法が見つかったのでシェアさせていただきます。
Tidal Orbit Monitor
いきなり作ったものですが、画像のように各Tidalのチャンネルのボリュームを見られるようにしています。
これによっていま鳴っているチャンネルがわかるので、音と比べればどのorbitからどの音が鳴っているか感覚的にわかると思います。
特別なソフトを使う必要がなく、SuperColliderのエディタから起動できるかつ軽量なので扱いやすいです
環境構築手順
- startup.scdの末尾に以下を追記する。(startup.scdはSuperColliderのエディタから「File -> Open startup file」で開けます)
- SuperColliderを再起動して、SuperDirtを起動させる
- SuperDirtの起動後に
~orbitMonitor.();を「Cmd + Enter」で実行すればTidal Orbit Monitorが立ち上がる
// =======================
// Orbit monitor synth
// =======================
SynthDef(\orbitMonitor, { |inbus, outbus|
var sig;
var amp;
sig = In.ar(inbus, 2);
amp = Amplitude.kr(Mix(sig)).lag(0.1) * 10;
Out.kr(outbus, amp);
}).add;
// =======================
// Orbit monitor setup
// =======================
~orbitMonitorSetup = {
~orbitMonitorBuses = Array.newClear(~dirt.orbits.size);
~orbitMonitorSynths = Array.newClear(~dirt.orbits.size);
~dirt.orbits.do { |orbit|
var bus;
var synth;
bus = Bus.control(s, 1);
synth = Synth.tail(
s,
\orbitMonitor,
[
\inbus, orbit.dryBus.index,
\outbus, bus.index
]
);
~orbitMonitorBuses[orbit.orbitIndex] = bus;
~orbitMonitorSynths[orbit.orbitIndex] = synth;
};
"Orbit monitor ready".postln;
};
// =======================
// Orbit GUI
// =======================
~orbitMonitorGUI = {
var n;
var rowHeight = 22;
var height;
// 既存Windowがあれば閉じる
if(~orbitWindow.notNil) {
~orbitWindow.close;
};
n = ~orbitMonitorBuses.size;
height = (n * rowHeight) + 20;
~orbitWindow = Window(
"Tidal Orbit Monitor",
Rect(200,200,260,height)
).front;
~orbitMeters = Array.newClear(n);
n.do { |i|
StaticText(~orbitWindow, Rect(10, 10 + (i*rowHeight), 60, 18))
.string_("orbit " ++ i);
~orbitMeters[i] =
LevelIndicator(~orbitWindow, Rect(70, 10 + (i*rowHeight), 160, 18));
};
Routine({
loop {
n.do { |i|
var v = ~orbitMonitorBuses[i].getSynchronous;
{
~orbitMeters[i].value = v.clip(0,1);
}.defer;
};
0.05.wait;
}
}).play(AppClock);
"Orbit monitor GUI started".postln;
};
~orbitMonitor = {
~orbitMonitorSetup.();
~orbitMonitorGUI.();
};