9月 26
はじめに
Sayコマンドより、日本語で話す方法は無いかと探してました。
嬉しいことに、先人の方がsaykanjiで実装してましたので、ちょっと改造することにしました。
-2009.09.26 仮版
-2009.10.03 修正:マルチバイト文字列の不具合修正 (gsedに変更)
-2009.10.10 追記:アクセント付き文字列
目的
- 英単語混じりな文章をsaykanaで発音可能にする。
改造概要
- ベースはsaykanjiのスクリプトを改造する。
- NADのカタカナ英語辞書 10.6+を使用する。
役割、英単語をカタカナ読みに変換する辞書です。(素晴らしい)
10.6+のバージョンアップ版を使用する。
~/Downloadsに展開してることを前提にしてます。
このファイルは改行コードがmac仕様になってるので、変換が必要です。
grep等で検索できないので、スクリプト内で変換します。
(UNIX改行でUTF-8の出力を指定する)
- NADのカタカナ英語辞書 10.6+を使用する。
- kshの関数としてロード可能にする。
- スクリプト指定でも実行可能にする。
動作環境
- OS
OS CPU 備考 Mac OSX 10.6 以上 Intel Mac MacBook Mac OSX 10.5 以上 PowerPC PowerBook G4 - ksh (pdksh,ksh93)が使用可能な環境
OS 設定方法 説明 Mac OSX cd /usr; ln -s /bin/ksh /usr/bin/ksh として使う - Macport で使用したソフト
ソフト名 バージョン 用途 nkf 2.0.9-20090426_0 辞書データ(.csv)のUTF/UNIX改行変換に使用 mecab 0.96_0 UTF8使用可能にする mecab-ipadic-utf8 2.7.0-20070610_0 辞書データ gsed 4.2.1_0 マルチバイト文字列の不具合対策 - mecab : /opt/local/lib/mecab/dic/ipadic-utf8/dicrcの修正
「私は」の変換が「ワタクシハ」になるので「ワタクシワ」に変更する。定義内容 備考 ;node-format-yomi = %pS%f[7] コメント node-format-yomi = %pS%f[8] こちらを有効にする。
- mecab : /opt/local/lib/mecab/dic/ipadic-utf8/dicrcの修正
機能
実装機能
- 起動オプション:saykana の起動オプションが使用可能なこと。
- 辞書登録:辞書に登録されていない単語を容易に登録できる様にすること。
- その他
未実装機能
- 記号の発音ができない。
起動オプション
saykanji.sh スクリプトの初期値変更で動作変更が可能です。
| オプション名 | 説明 | 備考 |
| -S <n> | 字幕表示 1:原文表示,2:1+音声文表示 | |
| -C | 辞書に未登録な単語のデータを作成 | ${SK_UNDICT}にテンプレートを作成する。デフォルト ON |
| -M | -C で作成したデータを辞書に登録する | 読みの「XX」は未登録として扱わない |
| -d | 数値文字を桁表現で発音する。指定時on。 | デフォルト off |
| -f <filel> | 指定した<file>を行単位で読込み音声に変換する | |
| -v <voice> | SayKanaのオプション f1:女性,m1:男性 | デフォルト m1 |
| -s <speed> | SayKanaのオプション [50-300] | デフォルト100 |
使用例
- 未登録な単語を指定した場合
$ saykana.sh 私の名前はhogehogeです。 "XX","hogehoge","無品詞" ~/Develop/cvsroot/tool/saykanji/unknown.csv:[未登録データ件数: 1]
- hogehogeが未登録なので、~/Develop/cvsroot/tool/saykanji/unknown.csvをエディタで開き編集します。
変更前 "XX","hogehoge","無品詞" 変更後 "ほげほげ","hogehoge","無品詞" - 再度実行する。
$ saykana.sh 私の名前はhogehogeです。
- hogehogeが未登録なので、~/Develop/cvsroot/tool/saykanji/unknown.csvをエディタで開き編集します。
- 字幕表示
- 原文表示
$ saykana.sh -S 1 私の名前はhogehogeです。 原文:私の名前はhogehogeです。
- 原文+音声文表示
$ saykana.sh -S 2 私の名前はhogehogeです。 原文:私の名前はhogehogeです。 音声: ワタクシ ノ ナマエ ワ ほげほげ デス 。
- 原文表示
- 数値の桁表現をする。(なんか変) (字幕表示)
$ ./saykanji.sh -S 2 -d 缶ジュースは120円です 原文:缶ジュースは120円です。 音声: カン ジュース ワ <numk VAL=120> エン デス 。
- ファイルを読ませる
$ ./saykanji.sh -f readme.txt
- Mac OSX: 青空文庫読み上げスクリプトで使ってみる。
アクセント付き文字列
以下のサイトを拝見すると、簡単には作れなさそうです。
要はSaykanaに渡すアクセント付きの文字列を取得手段が欲しいだけなんですが、
ぼちぼちと作るには、荷が重そう。
- 音声合成に必要な技術
- 形態素解析 UniDic
- GalateaTalk(GTalk) 音声合成
Chaon (音韻変換)を改造すれば「アクセント付きの文字列」が取れそう。
備考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | #!/usr/bin/ksh # $Id: saykanji.sh,v 1.8 2009/10/03 11:15:04 shimizu Exp $ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/local/bin:/usr/local/bin:~/bin SAYKANA=/usr/local/bin/saykana # 元辞書 # 入手先: http://nadroom.blog.shinobi.jp/Entry/91/ DICT=~/Downloads/カタカナ英語辞書10.6+/NADのカタカナ英語辞書10.6.txt # 辞書 # お使いの環境に応じて修正して下さい。 SK_DICT=~/Develop/cvsroot/tool/saykanji/kana.csv # 辞書 SK_UNDICT=~/Develop/cvsroot/tool/saykanji/unknown.csv # 辞書未登録単語集 _sk_opt_setup=0 # 初回のみ、動くなら0にして下さい。 ############################################################################## _sk_opt= _sk_opt_LOD=0 # -L Load のみ _sk_opt_VER=0 # -V 処理内容を表示 _sk_opt_SUB=0 # -S <n> (字幕表示: 1:原文表示, 2:1+音声文字表示) _sk_opt_CHK=1 # -C (辞書未登録な単語のデータ作成: 0:on, 1:off) # 1) ${SK_UNDICT} の「読み」を編集して下さい。 # (デフォルトでは読み部分が、XX ($_sk_unknown)になってます。) # 2) -M 指定又はONの時、次回起動時に${SK_DICT}に登録します。 _sk_opt_MRG=1 # -M (辞書未登録な単語を${SK_DICT}に登録する) _sk_opt_digit=0 # -d (数値桁表現音声: 0:on, 1:off) _sk_opt_file=0 # -f <file> (指定ファイルの音声出力) _sk_opt_voice="-v f1" # -v (SayKanaのオプション: f1=女性,m1=男性) _sk_opt_speed="-s 100" # -s <n> (SayKanaのオプション: speed [50-300]) _sk_unknown_word="チョメチョメ" # 辞書未登録な単語の読み方 [発音します] # : -C 指定時に使用 _sk_unknown="\"XX\"" # 辞書未登録な単語のデータ作成 # : ${SK_UNDICT}作成時に使用 # 使用するコマンドのチェック (簡易版) function _sk_cmd_check # <command> { typeset _leng=$(which $1); if [[ ${#_leng} -eq 0 ]]; then echo "Not Found : $1 : インストール又はパスを通して下さい" exit 2 fi } # 辞書&コマンドの存在確認 # ${SK_DICT} 辞書が無かったら作成する function _sk_setup # { if [[ -r ${DICT} ]]; then if [[ ! -f ${SK_DICT} ]]; then _sk_cmd_check mecab _sk_cmd_check grep _sk_cmd_check mv _sk_cmd_check sort _sk_cmd_check nkf _sk_cmd_check gsed nkf -Lu -w ${DICT} > ${SK_DICT} touch ${SK_UNDICT} fi else echo "Not Found : ${DICT}" exit 2 fi } # 英字判定 function _sk_isalpha # { typeset _ret; _ret=$(echo $1 | tr -d '[[:alpha:]]') echo ${#_ret} } # 数字判定 function _sk_isdigit # { typeset _ret; _ret=$(echo $1 | tr -d '[[:digit:]]') echo ${#_ret} } function _sk_lex_string # <string>... { typeset _result; typeset _word; typeset _yomi; (echo "$*" | mecab -O wakati | mecab -O yomi | gsed 's/ /\n/g' ) | while read _word ; do if [[ $(_sk_isalpha ${_word}) -eq 0 ]]; then _yomi=$(grep -i "\"${_word}\"" $SK_DICT | head -1 | cut -d',' -f1 | gsed 's/"//g') if [[ -n ${_yomi} ]]; then _word=${_yomi}; elif [[ ${_sk_opt_CHK} -eq 1 ]]; then echo "${_sk_unknown},\"${_word}\",\"無品詞\"" >> $SK_UNDICT [[ ${_sk_opt_VER} -eq 1 ]] && echo "${_sk_unknown},\"${_word}\",\"無品詞\"" _word=${_sk_unknown_word} # 知らない単語はxxになる。 fi elif [[ $(_sk_isdigit ${_word}) -eq 0 && ${_sk_opt_digit} -eq 1 ]]; then _word="<numk VAL=${_word}>" fi _result="${_result} ${_word}" done (( ${_sk_opt_SUB} >= 1 )) && echo "原文:$*" (( ${_sk_opt_SUB} >= 2 )) && echo "音声:${_result}" (saykana ${_sk_opt} "${_result}") 2>&1 > /dev/null } function _sk_make_uniq_file # <file> { typeset _file=$1; if [[ -f ${_file} ]]; then sort -u ${_file} > ${_file}.$$ mv ${_file}.$$ ${_file} fi } function _sk_lex_file # </file><file> { typeset _file=$1; typeset _buf; # 入力ファイルを出力し字句解析する。 # (nkf -Lu -w ${_file)) として、UTFに変換した方がよいかも? # (cat ${_file}) | (nkf -Lu -w ${_file}) | while read _buf; do _sk_lex_string ${_buf} done } function _sk_word_regist # ${SK_DICT} ${SK_UNDICT} { typeset _dict=$1; typeset _undict=$2; (grep -v "${_sk_unknown}" ${_undict}) | while read _buf; do echo "${_buf}" >> ${_dict} done (grep "${_sk_unknown}" ${_undict}) > ${_undict}.$$ mv ${_undict}.$$ ${_undict} } function saykanji # <option> <string>... { typeset _opt; typeset _word; typeset _tmp; #################################### #・前処理 # 1) 起動オプションの確認 while getopts ":LVS:CMdhf:v:s:" _opt; do case $_opt in L) _sk_opt_LOD=1 ;; V) _sk_opt_VER=1 ;; S) _sk_opt_SUB="$OPTARG" ;; C) _sk_opt_CHK=1 ;; M) _sk_opt_MRG=1 ;; f) _sk_opt_file="$OPTARG" ;; d) _sk_opt_digit=1 ;; v) _sk_opt_voice="-v $OPTARG" ;; s) _sk_opt_speed="-s $OPTARG" ;; h|?) printf "Usage: %s: [-v {f1|m1}] [-s 50-300] [-f file]\n" $0 exit 2;; esac done shift $(($OPTIND -1)) _sk_opt="${_sk_opt_voice} ${_sk_opt_speed}" if [[ ${_sk_opt_LOD} -eq 1 ]]; then _sk_opt_LOD=0 return fi # 2) 単語の辞書登録 if (( ${_sk_opt_MRG} == 1 )); then _sk_word_regist ${SK_DICT} ${SK_UNDICT} fi #################################### #・処理 # 1) 字句解析+音声 if [[ -f ${_sk_opt_file} ]]; then _sk_lex_file ${_sk_opt_file} else _sk_lex_string $* fi #################################### #・後処理 if [[ ${_sk_opt_VER} -eq 1 ]]; then # 同一単語の複数登録の抑止 _sk_make_uniq_file ${SK_UNDICT} (wc -l ${SK_UNDICT} | gsed 's/ //g' ) | while read _word _tmp; do if [[ ${_word} -gt 0 ]]; then echo "${SK_UNDICT}:[未登録データ件数: ${_word}]" fi done fi } if (( ${_sk_opt_setup} == 1 )); then _sk_setup fi if (( $# > 0 )); then saykanji $* fi |