lathoub / Arduino-BLE-MIDI

MIDI over Bluetooth Low Energy (BLE-MIDI) 1.0 for Arduino
MIT License
227 stars 33 forks source link

Midi steps audible when sending a stream of CC messages for volume control #71

Open jhsa opened 2 years ago

jhsa commented 2 years ago

As the tittle say, when I send midi CC messages from my volume pedal via BLE it seems to introduce some steps. This does not happen if I connect the Volume pedal directly to the other device via Midi, instead of using the Midi BLE I have on breadboard. Here is the code I am using. Do you see anything that could add delay to the midi? Or perhaps it comes from within a library? Thanks.

#include <Arduino.h>
#include <MIDI.h>
#include <Adafruit_TinyUSB.h>
#include "BLEMIDI_Transport.h"
#include "BLEMIDI_Client_ESP32.h"

BLEMIDI_CREATE_DEFAULT_INSTANCE(); //Connect to first server found
MIDI_CREATE_INSTANCE(HardwareSerial, Serial,  MidiSerial);

// USB MIDI object
Adafruit_USBD_MIDI usb_midi;

// Create a new instance of the Arduino MIDI Library,
// and attach usb_midi as the transport.
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MidiUsb);

byte Switch = 40;
int Led = 42; //modify for match with yout board
int MidiPwr = 41;
int timeout = 200;
bool isConnected = false;

void setup()
{
  BLEMIDI.setHandleConnected([]()
  {
    //    Serial.println("---------CONNECTED---------");
    isConnected = true;
    digitalWrite(Led, HIGH);
  });

  BLEMIDI.setHandleDisconnected([]()
  {
    //    Serial.println("---------NOT CONNECTED---------");
    isConnected = false;
    digitalWrite(Led, LOW);

  });

  pinMode(Led, OUTPUT);
  digitalWrite(Led, LOW);
pinMode(MidiPwr, OUTPUT);
  digitalWrite(MidiPwr, LOW);

   pinMode(Switch, INPUT_PULLUP);

  TinyUSBDevice.setManufacturerDescriptor("My_Manufacturer");
  TinyUSBDevice.setProductDescriptor("BLE_USB_Aapter");

  // Initialize MIDI, and listen to all MIDI channels
  // This will also call usb_midi's begin()
  MidiUsb.begin(MIDI_CHANNEL_OMNI);

  //  Serial.begin(115200);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MidiSerial.begin(MIDI_CHANNEL_OMNI);

  MidiSerial.turnThruOff();
  MIDI.turnThruOff();
  MidiUsb.turnThruOff();
delay(500);
  digitalWrite(MidiPwr, HIGH);
  }

  void loop()
  {
    if (MidiSerial.read()) {

      MIDI.send(MidiSerial.getType(),
                MidiSerial.getData1(),
                MidiSerial.getData2(),
                MidiSerial.getChannel());

      MidiUsb.send(MidiSerial.getType(),
                   MidiSerial.getData1(),
                   MidiSerial.getData2(),
                   MidiSerial.getChannel());
    }
    if (MIDI.read()) {

      MidiSerial.send(MIDI.getType(),
                      MIDI.getData1(),
                      MIDI.getData2(),
                      MIDI.getChannel());

      MidiUsb.send(MIDI.getType(),
                   MIDI.getData1(),
                   MIDI.getData2(),
                   MIDI.getChannel());
    }

    if (MidiUsb.read()) {
      MIDI.send(MidiUsb.getType(),
                MidiUsb.getData1(),
                MidiUsb.getData2(),
                MidiUsb.getChannel());

      MidiSerial.send(MidiUsb.getType(),
                      MidiUsb.getData1(),
                      MidiUsb.getData2(),
                      MidiUsb.getChannel());

    }
  }
lathoub commented 2 years ago

Why create usb_midi twice? Once here: Adafruit_USBD_MIDI usb_midi; en again (under another namespace) in the MACRO here: MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MidiUsb);

Not sure where TinyUSBDevice comes from.

Less important: set all behaviour (eg turnThruOff()) before opening.

jhsa commented 2 years ago

Why create usb_midi twice? Once here: Adafruit_USBD_MIDI usb_midi; en again (under another namespace) in the MACRO here: MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MidiUsb);

Not sure where TinyUSBDevice comes from.

Less important: set all behaviour (eg turnThruOff()) before opening.

I understand your first comment and I am trying to fix it by commenting Adafruit_USBD_MIDI usb_midi; But if I remove it, the code does not compile. The error is "usb_midi' was not declared in this scope". I used this example as my starting point, and the code is basically the same.

https://github.com/adafruit/Adafruit_TinyUSB_Arduino/tree/master/examples/MIDI/midi_test

I don't understand the second and the third, sorry. TinyUSB is the USB library I am using.

I also don't understand what you mean by " set all behaviour (eg turnThruOff()) before opening" What do you mean by Before Opening?

Also, I think that none of this has something to do with the stepping I am hearing on the Audio when I change the volume pedal??

lathoub commented 2 years ago

I'm trying to reproduce the issue - what hardware are you using?

But if I remove it, the code does not compile. The error is "usb_midi' was not declared in this scope".

Probably my bad, I'm not familiar with the TinyUSB - disregard my comment on this.

I also don't understand what you mean by " set all behaviour (eg turnThruOff()) before opening" What do you mean by Before Opening?

  MidiSerial.turnThruOff();
  MIDI.turnThruOff();
  MidiUsb.turnThruOff();
...
  MidiUsb.begin(MIDI_CHANNEL_OMNI);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MidiSerial.begin(MIDI_CHANNEL_OMNI);
jhsa commented 2 years ago

Ahh Ok, thanks for the tip on the MidithruOFF(). It's just I ntend to learn from the examples, and they see to have it after the MIDI.begin().

The Hardware I am using is the excellent ESP32-S3, which seems to be the only ESP32 currently capable of all flavours of MIDI. BLE, RTP, USB and Serial. This is fantastic. As you can see in the code, I made an adapter between all different MIDI connections. I might try to implement USB Host as well, but still didn't find some library for that..

jhsa commented 2 years ago
  MidiSerial.turnThruOff();
  MIDI.turnThruOff();
  MidiUsb.turnThruOff();
...
  MidiUsb.begin(MIDI_CHANNEL_OMNI);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MidiSerial.begin(MIDI_CHANNEL_OMNI);

Hmm, just tried this. It doesn't work, midi thru is not turned off. this has to be placed after the midi is initialized, as I had before, and as it shows in several examples. By the way, you can use the code I posted above as an example if you want. It works and it has a real life application. Anyway, the main question still remains, why is the BLE MIDI introducing steps when sending a Control Change stream for volume control?? Could it be that all that midi processing between all input/outputs is taking a long time to process?

jhsa commented 2 years ago

Nope, I have just reduced the amount of MIDI data being processed in the main Loop, and I still hear the steps. I think some library is introducing this steps. I wonder if there is some delay from the BLE connection itself. The strange thing is, I also get the steps if if I send the MIDI via USB instead of BLE.

lathoub commented 2 years ago

No clue 🕵️‍♀️ - if replacin the BLE link with USB doesn't fix the issue, it might not be related to the code visible here. Maybe in the way how you calculate the CC params at the source?

jhsa commented 1 year ago

No clue 🕵️‍♀️ - if replacin the BLE link with USB doesn't fix the issue, it might not be related to the code visible here. Maybe in the way how you calculate the CC params at the source?

Oh, didn't see your reply, I didn't get any notification. It is the BLE producing the audible stepping when I move the expression pedal. If I use wired MIDI there isn't any problem. But I will test again better tomorrow.