MIDIUSB icon indicating copy to clipboard operation
MIDIUSB copied to clipboard

need delay to send messages reliably

Open chriswatrous opened this issue 7 years ago • 6 comments
trafficstars

Board: Arduino Due OS: Windows 10

I'm learning how to use this library and I'm having trouble getting messages sent in quick succession to send reliably. It seems I need to add a delay in between each message.

Is this expected behavior? Or is this a bug?

This is what I would expect to work:

#include <MIDIUSB.h>

void noteOn(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOff);
}

void setup() {
}

void loop() {
    noteOn(0, 52, 100);
    noteOn(0, 53, 100);
    noteOn(0, 57, 100);
    noteOn(0, 60, 100);
    MidiUSB.flush();
    delay(200);

    noteOff(0, 52, 100);
    noteOff(0, 53, 100);
    noteOff(0, 57, 100);
    noteOff(0, 60, 100);
    MidiUSB.flush();
    delay(200);
}

But only the first message of each group sends reliably. (recorded in FL Studio): image

I tried adding a flush after each event:

#include <MIDIUSB.h>

void noteOn(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOn);
    MidiUSB.flush();
}

void noteOff(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOff);
    MidiUSB.flush();
}

void setup() {
}

void loop() {
    noteOn(0, 52, 100);
    noteOn(0, 53, 100);
    noteOn(0, 57, 100);
    noteOn(0, 60, 100);
    delay(200);

    noteOff(0, 52, 100);
    noteOff(0, 53, 100);
    noteOff(0, 57, 100);
    noteOff(0, 60, 100);
    delay(200);
}

Same result: image

If I add a 50 microsecond delay it works.

#include <MIDIUSB.h>

void noteOn(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOn);
    delayMicroseconds(50);
}

void noteOff(byte channel, byte pitch, byte velocity) {
    midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
    MidiUSB.sendMIDI(noteOff);
    delayMicroseconds(50);
}

void setup() {
}

void loop() {
    noteOn(0, 52, 100);
    noteOn(0, 53, 100);
    noteOn(0, 57, 100);
    noteOn(0, 60, 100);
    MidiUSB.flush();
    delay(200);

    noteOff(0, 52, 100);
    noteOff(0, 53, 100);
    noteOff(0, 57, 100);
    noteOff(0, 60, 100);
    MidiUSB.flush();
    delay(200);
}

image

25 microseconds is not quite enough: image

Thanks for your help.

chriswatrous avatar Feb 19 '18 00:02 chriswatrous

I also looked at the messages in MIDI-OX and it confirmed what I saw in FL Studio.

chriswatrous avatar Feb 19 '18 00:02 chriswatrous

Hi @chriswatrous, it is probably related to the USB controller that drops (or, better, doesn't accept) data packets if they are too fast. Due is not our main dev target and its clock almost doubles the Zero family so probably the behaviour was unnoticed until now.

facchinm avatar Feb 19 '18 09:02 facchinm

Same issue here, also with a Due and Win 10. Putting a 50 microseconds delay in between each message is better, but it's still not 100% reliable. such a shame

SorenAndreasen avatar May 28 '18 11:05 SorenAndreasen

A workaround for this issue is sending multiple event packets at the same time with MidiUSB.write(*buffer, size).

Working code:

void sendNotes(midiEventPacket_t events[], size_t size) {
    uint8_t data[4 * size];
    for (unsigned int i = 0; i < size; i++) {
        data[0 + i * 4] = events[i].header;
        data[1 + i * 4] = events[i].byte1;
        data[2 + i * 4] = events[i].byte2;
        data[3 + i * 4] = events[i].byte3;
    }
    MidiUSB.write(data, 4*size);
}

Helguli avatar Mar 10 '21 17:03 Helguli

I've tried everything: flush after each sendMIDI, flush after several sendMIDI, delay 500 microseconds, delay 1 millisecond, delay 10 milliseconds. But there was always more or less missing note-off events, though the debug messages stated that sendMIDI method have been invoked. It seems to be the library is not useable for Due at all for some reason.

Update: Even with simple Serial.write and Hairless midi<->serial bridge it works without any glitches, no need any delays... Why would a library won't do that?

ivanmart avatar Mar 20 '22 17:03 ivanmart