ゆっくりボイスのプログラミング入門【AquesTalk10】

C#からAquesTalk10を使ってゆっくりボイスを出させる手法を紹介します。C言語/Cの基本的な知識を前提としています。

1.記事を書いた理由

Twitterで、募集作ってほしいアプリを募集したところ、ゆっくりボイスを使える動画編集ソフトを作ってほしいという意見があったので、しばらく動画編集ソフト作成に取り組んでみたいと思います。

f:id:nakadasanda1:20200425132419p:plain

Aquestalkは、C#専用のライブラリーでは、ありません。評価版をダウンロードして公式ドキュメントを見れば理解できますが、このライブラリーは、もともとC言語から触る想定のライブラリーなので、C#から触るには、ちょっと下手順を踏む必要があります。それについても解説していきたいと思います。

Aquestalk10の購入、or評価版のダウンロード

公式サイトからAquestalk10をダウンロードします。

https://www.a-quest.com/download.html

2.とにかく実行だ。

visual studioを立ち上げます。

windowsフォームアプリケーション(.net Framework)を新規作成します。

f:id:nakadasanda1:20200425133602p:plain

ダウンロードしたaqestalkのファイルの中にある、lib ファイルを、C#ディレクトリー(bin/debag)に配置します。

f:id:nakadasanda1:20200425134214p:plain

f:id:nakadasanda1:20200425134318p:plain

そしたらprogram.csに以下のソースコードを書きます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Runtime.InteropServices;
using System.IO;
using System.Text.RegularExpressions;

namespace aquestalk
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        /// 

        const string dllname = "AquesTalk.dll";

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct AQTK_VOICE
        {
            public int bas;    // 基本素片 F1E/F2E/M1E (0/1/2)
            public int spd;    // 話速     50-300 default:100
            public int vol;    // 音量     0-300 default:100
            public int pit;    // 高さ     20-200 default:基本素片に依存
            public int acc;    // アクセント 0-200 default:基本素片に依存
            public int lmd;    // 音程1  0-200 default:100
            public int fsc;   // 音程2(サンプリング周波数) 50-200 default:100
            public void Init()
            {
                bas = 0;
                spd = 100;
                vol = 100;
                pit = 100;
                acc = 100;
                lmd = 100;
                fsc = 100;
            }
        }

        [DllImport(dllname)]
        extern static IntPtr AquesTalk_Synthe_Utf8(ref AQTK_VOICE pParam, byte[] koe, ref int size);

        [DllImport(dllname)]
        //声
        extern static void AquesTalk_FreeWave(IntPtr wav);
        [STAThread]
        static void Main()
        {


            while (true)
            {
                //不定長情報のメモリー確保
                IntPtr aqtk_p = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(AQTK_VOICE)));
                AQTK_VOICE aqtk_voice = (AQTK_VOICE)Marshal.PtrToStructure(aqtk_p, typeof(AQTK_VOICE));
                aqtk_voice.Init();

                //文字読み込み
                Console.WriteLine("何かひらがなを入れてください。");
                string koe = Console.ReadLine();
                System.Text.Encoding utf8Enc = System.Text.Encoding.GetEncoding("UTF-8");

                byte[] koeUtfBytes = utf8Enc.GetBytes(koe);

                int size = 0;
                IntPtr wavPtr = AquesTalk_Synthe_Utf8(ref aqtk_voice, koeUtfBytes, ref size);

                if (wavPtr == IntPtr.Zero)
                {
                }

                //C#であつかえるように
                byte[] wav_data = new byte[size];
                Marshal.Copy(wavPtr, wav_data, 0, size);

                //解放
                AquesTalk_FreeWave(wavPtr);

                //再生
                using (var ms = new MemoryStream(wav_data))
                using (var sp = new SoundPlayer(ms))
                {
                    sp.Play();
                }
            }

        }
    }
}

そしたら、実行、エラー😢
ということなので、visualStudioの上部のメニューからプロジェクト、プロジェクトのプロパティを押します。

f:id:nakadasanda1:20200425135658p:plain

出力の種類をwindowsアプリケーションから→コンソールアプリケーションに変更する。

f:id:nakadasanda1:20200425140039p:plain

再び実行すると、ひらがなの入力をしてくださいと表示されて読み上げが行われるのを確認できるはずです。漢字は、認識されていません。詳しくは、公式マニュアルを確認してください。

3.どういうしくみでしょう

C言語のライブラリーをc#で呼び出すには,DllImport属性とextern修飾子を使用して、実行時にライブラリーを読み込む必要があります。一番上のこれのことです。

        const string dllname = "AquesTalk.dll";
        [DllImport(dllname)]
        extern static IntPtr AquesTalk_Synthe_Utf8(ref AQTK_VOICE pParam, byte[] koe, ref int size);

        [DllImport(dllname)]
        //声
        extern static void AquesTalk_FreeWave(IntPtr wav);

このように
- 読み込み先のdllの名前
- "extern static"の宣言
- dll内で定義されているはずの関数名、引数、戻り値等の関数の宣言

を行うことでC#の関数と、同じ感覚で関数を呼び出せます。
重要な事として、関数の名前、引数、戻り値の方についてよく下調べをしないとだめです。AquesTalkの場合には、中に含まれている「aqtk10_win_man.pdf」というマニュアルを読み、”AquesTalk_Synthe_Utf8”という関数を知ることが必要です。

またC#C言語間での型名の読み替えが必要です。コツとして
- ポインターは、IntPtrで受け渡して、あとからMarshalクラスの関数で他の方に変換する
- 引数の参照私(ポインター)をC#で行うには、ref修飾子を使う

こんな感じでしょうか。AquesTalk_Synthe_Utf8関数の戻り値は、「Wavファイル」に相当するので、その知識をもとにIntPtrをバイト配列に変換し、SoundPlayerで音として再生しています。もちろん後からファイルに保存するなどの操作もできます。