ラズパイ3倍美味しいブログ

ラズパイ3を美味しく食べるはずがinto the VR!!!

ラズピッピが音声認識ミュージックプレーヤーになった日

この日記はRaspberry Pi Advent Calendar 2016の 23日目の記事です。

 今年の11月からラズベリーパイの存在を知って(会社の後輩が実験室でいじってるのを見てうっかり近づいたらすごい勢いでこっちの世界に引きずり込まれた)、気がついたら個人でもRSオンラインで100台限定セットのうちの1台を買ってしまい、ラズパイ3を新しい個人用パソコンとして活用しているところです。

 プログラミングなんて大学の講義でちょっと習っただけで、♯の意味だって忘れてました。ド素人もはなはだしいですが、ラズパイ可愛い♪♪♪だけの勢いでラズパイに触れてます。

 そんな私がアドベントカレンダーに投稿するとか、ド素人の分際でスイマセンスイマセンと思いながらの投稿です。

 

 基本的に、こんなド素人がどうやったらラズパイでやりたいことに近づけるか?
Googleでやりたいことを検索して、それに近いことをしている人のブログを読んで、その通りに真似をする。そういうことを繰り返している段階です。(python3は使いこなせるようになりたいので本読んで勉強中)

 最終的にやりたいのは、ロボットに対して音声で話しかける、ロボットが動いたり音声で応答してくれる。というやつ。

今回それに近いなと思って選んだのが、下記URLの記事です。

dq310.com

ちょうど1年前の投稿です。絵もついてて、本当にわかりやすい。

これをできるようになったら面白そう!ということでなぞらせていただきます。

(1)準備するもの

Raspberry Pi Raspberry Pi2 Model B を使用
→Raspberry Pi3 Model Bを使用しました
マイク SANWA SUPPLY MM-MCUSB16 USBマイクロホン 1600円
→購入済みです


スピーカー 家にあるアナログのPCスピーカー(何でも良いです)
Bluetooth付きのANKERのスピーカーをケーブルでつないでます。Bluetooth何故か使えない。これはまたいつか記事を書こう)
クリスマス用のCD
→音楽は、適当なmp3を用意しますが、とりあえずここのやり方に沿って、マライヤ.mp3、ポールマッカートニー.mp3、ワム.mp3と名づけて/home/pi/work/music/に置きます。

(2)大まかな手順
・スピーカーを使えるようにする
→スピーカー使えるのでパス
マイクを使えるようにする、録音できるようにする
マイクは使えるようになってるはずなんだけど、どうも一度立ち上げたほうがいいのか、下記テストしてから望む。
$ amixer sset Mic 54 -c 0
$ arecord -D plughw:0,0 -d 10 -f cd test.wav
$ aplay test.wav

音声認識できるようにする(Julius)
→Juliusは一度入れてみて使えてたけど念の為確認
音声合成できるようにする(AquesTalk Pi)
→AquesTalk Piも入れてるけど念の為確認
MP3を再生できるようにする(mpg321)
→mpg321ってなんだろう、入れる必要ありそう。
プログラムを組んで動かす(Julius + AquesTalk + mpg321)
→これは全く持ってわからん。どんなプログラムだろう。

音声認識ができるようにする Juliusの設定
ちょっといろいろトラブったので、Julius関係のファイルをフォルダごと全て捨てて、もっかいインストールし直し。
Juliusの設定に関しては下記のURLを参考にしました。

qiita.com

Juliusの設定

インストール
本家サイトからソースを取得しコンパイルします。

$ wget --trust-server-names 'http://osdn.jp/frs/redir.php?m=iij&f=%2Fjulius%2F60273%2Fjulius-4.3.1.tar.gz'
$ tar xvzf julius-4.3.1.tar.gz
$ cd julius-4.3.1/
$ ./configure
$ make

同じくディクテーションファイルも取得します。
$ mkdir ~/julius-kits
$ cd ~/julius-kits
$ wget --trust-server-names 'http://osdn.jp/frs/redir.php?m=iij&f=%2Fjulius%2F60416%2Fdictation-kit-v4.3.1-linux.tgz'
$ tar xvzf dictation-kit-v4.3.1-linux.tgz

Juliusの実行
$ ALSADEV="plughw:0,0" ~/julius-4.3.1/julius/julius -C ~/julius-kits/dictation-kit-v4.3.1-linux/main.jconf -C ~/julius-kits/dictation-kit-v4.3.1-linux/am-gmm.jconf -nostrip
これを実行するとバーっと文字が流れたあとに
<<< please speak >>>
と見えたので喋ってみた。
ーーーーー
私「こんにちは」
pass1_best: こんにちは 。
pass1_best_wordseq: <s> こんにちは+感動詞 </s>
pass1_best_phonemeseq: silB | k o N n i ch i w a | silE
pass1_best_score: -2938.071533
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 13245 generated, 1442 pushed, 220 nodes popped in 122
sentence1: こんにちは 。
wseq1: <s> こんにちは+感動詞 </s>
phseq1: silB | k o N n i ch i w a | silE
cmscore1: 0.708 0.574 1.000
score1: -2953.620850
すごい、ちゃんとこんにちはって認識した。

私「クリスマス」
pass1_best: クリスマス 。
pass1_best_wordseq: <s> クリスマス+名詞 </s>
pass1_best_phonemeseq: silB | k u r i s u m a s u | silE
pass1_best_score: -3398.527588
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 7703 generated, 1270 pushed, 217 nodes popped in 144
sentence1: クリスマス 。
wseq1: <s> クリスマス+名詞 </s>
phseq1: silB | k u r i s u m a s u | silE
cmscore1: 0.541 0.352 1.000
score1: -3410.509033
おう、クリスマスだ、クリスマスだぞう。

私「音楽流して」
pass1_best: 音楽 流し て 。
pass1_best_wordseq: <s> 音楽+名詞 流し+動詞 て+助詞 </s>
pass1_best_phonemeseq: silB | o N g a k u | n a g a sh i | t e | silE
pass1_best_score: -3936.660156
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 47711 generated, 2145 pushed, 477 nodes popped in 163
sentence1: 音楽 流し て いる 。
wseq1: <s> 音楽+名詞 流し+動詞 て+助詞 いる+動詞 </s>
phseq1: silB | o N g a k u | n a g a sh i | t e | i r u | silE
cmscore1: 0.479 0.897 0.338 0.774 0.020 1.000
score1: -3975.158691
認識してるぅ。音楽流している。というこのsentence1ってなんだろ。他の候補ってこと?

私「冷凍庫」
pass1_best: 〇 十 五 。
pass1_best_wordseq: <s> 〇+名詞 十+名詞 五+名詞 </s>
pass1_best_phonemeseq: silB | r e: | t o: | g o | silE
pass1_best_score: -2919.756836
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 22013 generated, 2625 pushed, 333 nodes popped in 122
sentence1: ルイ 十 五 。
wseq1: <s> ルイ+名詞 十+名詞 五+名詞 </s>
phseq1: silB | r u i | t o: | g o | silE
cmscore1: 0.651 0.061 0.059 0.010 1.000
score1: -2939.021240
れいとうこ、は認識できてない。ルイ15ってなんだお!

私「電気消して」
pass1_best: 手引き し て 。
pass1_best_wordseq: <s> 手引き+名詞 し+動詞 て+助詞 </s>
pass1_best_phonemeseq: silB | t e b i k i | sh i | t e | silE
pass1_best_score: -3348.595459
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 40607 generated, 2510 pushed, 393 nodes popped in 140
sentence1: 手引き し て 。
wseq1: <s> 手引き+名詞 し+動詞 て+助詞 </s>
phseq1: silB | t e b i k i | sh i | t e | silE
cmscore1: 0.504 0.197 0.209 0.038 1.000
score1: -3378.363281
これも理解してもらえてないっぽい。なんの手引きだ。

これは辞書を追加する必要があるらしい。以下参考URL
認識時間と認識率を高める工夫

qiita.com

辞書を作ってやったら正確に認識するらしいなということを理解する。

んでここからは、また元のサイトに戻って進めていく。

dq310.com

辞書の追加
$ vim word.yomi
-----------------------------------
お腹すいた おなかすいた
マライヤ まらいや
ポールマッカートニー ぽーるまっかーとにー
ワム わむ
とまれ とまれ
-----------------------------------
$ iconv -f utf8 -t eucjp ~/word.yomi | ~/julius-4.3.1/gramtools/yomi2voca/yomi2voca.pl > ~/julius-kits/dictation-kit-v4.3.1-linux/word.dic

 

$ vim ~/julius-kits/dictation-kit-v4.3.1-linux/word.jconf
-----------------------------------
-w word.dic #単語辞書ファイル
-v model/lang_m/bccwj.60k.htkdic #N-gram、または文法用の単語辞書ファイルを指定する
-h model/phone_m/jnas-tri-3k16-gid.binhmm #使用するHMM定義ファイル
-hlist model/phone_m/logicalTri #HMMlistファイルを指定する
-n 5 #n個の文仮説数が見つかるまで検索を行う
-output 1 #見つかったN-best候補のうち、結果として出力する個数
-input mic #マイク使用
-input oss #オープンサウンドシステム使用
-rejectshort 600 #検出された入力が閾値以下なら棄却
-charconv euc-jp utf8 #入出力エンコード指定(内部euc-jp, 出力utf-8)
-lv 1000 #入力の振幅レベルの閾値(0~32767)
-----------------------------------

$ julius -C ~/julius-kits/dictation-kit-v4.3.1-linux/word.jconf
マイクに向かって話しかけると、お腹すいたとかポールマッカートニーとか素早く判断してくれるぅ。すごひ。
でもため息とかをワム。。。と判断するのやめい。

ここまで出来たら下記URLの後編に移動します。

dq310.com

ここでは以下3つができるようになる。

・MP3を再生できるようにする(mpg321)
AquesTalkインストール
音声自動認識、音楽再生プログラムの作成 (Julius + AquesTalk + mpg321)

MP3を再生できるようにする(mpg321)
$ sudo apt-get install mpg321
さっくりゲット

$ mpg321 /home/pi/work/music/マライヤ.mp3

よし、音楽流れる。

AquesTalkインストール
と言いつつすでにインストール済みなので、喋れるかどうかだけ確認

$ cd aquestalkpi/
$ ./AquesTalkPi "嘘ではありませーん" | aplay
よしちゃんと喋る。

音声自動認識、音楽再生プログラムの作成 (Julius + AquesTalk + mpg321)

juliusをモジュールモード(サーバモード)で起動ということを行う。
(ココらへんからちょっとわからなくなっていく。未知の世界。)


/home/pi/julius-4.3.1/jclient-perlのフォルダにテキストエディタjclient_music.plのファイルを作成しておく。
中身は下記
-----------------------------------
#! /usr/bin/perl
use strict;
use IO::Socket;
use IO::Select;

my $host = "localhost";
my $port = 10500;

print STDERR "$host($port) に接続します\n";

# Socketを生成して接続
my $socket;
while(!$socket){
$socket = IO::Socket::INET->new(PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp',
);
if (!$socket){
printf STDERR "$host($port) の接続に失敗しました\n";
printf STDERR "再接続を試みます\n";
sleep 10;
}
}

print STDERR "$host($port) に接続しました\n";

# バッファリングをしない
$| = 1;
my($old) = select($socket); $| = 1; select($old);

# Selecterを生成
my $selecter = IO::Select->new;
$selecter->add($socket);
$selecter->add(\*STDIN);

# 各種コマンド
my $command_start = '~/aquestalkpi/AquesTalkPi "みゅうじっく 、スタート!" | aplay';
my $command_stop = '~/aquestalkpi/AquesTalkPi "みゅうじっく 、ストップ!" | aplay';
my $command_speak = '~/aquestalkpi/AquesTalkPi "、、えー、、、、hogehoge、を再生します。" | aplay';
my $command_retry = '~/aquestalkpi/AquesTalkPi "えっ? 、なんだって?" | aplay';
my $command_running = '~/aquestalkpi/AquesTalkPi "音楽再生中だよ。静かにしてね" | aplay';
my $command_play_mp3 = 'mpg321 /home/pi/work/music/musicname.mp3 &';
my $command_kill_mp3 = 'perl /home/pi/julius-4.3.1/jclient-perl/killmp3.pl';
my $musicPlay = 0;#音楽再生フラグ。2重起動防止

while(1){
my ($active_socks) = IO::Select->select($selecter, undef, undef, undef);

foreach my $sock (@{$active_socks}){
# Juliusからの出力を表示
if ($sock == $socket){
while(<$socket>){
print $_;
if ($_ =~/.*<WHYPO WORD=\"([^\"]{1,})\"/) {
print "$1\n";
my $callName = $1;
print "$callName\n";
my $result = "";
my $exeCom;
my $exeMusic;

if ( ($callName eq "マライヤ"
|| $callName eq "ポールマッカートニー"
|| $callName eq "ワム"
|| $callName eq "アクロスザスカイ"
|| $callName eq "ハチ"
|| $callName eq "パパパパ"
)
&& $musicPlay == 0) {
$exeCom = $command_speak;
$exeMusic = $command_play_mp3;
$exeCom =~ s/hogehoge/$callName/;
$exeMusic =~ s/musicname/$callName/;
$result = system ($exeCom);
$result = system ($command_start);
$result = system ($exeMusic);
$musicPlay = 1;

} elsif ($callName eq "とまれ") {
$result = system ($command_stop);
$result = system ($command_kill_mp3);
$musicPlay = 0;
} elsif ($musicPlay == 1 ) {
$result = system ($command_running);

} else {
$exeCom = $command_retry;
$result = system ($exeCom);
}
}

last if(/^\./);
}
# 標準入力をJuliusに送信
}else{
my $input = <STDIN>;
# 小文字を大文字に変換
$input =~ tr/a-z/A-Z/d;

print $socket $input;
}
}
}
-----------------------------------

また、killmp3.plというファイルを/home/pi/julius-4.3.1/jclient-perl/に保存。
-----------------------------------
#! /usr/bin/perl
use strict;
use POSIX qw( SIGKILL );

my $procname= "mpg321";
my $proxmax = "10";

my $proccnt = 0;
my @process;
eval {
@process = `ps -ef`;
@process = grep { /$procname/ } @process;
};

foreach my $process (@process){
if ($process =~/[a-z]{1,}\s{1,}([0-9]{1,})\s{1,}/) {
kill(SIGKILL, $1);
}

}
-----------------------------------
こんだけお膳立てしておいてから、LX Terminalで下記を打ち込んでエンター
$ julius -C ~/julius-kits/dictation-kit-v4.3.1-linux/word.jconf -module

続いて、LX Terminalで別のタブを開いて下記を打ち込んでエンター
$ perl ~/julius-4.3.1/jclient-perl/jclient_music.pl

おもむろに、マイクに話しかけてみる。

私「マライヤ」

ラズパイ「、、えー、、、、マライヤ、を再生します。」
ラズパイ「みゅうじっく 、スタート!」
と言うとマライヤ.mp3として保存しておいた曲が流れだした!
すごい!!!しかも、ラズピッピ、ちゃんと喋ってくれる。
私「とまれ」
ラズパイ「みゅうじっく 、ストップ!」

すっげぇえ。

 

しかしすぐに問題が発生。スピーカーとマイクの距離が近くて、スピーカーからもれてくる音声に対して、ラズパイが音楽再生中だよ。静かにしてね」を繰り返す。

うぬぬ、黙っとれー

ということで、物理的にスピーカーの位置をマイクから遠ざけてみたところ、スピーカーからの音声には反応せずとってもいい感じ。

それにしても、うっかりperlなんてまた知らないプログラミング言語をいじってしまった。

 

自分の流したい音楽を決めて、辞書作って、このjclient_music.plもそれと同じように変えたら、自分だけの音声認識ミュージックプレーヤーができますね。

ということで、だいぶ長々とした内容になってしまいましたが、素人が悪戦苦闘しながらも何かをつかみとりました。
あはは、夜明け前だ。だけど、めっちゃ楽しいなぁ。脳内麻薬でてますなぁ。

 

ここまで読んでいただきありがとうございました☆