Pages

2013年10月31日木曜日

Emacsでlookupで検索したのをfestivalでしゃべらせる

英語を辞書で調べたら発音がききたいので調べていた。
espeak は英語ぽくなかたったので、 festival を利用することにした。

参考サイト:
https://help.ubuntu.com/community/TextToSpeech
http://www.cstr.ed.ac.uk/projects/festival/manual/festival_toc.html

インストール

apt-getでインストールした。festvox-us1は女性の声でしゃべってくれる。
別にむさいおっさん声でいいなら必要ない。
女性の声もちょっとおばさんっぽいけど。。。

apt-get install festival festvox-us1

コマンドラインからつかう

echo "hello" | festival --tts

でも使えるし

$ festival
festival> ...

Festival コマンドで起動してあとから

(SayText "hi")

とかできる。
この時

(voice.list)

で使用可能な声のリストを見れる。
コマンドがなんかlispっぽい

Emacsから使う

festival.elパッケージをel-getからインストールした。
下のような設定をしているけどまだ使いはじめたばかりで変えるかもしれない。
取り敢えず注意点として、文字列内に"を含んでるとだめだった。
下の設定を使うには mine.el パッケージが必要です。(宣伝)
my/festivalコマンドはコマンドを実行する位置によってミニバッファから文
字列を指定して実行したり、フォーマットしたリージョン文字列をfestivalに
渡したりする。
my/festival-read-bufferはbufferの文字列をfestivalに読ませる。

(eval-when-compile (require 'cl))
(require 'festival)

(defvar my/festival-ignore-list
'(("[^0-9$a-zA-Z'\.#\+=\-]" . " ")
("###" . " ")
("\+\+\+" . " ")
("===" . " ")))

(defun my/festival (&optional txt)
"Read by festival from TXT or user input.
If user was selected region then pass region's words to festival."
(interactive)
(if (festivalp)
(let* ((replace
(lambda (from to str)
(replace-regexp-in-string from to str)))
(format
(lambda (text)
(loop with result = text
for (from . to) in my/festival-ignore-list
do (setq result (funcall replace from to result))
finally return result)))
(say
(lambda (text)
(festival-say (funcall format text)))))
(mine
:default '(funcall say (or txt (read-string "say: " (word-at-point))))
:region-handle-flag 'copy
:region '(funcall say mine:region-str)))
(festival-start)))

(defun my/festival-read-buffer ()
"Read from buffer's strings by using festival."
(interactive)
(mine
:default '(my/festival (buffer-string))
:C-u '(progn ; reset
(festival-stop)
(sleep-for 3)
(my/festival (buffer-string)))))

僕のlookup.elの呼び出し関数は、下のような感じなので(これもmine.elを…)

(defun my/lookup (&optional word)
"Search English word's meaning from my dictionaries.
If user specified WORD then search form it."
(interactive)
(let* ((ask (lambda ()
(read-string "lookup: " (word-at-point)))))
(if word
(lookup-pattern word)
(mine
;; カーソルの単語かユーザーに問い合わせする
:default '(lookup-pattern (or (word-at-point) (funcall ask)))
;; C-uを押してからの場合ユーザーに問い合わせした単語から調べる
:C-u '(lookup-pattern (funcall ask))
;; リージョン選択してる時はリージョンから
:region-handle-flag 'copy
:region '(lookup-pattern mine:region-str)))))

下のようなadvice関数を追加すれば、辞書検索するついでにその単語をしゃべ
るようにできました。

(defadvice lookup-pattern  (around ad-say-by-festival activate)
"Speak text that user is searching."
(condition-case error
(my/festival (ad-get-arg 0))
(error))
ad-do-it)

起動しなくなったら

メッセージを保存してなかったので不確かなのですが、

`(festival_warranty)'  segmentation fault (core dumped)

のようなメッセージがでてfestivalを起動できなくなったことがありました。
どちらが影響していたかわからないのでですが
~/.festival_historyと/var/crash/_usr_bin_festival.1000.crashを
削除したら起動できるようになりました。(自分用忘れぼうし)


0 件のコメント:

コメントを投稿