M5StickCでBluetooth MIDIの受信試す

M5Stack

 そういえば、送信ばっかりで受信を試したことがなかったので、試してみました。これ。

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

 なるほど、いい感じです。これまで送信しか試してなかったのは、MIDIコントローラーを作るということしか考えてなかったからでした。以前、試していたのはこれ。

  arduino-esp32-BLE-MIDI

 これをもとにフットスイッチをつくったりしていたのです( M5Stack_BLE-MIDI-Footswitch )。

 受信ができればさらに用途が広がりそうです。というわけで、次に作ろうと考えたのは、送受信するやつ。当然です。
 前に作ったコードから、ボタンまわりとMIDIデータ送信部分を抜き出し、最初のリンクにあるコードに付け加えてみました。しかし、これが動かない。受信はできるけど、送信はできないまま。

 そんなこんなで、最初のリンクのコードと2つめのリンクのコードを見比べてみます。足りなそうなのを加えてみます(ほぼわかってない)。出来上がったのが、以下のコード。ボタンを押せば、MIDIノートを送信します(NOTE ON / NOTE OFF)。

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

//add
#include <BLE2902.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.setTextColor(WHITE, BLACK); //  add
            
            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();
      }
    }
};

// add
const int buttonON = LOW;
const int buttonOFF = HIGH;
///// Button
const uint8_t buttonPins[5] = {37, 39, 0, 26    }; //A, B, PIN 36除く (26/36/0) 
boolean buttonFlags[5];
uint8_t buttonNote[5] = {60, 64, 67,   71, 72};
uint8_t buttonCC[5] = {79, 80, 81,   82, 83};

void noteOn(uint8_t channel, uint8_t pitch, uint8_t velocity) {
  uint8_t midiPacket[] = {0x80, 0x80,  (uint8_t)(0x90 | channel), pitch, velocity };
  pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes
  pCharacteristic->notify();
}
void noteOff(uint8_t channel, uint8_t pitch, uint8_t velocity) {
  uint8_t midiPacket[] = {0x80, 0x80,  (uint8_t)(0x80 | channel), pitch, velocity };
  pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes)
  pCharacteristic->notify();
}

 
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.");

  // add
  pinMode(M5_BUTTON_HOME, INPUT);
  pinMode(M5_BUTTON_RST, INPUT);
   
  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());

  // add
  pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  pCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  // add
  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
  pSecurity->setCapability(ESP_IO_CAP_NONE);
  pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
 
  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() {

    //add
    for (int i = 0; i < 2; i++) {

      int buttonValue = digitalRead(buttonPins[i]);
      buttonValue = digitalRead(buttonPins[i]);

      if (buttonValue == buttonON && buttonFlags[i] == false) {

          // noteOn
          noteOn(0, buttonNote[i], 127);

        M5.Lcd.setTextSize(2);
        M5.Lcd.setTextColor(WHITE);
        M5.Lcd.fillRect(36 + i * 74 , 60 -1, 34, 16 +1, RED);
        M5.Lcd.setCursor(4 + i * 74 , 60);
        M5.Lcd.printf("%2d On", buttonPins[i]);

        delay(60); //

        buttonFlags[i] = true;
      } //if

      if (buttonValue == buttonOFF && buttonFlags[i] == true) {

        // noteOff
        noteOff(0, buttonNote[i], 127);

        M5.Lcd.setTextSize(2);
        M5.Lcd.fillRect( 36 + i * 74, 60 -1, 34, 16 +1, BLUE);
        M5.Lcd.setCursor(40 + i * 74, 60);
        M5.Lcd.printf("Off", buttonPins[i]);

        delay(60); //
        M5.Lcd.fillRect(0 + i * 74, 60 -1, 78, 16 +1, BLACK);

        buttonFlags[i] = false;
      } // if

        delay(8); //
    } //for
  
  delay(1);
}

 もとはM5Stack用に作ったやつなので、余計なコードも残ってますが、M5StickCで動くはずです。ペアリングがうまくいったりいかなかったりするので、M5StickCの電源入れたり切ったりします(これもわかってない)。理屈も押さえずなんとなくでやってるので、おかしなところがあったら教えていただけるとありがたいです。

 あと、アイキャッチのM5StickCの写真ですが、モバイル版のPhotoshopでテキトーなフィルターを使ったらわけがわからなくなりました。特に意味はないです。

 WindowsでのBLE-MIDI通信を双方向で行いたい場合は、MIDIberryの最新エディションMIDIberryMがオススメです。

 Download MIDIberryM

 っていうか、CakewalkがDAWで唯一、ネイティブにBLE-MIDI対応してるんで、ほんとはそれがオススメ。まだ、モノによってはちょっと怪しいことがありますけど。

コメント