はじめに
uLipSync では AudioClip やマイクから得た音声を解析するモジュールと、その解析結果を受け取りリップシンクを動作させるためのコンポーネントが分かれています。
この解析結果を受け取る部分を自作することで色々と遊ぶことができるので、本記事ではそのやり方をご紹介します。
導入
いくつか方法はありますが、Package Manager から次の URL を Add package from git URL... するのが簡単だと思います。
https://github.com/hecomi/uLipSync.git#upm
直接 .unitypackage を導入する場合は Package Manager から Unity.Mathematics
や Unity.Burst
の導入を忘れずにおこなって下さい。その他基本的な概念や機能説明は、必要に応じて以下の記事をご参照下さい。
解析結果を受け取る手順
uLipSync コンポーネントを追加
まず適当な GameObject を作成し、uLipSync
コンポーネントをアタッチします。
uLipSync
コンポーネントの Profile に何かしらの Profile オブジェクトを指定します。Profile の作成の仕方は解説記事に載せていますが、ひとまずはパッケージに含まれているサンプル(uLipSync-Profile-Sample など)を指定すると動きます。
解析結果を受け取るコンポーネントの作成
次のようなコンポーネントを作ります。
using UnityEngine; public class CustomLipSyncEventHandler : MonoBehaviour { public void OnLipSyncUpdate(uLipSync.LipSyncInfo info) { if (info.volume < Mathf.Epsilon) return; Debug.LogFormat($"PHENOME: {info.phoneme}, VOL: {info.volume} "); } }
そして、これを任意の GameObject にアタッチします。次にこのイベントハンドラを uLipSync
に登録します。On Lip Sync Update (LipSyncInfo) で + ボタンを押し、イベントを追加、ここに先程の GameObject を指定してプルダウンリストから該当のイベントを選択します。
これで登録完了です。
AudioClip またはマイクコンポーネントの追加
マイクで喋る場合は、uLipSyncMicrophone
コンポーネントを uLipSync
と同じ GameObject にアタッチしておきます。
実行
実行してマイクに喋ると次のように認識された母音とボリュームが表示されます(AudioClip の場合はその音に応じたものが表示されます)。
渡ってくる情報
イベントに渡ってくる LipSyncInfo
の中身は次のようになっています。
public struct LipSyncInfo { // 認識された音素 public string phoneme; // ボリューム(0 ~ 1) public float volume; // ボリュームの生値 public float rawVolume; // 登録された音素と含まれる割合のテーブル(A が 80%、I が 20% など) public Dictionary<string, float> phonemeRatios; }
rawVolume
は RMS(Root Mean Square)ボリュームで、各サンプルの二乗和の平方根なので、比較的小さな値が出てきます。そのため、デシベル空間で適当な扱いやすい値に変更したものを volume
として返しています。より拘りたい方は、rawVolume
を使ってみて下さい。なお uLipSyncBlendShape
などのコンポーネントでは、そのコンポーネント内でこのデシベル空間での最小 / 最大値を調整できるようにし、rawVolume
を使って計算しています。
試しになにか作ってみる
それでは試しに phonemeRatios
を活用して、認識した音を使ってオブジェクトのカラーを変えるコンポーネントを作ってみます。
using UnityEngine; using System.Collections.Generic; public class CustomLipSyncEventHandler : MonoBehaviour { [System.Serializable] public struct PhonemeColor { public string phoneme; public Color color; } [SerializeField] List<PhonemeColor> phonemeColors; [SerializeField, Range(0.01f, 1f)] float minVolume = 0.2f; [SerializeField, Range(0f, 1f)] float smooth = 0.7f; [SerializeField] Renderer targetRenderer = null; Material _mat; Color _color; void Start() { if (!targetRenderer) return; _mat = targetRenderer.material; } void LateUpdate() { _mat.color += (_color - _mat.color) * (1f - smooth); } public void OnLipSyncUpdate(uLipSync.LipSyncInfo info) { if (!_mat) return; var color = Color.clear; foreach (var pc in phonemeColors) { float ratio = info.phonemeRatios.GetValueOrDefault(pc.phoneme, 0f); color += ratio * pc.color; } var volume = Mathf.Min(info.volume / minVolume, 1f); _color = color * volume + Color.white * (1f - volume); Debug.Log($"<color=\"#{ColorUtility.ToHtmlStringRGB(_color)}\">■</color> ({volume})"); } }
予め登録した音素が、認識した音素にどれくらい入っているかを見て色をブレンドし、指定した Renderer
コンポーネントのマテリアルのカラーを上書きしています。このコンポーネントを適当なオブジェクトにアタッチしたあと、先程と同じように uLipSync
コンポーネントに登録し、次のようにセットアップします。
実行すると次のようになります。
喋った音に応じてオブジェクトの色が変わりました。あとは色々とアイディア次第で面白いものが作れるかもしれません。
おわりに
正確に音を取らないと行けないようなユースケースでは、現状の解析法では外乱に弱いのでいまいちですが、間違っても大丈夫な賑やかしに使いたいようなケースでは面白い使い途が色々あるかもしれません。
余談
先日、VTube Studio さんが uLipSync を音声を使ったリップシンク向けの機能として採用して下さいました。
【📢】 #VTubeStudio v1.27.5 is now released!! (Windows/macOS/Android/iOS)
— VTube Studio (@VTubeStudio) 2023年9月23日
Added advanced lipsync 🎤 ( uLipSync by @hecomi ), support for Live2D 5.0 and a cute Twitch chat scroll overlay thingy ✨
🧵👇 pic.twitter.com/WInNWCBxBP
v3 から追加した UI のための API も使ってくださっていて、キャリブレーションの機構も搭載されています!カメラによるトラッキングではない場合に威力を発揮すると思います。VTube Studio をお使いの方はぜひお試し下さい。