AIで作る業務動画 Day 7|日本語音声でリップシンクJSONを生成する
今日のゴール
Rhubarb Lip Syncで日本語音声からリップシンクデータ(JSON)を生成して、実用レベルの精度が出るか検証する。
Day 6でRhubarbをインストールして英語音声では動いた。今日は本番環境で使う日本語音声で試す。
正直、Rhubarbは英語向けに作られているので、日本語でどこまで使えるか不安があった。
phonetic modeとは
Rhubarbには2つの認識エンジンがある。
| エンジン | 方式 | 対応言語 |
|---|---|---|
| PocketSphinx | 単語ベース | 英語のみ |
| Phonetic | 音素ベース | 言語非依存 |
日本語音声にはphonetic modeを使う。
phonetic modeは「単語」ではなく「音素」(個々の発音)を認識する方式で、言語に依存しない。開発者によると、イタリア語などの非英語でも「英語の音素に似ている部分」を認識できるとのこと。
コマンドは-r phoneticオプションを付けるだけ。
rhubarb -r phonetic -f json -o output.json input.wav
前提条件
- Rhubarb Lip Sync v1.14.0がインストール済み(Day 6)
- Gemini TTSで生成した日本語音声ファイル(Day 3-5)
手順
Step 1: テスト用音声の準備
Day 3-5で生成した7つの音声ファイルをテストに使う。
| ファイル | 音声長 | 内容 |
|---|---|---|
| keigo_01.wav | 4.13秒 | 敬語テスト |
| kougo_01.wav | 4.41秒 | 口語テスト |
| kanji_01.wav | 2.45秒 | 漢字テスト |
| choubun_01.wav | 15.01秒 | 長文テスト |
| voice_kore.wav | 4.81秒 | Koreボイス |
| day04_combined.wav | 41.55秒 | 掛け合い音声 |
| day05_combined.wav | 41.07秒 | 統合スクリプト出力 |
Step 2: リップシンクJSON生成
phonetic modeで実行する。
rhubarb -r phonetic -f json -o keigo_01.json keigo_01.wav
出力例:
Application startup. Input file: keigo_01.wav
Progress: Processing audio file...
Progress: Done.
全7ファイルで実行した結果:
| ファイル | 音声長 | キュー数 | キュー/秒 | 使用Shape | 結果 |
|---|---|---|---|---|---|
| keigo_01 | 4.13秒 | 31 | 7.5 | 7種類 | 成功 |
| kougo_01 | 4.41秒 | 32 | 7.3 | 6種類 | 成功 |
| kanji_01 | 2.45秒 | 19 | 7.8 | 6種類 | 成功 |
| choubun_01 | 15.01秒 | 106 | 7.1 | 9種類 | 成功 |
| voice_kore | 4.81秒 | 32 | 6.7 | 9種類 | 成功 |
| day04_combined | 41.55秒 | 279 | 6.7 | 9種類 | 成功 |
| day05_combined | 41.07秒 | 267 | 6.5 | 9種類 | 成功 |
全テスト成功率: 100%
キュー/秒は平均7前後。日本語の標準的な発話速度(6-8音素/秒)と概ね一致しており、口の動きが自然なペースで検出されている。
Step 3: JSONの構造確認
JSONが生成できたので、中身をサンプリングで確認した。
keigo_01.jsonの冒頭部分:
{ "start": 0.00, "end": 0.15, "value": "X" }, // 発話前の無音
{ "start": 0.15, "end": 0.26, "value": "A" }, // 開口
{ "start": 0.26, "end": 0.37, "value": "B" }, // 閉口
...
{ "start": 3.96, "end": 4.13, "value": "X" } // 発話後の無音
確認できたこと:
| 観点 | 結果 |
|---|---|
| start/endの連続性 | ギャップなし、正常 |
| 無音区間の検出 | 先頭・末尾にX(無音)が出現 |
| キュー密度 | 平均7キュー/秒(日本語の発話速度と一致) |
実際に口パクが自然に見えるかは、動画を作成してから目視で確認する予定(Day 9の統合テストで実施)。
現時点での判断:
- キュー密度が妥当なので、口の動きが速すぎ/遅すぎにはならないはず
- 無音区間が適切に検出されているので、話していないときは口が閉じるはず
- ただしRhubarbは英語音素ベースなので、日本語母音の厳密なマッピングは期待できない
アニメの口パクで重要なのは「口が動いているか」であって、言語学的な正確さではない。視覚的に違和感がなければ問題ないはずだが、これは動画を作ってから判断する。
Step 4: JSON出力仕様の確定
生成されたJSONを見ると、RhubarbはA〜H、Xの9種類の口形状を出力している。
{
"metadata": {
"soundFile": "keigo_01.wav",
"duration": 4.13
},
"mouthCues": [
{ "start": 0.00, "end": 0.15, "value": "X" },
{ "start": 0.15, "end": 0.26, "value": "A" },
{ "start": 0.26, "end": 0.37, "value": "B" },
...
]
}
9種類のうち、G(歯を閉じた口)とH(舌を見せる口)は英語の"L"音などで使われる形で、日本語ではほぼ出現しない。Xは無音区間を示す。
そこで、口パク画像は基本の6種類(A〜F)だけ用意して、G・H・Xは近い形にマッピングする方針にした。
| Rhubarb出力 | 使用する画像 | 理由 |
|---|---|---|
| A〜F | そのまま | 基本形状 |
| G | B | 閉じた口に近い |
| H | C | やや開いた口に近い |
| X | A | 無音なので閉じた口 |
Rhubarbの--extendedShapes ""オプションで出力を6種類に制限する方法もあるが、認識精度に影響する可能性があるため採用しなかった。生データを残しておいて、Remotion側で正規化する方が柔軟性がある。
動作確認チェックリスト
| 確認項目 | 結果 |
|---|---|
| phonetic modeでJSONが生成される | 達成 |
| 日本語音声でエラーが出ない | 達成(7ファイル全て成功) |
| mouthCues配列にキューが含まれる | 達成 |
| キュー密度が妥当(6-8/秒) | 達成(平均7/秒) |
| 視覚的に自然か | Day 9で確認予定 |
うまくいかない場合
| 症状 | 原因 | 対処 |
|---|---|---|
| 「Cannot read audio file」 | 対応形式外 | WAV/OGG形式に変換 |
| キューがほぼ「X」のみ | 無音が多い/音量が小さい | 音声ファイルを確認 |
| 処理が終わらない | ファイルが大きすぎる |
--threadsオプションで並列化 |
今日の成果物
- 日本語音声7ファイルのリップシンクJSON(全て正常生成)
- JSON構造の確認完了(キュー密度、無音検出が妥当)
- JSON出力仕様: 9形状 → 6形状にフォールバック
検証環境
| 項目 | バージョン |
|---|---|
| OS | Windows 11 Pro |
| Rhubarb Lip Sync | 1.14.0 |
| テスト音声 | Gemini TTS生成(Day 3-5) |
| 検証日 | 2026-01-07 |
明日のテーマ: Rhubarbの口パクデータ(mouthCues)が何を意味するか深掘りする。A〜Xの各形状が日本語のどの発音に対応するかをまとめて、Remotionで使えるマッピング表を作成する。
シリーズを追いかける
Discussion