-
Notifications
You must be signed in to change notification settings - Fork 1.2k
A CDC-like blocking behaviour for MIDI, incl. SysEx #618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thank you for your PR, issue 377 is the only reason 359 got reverted previously. It is necessary to re-test 377 for this PR to be merged. It should be reproducible with SAMD21/SAMD51 if it still exists, or just test with any mcu that you currently have and post your testing result here. |
All right, I could not make the example run on my hardware and could not be bothered to fix board definitions, so instead I tried the Blue Pill. I tested a similar setup under macOS, which is my daily OS of choice, and saw no problems other than MIDI Monitor acting ever so slightly sluggish. I used Reason 10, and had a MIDI device within it loop back the data. However, under Windows, the #377 error persists. So I went on and tried by SAMD21 hardware with my original firmware, which had ran perfectly fine before with loads of SysEx and stuff. Guess what? MIDI-OX didn't crash and worked as expected. Then I realized why. It's because my code is actually listening to the MIDI, while the example code doesn't. In fact, a similar thing happens if you do the opposite, on macOS at least. If you take a device with TinyUSB (or PluggableUSB, for that matter) and plug it into the Mac, if no host app is open, the device will eventually act sluggish and weird. It's a thing hard to spot with the TinyUSB example code, however the MIDI controller I'm developing has a lot of RGB LEDs, which reveal the issue. So to be sure it was the case I added two lines to
to read out the buffer. As expected, MIDI-OX ran just fine. To me though it makes perfect sense that you shouldn't really send data to a device that's not listening. In a way, #377 no longer seems like a proper test, rather an unintended operation. As a maker, why would one do it at all? As a developer, I would rather have been cautioned about this and have a robust data flow, because losing SysEx on input makes it plain unusable. The fix is pretty simple: a dummy read/flush function. I mean, I wish there was a way to keep this in check, but I understand that the only way to do so is to discard data from the buffer, which sends us back where we began. It also makes perfect sense that an OS MIDI driver shouldn't halt on this occurrence, but Windows' does. With that said, these are my findings, I'm barely an expert, so someone may prove me wrong. It's up to you to decide if this makes sense and the PR is worth it. |
The devices worked just fine with #359 and they still do. They work with any MIDI monitor/tool or musical software I tried on Windows. MIDI-OX might just not work correctly. It is unmaintained and the last release is 10 years old. It seems strange to work around this, as it is the only piece of software which appears to have problems. The simplest tool I could find for Windows is "Pocket MIDI", freely available from the Windows Store, and the examples/device/midi_test sketch appears to work just fine. |
@kaysievers true, Pocket MIDI works alright. I stand by my findings though, there seems to be a certain weirdness about Windows apps when the device isn't listening to data. I tested with Reason 10 for Windows, too. |
Hmm, do you mean midi_test.ino? There is a |
Nope, the MIDI example from TinyUSB: https://github.com/hathach/tinyusb/blob/master/examples/device/midi_test/src/main.c It has no reading function, and the overflow drove MIDI-OX crazy. I added lines (see above) that read out the buffer and it works fine. |
Ah, i see. That makes sense.
It's probably just old-school programming with blocking IO.
That should be added to the test in any case. MIDI devices which do not read incoming messages don't really exist in the real world. |
Well if this is true then a dummy read function should probably be added to both midi_test and dynamic_configuration examples with a comment explaining its presense. I could make a new PR with these changes, @hathach what do you think? |
Old serial MIDI has a fixed speed, and no flow control, conceptually it is just "broadcasting" data in a fixed format. Many devices have only one one-directional port, and communicate only in a single direction. The fixed speed makes it possible to avoid the concept of flow-control or client tracking. Transmitting devices just assume that the receiver is able to follow the entire stream of data it is interested in. It would usually not even know, if something, or how many devices are listening. With USB, data is transmitted at very different link speeds. It is always strictly point-to-point, and always bi-directional, even when only one direction is actually used in the device. With the old serial line, devices are not affected if nothing was listening to their data. USB is very different here, the sender and the receiver should deal with the fact that they always have a bi-directional point-to-point connection, even when they never use one of the directions:
The failure you see with the test program is that both sides are behaving badly at the same time. The current tinyusb's MIDI (without your or my patch) just throws away all packets which are not read fast enough. This solves the problem of the bad-behaving transmitter/software hanging in blocking IO. But this also makes it impossible to do any reliable data transfer that is faster and larger than the size of the buffer. You can only implement simple MIDI "toys" that play notes at the usual speed music is played, any SysEx data transfer at higher speed will always fail by corrupting the data stream.
Yes, I think this should be done. |
Thank you @homeodor and @kaysievers for following and testing the PR again. An proper testing with an additional pair of eyes is all this PR needed.
Would you also update the PR with the midi read as well, I actually haven't worked much with MIDI except for playing tone just enough for the demo. Afterwards, I don't see any reason to hold this back. |
Maybe you could add something like this to the dummy function as an explanation:
|
Also added a dummy readout for MIDI into examples
All right, I think it's all done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your PR. It looks perfect now. Should fix #377
This is basically a new try on what @kaysievers did in #359, with all the recent inner changes. It also has some functions rewritten in lieu of their CDC counterparts.
It might still cause issue #377, I haven't tested it this way, I don't have the hardware. However I'm pretty sure that I can feed loads of data into my SAMD21-based device and get 100% reliable transmission.
Two scenarios were tested, a ~6K worth of SysEx and complex lightshow data with thousands of notes, running at 500 BPM. SysEx is actually a file transmission with a checksum, so it's easily verifiable. No issues were encountered whatsoever. It is definitely a way to go for what I'm trying to achieve.
Any further testing is appreciated.
I hope that this is useful, however this is my first pull request ever, so if I did anything wrong, oops, sorry...