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

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

processingで雪見

 アナと雪の女王を久しぶりにBDで見た興奮から、ラズパイ3に入れたprocessingで雪の結晶作ったり雪を降らせることに強い関心を持っています。

とは言ってもprocessingはなんにもわかってないので、「snowflake processing」というキーワードで何か面白いのないかなーと探しまくっています。で、新たに2つ見つけました。

(1)クリックして雪の結晶作るよ

www.openprocessing.org

OpneProcessingとは何だろう(Processingで作成されたプログラムの投稿サイトっぽいですね→OpenProcessingがリニューアル! : だらっと学習帳)。

 

どうやら、マウスでクリックしたらランダムに雪の結晶を生成してくれそうです。

下記をコピーして、processing開いて貼り付け、名前をつけて実行します。

----------------
float dRam = 140; //dlugosc ramienia
float bRam = 7; //szerokosc ramienia
int ilR = 7; //ilość rekurencji

int ilRam = 6;

void setup() {
size(700, 700);
background(0);
noStroke();
smooth();
fill(255);
platekS(width/2, height/2, dRam, bRam, ilRam, ilR);
frameRate(29);
}

void draw() {
}
void mousePressed()
{
background(0);
ilRam = int(random(6)+3);

platekS(width/2, height/2, dRam, bRam, ilRam, ilR);
}

void platekS(float X1, float Y1, float H, float B, int ilRam, int ilRek)
{
int tabilRam = new int[ilRek];
float tabH = new float[ilRek];

float tabB = new float[ilRek];
float tabalfaR = new float[ilRek];

tabilRam[ilRek-1] = ilRam;
tabH[ilRek-1] = H;
tabB[ilRek-1] = B;
tabalfaR[ilRek-1] = 0;

for (int i = ilRek-2; i >= 0; i--) {
tabilRam[i] = int(random(6)+2);
tabH[i] = tabH[i+1]*random(0.5, 0.7);
tabB[i] = tabB[i+1]*random(0.4, 0.5);
tabalfaR[i] = random(HALF_PI, PI-HALF_PI/2);
print(i+": "+tabilRam[i]+" "+tabH[i]+" "+tabB[i]+" "+tabalfaR[i]+"\n");
}
platekR(X1, Y1, tabH, tabB, tabalfaR, tabilRam, ilRek);
}

void platekR(float X1, float Y1, float H, float B, float alfaR, int ilRam, int ilRek)
{
ilRek--;
if (ilRek+1 > 0 && ilRam[ilRek] != 0)
{
float alfa;
if(alfaR[ilRek] == 0)
alfa = (TWO_PI-alfaR[ilRek])/(ilRam[ilRek]);
else
alfa = (TWO_PI-alfaR[ilRek])/(ilRam[ilRek]-1);

pushMatrix();
translate(X1, Y1);
rotate(-(TWO_PI-alfaR[ilRek])/2);
for (int i = 0; i < ilRam[ilRek]; i++)
{

rect(0, -B[ilRek]/2, H[ilRek], B[ilRek]);
platekR(H[ilRek], 0, H, B, alfaR, ilRam, ilRek);
rotate(alfa);
}
popMatrix();
}
}
----------------
クリックするごとに、新しい雪の結晶ができるのです。これもまたすごい。

f:id:umesyurock0603:20170122022529p:plain

f:id:umesyurock0603:20170122022543p:plain

f:id:umesyurock0603:20170122022554p:plain


いいねぇ。。。こういうのいいね。
自動的にランダムに現れてくれたらもっと嬉しいなぁなんて贅沢なことを言ってみる。

あと色も青白くしたり発光しているように見せたり、ガラスのような質感に見せるようにしたり、したい。(そんな技術力がほしい!)

 

(2)クリックして雪の結晶作るよ

solemone.de


こっちは雪が降る様子を眺められる。
---------------
int quantity = 300;
float xPosition = new float[quantity];
float yPosition = new float[quantity];

int flakeSize = new int[quantity];
int direction = new int[quantity];

int minFlakeSize = 1;
int maxFlakeSize = 5;

void setup() {

size(800, 350);
frameRate(30);
noStroke();
smooth();

for(int i = 0; i < quantity; i++) {
flakeSize[i] = round(random(minFlakeSize, maxFlakeSize));
xPosition[i] = random(0, width);
yPosition[i] = random(0, height);
direction[i] = round(random(0, 1));
}

}

void draw() {

background(0);

for(int i = 0; i < xPosition.length; i++) {

ellipse(xPosition[i], yPosition[i], flakeSize[i], flakeSize[i]);

if(direction[i] == 0) {
xPosition[i] += map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
} else {
xPosition[i] -= map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
}

yPosition[i] += flakeSize[i] + direction[i];

if(xPosition[i] > width + flakeSize[i] || xPosition[i] < -flakeSize[i] || yPosition[i] > height + flakeSize[i]) {
xPosition[i] = random(0, width);
yPosition[i] = -flakeSize[i];
}

}

}
---------------

f:id:umesyurock0603:20170122023747p:plain

(画面キャプチャしたので、静止画ですが。。。)
実際は雪が降ってます。しんしんと雪が降っている。

 

processing楽しいなー!この魔法のようなプログラミング言語をもっと学びたい!!

processingで雪の結晶作りたい

 アナと雪の女王をBD借りて見てたら、雪の結晶が綺麗で、自分で作りたくなったので、ラズパイ3に入れたprocessingで作れないかなーと探してみた。

(なお、ラズパイ3にprocessing3.2.3を入れる方法は下記参照のこと)

umesyurock0603.hatenablog.com

まずは先人の知恵を借りる。 

haukun.projectroom.jp

いるじゃないか。processingで雪の結晶作ってる人!これだよ!去年(2016年)のクリスマスのアドベントカレンダーでやってはったのか。

リンク先のソースコードをコピーする。

-----------------------------------------------------------

// パーティクルクラス
class P {
float ang; // 進行角度
PVector pos; // 位置
float v; // 速度
int depth; // 深さ
float size; // 大きさ

P() {
pos = new PVector();
}

// 初期化
void init(float _ang, float x, float y, float _v, int _depth, float _size) {
ang = _ang;
pos.set(x, y);
v = _v;
depth = _depth;
size = _size;
}

// 子として生まれる
void born(P p, float _ang) {
ang = p.ang + _ang;
pos.set(p.pos.x, p.pos.y);
depth = p.depth - 1;
v = p.v * (0.4 * depth) * (random(0.2) + 0.8);
size = p.size;
}

// 描画動作
void act() {

// パラメータ変更
pos.add(cos(ang) * v, sin(ang) * v);
v -= 0.02;

// 描画
translate(width / 2, height / 2);
for (int i = 0; i < 6; i++) {
ellipse(pos.x, pos.y, size, size);
rotate(radians(60));
}
translate(- width / 2, -height / 2);
}
}

ArrayList<P> perticles = new ArrayList<P>();
float generateRatio; // 子供性確率変数
float waitCount; // 描画終了後の待機時間

//-------------------------------------------------
// setup
//--------------------------------------------------
void setup() {
background(0);
size(700, 700);
init();
}

//--------------------------------------------------
// 初期化処理
//--------------------------------------------------
void init() {
fill(255, 255);
noStroke();

perticles.clear();

P p = new P();
p.init(random(60), 0, 0, random(2) + 2, 3, random(3) + 1);
perticles.add(p);

generateRatio = random(0.03) + 0.02;
}

//--------------------------------------------------
// draw
//--------------------------------------------------
void draw() {

if (perticles.size() == 0) {
waiting();
} else {
drawing();
}
}

//--------------------------------------------------
// 描画完了後の余韻
//--------------------------------------------------
void waiting() {
fill(0, 8);
rect(0, 0, width, height);
waitCount++;
if (waitCount >= 50) {
waitCount = 0;
init();
}
}

//--------------------------------------------------
// 描画メイン処理
//--------------------------------------------------
void drawing() {

ArrayList<P> childs = new ArrayList<P>(); // 今回生まれた子
ArrayList<P> deads = new ArrayList<P>(); // 今回死ぬパーティクル

for (P p : perticles) {
p.act();
if (p.v <= 0) {
deads.add(p);
}

if (random(1) < (generateRatio * p.depth)) {
float r = random(30) + 20;
P child1 = new P();
child1.born(p, radians(r));
childs.add(child1);
P child2 = new P();
child2.born(p, radians(-r));
childs.add(child2);
}
}

// リストから生まれた子を追加
for (P child : childs) {
perticles.add(child);
}

// リストから死んだ子を削除
for (P dead : deads) {
perticles.remove(dead);
}
}

void mouseClicked() {
init();
}

-----------------------------------------------------------

 そしてprocessingを開く。コピーしたソースコードペーストする。名前をつけて保存する。

f:id:umesyurock0603:20170121215603p:plain

実行ボタンを押す

f:id:umesyurock0603:20170121215652p:plain

f:id:umesyurock0603:20170121215706p:plain

 そうすると、上記のような雪の結晶が中央からファーっと出来ては消え、出来ては消えを繰り返すのでありました。

綺麗!すごい綺麗だなぁ。眺めているだけで楽しいです。

 

あとはそうだなぁ、この雪の結晶のバリエーション増やしてみたいなとか、キラキラ舞わせてみたいなとか、もう少し青色がかった透明な感じにしたいなとか、ディズニーの魔法のようになんか出来ないかなとか、やりたいことは思いつくんだけど、技術が足りない。processingの本読んで、できること増やしていきたいなぁ。

雪の結晶がどう成り立つのかとか、そこも勉強したい。どんな種類があるのかとか。

 

※ちなみに、アナと雪の女王は、地上波で3/4に放映されるそうですね。。。

natalie.mu

ラズベリーパイ3にprocessing3.2.3をインストールする方法

ラズパイ3でprocessingを遊べたら大変楽しそうだなと思って調べたところ、下記サイトを発見。私がやりたいことはたいていからあげさんがすでに何年か前にやっている、ということにつくづく気付かされる。

karaage.hatenadiary.jp

人の顔を認識してアヘ顔にチェンジするのもやってみて成功しているんだけど、今回はとりあえずそれは置いておいて、processing入れるところだけをメモ書きしておく。
からあげさんのを見ると、processing3.0.1を入れているようですが、
https://github.com/processing/processing/releases
を確認すると、最新バージョンは3.2.3みたいです。(2016/11/7リリースされてんのかな)


LX Terminalを起動して下記を入れていく。

$ wget https://github.com/processing/processing/releases/download/processing-0255-3.2.3/processing-3.2.3-linux-armv6hf.tgz

$ tar xvzf processing-3.2.3-linux-armv6hf.tgz

$ cd processing-3.2.3/

$ ./processing

f:id:umesyurock0603:20170121214212p:plain

ほら、ラズパイ3にプロセッシング3.2.3入ったよ!

 

processingはまだまだ全然勉強してないんで、こっちも勉強していきたんだよー!

今、読み始めている本が下記の「遊んで学ぶはじめてのプログラミング Processingの魔法学校」なんだけど、面白いんだよ。。。全部読んでないから、まだ言えないけど、しょっぱなから面白そうなんだよ。Processingで魔法を使うってのが、夢が広がるじゃない。キャラも可愛いし、このProcessing本、読むぞ!!!

 

ラズパイ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になるとか)

「お呼びでしょうか」

「音楽流してー」

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

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

「了解しました」

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

「はーい」

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

「はーい」

「音楽止めて」

「はーい」

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

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