Ableton Live 10のMax For Liveでマルチチャンネル出力デバイスを作る

# はじめに
この記事はAbleton LiveとMax for Liveが扱える人に向けて書いています。
live.objectオブジェクトやlive.observerオブジェクトが使える前提とします。

2018年2月にAbleton Live 10がリリースされました。
新機能は色々ありますが、ここでは**Max for Live(以下M4L)からのマルチチャンネル出力**を取り上げます。
<img width="462" alt="スクリーンショット 2018-02-14 9.22.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/7208cb06-8a5d-f149-bb8b-b588b79f0eb8.png">
(画像はAbletonの[Web](https://www.ableton.com/ja/live/)から)
マルチチャンネル出力のサンプルとして[Surround Pannerデバイス](https://www.ableton.com/ja/packs/surround-panner/)が使用できますが、特殊なスピーカー配置の場合や独自のパンニングアルゴリズムを使用したい場合は自分でマルチチャンネル用M4Lを作ってしまった方が良さそうです。
そのやり方をSurround Pannerデバイスを参考に探ってみます。

## **注意**
この記事は**2018年2月14日**に書かれました。M4LからLiveの機能を使用する場合は[Live Object Model](https://docs.cycling74.com/max7/vignettes/live_object_model)(以下LOM)がドキュメントとなりますが、現時点ではAbleton Live 9.7.3に対応したものしか無いようです。
そのためSurround Pannerデバイスを参考にしてマルチチャンネル出力方法を探っていますが正しくない可能性もあるため、LOMがAbleton Live 10対応になった場合はそちらを確認するのが確実だと思います。


# とりあえず安直な方法を試す
plugout~オブジェクトに引数をたくさんつけたらマルチチャンネル出力が...
<img width="179" alt="スクリーンショット 2018-02-14 8.30.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/b0f22281-fe56-b7de-8e34-bc3153acc9d0.png">
**できません...！！！**
plugout~オブジェクトの引数1,2はこれまで通りのデバイスの出力となるので、サイン波は聞こえるはずですが、マルチチャンネル出力はできていないようです。
それもそのはずでマルチチャンネル出力といっても**どのタイプ（オーディオインターフェースかAbletonの他トラックなど）**の**どのチャンネル**から出すのかを指定しないと動きません。
すべての出力を使うような設計にすると無駄な負荷が生まれる恐れがある（使わない出力を確保する必要は無い）ので、必要なチャンネルのみ指定する設計になっているのだと思います。


# Surround Pannerデバイスはどうしているのか？
Surround Pannerデバイスを開いて確認してみます。
赤枠のサブパッチ **BrowseRouting2**で出力の指定をしているようです。
<img width="1539" alt="スクリーンショット 2018-02-14 9.47.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/3f61e9f0-5cc0-7c31-9a2b-56d80ff7e9a0.png">
同じbpatcherが合計で4つありますが、M4Lのマルチチャンネル出力は**2チャンネルごとに指定**するようになっています。
つまりSurround Pannerデバイスには通常のM4Lデバイスの出力以外にマルチチャンネル用出力が8チャンネル用意されていることになります。
最大出力チャンネル数は不明ですが、10ch出力をしたい場合はBrowseRouting2をもう1つ作ってパンニングアルゴリズムの部分を10ch用に書き換えれば動くと思います。
2チャンネルごとに指定する仕組みになっていますが、1チャンネル目からしか出さない(もしくは2チャンネル目のみ)という指定はできるので、例えば7チャンネルサラウンドにも対応できるようになっています。

## BrowseRouting2の中身を確認
さきほどの赤枠のBrowseRouting2を開いて確認する前に、どんな引数が指定されているのかを確認します。
<img width="398" alt="スクリーンショット 2018-02-14 10.20.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/f2ef20c0-b8c7-31f7-e7fc-2ecc1b49391f.png">
第1引数は"audio_outputs"、第2引数は"2"でした。
このbpatcherはマルチチャンネル用出力の1,2チャンネルですが、plugout~オブジェクトのインプット3,4に対応しています。
表にしてまとめると、

| BrowseRouting2の第2引数  | plugout~オブジェクトのインプット  |
|:-----------:|:------------:|
| 2       | 3, 4        |
| 3     | 5, 6      |
| 4       | 7, 8        |
| 5         | 9, 10          | 

となります。
ちなみに、BrowseRouting2の第2引数に1を指定するとplugout~のインプット1,2も他と同じように好きな出力を指定できますが、通常のM4Lデバイスの出力も兼ねている点に注意が必要です。トラブルの元になりそうなのでサラウンドパンナーを自作するときはplugout~のインプット1,2は使用しない方が良さそうです。

これを頭にいれた上でBrowseRouting2の中身を確認します。
\#1と\#2は先ほどの引数に対応しているので、#1は"audio_outputs"、#2は"2"です。
パッチ右上にある黄色のlive.pathオブジェクトでM4Lデバイス自体のidを取得し、黄色の[live.observer audio_outputs]でオーディオ出力に関するidのリストを取得します。
先述したようにM4Lのマルチチャンネル出力は2チャンネルごとに指定するようになっています。そのため2チャンネルごとにidが割り振られています。plugout~のインプット3,4に対応するidはリストの2番目なので、[zl nth 2]で取得しています。
そのidをサブパッチ RoutingObjectsの第2インプットに渡しています。RoutingObjectsは2つあり、引数を変えることで出力のタイプ(オーディオインターフェースや他トラックなど)の指定と、チャンネルの指定をそれぞれするようになっています。
<img width="704" alt="スクリーンショット 2018-02-14 9.56.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/02470c56-939e-3c09-5b4e-1d69bda81f47.png">

## RoutingObjectsの中身を確認
### **タイプ**
タイプの指定をしているサブパッチ [RoutingObjects available_routing_types routing_type]を開いてみます。
パッチ上側の[live.observer available_routing_types]で使用可能なタイプのリストを取得して、パッチ下側のlive.objectでタイプの選択をしています。
パッチ上側の[live.observer routing_type]では現在選択中のタイプが出力されます。
<img width="832" alt="スクリーンショット 2018-02-14 11.40.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/0c8f7b37-c71d-3c6d-c9d7-76ffee87ec9f.png">

### **チャンネル**
さきほどのタイプがチャンネルに変わっただけです。
パッチ上側の[live.observer available_routing_channels]で使用可能なチャンネルのリストを取得、パッチ下側のlive.objectでチャンネルの選択です。
同様に、パッチ上側の[live.observer routing_channel]では現在選択中のチャンネルが出力されます。
<img width="818" alt="スクリーンショット 2018-02-14 11.52.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/1ddc06c5-5ac7-e99f-7f99-fe0a53437911.png">

### **ハマりどころ**
タイプ、チャンネルの取得、選択ともに、dictionaryのフォーマットでやる必要があります。
dict系オブジェクトが多用されているのはそのためです。

# 簡略化したマルチチャンネルM4Lデバイスを作りました
dictonaryでどんなデータが送られているのかが分かりづらいので、シンプルなマルチチャンネルM4Lデバイスを作ってみました。
**リポジトリは[こちら](https://github.com/AkiyukiOkayasu/MaxForLive_MultiChannelExample)。**
現在出力可能なタイプとチャンネルがdict.viewに表示されるのでその中のidentifierをlive.numboxに打ち込むとサイン波が出力されます。
<img width="1046" alt="スクリーンショット 2018-02-14 13.54.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/91684dcf-77a8-7721-1e8f-eb0e1fb8610b.png">

マルチチャンネル用出力が4チャンネルありますが、そのうちのplugout~の3, 4チャンネルに対応した部分の中身を見てみます。
<img width="1250" alt="スクリーンショット 2018-02-14 13.43.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/212299/f7b50666-3cf9-2872-6d26-bfcff6d0250b.png">
とてもシンプルになりました。
live.objectに、"routing_type"と"routing_channel"を指定していますが、それもdictonaryのフォーマットで渡す必要があるので、dictオブジェクトを経由してから渡しています。
~~この仕組みスマートじゃない...~~

これを増やしていけばたくさんのチャンネルがM4Lデバイスで扱えるようになります。
チャンネル数も自在で好きなパンニングアルゴリズムが書けます。最高ですね。