Premiere + TouchDesigner で簡易タイムラインを作る

こんにちは！こちらは [TouchDesigner Advent Calendar 2021](https://qiita.com/advent-calendar/2021/touchdesigner) 6日目の記事です。よろしくお願いします。

今回作ったサンプルは以下にあります。
https://github.com/chimanaco/touchdesigner-advent-calendar-2021

## はじめに
Media Ambition Tokyo 2021 というイベントのトークセッションで Kezzardrix さんが Premiere からタイムラインを作るという話をされていまして、いつか自分でも作ってみようと思っていたところ、UE4 でライブ用のプリレンダーの映像を作るという案件がありまして。
UE4 でシーンを作っておいて決まったタイミングでカメラと一部プロップを切り替えるという構造的には単純なもので、TouchDesigner と UE4 の OSC 経由の疎通は以前からよくやっていたこともあり、自動で OSC を飛ばすタイムラインを作りました（バイブスで作ったのでKezzardrix さんが仰られていたものとはちょっと異なるはずです）。

その時作ったものをベースに同僚の凄腕 Premiere 使いたちと今後いい感じにコラボできるようにドキュメントを残すついでに Advent Calendar にも、というモチベーションで書いています。

## サンプル
![2021-12-06_23h42_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/1dca5863-92f0-bfec-6cb2-227bcf515b89.png)
サンプルはこんな感じでタイムラインの指定のフレームで指定のコメントを出力する、というものです。

## 手順

- [Premiere] 実際の曲と同じ長さでビデオコンテを作る。
- [Premiere] 任意のフレームにマーカーでコメントをつけて、テキストファイルを export する
- [TouchDesigner] export したファイルを読み込んでパースする
- [TouchDesigner] コメントがついているところは1、それ以外は0となる CHOP = タイムラインを作る
- [TouchDesigner] 該当フレームで該当コメントを出力する

という感じです。それでは実際に作り方を見ていきます。

## [Premiere] マーカーを配置する
![2021-12-06_18h19_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/893f7b20-ca86-0f76-c827-007112983702.png)
Premiere に動画ファイルを読み込みます。試す分にはなんでもいいので、[VJ LOOPS | BEEPLE | the work of mike winkelmann](https://www.beeple-crap.com/vjloops) から DL しました。タイムラインに D&D した後、この `Source: ファイル名` タブがあるウィンドウを表示します。（Premiere力が低いため正式名称が分かりませんすみません）
![2021-12-06_18h21_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/53299099-08d4-d069-1fec-59fee6916bf8.png)
この `Source: ファイル名` タブでマーカーを置きたい箇所までタイムラインを動かし、右クリックして `Add Marker` を選択します。
![2021-12-06_18h22_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/67fc3774-766e-92e1-f18d-6a18491b519d.png)
マーカーが追加されました。
![2021-12-06_18h23_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/3a374f88-8c41-e2f6-821d-c9847125954c.png)
追加されたマーカーをダブルクリックすると、ポップアップが出てきます。`Comments` のテキストフィールドに、任意のシーン名を入れます。ここでは `s1` としました。
![2021-12-06_18h26_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/50512702-c340-0fc5-828e-df5bb3209bcc.png)
同じ要領で別のシーンを追加していきます。 `s2, s3, s4` としました。
![2021-12-06_18h26_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/20427ff1-7d0a-d1cf-4e0c-5f7cd32ae5b2.png)
`Markers`タブを見ると追加したマーカーたちの情報を一覧することができます。

## [Premiere] export する
![2021-12-06_18h27_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/208eeb47-b63f-59f6-3621-0b5726faf02f.png)
マーカーたちの位置とシーン名が決まったらファイル書き出しをします。`File` > `Export` > `Markers` を選択します。
![2021-12-06_18h28_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/46076799-369f-ba77-746f-81d0978e3bf4.png)
File Type は `Text File` を選択します（csv でもいけると思いますが、今回のやり方だと自分は txt の方が早かったです）。
![2021-12-06_18h32_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/b2c7683e-beed-d2ac-a050-78eea3273b4f.png)
TouchDesigner のネットワークに D&D するとこんな感じです。これで Premiere の方は完了です！

## [TouchDesigner] 読み込んだデータをパースする
![2021-12-06_22h14_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/1d7f4564-8b47-07a0-b9e8-c0259c91d49e.png)
まず全体のフレーム数とフレームレートを Premiere の設定と同じにします。今回使用した動画ファイルは 30:01 の 30 FPSなのでこの設定を TouchDesigner にも反映させます。```31 * 30 = 930``` としました。
![12021-12-06_22h14_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/fcf3e45a-081d-8601-448f-ada468c4d6cb.png)
`ConvertDAT`で TouchDesigner に読み込んだ txt を table に変換します。使わない Columns があるので、`selectDAT` で `In Point` と `Description` の Column を取得して Merge します。Premiere の `Comments` は export したら `Description` になってますね。
![2021-12-06_22h24_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/9cd8672c-ff95-1f39-318c-1bfdb57ed024.png)
`ScriptDAT`で **00:00:05:03** のような表記をフレーム数に変換します。`def cook(scriptOp)` 内に以下のようなコードを書いて別の `TableDAT` にデータをコピーします。

```
so = scriptOp
so.copy(so.inputs[0])
	
to = op('TableTD')
to.clear()
to.appendRow( ['Marker', 'Description'])
	
orgNum = so.numRows
fps = float(var('FPS'))
	
for r in range(1, so.numRows):
	tex = str(so[r,0])
	mm = tex[3:5]
	ss = tex[6:8]
	ms = tex[9:11]
	
	mmf = float(mm) * 60 * fps	
	ssf = float(ss) * fps
	msf = float(ms)
	frame = mmf + ssf + msf

	des = so[r, 1]
	
	to.appendRow([frame, des])
return
```
これで Premiere で作られたマーカーたちの位置とコメントが TouchDesigner で使いやすいデータになりました。ここで作った **TableTD** という `TableDAT` は後で使用します。

## [TouchDesigner] タイムラインを作る
ここで得られたフレームの時だけ合図を送る、つまり1にするようにして、それ以外の時は0になるような CHOP を作ります。これが実質タイムラインになります。
![2021-12-06_22h51_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/d81bee20-ab37-44ef-22d9-0e9f0cb7a529.png)
フレーム数が入った Column だけにして CHOP に変換します。channel 毎に同じ処理を繰り返すので `Replicator` を使います。
![2021-12-06_22h56_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/9a975d1f-d724-57dc-6026-6bfb07788296.png)
こちらは `master1` の中身です。`"chan" + str(parent().digits)`を使って Replicate された item がそれぞれのナンバリングに基づいた channel を取得するようにします。

`End` パラメータを `var('RANGEEND')`とした 0 の入った `ConstantCHOP` を用意しておき、`SpliceCHOP`を使って該当するフレームと置き換えます。ここではサンプル数**930**、**153**サンプル目に**153**という数値が入っているという CHOP ができました。このままでもいいのですが1が入ってくれればいいので、他のフレームと揃えるために `LimitCHOP`で値を1にします。
![2021-12-06_23h11_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/41bfe9c1-c048-49b1-8c1f-01412c3fee57.png)
Replicate したそれぞれの item の出力を Merge して `MathCHOP` で `Combine Channels` を `Add` にすると、Premiere のマーカー位置に該当するフレームが1、それ以外は0というものができました。

## [TouchDesigner] 指定のフレームで指定のコメントを出力する
![2021-12-06_23h17_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/2f57a35a-c467-f0f7-f2ec-2876885cf587.png)
`Trim TOP`を使って、現在のフレームだけを取得するようにすると、該当フレームになった時に1を出力してくれます。
![2021-12-06_23h20_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/bbc2ea16-be75-4ce2-7026-8f2652b7f227.png)
毎フレーム毎に先に作った **TableTD** の Description をチェックして、別の `TextDAT` を更新します。ここが更新される前にさきほどの CHOP の値が1になって1つ前の Description が使われてしまうと困るので **0.5s** だけ早めに更新しています（しなくても大丈夫かもしれません。未確認です）。
1つ目の前は **s0**、それ以降は Description にある値を取得するよう以下のようなコードを書いています。

```
frameDelay = project.cookRate / 2
to = op('TableTD')
do = op('Description')

for r in range(1, to.numRows):
	if(val > to[r,0] - frameDelay ):
		do.text = to[r,1]
	elif(val < to[1,0] - frameDelay ):
		do.text = 's0'
```

![2021-12-06_23h27_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/c64b7395-706a-3713-f434-a5bbf86195c0.png)
あとは1が飛んできたタイミングで Description を使って何かするだけです。このサンプルでは単純に `print(シーン名)` していますが、このあたりはお好みでどうぞ。 

## おまけ
おまけとしてサンプルには UI がついています。**reset** ボタンで1フレームに戻る、**frame** スライダーを動かすとフレーム移動となっています。

## おわりに
11/11 の DUSTCELL 3rd ONE-MAN LIVE『自白』にて SOPPY という曲で使って頂いた映像が、このシステムをベースに作ったものになります。その節は関係者の皆さまありがとうございました！
[DUSTCELLが憧れの地・Zepp Tokyoに、新曲も披露された3rdワンマン（ライブレポート / 写真28枚） - 音楽ナタリー](https://natalie.mu/music/news/453760)

それでは引き続き [TouchDesigner Advent Calendar 2021](https://qiita.com/advent-calendar/2021/touchdesigner) をお楽しみください！
ありがとうございました～