TouchDesignerでのPython入門（基礎編）

# この記事について
TouchDesignerやってるけどPythonほとんど書いたことない私さのかずや(Twitter:[@sanokazuya0306](https://twitter.com/sanokazuya0306))が理解を深めるためにつくった、TouchDesignerでPython書けるようになりたい人用のメモ。
ほぼ[公式の英語チュートリアル](http://www.derivative.ca/wiki088/index.php?title=Introduction_to_Python_Tutorial)の翻訳。

ていうか全部書き終わってから[お触り本](http://www.bnn.co.jp/books/8842/)の後ろの方にまとまっている事に気づいてしまいました。もっと知りたい人はこっち買って！

## TouchDesignerでのPythonで得られる幸せ
TouchDesignerは工夫してコード繋げばいい感じの絵を出してくれるけど、**変数の扱いとかがめちゃ面倒**だったり、コード書く系のジェネやってる人とかはいろいろと不便を感じがち。
そういうときは**Python使えると大体解決するっぽい。**なので書けるに越したことはなさそう。
公式のチュートリアルもあるのですが、~~例によって読みにくいので~~噛み砕きながら日本語で残しておきます。

翻訳シリーズご興味ある方はこちらもどうぞ
[TouchDesignerでGLSL入門](https://qiita.com/sanokazuya0306/items/530ed55a021db24ad8ec)

### ちなみに
この基礎編では、下記公式のチュートリアルを順を追って日本語で紹介していきます。
[Introduction to Python Tutorial - TouchDesigner 088 Wiki](http://www.derivative.ca/wiki088/index.php?title=Introduction_to_Python_Tutorial)

ただ正直、~~公式のチュートリアルがあんまイケてないので~~とりあえずTouchDesigner上でPython動かしてみようぜーくらいで、**大した内容がありません。**
実際どう使ったらエエねん！というのは**応用編で紹介**します。あらかじめ！

# Python入力
公式チュートリアルの[Inputting Python](http://www.derivative.ca/wiki088/index.php?title=Introduction_to_Python_Tutorial#Inputting_Python)の部分。

## TextportでPythonする
TouchDesignerでPythonを試す一番簡単な方法は**Textport**を使う方法。
<img width="545" alt="スクリーンショット 2017-11-25 19.46.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/612a2341-005d-31ab-342e-4498fc11ed06.png">
メニュー → Dialogs → Textport and DATs でTextportを開く。

<img width="839" alt="スクリーンショット 2017-11-25 19.47.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/bd60028e-0792-3894-cc11-93f20c117080.png">
そうするとこんな感じの画面が出てくる。なんかごちゃごちゃ出てるときは右上のClearを押すと消える。

<img width="831" alt="スクリーンショット 2017-11-25 20.03.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/4359f041-6cbe-6bc9-2b03-918227b0b8c8.png">
試しに`help(absTime)`と入れると、[td Module](http://www.derivative.ca/wiki088/index.php?title=Td_Module)というTouchDesignerのどこでも使える変数（ここではabsTime）についての説明が見られる。td ModuleにあるものならabsTimeじゃなくてもなんでもいけるっぽい。


### 余談
TouchDesigner099で使える言語は**PythonとTScriptの2種類**ある。TScriptはC++用？のスクリプト言語。ターミナルで使うっぽい入力方式だけどよくわからない。[Wikipedia](https://en.wikipedia.org/wiki/TScript)と[公式のリファレンス](https://www.derivative.ca/wiki088/index.php?title=Tscript)読んで！
TouchDesignerは最初TScriptで作られていたらしい。それがどこかのタイミングで**Pythonベースに作り変えられ、TScript記述モードはいまも名残で残っている**様子。いまの主流はPython。

<img width="271" alt="スクリーンショット 2017-11-25 19.49.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/fe893ab1-06a1-a79c-7f9e-525d15496779.png">
**左上にPythonマークが表示されているときはPythonモード。**これをクリックすると下に切り替わる。

<img width="281" alt="スクリーンショット 2017-11-25 19.49.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/573079a7-3f35-a084-2a91-12b7f6fbf15e.png">
これが表示されているときは**TScriptモード。**物好きなアナタは試してみてはいかがでしょう。今回は使わないのでもう1度押してPythonモードに戻しておく。

## DAT ScriptでPythonする
複数行のスクリプトを使うときは、**Text DATなどのDAT**を使う。

<img width="561" alt="スクリーンショット_2017-11-25_22_37_32.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/3be18ce0-ec86-2cfd-7025-c2c5b26d91a0.png">
とりあえずText DATを適当に置く。右上にPythonマークが出てたらPython入力モード。上の余談と同様にTScriptモードにすることもできる。

<img width="307" alt="スクリーンショット_2017-11-25_22_40_55.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/4cca0715-5514-2351-b462-6ccac38a5171.png">
DATの中をいじるため、右下のViewer Active Flagを押す。
Viewer Active Flagのオンオフは選択状態でキーボードのAを押すことでも変更できる。

とりあえずこんな感じでいれてみよう。

```
for i in range(1,5):
    print(i)
```
1以上5未満の範囲でprint(i)を繰り返す、というPython文。
なんで5は含まへんの？と思って調べてみたら、0から数えて5つめまで(4)ということっぽい。詳しくはこのあたりをご参照。
[【Python入門】range関数で繰り返し処理をする方法とは? | プロスタ](http://programming-study.com/technology/python-range/)
ちなみに**1行目にはスペースやタブを入れてはならず、２行目以降のインデントはタブ1つか半角スペース４つでないといけない**らしい。

これをText DATの中にコピペ。

<img width="359" alt="スクリーンショット 2017-11-25 22.44.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/1ca19c28-b55f-5ffa-dd8c-809f02f53899.png">
右クリックしてRun Script、もしくは⌘+R。
一見何も起きないが、メニュー→Dialogs→Textports and DATsからさっきのTextportをもう一度開くと…

<img width="631" alt="スクリーンショット 2017-11-25 22.45.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/d579029f-a078-cff4-7407-4c41bfa7ec1b.png">
**Textportのなかで実行されている**ことがわかる。おめでとう。

## Moduleをimportする
Pythonを使えることのありがたみの１つは、**Pythonで導入できるModuleを使える**こと。TouchDesignerは最初から、一般的なModuleやNumPyなどの科学計算モジュールなどが入っているらしい。
プログラミング慣れしている方ならおなじみだと思いますが、Moduleとは、みんなが使える「定義や文が入ったファイル」。例えば四則演算以外のややこしめの計算とかも簡単にできたり。詳しくはこのへん。
[6. モジュール (module) — Python 3.6.3 ドキュメント](https://docs.python.jp/3/tutorial/modules.html)

例えばさっきのText DATにこんな感じで入れてみる。

```python
import math
print(math.sin(4))
```
mathというModuleをimport（使いますよという宣言）して、mathの中のsin計算をするsinという関数(math.sin()と書く)を引っ張って、そこに4をいれてますよ、というプログラム。
そして⌘+R。

<img width="553" alt="スクリーンショット 2017-11-25 23.03.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/17ee1792-7ba1-ff9d-866b-bba3f15032e4.png">
sin(4)の計算をしてくれてますね。ちなみに()の中は度ではなくラジアン(4[rad]=4*180/π[度]≒229[度])なのでご注意。

なお、新規Moduleの追加やModuleのバージョン変更は結構面倒くさいっぽいのでここでは省略。TouchDesigner099はPython3.5で動いているっぽく、Preferenceの`Python 64-bit Module Path`でPath指定すればいけるっぽいが、試してません(MacのPython Moduleがどこにあるのかわからんかった)。誰か必要なら試して！

## DATからInternal Moduleをつくる
**これはかなり便利っぽいテク。**Paletteで出せるものにもけっこう使われているので知っておいて損はなし。

Text DATを２つつくり、１つの名前を`my_utils`にし、下記を入力。

```python:my_utils
def my_adder(x,y):
    return 10*x+y
```
もう１つを`test_import`とし、下記を入力。

```python:test_import
import my_utils
a = my_utils.my_adder(1,5)
print(a)
```

上の`my_utils`内の`my_adder(x,y)`は、10*x+yを計算する関数。
それを下で`my_utils.my_adder(x,y)`で呼び出して、x,yを代入、print。
つまり、**`my_utils`がInternal Moduleとなって、別のDATで活用できる。** 便利か〜

<img width="385" alt="スクリーンショット 2017-11-26 0.16.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/ed0f345b-88a4-04b2-a696-f1df376703d7.png">
この状態でtext2をRun(⌘+R)。


<img width="551" alt="スクリーンショット 2017-11-25 23.48.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/d8a33aac-d163-4105-ad92-516de4161336.png">
また計算してくれるんですね〜、すばらしい

### Component Module
上記のように同じ階層にあるとInternal Moduleをちゃんと読み込んでくれるが、**別の階層にあると読み込んでくれない。**
<img width="1023" alt="スクリーンショット 2017-11-26 0.02.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/486bdd14-bc07-87b4-84d6-6d0ef6c5c11e.png">
別の階層にあるとこんな感じで怒られる。

しかし１ヶ所、共通でModuleを読み込んでくれる場所がある。
それが**`local/Modules`**。
<img width="1023" alt="スクリーンショット_2017-11-26_0_02_23.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/c8fd24c2-c84c-f93a-a80b-7d51098e2390.png">
`local`の中に入って

<img width="472" alt="スクリーンショット_2017-11-26_0_04_31.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/3cd5bfb7-2ef7-85c8-4c99-ee5498f4da1f.png">
`Container COMP`を置き、`modules`に名前を変えて、ここの中に`my_utils`を置く。ここにあるModuleを**Component Modules**と呼ぶっぽい。 

<img width="756" alt="スクリーンショット 2017-11-26 0.18.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/279bcb03-d376-4f5a-3617-2325dd13fe5e.png">
ここに置いていると同様に計算ができる。美しい…

### mod (Modules On Demand)
TouchDesignerでしばしば見る`mod`について。**`mod`はimportの欠点を補完するためのもの。**
というのも、便利なimportだが、２つの欠点がある。

>- Moduleの名前は単語でないといけないため、特定の階層を指定したくても**相対パスが使えない。**
- import文がウザいため、**パラメータ表現に向いていない。**
>

（ごめんなさい、正直なんでパラメータ表現にimport文が邪魔なのかよく分かってません、先生おしえて！）

これらを解決するために、TouchDesignerには**`mod`という関数**(?)がある。これを使うとimport文が不要になり、相対パスが使えるようになる。どういうことかというと…

```python:test_import
a = mod.my_utils.my_adder(1,3)
print(a)
```
**importが必要なModule名の最初に`mod`をつけるだけ**で、上記のように置き換えることができるようになる。

```python:test_import
a = mod('my_utils').my_adder(1,3)
print(a)
```
さらに、**`(' ')`で囲んでやれば相対パスが指定できる。**

```python:test_import
a = mod('/project1/my_utils').my_adder(1,3)
print(a)
```
もちろん、**絶対パスも指定できる。** 便利か〜

## Operatorで操作する
[Working with OPs in Python](https://www.derivative.ca/wiki088/index.php?title=Working_with_OPs_in_Python)の内容。
**TouchDesigner独特の関数(?)による指定の仕方に慣れる回。**

### 基本アクセス
よく使うものに`me`と`root`がある。
>- `me`: いま計算しているやつ。Operatorの中で使うときはそのOperator自身を指す。
- `root`: ルート階層（一番上）のComponentを指す。 
>

それから`op( )`というのを使うと各Operatorの情報にアクセスできる。詳しくはこちら。
[OP Class - TouchDesigner 088 Wiki] (http://www.derivative.ca/wiki088/index.php?title=OP_Class)

<img width="372" alt="スクリーンショット 2017-11-26 0.54.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/a0bd7010-c7d6-ca8d-a14a-4be9c8db22ac.png">
たとえば、Wave COMPとConstant COMPを出し、Constant COMPの`name0`の左にある＋を押し、青いボタンを押し、`op('wave1')`と入力する。

<img width="762" alt="スクリーンショット 2017-11-26 0.47.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/0312c659-e760-6fec-f621-4bfa402d9e92.png">
そうするとこうなる。**`op('wave1')`はwave1の絶対パスを表示してくれる。**
厳密に言うと絶対パスを指定しているわけではなく、wave1というオブジェクトを指定していて、便宜上そのパスを表示しているだけなのだけど、オブジェクト指向の説明はややこしいので省略します。

もちろんこの書き方はDATの中などでも使えて、`n = op('wave1')`のように変数に入れたりもできる。

<img width="302" alt="スクリーンショット 2017-11-26 0.58.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/b283c351-476a-44dc-76ab-d2aa7388dcb4.png">
`me.parent()`と入れると親階層を指定したりもできる。

<img width="714" alt="スクリーンショット 2017-11-26 1.42.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/bd3b9c75-7fef-55c3-5254-1d42f7fa8153.png">
COMPであれば`me`を使って、`me.op('子ノードの名前')['チャンネル名']`でCOMP内の子ノードの数値を取ってこれたりもする。

<img width="881" alt="スクリーンショット 2017-11-26 1.44.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/e7ffc44f-9699-b098-21e1-f8e2d882087d.png">
COMPじゃなくても、`op('COMPの名前').op('COMPの子ノードの名前')['チャンネル名']`とやれば下の階層の数値を引っ張り出せる。


### 例
```python
n = op('/project1')
m = n.ops('text*')
for a in m:
    print(a.name)
```
`Project`以下のOperatorで、`'text*'`に当てはまるものを抽出し、その名前をprintする。
Text DATにこれを入力すると…

<img width="612" alt="スクリーンショット 2017-11-26 1.28.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/a4db938e-f547-3fb3-6e7a-f0078110381c.png">
こうなる。

```python
print('i am ', me)
print('child of ', me.parent())
print('grandchild of ', me.parent(2))

print('root children:')
k = root.children
for r in k:
    print(r)
```
`me`や`.parent()`、`root`、`.children`をそれぞれ使ったもの。
これをいれると…

<img width="682" alt="スクリーンショット 2017-11-26 1.31.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/77925/b9356a9b-634e-3d87-8cf7-ac02c4703790.png">
こんな感じで表示してくれる。これで一通りわかるはず。


## コマンド早見表
[TouchDesigner Operaotr＆Python Scriptまとめ](https://qiita.com/freeman/items/f0038df7b3cdffcf3925)
こちらにもすでにある程度まとめられていますが…
[公式ページのコマンド/表現一覧](http://www.derivative.ca/wiki088/index.php?title=Introduction_to_Python_Tutorial#Python_-_TScript_Equivalents)は、コマンド一覧はあまりにコマンドライン的操作すぎるので省略。必要そうな表現一覧だけ記載。

| 目的       | Pythonコード |
|:-----------------|:------------------|
| 同じOPのパラメータを取得 | me.par.tx / me.par.value0 |
| 別のOPのパラメータを取得 | op('sphere1').par.tx / op('constant1').par.value0 |
| OP(例:constant1)の出力(chan1)を取得 | op('constant1')['chan1'] |
| OPの親 | .parent() |
| OPの親の親 / 親×n | .parent(2) / .parent(n) |
| table1の1,1を取得 | op('table1')[1,1] |
| OPの名前 | .name |
| OPの数値 | .digits |
| ランダム数値を生成 | tdu.rand(me.digits)　※()内はランダムシード |
| 要素(container1の子ノード)の数を数えたいとき | len(op('container1').children) |
| 要素(switch1)のinput/outputの数を数えたいとき | len(op('switch1').inputs) / len(op('switch1').outputs) |
| Info CHOPの内容はop().xxで引っ張り出せる | op('moviein1').width |
| 時間（フレーム単位） | absTime.frame / me.time.frame |
| 時間（秒単位） | absTime.seconds / me.time.seconds |

などなど…[お触り本](http://www.bnn.co.jp/books/8842/)の一番後ろの方にもあるのでご参照あれ。


# 以上これまで
以上で公式リファレンスの内容は大体終わりなんですが、これでみなさんPythonマスターですね！！

## とはいえ
そう、みなさんお気づきの通り、
**結局変数どうやって扱ったらええの？if文とかfor文的なやつとかどうやって書くの？とかが公式リファレンスには全くありません。**
~~公式リファレンスの説明冗長すぎひん？これまでの要素説明するのにこんな解説量いる？~~
基本自分でやれやというスパルタ感なので、我々プログラミングわからへんからTouchDesignerやってんねん勢にはちょっとまだまだハードル高くて泣ける。

なので**具体的にどう書けばifとはforとかできんの？あとCHOPとか使いたいねんけど？というのは応用編でまとめたい**と思います。
翌日のアドカレをおたのしみに〜