🦔

VOICEVOX Core v0.16.0 で俳句読み上げ動画を作る

に公開

はじめに

前回の記事(VOICEVOX Core を Python で扱う基本)では、VOICEVOX Core の Python バインディングを使って、テキストから音声を生成する方法を紹介しました。今回はその続編として、5・7・5 の俳句をずんだもんに読み上げてもらい、背景画像とともに動画を生成する CLI ベースのワークフローを紹介します。

なお、使用するバージョンは VOICEVOX Core v0.16.0 です。開発版では非同期処理の仕様変更が進んでいるため、安定したバージョンでの確認が目的です。

必要なツールのインストール

ディレクトリ構成(v0.16.0 想定)

以下のような構成でファイルを配置していることを前提とします:

project_root/
├── run.py                         # VOICEVOX Core 同梱のCLIスクリプト
├── models/
│   └── 0.vvm                     # ずんだもんの音声モデル
├── voicevox_core/
│   ├── c_api/
│   │   └── lib/                  # libvoicevox_core.so など
│   ├── onnxruntime/
│   │   └── lib/libvoicevox_onnxruntime.so.1.17.3
│   └── dict/open_jtalk_dic_utf_8-1.11/
└── say.py                        # ラッパースクリプト(後述)

環境変数の設定(毎回の実行前に):

export LD_LIBRARY_PATH=./voicevox_core/c_api/lib

音声の連結と動画の生成

音声の連結、画像と音声ファイルから動画を生成するために ffmpeg をインストールします。

sudo apt install ffmpeg

ffmpeg の代わりに Python モジュールを使った処理をしたい場合、moviepy をインストールします。moviepy は ffmpeg に依存します。今回はチュートリアルの分量が多いので紹介だけにとどめておきます。

画像生成用ツール(ImageMagick と日本語フォント)

sudo apt install imagemagick fonts-ipaexfont

ImageMagick がインストール済みであれば、convert コマンドで利用可能なフォント一覧を確認できます:

convert -list font | grep -i ipa

この出力に IPAexGothic や IPAexMincho が含まれていれば準備完了です。

画像ビューア(feh がおすすめ)

生成した画像を確認するために軽量ビューア feh を使います。

sudo apt install feh

他にも sxiv や ImageMagick の display があります:

sudo apt install sxiv
sudo apt install imagemagick  # display コマンドも含まれる

表示例:

feh haiku.png

feh は日本語フォントの表示も正しく、画像確認に最も適しています。

音声再生

ターミナルから音声を再生するために aplay をインストールします。

sudo apt install alsa-utils

動画再生

ターミナルから動画を再生するために mpv をインストールします。

sudo apt install mpv

Chromebook の場合、標準の動画再生プレイヤーを使うこともできます。フォルダアプリから Linux ディレクトリを開き、動画のある場所まで移動してダブルクリックすれば再生されます。

俳句の構成と音声分割

例となる俳句:

春の風
そよぐたんぽぽ
笑いけり

これを 5・7・5 の3句に分け、それぞれ別の .wav ファイルとして出力します。

VOICEVOX Core v0.16.0 以降では VoicevoxCore.tts() は利用できなくなっているため、同梱の run.py を用いた CLI 音声生成に切り替える必要があります。

まず、以下のように1句ずつ音声ファイルを生成します(ずんだもん:style-id=3):

export LD_LIBRARY_PATH=./voicevox_core/c_api/lib
uv run python run.py ./models/0.vvm \
  --style-id 3 \
  --dict-dir ./voicevox_core/dict/open_jtalk_dic_utf_8-1.11 \
  --onnxruntime ./voicevox_core/onnxruntime/lib/libvoicevox_onnxruntime.so.1.17.3 \
  --text "春の風" \
  --out haiku_1.wav
uv run python run.py ./models/0.vvm \
  --style-id 3 \
  --dict-dir ./voicevox_core/dict/open_jtalk_dic_utf_8-1.11 \
  --onnxruntime ./voicevox_core/onnxruntime/lib/libvoicevox_onnxruntime.so.1.17.3 \
  --text "そよぐたんぽぽ" \
  --out haiku_2.wav
uv run python run.py ./models/0.vvm \
  --style-id 3 \
  --dict-dir ./voicevox_core/dict/open_jtalk_dic_utf_8-1.11 \
  --onnxruntime ./voicevox_core/onnxruntime/lib/libvoicevox_onnxruntime.so.1.17.3 \
  --text "笑いけり" \
  --out haiku_3.wav

※ 上記の複雑なコマンドを毎回書かずに済むよう、以下の say.py を使用するのがおすすめです。

say.py:run.py を簡単に使うためのラッパー

毎回 run.py に長い引数を渡すのは面倒なので、設定済みのパスを使ってコマンドを簡略化する Python スクリプトを作成します。

以下は say.py の中身です:

import subprocess
import sys
from pathlib import Path

#各種設定(環境に合わせて編集)
VVM_PATH = Path("./models/0.vvm")
DICT_PATH = Path("./voicevox_core/dict/open_jtalk_dic_utf_8-1.11")
ONNX_PATH = Path("./voicevox_core/onnxruntime/lib/libvoicevox_onnxruntime.so.1.17.3")
STYLE_ID = 3  # ずんだもん(通常)
RUN_SCRIPT = Path("./run.py")

def main():
    if len(sys.argv) != 3:
        print("使い方: uv run python say.py 出力.wav \"テキスト\"")
        sys.exit(1)

    out_path = Path(sys.argv[1])
    text = sys.argv[2]

    cmd = [
        "uv", "run", "python", str(RUN_SCRIPT), str(VVM_PATH),
        "--onnxruntime", str(ONNX_PATH),
        "--dict-dir", str(DICT_PATH),
        "--style-id", str(STYLE_ID),
        "--text", text,
        "--out", str(out_path)
    ]

    subprocess.run(cmd, check=True)

if __name__ == "__main__":
    main()

実行例

export LD_LIBRARY_PATH=./voicevox_core/c_api/lib
uv run python say.py haiku_1.wav "春の風"
uv run python say.py haiku_2.wav "そよぐたんぽぽ"
uv run python say.py haiku_3.wav "笑いけり"

これで、簡潔なコマンドで .wav ファイルを生成できるようになります。

音声ファイルの連結とバッチ処理

say.py で音声ファイルを生成し、ffmpeg で連結する処理を行います。句と句の間を開けるため、無音ファイルを挿入します。

ffmpeg のみで無音挿入+連結を行う場合は、以下のような手順で concat 用リストファイルを用いる方法が安定です("concat:file1|file2|file3" 形式は .wav では正常に動作しない場合があります)。

generate_haiku.sh
#!/bin/bash
set -e

# 出力先ファイル名
OUT_FILE="haiku_combined.wav"

# 各句(5・7・5)
PHRASES=("春の風" "そよぐたんぽぽ" "笑いけり")

# 音声ファイル名
FILES=()

# ステップ1: 各句を say.py で音声化
for i in "${!PHRASES[@]}"; do
  index=$((i + 1))
  wav_file="haiku_${index}.wav"
  uv run python say.py "$wav_file" "${PHRASES[$i]}"
  FILES+=("$wav_file")
done

# ステップ2: 無音 pause.wav(700ms)を生成
if [ ! -f pause.wav ]; then
  ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=mono -t 0.7 -q:a 9 pause.wav
fi

# ステップ3: concat用リストを作成
echo "file '${FILES[0]}'" > haiku_list.txt
echo "file 'pause.wav'"   >> haiku_list.txt
echo "file '${FILES[1]}'" >> haiku_list.txt
echo "file 'pause.wav'"   >> haiku_list.txt
echo "file '${FILES[2]}'" >> haiku_list.txt

# ステップ4: 連結
ffmpeg -y -f concat -safe 0 -i haiku_list.txt -c copy "$OUT_FILE"

echo "生成完了: $OUT_FILE"
chmod +x generate_haiku.sh

Bash スクリプトを実行します。

./generate_haiku.sh

背景画像の生成(ImageMagick)

背景を単色で作る:

convert -size 1080x1920 canvas:"#FFDD88" background.png

俳句を画像にする:

方法A:フォントファイルを直接指定

convert -size 1080x1920 xc:white -gravity center \
  -font /usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf \
  -pointsize 64 -annotate 0 "春の風\nそよぐたんぽぽ\n笑いけり" haiku.png

方法B:-font IPAexGothic として指定(convert -list font で確認済みの場合)

convert -size 1080x1920 xc:white -gravity center \
  -font IPAexGothic \
  -pointsize 64 -annotate 0 "春の風\nそよぐたんぽぽ\n笑いけり" haiku.png

環境によっては B の指定方法でうまくいかない場合があるため、確実な方法としては A の .ttf ファイルをフルパスで指定する方法がおすすめです。

ImageMagick で生成されたテキスト描写の画像を扱う場合、メタ情報やチャンク構造が原因でほかのツール(Python の Pillow や moviepy など)がバグを起こす可能性があります。問題に遭遇したら別の方法で画像生成を試すことをおすすめします。

動画の生成(ffmpeg)

音声ファイルと背景画像から ffmpeg で動画を生成します。サイズは YouTube ショート動画を想定しています。

ffmpeg -loop 1 -i haiku.png -i haiku_combined.wav \
  -c:v libx264 -tune stillimage \
  -c:a aac -b:a 192k \
  -pix_fmt yuv420p -shortest \
  -vf "scale=1080:1920" \
  haiku_short.mp4

オプション解説です。

動画が正常に生成されているか再生して確認します。

mpv haiku_short.mp4

いろいろなエラーメッセージを消すには次のオプションを指定します。

mpv --vo=x11 --hwdec=no haiku_video.mp4

Chromebook の場合、標準の動画再生プレイヤーを使うことができます。ファイルアプリから Linux ディレクトリを開き、動画のある場所まで移動します。


補足:HTTP サーバー版で読み上げ速度を調整する

Python バインディングでは読み上げ速度を直接変更できませんが、HTTP サーバー版(VOICEVOX ENGINE)を使えば speedScale を指定できます。

curl -s -X POST "http://localhost:50021/audio_query?speaker=1" \
     -d "text=春の風" -o query.json
# 編集: query.json の "speedScale": 0.9 に変更

curl -s -X POST "http://localhost:50021/synthesis?speaker=1" \
     -H "Content-Type: application/json" \
     -d @query.json -o haiku_1.wav

おわりに

これまでの手順を通じて、以下のような一連のワークフローを構築できました:

  1. say.py を使って、3つの俳句の句をずんだもんの音声で .wav に出力
  2. generate_haiku.sh により、句と句のあいだに無音ファイルを挿入し、音声ファイルを連結
  3. convert と feh を用いて背景画像を作成・確認
  4. ffmpeg により画像と音声を結合し、YouTube ショート向けの .mp4 を生成

これにより、ChatGPTで生成した俳句テキストから、CLIだけで動画化まで自動化することが可能になります。

今後は、以下のような拡張が考えられます:

  • キャラやスタイルの切り替えによる対話型動画の制作
  • JSON/TOML による台本の管理とスクリプト化
  • 字幕や画像の動きを含めた簡易アニメーションの追加

まずはシンプルな俳句動画からスタートし、段階的に自動生成の幅を広げていきましょう。

本記事では、VOICEVOX Core v0.16.0 の Python バインディングを用いた俳句読み上げ動画の作成方法を紹介しました。読み手や句を増やすことで、複数キャラのかけあい動画や短い朗読作品にも応用できます。

今後は JSON/TOML 形式での台本入力や、字幕付き動画への発展も検討したいと思います。

Discussion