前回(第10回)は、VOICEVOXの抑揚をaudio_queryという中間表現に切り出し、生成と合成を分離した4月の話だった。JSONを挟むことで「読み上げてみないと分からない」問題に手を打った回だ。今回はその翌月、2026年5月に入る。テーマは一貫して速さ——動画生成のパイプラインを軽くし、確認サイクルを短くし、最後にはPythonの外にエンジンそのものを持ち出すところまで進む。
しゃべりの演技指定と、それを活かす仕組み
月初、5月4日の朝には別の下地作りが入っている。ad0da81「performance marker extraction」で、台本中に 【困惑気味に】 のような全角鉤括弧の演技指定を書けるようにする performance_markers.py が追加された。空の 【】 は「標準に戻す」リセット記号として扱う設計だ。同日中に 1f66f9e でサンプルの justfile にもマーカー抽出タスクが足され、リンターにもチェックが入る。
このマーカーが本当に効いてくるのは9日後の5月13日、8c05f02「performance tuning registry」でだ。performance_tuning.py は、performance_markers.json でマーカーの出現位置を突き合わせながら、performance_tuning.json に書いた調整値をAudioQueryのJSONへ適用する。つまり「ここは困惑気味に」という指定に対して、ピッチや話速のパラメータを後から差し込める仕組みになっている。5月29日には 252946b で、この照合が _processed_text(置換辞書適用後のテキスト)ではなく _original_text を優先するよう修正されている。正規表現や辞書置換で台本の見た目が変わっても、マーカーとの対応がズレないようにするための地味だが必要な直し方だ。
動画パイプラインを一回のffmpeg呼び出しに畳む
5月24日、動画生成まわりに大きな手が入る。b241573「動画生成パイプラインを単一パス実装に切替」と、それに続く 67164c9「単一パス動画オーバーレイ実装 + 解像度設定外部化」のマージだ。新設された video_single_pass_overlay.py は321行、対応するテストは単体テスト426行・結合テスト293行と、実装本体より検証コードの方が厚い。狙いは、それまで複数回に分かれていたffmpeg呼び出し(下地の合成→オーバーレイ→トランジションといった多段処理)を、フィルタグラフを組み立てて一回のエンコードで済ませる方向へ寄せることにある。エンコードは重い処理なので、通す回数そのものを減らすのが速度への一番効くレバーになる。
同じ日の17時38分、54e5ac5「–preview-video モードを追加」。480p・15fps・ultrafastプリセット・VideoToolbox品質60という低品質設定一式を PREVIEW_VIDEO_CONFIG にまとめておき、--preview-video オプションを立てるとこの設定を丸ごと差し替えて preview.mp4 を書き出す。本番相当の設定を一切いじらずに、確認用の軽い動画だけ別出力できるようにする作りだ。コミットメッセージには「preview.wav → preview.mp4 のファイル名バグを修正」の一言も添えられている。5分後の afe8f21 でこの機能がマージされ、単一パス化と同日にリリースされたことになる。
Swiftエンジンという新しい選択肢
そして5月28日、これまでとは毛色の違うコミットが入る。18時37分 3610163「S1-12 video_flow.py への Swift エンジン統合」で _detect_swift_engine()(PATHやリポジトリ内からバイナリを探す)と _run_swift_engine()(subprocess.run で起動し、非ゼロ終了なら例外を投げる)が実装された。3時間半ほど後の22時20分、5d31405が同じS1-12というID名で video_flow.py に108行を追加し、generate_video_from_audio_with_final_audio() の先頭でまずSwiftエンジンを試み、失敗すれば既存のffmpegパイプラインへフォールバックする経路を組んでいる。テストも11件追加され、「動く・動かないの両方」を検証した形跡がある。
翌29日未明の 756020b では PD2_NO_SWIFT_ENGINE=1 という環境変数で明示的に無効化できる逃げ道が足され、30日昼の ff4bcb0 で「Swift GPU エンジンをオプトイン方式に変更」。つまり、新しい実行経路をいきなりデフォルトにするのではなく、まず存在すれば試す→ダメならフォールバック→それも嫌なら環境変数で切る、という慎重な導入順序を踏んでいる。31日には 40b449d(pd2-engine-subtitle 対応へのエンジン検索拡張)と aa746e5(Swift経路への字幕・パネル統合)が続き、17時09分の 0e28f74「Swift GPU エンジンソースを main に取り込み」でようやくエンジン本体のソースコードがリポジトリに合流する。統合コード(呼び出し側)を先に書いて検証し、その後でエンジン本体を取り込む——今回追った範囲では、そういう順番で進んでいたことが読み取れる。
なぜSwiftだったのか
Swift導入の動機は、コード側からだけでは見えてこない部分がある。動画の生成にかかる時間が伸び続け、CPUを使い切ってしまう状態が常態化していたことが背景にある。原稿を準備してから書き出しまで30分以上かかるのはさすがに厳しく、GPUを使う方向に倒せないかと考えたときに、「Appleの環境ならSwiftでできるのでは」という思いつきがそもそもの出発点だったという。正式に動くまでには相応の時間がかかったが、いざ稼働し始めると所要時間はおよそ1/3程度まで縮んだ。ここまで追ってきた検出→フォールバック→オプトインという慎重な導入順序は、そうして得られた効果を安全に手元へ引き寄せるための手順だったとも言える。
見えてくるもの
5月のこの一連の流れは、パフォーマンス演技指定→調整レジストリという「表現の細かさ」を担保する仕組みと、単一パス化・プレビューモード・Swiftエンジンという「速さ」を担保する仕組みが、同じ月の中で並行して積まれていたのが印象的だった。しかもSwiftエンジンの導入は、いきなり置き換えるのではなく検出→フォールバック→オプトインという石橋の叩き方をしている。ここまでPythonの中で完結していた処理の一部が、初めて言語の外に出ていった回として覚えておきたい。