先日、Windows 用にバッチファイル ojtalk.bat を作ってみましたが、今度は似たような内容で Linux 用に bash スクリプトを作ってみました。対象は Ubuntu 12.04 と MinGW です。それ以外の場合は、実際にインストールされている場所に DICDIR と VDIRBASE の値を書き換えれば、おそらく動くでしょう。このスクリプトを /usr/local/bin あたりにコピーして使います。
Ubuntu 12.04 では、open-jtalk、open-jtalk-mecab-naist-jdic、hts-voice-nitech-jp-atr503-m001が apt-get や Ubuntuソフトウェアセンターでインストールできるので、それでインストールされているとします。
このスクリプトでは読み上げ文字列の指定は三種類あります。
まず、ちょっとした言葉はコマンドラインに書きます。
ojtalk こんにちは長い文章の時は、ファイルに utf-8 エンコードで保存して -f オプションで指定します。
ojtalk -f hoge.txt標準入力を読ませたいときは、文字を付けない '-' をコマンドラインに置きます。
cat hoge.txt|ojtalk -上記の読み上げ文字列の指定が複数あるときは、左から順に処理します。ただし文字列の合計の長さは bash の限界までです。
その他に、音声ファイルを作るときは、-ow hoge.wav とします。このとき、しゃべらせたくないときは、-quiet も一緒に指定します。hts-voice フォルダに他の音声データが入っているときは -vname mei_normal といった感じで音声を替えられます。このとき、その中に voice.info ファイルが入っていると、その情報を参照します。
さて、以前からの課題である GNOME orca の日本語化の件ですが、この bash スクリプトを使えば、python から次の形で呼び出せますから、以前よりシンプルに作れると思います。
os.system(u'ojtalk こんにちは'.encode('utf8'))
まず、このスクリプトを利用したものを作ってから、そのあとで Speech Dispatcher 経由のものを考えることにします。
以下、ojtalk ソース:
#!/bin/bash if [ `uname|grep "MINGW"` ]; then DICDIR=/usr/local/dic VDIRBASE=/usr/local/hts-voice DEFAULT_VOICE_NAME=hts_voice_nitech_jp_atr503_m001 mingw=1 else DICDIR=/var/lib/mecab/dic/open-jtalk/naist-jdic VDIRBASE=/usr/share/hts-voice DEFAULT_VOICE_NAME=nitech-jp-atr503-m001 mingw=0 fi # default parameters MESSAGE='open jtalk' S=48000 P=240 A=0.55 G=0 B=0.0 U=0.5 Z=1600 JM=1.0 JF=1.0 JL=1.0 MEI_S=48000 MEI_P=240 MEI_A=0.55 MEI_G=0 MEI_B=0.0 MEI_U=0.5 MEI_Z=6000 MEI_JM=0.7 MEI_JF=0.5 MEI_JL=1.0 if [ $mingw == 1 ]; then CURDIR=`dirname $0` TEMPTXTFILE=$CURDIR/_text.txt TEMPWAVFILE=$CURDIR/_wave.wav else TEMPTXTFILE=$(mktemp /tmp/ojtalk_txt_XXXXXXXX) TEMPWAVFILE=$(mktemp /tmp/ojtalk_wav_XXXXXXXX) fi L_SWITCH= QUIET_SWITCH=0 VNAME_VALUE= VDIR_VALUE= S_VALUE= P_VALUE= A_VALUE= G_VALUE= B_VALUE= U_VALUE= Z_VALUE= JM_VALUE= JF_VALUE= JL_VALUE= OT_VALUE=/dev/null OW_VALUE= TEXT= error(){ cmd=`basename $0` message="Bad parameter!" if [ "$1" ]; then message=$1; fi echo "$cmd: $message"; exit 1; } if [ ! -d $DICDIR ]; then error "No dic directory : $DICDIR" fi if [ ! -d $VDIRBASE ]; then error "No voice directory : $VDIRBASE" fi while [ $1 ]; do if [ $1 == -l ]; then L_SWITCH=-l elif [ $1 == - ]; then data=$(tr '\n\r' ' ') TEXT="$TEXT $data" elif [ $1 == -vname ]; then shift if [ ! $1 ]; then error; fi VNAME_VALUE=$1 elif [ $1 == -vdir ]; then shift if [ ! $1 ]; then error; fi VDIR_VALUE=$1 elif [ $1 == -quiet ]; then QUIET_SWITCH=1 elif [ $1 == -f ]; then shift if [ ! $1 ]; then error; fi if [ -f $1 ]; then data=$(cat $1|tr '\n\r' ' ') TEXT="$TEXT $data" else error "No text file: $1" fi elif [ $1 == -ow ]; then shift if [ ! $1 ]; then error; fi OW_VALUE=$1 elif [ $1 == -ot ]; then shift if [ ! $1 ]; then error; fi OT_VALUE=$1 elif [ $1 == -s ]; then shift if [ ! $1 ]; then error; fi S_VALUE=$1 elif [ $1 == -p ]; then shift if [ ! $1 ]; then error; fi P_VALUE=$1 elif [ $1 == -a ]; then shift if [ ! $1 ]; then error; fi A_VALUE=$1 elif [ $1 == -g ]; then shift if [ ! $1 ]; then error; fi G_VALUE=$1 elif [ $1 == -b ]; then shift if [ ! $1 ]; then error; fi B_VALUE=$1 elif [ $1 == -u ]; then shift if [ ! $1 ]; then error; fi U_VALUE=$1 elif [ $1 == -jm ]; then shift if [ ! $1 ]; then error; fi JM_VALUE=$1 elif [ $1 == -jf ]; then shift if [ ! $1 ]; then error; fi JF_VALUE=$1 elif [ $1 == -jl ]; then shift if [ ! $1 ]; then error; fi JL_VALUE=$1 elif [ $1 == -z ]; then shift if [ ! $1 ]; then error; fi Z_VALUE=$1 else TEXT="$TEXT $1" fi shift done if [ ! $VDIR ]; then if [ $VNAME_VALUE ]; then VDIR=$VDIRBASE/$VNAME_VALUE else VDIR=$VDIRBASE/$DEFAULT_VOICE_NAME fi fi if [ ! -d $VDIR ]; then error "No voice directory : $VDIR" fi if [ -f $VDIR/voice.info ]; then while read line; do if [[ $line =~ ^MESSAGE= ]]; then MESSAGE=`echo $line|sed "s/^MESSAGE=//"` fi if [[ $line =~ ^s= ]]; then S=`echo $line |sed "s/^s=//"` fi if [[ $line =~ ^p= ]]; then P=`echo $line |sed "s/^p=//"` fi if [[ $line =~ ^a= ]]; then A=`echo $line |sed "s/^a=//"` fi if [[ $line =~ ^g= ]]; then G=`echo $line |sed "s/^g=//"` fi if [[ $line =~ ^b= ]]; then B=`echo $line |sed "s/^b=//"` fi if [[ $line =~ ^u= ]]; then U=`echo $line |sed "s/^u=//"` fi if [[ $line =~ ^z= ]]; then Z=`echo $line |sed "s/^z=//"` fi if [[ $line =~ ^jm= ]]; then JM=`echo $line |sed "s/^jm=//"` fi if [[ $line =~ ^jf= ]]; then JF=`echo $line |sed "s/^jf=//"` fi if [[ $line =~ ^jl= ]]; then JL=`echo $line |sed "s/^jl=//"` fi done < $VDIR/voice.info fi if [[ $VNAME_VALUE =~ ^mei_ ]]; then if [ ! $S_VALUE ]; then S_VALUE=$MEI_S; fi if [ ! $P_VALUE ]; then P_VALUE=$MEI_P; fi if [ ! $A_VALUE ]; then A_VALUE=$MEI_A; fi if [ ! $G_VALUE ]; then G_VALUE=$MEI_G; fi if [ ! $B_VALUE ]; then B_VALUE=$MEI_B; fi if [ ! $U_VALUE ]; then U_VALUE=$MEI_U; fi if [ ! $Z_VALUE ]; then Z_VALUE=$MEI_Z; fi if [ ! $JM_VALUE ]; then JM_VALUE=$MEI_JM; fi if [ ! $JF_VALUE ]; then JF_VALUE=$MEI_JF; fi if [ ! $JL_VALUE ]; then JL_VALUE=$MEI_JL; fi else if [ ! $S_VALUE ]; then S_VALUE=$S; fi if [ ! $P_VALUE ]; then P_VALUE=$P; fi if [ ! $A_VALUE ]; then A_VALUE=$A; fi if [ ! $G_VALUE ]; then G_VALUE=$G; fi if [ ! $B_VALUE ]; then B_VALUE=$B; fi if [ ! $U_VALUE ]; then U_VALUE=$U; fi if [ ! $Z_VALUE ]; then Z_VALUE=$Z; fi if [ ! $JM_VALUE ]; then JM_VALUE=$JM; fi if [ ! $JF_VALUE ]; then JF_VALUE=$JF; fi if [ ! $JL_VALUE ]; then JL_VALUE=$JL; fi fi if [ "$TEXT" ]; then echo $TEXT>$TEMPTXTFILE else echo $MESSAGE>$TEMPTXTFILE fi if [ ! -f $TEMPTXTFILE ]; then error "No temp file : $TEMPTXTFILE" fi open_jtalk \ -x $DICDIR \ -td $VDIR/tree-dur.inf \ -tm $VDIR/tree-mgc.inf \ -tf $VDIR/tree-lf0.inf \ -tl $VDIR/tree-lpf.inf \ -md $VDIR/dur.pdf \ -mm $VDIR/mgc.pdf \ -mf $VDIR/lf0.pdf \ -ml $VDIR/lpf.pdf \ -dm $VDIR/mgc.win1 \ -dm $VDIR/mgc.win2 \ -dm $VDIR/mgc.win3 \ -df $VDIR/lf0.win1 \ -df $VDIR/lf0.win2 \ -df $VDIR/lf0.win3 \ -dl $VDIR/lpf.win1 \ -ow $TEMPWAVFILE \ -ot $OT_VALUE \ -s $S_VALUE \ -p $P_VALUE \ -a $A_VALUE \ -g $G_VALUE \ -b $B_VALUE \ $L_SWITCH \ -u $U_VALUE \ -em $VDIR/tree-gv-mgc.inf \ -ef $VDIR/tree-gv-lf0.inf \ -cm $VDIR/gv-mgc.pdf \ -cf $VDIR/gv-lf0.pdf \ -jm $JM_VALUE \ -jf $JF_VALUE \ -jl $JL_VALUE \ -k $VDIR/gv-switch.inf \ -z $Z_VALUE \ $TEMPTXTFILE if [ $mingw == 0 ]; then if [ -f "$TEMPWAVFILE" ]; then if [ $QUIET_SWITCH == 0 ]; then aplay -q $TEMPWAVFILE fi fi fi if [ "$OW_VALUE" ]; then cp $TEMPWAVFILE $OW_VALUE fi rm -f $TEMPWAVFILE rm -f $TEMPTXTFILE exit 0