音楽関連素人の自分が初めてMIDIで色々通信してみた

## 皆さんこんにちは、[おの/るしわん](https://twitter.com/tkyko13)です。

[![Image from Gyazo](https://i.gyazo.com/c4b325d4fb5e791eeabbf063b46cc0fe.png)](https://gyazo.com/c4b325d4fb5e791eeabbf063b46cc0fe)

こちらの記事は[IoTLT Vol.68](https://iotlt.connpass.com/event/189403/)でLTさせていただいた内容を記事にしたものになります。
Qiitaのスライドの機能も利用しつつですが、LTでは話せない試したソースコードの内容など入れ込んでいければと思います。

---

## プロトアウトスタジオ([#protoout](https://twitter.com/search?q=%23protoout&src=typed_query))4期生の講師やってます

* 音楽関連に興味ある学生が2/6人
* Qiitaトレンドに6人全員が載ったことも！
* クラウドファンディングでサクセス目指して奮闘中！！
    * 12月7日から2週間の予定

ぜひ学生の活躍をご覧いただければと思います。

---

## 目次

* MIDIに関して、初心者の自分が調べてみてわかったこと
* 買った基板を試してみた（necobitさんの[MT-4](https://necobit.base.shop/items/31977892)）
* MIDI周りの技術を使ってみた(Bluetooth MIDI)

全体的に自分は今こんなのにワクワクしてますという内容です

---

## MIDIとは？

Musical Instrument Digital Interfaceの略

大本として同じだが、端子とファイル拡張子で同じ名前を混合して使われていることは知っていました

[![Image from Gyazo](https://i.gyazo.com/ea73b38e39172f7b5f576770f08c1e4a.png)](https://gyazo.com/ea73b38e39172f7b5f576770f08c1e4a)

--- 

今回調べて勉強になった点は、

* 端子の種類は3種類
    * inとoutが別れているので、通信は一方方向
    * thruは機能の一部のイメージだけども…
* 両脇2ピンは使ってないらしい
    * 一番真ん中がGND
    * その両脇でデータ通信
* USBでも同じ内容のデータを送ることもできる
    * USBでつなぐMIDIキーボードなんてのもある（これは以前から知っていた）
    * 送るデータは主に音色、音程、強さ
    * 音楽用らしく、同期信号も送っているらしい…

---

## そもそもなぜMIDIを扱おうと思ったのか

[MFTokyo2020](https://makezine.jp/event/mft2020/)で、[necobit](https://necobit.com/)さんの展示を拝見しました

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">スピーカー自作とかにもハマったけど、やっぱり行き着く先はアナログ音ですかねぇ<br>necobitさんの基盤買っちゃいました！<br> <a href="https://twitter.com/hashtag/mft2020?src=hash&amp;ref_src=twsrc%5Etfw">#mft2020</a> <a href="https://t.co/HPSZF8LEZk">pic.twitter.com/HPSZF8LEZk</a></p>&mdash; るしわん (@tkyko13) <a href="https://twitter.com/tkyko13/status/1312642500524343296?ref_src=twsrc%5Etfw">October 4, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

--- 

基板(MT-4)を購入しちゃいました。MIDIデータからソレノイドなど4つ動かせるものだそうです。

[![Image from Gyazo](https://i.gyazo.com/9f300129f1e995983a8793a095d069f5.jpg)](https://gyazo.com/9f300129f1e995983a8793a095d069f5)

--- 

Maker Faireの帰りにアキバへ寄りました。

目的はPCからMIDI端子に変える何かですね。
単純に、3.5mmジャックからMIDI変換を探しましたが、ありませんでした。
考えるとわかることでしたが、MIDIの送信しているデータは音程や強さですので、単純な変換ケーブルはなかったでした。
MIDIインターフェースのようなものもあり、USBで繋げるものもありますが、高価なものが多かったでした。

--- 

後日M5Stackのモジュールを再びnecobitさんから通販で購入し、PCからの音でなく、M5Stackからの音でMT-4を動かそうとしました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">かっちった…midiの端子ってまだまだ使うよなぁmidiインターフェイスも欲しくなってくるがああいうのめっちゃ高い〜<br>M5Stack用MIDIモジュール 2 を購入しました！ <a href="https://t.co/YBFcJfVjHt">https://t.co/YBFcJfVjHt</a> <a href="https://twitter.com/hashtag/BASEec?src=hash&amp;ref_src=twsrc%5Etfw">#BASEec</a> <a href="https://twitter.com/necobitter?ref_src=twsrc%5Etfw">@necobitter</a>より</p>&mdash; るしわん (@tkyko13) <a href="https://twitter.com/tkyko13/status/1314430699366047744?ref_src=twsrc%5Etfw">October 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

---

## M5Stackの演奏からファンを回す

[こちら](https://github.com/necobit/M5Stack-MIDI-Module)のサンプルコードからM5StackをArduinoで書き込んでいきます

今回はその中の「M5Stack_MIDI_T_RndSeq」から使っていきます

--- 

### 開発環境や利用したライブラリ
* Arduino 1.8.13
* [Arduino MIDI](https://playground.arduino.cc/Main/MIDILibrary/)
    * 自分はIDE内で検索してもなかなか見つからなかったのでZipでダウンロードしました

その他、サンプルコードによっては別途ライブラリが必要ですので、サンプルコード内のコメントを読み飛ばさないように…

--- 

### 動いた！

ランダムな値を通信しているものなので、演奏と一緒という感じではないですが、動かすことができました！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">M5StackのMIDIモジュールを使ってMT-4を介し、ちっちゃいですがファンを回しました！<br>本当はソレノイドで何か叩きたかったですが、いったん手元のもので成功<a href="https://twitter.com/hashtag/necobit?src=hash&amp;ref_src=twsrc%5Etfw">#necobit</a> <a href="https://twitter.com/hashtag/%E9%9B%BB%E5%AD%90%E6%A5%BD%E5%99%A8%E5%88%9D%E5%BF%83%E8%80%85?src=hash&amp;ref_src=twsrc%5Etfw">#電子楽器初心者</a> <a href="https://twitter.com/hashtag/%E6%B2%BC%E5%85%A5%E3%82%8A%E5%8F%A3?src=hash&amp;ref_src=twsrc%5Etfw">#沼入り口</a> <a href="https://t.co/lE9IIHUe1n">pic.twitter.com/lE9IIHUe1n</a></p>&mdash; るしわん (@tkyko13) <a href="https://twitter.com/tkyko13/status/1317359638099025920?ref_src=twsrc%5Etfw">October 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

--- 

配線とかは特に特殊なところはないですが、M5StackのMIDIモジュールのoutからMT-4へつなぎ、各電源をつなぐ
MT-4には、モーター用の電源ソケットがあるのでモーターに合わせたACアダプタをさす
自分は今回5Vで動く小さなファンだったので、5VのUSB-Cでつないでいます

[![Image from Gyazo](https://i.gyazo.com/f076b73ad9c906c6ed7143047995cd11.png)](https://gyazo.com/f076b73ad9c906c6ed7143047995cd11)

--- 

## Bluetooth MIDIの発見

* USBケーブルで同じようなデータ送るものもあるし確かにあってもおかしくない
* ちなみにWeb Bluetoothから利用することもできるみたい
    * https://qiita.com/ryoyakawai/items/200b3b05d8bd0096f68d

--- 

### MacでBluetooth MIDIを利用する

サンプルコードの「BLE-LOCAL_MIDI_Translator」を利用します。
このコードをArduinoでM5Stackに書き込みます。

--- 

次にMacで、[こちら](https://support.apple.com/ja-jp/guide/audio-midi-setup/ams33f013765/mac)を参考にしつつ、
「Audio MIDI設定」というアプリケーションから

[![Image from Gyazo](https://i.gyazo.com/c7be48e88ee05d410db57aa464c8da3a.png)](https://gyazo.com/c7be48e88ee05d410db57aa464c8da3a)

サンプルコードのままだと「M5」という名前で見つかるので接続します

--- 

例えば、「Garage Band」で流した音をM5Stackへ送りたい場合は、

[![Image from Gyazo](https://i.gyazo.com/070d6ddf483aad7cfab3892c853c1339.png)](https://gyazo.com/070d6ddf483aad7cfab3892c853c1339)

すでに設定には、接続されていると出てくる

これで行ける（と思う…）

--- 

### BLE-LOCAL_MIDI_Translatorのサンプルコードについて

BLEからLOCALに変換するコードだと思うのですが、2020年10月現在ではまだ変換されておらず、BLEで受け取ったデータをコンソール出力のみのようです

そこで自分が通信するデータを変えながらデータを観察し、どこにどのデータがあるのかを見て変換するソースコードを自作してみました（ただ音を止めるなどの処理がまだなので完璧ではないです！）

```cpp

#include <Arduino.h>

// M5STACK(ESP32)向け BLE MIDI
// Programed by Kazuyuki Eguchi 2018/04/24
// BLE->LOCAL Transrate code add by necobit 2020/07/03

#include <M5Stack.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

 #include <MIDI.h>
// MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI_H);
 MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI);

#define MIDI_SERVICE_UUID        "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
#define MIDI_CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3"
#define DEVIVE_NAME "M5"

BLEServer *pServer;
BLEAdvertising *pAdvertising;
BLECharacteristic *pCharacteristic;
int pos = 0;
char midi_s[5];
char midi_send[3];

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setTextSize(1);
      M5.Lcd.setCursor(10, 0);
      M5.Lcd.printf("BLE MIDI Connected.");
    };

    void onDisconnect(BLEServer* pServer) {
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setTextSize(1);
      M5.Lcd.setCursor(10, 0);
      M5.Lcd.printf("BLE MIDI Disconnect.");
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();
      pos = 0;

      if (rxValue.length() > 0) {
        for (int i = 0; i < rxValue.length(); i++)
        {
          midi_s[pos] = rxValue[i];
//          Serial.printf("%x ", midi_s[pos]);

          pos++;

          if (pos == 5)
          {
            //7bit
//            char tone = midi_s[2] << 1;
//            tone = tone >> 1;
            char pitch = midi_s[3] << 1;
            pitch = pitch >> 1;
            char vel = midi_s[4] << 1;
            vel = vel >> 1;

            MIDI.sendNoteOn(pitch, vel, 1);

            Serial.printf("%d ","%d ", pitch, vel);
            
            pos = 0;
          }
        }
        Serial.println();
      }
    }
};

void setup() {
  M5.begin();
  Serial.begin(115200);
  Serial2.begin(31250);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(10, 0);
  M5.Lcd.printf("BLE MIDI Disconnect.");

  BLEDevice::init(DEVIVE_NAME);
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(BLEUUID(MIDI_SERVICE_UUID));
  pCharacteristic = pService->createCharacteristic(
                      BLEUUID(MIDI_CHARACTERISTIC_UUID),
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_WRITE_NR
                    );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  oAdvertisementData.setFlags(0x04);
  oAdvertisementData.setCompleteServices(BLEUUID(MIDI_SERVICE_UUID));
  oAdvertisementData.setName(DEVIVE_NAME);
  pAdvertising = pServer->getAdvertising();
  pAdvertising->setAdvertisementData(oAdvertisementData);
  pAdvertising->start();
}

void loop() {
//  delay(10);
}
```

送られてくるバイナリ配列の

* 2番目 - tone、音色
* 3番目 - pitch、高さ
* 4番目 - vel、強さ

でした。これはMIDIで送るデータの主なものですので、これでMT-4へ`MIDI.sendNoteOn()`で送ることができます。

--- 

## Garage Bandからファンを回せたら楽しいよね

まだコードが完成してないですが、できそうなことはわかりました

やはり何か既存のアプリケーションからファンを回したり、モーターを回したりすることは何かもっと身近に電子工作が入ってくる感じがしてすごく面白く感じますし、普段の行動をハックするようなものだったり、Arduinを普段使わない人にも使ってもらえそうになる気もしました