時報プログラムとバグ

私の実家では、私が小さいころにディズニーの機械時計を買った。
これが鳩時計みたいな奴だった。

具体的には00分になると真ん中がパカッと開き、中に入っているディズニーのキャラクターが動くと同時にオルゴール調のメロディーが鳴る、というものだった。時間ごとにメロディーが一定だったか、時間により違うんだったかはちと覚えていない。

確か「世界中誰だって~」で始まるんだったかな。
ちなみに、光センサーか何かが付いていて、真っ暗では鳴らないんだったと思う。なんか八角形でクソデカかったような気がするんだけど・・・どうたったかな。

まぁ、とにかく1時間ごとにメロディーが鳴って、「あ、そろそろ・・・」という代物だった。


ところで急に話は変わるが、妻への数少ない不満としては、「妻は寝るのが遅い」。
いや、じゃあ「お前だけ先に寝りゃいいじゃん」って言われるとまぁそうなんだけどさ・・・。

妻は睡眠時間が少なくても大丈夫なタイプみたい・・・というか私が一杯寝ないといけないタイプなのかもしれないけど、とにかく寝るのが遅い。放っておくと1時とか2時とか。
私より早く起きて通勤するのに、凄い奴だといつも思うが・・・。

そんな現状の、一つ時間の区切りになっているのは24時の消灯時間である。
我家はスマートリモコンが出始めた頃にいくつか機械を入れたのだ。
スマートリモコンは照明とエアコンはGoogle Homeの音声認識で操作することができる装置だが、予め決めたルールに倣って、自動的に操作することもできる。

24時にいったんすべての照明・エアコンを停めるようにしている。これは旅行時の消し忘れ防止の意味もあるし、なんとなくもう寝るんだという意味でこうした。
ちなみに、朝7時になると勝手に電気が付く。以前は出かける際に消していたが、妻は消さない人なので、私も消さないことにした。なに、蛍光灯・電球時代に比べて、微々たる差さ。球も切れないし。

この24時に照明が全部落ちるのを合図に、妻も寝る支度をはじめてくれる…ような気がする。
だから、この「毎日同じ時間に何かが起こる」って習慣を整えるうえで結構良いんじゃないかな?と思って、冒頭で述べたディズニーの鳩時計を思い出したのだ。


と、いうわけで時報があったら、生活リズムが狂うのを防げるんじゃないかなと思ったわけだ。

ただ、実家のように明るければ常にメロディーが鳴るというのも、なんかイマイチである。
本当は特定のトリガとなる時刻に、それに紐づいたメロディーを鳴らしたい。

そこでまずGoogleHomeに時報をさせることにした。
ところがだ、GoogleHomeだと音楽を定時に流させるというのは難しいことが分かった。とりあえずテキスト読み上げはできるので、「時報です。いま11時になりました」という塩梅に自動でGoogleHomeにしゃべらせてみることにした。

これ自体はとりあえず簡単にできたし、一応のところ用は成したのだが・・・妻がGoogleHomeが突然しゃべりだしたら怖いと言い出した。まぁ、抑揚に乏しいからか、確かに不気味かもと私も思った。

まぁ、そのうち慣れるだろうと思っていたが、鳴るたびに妻に「不気味」「怖い」と言われ続けると、だんだん鬱陶しくなってくる。


そこで、もっといい感じの時報を作ることにした。

本業だったらPLCにパトライト社あたりの音声合成警音器あたりを使うんだけど、安く済ませたい。貧乏性だし。
そこで、24時間付けっぱなしにするパソコンを設けて、それに時報をさせることにした。

メインPCだと24時間付けっぱなしだと勿体ないんで、Amazonで安いモニターと安いPCを買った。そう、これめっちゃ良かったから、今度改めて紹介しよう。

で、買ってから時報を鳴らすフリーソフトを探した。
が、いくらでも出てくるだろうと思ったが、案外無いのだ・・・

探すのが面倒だったから、適当な再生ソフトを作った。


とりあえず

07:00(起床時間) = Just Communication (TWO-MIX)
08:00(出勤時間) = All the things she said (カトゥーン)
12:00(昼) = やさしさに包まれたなら(魔女の宅急便)
23:00(就寝準備) = Its a long load(ランボー)
24:00(寝る時間) = 炎のたからもの(カリオストロの城)

に設定した。なんかすごいラインナップだけど、最近音楽は全部youtubeで聞いちゃうから、mp3ファイルが荒れてて、パッと時報に使いたいなと思った曲が無かった。
そのうちAmazon Musicでなんか買おうと思う。(買うとダウンロードできる)

最初はファイル名をjihou07.mp3とか、jihou08.mp3とかにリネームして入れておくって方式にしていたけど、曲を入れ替えたりするときに不便だし、なんかイケていないので適当にドロップしてファイル名で覚えておく方式にした。


ところがだ、ふと気づくと時報が鳴らないのである。最初は何の問題か分からなかった。
しかし鳴るときもあるので不思議だ。

そして何日か過ぎると、妻から「昼は必ず鳴る」「夜も24時のは鳴る。23時は鳴らない」と言われて、そういわれてみれば確かにそうだと気づいた。

どうしてだ?試しに試験再生ボタンを押してみると、08時の「水の星に愛をこめて」は鳴るけれど、07時の「Just Communication」は鳴らない。時間を変えてみても、「Just Communication」が鳴らない。

同様に、「やさしさに包まれたなら」は鳴るけれど、「Its a long load」は鳴らない。
ん~?


ここで、プログラムに詳しい人はピンときたかもしれない。

鳴らない曲=スペースが含まれる
鳴る曲=スペースが含まれない・・・!

そう、再生はAPIという1行のコマンドを送り付ける物を使っていて、例えばtest.mp3を再生する場合は

play test.mp3

停める場合は

close test.mp3

という塩梅でコマンドを出す。スペースが区切り文字になっているのだ。
スペースを区切りとして[コマンド][ファイル名][オプション(省略可)]となっている。

つまりplay やさしさに包まれたなら.mp3は
[コマンド]=play
[ファイル名]=やさしさに包まれたなら.mp3
[オプション]=無
と解釈される。

ところが、just communication.mp3を再生しようとすると

play just communication.mp3となり、
[コマンド]=play
[ファイル名]=just
[オプション]=communication.mp3
となってしまい、正しく解釈されないのだ!

・・・と、思ったのだが、プログラムはちゃんと””で囲うようになっていた。
つまり play “just commuication.mp3″というコマンドを送るようにしていた。作っている最中から、パスにスペースが入るかもしれないと考えていたようだ。

もしかして” play just communication.mp3″にしないといけないのか?とか、play ‘just communication.mp3’?”paly ‘just communication.mp3′”?とかいろいろ試したけどダメ。

うーんなんでだ?


ググって探してやっとわかった。

大抵のサイトには、mciSendStringA APIの使い方として、「play ファイル名」を紹介しているのだが、以下のサイトにはもうちょっと詳しく解説してあった。

本来はいきなりplayじゃなくって、
open [ファイル名] alias [エイリアス名]で開いて、開いたものに対して
play [エイリアス名] として再生するのだ。

ただ恐らく、省略としていきなりplay test.mp3とすると、
open test.mp3 alias test.mp3
play test.mp3
と解釈して作動してくれるようになっているのだと思う。

このエイリアス名という概念を認識していなかったから、再生プログラムは

Public Class clsMusicCtrl
    '**********************************************
    ' 定数
    '**********************************************
    Private arrPlayed As New List(Of String)
    '**********************************************
    ' API
    '**********************************************
    Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String,
                                                                                   ByVal lpstrReturnString As String,
                                                                                   ByVal uReturnLength As Long,
                                                                                   ByVal hwndCallback As Long) As Long
    '**********************************************
    ' 公開メソッド
    '**********************************************
    Public Sub runMP3(ByRef strPath As String)
        Call mciSendString("play """ & strPath & """", "", 0, 0)
        arrPlayed.Add(strPath)
    End Sub
    Public Sub stopMusic()
        For Each strPath As String In arrPlayed
            Call mciSendString("close """ & strPath & """", "", 0, 0)
        Next
        arrPlayed.Clear()
    End Sub

End Class

としていた

ここで、今回スペースが入ると再生できない問題の本性は、ファイル名はスペースが入ってもよくても、エイリアス名はスペースが入る名前で定義できないのだと思う。
そこで、openコマンドで明示的にエイリアスを定めるようにした。

Public Class clsMusicCtrl
    '**********************************************
    ' 定数
    '**********************************************
    Const LS_Alias1 As String = "music1"
    '**********************************************
    ' API
    '**********************************************
    Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String,
                                                                                   ByVal lpstrReturnString As String,
                                                                                   ByVal uReturnLength As Long,
                                                                                   ByVal hwndCallback As Long) As Long
    '**********************************************
    ' 公開メソッド
    '**********************************************
    Public Sub runMP3(ByRef strPath As String)
        Call stopMusic()
        Dim strCommand As String = "open " & Chr(34) & strPath & Chr(34) & " alias " & LS_Alias1
        Call mciSendString(strCommand, "", 0, 0)
        Call mciSendString("play " & LS_Alias1, "", 0, 0)
    End Sub
    Public Sub stopMusic()
        Call mciSendString("close " & LS_Alias1, "", 0, 0)
    End Sub

End Class

そしたらうまくいった。


今日の反省・・・

良く分からんものを、動くからイイやと放っておくと、後で訳の分からことになる・・・

シェアする

  • このエントリーをはてなブックマークに追加

フォローする