目次
libopenjtalk
python-jtalk
since 2014-01-16
NVDA日本語版を Open JTalk 1.07 に移行させるにあたり、新しく python-jtalk リポジトリを作り、libopenjtalk と htsengineapi のレポジトリは、python-jtalk のサブモジュールとして参照されるかたちにする。
http://sourceforge.jp/ticket/browse.php?group_id=4221&tid=30704
過去の記事
Open JTalk (配付サイト)の派生版を作る。
- libopenjtalk.dll (または .so) を作るためのソース
- http://github.com/nishimotz/htsengineapi : Open JTalk 由来 = New BSD ライセンス htsengineapi
- http://github.com/nishimotz/libopenjtalk : Open JTalk 由来 = New BSD ライセンス libopenjtalk
- nvdajp_jtalk の miscdep のリポジトリとアーカイブの一部として libopenjtalk.dll を配布
- libopenjtalk を叩くラッパー : nishimotz 実装の _jtalk_core.py (since 2010-12-04)
- python 2.7 Windows, 32bit 対応。ctypes の宣言が 32bit ポインタに依存。Windows API に依存していないはず。。
- 話者モデル、辞書、libmecab が別途必要
- ほぼそのまま http://tts.rcpt.cc 日本語TTSテストサイト で使用 (2011-01-04)
- 過去のバージョン
- https://gist.github.com/728118 PortAudio 対応 with pyaudio
- nvdajp_jtalk synthDrivers/_jtalk_core.py from lp:~nishimotz/nvdajp/with_jtalk rev 3562
- http://github.com/nishimotz/ojt-python : NVDA 由来の GPL コードを含んでいる ojt-python
- 現在 nvdajp に組み込まれている libopenjtalk.dll は cygwin の MinGW 互換 gcc-3 でコンパイルされている。
- Open JTalk の一部だった mecab は libopenjtalk.dll に含まれていない
- 中の人によると「Open JTalkはHTS Engine APIのサンプルアプリケーションという位置づけ」らしい。確かに HTS Engine API は(勝手にリポジトリを作ってみたものの)いじらなくてもよさそうだ。
パッチを作る
since 2012-07-12
いまさらながら Open JTalk 1.05 から NVDA 版ライブラリへのパッチを作る。
追加されたファイルは github を参照のこと。
htsengineapi も必要。
diff --git b/jpcommon/jpcommon_label.c a/jpcommon/jpcommon_label.c
index 97a8899..a9dcef0 100644
--- b/jpcommon/jpcommon_label.c
+++ a/jpcommon/jpcommon_label.c
@@ -105,7 +105,7 @@ static void JPCommonLabelPhoneme_convert_unvoice(JPCommonLabelPhoneme * p)
}
}
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabelPhoneme_convert_unvoice() in jpcommon_label.c: %s cannot be unvoiced.\n",
p->phoneme);
}
@@ -148,7 +148,7 @@ static void JPCommonLabelWord_initialize(JPCommonLabelWord * w, const char *pron
}
}
if (find == 0) {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabelWord_initializel() in jpcommon_label.c: %s is unknown POS.\n",
pos);
i = 0;
@@ -161,7 +161,7 @@ static void JPCommonLabelWord_initialize(JPCommonLabelWord * w, const char *pron
}
}
if (find == 0) {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabelWord_initializel() in jpcommon_label.c: %s is unknown conjugation type.\n",
ctype);
i = 0;
@@ -174,7 +174,7 @@ static void JPCommonLabelWord_initialize(JPCommonLabelWord * w, const char *pron
}
}
if (find == 0) {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabelWord_initializel() in jpcommon_label.c: %s is unknown conjugation form .\n",
cform);
i = 0;
@@ -270,6 +270,7 @@ static int index_accent_phrase_in_breath_group(JPCommonLabelAccentPhrase * a)
if (index == a)
break;
}
+ if (i > 3) i = 3;
return i;
}
@@ -369,6 +370,7 @@ static int count_mora_in_utterance(JPCommonLabelMora * m)
for (i = 0, index = m->next; index != NULL; index = index->next)
i++;
+ if (i > 10) i = 10;
return index_mora_in_utterance(m) + i;
}
@@ -393,8 +395,8 @@ static void JPCommonLabel_insert_pause(JPCommonLabel * label)
if (label->short_pause_flag == 1) {
if (label->phoneme_tail != NULL) {
if (strcmp(label->phoneme_tail->phoneme, JPCOMMON_PHONEME_SHORT_PAUSE) == 0) {
- fprintf(stderr,
- "WARNING: JPCommonLabel_insert_word() in jpcommon_label.c: Short pause should not be chained.\n");
+ HTS_error(0,
+ "WARNING: JPCommonLabel_push_word() in jpcommon_label.c: Short pause should not be chained.\n");
return;
}
label->phoneme_tail->next =
@@ -403,8 +405,8 @@ static void JPCommonLabel_insert_pause(JPCommonLabel * label)
label->phoneme_tail, NULL, NULL);
label->phoneme_tail = label->phoneme_tail->next;
} else {
- fprintf(stderr,
- "WARNING: JPCommonLabel_insert_word() in jpcommon_label.c: First mora should not be short pause.\n");
+ HTS_error(0,
+ "WARNING: JPCommonLabel_push_word() in jpcommon_label.c: First mora should not be short pause.\n");
}
label->short_pause_flag = 0;
}
@@ -433,7 +435,7 @@ void JPCommonLabel_push_word(JPCommonLabel * label, char *pron, char *pos, char
label->phoneme_tail->up->up->up->emotion = strdup(JPCOMMON_FLAG_QUESTION);
}
} else {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabel_push_word() in jpcommon_label.c: First mora should not be question flag.\n");
}
return;
@@ -458,7 +460,7 @@ void JPCommonLabel_push_word(JPCommonLabel * label, char *pron, char *pos, char
label->mora_tail = label->mora_tail->next;
label->word_tail->tail = label->mora_tail;
} else {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabel_push_word() in jpcommon_label.c: First mora should not be long vowel symbol.\n");
}
pron += find;
@@ -469,7 +471,7 @@ void JPCommonLabel_push_word(JPCommonLabel * label, char *pron, char *pos, char
if (label->phoneme_tail != NULL && is_first_word != 1)
JPCommonLabelPhoneme_convert_unvoice(label->phoneme_tail);
else
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabel_push_word() in jpcommon_label.c: First mora should not be unvoice flag.\n");
pron += find;
} else {
@@ -550,7 +552,7 @@ void JPCommonLabel_push_word(JPCommonLabel * label, char *pron, char *pos, char
}
pron += find;
} else {
- fprintf(stderr,
+ HTS_error(0,
"WARNING: JPCommonLabel_push_word() in jpcommon_label.c: %s is wrong mora list.\n",
pron);
break;
@@ -627,7 +629,7 @@ void JPCommonLabel_make(JPCommonLabel * label)
for (p = label->phoneme_head, label->size = 0; p != NULL; p = p->next)
label->size++;
if (label->size < 1) {
- fprintf(stderr, "WARNING: JPCommonLabel_make() in jcomon_label.c: No phoneme.\n");
+ HTS_error(0, "WARNING: JPCommonLabel_make() in jcomon_label.c: No phoneme.\n");
return;
}
label->size += 2;
diff --git b/njd2jpcommon/njd2jpcommon.c a/njd2jpcommon/njd2jpcommon.c
index 8f7798c..85f6d50 100644
--- b/njd2jpcommon/njd2jpcommon.c
+++ a/njd2jpcommon/njd2jpcommon.c
@@ -83,7 +83,7 @@ static void convert_pos(char *buff, char *pos, char *pos_group1, char *pos_group
return;
}
}
- fprintf(stderr,
+ HTS_error(0,
"WARING: convert_pos() in njd2jpcommon.c: %s %s %s %s are not appropriate POS.\n", pos,
pos_group1, pos_group2, pos_group3);
strcpy(buff, njd2jpcommon_pos_list[4]);
@@ -99,7 +99,7 @@ static void convert_ctype(char *buff, char *ctype)
return;
}
}
- fprintf(stderr,
+ HTS_error(0,
"WARING: convert_ctype() in njd2jpcommon.c: %s is not appropriate conjugation type.\n",
ctype);
strcpy(buff, njd2jpcommon_ctype_list[1]);
@@ -115,7 +115,7 @@ static void convert_cform(char *buff, char *cform)
return;
}
}
- fprintf(stderr,
+ HTS_error(0,
"WARING: convert_cform() in njd2jpcommon.c: %s is not appropriate conjugation form.\n",
cform);
strcpy(buff, njd2jpcommon_cform_list[1]);
diff --git b/njd_set_unvoiced_vowel/njd_set_unvoiced_vowel.c a/njd_set_unvoiced_vowel/njd_set_unvoiced_vowel.c
index 1dd01b0..c23153b 100644
--- b/njd_set_unvoiced_vowel/njd_set_unvoiced_vowel.c
+++ a/njd_set_unvoiced_vowel/njd_set_unvoiced_vowel.c
@@ -136,7 +136,7 @@ static int strcat_skip(char *buff, char *str, int *last_unvoiced_flag, int *mora
*last_unvoiced_flag = 1;
return strlen(NJD_SET_UNVOICED_VOWEL_QUOTATION);
}
- fprintf(stderr, "WARNING: strcat_voiced() in njd_set_unvoiced_vowel.c: Wrong pron.");
+ HTS_error(0, "WARNING: strcat_voiced() in njd_set_unvoiced_vowel.c: Wrong pron.");
return 1;
}
ライブラリ版のための makefile の修正:
diff --git b/Makefile.mak a/Makefile.mak
index 0f16444..33b9e9e 100644
--- b/Makefile.mak
+++ a/Makefile.mak
@@ -5,9 +5,9 @@ all:
cd text2mecab
nmake /f Makefile.mak
cd ..
- cd mecab
- nmake /f Makefile.mak
- cd ..
+ rem cd mecab
+ rem nmake /f Makefile.mak
+ rem cd ..
cd mecab2njd
nmake /f Makefile.mak
cd ..
@@ -38,12 +38,15 @@ all:
cd jpcommon
nmake /f Makefile.mak
cd ..
- cd bin
- nmake /f Makefile.mak
- cd ..
- cd mecab-naist-jdic
+ cd lib
nmake /f Makefile.mak
cd ..
+ rem cd bin
+ rem nmake /f Makefile.mak
+ rem cd ..
+ rem cd mecab-naist-jdic
+ rem nmake /f Makefile.mak
+ rem cd ..
clean:
cd text2mecab
@@ -85,7 +88,10 @@ clean:
cd bin
nmake /f Makefile.mak clean
cd ..
- cd mecab-naist-jdic
+ rem cd mecab-naist-jdic
+ rem nmake /f Makefile.mak clean
+ rem cd ..
+ cd lib
nmake /f Makefile.mak clean
cd ..
Windows版をつくる
執筆:2010-08-21
更新:2011-02-15
Open JTalk 1.02 対応。
Windows XP SP3 (32bit) + Cygwin 1.7.7 を使用。
github には ssh key 登録済みとするがダウンロードするだけなら http 経由でよい。
gcc-3 による mingw クロスコンパイルをやってみる。
$ /usr/bin/set-gcc-default-3.sh $ cd c:/work/github $ git clone git@github.com:nishimotz/htsengineapi.git $ git clone git@github.com:nishimotz/libopenjtalk.git
HTS Engine API
まず HTS Engine API から。
configure.ac の 69 行 AC_HAVE_LIBRARY([winmm],,AC_MSG_ERROR(No winmm)) をコメントアウト。その直後に
AC_DEFINE(AUDIO_PLAY_NONE)
を追加。
$ cd htsengineapi $ export CC=gcc-3 $ export CFLAGS=-mno-cygwin $ export LDFLAGS=-mno-cygwin $ ./configure $ make
./bin と ./lib にファイルができる。
libopenjtalk
つぎに libopenjtalk を。やろうとしているのは「オーディオ出力をしない」「mecab辞書をコンパイルしない」「mecab関連ディレクトリをコンパイルしない」「binの中の実行ファイルを作らない」という作業。
$ cd .. $ cd libopenjtalk
configure.ac の 268-275 行の先頭に # をつけてコメントアウト。
Makefile.am の SUBDIRS = につづく mecab bin mecab-naist-jdic という行をコメントアウト。
mecab/src/Makefile.am の MAINTAINERCLEANFILES から mecab-dict-index を消す。 下記をコメントアウトする。
#noinst_PROGRAMS = mecab-dict-index #mecab_dict_index_SOURCES = mecab-dict-index.cpp #mecab_dict_index_LDADD = libmecab.a
ビルド手順:
$ autoreconf $ autoheader $ aclocal $ automake $ autoconf $ bash do_configure_mingw32.sh $ make $ cd lib $ make -f Makefile.mingw32 $ strip libopenjtalk.dll
補足: do_configure_mingw32.sh の中身はだいたい下記の通り。
export CXX='g++ -mno-cygwin' export CC='gcc -mno-cygwin' ./configure --with-hts-engine-header-path=/cygdrive/c/work/github/htsengineapi/include \ --with-hts-engine-library-path=/cygdrive/c/work/github/htsengineapi/lib \ --build=i686-pc-mingw32 --with-charset=shift_jis
作業場所が c:/work/github でない場合は修正してください。
lib の中に jtalk.py がある(かも知れない)が、廃止予定。
nmake 対応
since 2011-10-15
nvda のビルドシステムへの統合 = scons 対応の一歩手前として、nmake でコンパイルできるようにした。
すでに元ファイルに Makefile.mak が含まれているので、若干の修正のみ。
https://github.com/nishimotz/libopenjtalk/commit/8f06316be72c4a412f1db4f299c2c4d24a246c71
https://github.com/nishimotz/htsengineapi/commit/5e2f3e7cae43498bdf648a61e91d0c22c36d0546
Windows SDK v7 コマンドシェルの初期状態では x64 をビルドしてしまうので、以下のように:
> setenv /x86 > cd htsengineapi > nmake -f Makefile.mak > cd .. > cd libopenjtalk > nmake -f Makefile.mak
DLL は libopenjtalk/lib の中に作られる。
Ubuntu 9.04 32bit
since 2010-12-10
github の htsengineapi を。
$ cd htsengineapi $ ./configure $ make $ cd ..
github の libopenjtalk は ubuntu_sjis ブランチで作業をしている。
$ git clone --origin github git@github.com:nishimotz/libopenjtalk.git $ cd libopenjtalk $ git checkout -b github/ubuntu_sjis
$ autoreconf $ automake $ autoconf $ sh do_configure_ubuntu.sh $ make $ cd lib $ make -f Makefile.ubuntu $ ls .libs/ libopenjtalk.a libopenjtalk.lai libopenjtalk.so libopenjtalk.so.0.0.0 libopenjtalk.la libopenjtalk.o libopenjtalk.so.0 $ cd ../../..
無駄を承知で launchpad.net の nvdajp のレポジトリを取ってくる:
$ mkdir launchpad-nvdajp $ cd launchpad-nvdajp $ bzr branch lp:~nishimotz/nvdajp/with_jtalk $ cd with_jtalk $ cd source/synthDrivers
_jtalk_core.py の "if _ _ name _ _ == '_ _ main _ _':" の数行あと:
# MECAB_DLL = "jtalk" + os.sep + "libmecab.dll" # JT_DLL = "jtalk" + os.sep + "libopenjtalk.dll" MECAB_DLL = "/usr/lib/libmecab.so.1" JT_DLL = "../../../../github/libopenjtalk/lib/.libs/libopenjtalk.so"
これで python _jtalk_core.py を実行すると _test.wav ができている。
play _test.wav すると音声が聞こえる。
リビジョン 3566 にて確認した。(2010-12-17)
ojt-python
2010-12-24
ojt-python は nvdajp の JTalk ドライバの土台のつもりだったが、このレポジトリを続けるかどうか検討中。
Python 2.7 および下記のライブラリを使う:
- comtypes-0.6.*.win32.exe
- pywin32-***.win32-py2.7.exe
mecab の準備
- http://sourceforge.net/projects/mecab/files/ から mecab-0.98.exe を入手してインストール。
- 辞書は Shift-JIS を選ぶ(実際にはmecab添付の辞書は libopenjtalk からは使わない)
- インストールディレクトリは C:\MeCab にしておく。
c:\work\jtalk に必要なファイルを揃える
- dic : Open JTalk の SJIS 辞書
- voice : Open JTalk の話者 m001
- libmecab.dll : mecab から。
- mecabrc : mecab から。ただしこのファイルは存在していれば中身はコメントだけでよい。存在しないとレジストリを見に行ってしまうため。
> type c:\work\jtalk\mecabrc ; ; Configuration file of MeCab ; ; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $; ; dicdir = $(rcpath)\..\dic\ipadic ; userdic = /home/foo/bar/user.dic ; output-format-type = wakati ; input-buffer-size = 8192 ; node-format = %m\n ; bos-format = %S\n ; eos-format = EOS\n
c:\work\jtalk\dic のディレクトリ 2010/09/03 00:05 <DIR> . 2010/09/03 00:05 <DIR> .. 2009/12/02 15:08 262,496 char.bin 2009/12/02 15:14 4,349 COPYING 2010/08/28 23:40 74 dicrc 2009/12/02 15:08 58,225 left-id.def 2009/12/02 15:08 3,792,262 matrix.bin 2009/12/02 15:08 1,477 pos-id.def 2009/12/02 15:08 6,241 rewrite.def 2009/12/02 15:08 58,225 right-id.def 2009/12/02 15:08 49,207,063 sys.dic 2009/12/02 15:08 5,409 unk.dic c:\work\jtalk\voice のディレクトリ 2010/09/03 00:05 <DIR> . 2010/09/03 00:05 <DIR> .. 2010/05/13 05:30 6,221 COPYING 2010/05/13 05:30 11,616 dur.pdf 2010/05/13 05:30 40 gv-lf0.pdf 2010/05/13 05:30 416 gv-mgc.pdf 2010/05/13 05:30 91 gv-switch.inf 2010/05/13 05:30 959 INSTALL 2010/05/13 05:30 105,104 lf0.pdf 2010/05/13 05:30 6 lf0.win1 2010/05/13 05:30 15 lf0.win2 2010/05/13 05:30 15 lf0.win3 2010/05/13 05:30 561,632 mgc.pdf 2010/05/13 05:30 6 mgc.win1 2010/05/13 05:30 15 mgc.win2 2010/05/13 05:30 15 mgc.win3 2010/05/13 05:30 6,794 README 2010/05/13 05:30 37,333 tree-dur.inf 2010/05/13 05:30 287 tree-gv-lf0.inf 2010/05/13 05:30 178 tree-gv-mgc.inf 2010/05/13 05:30 231,813 tree-lf0.inf 2010/05/13 05:30 95,250 tree-mgc.inf
実行は cygwin でなく Python for Win32 で行う:
> cd ojt-python > python jtalk_mingw32.py speaking text: こんにちは。 text2mecab: こんにちは。 Mecab_print size: 2 こんにちは,感動詞,*,*,*,*,*,こんにちは,コンニチハ,コンニチワ,5/5,C1 。,記号,句点,*,*,*,*,。,。,。,*/*,*
試行錯誤の記録
以下は cygwin (mingw32) 32bit DLLを作るためのコンパイル方法の覚え書き。
$ cd libopenjtalk $ ./configure --with-hts-engine-header-path=../htsengineapi/include/ \ --with-hts-engine-library-path=../htsengineapi/lib/ \ --with-charset=UTF-8 --build=i686-pc-mingw32
失敗。sys/mman.h と sys/times.hでwarningが出る。そしてwinmmがないというエラー。 その他で気になるのは iconv_open がない、というあたりか。
とりあえず winmm だけ削って先に進んでみることにした。
configure.acのしくみは資料を参考にした。
configure.ac の 268-275 行の先頭に # をつけてコメントアウト。
$ autoheader $ aclocal $ automake $ autoconf $ ./configure --with-hts-engine-header-path=../htsengineapi/include/ \ --with-hts-engine-library-path=../htsengineapi/lib/ \ --with-charset=UTF-8 --build=i686-pc-mingw32 $ make
しばらくすすむのだが、mecab が内部で g++ を呼び出しているらしく、失敗。
疲れてきたので、荒っぽい方法を選ぶ。
$ sh /usr/bin/set-gcc-default-3.sh
$ g++ -v Reading specs from /usr/lib/gcc/i686-pc-cygwin/3.4.4/specs Configured with: /managed/gcc-build/final-v3-bootstrap/gcc-3.4.4-999/configure --verbose --program-suffix=-3 --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,ada,c++,d,f77,pascal,java,objc --enable-nls --without-included-gettext --enable-version-specific-runtime-libs --without-x --enable-libgcj --disable-java-awt --with-system-zlib --enable-interpreter --disable-libgcj-debug --enable-threads=posix --enable-java-gc=boehm --disable-win32-registry --enable-sjlj-exceptions --enable-hash-synchronization --enable-libstdcxx-debug Thread model: posix gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
$ make clean $ make
mecab/src の中で失敗する。
mecab-dict-index を作れなくてこまっているようなので、また荒っぽいことをやる。
mecab/src/Makefile.am
MAINTAINERCLEANFILES から mecab-dict-index を消す。 下記をコメントアウトする。 #noinst_PROGRAMS = mecab-dict-index #mecab_dict_index_SOURCES = mecab-dict-index.cpp #mecab_dict_index_LDADD = libmecab.a
トップディレクトリで make clean; autoconf する。
さきほどの configure をやりなおす。
こんどは HTS_engine.h がないと怒られてとまる。
そうか、configure は相対パスじゃだめなのか。。。
$ ./configure --with-hts-engine-header-path=/cygdrive/c/work/github/htsengineapi/include \ --with-hts-engine-library-path=/cygdrive/c/work/github/htsengineapi/lib \ --with-charset=UTF-8 --build=i686-pc-mingw32
こんどは waveXXX がないと言われる。どうやらさきほどコンパイルした libHTSEngine.a が使ってしまったらしい。
/cygdrive/c/work/github/htsengineapi/lib/libHTSEngine.a(HTS_audio.o): HTS_audio.c:(.text+0xfe): undefined reference to `_waveOutWrite@12'
やっぱり winmm なしの libHTSEngine を作ることにする。
$ cd ../htsengineapi
configure.ac の 69 行 AC_HAVE_LIBRARY([winmm],,AC_MSG_ERROR(No winmm)) をコメントアウト。 その直後に
AC_DEFINE(AUDIO_PLAY_NONE)
を追加。
$ make clean $ autoconf $ ./configure --build=i686-pc-mingw32 $ make
うまくいったらしい。
$ nm lib/libHTSEngine.a | grep _wave
何も出てこない。
$ cd ../libopenjtalk
また怒られた。__getreent がないなど。
http://www.mail-archive.com/cygwin@cygwin.com/msg36709.html
なるほど。サブディレクトリで -mno-cygwin が外れてしまったらしい。
$ export CXX='g++ -mno-cygwin' $ export CC='gcc -mno-cygwin' $ make distclean $ ./configure --with-hts-engine-header-path=/cygdrive/c/work/github/htsengineapi/include \ --with-hts-engine-library-path=/cygdrive/c/work/github/htsengineapi/lib \ --with-charset=UTF-8 --build=i686-pc-mingw32 $ make
エラー。 mecab-naist-jdic が作れない。さきほど mecab-dict-index を削った影響。 どうせ辞書は別途ダウンロードできるはずなのでこれも削る。
Makefile.am の SUBDIRS = につづく mecab bin mecab-naist-jdic という行をコメントアウト
$ automake $ autoconf $ ./configure オプションは上と同じ
やっとコンパイルが通った。
