Processingのsketch作成から動画出力までをvscodeで完結させる

# 前置き
- Processingで作ったsketchをmp4で出力したい
- 公式IDEのMovieMaker使えば可能だが、GUIでポチポチやるのは面倒くさい
- というかそもそも公式IDEの立ち上げが面倒くさい。
- vscodeでsketch作成から動画出力までやったら楽やん

# この投稿で実現したいこと
- vscodeでsketchを書く
- vscodeでsketchを実行する（pngを出力する）
- vscodeでpngからmp4を生成する
- vscodeで不要になったpngを削除する

# フォルダ構成
この投稿では以下のフォルダ構成を前提とします[^0]

```
C:\Users\Public
  + Documents               # vscodeのワークスペース
    + .vscode
      + tasks.json
    + Processing
      + sketch1
        + sketch1.pde
        + out               # png生成用フォルダ。事前に作成しておく必要はない  + Tools
    + Processing
      + processing-java.exe # Processingに同梱されているexe
    + ffmpeg
      + bin
        + ffmpeg.exe
```

[^0]: 例なので割と不自然な構成です。自身の環境に適宜置き換えてください。また2つのexeに関連するその他のファイル・フォルダは省略しています。

# vscodeでsketchを書く
sketchフォルダをvscodeで開いて普通にコードを書きます。この投稿ではsketch実行時にpngを生成し、それを後工程でmp4に変換します。そのため`draw()`の中に`saveFrame()`を入れておきます。ポイントは以下です。

- 今回はsketchフォルダに`out`というフォルダを作ってpngが保存されるようにします
- Windowsのパス区切り文字`\`がエスケープ文字`\`とかぶるので、エスケープ文字ではなく円マークなのだとわかるよう`\\`とします
- 四桁の数字の連番でpngが生成されるよう`####`を指定します

```sketch1.pde
void draw(){
  saveFrame("out\\####.png"); 
}
```



# vscodeでsketchを実行する
Processingは同梱されている`processing-java.exe`を使うとCLIから実行できるようになります。

```Powershell
C:\Users\Public\Tools\Processing\processing-java.exe --force --sketch="C:\Users\Public\Documents\Processing\sketch1" --run
```

これとvscodeのタスク機能を使って、公式IDEを使わずにsketchを実行できるようにします。

## tasks.jsonを設定する
`Ctrl`+`Shift`+`P` から「タスク：タスクの構成」を実行して`tasks.json`を編集します。

- tasks.jsonの書き方は[Integrate with External Tools via Tasks
](https://go.microsoft.com/fwlink/?LinkId=733558)で解説されています。
- argsの箇所で使っている${fileDirname}など変数については[Variable Reference](https://go.microsoft.com/fwlink/?LinkId=733558)で解説されています

```tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run Processing Sketch", // わかりやすい名前を付ける
      "windows": {
        "command": "C:\\Users\\Public\\Tools\\Processing\\processing-java.exe", // ここのパスはご自身の環境に合わせてください
      },
      "type": "process",
      "args": [
        "--force",
        "--sketch=${fileDirname}", // スケッチのフォルダまで指定する。ファイルは指定しない。
        "--run"
      ],
      "group": {
        "kind": "build", // Ctrl+Shift+Bで実行したい(=楽したい)のでbuildにする
        "isDefault": true
      },
      "presentation": {
        "reveal": "always", // 画面表示を常に行う
        "panel": "new"      // 新しいterminalで実行する
      }
    }
  ]
}
```

## タスクとして実行する
tasks.jsonを設定したうえで、sketch1.pdeを編集中の状態で以下いずれかを実行します。すると、sketchには`saveFrame()`が記述されているのでoutフォルダが作られ、そこに4桁連番のpngが生成されます

- `Ctrl`+`Shift`+`B`
- `Ctrl`+`Shift`+`P` → 「ビルドタスクの実行」

# vscodeでpngからmp4を生成する
前述の通りMovieMakerを使うのは面倒くさいので、processing-java.exeと同じようにCLIから実行できる動画変換ツール`ffmpeg`を使います。[ここ](https://ffmpeg.org/download.html)からダウンロードしておきます

## tasks.jsonを設定する
こちらもvscodeのタスクとして実行できるよう、`tasks.json`に設定を追加します。ポイントは以下の通りです

- `powershell.exe`の`-Command`パラメータに`ffmpeg.exe`を渡す形で実行する[^1]
- `ffmpeg`の設定は以下を参照
  - [ffmpeg Documentation - ffmpeg](https://ffmpeg.org/ffmpeg.html)
  - [ffmpeg Documentation - ffmpeg-all](https://ffmpeg.org/ffmpeg-all.html)

```tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      // processing-java.exeの処理
    },
    {
      "label": "Create mp4 from png", // わかりやすい名前をつける
      "windows": {
        "command": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
      },
      "type": "process",
      "args": [
        "-NoProfile",
        "-Command",
        // ここからffmpeg
        "C:\\Users\\Public\\Tools\\ffmpeg\\bin\\ffmpeg.exe", // ここのパスはご自身の環境に合わせてください
        "-r 30",                            // inputのフレームレート
        "-i ${fileDirname}\\out\\%04d.png", // inputとなるpng。.pdeのsaveFrame()で指定したものと同じpathにする
        "-crf 18",                          // 品質。0-50を指定する。小さいほど品質が高い
        "-vcodec libx264",                  // h.264でエンコード
        "-pix_fmt yuv420p",                 // エンコーダに渡すピクセルフォーマット
        "-r 60",                            // outputのフレームレート
        "${fileDirname}\\out\\out.mp4"
      ],
      "group": "test", // testにする
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}
```

[^1]: `command`に直接`ffmpeg.exe`を指定してもいい気がするが何故かエラーになってしまいそれを解消できていないのでこの形にしている

## タスクとして実行する
tasks.jsonを設定したうえで、sketch1.pdeを編集中の状態で以下を実行するとffmpegが実行され、outフォルダにmp4ファイルが生成されます。

1. `Ctrl`+`Shift`+`P`
2. 「テスト タスクの実行」を実行
3. 「Create mp4 from png」（`tasks.json`で設定したlabelの名前）を選択

# vscodeで不要になったpngを削除する
mp4を生成したらpngはもう不要なのでPowershellの`Remove-Item`で削除します。これも`tasks.json`で設定します。

## tasks.jsonを設定する

- `powershell.exe`の`-Command`パラメータに`Remove-Item`を渡す形で実行する[^2]

```tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      // processing-java.exeの処理
    },
    {
      // ffmpeg.exeの処理
    },
    {
      "label": "Remove png", // わかりやすい名前を付ける
      "type": "process",
      "windows": {
        "command": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
      },
      "args": [
        "-NoProfile",
        "-Command",
        "Remove-Item -Path ${fileDirname}\\out\\*png" // pngの削除
      ],
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}
```

[^2]: `type`を`shell`にして`command`に直接`Remove-Item`を指定してもいい気がするが何故かエラーになってしまいそれを解消できていないのでこの形にしている

## タスクとして実行する
tasks.jsonを設定したうえで、sketch1.pdeを編集中の状態で以下を実行するとoutフォルダにあるpngファイルが削除されます。

1. `Ctrl`+`Shift`+`P`
2. 「テスト タスクの実行」を実行
3. 「Remove png」を選択

# まとめ
- .pdeに`saveFrame()`を書いておく
- `tasks.json`に以下の処理を書く
  - `processing-java.exe`の実行
  - `ffmpeg.exe`の実行
  - `Remove-Item`の実行
- vscodeのコマンドパレット（`Ctrl`+`Shift`+`P`）から、ビルドタスクorテストタスクを実行する

やったー！vscodeだけでmp4出力後のpng削除まで含めて完結したよ！