atsushieno / managed-midi

[Past project] Cross-platform MIDI processing library for mono and .NET (ALSA, CoreMIDI, Android, WinMM and UWP).
MIT License
195 stars 26 forks source link

Unable to send (but can receive) SysEx messages on Windows #59

Closed jskeet closed 5 years ago

jskeet commented 5 years ago

I'm writing an explorer for my Roland TD-17 drum kit, and have previously been using the Sanford MIDI library. I want to move to managed-midi for portability, but I'm stuck on one aspect.

Sample code, running on Windows, so the output device type is Commons.Music.Midi.WinMM.WinMMMidiOutput:

// This exact byte sequence works with Sanford MIDI
byte[] identityRequest = { 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 };
var input = await MidiAccessManager.Default.OpenInputAsync(inputPortId);
input.MessageReceived += (sender, args) => Console.WriteLine(BitConverter.ToString(args.Data, args.Start, args.Length));
var output = await MidiAccessManager.Default.OpenOutputAsync(outputPortId);
output.Send(identityRequest, 0, identityRequest.Length, 0L);
await Task.Delay(10000);

I know that the "message received" handler works, because changing anything on the device causes a SysEx message to be sent and displayed. I know that the output port itself is correct because I can send other messages.

So what am I doing wrong here in terms of sending the SysEx message? Is there something I need to do to enable SysEx?

atsushieno commented 5 years ago

No there shouldn't be nothing special to do for sysex. Let me try once I move back to homeland where I have my windows environment. It should work but it's been a while since I tried Windows sysex output last time.

jskeet commented 5 years ago

Righto - and thanks for your response. I did have a look at the source code, and I can see there's a fairly different path for SysEx vs non-SysEx messages.

In the meantime, is there a reasonably simple way of debugging this myself, if I clone the repo? The readme suggests it may not be too hard to hack around with it... hopefully if I add a dependency directly on the right projects, I'll be able to debug... I may be able to suggest a solution myself.

jskeet commented 5 years ago

Okay, I've found the bug, I believe.

MidiEvent.Convert takes the byte array and creates a new MidiEvent with a type of 0xf0, extraData of the original byte array, but extraDataOffset of 1 and extraDataLength of 5. WinMMMidiOutput.Send then copies just the 5 bytes into the MidiHdr.Data, instead of all 6 from the original message. If I change this line in MidiEvent.Convert:

yield return new MidiEvent (0xF0, 0, 0, bytes, index + 1, size - 1);

to

yield return new MidiEvent (0xF0, 0, 0, bytes, index, size);

... then everything seems to work. Now that may well not be the real fix, because something else may rely on that "extra data" being genuinely "extra data" rather than "all data" - but that's probably something you can work out better than I can. If we don't change the "extra data" offset/length, then the WinMMMidiOutput.Send needs to be changed to allocate an extra byte and set the first byte to 0xf0, followed by the extra data.

Let me know if I'm not making much sense - it's Friday evening, and it's been a long week, so I may not be communicating as clearly as I should :)

The good news is that having made that change locally, it looks like it's all working like a charm - I get the same data out of my drum kit that I did with Sanford Midi. That's just on Windows, of course... next I'll try my Raspberry Pi, and eventually Xamarin...

atsushieno commented 5 years ago

Hi, sorry for getting back late, I'm back in front of Windows today. And thanks for the fix suggestion! It indeed was problematic chopping. It is fixed as of 311b9e3.

On that weird-looking regression: According to my github activities, it is most likely that commit f92f7c44 which introduced this was introduced when I was dealing with fluidsynth API (I also have NFluidsynth.MidiAccess) which did not require status byte when it takes sysex bytes.

It somehow does not break sysex messaging in ALSA so it was left unnoticed.

It's great that other parts just worked fine and your app is getting x-plat, which is exactly the primary goal of this project :-)

atsushieno commented 5 years ago

And I'm stuck at Azure DevOps problem that it is incapable of handling sign in from project page which navigates to https://aex.dev.azure.com/me?mkt=en-US and individual project page https://atsushieno.visualstudio.com/managed-midi loses my signin state. sigh. Maybe I dump Azure DevOps and migrate to GitHub Actions but package updates may take a while.