前回より男声パラメータにピッチ指定が追加されています。これがないと変な声になる模様。
『ゆっくり』などのテキスト読み上げは有名なんだけど、いかんせん内部エンジンが商用ソフトだ。フリー配布されているとはいえ安心して使えないし未来における保証もない。クローズドという事はそのメーカーが消えてしまえばそれまでだからだ。
ゆえにフリーソフトウェアなものを求めていた。この種のものだと大学系の研究成果なんかかな、と思っていたら、それに近い種類と思われるものがきっちり存在した。それが今回話題のOpenJTalkだ。もちろん、さっそく使わせてもらう事にした。
インストールと簡易呼び出しスクリプトの基本は、以下のサイトの情報を参考にさせてもらった。Debian squeezeで試しているがWheezyでもこの記事直している時点では問題ないだろう。
http://pochi.usamimi.info/linux/open_jtalk.html
なお上記サイトとうちのスクリプトの違いは、再生スクリプトをひとつにまとめた事、あとその場でコマンドライン版 alsaplayer を呼び出し再生している事の二点だ。うちは「その場で適当に読み上げてほしい」わけで、このサイトの方のように読み上げwavファイルが欲しいわけではないから、ここだけちょっと細工した。
インストール条件において MeCab の必要性を聞いた事があるが、解説しているサイトの記述によると組み込まれているわけで別途入れる必要はないとの事だ。まぁどちらにせよ、うちのPCには MeCab は入っているわけで、ない場合どうなるかの検証はまた別の機会に。
ではインストールに入る。基本的に上記サイトさんの記事のコピペであるが、私が実際にどうしたかのメモに近いので、その部分だけはあからさまに違うので要注意。
OpenJTalkは「内部で呼び出しているエンジンのインストール」→「OpenJTalk本体のインストール」→「音声ファイル他のインストール」という手順を踏むようだ。特に最初のエンジンのヘッダがないとOpenJTalkはそもそもコンパイルできない。
以下のバージョン等は 2011/5/12時点のものです。
もちろん、それぞれに最新版がある場合はそれを入手。ただしパッチの摘要などはもちろんその最新版の事情に添う必要があります。
まずこいつを入れないとOpenJTalkがコンパイルできない。
$ tar zxvf hts_engine_API-1.05.tar.gz $ cd ./hts_engine_API-1.05 $ ./configure $ make $ sudo checkinstall
参考にしたサイトさんのパッチは1.03用ですが、該当部分は変わらないようなので念のために現在もあてています。
--- open_jtalk-1.04/jpcommon/jpcommon_label.c 2011-04-29 14:08:32.000000000 +0900 +++ jpcommon_label.c 2011-05-01 19:55:40.000000000 +0900 @@ -270,6 +270,7 @@ if (index == a) break; } + if (i > 3) i = 3; return i; } @@ -369,6 +370,7 @@ for (i = 0, index = m->next; index != NULL; index = index->next) i++; + if (i > 10) i = 10; return index_mora_in_utterance(m) + i; }
参考元サイトさんは、 jpcommon_label.diff という名のファイルを作って上をコピペ、パッチをあてれば簡単といってます。個人的にも同意なのでさっそく便乗。
$ patch < jpcommon_label.diff
さて、インストール本番だ。
$ cd ../ $ ./configure --with-charset=UTF-8 $ make $ sudo checkinstall
辞書ファイル、それから音声ファイル(追加でもらってきたやつ含めて二種類)を展開します。
辞書ファイル(open_jtalk_dic_utf_8-1.04.tar.gz) を作業用ディレクトリに置いて展開し、出来たディレクトリを /usr/local/share/open_jtalk へ配置します。
$ tar zxvf open_jtalk_dic_utf_8-1.04.tar.gz $ sudo mkdir /usr/local/share/open_jtalk $ sudo mv ./open_jtalk_dic_utf_8-1.04 /usr/local/share/open_jtalk/
hts_voice_nitech_jp_atr503_m001-1.04.tar.gz を作業用ディレクトリに置いて展開し、 出来たディレクトリを /usr/local/share/hts_voice へ配置します。(元サイトと少しだけ違うので注意してください)
$ tar zxvf hts_voice_nitech_jp_atr503_m001-1.04.tar.gz $ sudo mkdir /usr/local/share/hts_voice $ sudo mv ./hts_voice_nitech_jp_atr503_m001-1.04 /usr/local/share/hts_voice/
MMDAgent_Example-1.0.zip を作業用ディレクトリに置いて展開し、MMDAgent_Example-1.0/Voice/mei_normal を /usr/local/share/hts_voice へ配置します。
$ unzip MMDAgent_Example-1.1.zip $ sudo mv ./MMDAgent_Example-1.1/Voice/mei_normal /usr/local/share/hts_voice/
これでインストール完了ですが、あいかわらずのオプションの多さには私も驚きました。というわけで、動作支援スクリプトを書きます。今回ちょっとだけ改良、前回のPerlものを参考にRubyの需要があったのでRubyで書きました。
元サイトさんのものがベースになっていますが、一部のパラメータを追加しています。
使い方は以下の通り。
(通常) $ openjtalk.rb こんにちは (同上) $ openjtalk.rb M:こんにちは (女性) $ openjtalk.rb F:ゆっくりしていってね
最初にF:とつけるとMMDAgentのサンプル音声を使います。M:をつけると明示的に標準を使いますが、デフォルトはこちらにしてありますので、F:指定するか無印か、でOKです。コードを流用される時にお好きなようにしてください。
なお、呼び出している alsaplayer はテキスト版( alsaplayer-text )です。モノラルのwavを再生する小さなものなら何でもいいでしょう。
二つに分かれています。まずはUI部。
(openjtalk.rb)
#!/usr/bin/ruby require 'open_jtalk.rb' ARGV.each{|x| x2 = "#{x}" openjtalk(x2) }
そして、以下が本体。
(open_jtalk.rb)
#!/usr/bin/ruby =begin I/F: openjtalk(sex,seq) sex: Male/Man/M/Female/F/Women/W/"" seq: 文字列 =end $ojt_audioplayer = "/usr/bin/alsaplayer --quiet" def ojt_getParam(x) # path = "/usr/local" hontai = path+"/bin/open_jtalk" m_voice = path+'/share/hts_voice/hts_voice_nitech_jp_atr503_m001-1.04' f_voice = path+'/share/hts_voice/mei_normal' voice = m_voice sex = "M" dic = path+'/share/open_jtalk/open_jtalk_dic_utf_8-1.04' #dic = ENV['HOME']+'/.openjdic' tmpdir = "/tmp" infile = "#{tmpdir}/in#{$$}.txt" outfile = "#{tmpdir}/out#{$$}.wav" # if x =~ /(F(emale){0,1}|W(omen){0,1})/i sex = "F" end # s = [] if sex == "M" s = [ "-x #{dic}", "-td #{voice}/tree-dur.inf", "-tm #{voice}/tree-mgc.inf", "-tf #{voice}/tree-lf0.inf", "-md #{voice}/dur.pdf", "-mm #{voice}/mgc.pdf", "-mf #{voice}/lf0.pdf", "-dm #{voice}/mgc.win1", "-dm #{voice}/mgc.win2", "-dm #{voice}/mgc.win3", "-df #{voice}/lf0.win1", "-df #{voice}/lf0.win2", "-df #{voice}/lf0.win3", "-a 0.075", # 高低? "-ow #{outfile}", "-em #{voice}/tree-gv-mgc.inf", "-ef #{voice}/tree-gv-lf0.inf", "-cm #{voice}/gv-mgc.pdf", "-cf #{voice}/gv-lf0.pdf", "-k #{voice}/gv-switch.inf" ] else voice = f_voice s = [ "-x #{dic}", "-td #{voice}/tree-dur.inf", "-tm #{voice}/tree-mgc.inf", "-tf #{voice}/tree-lf0.inf", "-tl #{voice}/tree-lpf.inf", "-md #{voice}/dur.pdf", "-mm #{voice}/mgc.pdf", "-mf #{voice}/lf0.pdf", "-ml #{voice}/lpf.pdf", "-dm #{voice}/mgc.win1", "-dm #{voice}/mgc.win2", "-dm #{voice}/mgc.win3", "-df #{voice}/lf0.win1", "-df #{voice}/lf0.win2", "-df #{voice}/lf0.win3", "-dl #{voice}/lpf.win1", "-ow #{outfile}", "-a 0.075", # 高低? "-u 0.0", # 有声化・無声化? "-em #{voice}/tree-gv-mgc.inf", "-ef #{voice}/tree-gv-lf0.inf", "-cm #{voice}/gv-mgc.pdf", "-cf #{voice}/gv-lf0.pdf", "-jm 0.5", # 大小? "-jf 1.2", # 抑揚? "-k #{voice}/gv-switch.inf" ] end r = s.join(" ") [outfile,hontai + " " + r] end def openjtalk(x) if x != nil && x != "" sex = "M" if x =~ /^(F(emale){0,1}|W(omen){0,1}):/i sex = "F" end s = ojt_getParam(sex) x.gsub! /^(M|F):/,'' system("echo \"#{x}\" | #{s[1]} 1> /dev/null 2> /dev/null") if File.exist?(s[0]) == true system("#{$ojt_audioplayer} #{s[0]} 1> /dev/null 2> /dev/null") File.unlink(s[0]) end end end
1.03の頃のスクリプトをそのまま利用していると変な音声になる事があります。ピッチシフトをちゃんと指定していないとおかしくなるようなので、女声側のパラメータのコピペでもいいのでもらって指定してみてください。