TidalCyclesとSuperColliderの連携 - 改訂版

TidalCycles 0.8からは、SuperColliderをベースにしたSuperDirtが標準の音響生成エンジンとなりました。そのため、以前は少し面倒だったSuperColliderで独自に作成した楽器(Synth)との連携が簡単になりました。

以下のチュートリアルは、SuperDirtのGithubリポジトリ内にあるチュートリアルをベースにしています。

- [https://github.com/musikinformatik/SuperDirt/blob/master/synths/default-synths.scd](https://github.com/musikinformatik/SuperDirt/blob/master/synths/default-synths.scd)

## セットアップ

以降のサンプルを動かすには、TidalCycles 0.8のセットアップが完了している必要があります。セットアップの手順は下記を参照してください。

- [TidalCycles 0.8 リリース](http://qiita.com/yoppa/items/b195d4014de63686b2e0)

## 基本 - 440Hzのサイン波

まず、シンプルなサンプルを作成してみましょう。440Hzのサイン波を生成するシンプルな楽器を定義します。

```
SynthDef("testsynth", {
	arg out;
	var sound = SinOsc.ar(440.0);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, 0.5));
}).add;
```

これを、Tidalから演奏するには、SuperDirtを起動した状態で以下のように呼び出します。

```
d1 $ sound "testsynth"
```

「sound」省略して「s」だけでも大丈夫です。

```
d1 $ s "testsynth"
```

Tidal向けに定義されたSynthdefの特徴として、最終出力で、Out.ar(...) ではなく OffsetOut.ar(...) を使用していることに気付きます。これは、Tidalで複雑なリズムを生成する際に、できるだけ正確なタイミングでトリガーされるための工夫です。また、最終出力で、DirtPan.ar(...) を使用しています。これは、Tidalで設定したPanの指定を反映するためのものです。ただし、現状ではまだ反映されていません。また、現在の状態では音がずっと持続してしまい、リズムの切れ目が不明確です。


## 定位(Pan)と持続時間(Sustain)を設定

もう少し改良して、定位(pan)と音の持続時間(sustain)を設定できるようにしてみましょう。以下のようにSynthdefを修正します。

```
SynthDef("testsynth", {
	arg out, sustain=1, pan;
	var env = EnvGen.ar(Env.linen(0.01, 0.98, 0.01, 1,-3), timeScale:sustain, doneAction:2);
	var sound = SinOsc.ar(440.0);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;
```

引数に、sustainとpanが追加されました。設定したsustainの値でエンベロープを生成しています。またpanの値をDirtPan.ar()に指定しています。

では、以下のようにTidalから演奏してみましょう。

```
d1 $ s "testsynth*2" # sustain "0.2" # pan "0 1"
```

左右交互に、0.2秒の長さで音が鳴るようになりました。

## 音程を設定

次に音程を指定できるようにしましょう。以下のように修正します。

```
SynthDef("testsynth", {
	arg out, sustain=1, pan, accelerate, freq;
	var env = EnvGen.ar(Env.linen(0.01, 0.98, 0.01, 1, -3), timeScale:sustain, doneAction:2);
	var sound = SinOsc.ar(freq * Line.kr(1,1+accelerate, sustain));
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;
```

Tidalからは、「n (またはnote)」という指定で音程を設定できます。nが9の時、A5(ピアノの中心のラ)の音程になります。例えば以下のようにして音程を指定します。

```
d1 $ s "testsynth*2" # sustain "0.2" # pan "0 1" # n "9 21"
```

## エンベロープを変更

エンベロープのカーブを調整することで、音の表情が変化します。例えば、よりパーカッシブなエンベロープに変更してみましょう。

```
SynthDef("testsynth", {
	arg out, sustain=1, pan, accelerate, freq;
	var env = EnvGen.ar(Env.perc(0.001, 0.999, 1, -4), timeScale:sustain, doneAction:2);
	var sound = SinOsc.ar(freq * Line.kr(1,1+accelerate, sustain));
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;
```

持続時間を調整します。

```
d1 $ s "testsynth*2" # sustain "0.5" # pan "0 1" # note "9  21"
```

## 応用

あとは、SuperColliderの様々なUGens(ユニットジェネレイター)を使用して複雑な音を生成していくことが可能です。例えば、Roland TR-808風のバスドラム。

```
SynthDef("super808", {
	arg out, speed=1, sustain=1, pan, voice=0, n;
	var env, sound, freq;
	n = ((n>0)*n) + ((n<1)*3);
	freq = (n*10).midicps;
	env = EnvGen.ar(Env.linen(0.01, 0, 1, 1, -3), timeScale:sustain, doneAction:2);
	sound = LPF.ar(SinOscFB.ar(XLine.ar(100*freq, freq, 0.025/speed), voice), 9000);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env))
}).add;
```

これを、Tidalから演奏します。

```
d1 $ s "super808*8" # sustain "0.5" # pan "1 0.5 0" # gain "1 0.5 0.75 0 1"
```

さらに、先程の"testsynth"と同時に鳴らしてみましょう。

```
d1
$ stack[
s "super808*8" # sustain "0.5" # pan "1 0.5 0" # gain "1 0.5 0.75 0 1",
s "testsynth*8" # sustain "0.25" # pan "0 0.7 0.3 0.5 1" # note "52 40 47" # gain "1 0.5 0.8 1"
]
```

さらに、juxや、gapなどで操作してみます。

```
d1
$ jux (iter 8)
$ every 4 (gap 16)  
$ stack[
s "super808*8" # sustain "0.5" # pan "1 0.5 0" # gain "1 0.5 0.75 0 1",
s "testsynth*8" # sustain "0.25" # pan "0 0.7 0.3 0.5 1" # note "52 40 47" # gain "1 0.5 0.8 1"
]
```

徐々に複雑なリズムが生成されるようになりました。様々な工夫でオリジナルな表現が可能となりそうです!