ゆっくりボイス : AquesTalk 1 を C# から呼び出してみる
前回、SofTalk というフリーソフトをコマンドラインから呼び出し、ゆっくりボイスでテキストを発話させてみた。
- 過去記事 : ゆっくりボイスの SofTalk を CLI から使う
今回は SofTalk が利用している大元の合成音声ライブラリ「AquesTalk」を利用して、自作の C# のコードから発話させてみようと思う。
目次
AquesTalk のおさらい
合成音声ライブラリ AquesTalk は、大きく分けて 1・2・10 系という3つのバージョンがある。いずれも機能制限がある「評価版」であれば、公式サイトから無料でダウンロード、利用できる。
いずれのバージョンも、Windows 向けには .dll
、Linux 向けには .so
ファイルといった「動的リンクライブラリ」を提供しているので、プログラミング言語を問わず、.dll
ファイルを呼び出すためのコードを書けば AquesTalk が利用できるというワケ。
公式サイトには C/C++ 言語のコード例が記載されている「プログラミングガイド」などのドキュメントがあり、どういう関数が存在し、どういう引数を指定して呼び出せばよいかなどが確認できるので、合わせてダウンロードして読んでおこう。
今回はバージョン 1 系を利用したコードを組んでいく。
評価版の制限を回避したい
前述のとおり、公式サイトでダウンロードできる「評価版」のライブラリは、機能制限がかかっている。
評価版は「ナ行、マ行」の音韻がすべて「ヌ」になる制限があります。
つまり、「こんにちわ」というテキストを渡すと「こんぬちわ」と発話するような制限があるようだ。この制限を回避するには、ライセンスを購入する必要がある。
しかし、フリーソフトの「SofTalk」や「棒読みちゃん」にはこうした制限はかかっていないのに、なぜ本家本元の AquesTalk ライブラリにはこうした制限がかかっているのだろうか?
コレは AquesTalk のライセンス形態が途中で変更されたためにこのようになっているらしく、以前のライセンス形態で提供されていた AquesTalk 1 系はもっと自由に使えたようである。
そこで色々試したところ、公式サイトからダウンロードできる評価版の AquesTalk.dll
ではなく、「SofTalk」や「棒読みちゃん」に同梱されている AquesTalk.dll
ファイルを利用することで、評価版の制限を回避して発話させることに成功した。以下でもう少し詳しく解説しようと思う。
ただし、当然ながら自己責任で。このプログラムは手元で遊びで利用するにとどめてもらいたい。
AquesTalk.dll
を用意する
善良な市民は、公式サイトから評価版のライブラリ aqtk1-win-eva_173.zip
をダウンロードし、Zip を解凍した中から aqtk1-win-eva/x86/f1/AquesTalk.dll
を取得しておく。64bit 版の x64/
ディレクトリではなく、32bit 版の x86/
ディレクトリにある方を使用すること。
f1/
と同階層に他にもディレクトリがいくつかあるが、コレがそれぞれの声質になっている。今回は「f1
女声1」を使用する前提で話を進めるが、他のボイスを使用したい場合はそのディレクトリ配下の AquesTalk.dll
を取得すれば良い。
前述のとおり、評価版を回避してみたい人は、「SofTalk」や「棒読みちゃん」をダウンロードし、その中から AquesTalk.dll
を取得する。
- 「SofTalk」の場合は解凍したディレクトリ配下の
dll/f1/AquesTalk.dll
を取得するf1/
と同階層にあるdvd/
やm1/
などが、同じ v1 系の別の声質の DLL ファイルaqt2/
とaqt10/
はそれぞれ v2・v10 系の DLL ファイル群があるディレクトリ
- 「棒読みちゃん」の場合は解凍したディレクトリ内の
AquesTalk/f1/AquesTalk.dll
を取得するf1/
と同階層にあるdvd/
やm1/
などが、同じ v1 系の別の声質の DLL ファイル
SofTalk 同梱の DLL でも、棒読みちゃん同梱の DLL でも、どちらでも同じように利用できた。
C# コードを書く
ということで、AquesTalk.dll
を用意したら、以下のような C# のコードを書いていく。
atk1.cs
using System; // Console
using System.IO; // MemoryStream
using System.Media; // SoundPlayer
using System.Runtime.InteropServices; // Marshal
public class ATK1 {
// DLL ファイルへのパス
const string dllPath = ".\\AquesTalk.dll";
[DllImport(dllPath)]
private static extern IntPtr AquesTalk_Synthe(string koe, int iSpeed, ref int size);
[DllImport(dllPath)]
private static extern void AquesTalk_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);
// 音声ファイルとしてそのまま保存可能なバイト列の先頭ポイントを取得する
int size = 0;
IntPtr wavPtr = IntPtr.Zero;
try {
wavPtr = AquesTalk_Synthe(koe, iSpeed, ref size); // 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);
// アンマネージドポインタは用がなくなった瞬間に解放する
AquesTalk_FreeWave(wavPtr);
// 同期再生する
using(var ms = new MemoryStream(wav))
using(var sp = new SoundPlayer(ms)) {
sp.PlaySync();
}
Console.WriteLine("Finished");
}
}
公式のプログラミングガイドやブログ記事等を参考に書いてみた。
- 定数
dllPath
で「同ディレクトリの.\AquesTalk.dll
」を相対パス指定している- PATH が通っている場所に DLL を置いておけば、相対パスでなく
"AquesTalk.dll"
と書いても読み込めるみたい
- PATH が通っている場所に DLL を置いておけば、相対パスでなく
- DLL 内の
AquesTalk_Synthe
関数とAquesTalk_FreeWave
関数を呼び出せるようにDllImport
しておく- それぞれ発話とメモリ解放の関数。引数の型などは公式のプログラミングガイドに記載がある
- 参考 : 【Windows/C#】なるべく丁寧にDllImportを使う - Qiita
- 定数
iSpeed
が読み上げ速度 - 定数
koe
が読み上げるテキストの指定部分。基本的にひらがなのみ対応しており、漢字や英数字は認識できないので予めひらがなにしておくこと- 「SofTalk」や「棒読みちゃん」などのツールは、この部分を IME の再変換機能だったり、MeCab のような形態素解析ライブラリなんかでひらがなに展開して読み上げ処理を行わせているようだ
- 漢字などを展開する処理を自前で実装することも可能だが、今回は実装していない
SoundPlayer.PlaySync()
で音声を同期的に再生させている- それ以外はエラーハンドリングやデバッグログ出力をちまちま書いている程度
C# コードを csc.exe
でコンパイルする
こうして記述した C# のコードを、.NET Framework に内蔵されている csc.exe
でコンパイルする。というのも、僕はあまり C# に明るくなく、Visual Studio で開発したりしていないので、今回はかなり簡易的に、csc.exe
を使ってコンパイルしてしまっている。
ココで、AquesTalk.dll
との兼ね合いで 32bit 版の実行ファイルを生成する必要があるので、そのためのオプション指定 /platform:x86
を忘れずにしておこう。使用する csc.exe
も 64bit 版ではなく 32bit 版を使う方が良いだろう (ディレクトリパスが Framework64\
ではなく Framework\
の方を使う)。
csc.exe
の所在やバージョンは環境によると思うが、自分の環境では以下のフルパスを指定してコンパイルした。
@Rem コンパイルする
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nologo /platform:x86 .\atk1.cs
@Rem 実行する
.\atk1.exe
そしてコンパイルして生成した atk1.exe
を実行すれば、実行時に同ディレクトリにあるであろう AquesTalk.dll
を利用して発話できる。
.dll
ファイルは「動的リンクライブラリ」と言うだけあって、コンパイル時に atk1.exe
の中には内包されず、EXE の実行時に DLL ファイルを探しに行くモノなので、利用する際は atk1.exe
と AquesTalk.dll
が必ずセットで必要になる。
また、今回のコードの場合でいうと、AquesTalk.dll
を別の声質のモノと差し替えれば、atk1.exe
の方は再コンパイルすることなく声質を変えたりもできる。
以上
今回は以上とする。
読み上げ速度やテキストを標準入力で受け取れるように C# コードを書ければ、CLI ツールが出来上がるだろう。
また、途中でも触れたように AquesTalk ライブラリは漢字や英数字が認識できないので、テキストをひらがなに展開するような事前処理を入れてあげたりすると「SofTalk」や「棒読みちゃん」のように利用しやすくなるだろう。
フリーソフトの他にも、既に似たような Python 製のコードが存在したりするものの、Twitter のタイムラインを読み上げさせたりするようなプログラムも、コレを元に組んでいけそうだ。
参考
- 【C#】ゆっくりボイスのプログラミング入門【AquesTalk】 - Bakulog
- 今回大きく参考にさせていただいた記事
- 【C#】FodyでDLLファイルをEXEファイルに埋め込む方法|○NAKA BLOG
- 実行ファイルとDLLを一つにまとめる - Qiita
- 今回は未検証だが、DLL ファイルを Exe に内蔵する方法は ILMerge や Fody などがある模様
- Goでゆっくりしていってね! — KaoriYa
- Go 言語で AquesTalk 1 系の DLL ファイルを呼び出す例
- Na-x4/AquesTalk-python: Python Wrapper for AquesTalk (Old License)
- Python で実行する例