nvdajp_jtalk

2010-12-09 nvdajp の音声エンジン JTalk の開発メモをこちらに移動します。

JTalk 派生プロジェクト

概要

  • nishimotz 開発ブランチ at launchpad.net
    • 本家 2011.1 + 日本語対応ブランチ (2011-01より)
    • 本家が bzr で管理していないバイナリファイルなど
      • source/synthDrivers/jtalk の中身を含む nishimotz 版 miscdep
        • source/synthDrivers/jtalk/libopenjtalk.dll の詳細は libopenjtalk
        • Open JTalk 1.02 ベース+m001使用時の音素継続長の不具合回避
        • 標準エラー出力に HTS のワーニングが出るのを止めた
        • mecab 辞書の調整
          • 英単語辞書のチューニング、英文字列のローマ字読みに対応(暫定実装)
          • 英単語の辞書の無駄を省いたので容量が少し小さくなりました
      • DLLおよび辞書のベースとなるリビジョン(github) libopenjtalk htsengineapi
  • メンテナンス保留中
    • 本家NVDA + JTalk ブランチ(2010-12より)
      • メニューなどは日本語化されており、日本語エンジンを含むが、IME読み上げには非対応
  • 過去の開発ブランチ
    • nvdajp + JTalk ブランチ(2010-09から2010-12)
    • 過去の miscdep
      • nvdajp-miscdep-20110202v2.7z (Open JTalk 1.01 ベース)公開終了しました

TODO

以下に取り組みたい:

  • 英単語からカタカナに変換する処理の統合
    • ローマ字カナ変換を組み込む
  • テキスト解析の各ステップを再検討する
    • 各ステップを単体で動作確認できる _ _main_ _() を書いてみる
    • もし ssml 対応エンジンを作るならどこで何をするべきか?

以下は着手済み:

  • mecab が読み付与に失敗した形態素の後処理
    • 辞書への単漢字の追加によって不具合は緩和されている
  • スライダーを動かすような出力における音切れの改善
    • キーボードの左右キーで話速スライダーを動かすときは問題が起きない。マウスでドラッグすると出力キューがたまる。
    • lastIndex の処理と関係あったかも?
  • 話者モデルの切り替えに対応するリファクタリング
    • MMDAgent の話者モデルへの対応
    • lp:~nishimotz/nvdajp/with_jtalk rev 3575 で実現

jtalk_core

_jtalk_core.py はアプリケーション、OSに依存しない処理をまとめた。

  • 現在は ctypes で 32bit ポインタに依存する記述をしている

_nvdajp_jtalk.py は espeak ドライバに由来するコード。

覚え書き:

  • speak() の処理
    • _execWhenDone() にて出力キューに _speak() 関数オブジェクトを入れる
  • 出力キュー
    • bgThread / bgQueue が管理している
    • テキスト解析、波形生成、デバイス出力の処理を分けていない
  • _speak() の処理
    • isSpeaking = True にする
    • unicodedata.normalize('NFKC', msg) の実行。効果ある?
    • predic 適用(re.compile しておくと実行時に高速)
    • engdic 適用(re.compile しておくと実行時に高速)since rev 3563
    • 半角スペースで分割(応答の高速化を期待)
      • nvdajp_dic.dic1 にあれば nvdajp_dic.dic1[m][4] に置換
      • SJIS に変換
      • libjt_text2mecab()
      • Mecab_analysis(str)
      • libjt_synthesis() ここで残りの処理を実行
      • libjt_refresh()
    • isSpeaking = False に戻す
  • libjt_synthesis() の処理
    • オリジナルの Open JTalk の処理を、JPCommon_make_label() まで実行
    • JPCommon_get_label_size が2より大きい場合:
      • JPCommon_get_label_feature()
      • HTS_Engine_load_label_from_string_list()
      • HTS_Engine_create_sstream()
      • HTS_Engine_create_pstream()
      • HTS_Engine_create_gstream()
      • 音声波形のポインタと大きさを取り出す
      • trim_silence() を実行。文頭と文末の無音を除去
      • feed_func(buf) を実行。実体は player.feed() の呼び出し。
      • libjt_refresh() して buf を返す。
    • 備考
      • 処理の途中で isSpeaking が Falase になったら、その時点で処理を打ち切って None を返す
        • 新しい _jtalk_core.py では is_speaking を返す関数オブジェクトを渡している
      • JPCommon_get_label_size < = 2 のときには読みを持つ形態素が含まれていない、という知見。
  • speak() に渡る文字列は、画面表示が "CapsLock" であっても synthDriver に渡す前に "Caps Lock" のようにスペースを挿入してくれている。

naist-jdic

  • naist-jdic.csv について
    • 最後の2つのフィールド "0/4,C2"
    • 前者は "アクセント位置/モーラ数"
    • 後者はアクセント結合規則の適用に関する属性。GalateaTalkの aConType と等価。C0 にしておけばアクセント結合が起こらない、という話だが。。

履歴

2010-09-01 音声エンジン関連

2010-11-17 RateSetting

  • userConfig/nvda.ini の [speech] [jtalk] があって rate というプロパティがないと落ちるらしい
  • jtalk.pyの_set_rate()が呼ばれるときにintでなくてfloatを受け取っていた。_jtalk.pyの中で割り算をした結果がfloatになりctypesにうまく渡せず。。やっとわかった。
  • lp:~nishimotz/nvdajp/with_jtalk リビジョン 3536 をpushしました

話速はフレームシフトの変更で行っている。

  • Open JTalk の標準フレームシフトは 80 samples (5ms at 16KHz サンプリングレート)
  • NVDA の話速(speechrate)は 0-100 で設定。
  • サンプル数 = 80 - (speechrate / 2) としている
    • _jtalk.py の OpenJTalk_synthesis()
  • 話者モデル m001 の場合の実測値(複数の文の出力における継続時間の平均)
    • s5 speechrate = 100 : 22.8 モーラ/sec (フレームシフト 30 samples)
    • s4 speechrate = 85 : 18.0 モーラ/sec (フレームシフト 38 samples)
    • s3 speechrate = 70 : 15.2 モーラ/sec (フレームシフト 45 samples)
    • s2 speechrate = 55 : 12.9 モーラ/sec (フレームシフト 53 samples)
    • s1 speechrate = 40 : 11.3 モーラ/sec(フレームシフト 60 samples)
  • 上記から推定すると
    • speechrate = 50 で約 12.5 モーラ/sec (フレームシフト 55 samples)
    • speechrate = 0 で約 8.6 モーラ/sec (フレームシフト 80 samples)

2010-11-17 rate プロパティがないエラー

バージョンアップして rate プロパティがない場合の nvda.log のエラー。

configobj.py を直せたらいいと思うのですが。。

Initializing speech
ERROR - synthDriverHandler.setSynth (14:20:05):
setSynth
Traceback (most recent call last):
  File "C:\work\nvdajp\lp\devinstaller\nvda\nvda\source\synthDriverHandler.py", line 77, in setSynth
    newSynth.loadSettings()
  File "C:\work\nvdajp\lp\devinstaller\nvda\nvda\source\synthDriverHandler.py", line 413, in loadSettings
    [setattr(self,s.name,c[s.name]) for s in self.supportedSettings if not s.name=="voice" and c[s.name] is not None]
  File "C:\work\nvdajp\lp\devinstaller\nvda\nvda\source\configobj.py", line 583, in __getitem__
    val = dict.__getitem__(self, key)
KeyError: 'rate'

2010-11-19 nvdajp_jtalk に変更

バージョンアップ時のエラーを回避する。

本家をマージしないままの作業で恐縮ですが、

lp:~nishimotz/nvdajp/with_jtalk

リビジョン 3538 をpushしました。

ini ファイルに書き込まれるエンジン名を nvdajp_jtalk にしました。 ファイル名も揃えた方がよさそうだったので、 jtalk.py を nvdajp_jtalk.py に、 _jtalk.py を _nvdajp_jtalk.py に付け替えました。

他のファイルはいじっていません。 configobj.py を直そうかと思ったのですが、 値が見つからない場合に何らかのデフォルト値を与えなくてはならず、 変なことをすると副作用がありそうなので、やめておきます。

ソースから実行するときには pyc を消さないと、 エンジンが二つ現れて変なことになります。。

今回、音声設定には espeak と同じようにすべての設定項目が 現れますが、実際に変更できるのは速度の設定だけで、 あとはダミーです。 ini ファイルにはすべての項目が書き込まれるので、 今後、機能を追加しても、起動エラーは回避できると思います。

2010-11-23

with_jtalk ブランチのリビジョン 3540

  • 実装ファイルが nvdajp_jtalk.py _nvdajp_jtalk.py _jtalk_core.py の3つになった

2010-11-27

with_jtalk ブランチのリビジョン 3543

  • rate から fperiod を求める処理を nvdajp_jtalk.py に移した
  • speak() にあったテキスト前処理を _speak() に移した。応答速度が改善?
  • OpenJTalk_synthesis() で buf を返すので refresh を外でやってもらうようにした。

2010-12-05

with_jtalk ブランチのリビジョン 3563

  • _jtalk_core.py の整備 libopenjtalk
    • thres 64 → 128 にしたので、すこしレスポンスが良くなった印象
  • 英単語からカタカナに変換する処理の修正
    • jtalk/bep-eng.dic を jtalk/eng_dic_maker.py で _nvdajp_eng_dic.py に事前に変換する
    • 文字数の長いパターンから短いパターンに向かって順番に適用していく、という単純な処理。
    • predic に含めていたアドホックな英単語の読み付与を jtalk/eng_dic_maker.py に移動。
  • その他読み付与
    • 「マイ コンピュータ」 → 「マイコンピュータ」など
    • 現状ではスペース区切りでエンジンに送る命令を分割している
    • 一気に読ませたいものは predic でスペース削除しておく
  • 50000件の辞書を読み込むので起動に時間がかかってしまう。今後の課題

2010-12-16

with_jtalk ブランチのリビジョン 3565

  • mecab 辞書に bep-eng.dic を追加した。
    • ただしアクセント型は全部 0 型にしている
    • 辞書のコンパイルは Ubuntu 9.04 の mecab でやっている。
    • 使用したスクリプトは libopenjtalk (github) にコミットした
  • _jtalk_core.py からは英語辞書は読み込まないようになった。エンジン起動は高速化。

2010-12-18

with_jtalk ブランチのリビジョン 3568

  • 文字列の途中で読み上げが終わってしまうことがある、という不具合を解決した(つもり)
    • 再現方法:Firefox で [NVDAキー]+[カーソル下]のカーソル位置から最終まで読み上げコマンド
    • スピーチビューアで DTalker (SAPI5) と挙動を比較したら違いがわかる。
    • _get_lastIndex() が実装されていないことが原因と思われる。
  • 実装内容:speakText() で受け取った index を _speak() の処理終了時に lastIndex グローバル変数に代入する。

2010-12-30 synthDrivers

2010-12-01 の本家 Changeset main,3962 から orderedDict が使われるようになった。

http://www.nvda-project.org/changeset/main,3962

http://docs.python.org/whatsnew/2.7.html#pep-0372

これにより jtalk は最新ブランチとの互換性がなくなっている。

http://www.nvda-project.org/changeset/main,3977 SAPI 関連のfixあり

lp:~nishimotz/nvdajp/main 3533 にて解決。

http://bazaar.launchpad.net/~nvda-core-dev/nvda/main/revision/3995 本家が silence.py を直した。あっさり1行で。。2011-01-04

nvdajp_jtalk.txt · 最終更新: 2011/04/21 09:48 by Takuya Nishimoto
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0