k.KOUTAROU
SUKAMOTO
← ALL WORKS

CASE STUDY 04 / AI / リアルタイム

会話・声・表情・身体動作を、ひとつの流れにつなぐ。

開発中・未公開Python音声処理RVCOllamaモーション生成VRChat
Miraのロゴ。ピンクと青のグラデーションのクジラ
作品画像

00 / OVERVIEW

この作品について

僕が制作しているAI VTuber「Mira」です。音声での会話、3Dキャラクターの表情と身体動作、ゲーム内の行動をつなぐために、Windows上で動くコントローラーを作っています。現在は開発中・未公開です。

会話、声質変換、モーション生成には既存のモデルや基盤を使っています。僕が実装しているのは、それらをつなぎ、音声が途切れたり、返事より遅れて古い動作が届いたりする問題を扱う部分です。声と身体が同じ会話に参加しているように見せることを目指しています。

SYSTEM MAP / MIRA

聞く・考える・動くを、ひとつの体験へ。

声と演技を並行して動かし、会話のタイミングを揃えています。

01会話の声VOICE
INPUT相手の声を集めるDiscordの参加者音声をミックス
CONVERSATION会話システムに渡す外部の会話システムが返す音声
VOICE CONVERSIONMiraの声に変換RVC → バッファで再生を安定化
OUTPUTDiscordで話す一定間隔で音声を送り出す
02演技と身体ACTING
INPUT発話の内容を読む字幕、またはローカルWhisper
UTTERANCE EVENTひとつの発話に整理字幕の確定待ち・重複の除去
ACTING DECISION演技を判断するOllama:感情・視線・姿勢・身振り
OUTPUT身体と行動へ必要に応じてDiP → VRChat / ゲーム
声と身体をつなぐタイミング制御

口の動きは実際の再生音声から推定。古い動作を捨て、声と演技のずれを抑える。

Miraの処理の流れです。外部モデルをつなぎ、待ち時間や処理中の状態をコントローラーで管理しています。

01 / DESIGN NOTES

一つの発話から、声と演技を動かす

Discord参加者の音声を混ぜて会話システムへ渡し、返ってきた音声をRVCでMiraの声に変換してDiscordへ送ります。RVCは音声の声質を変えるために使っています。字幕かローカルのWhisperによる認識結果から発話イベントを作り、演技やゲーム内の行動にも渡します。

演技の判断にはOllamaを使います。感情、仕草、視線、姿勢、強度、英語の動作プロンプトを決められた形式で受け取り、表情の選択やDiPによる全身モーション生成へつなげます。声と動きが別々の話をしないように、一つの発話を共通の起点にしています。

02 / DESIGN NOTES

不規則に届く音声を、一定の間隔で送る

音声変換の結果はまとまって届くことがありますが、Discordには一定の間隔で送り続ける必要があります。その差を埋めるため、再生前に少し蓄えるプリバッファと、途切れた後に蓄え直す再バッファを用意しています。短い欠落は減衰する音で補い、音声が溜まりすぎたら古い区間を捨てます。

無音も時間として残し、再バッファ中に変換前のマイク音声へ切り替わらないようにしています。また、ストリームが有効でも音声コールバックが止まっている場合は再接続を試みます。同じマイクを複数の経路で開かないように管理する処理も入れました。

BUFFER / 音声の時間を整える

届き方は不規則。聞こえ方はなめらかに。

変換音声の到着まとめて届く・間が空く
蓄えてから再生短い途切れを補間遅延が増えたら古い音声を整理
Discordへの送出一定間隔の音声フレーム
バッファの役割を示した模式図です。蓄え直している間は変換前のマイク音声へ切り替えず、無音を送ります。

03 / DESIGN NOTES

字幕の更新と、新しい指示を区別する

認識途中の字幕は何度も書き換わります。更新のたびに演技を生成しないよう、文字列が安定するまで待ってから推論へ渡します。字幕とWhisperが同じ発話を拾った場合は重複を除きますが、後から同じ指示をもう一度話した場合は、新しい発話として受け付けます。

明示的な動作指示は、自動の演技より優先します。受付後の一定時間は自動モーションで上書きせず、緊急の指示では再生待ちのフレームを捨てます。リクエストIDで結果を照合し、遅れて届いた過去の推論や動作も除外します。今の会話に、前の指示が割り込まないようにするためです。

04 / DESIGN NOTES

短い動作をつなぎ、転送の負荷を抑える

モーション生成のワーカーを常駐させ、前回の生成状態を次へ引き継ぎます。クリップの境界は複数フレームで補間し、生成のたびにニュートラル姿勢へ戻らないようにしています。必要なリセット時だけ導入フレームを挟みます。

生成した22関節の座標はMIDIでVRChat側へ送ります。生成と送信の周期を分け、送信は3フレームに1回にして、通信量と受信イベントの負荷を抑えています。座標の量子化と受信側の補間も使うため、動きがどう見えるかは実機に合わせて調整する必要があります。

MOTION / 動作をつなぐ

動きの生成と転送を、別の時計で。

GENERATE状態を持つDiPワーカー直前の動作から次のクリップへ
BLEND境界をなめらかに接続毎回ニュートラル姿勢に戻さない
TRANSFER22関節 → MIDI3フレームに1回の送信・量子化
RECEIVEVRChatで補間受信側で中間の動きをつなぐ
明示的な動作指示を自動演技より優先。リクエストIDで古い生成結果を除外し、今の発話に合った動作を届けます。

05 / DESIGN NOTES

再生される声から、口の形を求める

口パクは字幕の時刻だけに合わせず、実際の音声を分析して動かします。LPC分析で音声の特徴を取り出し、日本語の五母音を簡易的に推定します。値をなめらかにし、境界付近で口形が細かく切り替わらないようにする処理と、第二候補を少し混ぜる処理も入れています。

表情は、最初に決めた感情から小さな変化や仕草を展開し、毎回推論を追加せずに演技を続けます。ゲームとの連携では、セッションの開始、状態確認、停止、結果の回収を管理しています。会話・声・身体・行動で異なる時間の進み方を揃えることが、この開発で取り組んでいる課題です。

REFERENCE

関連リンク・公開情報

開発中の作品です。公開パッケージはありません。

NEXT CASE STUDY

EasyInventorySystem ↗