Unityで音声合成を再生する (Amazon Polly)

Unityで Alexaのような音声合成を試してみました。
「.Net」 に対応している AWS の音声合成サービス 「Amazon Polly」 を使います。

# やりたいこと

1. 入力したテキストの発話
2. ボイスの選択（ 男性女性 / 日本語・多言語 ）

下記のサイトで Alexaの音声合成を試せるので、これと同じような仕組みを検討します。
[SSML Editor : VoiceFlow](https://creator.voiceflow.com/ssml)
<img width="672" alt="スクリーンショット 2020-02-13 17.33.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/53590dfb-6433-634a-559b-b7654a6e1718.png">

# Amazon Polly とは
>　Amazon Polly は、文章をリアルな音声に変換するサービスです。テキスト読み上げができるアプリケーションを作成できるため、まったく新しいタイプの音声対応製品を構築できます。Polly は、高度なディープラーニング技術を使用したテキスト読み上げ (TTS) サービスで、自然に聞こえるように人間の音声を合成します。何十種類ものリアルな音声を多数の言語でサポートしているため、さまざまな国に対応した音声アプリケーションを構築できます。(AWSサイトより)

Polly API に テキストを送信するだけで、Amazon Polly からオーディオストリームがレスポンスされます。アプリケーションで直接ストリーミングしたり、MP3 に保存することもできます。
AWSのアカウントが必要ですが、「1か月あたり数百万文字」までの無料利用枠があるので、無料で始められます。 

[Amazon Polly : AWS](https://aws.amazon.com/jp/polly/?nc=sn&loc=0)

# Amazon Polly の準備

### AWSアカウントの作成
AWSアカウントがない場合は、下記からアカウントを作成してください。

[AWSアカウントの作成の流れ : AWS](https://aws.amazon.com/jp/register-flow/)
途中、クレジットカード情報の入力が必要です。

AWS SDK を使う際に、「アクセスキー ID」と「シークレットアクセスキー」が必要になるので、アカウント作成後に、IAMからアクセスキーを作成しておきます。

### AWS SDK の入手
下記から AWSSDK.Core と AWSSDK.Polly の最新版をダウンロードします。
https://www.nuget.org/packages/AWSSDK.Core/
https://www.nuget.org/packages/AWSSDK.Polly/
<img width="1171" alt="スクリーンショット 2020-02-13 18.49.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/b57a1aff-b902-1b1e-659e-e30bdb4d5808.png">

ダウンロードした「awssdk.core.\*\*\*\*.nupkg」と「awssdk.polly.\*\*\*\*.nupkg」は、拡張子を zip に変更すると解凍できます。
下記の階層から、それぞれの「.Net4.5」用DLLを取り出しておきます。
<img width="820" alt="スクリーンショット 2020-02-13 18.59.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/1fb0f9dc-537d-0205-bab5-098e423152da.png">

# 音声合成コンポーネントを作る

新規作成したUnityプロジェクトに「Plugins」フォルダを作り、先ほどのDLLを配置します。
<img width="520" alt="スクリーンショット 2020-02-13 19.16.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/435d8b64-6566-bbd7-4099-acb323285b07.png">

ProjectSettings から Api Compatibility Levelを「.Net 4.x」に変更します。
<img width="669" alt="スクリーンショット 2020-02-13 19.17.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/0fa62a78-82da-a02c-d669-f671693030d6.png">

下記のスクリプトを作成します。
"access-key"と "secret-key"は、自分のキーに書き換えてください。

```PollyTest.cs
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Amazon.Polly;
using Amazon.Polly.Model;

public class PollyTest : MonoBehaviour
{
    public VoiceType voiceType;
    public string text;
    private AmazonPollyClient client;
    private AudioSource audioSource;
    private List<FieldInfo> voiceList = new List<FieldInfo>();

    private string fileName = "voice.ogg";

    void Awake()
    {
        audioSource = gameObject.AddComponent<AudioSource>();

        string voiceNames = "";
        var list = typeof(VoiceId).GetFields();
        foreach (FieldInfo prop in list)
        {
            voiceNames += prop.Name + ",";
            voiceList.Add(prop);
        }
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(Speak());
        }
    }

    private IEnumerator Speak()
    {
        client = new AmazonPollyClient("access-key", "secret-key", Amazon.RegionEndpoint.USEast1);
        SynthesizeSpeechRequest sreq = new SynthesizeSpeechRequest();
        sreq.Text = text;
        sreq.OutputFormat = OutputFormat.Ogg_vorbis;
        sreq.VoiceId = voiceList[(int)voiceType].GetValue(null) as VoiceId;
        SynthesizeSpeechResponse sres = client.SynthesizeSpeech(sreq);

        //save voice
        using (var fileStream = File.Create(Application.persistentDataPath + "/" + fileName))
        {
            sres.AudioStream.CopyTo(fileStream);
            fileStream.Flush();
            fileStream.Close();
        }
        //play voice
        using (WWW www = new WWW("file:///" + Application.persistentDataPath + "/" + fileName))
        {
            yield return www;
            audioSource.clip = www.GetAudioClip(false, true, AudioType.OGGVORBIS);
            audioSource.Play();
        }
    }
}

public enum VoiceType
{
    Aditi, Amy, Astrid, Bianca, Brian, Camila, Carla, Carmen, Celine, Chantal, Conchita, Cristiano, Dora, Emma, Enrique, Ewa, Filiz, Geraint, Giorgio, Gwyneth, Hans, Ines, Ivy, Jacek, Jan, Joanna, Joey, Justin, Karl, Kendra, Kimberly, Lea, Liv, Lotte, Lucia, Lupe, Mads, Maja, Marlene, Mathieu, Matthew, Maxim, Mia, Miguel, Mizuki, Naja, Nicole, Penelope, Raveena, Ricardo, Ruben, Russell, Salli, Seoyeon, Takumi, Tatyana, Vicki, Vitoria, Zeina, Zhiyu
}
```
ここでは、Amazon Polly から取得したオーディオストリームを Oggファイルとして保存して、WWW.AudioClipで再生しています。

GameObjectにスクリプトをアタッチします。
インストラクタ上で、ボイス選択 と 再生したい音声テキスト を変更できます。
<img width="573" alt="スクリーンショット 2020-02-13 19.29.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/1822b375-cdba-e895-d0a7-14c91a7687ef.png">

スペースキーで、音声が再生されると完成です。

VoiceType を Mizuki か Takumi にすると、日本語の音声合成も可能です。