2012年05月09日

Open JTalk を利用する日本語読み上げ bash スクリプト

先日、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


拍手する
posted by takayan at 02:30 | Comment(0) | TrackBack(0) | 音声合成 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]


この記事へのトラックバック