Page 1 of 1

BLE MIDI randomly disconnects and only works on Linux

Posted: Tue Aug 14, 2018 6:43 pm
by PieterP
Hi, I'm trying to use Bluetooth Low Energy to send and receive MIDI messages.

There are 2 main problems:

1. On Linux (using BlueZ 5.50), it works, and the MIDI events show up in my MIDI monitor. However, after some time (ranging from a couple of seconds to many minutes), it randomly disconnects, and doesn't automatically connect again. I have no idea why this is.

2. On Windows 10, I can connect to the ESP32, but even though it says "connected" in the Windows settings, but in the Serial Monitor, it says "Disconnected" 2 or three seconds after "Connected".
Between the "Connected" and "Disconnected", the "notify" fails, because "notifications disabled; ignoring".

On Android, I can see it using the Bluetooth settings, and I can pair, but I can't do anything with it. It doesn't show up when scanning using the MIDI BLE Connect app.
[hr]
I'm using this example and Neil Kolban's BLE library that comes with the ESP32 Arduino Core:

Code: Select all

/*
    BLE_MIDI Example by neilbags 
    https://github.com/neilbags/arduino-esp32-BLE-MIDI
    
    Based on BLE_notify example by Evandro Copercini.

    Creates a BLE MIDI service and characteristic.
    Once a client subscibes, send a MIDI message every 2 seconds
*/

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

#define SERVICE_UUID        "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
#define CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

uint8_t midiPacket[] = {
   0x80,  // header
   0x80,  // timestamp, not implemented 
   0x00,  // status
   0x3c,  // 0x3c == 60 == middle c
   0x00   // velocity
};

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      Serial.println("Connected ++++++++++++++++++++++++++");
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      Serial.println("Disconnected -----------------------");
    }
};

void setup() {
  Serial.begin(115200);

  BLEDevice::init("ESP32 MIDI Example");
    
  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID));

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
    BLEUUID(CHARACTERISTIC_UUID),
    BLECharacteristic::PROPERTY_READ   |
    BLECharacteristic::PROPERTY_WRITE  |
    BLECharacteristic::PROPERTY_NOTIFY |
    BLECharacteristic::PROPERTY_WRITE_NR
  );

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
}

void loop() {
  if (deviceConnected) {
   // note down
   midiPacket[2] = 0x90; // note down, channel 0
   midiPacket[4] = 127;  // velocity
   pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes
   pCharacteristic->notify();

   // play note for 500ms
   delay(500);

   // note up
   midiPacket[2] = 0x80; // note up, channel 0
   midiPacket[4] = 0;    // velocity
   pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes)
   pCharacteristic->notify();

   delay(500);
  }
}
I added the debug output and a WireShark capture as attachments. (I only have a capture on Linux, Bluetooth capture is not supported on Windows, AFAIK.)

I have no idea how to debug this, so any help or pointers would be greatly appreciated.

Thanks,
Pieter

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Wed Aug 15, 2018 12:49 pm
by chegewara
For android i prefer this one:
https://play.google.com/store/apps/deta ... dsynthmidi

On esp32 try this, it works on windows and android for me:
https://github.com/nkolban/esp32-snippets/issues/510

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Wed Aug 15, 2018 9:38 pm
by PieterP
Hi, thank you for your response.

I tried the first sketch in that GitHub issue, but it doesn't work for me. Windows behaves the same (Windows says connected, ESP says "notifications are disabled", ESP says disconnected, Windows still says connected). Fluidsynth on Android finds the ESP, and it shows up as "MIDI", it says "Port opened OK", but it doens't play anything, I tried an Android MIDI monitor as well, it sees the MIDI device (created by Fluidsynth), but no MIDI events are reported.
Linux is not happy with the security options, it gives errors in dmesg when I connect to it:

Code: Select all

[  +0,089796] Bluetooth: hci0: security requested but not available

Garageband on iOS also sees the device, but I can't connect to it.

I haven't been able to compile the second sketch. Is this for the Arduino environment, or do I need to compile it using ESP-IDF?

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Thu Aug 16, 2018 5:15 am
by chegewara
Second one is for esp-idf, but you can reuse only part of code in first listing. Try to copy/paste part of code that is about secured connection. You can also see how it looks like in this repository for arduino (secured connection).

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Thu Aug 16, 2018 9:58 am
by PieterP
I tried using the setup part of the second program in the first one. This is what I ended up with:

Code: Select all

/*
  Based on:
    BLE_MIDI Example by neilbags
    https://github.com/neilbags/arduino-esp32-BLE-MIDI

    Based on BLE_notify example by Evandro Copercini.

    Creates a BLE MIDI service and characteristic.
    Once a client subscibes, send a MIDI message every 2 seconds
*/

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

uint8_t note = 64;

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

uint8_t midiPacket[] = {
  0x80,  // header
  0x80,  // timestamp, not implemented
  0x00,  // status
  0x3c,  // 0x3c == 60 == middle c
  0x00   // velocity
};

class MyCallbacks: public BLEServerCallbacks, public BLECharacteristicCallbacks {
    void onConnect(BLEServer* pServer) override {
      deviceConnected = true;
      Serial.println("Connected!");
    };

    void onDisconnect(BLEServer* pServer) override {
      deviceConnected = false;
      Serial.println("Disonnected!");
    }

    void onWrite(BLECharacteristic* pChar) override {
      std::string value = pChar->getValue();
      const uint8_t * const data = reinterpret_cast<const uint8_t * const>(value.data());
      size_t len = value.size();
      Serial.print("Write: ");
      for (size_t i = 0; i < len; i++)
        Serial.printf("%02x ", data[i]);
      Serial.println();
    }

    void onRead(BLECharacteristic* pChar) override {
      Serial.println("Read");
      pChar->setValue("");
    }
};

void setup() {
  Serial.begin(115200);

  static MyCallbacks cb;

  BLEDevice::init("TEST");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(&cb);

  BLEService* pService = pServer->createService("03b80e5a-ede8-4b33-a751-6ce34ec4c700");
  pCharacteristic = pService->createCharacteristic("7772e5db-3868-4112-a1a9-f2669d106bf3",
                                                    BLECharacteristic::PROPERTY_READ   |
                                                    BLECharacteristic::PROPERTY_NOTIFY |
                                                    BLECharacteristic::PROPERTY_WRITE_NR
                                                  );

  pCharacteristic->setCallbacks(&cb);

  pCharacteristic->addDescriptor(new BLE2902());
  pService->start();


  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->addServiceUUID(pService->getUUID());
  pAdvertising->start();


  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);

  ESP_LOGD(LOG_TAG, "Advertising started!");
}

void loop() {
  if (deviceConnected) {

    note = note + random(-5, 5);
    note &= 0x7F;
    
    // note down
    midiPacket[2] = 0x90; // note down, channel 0
    midiPacket[3] = note;
    midiPacket[4] = 127;  // velocity
    pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes
    pCharacteristic->notify();
    // play note for 500ms
    delay(500);

    // note up
    midiPacket[2] = 0x80; // note up, channel 0
    midiPacket[3] = note;
    midiPacket[4] = 0;    // velocity
    pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes)
    pCharacteristic->notify();

    delay(500);
  }
}
  • Ubuntu Linux 16.04 (BlueZ 5.50): still works, still plays the notes, but also still disconnects after a short period of time
  • iOS 11.4.1: can connect to the ESP using Garageband, and it plays the notes. No disconnects encountered yet.
  • Android 8.1.0: can connect to it using Fluidsynth and it plays the notes, but once it disconnects, I cannot connect to it again, and I have to reboot my phone.
  • Windows 10 (1803) : still the same problem as described in my first post: it connects and immediately disconnects, but still says "connected" in the Windows settings.
I'll try a different Windows and Linux machine to see if it has the same problems.

How did you test it under Windows? How did you connect it? What MIDI software did you use?

Thank you.

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Tue Aug 21, 2018 8:13 am
by PieterP
Any ideas? How can I debug problems like this?

Re: BLE MIDI randomly disconnects and only works on Linux

Posted: Tue Aug 21, 2018 5:12 pm
by chegewara
I dont know what to say. Your code perfectly works on my samsung s9+ with android 8.0. Fluidsynth connects as many times as i want without issues.

On windows ive been using MIDIberry. Also, your code tested and works fine. Windows 10 pro. More, windows auto-reconnect because devices are paired.