娘の誕生日プレゼントを作る 9歳 テック話
先日書いた娘の誕生日プレゼントの記事のテック話に特化したバージョンを書いてみる。
オリジナル版音楽の棚
今年の長女へのプレゼントは、過去に自分が作品として作った「音楽の棚」をリメイクしてプレゼントした。扉を開くとそこに設定された音楽が再生されるという、ある種音楽のプレイヤーでありディスプレイ棚であるという作品だ。
そのオリジナル版の頃について振り返ると、なんと2007年に作ったものだ。今から13年前。iTunesはあったけど、iPhoneもまだ日本には来てないころ。当然サブスクリプションの音楽サービスなんてない。iTunes Storeはあったけど、App Storeもまだない。
当時の「音楽の棚」は、展示に向けて作っていてバタバタしてたこともあって、結局Objective-Cで書いたMacのプログラムで、フォルダに格納したファイルを直接再生する形で実現していた。iTunesをコントロールしてiTunes上のプレイリストを再生するとかやればよかったんだけど、それを作る余裕もなく。。。
当時はiPodにDockコネクタでつないで、シリアル通信のコマンドを駆使して画面にオリジナルの画像を出したりしつつ、iPodのコントロールをするのが自分の中で流行っていた。なので音楽の棚もそういう形に進化するんだと思っていたのを思い出した。
時代が過ぎて今
13年たった今、音楽を聞く場合は、Apple MusicやSpotify、Youtube Music、Amazon Musicなどサブスクリプションの音楽サービスがたくさんある。我が家は、Apple Musicのファミリーアカウントに契約して、家族全員Apple Music聴き放題。
娘は自分が昔使っていたiPhoneを受け継ぎ、SIMこそは入ってないがWiFiにつながるインターネット端末的にiPhoneを触っている。
なので「音楽の棚」をリメイクすると決めたとき「Apple Musicに対応できたらいいな」と思っていた。それができれば、娘は自分でプレイリストを編集できるので、音楽の棚の醍醐味でもある、飾るものを考えそれに合う曲を設定するというとてもいい時間を体験できる。
とはいえ、Apple MusicのAPI叩くとかはJavaScriptだしブラウザで再生みたいなやり方になる。RapberryPiでやってる例もなかなか見つからない。iOSかMacOSのマシンを使えば、直接プレイヤーを作るのは簡単そうだけど、ちょっと音楽の棚のためだけにAppleのデバイスを専有するのもなという感じ。
さてどうしよう。
計画の全容
まず、音楽の棚の機能を実現するにあたって、制作としてなにをすることになるか。それをリストアップする。
1. MUJIの棚をハックして扉が開放できるディスプレイ棚を作る(木工作業)
2. 上記棚の扉が開いたことをスイッチなどで検知するデバイスを決める(電子工作と簡単なプログラム)
3. 音楽を再生するデバイスを決めそれをどうコントロールするか決める(何で実装するか未定)
1はCADで設計し、CAM作業をへてCNCで切削。この娘プレゼントシリーズではある時から必ずやってることなんで慣れている作業。
2はいわゆるリモコンのような機能を実現するパート。RaspberryPiが良さそう。ネットワークに繋いでOSCとか送ればいい。
3はスピーカーとつなぐデバイス。ここに音楽データを入れてそれを直接叩くのが最もシンプルっぽい。OSC経由でリモコンのコマンドを受けてここで処理する。
Spotify API
すぐに思いついたのがSpotifyだ。Spotifyは、RaspberryPiで簡単に再生できたという記憶があり、なにかちょっと検索するだけでも使えそうなものがみつかる。
Spotipyといういかにもなダジャレネーミングのライブラリは、PythonでSpotify APIを叩くためのライブラリ。割と使ってる人も多く期待値が高い。
ドキュメントサイトもあった。
ていうか、そもそもSpotifyのAPIってなにできるんだろうってことを掘り下げていく。
公式のサイトがとても立派でドキュメントもあるし、コンソールもあってそこではOAuthもできてTokenも簡単に取得でき、APIをブラウザで試せる。すごい。
これを見ていて、気になるAPIがあった。
ドキュメントを読むと、再生に使えるデバイスのリストを取得。ん?そういえば、自宅にもあるGoogle HomeでSpotifyが再生できるぞ。もしや、再生先としてGoogle Homeを使えるのか!?
もし使えたら最高にスマートだ。プレイヤーはGoogle Homeを使い、プレイリストはSpotifyで管理し、音楽の棚からAPIを叩けばOKとなる。
一旦これを目指す方向でスタートをした。ただし、なにか罠がある気配がプンプンするので、いつもならプログラム作業は納期の前日にやるんだけど、一週間前の週末にやってみることにした。
Google HomeでSpotifyを再生する
まず、iPhoneとかパソコンのSpotifyアプリを立ち上げると、Google Homeと同じネットワークに繋がっていれば、デバイスのリストにGoogle Homeが現れる。それを選ぶと、Google Homeが「ピロリン!」と音を出し、プレイヤーで再生した音はGoogle Homeから再生される。
期待できる。早速SpotipyをMacのPythonにインストールしてテストしてみる。
sudo pip3 install spotipy
OAuth とかで軽く手こずるも解説はネットにたくさん転がっててすぐできた。
が、なんかMacのSpotifyアプリしかデバイスに出てこない。
「同じネットワークにいるのになー。」
試しにiPhoneでGoogle Homeから再生してみる。その後Pythonからデバイスのリストを取得すると、
「あ!出てきた!」
期待通り、Google Homeのデバイス名がでてきて、IDなど取得できる。
この状態でPythonからプレイコマンドを送ると、Google Homeから音楽が再生された!いいね。
しかし、iPhoneでGoogle Homeからの再生をやめたあとPythonからデバイスリストを取得すると出てこない。さっき取得したIDで無理やり再生しようとしても、そのIDは見つかりませんのエラー。
「うーん。。。」
あー、これはあれだな。iPhoneのSpotifyアプリとかだとローカルネットワーク内をなんかしらの方法で検索してるのに対して、Spotify APIだといきなりクラウドにつながっているわけで、ローカルを探索する方法はないからだ。そりゃそうかということになる。
予想だけど、iPhoneアプリからデバイスをGoogle Homeに指定したときに「ピロリン!」って鳴ってるとき、あれは何かしらの方法でアクティブ化してるに違いない。
こういうときはググるしかないので、調べた。
調べているとChrome Castで同様の問題について言及してるのがあった。そしてPyChromecastというPythonのライブラリを発見。サンプルを見るとSpotifyを扱うものがあった。そして、Google HomeもChromecastデバイスとしてサーチ可能であることが判明。
ちょっとやってみると、「ピロリン!」の音が出た。が、鳴らない。
APIにわたす引数など見ていると、Spotifyのユーザ名やパスワードを渡してる。なんともすごい仕様。これから推測するに、Google HomeがSpotifyに自分のユーザーでログインし、Spotifyデバイスとして登録してるんだろう。それによってSpotifyのサーバー上で、自分のアカウントのデバイスとして登録される。そういう仕組だと思う。
そしてPyChromecastでのアクセスになにか問題があるのか、いろいろやってもなかなか解決する見込みがなかったので、ちょっとこれはあと数日しか稼働できない状況からすると
「深追いするな」
の雰囲気だ。
代案として思いつくのは、RaspberryPiをSpotify ConnectのデバイスとしてワークさせるRaspotifyだろう。
これをインストールすると、RaspberryPiがSpotify対応デバイスとなる。USBのオーディオインターフェースをつないでRaspotifyを使えば、家にあまってるチボリオーディオがSpotify Connectスピーカーとしてワークする。もしかしたら、これだったらなにか改善の見込みがあるかもしれない。
Raspotify
早速RaspberryPi3に新規にRaspbian LiteをセットアップしRaspotifyを入れる。USBオーディオインターフェースをデフォルト出力先として機能させる設定をしたら、簡単に完成した。
早速やってみる。まず、iPhoneのSpotifyアプリから検索すると、Raspotifyが無事に見える。
「お〜!」
わりと感動した。
で、その後iPhoneのSpotifyアプリでRaspotifyから音を出すのをやめて、その後PythonからSpotifyAPIを叩いてデバイスリストを取得してみる。
「お〜!!出た」
GoogleHomeではこの手順だとリストに出なくなる状況だが、Raspotifyでは出る。きた。これを期待してた。ログアウトの処理ができてないおかげだろう。
ただ、RaspotifyのRaspberryPiを再起動すると、デバイスリストにはでなくなる。きっとログアウト状態になっちゃうのだろう。だけど、一回iPhoneのSpotifyアプリから音楽を再生すると、その後はずっとデバイスリストに出る。再起動するまでは。
ひとまず家で使うレベルならこれで満足できる。一旦これで行くことにする!(これが個人消費プロジェクトのいいところ)
システム構成が確定
音楽の棚の木工デバイスに、スイッチをつける。スイッチは「ドアスイッチ」で検索して出てきたOMRONのスイッチの最も小型なものを使うことに。
このスイッチをドアの数の4つ使う。それぞれの接点を取得するデバイスは、RaspberryPi ZeroWを使う。薄くて小さくて隙間に仕込みやすいからだ。
そのRaspberryPi ZeroWで、GPIOの状態を監視し、変化があればSpotify APIを叩き、プレイリストの音楽を再生する。再生するデバイスはRaspotifyの入ったRaspberryPi 3Bを使う。
RaspberryPi ZeroWもRaspberryPi 3BもどちらもWiFiでつなぐ。なので、音楽の棚とチボリオーディオは直接ケーブルではつながらない。レイアウトに自由度があってとてもいい。
プレイリスト
プレイリストはSpotifyのアカウント内に作っておく。LeftTop、LeftBottom、RightTop、RightBottomの4つを作った。
ただ、ややこしいのは、複数の扉が同時に開いているときは、それら開いてる扉に設定された曲すべてをシャッフル再生したい。それをどう実装するか。
いろいろ考えたが、MusicCabinetという一時利用のプレイリストを作っておくのが良いと考えた。
扉が開いたら、その扉に設定された曲をMusicCabinetプレイリストに追加。
扉が閉じたら、その扉に設定された曲をMusicCabinetプレイリストから削除。
こうすることで、動的にMusicCabinetのプレイリストが変化し、単にシャッフル再生をしているだけでうまくいくはずだ。
完成動画を見てもらうとわかるが、この右側の画面はiPhoneのSpotifyアプリの画面だ。動的に曲の内容が変化してるのがわかる。素晴らしい。Spotifyがとても良くできている!助けられた!
ということで、割と簡単に実現できてしまった。
進化した音楽の棚
今回、音楽の棚をリメイクしたことで、すげー進化した。Spotifyを使ってることで、膨大なライブラリにアクセスできる。そして、プレイリストの編集もiPhoneなどで簡単にできる。そして、スピーカーも音楽の棚の場所にとらわれず、部屋の中のいい場所に設置できる。
なんていうか以前作った頃と比べて、オープンソースを躊躇なく使ってることで得られる恩恵も多く、RaspberryPiなどの安価で小さいコンピュータもあり、Spotifyというサブスクリプション音楽サービスもあり、少ない実装で大きな飛躍がとげられた!
まとめ
木工のところの設計は省略してることに今気がついたけど、ひとまず公開しますよ。