ギターで家電を操作してみる

この記事は [IoTLT Advent Calendar 2018 8日目](https://qiita.com/advent-calendar/2018/iotlt_neo) の記事です。

こんにちは。田中みそです。
普段はスマートスピーカー界隈を中心に活動していますが、IoTLTにもちょくちょく参加しています。

色々書いてたら前置きが長くなってしまったので先に作ったやつをご覧ください。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">IoTLT Advent Calendar 8日目ネタ用動画。<br>SUI(Sound User Interface)で家電操作。<br><br>・おなじみのフレーズで照明を暖色に<br>・地下のフレーズで消灯<br>・地上のフレーズで再度暖色に<br><br>Larrivee / OM-10 Mucha Lady<br><br>※音出てないっぽかったのであげなおし！ <a href="https://t.co/iQgpNmFEzg">pic.twitter.com/iQgpNmFEzg</a></p>&mdash; 田中みそ@技術書典5-う28/スマートスピーカーを遊びたおす本 (@miso_develop) <a href="https://twitter.com/miso_develop/status/1071043395987005440?ref_src=twsrc%5Etfw">2018年12月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こんな感じでタイトルのまんまギターで家電を操作できるようにしました。

それでは以下前置きになります。
※実装部は[こちら](#仕組み)。



# スマートスピーカーから家電操作
私はスマートスピーカーで主におうちハック的な試みを行っていまして、下図のように大体音声操作できる環境を構築しています。
このあたりの内容は昨年のAdvent Calendarにてまとめていますので、ご興味ある方は↓をご覧ください。

[Google Homeでやったことまとめ（Qiita）](https://qiita.com/miso_develop/items/99624915d3d6e41a5fb3)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/207109/9e7b3b54-b386-0334-f9de-b76908db4c1f.png)

そして実際構築してから1年が経過し、使用感を以下の記事にまとめてみました。

[Google Homeと暮らした1年間のログを分析してみた（Qiita）](https://qiita.com/miso_develop/items/9a894c2eedf558c4f2c8)

ここで、

> * ウェイクワードは未だに慣れない
> 	* 「OK Google」はやっぱ長い

とあるように、1年間スマートスピーカーを使いたおしてもウェイクワードには未だ慣れません。

たとえば「お母さん、テレビ8チャンにして」と家族に対し話しかけるのと「ねぇGoogle、テレビ8チャンにして」は同じことだろうと考えていたのですが、機械を操作するという意識がどこかにあるのかウェイクワードがやたらと億劫なのです。



# 人の喋り声のように弾くギター
スマートスピーカーをいじってくうちに誰しもが一度は試してみたくなるのがウェイクワードまわりではないでしょうか。
ウェイクワードなしで動くようにしたり、別のスマートスピーカーのウェイクワードで起動したり。

話は変わりますが、私は音楽専門学校の音響科出身で学校の友人は洋楽好きが多く、色んな音楽を紹介してもらいました。
そのうちの一曲なのですが、人の発声に合わせ、同じピッチでギターを弾くという神がかった演奏をするギタリストが話題になりました。

私もスマートスピーカー購入当初、ウェイクワードを無理やり変えてみたくなりまず考えたのが上記のギタリストようにギターからウェイクできないか、ということでした。
しかし当然ながらピッチだけ発話に似せてもスマートスピーカーは認識してくれません。



# オリジナルウェアラブルスマートスピーカー
そうこうしつつ並行してスマートスピーカーを色々といじっていたのですが、そのうち作ったものの一つにオリジナルのウェアラブルスマートスピーカーがあります。
私のプロフィール画像でも履いているバナナパンツにGoogle Assistantを搭載してみたのです。

仕組みはRaspberry Pi Zero WにGoogle Assistant SDKをのせ、バナナパンツのバナナの中（何故か空洞になってる）に詰め込んでいます。
このときウェイクワードも「OK バナナ」に変更しており、これにはSnowboyというサービスを使用しました。

[たぶん世界初…？Google Assistant搭載〇〇〇を作ってみた（Speaker Deck）](https://speakerdeck.com/miso/tabunshi-jie-chu-dot-dot-dot-google-assistantda-zai-000wozuo-tutemita)
※若干卑猥な画像が含まれますので閲覧にはご注意ください。

[OK バナナ（YouTube）](https://www.youtube.com/watch?v=nQVJRvZ0TEE)
※若干卑猥な映像が流れますので閲覧にはご注意ください。



# Snowboy Hotword Detection
[Snowboy](https://snowboy.kitt.ai/)とはあらかじめ登録しておいたウェイクワード（ホットワード）を検知したら処理を走らせることのできるサービスです。
Webから音声登録を行い定義ファイルをダウンロードし、それを使ってプログラムを組みます。
色んな言語のライブラリがあり、私はNode.jsを使いました。

これを使って「OK バナナ」のウェイクワードを実装したのですが、認識が結構ザルでキーボードのタイピング音ですら反応する状態でした。
そこで思ったのが逆に声じゃなくても認識できるんじゃね？ということです。



# 実際に試してみた
前置きが長くなってしまいましたが、実際に試して作ったのがこの動画のものです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">IoTLT Advent Calendar 8日目ネタ用動画。<br>SUI(Sound User Interface)で家電操作。<br><br>・おなじみのフレーズで照明を暖色に<br>・地下のフレーズで消灯<br>・地上のフレーズで再度暖色に<br><br>Larrivee / OM-10 Mucha Lady<br><br>※音出てないっぽかったのであげなおし！ <a href="https://t.co/iQgpNmFEzg">pic.twitter.com/iQgpNmFEzg</a></p>&mdash; 田中みそ@技術書典5-う28/スマートスピーカーを遊びたおす本 (@miso_develop) <a href="https://twitter.com/miso_develop/status/1071043395987005440?ref_src=twsrc%5Etfw">2018年12月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

目論見通りギターから家電が操作できました。



# 仕組み
既存のスマートスピーカーでの家電操作はFirebase Realtime Databaseがハブの役割となっており、スマートスピーカーはなんとかしてここに発話内容（家電操作コマンド）を書き込みます。
そしてラズパイ側でそれを監視して書き込みがあったら情報拾って割り当ててある処理を実行します。

つまりFirebase Realtime Databaseに書き込みできさえすればいいので、Snowboyでギターのフレーズ検知時にHTTP PUTでFirebaseへ書き込みを行っています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/207109/67064021-3874-ffe2-a2b2-7da9c8cfef8e.png)

またプログラム自体はラズパイ上のLinuxにて動いています（OK バナナの環境をそのまま使用したため）。
そのためラズパイからFirebaseに書き込み、それをまたラズパイで監視という無駄な動きが発生しています。
Snowboyの仕組みのみであればウェイクワード検知時にそのまま家電操作処理を行ってしまえばいいです。

## ソースコード
以下の手順でFirebaseへ書き込むところまで動きます。

1. Firebase Realtime Databaseを作成し、ソース上のURL、DB Pathを書き換え
1. Snowboyで音声モデルを作成、ダウンロードし`./model/`配下に配置
1. `data`オブジェクトのkeyを音声モデルのファイル名に書き換え、`command`にFirebaseへ書き込む内容を記述
1. `npm i snowboy node-record-lpcm16`でパッケージインストール
1. `node index.js`で実行

```js:index.js
const {Models, Detector} = require("snowboy")
const record = require("node-record-lpcm16")
const https = require("https")

// 自分で作成したFirebaseプロジェクトのものに置き換える
const config = {
    host: "xxxxxxxx.firebaseio.com",
    path: "/xxxxxxxx/word.json",
}

// keyにSnowboyの音声モデルファイル名、commandにFirebaseへ書き込む文字列を入れる
const data = {
    "ground": {command: "light 3"},
    "underground": {command: "light off"},
}

const main = (index, hotword) => {
    const command = data[hotword].command
    log(hotword, command)
    
    https.request({
        host: config.host,
        path: config.path,
        method: "PUT",
    }).end(JSON.stringify(command))
}

const models = new Models()
const sensitivity = "0.5"
for (const key in data) {
    models.add({
        file: `./model/${key}.pmdl`,
        sensitivity: sensitivity,
        hotwords: key,
    })
}

const detector = new Detector({
    resource: "./common.res",
    models: models,
    audioGain: 2.0,
    applyFrontend: true
})
detector.on("hotword", main)

const mic = record.start({threshold: 0})
mic.pipe(detector)

console.log("start")
```



# さいごに
GUI（Graphical User Interface）、CUI（Character User Interface）、VUI（Voice User Interface）とも違う、SUI（Sound User Interface）とも言えるUIで家電を操作することができました。
実用性はさておき色々と応用もきくのではないかと思うので、みなさまも色々試されてみてはいかがでしょうか。

※精度が確かであれば一人宅録とかでRecord/Stopを楽器自身から操作できるのは割と実用的ではないかと思います。