目次
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 オプションは上と同じ
やっとコンパイルが通った。