蛇腹楽器(アコーディオン/バンドネオン)型MIDIコントローラーを作る

MIDIを使ってアコーディオンやバンドネオンといった蛇腹楽器を入力する際、あの蛇腹特有の強弱をうまく表現するにはどうしたらよいかが課題となるのは筆者だけではあるまい。おそらくペダルやホイールを使って入力したり、DAW上で鉛筆ツールでコントロールチェンジ(CC)のカーブをちまちま描いたりするのが普通で、まぁそれでなんとかなるものではあるが、今ひとつテンションが上がらない。ブレスコントローラーを使って息で入力するのもよさそうだと調べているうち、[ブレスコントローラーをDIYする方法を紹介している人](https://youtu.be/es92GqYBge0)をみつけた。ふーむ、同じ発想で蛇腹コントローラーも作れてしまうのではなかろうか？

というわけで試作してみた。[ジャージャジャージャ！ジャージャジャージャ！](https://youtu.be/zcIZntL3wqs?t=736)
![PXL_20220911_002356244.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/f8a9536c-7aee-5479-ba6d-3b3bedd6d1fd.jpeg)
実際に動作しているところは次の動画を見て欲しい(もしサムネイルが出ていなくてもビデオは存在しているのでクリックしてみて欲しい)。あらかじめ入力された音符に、このデバイスでボリュームコントロールを追加するというデモである。このデバイスは機能的にはブレスコントローラー相当で、音程を出力する機能がない(しかも同時に別のキーボードを弾くこともできない)ので、このようにあらかじめ入力された音程の上に強弱を当てる使い方になる。筆者の操作が本物の蛇腹楽器っぽい、あるいは音楽的に巧い表現かどうかはともかく[^1]、少なくとも**ベロシティ一定で無表情に入力された音符に対し、蛇腹操作によりしっかり表情が付けられている**という技術的成果はわかってもらえるだろう。

[^1]: 後から見ると、蛇腹の開閉はアコーディオンなら左手、バンドネオンなら両手で行うべきだが、右手を使っているのでその時点でもうおかしい。

<iframe width="560" height="315" src="https://www.youtube.com/embed/dIGZ_JCZtgU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

誰でも思いつきそうなもののわりには製作記事が公開されているのを見たことがなく、もしかしたら「本格的に蛇腹楽器を弾けるわけではないがその表現だけは模倣したいというDTM屋のための簡易デバイス」という意味では世界初かもしれないので、以下「自分もこんなものが欲しかった」という人の参考になるように解説を書いてみる。

# システム全体構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/20c16417-1ba0-049a-abdc-f0c406ff5054.png)
(1) 子供用アコーディオン: 3000円くらいで売っている[この手のもの](https://www.amazon.co.jp/dp/B0B14NZB7J)。改造して中に気圧センサーを仕込む。
(2)  気圧センサー: (1)の内圧を測る。気圧変化に対して感度の高いものであればなんでもよいが、定番の[BMP280](https://www.bosch-sensortec.com/products/environmental-sensors/pressure-sensors/bmp280/)がよいだろう。筆者は手元にあったのが[BME280](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/)だったので、温度計・湿度計を無効化してそちらを使った。
(3) Adruino: (2)の値を読み取り、USBシリアルでPCに送る。本当にそれだけなので大した性能は必要ないし、実際どんなマイクロプロセッサでも構わない。筆者はこれまた手元にあったM5StickCを使った。
(4) JabaraMIDI: (3)から送られてきた気圧データをもとにMIDIメッセージを作成、送出するカスタムアプリケーション。筆者が[Processing](https://processing.org/)で書いたものを後で紹介する。
(5) 仮想MIDIデバイス: アプリケーション間でMIDIメッセージを仲介する仮想MIDIデバイス。[loopMIDI](https://www.tobias-erichsen.de/software/loopmidi.html)というフリーソフトウェアを使って作成することができる。(4)にとってはMIDI出力デバイス、(6)にとってはMIDI入力デバイスに見え、(4)が送出したMIDIメッセージを(6)が受け取れるようになる。
(6) DAW: DAWやソフトウェア音源など、生成されたMIDIメッセージを最終的に受け取るアプリケーション。

本当は(3)ArduinoをPCから直接MIDIデバイスに見えるようにプログラムしたかったのだが、M5StickCのUSBコントローラーにはそういう柔軟性はなさそうだったので、センサーデータをUSBシリアルで生で送り、PC側で(4)(5)といったソフトウェアで仮想MIDIデバイスとして見せる構成とした。ちょっとダサい気もするが、デバッグや試行錯誤がしやすいというメリットもあり、最初の試作品の構成としては妥当だろう。[ESP32-S2といったボードを使えばUSB接続のMIDIデバイスを作れるらしい](https://esp32.com/viewtopic.php?t=22114)ので、これについては後日調査したいと思う。(追記: やってみた→https://qiita.com/tomoto335/items/d20aa668a62ad49cda36)

また、[BLE MIDIを使ってM5StickCをBluetooth接続のMIDIデバイスにできるらしい](https://qiita.com/siy1121/items/274dadeb0aa86b6655b8)のだが、試してみたところ筆者のPCからはデバイスの発見すらできず、また接続できたとしてもWindowsはBLE MIDIをネイティブサポートしていないため(4)(5)相当のものはいずれ必要となり、あまりメリットもないので早々に断念して上記の「ダサいが確実に動く」構成とした。

# デバイス側((1)～(3))解説

## センシング方式

アコーディオンの蛇腹は、普段は密閉されており、キーを押すと対応するリードの蓋が開いて音が鳴る仕組みになっている。またリードのついていない空気弁という穴もあり、この穴を開くと音を出さずに蛇腹を開閉して空気を出し入れできる。

ということは、リードまたは空気弁の穴に先述のDIYブレスコントローラーのようなセンサーを取り付け、穴を流れる空気の圧力を測ればよさそうである…というのが当初の考えであった。しかし、あのセンサーは少々ちゃんとした(難しいというわけではないが)工作が必要なので、もうちょっと簡単にPoCできないか？と考えた。楽するために考え抜くのはプログラマーの性である。

まず思いついた代案は音量測定方式である。「子供用とはいえこのアコーディオンは普通に音が出るのだから、その音をマイクで拾って音量をMIDIメッセージに変換すればよいではないか！簡単！天才！実はこれなら[DAW単体の機能でできる](https://steinberg.help/cubase_pro_artist/v9/ja/cubase_nuendo/topics/sample_editor_variaudio/sample_editor_variaudio_midi_extract_from_audio_t.html)んじゃね？」ということである。しかし、この方法は早々に諦めることになった。この楽器は非常に音が出にくく、安定した音を出すには大量の空気が必要で、この小さな蛇腹ではすぐに開閉しきってしまい音量コントロールどころではないのである。小さい動きを検出して実用に足るようにするには、やはり空気圧を直接測る方式でなければならないだろう。

次に思いついたのは内圧測定方式である。「蛇腹の開閉によりリードという負荷を通って空気が出入りするということは、内圧が外気圧に対して上下しているということだから、それを気圧センサーで測ったらどうか？」ということだ。これならアコーディオンのハウジングのどこかに気圧センサーを無造作に置くだけでよく、難しい工作が不要になる。一方この方式の欠点は、外気圧＝蛇腹を静止している状態の内圧を測っておく必要があり(キャリブレーション)、一方外気圧は気象により刻々と変化していくので、頻繁にキャリブレーションを行う、あるいは外気圧測定用にもうひとつセンサーを付けるなど、一工夫必要になることだ。

結局今回の試作では内圧測定方式を試してみた。結果はデモ動画でご覧いただいた通り、まあ意図通りに動作してくれている。

## キーで開閉 vs 開けっ放し？

もうひとつ機構上の設計判断として、キーによる穴の開閉機構を残す(キーを押したときだけ空気が流れる)か、それとも穴を開放する(キーを押さなくても蛇腹を動かせば常に空気が流れる)かがある。今回の試作では後者を選択した。

キーによる穴の開閉機構を残すメリットは、本物の蛇腹楽器の機構に近くなり、圧力をかけてから穴を開くことでブレスコントローラーでいうところのタンギングのようなアタックの表現が可能になる(かもしれない)ということだ。一方で、音程を別に入力せねばならないという本デバイスの宿命により、「別に入力された音程と完璧にタイミングを合わせてキーを押して穴を開く」ことが求められることになり、それでは難しすぎて使えない気がする。また、システム側にとっても非常に速い変化に精密に追随する必要があるはずで、数千円のDIYデバイスで目指すのは無理がありそうだ。

というわけで、後者の穴を開放する機構を取ることにした。これにより、キーは飾りで、「蛇腹を動かしたらその情報が常に出力される」というシンプルなデバイスとなる。これは本物の蛇腹楽器奏者にとっては違和感があるかもしれないが、このデバイスは蛇腹楽器シミュレーターのような上等なものではなく、単なる蛇腹の形をしたモジュレーションホイールでありエクスプレッションペダルであると割り切れば、(特に本物の蛇腹楽器奏者ではない自分にとっては)問題ない。実のところ、アタック部分の表情はシンセサイザーの音源波形の方に含まれているはずだからこのデバイスでそれを表現する必要はないとも考えられるし、まずは大雑把でも動く・手に負えるものを作ってみる方が本DIYプロジェクトの落としどころとして適切であろう。

## アコーディオンの改造とセンサーの取り付け

1. 左手側のハウジングを開く。
2. 中にあるボタンと穴の開閉機構を取り除く。
3. 空気弁の穴(A)を残し、リードのある音の出る穴(B)を塞ぐ。
4. ボタンの穴(C)を塞ぐ。
5. ハウジングの蓋のサウンドホール(D)を、どれかひとつを適当に残して塞ぐ。残した穴(E)は気圧センサーのコードを通すとともに、空気の(唯一の)出入口とする。
6. 気圧センサー(F)を適当なところに固定する。
7. Arduino(G)を気圧センサーに接続し、USBケーブルを繋いだ時に邪魔にならない適当な位置に固定する。
8. ハウジングの蓋を戻して再び固定する。

![PXL_20220911_001108287.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/35776fd4-8f85-7bbe-a578-8d3ecba1544e.jpeg)
![PXL_20220911_001554728.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/ec3289a0-88a8-3abb-9cf2-011ef5f813cd.jpeg)
真面目に穴に空気圧センサーを付けるより100倍簡単である！結局ゴールは以下の3点だけなので、やり方はいくらでもあり、ここで示したやり方にこだわる必要はない。

* 蛇腹とハウジングの間の穴を開放する
* ハウジングと外気との間の空気の流れを制限する(蛇腹の小さな動きでハウジングの内圧が上下しやすくなるように)
* ハウジング内のどこかに気圧センサーをつける

右手側のハウジングを使うとか、Arduinoをハウジングの中に入れてUSBコネクタやUSBケーブルを穴から出すとか、バリエーションはいろいろ考えられるだろう。

## Arduinoのプログラム

筆者はM5StickCで以下のプログラムを走らせている。BME280から気圧センサーの値を取得し、だらだらとUSBシリアルに書き込むだけである。値の解釈はすべてPC側で行うのでこちら側では何の処理も必要ない。別のボードやセンサーを使っていても、巷で公開されているサンプルプロジェクトやサンプルコードを参考に同じ処理を書くのは容易だろう。

https://gist.github.com/tomoto/096555a1468bdbf84335f10b9de4b66d?file=JabaraSensor.ino

高いサンプリングレートで滞りなくデータが撮れるよう、BME280の動作を次のように設定している。実際のサンプリングレートは余裕を持って50サンプル/秒(20ms周期)にしているが、100サンプル/秒(10ms周期)くらいまで上げられるかもしれない[^3]。
* 値の取得が滞りなく行えるよう、バックグラウンドで計測を走らせる(`MODE_NORMAL`)
* ~~気圧以外は測定しないようにして、計測時間が短くなるようにする(`SAMPLING_NONE`)~~ 気圧を正確に測るには温度による補正が必要らしく、気圧と温度は両方最速で測る(`SAMPLING_X1`)。湿度は測らない(`SAMPLING_NONE`)。
* 結果が若干良いように思えたので、フィルターをちょっとかける(`FILTER_X4`)
* 計測間は待ち時間なしでぶん回す(`STANDBY_MS_0_5`)

[^3]: 実際に100サンプル/秒まで上げてみたところ、デバイス側もPC側も問題なく処理できた。実際に演奏してみると確かにそのくらい欲しい。

# PC側((4)～(6))解説

## JabaraMIDI

PC上でシリアルポートからセンサーデータを読み出し、MIDIメッセージを生成して別のMIDIデバイスに送るカスタムアプリケーションである。筆者が書いたProcessingのコードを以下にポストしておく。シリアルポートが読めてMIDIメッセージを送れればPythonなど別の言語でも簡単に書けるはずだ。

https://gist.github.com/tomoto/096555a1468bdbf84335f10b9de4b66d?file=JabaraMIDI.pde

以下のようなパラメタがあるが、動作環境・演奏者・演奏スタイルが決まればそうころころ変えるものでもないので、ソースコードに決め打ちしてある。変える必要があればProcessing IDEでちょちょっと書き換えるか、頻繁に変える必要があるならUIに設定フィールドを追加すればよい。

* 出力先MIDIデバイス(midiOut): loopMIDIで仮想MIDIデバイスを作成する際に名前を "JabaraMIDI" にすれば変える必要はない。
* 入力シリアルポート(serialIn): Arduinoが接続されたシリアルポート名。
* 送出先MIDIチャンネル(midiChannel): 0始まりなので注意。
* 送出するCCのControl Number(midiControlNumber): 操作したい対象によって、Volumeなら7、Expressionなら11、Modulationなら1、などを指定。
* 出力されるCCの値の振れ幅(minValue, maxValue): 下図参照。
* 入力される気圧センサーの値の振れ幅(positiveScale, negativeScale): 下図参照。開き方向と閉じ方向とで異なる値を指定できる。
* カーブのかたち(curveFactor): 1.0だとCCの値は気圧変化に対して直線的に変化する。<1.0だとcompress(上に盛り上がるカーブ)、>1.0だとexpand(下に凹んだカーブ)のようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/e1cfacab-bb6c-f0d3-55cf-cd758d06a97e.png)
JabaraMIDIのアプリケーションウィンドウ上にはMuteボタンがある。このデバイスは放っておいても微妙な気圧変化でCCを垂れ流すので、演奏時以外はMuteボタンを押してMIDIメッセージ送出を止めるとよい。

### 基準気圧のキャリブレーション

JabaraMIDIによる基準気圧(蛇腹静止時の気圧＝外気圧)のキャリブレーションは、明示的な操作なしに行われる。3秒間センサーの値に変動がほとんどない場合、そのときの気圧が新たな基準気圧として随時更新されていく。

気象による気圧変化の影響はかなり大きく、数十秒の単位で変わっていくので、なるべく頻繁に3秒の静止状態を作るのが望ましい。特に開きと閉じのバランスが悪くなったと感じたら、基準気圧のずれが原因かもしれないので、3秒静止させキャリブレーションを行うとよい。

キャリブレーションが一度も行われていないとMIDIメッセージは送出されない。JabaraMIDI起動直後はデバイスをしばらく静止させて、アプリケーション画面上で値を示すバーが動き出すまで待つようにすること。

## loopMIDIの設定方法

JabaraMIDIの送出したMIDIメッセージをDAWなど別のアプリケーションで読むためには、仮想MIDIループバックデバイスと呼ばれるMIDIケーブルのような働きをする仮想的なMIDIデバイスをあらかじめPC上に作っておく必要がある。それを行うのが loopMIDI である。

(1) loopMIDIを実行して、"JabaraMIDI" という名前で仮想MIDIデバイスを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/dab310c2-8558-3848-1a5c-d4522c840cbc.png)
(2) JabaraMIDIアプリケーションの出力先MIDIデバイス(midiOut)を "JabaraMIDI" にしておく。これにより、送出されるMIDIメッセージはこの仮想MIDIデバイスに向かって送られることになる。

(3) 一方、DAWからもJabaraMIDIというMIDIデバイスが見えるようになり、JabaraMIDIアプリケーションが送出したMIDIメッセージはこのデバイスからやってきたものとしてDAWに認識される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/62643d69-502c-fbc8-06d7-f355af611350.png)
loopMIDIの設定は記憶されるので一度やるだけでよい。loopMIDIインストール時に自動起動オプションをオンにしていなければ、起動だけは手で(PCの起動につき一回)行う必要がある。この設定ができていない状態でJabaraMIDIアプリケーションを実行すると、出力先MIDIデバイスが存在しないというエラーが出る。

# リファレンス一覧

* [Simplest Breath Sensor for a MIDI Wind Instrument EVER - From a plastic water bottle](https://youtu.be/es92GqYBge0) (KontinuumLab)
  DIYブレスコントローラーの作り方。光学距離センサーCNY70とゴムの膜を使うところがユニーク。
* [USB MIDI Breath Controller](https://www.tecontrol.se/products/usb-midi-breath-controller) (TEControl)
  DIYでないUSBブレスコントローラーでおそらく最安。他のメーカー・機種はさらに高価。
* [チャラチャンラジオ18 ジャバミを気に入りすぎてしまった妹](https://youtu.be/zcIZntL3wqs) (チャラン・ポ・ランタン)
  ジャバミが呪いを解いてあげる！ジャージャジャージャ！ジャージャジャージャ！
* [BMP280データシート](https://www.bosch-sensortec.com/products/environmental-sensors/pressure-sensors/bmp280/) /  [BME280データシート](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/) (Bosch)
* [Processing](https://processing.org/) (processing.org)
  筆者がJabaraMIDIアプリを書くために使った言語。
* [loopMIDI](https://www.tobias-erichsen.de/software/loopmidi.html) (Tobias Erichsen)
  PC上に仮想MIDIデバイスを作り、複数のアプリケーション間でMIDIイベントを送受信するためのソフトウェア。仮想MIDIケーブルとも。
* [EspTinyUSB for ESP32-C3](https://esp32.com/viewtopic.php?t=22114) (Expressif)
  ESP32でUSBのMIDIデバイスを作りたければ対応したボードが必要というお話。
* [M5StickCで振って遊べるMIDIコントローラを作る](https://qiita.com/siy1121/items/274dadeb0aa86b6655b8) (@siy1121)
  M5StickCを使ったBLE MIDIデバイスの作り方。当初これが最も近道だと思われたが、Windows 11がデバイスを発見してくれず頓挫。
* [Why do Bluetooth LE / BLE Midi Controllers not work in Windows 11 any longer (WIn11 Home 64bit, latest (stable) updates)](https://answers.microsoft.com/en-us/windows/forum/all/why-do-bluetooth-le-ble-midi-controllers-not-work/7f1b0df9-1f3c-45e4-980d-e36ccf8bd1af)
  Windows上のBLE MIDIの問題。筆者の場合はそもそもデバイスが発見されない＆ペアリングできないのでここで議論されている症状とは異なるが、一筋縄ではいかないのは確かだろう。
* [MIDIberry](http://newbodyfresher.linclip.com/) (newbodyfresher)
  Windows上でBLE MIDIデバイスと対話するためのアプリケーション。WindowsはネイティブでBLE MIDIプロトコルをサポートしていないので必要なものだが、筆者の場合はそもそもデバイスがペアリングできなかった(本アプリケーション上でMIDIデバイスとして表示されない)ので使えず。
* [VariAudio](https://steinberg.help/cubase_pro_artist/v9/ja/cubase_nuendo/topics/sample_editor_variaudio/sample_editor_variaudio_midi_extract_from_audio_t.html) (Steinberg)
  オーディオデータの音量からMIDIデータを抽出するDAW機能の一例。この手の機能はプロフェッショナル向けなので有償のことが多い。