C#）DeepL API で翻訳した結果をボイスロイドにしゃべってもらいたい！（２）

# 前回までのあらすじ
これは「[自由研究室 AIRS-Lab](https://www.airs-lab.jp)」の [Advent Calendar](https://qiita.com/advent-calendar/2021/airs-lab)、9日目の記事です。

英語よわよわ勢の私は DeepL で翻訳した結果をボイスロイドにしゃべってもらうべく日夜（3日くらい）研究を重ねついに DeepL API を使った翻訳ができるようになったが…（[前回記事](https://qiita.com/fuji_t/items/4d9ca45006ce0c2aaa32)）

# やりたいこと
- DeepL API を使って英語を日本語に、日本語を英語に翻訳する。
- 翻訳した結果を ボイスロイド（CeVIO AI）にしゃべってもらう。
- というのを C# で実現する。

※ 今回の記事範囲は 「翻訳した結果を ボイスロイド（CeVIO AI）にしゃべってもらう」内容となります。
※ DeepL API を使った翻訳は[別記事](https://qiita.com/fuji_t/items/4d9ca45006ce0c2aaa32)に分けています。

【最終的な完成イメージ】
<iframe width="560" height="315" src="https://www.youtube.com/embed/W2eI6WaMapU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 翻訳した結果をボイスロイド（CeVIO AI）にしゃべってもらいましょう
というわけで、いよいよボイスロイドにしゃべってもらう機能を追加しましょう！
今回は、日本語と英語の両対応にしたかったので、[マキマキ（弦巻マキ）](https://www.ah-soft.com/cevio/maki/)を使っています。日本語発話だけでよいなら、他の [CeVIO AI 対応キャラ](https://cevio.jp/products_cevio_ai/) でもかまいません。

## フォームのデザイン
今回追加するコントロールは CeVIO AI を起動するためのボタンと、キャスト（キャラ）を選ぶためのコンボボックスです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/02abcf37-fdcf-0384-796e-dd74d52838a3.png">



## CeVIO AI との連携
### .NET連携 API
CeVIO AI には [.NET連携 API](https://cevio.jp/guide/cevio_ai/interface/dotnet/) が用意されています。ぶっちゃけ [ここ](https://cevio.jp/guide/cevio_ai/interface/dotnet/) を見ればもうほとんど解決です！しかも親切にサンプルコードも配布してくれているので、至れり尽くせりです。今回は最低限の機能しか実装しませんが、他にもいろいろな操作ができそうなので、一度目を通しておくとよいでしょう。

### DLL の参照登録
.NET連携するには、DLLへの参照を追加する必要があります。ソリューションエクスプローラーの「参照」を右クリックして「参照の追加…」から「参照マネージャー」を表示させてください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/b41bbad3-16ff-aaf7-736f-e1207a2f6bd5.png" width="64%">

CeVIO AI のインストールフォルダにある「CeVIO.Talk.RemoteService2.dll」を参照先に追加し、チェックを入れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/e3a65114-5904-ca4b-3391-b8fcb993a562.png" width="64%">

そこまでできたら、以下をインポートしておきます。

```csharp
using CeVIO.Talk.RemoteService2;
```

## CeVIO AI の起動、終了

### フィールドの宣言
まずは下記のようにクラスのフィールドを宣言しておきましょう。

```csharp
public Talker2 CevioTalker;
```

### CeVIO AI の起動
［音声アプリ起動］ボタンを押したら CeVIO AI が起動するようにします。同時に利用可能なキャスト名を取得して cmbCast に登録しておきます。btnStartAppli_Click() に以下のようなコードを書きましょう。

```csharp:btnStartAppli_Click()
private void btnStartAppli_Click(object sender, EventArgs e)
{
    // 【CeVIO AI】起動
    ServiceControl2.StartHost(false);

    // Talkerインスタンス生成
    CevioTalker = new Talker2();

    // 利用可能なキャスト名を取得
    cmbCast.Items.AddRange(Talker2.AvailableCasts);
    cmbCast.SelectedIndex = 0;
}
```

### CeVIO AI の終了
本アプリが終了するタイミングで、起動させていた CeVIO AI も終了させましょう。フォームのクロージングイベントに以下のコードを書きます。

```csharp:frmMain_FormClosing()
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
    // 【CeVIO AI】終了
    ServiceControl2.CloseHost();
}
```

## トーク
### 翻訳結果を発話
翻訳結果をしゃべってもらう機能を実装します。キャスト設定のコンボボックスで選ばれているキャストを設定して、翻訳結果のテキスト（txtResult のテキスト）を Speak() メソッドに渡します。

```csharp:startTalk()
private void startTalk()
{
    // キャスト設定
    CevioTalker.Cast = cmbCast.SelectedItem.ToString();

    // 再生
    SpeakingState2 state = CevioTalker.Speak(txtResult.Text);
    state.Wait();
}
```

### startTalk() を呼び出す
`btnTranslate_Click()` から `startTalk()` を呼び出します。発話の前に翻訳結果がきちんと表示されるように、`txtResult.Refresh()` を追記しておきます。 

```csharp:btnTranslate_Click()
private async void btnTranslate_Click(object sender, EventArgs e)
{
    using (var httpClient = new HttpClient())
    {
        using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api-free.deepl.com/v2/translate"))
        {
            //（省略）

            var resBodyStr = response.Content.ReadAsStringAsync().Result;
            JObject deserial = (JObject)JsonConvert.DeserializeObject(resBodyStr);
            txtResult.Text = deserial["translations"][0]["text"].ToString();
            txtResult.Refresh();

            startTalk();
        }
    }
}
```

## 完成！
お疲れさまでした。これで完成です！
これで翻訳結果をマキマキに教えてもらえるようになりますね！
最後にコードを再掲しておきます。

```csharp
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using CeVIO.Talk.RemoteService2;
```

```csharp
public partial class frmMain : Form
{
    public Talker2 CevioTalker;

    public frmMain()
    {
        InitializeComponent();
    }

    private async void btnTranslate_Click(object sender, EventArgs e)
    {
        using (var httpClient = new HttpClient())
        {
            using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api-free.deepl.com/v2/translate"))
            {
                var contentList = new List<string>();
                contentList.Add("auth_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
                contentList.Add("text=" + txtSource.Text);

                if (radioJA.Checked)
                {
                    contentList.Add("target_lang=JA");
                }
                else if (radioEN.Checked)
                {
                    contentList.Add("target_lang=EN");
                }

                request.Content = new StringContent(string.Join("&", contentList));
                request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");

                var response = await httpClient.SendAsync(request);

                var resBodyStr = response.Content.ReadAsStringAsync().Result;
                JObject deserial = (JObject)JsonConvert.DeserializeObject(resBodyStr);
                txtResult.Text = deserial["translations"][0]["text"].ToString();
                txtResult.Refresh();

                startTalk();
            }
        }
    }

    private void txtSource_TextChanged(object sender, EventArgs e)
    {
        txtResult.Text = "";
    }

    private void btnStartAppli_Click(object sender, EventArgs e)
    {
        // 【CeVIO AI】起動
        ServiceControl2.StartHost(false);

        // Talkerインスタンス生成
        CevioTalker = new Talker2();

        // 利用可能なキャスト名を取得
        cmbCast.Items.AddRange(Talker2.AvailableCasts);
        cmbCast.SelectedIndex = 0;
    }

    private void startTalk()
    {
        // キャスト設定
        CevioTalker.Cast = cmbCast.SelectedItem.ToString();

        // 再生
        SpeakingState2 state = CevioTalker.Speak(txtResult.Text);
        state.Wait();

    }

    private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        // 【CeVIO AI】終了
        ServiceControl2.CloseHost();
    }
}
```

# おまけ：VOICEROID2 バージョン
「VOICEROID2 は持ってるけど、CeVIO AI は持ってないんですけど…」
「「ボイスロイドにしゃべってもらいたい！」って記事だから VOICEROID2 で喋らせられるのかと思ったのに…」
はい、そうですよね。まぁ、でも、VOICEROID2 でもこんな感じ ↓ で実現できるので挑戦してみてくださいね。

<iframe width="560" height="315" src="https://www.youtube.com/embed/WLNirqSlfxo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<br>
こちらの記事を参考にすれば比較的簡単に実装できると思いますー。
https://hgotoh.jp/wiki/doku.php/documents/voiceroid/tips/tips-003

ではでは、よいボイロライフを。