Issue: When connected to Win10 PC USB, sending MIDI clock (usbMIDI.sendRealTime) and MIDI notes, after about an hour the Teensy becomes very sluggish, eventually MIDI notes stop sending but clock still sends, though timing is erratic. This is fairly readily reproducible on our 3 Windows 10 PCs. This issue does NOT happen when connected to an iPad as USB host via camera connection kit.
After spending a few days trying to isolate the issue, we decided to just write some barebones code to do essentially what our own system is doing for clock and MIDI note output. So we whipped this up quick and dirty. The following will compile in Arduino with Teensyduino. There's a blink and some serial output just to see some activity, but you can use MIDI-OX or MIDIClock tool to monitor it. The MIDI sends section takes about 5uS.
Images of clock timing when Teensy goes in the the bad condition, on two different PCs:
Teensy 3.2
Teensyduino version: 1.42 (also tested with 1.41)
Arduino version: 1.8.5
Windows audio driver version: 4/11/2018, 10.0.17124.1
"Serial + MIDIx4"
96MHz (overclocked)
Optimize: "Fastest"
Test scenarios:
1) Send notes, but don’t send real time clock (by removing usbMIDI.sendRealTime calls) – fixes the issue
2) Send notes and clock to only one USB port – no change. That is, configured for only one virtual MIDI port rather than four.
3) On our system, we had an interrupt with a higher priority than USB. We changed the interrupt to a lower priority – fixes the issue, but its causing performance problems elsewhere. For instance, SPI display updates that cause a full screen redraw causes the MIDI clock to stutter badly. Hence the effort to fix this.
4) Once in the "condition" if we dynamically stop sending to USB MIDI the system returns to normal performance. We can use an encoder to change from USB to serial MIDI for instance, and performance returns. Then, clock out of HW serial is stable.
5)Doesn't happen with iPad as USB host even with our MIDI loop at a higher interrupt priority than USB.
6)Problem happens whether using a USB hub or directly connected to USB port on motherboard. USB 2 or USB 3 ports.
7)Doesn't seem to matter how fast or slow we are sending MIDI notes.
8)Doesn't seem to matter if software on Windows is consuming the notes or not. We've used MIDI-OX, DEXED and Arturia virtual instruments as MIDI receivers.
9)We recently added "usbMIDI.send_now();" as an experiment but it had no effect.
We could use some recommendations on how to further isolate the issue. It feels like a buffer problem or memory leak, but not sure how to measure it. Maybe some problem with interaction between Win10 USB or MIDI handler and Teensy USB MIDI?
After spending a few days trying to isolate the issue, we decided to just write some barebones code to do essentially what our own system is doing for clock and MIDI note output. So we whipped this up quick and dirty. The following will compile in Arduino with Teensyduino. There's a blink and some serial output just to see some activity, but you can use MIDI-OX or MIDIClock tool to monitor it. The MIDI sends section takes about 5uS.
Code:
#include <MIDI.h> // make sure to use Teensy optimized driver - 4x USB ports, etc...
unsigned int gMIDI_Count=0;
IntervalTimer T;
void setup() {
Serial.begin(57600); //'57600
Serial.println(F("Starting up Test"));
T.priority(96); // try 96 (higher than USB) or 128 (lower than USB)
byte responce = T.begin(MIDITicToc, 20833); // 20833 = 120 BPM
Serial.println(String("Responce = " ) + responce );
pinMode(13, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
}
void MIDITicToc() {
// SEND MIDI CLOCK OUT TO USB!!!!!!!!!!!!
usbMIDI.sendRealTime(usbMIDI.Clock, 0); //0xF8
usbMIDI.sendRealTime(usbMIDI.Clock, 1); //0xF8
usbMIDI.sendRealTime(usbMIDI.Clock, 2);
usbMIDI.sendRealTime(usbMIDI.Clock, 3);
usbMIDI.send_now();
gMIDI_Count++;
// double time LED blink
if (gMIDI_Count%12 == 0) digitalWrite(13, HIGH);
if ((gMIDI_Count+6)%12 == 0) digitalWrite(13, LOW);
//
if (gMIDI_Count%24 == 0) { // 24 typical for MIDI clock to beat 24 pulses per quarter note
usbMIDI.sendNoteOn(67, 127, 1, 0);
usbMIDI.sendNoteOn(67, 127, 1, 1);
usbMIDI.sendNoteOn(67, 127, 1, 2);
usbMIDI.sendNoteOn(67, 127, 1, 3);
usbMIDI.send_now();
//Serial.println(String("Play Note... ") + gMIDI_Count);
Serial.println(gMIDI_Count);
}
if ((gMIDI_Count+18)%24 == 0) { // 18 is 75% (of 24) gate time
usbMIDI.sendNoteOff(67, 0, 1, 0);
usbMIDI.sendNoteOff(67, 0, 1, 1);
usbMIDI.sendNoteOff(67, 0, 1, 2);
usbMIDI.sendNoteOff(67, 0, 1, 3);
usbMIDI.send_now();
//Serial.println(F("Stop Note..."));
}
}
Images of clock timing when Teensy goes in the the bad condition, on two different PCs:
Teensy 3.2
Teensyduino version: 1.42 (also tested with 1.41)
Arduino version: 1.8.5
Windows audio driver version: 4/11/2018, 10.0.17124.1
"Serial + MIDIx4"
96MHz (overclocked)
Optimize: "Fastest"
Test scenarios:
1) Send notes, but don’t send real time clock (by removing usbMIDI.sendRealTime calls) – fixes the issue
2) Send notes and clock to only one USB port – no change. That is, configured for only one virtual MIDI port rather than four.
3) On our system, we had an interrupt with a higher priority than USB. We changed the interrupt to a lower priority – fixes the issue, but its causing performance problems elsewhere. For instance, SPI display updates that cause a full screen redraw causes the MIDI clock to stutter badly. Hence the effort to fix this.
4) Once in the "condition" if we dynamically stop sending to USB MIDI the system returns to normal performance. We can use an encoder to change from USB to serial MIDI for instance, and performance returns. Then, clock out of HW serial is stable.
5)Doesn't happen with iPad as USB host even with our MIDI loop at a higher interrupt priority than USB.
6)Problem happens whether using a USB hub or directly connected to USB port on motherboard. USB 2 or USB 3 ports.
7)Doesn't seem to matter how fast or slow we are sending MIDI notes.
8)Doesn't seem to matter if software on Windows is consuming the notes or not. We've used MIDI-OX, DEXED and Arturia virtual instruments as MIDI receivers.
9)We recently added "usbMIDI.send_now();" as an experiment but it had no effect.
We could use some recommendations on how to further isolate the issue. It feels like a buffer problem or memory leak, but not sure how to measure it. Maybe some problem with interaction between Win10 USB or MIDI handler and Teensy USB MIDI?