midi: allow bigger sysex messages to be sent, such as the OLED image - #174
Conversation
|
I have tested these for
I will try to find a way to test the last one before marking this as ready |
fe72bae to
b39b9b2
Compare
|
Looking forward to this one going in. |
Some simplifications were made to the driver code by Rohan under the assumption we were only going to queue up to 32 usb-midi messages for a device per "tick" of the main routine. These had to be reconsidered, like there is now again a callback from the usb driver interrupt back to midi_engine to check for more data to send. It doesn't seem to be possible to increase the amount of data sent in each call to the driver more than 32 messages (or 128 bytes). Instead, implement a ring buffer for midi data waiting to be sent over USB. When we get an interrupt for usbSendComplete, we can check the ring buffer again and restart the low-level send until the ring buffer is empty. Implement a sysex request for sending the contents of the OLED display as a sysex reply message. This needs more work before being generally useful as an external display, but serves as a test case for larger sysex messages.
…icies These objects are intended to be used this way. If disconnected these get disabled, but not pointers into invalid memory above class MIDIDevice: > These never get destructed. So we're safe having various Instruments etc holding pointers to them.
|
Update: sending as a host to devices now works for most devices. a buffer limit of 64 bytes seems common, so lets use that for devices. some devices have even lower limits tho, like my MIDIMATE II serial MIDI to USB converter which only accepts sending one (1) midi packet at a time. (We could try to figure this out from the configuration data, I tried with the |
m-m-adams
left a comment
There was a problem hiding this comment.
I've added some comments where I think this could be improved a bit.
The only big issue is that the current behaviour of send all messages to all devices doesn't work well for sysex since it's much more data and sysex parsing bugs are very common (especially with older gear). In peripheral mode that's fixable by enabling the third upstream port (already in the config), in host mode it would need some extra code to check that the device being sent to is the one requesting data
| class MIDIDeviceUSBUpstream final : public MIDIDeviceUSB { | ||
| public: | ||
| MIDIDeviceUSBUpstream(uint8_t portNum = 0) { portNumber = portNum; } | ||
| MIDIDeviceUSBUpstream(uint8_t portNum = 0) : MIDIDeviceUSB(portNum) {} |
There was a problem hiding this comment.
Is the portnum still necessary after giving it a default value in the mididevice USB class?
| // (3 payload bytes per USB-MIDI message) | ||
| #define MIDI_SEND_BUFFER_LEN 32 | ||
| // NOTE: increasing this even more doesn't work. | ||
| // Looks like a hardware limitation (maybe we more in FS mode)? |
There was a problem hiding this comment.
I've just been reading the the usb midi spec and we might be able to use the maximum buffer size specified by a downstream device instead of this guesswork.
|
|
||
| for (int d = 0; d < MAX_NUM_USB_MIDI_DEVICES; d++) { | ||
| if (connectionFlags & (1 << d)) { | ||
| connectedDevice = &connectedUSBMIDIDevices[ip][d]; |
There was a problem hiding this comment.
I don't believe this works properly, won't it just send to the first connected device? Since each ConnectedUsbMidiDevice holds an array of 4 USBMidiDevices it should check that the current device is actually held by the connecteddevice it finds
There was a problem hiding this comment.
This follows the existing logic in sendMessage and it does seem to work. connectionFlags is private to the inner USBMIDIDevice and should only have a flag set for the specific connected device. It's a bit weird way of structuring things tho.
What I think we don't support at all is virtual port/cable differentiation for a specific connected device. That would be an important follow-up refactor.
This is already what this branch implements. Sysex replies are being sent to the specific device that sent a request. not sure what makes it seem like otherwise. I agree the thrird port should be added at this point, but differentiation between virtual ports is already implemented (request the oled data on virtual midi out 2; get a reply on virtual midi in 2). |
|
Thanks for the review. I tried to make the naming of new stuff more consistent and added a bit more comments. |
My assumption was based on the original firmware behaviour on flush to send the buffered midi to all devices and I don't see logic that changes that. It's differentiated by midiDeviceUSB but that's not respected by the flush functions. If I've misread the code to change that then no worries, I've got nothing that can be hosted and log midi messages to test with so that statement is purely based on reading the code
Yeah it's not a huge deal, it just needs to be declared with the other 2. It wouldn't have to be added to the menu structures or preferences files since it should just be used by a companion app or similar |
what happened is that all devices gets flushed at the same time even though one device's buffer was full. I'd like to untangle that temporal mix-up at some point as well. But there was still a dedicated buffer for each physical device so it was always possible to send messages to a specific device (even though with note/cc data they often contained exactly the same contents). |
|
Makes sense, thanks |
|
Added the third port dedicated for sysex data (it never sends channel/MPE data). |
I kept some refactors in the midi device menu even though I didn't add the new port to the menu right now, as there is no relevant settings. we could add it later by just adjusting `lowestDeviceNum`
|
|
||
| rle = false; // not yet implemented | ||
|
|
||
| uint8_t reply_hdr[5] = {0xf0, 0x7e, 0x02, 0x40, rle ? 0x02 : 0x01}; |
There was a problem hiding this comment.
If I'm reading this correctly, the message being sent is "Universal Non-realtime sample data packet".
Should this be changed to use 0x7d as the second byte, or is there a specific reason this message type was chosen?
There was a problem hiding this comment.
no you are right, it is supposed to be 0x7d
Some simplifications were made to the driver code by Rohan under the
assumption we were only going to queue up to 32 usb-midi messages
for a device per "tick" of the main routine.
These had to be reconsidered, like there is now again a callback from the usb driver
interrupt back to midi_engine to check for more data to send.
It doesn't seem to be possible to increase the amount of data sent in
each call to the driver more than 32 messages (or 128 bytes).
Instead, implement a ring buffer for midi data waiting to be sent over USB.
When we get an interrupt for usbSendComplete, we can check the ring
buffer again and restart the low-level send until the ring buffer is
empty.
Implement a sysex request for sending the contents of the OLED display
as a sysex reply message. This needs more work before being
generally useful as an external display (not to mention client code for multiple platforms)
, but serves as a test case for larger sysex messages. This also tangents #121 , an unified build
would eventually allow developers with a 7SEG display to test how their code
would look on a virtual OLED display.