Touchdesignerでノード接続とカスタムパラメータの自動リスト化

# はじめに
僕のようなTouchdesigner初心者にとって、TD学習でChatGPTを頼る機会も多いですが、コードベースのツールと違い、人間にとって視覚的に分かりやすいノードベースのツールは、ChatGPTにクエリを投げるには不便なことも多い。
そこで、同一階層内にあるノードがどこから入力されてどこに出力されるか、そしてデフォルトのパラメータのどこを変えたかをYAML形式で出力されるスクリプトを作りました。

# 実験
TDを触ると誰もがバナナを回しますので、この[チュートリアル](URL "https://www.youtube.com/watch?v=lWGknmeueMA&list=PLSqkC3f_BStyrO-ZSgJ2Ee4WONJYzO3s1&index=3")で作ったプロジェクトに以下のtxtファイルをドロップして、text Datをctrl + rで実行します。



```python:network_tree_with_modified_parameters.txt
import yaml

def get_connections(op):
    """
    ノードの入力および出力接続を取得する。

    Args:
        op (Operator): 対象のTouchDesignerノード。

    Returns:
        tuple: 入力ノードのリスト、出力ノードのリスト。
    """
    inputs = [input_op.path for input_op in op.inputs] if op.inputs else []
    outputs = [output_op.path for output_op in op.outputs] if op.outputs else []
    return inputs, outputs


def get_modified_parameters(op):
    """
    デフォルトから変更されたパラメータを取得する。

    Args:
        op (Operator): 対象のTouchDesignerノード。

    Returns:
        dict: 変更されたパラメータ名とその値の辞書。
    """
    modified_params = {}
    for param in op.pars():
        if not param.isDefault:
            modified_params[param.name] = param.eval()
    return modified_params


def collect_node_data(op):
    """
    ノードの情報を辞書形式で収集し、子ノードを再帰的に収集する。

    Args:
        op (Operator): 対象のTouchDesignerノード。

    Returns:
        dict: ノード情報を含む辞書。
    """
    inputs, outputs = get_connections(op)
    modified_params = get_modified_parameters(op)

    node_data = {
        "type": op.type,
    }

    if inputs:
        node_data["inputs"] = inputs

    if outputs:
        node_data["outputs"] = outputs

    if modified_params:
        node_data["modified_parameters"] = modified_params

    if op.children:
        node_data["children"] = [collect_node_data(child) for child in op.children]

    return {op.name: node_data}


# ファイル名を指定して保存
output_file_path = 'network_tree_with_modified_parameters.yaml'

# ルートノードを設定（例: /project1）
root_op = op('/project1')  # 適宜ルートノードを変更

# ノード情報を収集してYAML形式で保存
network_data = collect_node_data(root_op)

with open(output_file_path, 'w') as file:
    yaml.dump(network_data, file, default_flow_style=False, allow_unicode=True)

print(f"Network tree with modified parameters has been saved to {output_file_path}")


```


すると、以下のようなファイルが同一ディレクトリ内にyaml形式で保存されます。

```yaml:td_network.yaml
project1:
  children:
  - lfo1:
      modified_parameters:
        frequency: 0.47
        timeslice: true
        wavetype: ramp
      outputs:
      - /project1/math1
      type: lfo
  - math1:
      inputs:
      - /project1/lfo1
      modified_parameters:
        pageindex: 2
        torange1: 0.0
        torange2: 360.0
      outputs:
      - /project1/null1
      type: math
  - null1:
      inputs:
      - /project1/math1
      type: 'null'
  - null2:
      inputs:
      - /project1/over2
      type: 'null'
  - over1:
      inputs:
      - /project1/transform1
      - /project1/constant1
      modified_parameters:
        size: input1
      outputs:
      - /project1/over2
      type: over
  - over2:
      inputs:
      - /project1/text1
      - /project1/over1
      outputs:
      - /project1/null2
      type: over
  - text1:
      modified_parameters:
        font: Impact
        fontcolorb: 0.0
        fontcolorg: 0.5450981
        fontcolorr: 1.0
        fontsizex: 76.5
        pageindex: 1
        resmult: false
        resolutionh: 720
        resolutionw: 1280
        text: This is a banana
      outputs:
      - /project1/over2
      type: text
  - constant1:
      modified_parameters:
        colorb: 1.0
        colorg: 0.73333
        colorr: 0.0
        pageindex: 2
      outputs:
      - /project1/over1
      type: constant
  - transform1:
      inputs:
      - /project1/moviefilein1
      modified_parameters:
        rotate: 93.41960906982422
      outputs:
      - /project1/over1
      type: transform
  - moviefilein1:
      outputs:
      - /project1/transform1
      type: moviefilein
  - network_tree_with_modified_parameters:
      modified_parameters:
        extension: txt
        file: network_tree_with_modified_parameters.txt
        language: text
      type: text
  modified_parameters:
    h: 720
    pageindex: 1
    parentshortcut: Project
    top: null
    topsmoothness: usetop
    w: 1280
  type: container


```


このYAMLファイルをChatGPTに投げるとこんな返事が返ってきます。


```text

1. project1 (Container)
Type: container
Modified Parameters:
pageindex: 1
w: 1280
h: 720
top: None
topsmoothness: usetop
parentshortcut: Project
概要: project1は、このネットワークの親コンテナで、全体の設定を管理します。このコンテナは1280x720の解像度を持ち、ビジュアルの表示エリアを定義しています。

2. lfo1 (LFO)
Type: lfo
Outputs: /project1/math1
Modified Parameters:
wavetype: ramp（ランプ波形）
frequency: 0.47（低周波）
timeslice: True（リアルタイムに値を出力）
概要: lfo1は、時間ベースのランプ波形を生成し、0から1の範囲で周期的な値を出力します。波形の周波数は0.47Hzで、出力は次のmath1ノードに送られます。

3. math1 (Math)
Type: math
Inputs: /project1/lfo1
Outputs: /project1/null1
Modified Parameters:
pageindex: 2
torange1: 0.0
torange2: 360.0
概要: math1は、lfo1からの0～1の値を、0～360の範囲にスケーリングします。この範囲は回転角度や位置調整に使われる可能性があります。

4. null1 (Null)
Type: null
Inputs: /project1/math1
概要: null1は、デバッグや出力の確認用に使われるパススルーノードです。特に計算結果を次のノードに安全に送る役割を果たします。

5. null2 (Null)
Type: null
Inputs: /project1/over2
概要: null2は、ビジュアルの最終出力を確認するためのノードです。プロジェクト全体の合成結果がここに集約されます。

6. over1 (Over)
Type: over
Inputs: /project1/transform1, /project1/constant1
Outputs: /project1/over2
Modified Parameters:
size: input1（入力1のサイズを採用）
概要: over1は、2つの入力（transform1とconstant1）を合成するノードです。input1のサイズ設定により、背景やオーバーレイのサイズが調整されます。

7. over2 (Over)
Type: over
Inputs: /project1/text1, /project1/over1
Outputs: /project1/null2
概要: over2は、over1の出力（背景とコンポジット）にtext1（テキスト）を重ねるノードです。

8. text1 (Text)
Type: text
Outputs: /project1/over2
Modified Parameters:
テキスト: "This is a banana"
フォント: Impact
フォントサイズ: 76.5
色: 橙色（R: 1.0, G: 0.545, B: 0.0）
解像度: 1280x720
概要: text1は、"This is a banana"というテキストを作成し、フォントと色が設定されています。このテキストは、ビジュアルの最前面に表示されます。

9. constant1 (Constant)
Type: constant
Outputs: /project1/over1
Modified Parameters:
色: 青色（R: 0.0, G: 0.733, B: 1.0）
概要: constant1は、背景色として使用される青色を生成します。この色は、over1でビジュアルに合成されます。

10. transform1 (Transform)
Type: transform
Inputs: /project1/moviefilein1
Outputs: /project1/over1
Modified Parameters:
回転角度: 205.8度
概要: transform1は、入力画像（moviefilein1）を回転させます。この回転角度はlfo1やmath1の値を使用してアニメーションされる可能性があります。

11. moviefilein1 (Movie File In)
Type: moviefilein
Outputs: /project1/transform1
概要: moviefilein1は、外部ファイルから動画や画像を読み込むノードです。これが回転され、over1で背景として使用されます。

全体のフロー
動画（moviefilein1）が回転（transform1）され、背景に設定されます（over1）。
背景に青いオーバーレイ（constant1）が追加されます。
テキスト（text1）が最前面に合成されます（over2）。
LFO（lfo1）の波形を利用して、アニメーションが実現される可能性があります。

```

教科書的な説明が多いですが、同じNullでもその役割の違いを認識したりと有用な部分もありそうです。
そもそも、Touchdesigner画面のスクリーンショットなどをChatGPTに投げるとエラーが出たり、表示されていないタブやパラメーターを考慮することができないので、構造化したファイルで書きだすことで、それらしい答えを返してくれる確率が上がったりします。

# 限界
最終的な画がどうなっているかをyamlから推測するのは現状難しいようで、自分の作りたい画がどのように実現できるかはやはり人間が主導でやらざるを得ません。ただ、チュートリアルを写経したファイルの理解のために構造を書きだすのはある程度使えるかもしれないです。

Touchdesignerを極める日はまだ遠い…