ゆっくりボイス:AquesTalk 2 を C# から呼び出してみる

今度は AquesTalk 2 系を触るよ。

前回の記事で AquesTalk 1 系の DLL を呼び出せたので、今度は AquesTalk 2 系を呼び出してみる。

v1 系との大きな違いは、v1 系は声質ごとに DLL ファイルが存在していたのに対し、v2 系では DLL ファイルは単一で、声質のデータ (.phont) ファイルを別途読み込んで使うという形式になっている点。

ライブラリを用意する

善良な市民は、公式から評価版のライブラリをダウンロードしよう。

aqtk2-win-eva_230.zip を解凍し、lib/AquesTalk2.dll (本体 DLL) と、phont/ 配下のテキトーな .phont ファイルを1つ取得しておこう。以降のコード例では phont/aq_f1c.phont を使う前提とする。

評価版を回避したい人は、SofTalk に同梱されている DLL と .phont ファイルを流用しても動かせた (自己責任で)。

C# コードを書く

取得した AquesTalk2.dll.phont ファイルと同じディレクトリに、C# ソースファイルを作って実装していく。

using System;                          // Console
using System.IO;                       // MemoryStream
using System.Media;                    // SoundPlayer
using System.Runtime.InteropServices;  // Marshal

public class ATK2 {
  // DLL ファイルのパス
  const string dllPath = ".\\AquesTalk2.dll";
  // 声質の定義ファイルのパス
  const string filePath = ".\\aq_f1c.phont";
  
  [DllImport(dllPath)]
  private static extern IntPtr AquesTalk2_Synthe(string koe, int iSpeed, ref int size, byte[] phontDat);
  // phont ファイルを使用せず DLL 内蔵の音質だけ使う場合は
  // 以下のように「byte[] phontDat」部分を「int phontDat」と宣言し引数に 0 を与えて呼び出せば良い
  //private static extern IntPtr AquesTalk2_Synthe(string koe, int iSpeed, ref int size, int phontDat);
  
  [DllImport(dllPath)]
  private static extern void AquesTalk2_FreeWave(IntPtr wavPtr);
  
  public static void Main() {
    Console.WriteLine("Start");
    
    const int iSpeed = 100;
    const string koe = "こんにちわバージョンつー";
    Console.WriteLine("DLL   : {0}", dllPath);
    Console.WriteLine("Speed : {0}", iSpeed);
    Console.WriteLine("Text  : {0}", koe);
    
    // phont ファイルを読み込む
    FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    byte[] buffer = new byte[fs.Length];
    int bytesRead = fs.Read(buffer, 0, buffer.Length);
    fs.Close();
    
    // 音声ファイルとしてそのまま保存可能なバイト列の先頭ポイントを取得する
    int size = 0;
    IntPtr wavPtr = IntPtr.Zero;
    try {
      wavPtr = AquesTalk2_Synthe(koe, iSpeed, ref size, buffer);  // throws
      // phont ファイルを使用せず DLL 内蔵の音質だけ使う場合は
      // 「phont ファイルを読み込む」部分の処理を削除し以下のように呼び出せば良い
      //wavPtr = AquesTalk2_Synthe(koe, iSpeed, ref size, 0);  // throws
      
      // 失敗していれば終了する
      if(wavPtr == IntPtr.Zero) {
        Console.WriteLine("ERROR : 音声生成に失敗しました。不正な文字が使われた可能性があります。終了します");
        return;
      }
    }
    catch(Exception exception) {
      Console.WriteLine("ERROR : 例外が発生しました");
      Console.WriteLine(exception);
      Console.WriteLine("終了します");
      return;
    }
    
    // C# で扱えるようにマネージド側へコピーする
    byte[] wav = new byte[size];
    Marshal.Copy(wavPtr, wav, 0, size);
    
    // アンマネージドポインタは用がなくなった瞬間に解放する
    AquesTalk2_FreeWave(wavPtr);
    
    // 同期再生する
    using(var ms = new MemoryStream(wav))
    using(var sp = new SoundPlayer(ms)) {
      sp.PlaySync();
    }
    
    Console.WriteLine("Finished");
  }
}

C# コードを csc.exe でコンパイルする

前回の記事と同じく、.NET Framework の簡易的なコンパイラ、csc.exe を使ってコンパイルする。前回と同様、32bit 指定でコンパイルしないと動作しない。

csc.exe の所在やバージョンは環境によると思うが、自分の環境では以下のフルパスを指定してコンパイルした。

@Rem コンパイルする
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nologo /platform:x86 .\atk2.cs

@Rem 実行する
.\atk2.exe

前回と同様、当然ながら DLL ファイルと .phont ファイルは実行時に読み込むので、コンパイルした atk2.exe と同じディレクトリに置いておくこと。

以上

v1 系と v2 系は声質データの扱い方が異なることがよく分かった。v1 系と同じ声質でも手直しが入っているのか、若干違って聴こえたりするので、好みのモノを選ぶと良いだろう。

v10 系も仕組みの違いはあるが、自前でプログラムを組むことは可能である。ただ、v10 系はプログラムの実行時にライセンスキーを指定してライセンス認証用の関数を実行することで評価版の制限を解除するような作りになっているらしく、v1・v2 系で示したような「SofTalk」同梱の DLL の流用では回避が難しそうである。

↑ 評価版で良ければ、上のコードが参考になると思われる。v10 系は様々なパラメータで読み上げ方を調整できるので、より高精度な読み上げを行わせたい場合は v10 系に手を出してみるのが良いだろう。

個人的には、世の「ゆっくり動画」で聞き馴染みがあるのは v1 系の声質なので、v1 系のライブラリで何か読み上げさせて自己満足しておこうかなーと思っている。