Ubuntu Weekly Recipe

第427回Twitterクライアントのmikutterに日本語を話してもらおう(後編)

今回は前回に引き続き、mikutterに関するレシピをお届けします。mikutterプラグインを書き、タイムラインにツイートが増える度に、その内容を音声出力するようにします。

プラグインの概要

本連載の第250回第251回では、日本語テキストから音声を合成し、サウンドサブシステムから出力しました。これらを処理するPython 2スクリプトを用意したわけですが、今回はこれをRubyに移植し、mikutterプラグインとして利用可能にします。

処理内容などはほぼ前回を踏襲します。すなわち、日本語テキストをMeCabを使って形態素解析し、辞書から発音を取得します。その結果を利用してMbrola向けに音素リストを作成し、mbrolaコマンドを使って音声を合成します。音声データはaplayを使ってサウンドサブシステムに出力します。

MeCabとMbrolaに関しては、本連載の第250回第251回を参照してください。

MeCabと辞書の準備

まずは、RubyスクリプトからMeCabを使えるようにします。MeCabにはRubyバインディングがあり、Ubuntuでは「ruby-mecab」パッケージとしてインストール可能です。以下のコマンドを実行し、インストールしてください。依存関係で、MeCab本体のパッケージもインストールされます。

$ sudo apt-get install ruby-mecab

次にMeCabが利用する辞書をインストールします。今回も「mecab-naist-jdic」を利用します。以下のコマンドを実行し、インストールしてください。

$ sudo apt-get install mecab-naist-jdic

システム上に辞書が複数存在する可能性があるため、第251回のAlternativeを使う手順に従って、デフォルトで使われる辞書を確認してください。

$ sudo update-alternatives --config mecab-dictionary
alternative mecab-dictionary (/var/lib/mecab/dic/debian を提供) には 2 個の選択肢があります。

  選択肢    パス                               優先度  状態
------------------------------------------------------------
* 0            /var/lib/mecab/dic/naist-jdic         100       自動モード
  1            /var/lib/mecab/dic/naist-jdic         100       手動モード
  2            /var/lib/mecab/dic/naist-jdic-eucjp   90        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:

これで、RubyスクリプトからMeCabを利用する準備が整いました。実際に利用できるかどうかを確認するために、以下のサンプルを実行してください。

#!/usr/bin/ruby

require 'MeCab'

msg = 'やあ、こっちに来ておくれよ、と彼は言う。'

tokenizer = MeCab::Tagger.new('-Owakati')
result = tokenizer.parseToNode(msg)

while result = result.next do
  p(result.surface, result.feature)
end

以下のような出力が得られたら成功です。

$ ./sample.rb
"やあ"
"感動詞,*,*,*,*,*,やあ,ヤア,ヤー,,"
"、"
"記号,読点,*,*,*,*,、,、,、,,"
"こっち"
"名詞,代名詞,一般,*,*,*,こっち,コッチ,コッチ,,"
"に"
"助詞,格助詞,一般,*,*,*,に,ニ,ニ,,"
"来"
"動詞,自立,*,*,カ変・来ル,連用形,来る,キ,キ,き/来,"
"て"
"助詞,接続助詞,*,*,*,*,て,テ,テ,,"
"おくれよ"
"動詞,自立,*,*,一段,命令yo,おくれる,オクレヨ,オクレヨ,おくれよ/後れよ/遅れよ,"
"、"
"記号,読点,*,*,*,*,、,、,、,,"
"と"
"助詞,格助詞,引用,*,*,*,と,ト,ト,,"
"彼"
"名詞,代名詞,一般,*,*,*,彼,カレ,カレ,,"
"は"
"助詞,係助詞,*,*,*,*,は,ハ,ワ,,"
"言う"
"動詞,自立,*,*,五段・ワ行促音便,基本形,言う,イウ,イウ,いう/云う/言う/謂う,"
"。"
"記号,句点,*,*,*,*,。,。,。,,"
""
"BOS/EOS,*,*,*,*,*,*,*,*"

Mbrolaの準備

次はMbrolaの準備です。まず「mbrola」パッケージをインストールします。

$ sudo apt-get install mbrola

次に、音声データベースをインストールします。日本語発音用データベースはUbuntuのリポジトリからは提供されていないため、Copying the MBROLA Bin and Databasesから、jp3をダウンロードします。

これでmbrolaを使う準備が整いました。実際に使えるかどうか、以下のサンプルを使って確認してみましょう。

w   55  0   400
a   55  0   400
t   55  0   440
a   55  0   440
S   75  0   440
i   75  0   440
w   75  0   400
a   75  0   400
m   75  0   400
i   75  0   400
k   75  0   430
u   75  0   430
_   75  0   400
t   75  0   400
a   75  0   420
a  500  0   420 20  440 40  400 60  440 80  400 100 440
tS  75  0   400
a   75  0   400
N   75  0   400
_   75

サンプルをsample.phoというファイルに保存し、以下のコマンドを実行してください。ここでは、サンプルとjp3データベースがカレントワーキングディレクトリに保存されたと仮定しています。

$ mbrola ./jp3/jp3 ./sample.pho -.raw | aplay -D default -r 22050 -c 1 -f S16_LE

「わたしはみくったーちゃん」と聞こえたら成功です。もし聞こえない場合は、psコマンドなどでPulseAudioサウンドサーバーが起動していることを確認してください。

なお上記コマンドを実行するとmbrolaプロセスがコアダンプします。筆者が確認する限りfree(3)やmunmap(2)の実行でSIGSEGVが送出されることから、プロセスのVMA上でバッファーオーバーランが発生し、不正な値がポインタに書かれたのだと思います。しかしUbuntuDebianのバグトラッキングシステムでは、類似のバグを見つけられませんでした。mbrolaは非オープンソースソフトウェアであり、ビルド済みバイナリのみが配布されています。そのため、これ以上の調査はできませんでした。今回のレシピは、この問題を無視して進めます。mbrolaは面白いソフトウェアであるだけに、残念です。

プラグインの作成

以上で準備が整いました。前回の最後のサンプルについて、プラグイン名とクラス名をそれぞれ「mecabrola」「Mecabrola」に変更しつつ、拡張します。以下がエントリーポイントとハンドラー部分です。

Mecabrola.create(:mecabrola) do
  onupdate do |service, messages|
    # Skip when several messages are going to be displayed.
    if messages.length() > 1 then
      next
    end
    if !messages[0].respond_to?('body') then
      next
    end
    # The array includes one message.
    tokens = self.tokenize_message(messages[0].body())
    lines = self.generate_pho_lines(tokens)
    handle = self.write_pho_file(lines)
    self.run_mbrola_aplay(handle)
  end
end

今回は簡便のため、1回のブロック呼び出しで1メッセージだけ処理します。まずMecabrolaクラスのインスタンスメソッド「tokenize_message」でMeCabを用いた形態素解析を行います。次に「generate_pho_lines」メソッドでMbrolaの音素リスト(phoフォーマット)のデータを生成します。⁠write_pho_file」メソッドで一時ファイルに書き出し、⁠run_mbrola_aplay」メソッドで音声合成と音声出力を行います。

Mecabrolaクラスの各メソッドの内部処理に関しては、割愛します。

プラグインの試験

以下がプラグインの圧縮アーカイブです。

mikutterの作法に従って「~/.mikutter/pluin/mecabrola」以下に配置してください。同じディレクトリにmbrolaのjp1あるいはjp3データベースも配置してください。

$ ls -1a ~/.mikutter/plugin/mecabrola/
.
..
.mikutter.yml
jp1
jp3
mecabrola.rb

mikutterを再起動すると、きっと何らかの音声出力が聞こえるはずです。おそらく、多くのツイート内容について、発声が途中で切れると思います。多くの場合、⁠与えたphoフォーマットデータ内のエントリーに、jp1/jp3データベースに収録されていない音素組み合わせがあり、処理を中断した」というのが原因です。これに関しては、本連載の第252回を参照してください。筆者のTLに流れてくるツイートから生成した音素組み合わせにおいて、よく見られたものは以下でした。

  • u-xo: フォロワーの「ふぉ」など
  • u-xe: ウェブの「うぇ」など
  • u-xi: イポンツィの「ツィ」など
  • dZ-_: じょうろの「じょ」など
  • S-j: 商標の「しょ」など
  • dZ-j: 順列の「じゅ」など

どのような組み合わせで終了しているかは、mikutterを--debugオプション付きで実行して確認できます。

$ mikutter --debug
...
Fatal error: Unkown recovery for e-xi segment
...

加えて、英単語は無声としているので発音されない点に留意してください。プラグインには他にも改善すべき点が多々ありますが、紙面の都合上、ここで開発を終えたいと思います。

まとめ

本レシピではTwitterプラグインであるmikutterのプラグインを書き、mikutterの機能を拡張しました。日本語テキストの自然言語処理、テキスト読み上げと言った学術領域の成果を援用し、プラグインの機能を実装しました。mikutterのプラグインは比較的書きやすいように思いましたので、みなさんも好みの機能を実装してmikutterに親しんでみるとよいでしょう。

おすすめ記事

記事・ニュース一覧