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

MidiInput.MessageReceived is dropping messages on Linux / not receiving all of them #71

Open oxysoft opened 2 years ago

oxysoft commented 2 years ago

Hello, I am writing an application using this library. The application receives MIDI input and tracks held notes using the incoming messages. Unfortunately if I press a large number of notes all at once, or release many at once, then the tracking is invalid

https://user-images.githubusercontent.com/3945277/165197135-808e097f-9a19-4ace-87ab-0c81136fc18d.mp4

Here, I am pressing all the white notes (non-ghosted) and releasing them all at once. As you can see, only some of them light up, and some of them stay stuck when I release them all.

This is the relevant code:

        public PianoDrawable()
        {
            IMidiAccess midiaccess = MidiAccessManager.Default;
            foreach (IMidiPortDetails details in midiaccess.Inputs)
            {
                IMidiInput input = midiaccess.OpenInputAsync(details.Id).Result;
                _midiInputs.Add(input);
                input.MessageReceived += OnMidiInputMessage;
            }
        }

        private void OnMidiInputMessage(object? sender, MidiReceivedEventArgs e)
        {
            var events = MidiEvent.Convert(e.Data, e.Start, e.Length);
            Console.WriteLine($"{e.Start} - {e.Length}@{events.Count()}");
            foreach (MidiEvent ev in events)
            {
                if (ev.EventType == MidiEvent.NoteOn)
                {
                    byte a440 = ev.Msb;
                    byte vel  = ev.Lsb;

                    _notes[a440] = vel > 0;
                }
                else if (ev.EventType == MidiEvent.NoteOff)
                {
                    byte a440 = ev.Msb;
                    _notes[a440] = false;
                }
            }
        }

Anything off with this piece of code? Or is there a peculiarity about MIDI that I don't know? Note I've never had this kind of issue in FL Studio to my knowledge, using JACK and wineasio, so I don't think it's a problem or limitation with my MIDI/USB adapter.

Cheers

atsushieno commented 2 years ago

Hi. I'm rather curious about the outputs from Console.WriteLine(); if it drops some notes at that level then there may be problem with MidiEvent.Convert(). If the correct MIDI events are not passed at e.Data then there may be either MIDI packet dropouts at AlsaMidiAccess (or whatever I created, I haven't written C# code for years anymore) or it was already corrupt before our library. Try dumping e.Data content on the console as well?

oxysoft commented 2 years ago

(A) Pressing one by one:

0 - 3@1 [144, 48, 41]
0 - 3@1 [144, 48, 0]
0 - 3@1 [144, 50, 34]
0 - 3@1 [144, 50, 0]
0 - 3@1 [144, 52, 41]
0 - 3@1 [144, 52, 0]
0 - 3@1 [144, 53, 40]
0 - 3@1 [144, 53, 0]
0 - 3@1 [144, 55, 40]
0 - 3@1 [144, 55, 0]
0 - 3@1 [144, 48, 62]

(B) Pressing all five at once:

0 - 3@1 [144, 55, 49]
0 - 2@1 [52, 50]
0 - 2@1 [50, 54]
0 - 2@1 [48, 55]
0 - 2@1 [53, 50]

(C) Releasing all five at once:

0 - 3@1 [144, 48, 0]
0 - 2@1 [52, 0]
0 - 3@1 [144, 50, 0]
0 - 4@2 [254, 144, 53, 0]
0 - 3@1 [144, 55, 0]

Looks like the data is getting jumbled up somewhere. In (B) these look like the right messages, but missing 144 in front. In (C), we see an extra 254 slips in front.

atsushieno commented 2 years ago

The input byte sequences most likely contain input messages with running statuses.