USBhost_t36 MIDI losing midi note on / off events (Teensy 3.6) during modwheel change

@rvh & @PaulS:

Unfortunately, I don't have an Arturia MiniLab MKII here, so can't provide any local testing of this proposal for you. Can you try the following modified (mods in RED) sketch to see if you see any positive effect (you'll need to make sure to select the USB Type in the Arduino IDE as "Serial + MIDI"):

Code:
...

Thanks for the suggestion, but it doesn't seem to change anything.

I have been experimenting with the values of MAX_PACKET_SIZE and RX_QUEUE_SIZE in the MIDIDevice_BigBuffer class in USBHost_t36.h. If I set them both to very large values (4000) the issue is substantially improved, but not entirely eliminated. I haven't found any values that totally fix it. But maybe that's of some help to figure out what the problem is?

-- edit -- after some more testing, I'm not so sure changing those sizes actually improves things much.

-- edit 2 -- But adding "USBHub hub1(myusb);" does now allow the host port to work with the unpowered HUB device, so thanks for that (maybe that was your main intention).
 
Last edited:
@rvh:

Sorry, I had to edit my previous post *several* times to get all of the device names correct. My TeensyMIDIPolySynth supports all three types of MIDI interfaces (traditional MIDI serial via 5-pin DIN connectors, usbMIDI via the USB interface used for serial monitor & programming, & usbhostMIDI via the USB host interface), so it was only a slight challenge to map & translate my device names to your device names. If possible, you might check the modified version again.

Mark J Culross
KD5RXT
 
@rvh & @PaulS:

Unfortunately, I don't have an Arturia MiniLab MKII here, so can't provide any local testing of this proposal for you. Can you try the following modified (mods in RED) sketch to see if you see any positive effect (you'll need to make sure to select the USB Type in the Arduino IDE as "Serial + MIDI"):

Code:
...

}

So when I use your code AND go via the unpowered hub, the issue seems to be resolved. Thanks very much! This is a tentative solution for me.

What is the likely reason it doesn't work if I don't go via the (unpowered) hub? Is the T4.1 talking to the hub at a different rate than when it is connected directly to the controller?
 
So when I use your code AND go via the unpowered hub, the issue seems to be resolved. Thanks very much! This is a tentative solution for me.

What is the likely reason it doesn't work if I don't go via the (unpowered) hub? Is the T4.1 talking to the hub at a different rate than when it is connected directly to the controller?

Sorry, that depth of understanding is way above my pay grade !! We'll have to hope that Paul Stoffregen notices this thread & can give some detailed insight.

Until then, glad to hear that you at least have an approach which appears to help avoid the problem !!

Mark J Culross
KD5RXT
 
So when I use your code AND go via the unpowered hub, the issue seems to be resolved. Thanks very much! This is a tentative solution for me.

What is the likely reason it doesn't work if I don't go via the (unpowered) hub? Is the T4.1 talking to the hub at a different rate than when it is connected directly to the controller?

I know of one unrelated T3.5 project which I use from time to time where teensy is a USB client and where a USB hub in between resolves all (and these are numerous critical) problems that's why I suggested you to use it. Now I guess the problem is due to undiscovered bugs in the teensy USB libraries...
 
I've been having a look at this, using a Teensy 4.1 and Arturia MiniLab Mk II. Nothing very useful to report, but I thought I'd list stuff I've done, for the record. It's entirely possible that something I've "looked at and eliminated" is actually still relevant or part of the issue - that's the nature of debugging.
  • I can reproduce the problem
  • all messages received at the USB callback make it to the sketch level
  • I've uncommented the #define USBHOST_PRINT_DEBUG in USBHost_t36.h to get debug output
  • I've never seen more than 2 MIDI messages per 1ms USB frame, so it doesn't seem to be buffer overflow
  • the receive queue management looks OK to me
  • putting a USB 1.1 hub in didn't work
  • putting a USB 2.0 hub in did work
  • the above may be due to the MiniLab being a Full Speed only device, so the USB 2.0 hub is doing some buffering
This is all fairly medium-level stuff, so I suspect the true issue lies lower down somewhere in ehci.cpp, and needs a fuller understanding of the USB functionality at register level than I have.

One minor improvement I'd make to the loop() code is this:
Code:
void loop() 
{
  myusb.Task();
  while (midi1.read())
     ;
}
This ensures all available messages are dealt with on every loop() iteration, allowing you to put other stuff in loop() without stalling the MIDI responses quite so badly. Doesn't fix the problem, though...
 
Remembering that it is possible to set the USB Device port [the micro-usb connector port] to 12Mbit full-speed instead of 480Mb high-speed, I skimmed through USBHost_t36.h, imxrt_usbhs.h and ehci.cpp to see whether that could be done for the host port as well.
Yes, it can, see ehci.cpp [to be found at C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\USBHost_t36\ehci.cpp]:

ehci.cpp-mod.png

When I uncommented line 267, compiled the code from message #13, uploaded it to the Teensy and powered the whole system down and up, I couldn't get the Arturia MIDI output to fail.
Did not test for an extended time though, so please give it a try with your setup as well.

Paul

Later I found this thread...
 
Remembering that it is possible to set the USB Device port [the micro-usb connector port] to 12Mbit full-speed instead of 480Mb high-speed, I skimmed through USBHost_t36.h, imxrt_usbhs.h and ehci.cpp to see whether that could be done for the host port as well.
Yes, it can, see ehci.cpp [to be found at C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\USBHost_t36\ehci.cpp]:

View attachment 31518

When I uncommented line 267, compiled the code from message #13, uploaded it to the Teensy and powered the whole system down and up, I couldn't get the Arturia MIDI output to fail.
Did not test for an extended time though, so please give it a try with your setup as well.

Paul

Later I found this thread...

Unfortunately forcing 12Mbit by uncommenting line 267 in ehci.cpp doesn't fix it for me, and I still get 'hanging notes'. In fact it's worse because adding the (unpowered) USB hub then doesn't resolve the issue anymore.

So for now, I'm still stuck with having to use a hub to make it work.
 
I've been having a look at this, using a Teensy 4.1 and Arturia MiniLab Mk II. Nothing very useful to report, but I thought I'd list stuff I've done, for the record. It's entirely possible that something I've "looked at and eliminated" is actually still relevant or part of the issue - that's the nature of debugging.
  • I can reproduce the problem
  • all messages received at the USB callback make it to the sketch level
  • I've uncommented the #define USBHOST_PRINT_DEBUG in USBHost_t36.h to get debug output
  • I've never seen more than 2 MIDI messages per 1ms USB frame, so it doesn't seem to be buffer overflow
  • the receive queue management looks OK to me
  • putting a USB 1.1 hub in didn't work
  • putting a USB 2.0 hub in did work
  • the above may be due to the MiniLab being a Full Speed only device, so the USB 2.0 hub is doing some buffering
This is all fairly medium-level stuff, so I suspect the true issue lies lower down somewhere in ehci.cpp, and needs a fuller understanding of the USB functionality at register level than I have.

One minor improvement I'd make to the loop() code is this:
Code:
void loop() 
{
  myusb.Task();
  while (midi1.read())
     ;
}
This ensures all available messages are dealt with on every loop() iteration, allowing you to put other stuff in loop() without stalling the MIDI responses quite so badly. Doesn't fix the problem, though...

Thanks for the added info. In my synth code I indeed use a 'while' rather than an 'if' to read the midi stream, but in the test program #13 the loop is so short I can't imagine it matters.
 
Unfortunately forcing 12Mbit by uncommenting line 267 in ehci.cpp doesn't fix it for me, and I still get 'hanging notes'.
After more testing today, I eventually got it to fail as well (albeit it that I had to work the keys and the modulation strip much faster then before].

Paul
 
Just curious, which unpowered hub (brand/model) do you use?

Paul

It's very small and cheap "SAMVOL" SY-H20. I'm using the host port on a synth that will be sold to others, so I need a simple/cheap solution for anyone that runs into this problem. Or hopefully when possible, we'll get revised host USB code that avoids the issue.
 
Bought a $6 LogiLink USB 2.0 hub for a test and can confirm that:
1. adding this hub solves the missing note-off/on events,
2. when forcing the USB host port to 12Mbs, adding this hub does not resolve the issue.

Paul
 
We'll have to hope that Paul Stoffregen notices this thread & can give some detailed insight.

I don't have an Arturia MiniLab. Even if I buy one, a test case involving manually playing a musical instrument isn't ideal. The actual MIDI messages transmitted and their relative timing is never consistent.

If you have time to experiment, please try to compose a small program I can run on a Teensy 4.0. It should have a number of usbMIDI.sendNoteOn(), usbMIDI.sendNoteOff(), usbMIDI.sendControlChange() which reliably reproduce the missing received message problem on Teensy 4.1 USB host.

For inspiration, please check out this Teensy 4.0 program I wrote to investigate another USB host MIDI issue (involving MIDI transmit rather than receive, and involving multiple USB MIDI devices). If anyone can write such a program to reliably reproduce this USB host MIDI receive issue, it will save time and let me investigate sooner.
 
If you have time to experiment, please try to compose a small program I can run on a Teensy 4.0
I had so I wrote a small program that kind of emulates the Arturia controller output using a Teensy 4.0.
Took me a few hours fiddling but finally got the error showing up: [GREEN is still OK, RED is where the erros start occuring.]

Serial  screendump.jpg

So it looks like a timing issue when (over)flooding the MIDI bus with data.

The emulation code spits out 16 notes ON, then 16 CC messages, then 16 notes OFF and then 16 CC messages.
This code only fails when both note_delay and CC_delay are 0 (zero). If either note_delay or CC_delay is 1 msec, then no errors occur:
Code:
[COLOR="#FF0000"]int note_delay = 0;
int CC_delay = 0;[/COLOR]

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  digitalToggle(LED_BUILTIN);                     // show loop activity

  for (int note = 0x3C; note < 0x4C; note++) {    // 16 notes ON
    usbMIDI.sendNoteOn(note, 0x3F, 1);            // incr notes ON, velocity 0x3F, channel 1
    delay(note_delay);                              
  }

  for (int i = 0; i <= 15; i++) {                 // send 16 CC messages
    usbMIDI.sendControlChange(0x01, 0x3F + i, 1); // send CC modulation wheel, incr mod value, channel 1
    delay(CC_delay);                             
  }

  for (int note = 0x4B; note > 0x3B; note--) {    // 16 notes OFF
    usbMIDI.sendNoteOff(note, 0x00, 1);           // decr notes OFF, velocity 0x00, channel 1
    delay(note_delay);
  }
  
  for (int i = 0; i <= 15; i++) {                 // send 16 CC messages
    usbMIDI.sendControlChange(0x01, 0x3F + i, 1); // send CC modulation wheel, incr mod value, channel 1
    delay(CC_delay);
  }

  while (usbMIDI.read()) {                        // ignore incoming messages
  }
}

I see you have been busy also in the meantime, so I will try your fix now and report back.

Paul
 
Last edited:
Really do not believe it will help with this problem. But if you have a little time to try replacing your ehci.cpp file, should be pretty easy to give it a try.

Found ehci.cpp here: C:\Users\Paul\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\USBHost_t36 and replaced it by the one attached to your message in the other thread.
Restarted the Arduino IDE and compiled the host code from message #13.

Well, the errors are still there. The serial output looks very similar, if not identical, to the screenshot from my previous message.

But later I checked the verbose compilation output and saw that ehci.cpp was used from another location:

Compilation verbose output.png

So I replaced ehci.cpp in C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\USBHost_t36 as well with your new version.
Again restarted the Arduino IDE and compiled the host code from message #13.

Unfortunately the errors are still there. So your guess is correct...

Paul
 
Looks like that program will transit an infinite non-stop flood of MIDI messages. Can the problem be reproduced with a large but finite burst?
 
Running the test here. Looks like 10 sets of messages is enough to reliably reproduce the problem.

Code:
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  delay(2500);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);                      // show loop activity
  for (int n = 0; n < 10; n++) {
    for (int note = 0x3C; note < 0x4C; note++) {        // 16 notes ON
      usbMIDI.sendNoteOn(note, 0x3F + n, 1);            // incr notes ON, velocity 0x3F, channel 1
    }
    for (int i = 0; i <= 15; i++) {                     // send 16 CC messages
      usbMIDI.sendControlChange(0x01, 0x3F + i, n + 1); // send CC modulation wheel, incr mod value, channel 1
    }
    for (int note = 0x4B; note > 0x3B; note--) {        // 16 notes OFF
      usbMIDI.sendNoteOff(note, 0x00 + n, 1);           // decr notes OFF, velocity 0x00, channel 1
    }
    for (int i = 0; i <= 15; i++) {                     // send 16 CC messages
      usbMIDI.sendControlChange(0x01, 0x3F + i, n + 1); // send CC modulation wheel, incr mod value, channel 1
    }
  }
  digitalWrite(LED_BUILTIN, LOW);
  elapsedMillis ms = 0;
  while (ms < 60000) {
    usbMIDI.read();                               // ignore incoming messages
  }
}

It's all wired up on my workbench. Hope to deep dive into the problem soon...

usb2.jpg
 
I've committed a fix on github.

https://github.com/PaulStoffregen/USBHost_t36/commit/bf4dd30135675716e3ab11e04da54602cf6e196c

Turned out to be an embarrassingly simple mistake. A boolean flag wasn't getting set to remember a packet buffer was queued for reception, which caused other parts to later misbehave. This particular path only get exercised if multiple USB packets arrive faster than the sketch code reads the MIDI messages.

New midi.cpp file is attached to this message.
 

Attachments

  • midi.cpp
    16.7 KB · Views: 88
I've committed a fix on github.

https://github.com/PaulStoffregen/USBHost_t36/commit/bf4dd30135675716e3ab11e04da54602cf6e196c

Turned out to be an embarrassingly simple mistake. A boolean flag wasn't getting set to remember a packet buffer was queued for reception, which caused other parts to later misbehave. This particular path only get exercised if multiple USB packets arrive faster than the sketch code reads the MIDI messages.

New midi.cpp file is attached to this message.

Thanks Paul. I tried the new midi.cpp file, but unfortunately the behavior with my Arturia Minilab seems unchanged. Still seems to work reliably only via the hub.
 
Please edit that midi.cpp file to add any syntax error. Does Arduino fail to compile it? If you're still seeing the old behavior, odds are you have multiple copies and replaced a copy which Arduino is ignoring.
 
Yes it fails with the appropriate message if I put in a syntax error. Hopefully PaulS will be able to try the file with his minilab too and let us know if he sees the same result.
 
Back
Top