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

ラズパイ3を美味しく食べるはずがinto the VR!!! Amazon echoのAlexaがトモダチ・・・ラズパイはおやつ。

ラズパイ3とBlutoothスピーカーをBluetooth接続できた!

 raspberry pi3とAnkerのSoundCore miniというBluetoothスピーカーをBluetooth接続できたので方法を記す。

  

Bluetooth接続できるし、色はピンクで可愛いし、何となく評判もいいっぽいし、これにしよ!と直感で購入。イヤホンジャックとauxケーブルで普通につなぐこともできるようだし。もしBluetoothが繋がらなくても安心・・・実際、auxケーブルはダイソーで100均で売ってた奴でつなげること可能でした。

 まぁ、ラズベリーパイ3でもBluetooth接続なんて簡単だろ、ちょちょいのちょいやと思ってたら、ひたすらうまくいかない、このスピーカーはラズベリーパイ3では使えない的なメッセージも出てきて、Bluetooth接続スピーカーなんて買うんじゃなかったかと1ヶ月くらいは悪戦苦闘してた。

何度目かのトライかは忘れたけど、この度そんな状態からようやく脱することができたので、その方法を下記しときます。誰かの参考になれば。。。

 

まずはBluetoothスピーカーの接続では下記のサイトを参考にしてみました。

3つほど色々見比べて参考にさせてもらいました。

eba-gml.blogspot.jp

Bluetooth ヘッドセット - ArchWiki

 Raspberry PiにBluetoothスピーカーをつなぐ。TaoTronics TT-SK03(B) | なみさ日記

下準備としては下記の2つをインストールする
$ sudo apt-get install pulseaudio-module-bluetooth
$ sudo apt-get install pavucontrol

bluetoothをrestartしておく
$ sudo service bluetooth restart

対話モードというのか、Bluetoothの設定をしていく。

$ bluetoothctl
[NEW] Controller %%:%%:%%:%%:%%:%% raspberrypi [default]
[NEW] Device ##:##:##:##:##:## SoundCore mini
SoundCore miniの名前が付いている方の##:##:##:##:##:##をコピーする

# power on
# trust ##:##:##:##:##:##
私のうまく行ったポイントとしては、先にtrustしてからpairするというところだった。
pairしてからtrustするというのは見かけたのだが、順番を逆にしてみた。

# pair ##:##:##:##:##:##
ここで何度かうまくいかなかったが、デスクトップ画面の右上、音量ボタンを右クリックしSoundCore miniを選択する。

f:id:umesyurock0603:20170116022953p:plain

f:id:umesyurock0603:20170116023019p:plain


さらに、Soundcore mini本体のモード変更ボタンを2回押すことで接続がうまくいきました。
AnkerのSoundCore miniはモード変更が下記4パターンあるらしい。
a 電源オン直後 Bluetooth探しているような音と光の点滅が見える
b auxモード(auxケーブルつないでたらこちらのモードにする)
c ザーという音が流れる ラジオ探索モードらしい
d SDカードモード(本体にマイクロSDカード入れる穴があるからここにいれたらその音楽を流すみたい。やったことないけど)


モード変更ボタンを押すごとにこのパターンが変わるようなんだけど、電源オン直後の状態ではうまく繋がらず、モード変更ボタンを2回押すことでうまくつながるなというイメージがある。電源オン直後がaで1回ボタン押すとcになる(auxケーブルは抜いてるのでbは飛ばされる)→さらにボタン押すとaに戻る(SDカードは入れてないのでdは飛ばされる)ということなのかな。(あくまでも想像です)

Bluetooth接続がうまくいくと ピロリン♪と軽快な電子音が鳴る。光の点滅も止まって青紫の光が点灯する。
これが接続がうまくいった証。

思わずつながった!!!と叫んでしまったぐらいには嬉しい。
                                   
このBluetoothスピーカーの良い所は、別の部屋にSoundCore mini持って行っても音声が流れ続けるってとこですね。
スピーカーはリビングに普段置いてるんだけど、洗面所に持って行って、掃除しながら音楽聞くなんてことができる。
扉閉めても大丈夫。Bluetooth接続切れない。

ただ、とくに音楽流さずに放置しとくといつのまにか電源落ちてるのか、Bluetooth接続切れてるのよね・・・。何時間放置すると落ちるとかあるのかなぁ?不明です。(もしかしたらだけどラズパイ3のUSBにBluetoothスピーカーをつないでいるせいとかそういう理由があるのかもしれない)(独立して電源を供給するようにしてみたんだけど、いつの間にかまた落ちてる。。。一方、電源つなげずにBluetooth接続した状態で放置してたらそれは10時間ぐらいつながってるのね、どういうこと??)


再度接続させたい場合は、Soundcore miniの電源入れなおして、ラズパイの画面の右上の音量コントロールボタンのSoundcore mini選択するとうまくつながる。

 

最後に

Bluetoothスピーカーつながらない問題について重要なチェックポイント

・auxケーブルは抜いているか?

・そもそもBluetoothスピーカーの電源切れてないか?

BluetoothスピーカーのBluetooth接続モードにちゃんとなってるか?

・ラズパイ3の音声出力モードがAnalogになってないか?

私は色々やらかしてつまづきまくった・・・。

 

f:id:umesyurock0603:20170116030009j:plain

ラズパイ3と良いBluetoothスピーカーライフを!!

ちなみに、このBluetoothスピーカー、マイクもあるって書いてあるんだけど、マイクってなんじゃい。このスピーカーに話しかけたら応答するとかもできるんだろうか。

cronで毎朝目覚めの音楽とラジオ体操流すよ

 朝の目覚めが爽やかな音楽とともに訪れるようにするために、ラズベリーパイ3のcronというシステムを作ってモーニングミュージックを定刻で流したくなった。

目標:朝の6時45分に爽やかな音楽を日替わりで流し、ついでに6時55分からはラジオ体操を流すことで強制的に毎朝体操し健康な身体を手に入れる。

曲の準備(曲リストと選んだ意図)

月曜日 ミッキーマウス・クラブマーチ←月曜日を奮い立たせるためにミッキー様の力を借りる。
火曜日 Wild_Child←傷ついた精神を癒やしてくれるようなEnyaの歌声。
水曜日 SugarBabyLove←週の半分過ぎたよ。なんか明るい気分のSugarBabyLove。
木曜日 Always_Look_On_The_Bright_SideMonty Pythonの曲!自分のPCに入ってる曲を漁っていたら見つけた。いつの間にか入れていたらしい。python勉強中なので入れておく。
金曜日 Ob-La-Di_Ob-La-Da←ようやく金曜日、頑張れよという活力のために。
土曜日 OnlyTimeEnyaの癒やしの歌声。土曜日だから寝過ごしてもいいよ、この時間は貴重なあなただけの時間だよという起きても起きなくてもいいよというメッセージを込めた選曲。どうせ子供に起こされるけどね。
日曜日 FlorasSecret←もう日曜日という残酷な現実を忘れさせてくれるEnyaの癒やしの歌声。今日こそは寝過ごしてもいいよというメッセージを込めた選曲だが、どうせ子供に叩き起こされる。

Enya率が高い。

事前確認

$ mpg321 /home/pi/work/music/morning/ミッキーマウス・クラブマーチ.mp3
$ mpg321 /home/pi/work/music/morning/SugarBabyLove.mp3
$ mpg321 /home/pi/work/radiotaiso/ラジオ体操第1号令.mp3

これでちゃんと曲が流れてくるかどうかを確認する。おーけー。

http://www.tapun.net/raspi/raspberry-pi-talk-weather

cronの設定

下記のサイトを参考にcronの設定をしていく。

www.tapun.net

cronの起動
$ sudo /etc/init.d/cron start
[ ok ] Starting cron (via systemctl): cron.service.
というのが出てくる。これでとりあえずOK。

cron設定ファイルを開きます
$ crontab -e
と打ち込むと、
no crontab for pi - using an empty one

Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny

Choose 1-4 [2]: 3
というのが出てきた。エディタは何にしますか、nanoがおすすめだよ!って言われているみたいだけど、nanoの使い方知らんのよ。。。(調べればいいんだろうけど)vimにしたいと3を選択しエンター
-----------------------------------------------------
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
~
"/tmp/crontab.WrXRic/crontab" 22L, 888C 1,1 全て
-----------------------------------------------------
上記の内容がでてきた。cronの設定の仕方を教えてくれているっぽい。

crontab で細かいスケジュールの設定 | junkpotてくなメモ

crontabについては上記サイトを参考に理解をする。

分 時 日 月 曜日 [実行するコマンド]
分 0 〜 59
時 0 〜 23
日 1 〜 31
月 1 〜 12
曜日 0 〜 6 0-日、1-月、2-火、3-水、4-木、5-金、6-土

とのことです。法則もわかったことだしやるぞ!

$ crontab -e

下記の行を一番下の方に挿入(i)して(Esc)、保存(Shift+ZZ)する。

45 6 * * 1 mpg321 /home/pi/work/music/morning/ミッキーマウス・クラブマーチ.mp3
45 6 * * 2 mpg321 /home/pi/work/music/morning/Wild_Child.mp3
45 6 * * 3 mpg321 /home/pi/work/music/morning/SugarBabyLove.mp3
45 6 * * 4 mpg321 /home/pi/work/music/morning/Always_Look_On_The_Bright_Side.mp3
45 6 * * 5 mpg321 /home/pi/work/music/morning/Ob-La-Di_Ob-La-Da.mp3
45 6 * * 6 mpg321 /home/pi/work/music/morning/OnlyTime.mp3
45 6 * * 0 mpg321 /home/pi/work/music/morning/FlorasSecret.mp3
55 6 * * 1,2 mpg321 /home/pi/work/radiotaiso/ラジオ体操第1号令.mp3
55 6 * * 3,4 mpg321 /home/pi/work/radiotaiso/ラジオ体操第2号令.mp3
55 6 * * 5 mpg321 /home/pi/work/radiotaiso/みんなの体操号令.mp3
0 9 * * 6,0 mpg321 /home/pi/work/radiotaiso/みんなの体操号令.mp3

が、最初はうまく行かず、何が悪いのか。。。と探したところ、下記のサイトを発見。

roboneco.hateblo.jp

crontabはエラーをメールで送ってくれるんですが、それを見る限り、どうやらここの一番最後の行を自前のローカルIPに書き換えないといけないみたいです。おそらくデフォルトではこうなっているのですが
127.0.0.1 raspberrypi
これを自前のIPに書き換えてください

とのこと。自分のローカルIPを
$ ip a
で調べてみる

$ sudo vim /etc/hosts
一番最後の行を192.#.#.#に変更(自分のアドレス入れてね)

結果:テストは成功

 こうすることで、私の環境でならうまくいくようになりました。(もしかしたら他に設定しているもののおかげもあったりするかもしれない)

とりあえず2分後に設定した音楽は流れてくれたので、あとは朝を待つのみ。

→翌朝成功しました。が、6時20分に子供らに叩き起こされてたので、せっかくの音楽設定した意味は!??!!ラジオ体操にいたっては、子供のオムツ処理中だったので結局できてねえ!!!

めげずに頑張ります。

今後の課題

 実は、このmp3を流す前に、時報をOpenJTalkで喋らそうとしたり、pythonのプログラムを走らせて天気予報を言わせようとがんばってたんだけど、そちらはうまく行っておりません。mp3を流すという手段であれば、うまくいくんだけどなぁ。

mpg321でmp3をランダム再生するよ

ラズベリーパイ3の特定のフォルダに入れたmp3をmpg321でランダム再生するperlのプログラムを自分用にカスタマイズする。
参考にさせていただいたのは下記サイト。

digress.exblog.jp

こちらのサイトではaplayでランダム再生されている。
元のプログラムは上記サイトからコピーペーストしてます。(私はperlの文法何も知らんのやで。。。)

自分はrandommp3.plという名前のperlを作ります。
アクセサリ→Text Editorを開き、下記の内容をコピーペースト。赤字は自分の環境用に変えた箇所。
/home/piのフォルダにrandommp3.plという名前をつけて保存する。

############################## ここから
#!/usr/bin/perl

#$player = "aplay";

## 使用プレーヤーを変更
$player = "mpg321"; #mpg321でmpg3ファイル再生したい場合、コメントアウト(#)を取る。→取りました。

## -def オプションで再生したいフォルダー。ほぼ必須。→ここはMusicを指定しておきました。
$defaulturl = "/home/pi/Music";

## 追加フォルダー。ここに書き込んだフォルダー内の該当音楽ファイルは必ず再生されます。→ここも再生されます。
$defaulturls = "/home/pi/work/music";

$max = 0; #再生曲数 0で無制限

if($player eq "mpg321"){@type = (".mp3");}else{@type = (".wav",".wave");}
$dir = "./";
$udir = "0";
$list = 0;
$alist = 0;
$noran = 0;
$down = 0;


if ($ARGV[0]){
foreach $_ (@ARGV){

if($_ =~ /\-dir\=/i){
$_ =~ s/\-dir\=//; $dir = $_;
$udir = 8;
}

if($_ =~ /\-max\=/i){$_ =~ s/\-max\=//; $max = $_;}

if($_ =~ /\-def/i){$dir = "$defaulturl"; $udir = 88;}

if($_ =~ /\-list/i){$list = 8;}
if($_ =~ /\-alist/i){$alist = 8;}
if($_ =~ /\-noran/i){$noran = 8;}
if($_ =~ /\-down/i){$down = 8;}
}
}
else{
$dir = "./";
if($player eq "mpg321"){@type = (".mp3");}else{@type = (".wav",".wave");}
}

if($player eq "mpg321"){@type = (".mp3");}else{@type = (".wav",".wave");}
&getlist($dir);
if($defaulturls ne ""){&getlist($defaulturls);}


print "\n********************************************\n";
print "randommp3.pl は mpg321 でのランダム演奏用です。\n";
print "(初期設定の使用プレーヤー変更してmp3演奏するようにしました)\n";
print "ex: perl randommp3.pl -alist -list -dir=./sound\n";
print "------------------------------------------------\n";
print "-def (設定したデフォルト\"" . $defaulturl . "\"を再生)\n";
print "-alist (再生一覧リストを表示)\n";
print "-list (再生リストを表示)\n";
print "-noran (ランダム再生しない)\n";
print "-down (逆順に再生)\n";
print "-dir=URL (URLのフォルダー内を演奏)\n";
print "-max=数字 (最大演奏回数、無指定で無制限)\n";
print "演奏中 次の Ctrl + C\n";
print "演奏中 中止 Ctrl + Z\n\n";


if($noran){@new = @files; print "\**NORANDOM**\n\n";}
elsif($down){@new = sort {$b cmp $a} @files; print "\**DOWN**\n\n";}
else{
foreach (@files){
my $r = rand @new+1;
push(@new, $new[$r]);
$new[$r] = $_;
}
print "\**RANDOM**\n\n";
}

if($alist){
$listii = 0; print "再生予定リスト\n------------------------------------------------\n";

foreach (@new){
$listii ++;
$wlists = $_;
$wlists =~ s/$defaulturl\//\//g;
$wlists =~ s/$defaulturls\//\//g;
if($player eq "mpg321"){$wlists =~ s/\.mp3//ig;}else{$wlists =~ s/\.wa.+//ig;}
print "$listii*$wlists\n";
if($listii == $max){last;}}

print "------------------------------------------------\n\n\n";
}

$listi = 0;
foreach (@new){
$listi ++;

$lists = " \"$_\"";

if($list){
$wlists = $_;
$wlists =~ s/$defaulturl\//\//g;
$wlists =~ s/$defaulturls\//\//g;
if($player eq "mpg321"){$wlists =~ s/\.mp3//ig;}else{$wlists =~ s/\.wa.+//ig;}
}

#if($list){print "------------------------------------------------\n\n";}

if($player eq "mpg321"){
if($lists){system("mpg321 $lists");}
else{print "--NoFile--\n\n";}
}
else{
if($list){print "NowPlay$listii*$wlists\n";}
if($lists){system("aplay -q $lists");}
else{print "--NoFile--\n\n";}
}

if($listi == $max){last;}
}

exit;
#-----------------------------------------------------------------------

sub getlist{
my $ndir = $_[0];
my @get;

#opendir(IN,$ndir) or die "opendir $dir エラー : $!";
opendir(IN,$ndir) or return;

@get = readdir IN;
closedir(IN);

foreach $files (@get){
next if $files =~ /^\.\.$/;
next if $files =~ /^\.$/;


foreach (@type) {
if($files =~ /$_$/i){
if($ndir =~ /^\.\/.+/i){push @files, "$ndir" . "/$files";}
elsif($udir){$ndir =~ s/\/$//i; push @files, "$ndir" . "/$files";}
else{push @files, "$files";}
}
}


if($ndir =~ /^\.\/.+/i){$nndir = $ndir . "/$files";}
elsif($udir){$ndir =~ s/\/$//i; $nndir = "$ndir" . "/$files";}
else{$nndir = $ndir . "$files";}

#print "$nndir\n";#TEST用
if(-d $nndir){&getlist($nndir);}
}

}

############################## ここまで

使用例

コマンドで

$ perl randommp3.pl -list
とすると、ランダムに再生してくれるし、-listというのをつけているので、再生リストを表示してくれる。ここにさらに -alistというのをつけると再生予定リストも表示してくれる。試しにやってみたら1番目から53番目までリスト表示した。(再生数指定していないからどうなるんかと思ってたけど、53個で終わった。。なんでやろ)-max=数字 (最大演奏回数、無指定で無制限)というのをつけると最大演奏回数を指定できるっぽい。

CtrlとCを同時に押すと次の曲を再生する。
CtrlとZを押すと終了する。

※特定のフォルダにあるmp3をランダム再生できるようになりますが、特定のフォルダは、さらに中にフォルダ分けされててその中にmp3があったとしても再生します。
そのフォルダの下位のフォルダも全部等しくランダム再生されるようです。

なお、ラズベリーパイ3の特定のフォルダにWindowsPCからmp3を入れる方法としては、前回のブログ参照のこと。(ネットワークにつながってる必要があります)

 

ランダム再生できるようになったー。このperl音声認識&音声応答ミュージックプレーヤーに組み込むことできるんとちゃう?
ランダム再生して、とお願いしたら、ランダム再生するよと言ってランダム再生してくれる奴ー。

音声認識&音声応答ミュージックプレーヤー その2

 前回のラズピッピ音声認識&音声応答ミュージックプレーヤーの続き。さらに音楽を充実させてみた実験。

umesyurock0603.hatenablog.com


(1)WindowsPCに保存しているiTunes内の音楽をmp3に変換する。WAVで取り込んでてもMP3に変換できんだってね。知らなかった、助かった。

digitalfan.jp

(2)mp3データをWinSCPを使って、ラズパイではSSH接続を有効にしておいて、指定のフォルダに移動させる。(WindowsPCの中のファイルを、ラズベリーパイの中身を覗き見ながらここのフォルダに移動しよーってことができる。とっても便利。)

www.kibanhonpo.com


(3)作っていたword.yomiファイルに新しく単語を追加、さらにjuliusが認識可能な単語辞書ファイル(word.dic)へ変換。
(4)/home/pi/julius-4.3.1/jclient-perlのフォルダに作っていたjclient_music.plのファイルをテキストエディタで開いて、こっちもいじる。
(5)LXTerminalで
$ 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
これで私の思った通りの曲を再生してくれるミュージックプレーヤーができるはず!

(1)(2)は参考サイトを参考にして、ラズパイの中にmp3をじゃんじゃん入れます。(mp3のファイル名は後ほど変える必要が出てきます。。。)

(3)word.yomiファイルに新しく単語を追加、さらに変換。
参考サイト再掲

usicolog.nomaki.jp

 辞書の作成は、単語帳を作り、それを変換することで作成できます。

(前回やったけど、あんまりわかってなかったな。単語帳を作って、それを変換しなくてはいけない、あと、julius-kitsフォルダ下に作成しなきゃいけない
 単語帳(word.yomiとした)を、julius-kitsフォルダ下に作成します。単語帳ファイルには"認識させたい単語"+"Tab"+"単語の読み" を記述します。

今回新たに追加したword.yomiは以下の通り。

$ vim word.yomi
-----------------------------------
ポルカ ぽるか
トライエブリシング とらいえぶりしんぐ
シャキーラ しゃきーら
オッケー おっけー
ポケモンはらはらリレー ぽけもんはらはらりれ
ポケモン言えるかな ぽけもんいえるかな
めざせポケモンマスター めざせぽけもんますた
エレクトリカルパレード えれくとりかるぱれーど
Under_The_Sea あんだーざしー
とまれ とまれ
-----------------------------------

※トライエブリシングのは入れていても大丈夫だった。(エラー出なかった)

ポケモンはらはらリレーポケモン言えるかなを並べていたが、ちゃんと音声を区別してくれた。

Under_The_SeaはUnder The SeaとSpace区切りだとエラーになったので_を入れてみたところ、エラーは出なかった。ただし、aquesTalk Piはこのタイトルを「アンダーザえすいーえー」と読み上げよった。意図した読み上げをしてほしい場合は、「

アンダーザシー あんだーざしー」としなければいけないのかもしれない。(後で変えよう。。)


作成した単語帳(word.yomi)を、juliusが認識可能な単語辞書ファイル(word.dic)に変換します。
$ 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

「曲名(mp3のファイル名) 読み方」だが、曲名と読み方の間をTabで区切ってないとここでエラーが出てた。

 

(4)/home/pi/julius-4.3.1/jclient-perlのフォルダに作っていたjclient_music.plのファイルをテキストエディタで開いて、こっちもいじる。

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 "Under_The_Sea"
|| $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;
}
}
}
-----------------------------------

(5)LXTerminalで

$ 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を流してくれる。「とまれ」というと音楽止めてくれる。

音声認識の点でマイクの感度が高すぎると周囲の雑音をすぐ拾って勝手に変換してしまう気がした。気のせいかなぁ。マイクの感度を下げてみたりしている。もしくは、周囲がテレビつけてたりして騒がしいと音声認識しにくいのかもしれない。夜中に一人で音声認識させてる時は結構小さいつぶやきでも正しく拾ってくれるんだけどなぁ。

マイクの感度とマイク使えてるかどうかの確認は下記を行っている。

$ amixer sset Mic 54 -c 0
$ arecord -D plughw:0,0 -d 10 -f cd test.wav
$ aplay test.wav

 

あとはそうだなぁ。より一層会話している感じがほしいかなぁ。

「ウィーゴー」(→呼びかけることにより音楽再生機能がONになるとか)

「お呼びでしょうか」

「音楽流してー」

「それでは適当に流します」(シャッフル再生機能)

「次のやつ流して」(曲のスキップ)

「了解しました」

「音おっきくして」(音量大)

「はーい」

「音ちっさくして」(音量小)

「はーい」

「音楽止めて」

「はーい」

とかいう応答をやってみたい。もっとそう、会話してる感がほしい!!

「ロボ、○○して」と話しかけることをやってた人がいたと思うのでそれで研究してみよう。

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

この日記は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もそれと同じように変えたら、自分だけの音声認識ミュージックプレーヤーができますね。

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

 

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

Python3を勉強したいんや

Python3を勉強したいんや!もう絶対この本だけは年内に読んでやるんだ!絶対だ!!

と心に決めた本。確かな力が身につくpython「超」入門 著=鎌田正

 

2016/3/31に第1刷が発行されている。つまり結構新しい。

WindowsMacでの使い方を教えてくれているので、RaspberryPiだったらこういうことかと適当に置き換えながら読んでいる。

SBクリエイティブ:確かな力が身につくPython「超」入門 ←公式ページ

第1刷は数カ所誤記があるので注意正誤情報

 

pythonのパの字も、ラズベリーパイに出会うまで(2016年11月・・・つまり2ヶ月前まで)知らなかったので、ド素人もいいとこですよ。プログラミングの経験は、大学の時にC++の授業があったけど、何も身に付いた覚えはないレベル。わけがわからなくて腹を立てたことは覚えている。

 

そんな私ではありますが、Python面白そうだなぁと思わせてくれる良書ですね。

Raspberry PiのPiがPython 由来なら、Pythonも愛さねばなるまい。

 

この本の良いところは、今はココわからなくても大丈夫、とか教えてくれるところ。ここが間違いやすいからねと教えてくれるのもいい。例としてあげているプログラムは、真面目くさってない。ちょっとクスっとする。Python大好きな優しい先輩から、イチから個別指導してもらってるような印象ですね。(勝手にそう思っている。)

絵も可愛いのね。蛇と蛇使いの絵。

requestsという外部ライブラリを使って天気予報を取得する件についても書かれてあるようなので、はやくそこにたどり着きたい。あと、PythonQRコードも作成できちゃうようなのでそこも気になる。そんなんできるんだーという驚き。

 

はよ読みたい。

天気予報喋らせっぞ!!

ラズパイ3で現在時刻を喋ったのであれば、天気予報も喋らせたい。という欲がわいてきた。参考にしたのは下記の2サイト。

raspi.seesaa.net

www.tapun.net

まず1つ目のサイトのやっているとおりに、ことを進める。
jsayコマンドというのを使えるようにするために

raspi.seesaa.net

を参考にjsayで喋ることができるようになるよう頑張る。いままでOpenJTalkで喋らせるようにしてきてたんだけど、一旦おいといて、もう一度イチから真似していれてみる。

jsayを使えるようにする!

今回は、aptではなく、ソースからmake installでインストールをします。

make installでインストールしたアプリケーションを管理する「paco」というソフトウェアをまずインストールしておきます。

 paco・・・当たり前だけどドシロウトのため全く存じません。とりあえず入れるんだね。

$ sudo apt-get install paco

hts_engine API(version 1.09)のインストール
/tmp にダウンロードして解凍
下記を1行ずつ実行していく。
$ cd /tmp
$ sudo wget http://sourceforge.net/projects/hts-engine/files/hts_engine%20API/hts_engine_API-1.09/hts_engine_API-1.09.tar.gz
$ sudo tar zxvf hts_engine_API-1.09.tar.gz

ビルド、コンパイル、インストール。下記を1行ずつ実行していく。
$ cd /tmp/hts_engine_API-1.09
$ sudo ./configure
$ sudo make
$ sudo paco -lD "make install"
あっ最後にpacoというやつ使ってる。

Open JTalk(version 1.08)のインストール
/tmp にダウンロードして解凍

$ cd /tmp
$ sudo wget http://sourceforge.net/projects/open-jtalk/files/Open%20JTalk/open_jtalk-1.08/open_jtalk-1.08.tar.gz
$ sudo tar zxvf open_jtalk-1.08.tar.gz

ビルド、コンパイル、インストール
$ cd /tmp/open_jtalk-1.08
$ sudo ./configure --with-charset=UTF-8
$ sudo make
$ sudo paco -lD "make install"
あっまたpacoってやつ使ってる。

確認
下記のコマンドを実行し「hts_engine_API-1.09」と「open_jtalk-1.08」が表示されればOKです。

$ paco -a

hts_engine_API-1.09 open_jtalk-1.08
ようし、出た。ここまでOK。


辞書ファイルの入手
辞書ファイル(version 1.08) をダウンロードして、/usr/local/share/の下に置きます。
/tmp にダウンロード・解凍して配置
$ cd /tmp
$ sudo wget http://sourceforge.net/projects/open-jtalk/files/Dictionary/open_jtalk_dic-1.08/open_jtalk_dic_utf_8-1.08.tar.gz
$ sudo tar zxvf open_jtalk_dic_utf_8-1.08.tar.gz
$ sudo mkdir /usr/local/share/open_jtalk
$ sudo mv /tmp/open_jtalk_dic_utf_8-1.08 /usr/local/share/open_jtalk/

MMDAgent音声ファイルの入手
MMDAgent(version 1.4 ) をダウンロードして、/usr/local/share/の下に置きます。
/tmp にダウンロード・解凍して配置

$ cd /tmp
$ sudo wget http://sourceforge.net/projects/mmdagent/files/MMDAgent_Example/MMDAgent_Example-1.4/MMDAgent_Example-1.4.zip
$ sudo unzip MMDAgent_Example-1.4.zip
$ sudo mkdir /usr/local/share/hts_voice
$ sudo mv /tmp/MMDAgent_Example-1.4/Voice/mei /usr/local/share/hts_voice/

しゃべらせる
シェルの作成
/usr/local/bin の下にopen_jtalkを使って喋らせるためのシェルを作成します。
$ sudo vim /usr/local/bin/jsay
私はvimを使います。
ところでこのjsayってどういうファイルなんだろう?pyでもないのか。vimで作った後で調べたらシェルスクリプトって書いてあった。

シェルスクリプト - Wikipedia

シェルスクリプトは、オペレーティングシステムのシェルまたはコマンドラインインタプリタ向けに書かれたスクリプトである。シェルスクリプトは他のツールを組み合わせるためのグルー型のドメイン固有言語とみなされることもある[1]。シェルスクリプトで書かれる典型的処理としては、ファイル操作、プログラム実行、テキストの印刷などがある。
うん、わからん。けどそういうものを作ったらしい。
--------------------------------
#!/bin/sh

# 引数チェック
CMDNAME=`basename $0`
if [ $# -lt 1 ]; then
echo "Usage: ${CMDNAME} [ text ]" 1>&2
exit 1
fi


# 定数定義(出力ファイル名、辞書の場所、音声データの場所)
TMPFILE=`mktemp /tmp/tmp.XXXXXXXX.wav`
DIC=/usr/local/share/open_jtalk/open_jtalk_dic_utf_8-1.08/
VOICE=/usr/local/share/hts_voice/mei/mei_normal.htsvoice


# 音声データ生成
echo "$1" | open_jtalk \
-x ${DIC} \
-m ${VOICE} \
-ow ${TMPFILE} && \


# 生成した音声データを再生する
aplay --quiet ${TMPFILE}


# 生成した音声データを削除する
rm -f ${TMPFILE}

# 終了
exit 0
--------------------------------
「jsay」ファイルを保存したら、実行権限を付けます。

$ sudo chmod +x /usr/local/bin/jsay

以下のようにjsayの引数に、喋らせたい文字列を渡すことでしゃべらせることができます。
$ jsay こんにちは
メイさんのノーマルの声で喋った。jsayの中身にもmei_normal.htsvoiceを使うこと書いてあるしね。特にトラブルはなかったけど、黒い背景に白い文字がずっと流れていくのを見つめていた。

これでようやっと下ごしらえ終了だよ。

 

いよいよ天気予報を喋ってもらう

livedoorの天気予報APIWeather Hacks」を使用します。
商用利用は認められておらず、個人利用に限るっぽい

talk_weather.pyファイルを作成する。とりあえずいつもの/home/piに置いておいたらいいだろ。

$ sudo vim talk_weather.py

--------------------------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import shlex
import subprocess
from datetime import datetime
import urllib2
import json
CMD_SAY = 'jsay'
def main():
say_datetime()
say_weather()
return
def say_datetime():
d = datetime.now()
text = '%s月%s日、%s時%s分%s秒' % (d.month, d.day, d.hour, d.minute, d.second)
text = CMD_SAY + ' ' + text
print text
proc = subprocess.Popen(shlex.split(text))
proc.communicate()
return
def say_weather():
city = '130010'; # Tokyo 他の地域の方は、番号を変えてください。
json_url = 'http://weather.livedoor.com/forecast/webservice/json/v1' #API URL
weather_text = u'%sの天気は%sです。'
temperature_text = u'%sの予想最高気温、%s度、予想最低気温、%s度です。'
try:
r = urllib2.urlopen('%s?city=%s' % (json_url, city) )
obj = json.loads( unicode(r.read()) )
title = obj['title']
forecasts = obj['forecasts']
# TODAY
cast = forecasts[0]
temperature = cast['temperature']
today_w_txt = weather_text % (cast['dateLabel'], cast['telop'])
today_t_txt = temperature_text % (cast['dateLabel'], temperature['max']['celsius'], temperature['min']['celsius'])
# TOMMOROW
cast = forecasts[1]
temperature = cast['temperature']
tommorow_w_txt = weather_text % (cast['dateLabel'], cast['telop'])
# SAY
weather_str = title + ' ' + today_w_txt + ' ' + today_t_txt + ' ' + tommorow_w_txt
weather_str = weather_str.encode('utf-8')
text = '''%s '%s' ''' % (CMD_SAY, weather_str)
print text
proc = subprocess.Popen(shlex.split(text))
proc.communicate()
finally:
r.close()
return
### Execute
if __name__ == "__main__":
main()
--------------------------------

さー喋ってもらうぞ。

$ python talk_weather.py

jsay 12月17日、23時51分50秒
Traceback (most recent call last):
File "talk_weather.py", line 52, in <module>
main()
File "talk_weather.py", line 11, in main
say_weather()
File "talk_weather.py", line 35, in say_weather
today_t_txt = temperature_text % (cast['dateLabel'], temperature['max']['celsius'], temperature['min']['celsius'])
TypeError: 'NoneType' object has no attribute '__getitem__'

12月17日、23時51分50秒は言ってくれるけどそれ以降言ってくれない。うーん?

www.tapun.net

参考サイトにも最高気温・最低気温がnullになるとか書いてある。この問題の対処法として下記が紹介されていた。

talk_weather2.pyというものを下記の内容で作っておられる。
--------------------------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import shlex
import subprocess
from datetime import datetime
import urllib2
import json
CMD_SAY = 'jsay'
def main():
say_datetime()
say_weather()
say_temperature()
return
def say_datetime():
d = datetime.now()
text = '%s月%s日、%s時%s分%s秒' % (d.month, d.day, d.hour, d.minute, d.second)
text = CMD_SAY + ' ' + text
print text
proc = subprocess.Popen(shlex.split(text))
proc.communicate()
return
def say_weather():
city = '130010'; # Tokyo
json_url = 'http://weather.livedoor.com/forecast/webservice/json/v1' #API URL
weather_text = u'%sの天気は%sです。'
try:
r = urllib2.urlopen('%s?city=%s' % (json_url, city) )
obj = json.loads( unicode(r.read()) )
title = obj['title']
forecasts = obj['forecasts']
# TODAY
cast = forecasts[0]
temperature = cast['temperature']
today_w_txt = weather_text % (cast['dateLabel'], cast['telop'])
# TOMMOROW
cast = forecasts[1]
temperature = cast['temperature']
tommorow_w_txt = weather_text % (cast['dateLabel'], cast['telop'])
# SAY
weather_str = title + ' ' + today_w_txt + ' ' + tommorow_w_txt
weather_str = weather_str.encode('utf-8')
text = '''%s '%s' ''' % (CMD_SAY, weather_str)
print text
proc = subprocess.Popen(shlex.split(text))
proc.communicate()
finally:
r.close()
return
def say_temperature():
city = '130010'; # Tokyo
json_url = 'http://weather.livedoor.com/forecast/webservice/json/v1' #API URL
temperature_text = u'%sの予想最高気温、%s度、予想最低気温、%s度です。'
try:
r = urllib2.urlopen('%s?city=%s' % (json_url, city) )
obj = json.loads( unicode(r.read()) )
title = obj['title']
forecasts = obj['forecasts']
# TODAY
cast = forecasts[0]
temperature = cast['temperature']
today_t_txt = temperature_text % (cast['dateLabel'], temperature['max']['celsius'], temperature['min']['celsius'])
# TOMMOROW
cast = forecasts[1]
temperature = cast['temperature']
tommorow_t_txt = temperature_text % (cast['dateLabel'], temperature['max']['celsius'], temperature['min']['celsius'])
# SAY
temperature_str = title + ' ' + today_t_txt + ' ' + tommorow_t_txt
temperature_str = weather_str.encode('utf-8')
text = '''%s '%s' ''' % (CMD_SAY, temperature_str)
print text
proc = subprocess.Popen(shlex.split(text))
proc.communicate()
finally:
r.close()
return
### Execute
if __name__ == "__main__":
main()
--------------------------------

今度こそ喋ってくれよ。
$ python talk_weather2.py
jsay 12月18日、0時5分15秒
jsay '東京都 東京 の天気 今日の天気は晴れです。 明日の天気は晴時々曇です。'
Traceback (most recent call last):
File "talk_weather2.py", line 78, in <module>
main()
File "talk_weather2.py", line 12, in main
say_temperature()
File "talk_weather2.py", line 65, in say_temperature
tommorow_t_txt = temperature_text % (cast['dateLabel'], temperature['max']['celsius'], temperature['min']['celsius'])
TypeError: 'NoneType' object has no attribute '__getitem__'

となる。
12月18日、0時5分15秒
東京都 東京 の天気 今日の天気は晴れです。 明日の天気は晴時々曇です。

とまでは言ってくれるようになった!
予想最高気温、予想最低気温は何故か喋ってくれないのねー。これはどうしたもんかね。
まぁ、天気予報喋ってくれるだけありがたいかねぇ。

他にも天気予報喋らせてる人いないかな。調べてみたい。