Help us understand the problem. What is going on with this article?

録音した音声ファイルからリップシンクを行う

More than 1 year has passed since last update.

はじめに

リップシンクにはOVRLipsyncを用います。本来、マイクの入力からによるリアルタイムリップシンクが想定されていますが、既に録音してある音声ファイルからリップシンクを行うようにします。


記事中にある僕の書いたソースコードはパブリックドメインとします。

使い時

歌のMV収録なんかするときに便利です。毎回歌わないで済みます。
また、直接音声を流し込めるのでリップシンクの動作テストにおいても便利です。声質によってリップシンクの値は変わるので、ちゃんと本人の声でパラメータ調整をしましょう

動作環境

セットアップ

1.OVRLipsyncセットアップ

何らかのモデルを配置し、OVRLipsyncが正常に動作するようにします。こちらのセットアップにおいては「Unity でリップシンクができる OVRLipSync を試してみた」がとても参考になります。
セットアップが終了し、以下のようにAudioSource,OVRLipSync,OVRLipSyncContextMorphTarget,OVRLipSyncContext,OVRLipSyncMicInputのコンポーネントがシーン内存在しているとして進めていきます。本記事のモデルと音声ファイルは、ユニティちゃんに含まれるものを利用しています。
image.png

2.マイク無効化

OVRLipSyncMicInputがマイクの入力を受け取り、その音声をAudioSourceに渡します。今回はマイク入力が必要ではないので、このOVRLipSyncMicInputを非アクティブにしてしまうか、コンポーネントから外します。
image.png

3.AudioSourceに音声セット

AudioSourceのAudioClipにリップシンクをさせたい音声ファイルをセットします。

キャプチャ2.png

以上です。これで再生すると音声ファイルからリップシンクが行われます。

4.拡張:スライダーで自由タイミング再生

セリフ一部分だけとか、Aメロ部分だけ再生したいとかあるので、スライダーで好きなタイミングから再生できるものも作りました。以下がソースコードです。

AudioController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioController : MonoBehaviour {

    public AudioSource audioSource;
    public float AudioTimeNow = 0.0f;
    public float AudioFullLength;
    public bool Stop = false;
    private AudioClip audioClip;

    void Start () {
        if(!audioSource){
            Debug.LogWarning("AudioSourceがセットされていません");
            return;
        }
        if(!audioSource.clip){
            Debug.LogWarning("AudioClipがセットされていません");
            return;
        }
        audioClip = audioSource.clip;
        AudioFullLength = audioClip.length;
    }

    void Update () {
        if(!audioSource){
            Debug.LogWarning("AudioSourceがセットされていません");
            return;
        }
        if(Stop){
            if(audioSource.isPlaying){
                audioSource.Pause();
            }
            return;
        }else{
            if(!audioSource.isPlaying){
                audioSource.UnPause();
            }
        }
        AudioTimeNow = audioSource.time;
    }

    private void OnValidate(){
        audioSource.time = AudioTimeNow;
    }
}
AudioControllerEditor.cs
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(AudioController))]
public class AudioControllerEditor : Editor {

    public override void OnInspectorGUI()
    {
        var audioController = target as AudioController;
        // -- 再生時間 --
        EditorGUILayout.LabelField( "再生時間(最小/現在時間/最大)" );
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.FloatField(0, GUILayout.Width(48) );
        audioController.audioSource.time = EditorGUILayout.Slider(audioController.audioSource.time, 0f, audioController.AudioFullLength);
        EditorGUILayout.FloatField(audioController.AudioFullLength, GUILayout.Width(48) );
        EditorGUILayout.EndHorizontal();
        // --   一時停止 --
        EditorGUILayout.LabelField( "一時停止" );
        audioController.Stop = EditorGUILayout.Toggle(audioController.Stop);
    }
}

上記のスクリプトを作成し、アタッチすることで以下の動画のように音声を早送りしたり途中から始めたりできるようになります。


注意

OVRLipsyncは機械学習ベースで動いているため、音声に雑音が混ざっていると反応が悪くなります。なので、歌も楽器や曲の音が入っているとリップシンクの精度が著しく落ちてしまいます。歌のみの音源も録音しておき、リップシンクにはそちらの音源を利用しましょう

"OVRLipSyncContext"のAudioLoopBackをアクティブにすると再生音声が聞こえるようになります。こちらをアクティブにしておくとリップシンクの確認が行いやすいです。

"AudioSource"のPlayOnAwakeがアクティブになっているとUnity再生時に自動で音も再生されます。音が鳴らない時もこちらを確認すると良いでしょう。

imageLicenseLogo.png
本記事はユニティちゃんライセンス条項の元に提供されています

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away