TouchDesigner×Pythonで軽率にOSC通信する方法を初心者向けに説明する

この記事は[Iwaken Lab.アドベントカレンダーの6日目](https://qiita.com/advent-calendar/2021/iwakenlab)です。
# 背景

同一ネットワークのリアルタイム通信を行う場合、UDPやTCP通信など行う場合、OSC通信が有用である場合があります。

例えば、私が以前HoloLensプレゼンを行った時の、HoloLens→Unreal Engineへの通信もOSC通信で行いました。

https://youtu.be/hMo4JAANi8w?t=875

ここで、入力と出力を増やしたいといった場合に、OSC通信を束ねる役割があると便利になります。(リレーサーバー的な役割)
それをTouch Designerで行う場合のヒントになる記事がこちらになります。

![Youtube (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/03f86d69-d637-5285-85f5-3bb8c705eaa7.png)

## OSC通信とは

> OpenSound Control（OSC）とは、電子楽器（特にシンセサイザー）やコンピュータなどの機器において音楽演奏データをネットワーク経由でリアルタイムに共有するための通信プロトコルである
https://ja.wikipedia.org/wiki/OpenSound_Control

> OSC（Open Sound Control）とは，送信者（クライアント）から受信者（サーバ）へ，つぎのようなデータを送るための仕組みです．
https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial4.html

> もともとは電子楽器のコンピュータ制御のためにつくられましたが，今ではさまざまな用途に使われています．通信の実装部分には UDP を利用することが多いようです．UDP とは，TCP と同様に，IP（Internet Protocol）を使ったデータ通信方法のひとつです．

UDP通信を利用することが多いというのもポイントです。
つまり、**IPアドレス**と**Port番号**が分かればデータを投げつけることができます。

投げられるデータは

- 整数 (int)
- 実装 (float)
- 文字列 (string)

などです。



## なぜOSC通信が有用か

同一ネットワーク内でのリアルタイム通信を行いたいケース、例えば撮影スタジオ、VJイベント、XR展示ではOSC通信が便利になるケースが多いです。

個人的意見としては以下です

- 複数のツール/プログラミング言語に対応している
    - Madmapper,TouchDesigner
    - Unity,Unreal Engine
    - Python,C#,C++...
- 実装が楽
    - グローバルに行う場合、サーバーを準備する必要がある→ローカルネットワーク内の通信を行うには too Much
    - UDP通信、TCP通信→ 既存のツールで対応していない場合がある
    - OSC通信→既存ツールで対応している + 実装もシンプル


## TouchDesingerとは

> TouchDesignerというのは、カナダのDerivative社が開発しているアプリケーションで、コードを書かなくてもインタラクティブなコンテンツが作成できるため、デザイナーからプログラマー、アーティストまで、幅広くコンテンツ開発ができるということが魅力のひとつです。では、コードを書かずにプログラミングができるというのはどういうことでしょうか。以下で実際の画面を見ていただくとわかるかと思います。
https://www.taki.co.jp/blog/lab_takagi_20190902/

ノードベースで3Dのレンダリングや、データのやり取りをできるツールです。
メディアアートやVJなどに使われることが多いそうです。

## なぜTouchDesignerでOSCを行いたいか

OSC通信を束ねるリレーサーバー的な役割に関して、**ぶっちゃけ手段は何でもOKです**

チームに合わせて「どの技術力が高いか」「現場での柔軟性が高い手段が何か」を照らし合わして技術選定すると良いです。

私の場合

- 現場ではソースコードを書けない人も微修正対応する可能性がある
- アプリ化してUI的に使いやすいようにしたい
- TouchDesigner触ってみたい

という理由から、C#やC++などではなく、TouchDesignerを選びました。

# この記事が解決すること

今までTouchDesinger触っていなかったプログラマが、TouchDesignerを触ると

- **「どこから触ればいいかわからない」**

となり、調べようにも

- **「Pythonでカスタマイズしたいが、英語の記事しかない」**
- **「意外とピンポイントで知りたい記事が見つからない」**

といったケースが多かったです。

この記事では、TouchDesigner×PythonでOSC通信を最低限行う実装とオススメ設定をご紹介します。

# 手順

- 最初の準備を行う
- OSCIn/Outを作る
- Pythonでリレー通信の処理を書く

# 最初の準備を行う

TouchDesignerを立ち上げると、NewProject.toeが立ち上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/04bd247c-254b-5d7f-93e1-75d475990817.png)

まずこれらのノードたちを削除しましょう。

ノードを選択してBackSpaceキーを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/faa20817-7905-1ac6-e73c-d84895db8093.png)


# OSCInノードを作って設定

OSC通信を受け取るノードになります。

まず**Tabキー**を押すとOP Create Dialogが現れます。これを選ぶと様々なノードを生成できます。
ここから**「DAT」**タブを選択し、**OSC In**を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/8c0dcc42-29ac-5bda-64c9-11ce72213306.png)

OSC Inを生成。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/a74847e1-2740-3ea4-273b-f58b1ab0fd02.png)


生成されたOSCInをクリックして**「Pキー」**をクリックします (パラメータ画面を開くショートカットキーになります)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/b71dc292-7970-866b-b121-cdb5ea3aecbe.png)

OSC Inの設定について以下について設定します

|項目|設定|
|---|---|
|Active|On|
|Protocol|Messaging(UDP)|
|Port|7000 (なんでもOK)|
|LocalAddress|(自分のPCのIPAddress)|

# OSCOutノードを作って設定

OSC通信を送信するノードになります。
送信する目的地の数だけ作る想定です。

まず**Tabキー**を押して**「DAT」**タブを選択し、**OSC Out**を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/f0db5b80-2c05-fdb2-31fe-3de2b5bf270c.png)

パラメータ設定を以下のようにします。

|項目|設定|
|---|---|
|Active|On|
|Protocol|Messaging(UDP)|
|NetWorkAddress|(送り先のIPAddress)|
|Port|7001 (なんでもOK/OSC Inと変えてみる)|

# Pythonでリレー通信の処理を書く

狙い、OSC通信を受け取って、別のIPAddressに通信する。

oscin1にくっついているこのノードをPythonで書き換える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/d9904043-7ff5-5104-8044-4bd32553e30e.png)

## お気に入りのEditorで編集

ノードを選択し「Ctrl+E」もしくは右クリックで「Edit Contents」を押すと、Editorが立ち上がります。
この時のEditorを設定するには、

- [Edit]>[Preferences]でダイアログを開き
- [DATsタブ]>[Text Editor]で選択
- [Save]ボタン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/957bb157-bb38-4ed3-e577-c7d1069b886a.png)

私はVSCodeを選択しています。

# Pythonで書いてみる

開くとこのような画面が開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/f7dfb8ec-4d25-0543-772a-5cce091fab53.png)

onReceiveOSC関数を書き換えましょう。

```python
def onReceiveOSC(dat, rowIndex, message, bytes, timeStamp, address, args, peer):
	# oscout1という名まえのノードを取得
	osc_out = op("oscout1")
	# address: OSCAddress 例:"/hoge/fuga"
	# args: 変数のリスト 例:[0,0,1]
	osc_out.sendOSC(address,args)
	return
```

これで、OSCInから受け取ったOSCAddressと引数がOSCOutの目的地へ送られる実装ができました。

# これで完成です！！！

# その他便利設定

## TouchDesignerを最小化しても、OSC通信を止めないようにする

デフォルトではTouchDesingerを最小化すると、OSC通信のプロセスが止まってしまいます。これでは不便です。それを回避する設定は
[Edit]>[Preferences]>[General]>**[Stop Playing when Minimizedのチェックを外す]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/e04aad7a-008f-9380-fe22-ea70f3a26216.png)

## デバッグログを吐き出す

`print("hogehoge")`と書くと書き出される。
ログの場所は[Dialogs]>[Textport and DATs]を選択する。すると登場する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/36120192-128d-43bf-1e40-68b7dbf12f5e.png)

# この記事では書きませんでしたが、やりたいと思われること

- ボタンなどUIを作る
- 複数のOSC Outに送る
- 受け取ったOSCAddressによってフィルタリングを行う