M5StickC(ESP32)にWindows10からBLE-MIDIでリアルタイム数値送信をしてみる

現時点の情報です。最新情報はM5StickC非公式日本語リファレンスを確認してみてください。

概要

ESP32を搭載しているM5StickCに対して、リアルタイムにパラメータ値を送信してみたくなり、パソコンからBLE-MIDIを使って送信してみました。

BLE-MIDIとは?

MIDI over Bluetooth LEの略であり、Bluetoothを使ってMIDI信号を送受信するプロトコルです。あまり一般的ではなく、Windowdだと標準サポートされていないので、別途アプリが必要になります。

MIDIとは?

楽器などのデータを送受信するプロトコルで、主にケーブルを使って従来は接続をしていました。中身はUARTのシリアルデータでキーボードなどの、どのキーをどれぐらいの強さで押したとか、離したとかのデータを通信を行っています。

音楽以外の分野でも使われており、ライブハウスなどの照明のコントロールとかもMIDIの場合があります。

実現したいこと

MIDIコントローラーのボリューム値などを、M5StickCに送信してリアルタイムにパラメータを変更したい!

類似技術

blynkなどを利用して、スマホなどから操作するシステムはあります。ただ実際のボリュームとか、ハードウエアで操作したくなることってありますよね?

用意したMIDIコントローラー

かなり古めのUSB接続のMIDIコントローラーです。DJ用なのかな?

MIDIコントローラーは、USBジョイスティックなどと同じで、これ自体ではなにもできず他のアプリと連携して使います。MIDIやジョイスティックは規格が統一されているので、設定を変えることで、比較的どんなコントローラーでも接続することが可能です。

MIDIコントローラーがない人向け

実は、ChromeなどのブラウザはWeb MIDI APIに対応しており、ブラウザからKORGのnanoKONTROL2相当の操作が可能です!

このコントローラーですね。小さくてかわいいです。

Windows側の設定

ここが結構面倒です。WindowsはBLE-MIDIに対応していませんので、なにかソフトを入れる必要があります。

KORG BLE-MIDI Driver

上記が定番でしたが、正規の使い方でないのとWindows10だとうまく動かなくなっている気がします。これが動けば一番カンタンです。BLE-MIDIとしてESP32を認識してくれて、仮想MIDIポートを作成してくれます。

Windows Updateで動かなくなったり、動いたりと不安定です。また、「インテル® ドライバー & サポート・アシスタント」などで最新ドライバーをいれると動くことがあります。

MIDIberry

私は上記ソフトを利用させていただきました。ただこのアプリでBLE-MIDIとしてESP32を認識して、他のとMIDIポート接続することができます。

このアプリは仮想MIDIケーブル的な動きになり、MIDIポートとMIDIポートを接続するような動きをしてくれます。

loopMIDI

ハードウエアのMIDIコントローラーを使うときには必須ではないですが、ブラウザ上などのWeb MIDI APIを利用する場合に必要になるソフトです。

仮想MIDIポートを作成してくれます。他のMIDI仮想ケーブルソフトなどを使って、中継として利用します。

MIDI接続図

ハードウエアMIDIコントローラーの場合

ハードウエアのMIDIコントローラーを接続した場合には、上記のような図になります。MIDIコントローラーがMIDIポートとして認識されるので、MIDIberryでESP32のBLE-MIDIと接続してあげます。

ブラウザベースのMIDIコントローラーの場合

Web MIDI APIはMIDIポートとの接続する、仮想ケーブルです。MIDIBerryも仮想ケーブルのため、そのままだと接続できません。そこで仮想MIDIポートのloopMIDIを使うことで、接続することが可能になります。

M5StickCの設定

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

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

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

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

    void onDisconnect(BLEServer* pServer) {
      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++)
        {
          Serial.printf("%02x", rxValue[i]);
          midi[pos] = rxValue[i];
          pos++;
          if (pos == 5)
          {
            M5.Lcd.setTextSize(3);
            M5.Lcd.setCursor(10, 30);
            M5.Lcd.printf("%02x %02x %02x", midi[2], midi[3], midi[4]);
            pos = 0;
          }
        }
        Serial.println();
      }
    }
};

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(WHITE, BLACK);
  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(1);
}

受信して、画面に表示するスケッチです。

上記のコードをベースにM5StickC用に表示だけ変更しています。BLE MIDIとして待ち受けて、MIDI信号を受信するだけのシンプルなコードです。

接続方法

Windows10のBluetoothにデバイスを追加する

M5StickCという名前で待ち受けしているので、Windows10から追加します。BLE-MIDIドライバが入っていると、この時点でMIDIポートが作成されるのですが、通常はこのままでは利用できません。

MIDIコントローラーを接続する

ハードウエアMIDIコントローラーの場合

USBケーブルで接続して、本体の電源をいれればMIDIポートして認識されます。

ブラウザベースのMIDIコントローラーの場合

loopMIDIで仮想MIDIポートを1つ作成します。

ChromeなどのWeb MIDI APIに対応したブラウザで開きます。最初にMIDIへのアクセスを許可するか聞かれると思いますので、許可します。その後に左上のMIDIポートをloopMIDIで作成した仮想MIDIポートに指定します。

MIDIberryで接続させる

入力にハードウエアMIDIコントローラーのMIDIポートか、ブラウザベースのMIDIコントローラーに接続したloopMIDIの仮想MIDIポート選びます。出力にはM5StickCのBLE-MIDIを選択します。

この状態でボリュームなどを変更すると、上記のように入力モニターに値がでます。

M5StickCでも同じ情報が受信できています。3バイトのデータで、チャンネルとイベント種別、値などのデータになっています。

ボリュームは0から127までの値なので、それより細かい調整をしたい場合には複数のボリュームを組み合わせて制御をする必要があります。

この辺のチャンネルなどは使っているMIDIコントローラーによって、ちょっと動きが違うので、使っているものに合わせて自分でカスタマイズする必要があります。

まとめ

MIDIは興味がって、いろいろ機材を準備しているのですが、なかなか手が出せていなかったので、かんたんに使ってみました。

画面処理がM5StickC用になっていますが、BLE-MIDI自体はすべてのESP32で動かすことができます。

備考

上記に送信も対応したソースがあります!

コメントする

メールアドレスが公開されることはありません。

管理者承認後にページに追加されます。公開されたくない相談はその旨本文に記載するかTwitterなどでDM投げてください。またスパム対策として、日本語が含まれない投稿は無視されますのでご注意ください。