【Unity】VoiceVoxに音声合成してもらってAudioClipとして取得して再生する方法

今回は勉強のために VoiceVoxに音声合成してもらってAudioClipとして取得して再生する コードを書いてみました。

環境

VoiceVoxサーバは ローカルの50021ポートで動作しています。 (VOICEVOXのソフトを起動するとサーバも起動します。)

VoiceVoxのAPI

VoiceVoxのAPIで行う処理としては2段階にわかれます。

音声合成用のクエリを作成する

VoiceVoxサーバにテキストを投げて、音声合成用のクエリを作成してもらう処理です。
問い合わせ先
http://localhost:50021/audio_query
引数
text(string) 音声に変換したい文字列
speaker(integer) 話者ID
メソッド POST
http://localhost:50021/audio_query?text="こんにちは"&speaker=8

音声合成する

①で受け取ったクエリをそのまま投げて音声合成してもらう処理です。
問い合わせ先
http://localhost:50021/synthesis
引数
speaker(integer) 話者ID
メソッド POST
BODYに受け取ったクエリを渡す(application/json
http://localhost:50021/synthesis?speaker=8

VoiceVoxManager クラス

今回作成したクラスのコードの概要は下記の通りです。

概要

VoiceVoxManagerクラスはVoiceVoxサーバを利用し、テキストから音声合成を行うためのクラスです。このクラスを利用することで、任意のテキストを音声化し、その音声をアプリケーション内で再生することが可能になります。

プロパティ

AudioClip AudioClip:
AudioClip形式で保持された音声データを返すプロパティです。このプロパティは読み取り専用です。

メソッド

async UniTask<byte[]> GetQuery(string text, int speakerId):
VoiceVoxサーバにテキストを投げて、音声合成用のクエリを作成します。作成されたクエリはbyte配列で返されます。 このメソッドはプライベートメソッドなので使うのは下記のDownloadAudioClipになります。

async UniTask DownloadAudioClip(string text, int speakerId):
クエリを投げて音声合成を行います。結果のAudioClipはプライベートフィールドである_audioClipに格納され、公開プロパティAudioClipを通じて取得することが可能です。 このメソッドも非同期であり、音声のダウンロードに時間がかかる可能性があるため、awaitを用いて実行する必要があります。 textに音声に変換したいテキスト、speakeridに話者番号を渡します。

エラーハンドリング

GetQueryメソッドおよびDownloadAudioClipメソッドでは、音声のクエリ作成やダウンロード中にエラーが発生した場合、そのエラー情報をデバッグログに出力します。

使用例

VoiceVoxManager voiceVoxManager = new VoiceVoxManager();//VoiceVoxManagerクラスを作成
await voiceVoxManager.DownloadAudioClip("今日も良い天気ですね。夕食は何を食べますか?", 8);//音声合成する
audioSource.clip = voiceVoxManager.AudioClip; //生成した音声をAudioClipに設定
audioSource.Play();//音声を再生

コード

using Cysharp.Threading.Tasks;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

public class VoiceVoxManager
{
    private AudioClip _audioClip; //プライベートフィールドを定義
    private string baseURL = "http://localhost:50021/";  //VoiceBoxサーバのベースURL
    public AudioClip AudioClip { get => _audioClip; } //プライベートフィールド_audioClipの値を返すプロパティ

    private async UniTask<byte[]> GetQuery(string text, int speakerId) // VoiceVoxサーバにテキストを投げて、音声合成用のクエリを作成してもらう
    {
        string EncodedUrl = UnityWebRequest.EscapeURL(text, Encoding.UTF8); //音声に変換したいテキストをURLエンコード
        string url = baseURL + $"audio_query?text={EncodedUrl}&speaker={speakerId}"; // 問い合わせ先URLを作成
        using(UnityWebRequest request = new UnityWebRequest(url, "POST")) //urlとPOSTを指定してリクエストを作成
        {
            request.downloadHandler = new DownloadHandlerBuffer(); //そのままの形式でダウンロード 
            await request.SendWebRequest();//WEBサーバにリクエストを送信する

            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.Log($"エラーです。{request.error}");
                return null;
            }
            else
            {
                return request.downloadHandler.data; //返ってきたデータ(クエリ)をそのまま戻り値として返す
            }

            
        }
    }

    public async UniTask DownloadAudioClip(string text, int speakerId) //クエリを投げて音声合成してもらい、AudioClipを受け取る関数
    {
        byte[] query = await GetQuery(text, speakerId);//音声合成用のクエリを作成する

        string Url = baseURL + $"synthesis?speaker={speakerId}";// 問い合わせ先URLを作成
        using (UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(Url, AudioType.WAV))//WAV形式のデータを要求するリクエストを作成
        {
            request.method = "POST";//POSTメソッドを指定
            request.SetRequestHeader("Content-Type", "application/json");//ヘッダーを設定
            request.uploadHandler = new UploadHandlerRaw(query);//BODYにクエリを設定
            await request.SendWebRequest();//WEBサーバにリクエストを送信する

            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.Log($"エラーです。{request.error}");
            }
            else
            {
                _audioClip = DownloadHandlerAudioClip.GetContent(request); //AudioClip形式でデータを受け取る
            }
        }
    }
}

参考

下記サイトを参考にさせて頂きました。 ありがとうございます。

github.com

qiita.com