obnizと圧電スピーカーを使ってキーボードをキーボード（音楽）に変えてみた

# はじめに
いまOTTOというArduinoベースのオープンソースロボットをobnizに移植する個人プロジェクトを進めています（[IoTLT vol.54](https://iotlt.connpass.com/event/138773/)で[LTしたやつ](https://speakerdeck.com/miso/obnizdeyou-buopunsosurobotuto)です）。
OTTOには圧電スピーカーも搭載されており、これを使ってロボっぽいピロピロ音を出すことができます。

先日、この圧電スピーカーを使ってobniz版OTTOに今流行りのパプリカを歌わせてみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">OTTOにパプリカ歌って踊らせてみた <a href="https://t.co/6W8Zq1ncjT">pic.twitter.com/6W8Zq1ncjT</a></p>&mdash; 田中みそ@LINE API Expertになりました！ (@miso_develop) <a href="https://twitter.com/miso_develop/status/1198059802846359553?ref_src=twsrc%5Etfw">November 23, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

圧電スピーカーで音を鳴らすのは周波数を渡すだけととても単純だったので、これを応用してobnizと圧電スピーカーを使って普段コードを打ち込んでるキーボードをキーボード（音楽用）に変えてみたいと思います。

# ハードウェア実装
まずは圧電スピーカーを用意します。
obnizの[パーツライブラリページ](https://obniz.io/ja/sdk/parts/Speaker/README.md)に秋月やSwitch Scienceの通販リンクがあります。
大きさとかで30円～100円と割と種類ありますが、なんでもいいと思います。
私は手元にあったやつを使いました。

![IMG_20191204_225038.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207109/02590e86-e5ff-3d1b-084c-1466a747aef2.jpeg)

このうち左下のやつは飛び抜けて音がでかかったため除外しました。
他のは大体同じ音量ですが、左上のは音が悪かったです。

そしてこれらをobnizに直挿しします。
ブレッドボードを使えば12個繋げられますが、obnizと言えばモーター然り直差しなので、このままいきます。

![IMG_20191204_221332.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207109/72acc44c-e8a3-caee-1589-42768ce29082.jpeg)


# ソフトウェア実装
キーボードのイベント拾うならHTMLで実装するのが手軽ですが、画面上にキーボードの画像表示してどこが押されてるかとかの描画もないといけない感じがするので、HTMLは使いません。
代わりにNode.jsで実装します。

Node.jsでリアルタイムにキーイベントを拾うには↓のパッケージが良さそうです。
**[iohook](https://www.npmjs.com/package/iohook)**

こんな感じでキーイベントだけでなくマウスポインターとかも拾えます。

```js:index.js
'use strict';
const ioHook = require('iohook');

ioHook.on("mousemove", event => {
  console.log(event);
  // result: {type: 'mousemove',x: 700,y: 400}
});
ioHook.on("keypress", event => {
  console.log(event);
  // result: {keychar: 'f', keycode: 19, rawcode: 15, type: 'keypress'}
});
//Register and stark hook 
ioHook.start();
```

あとは圧電スピーカーの制御コードをobnizの[パーツライブラリ](https://obniz.io/ja/sdk/parts/Speaker/README.md)からコピって、keydownで音鳴らしてkeyupで音止めるようにすればいいわけですね。



# 完成したコード
こちらが完成したコードです。
キーボードのキーコードとスピーカーで鳴らす周波数のマップオブジェクトを用意しています。
それと各圧電スピーカーの割当の制御とかも書いてます。
あとは上記で書いたような実装です。

`npm install obniz iohook`したうえで、obniz IDと各スピーカーのピン番号を書き換えて実行してみてください。

```js:index.js
"use strict"
const ioHook = require("iohook")
const Obniz = require("obniz")

const keymap = {
	"16": 370,	// F#3
	"30": 392,	// G3
	"17": 415,	// G#3
	"31": 440,	// A4
	"18": 466,	// A#4
	"32": 494,	// B4
	
	"33": 523,	// C4
	"20": 554,	// C#4
	"34": 587,	// D4
	"21": 622,	// D#4
	"35": 659,	// E4
	
	"36": 698,	// F4
	"23": 740,	// F#4
	"37": 784,	// G4
	"24": 831,	// G#4
	"38": 880,	// A5
	"25": 932,	// A#5
	"13": 988,	// B5
	
	"39": 1047,	// C5
	"41": 1109,	// C#5
	"27": 1175,	// D5
	"26": 1245,	// D#5
}

const obniz = new Obniz("xxxx-xxxx")
obniz.onconnect = async () => {
	const speakers = []
	speakers.push(	// スピーカーは繋げられるだけここに列挙
		{ assign: 0, obniz: obniz.wired("Speaker", {signal: 0, gnd: 1}) },
		{ assign: 0, obniz: obniz.wired("Speaker", {signal: 2, gnd: 3}) },
		{ assign: 0, obniz: obniz.wired("Speaker", {signal: 4, gnd: 7}) },
	)
	
	ioHook.on("keydown", event => {
		if (!keymap[event.keycode]) return
		
		if (speakers.some(speaker => speaker.assign === event.keycode)) return
		
		for (const speaker of speakers) {
			if (speaker.assign) continue
			
			speaker.assign = event.keycode
			speaker.obniz.play(keymap[event.keycode])
			return
		}
		
	})
	
	ioHook.on("keyup", event => {
		if (!keymap[event.keycode]) return
		
		for (const speaker of speakers) {
			if (speaker.assign !== event.keycode) continue
			
			speaker.assign = 0
			speaker.obniz.stop()
			return
		}
	})
	
	ioHook.start()
}
```

# キー割り当て

こんな感じで音程を割り当てています。

![assign.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207109/fe53884d-e5c5-f879-60ab-7d4005e20f1a.png)


# 演奏してる様子

ひとまずドレミファソラシド。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">obnizと圧電スピーカーでキーボードをキーボード（音楽）化した。 <a href="https://t.co/zwrHBUTPmE">pic.twitter.com/zwrHBUTPmE</a></p>&mdash; 田中みそ@LINE API Expertになりました！ (@miso_develop) <a href="https://twitter.com/miso_develop/status/1202221681214836737?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

スピーカー3つ繋いでるので3和音まで出せます。
（直差しじゃなければ12和音まで出せます）

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">スピーカー3つ繋げてるので3和音まで可。<br>（3つめのスピーカー音悪し） <a href="https://t.co/YmWEjWEhkQ">pic.twitter.com/YmWEjWEhkQ</a></p>&mdash; 田中みそ@LINE API Expertになりました！ (@miso_develop) <a href="https://twitter.com/miso_develop/status/1202222074376286208?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

最後に一曲演奏してみます。
なんの曲かわかったらまじ神です。

ちなみに所々音出てないのは回路やパーツやプログラムが悪いわけではなく、多分指を離すのが遅くて3和音鳴ってる状態のまま次のキー押しちゃってるのが問題です。
つまり演奏が下手なだけです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">一曲弾いてみた。<br>なんの曲か分かったらまじで神。<br>（所々音出てなかったりミスってたり…） <a href="https://t.co/2KwPZphHS8">pic.twitter.com/2KwPZphHS8</a></p>&mdash; 田中みそ@LINE API Expertになりました！ (@miso_develop) <a href="https://twitter.com/miso_develop/status/1202222824267501569?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

# おわりに
ここまで書いてそもそもこれはIoTなのか疑問になりましたが、obnizはネットにつながってないと動かないのでこれはきっとIoT。