0

I am developing a Unity game that relies on MIDI input from a piano keyboard, using the DryWetMIDI library. I have to detect when a chord has been played and process the chord as a whole.

Currently, my approach is to wait for 0.1 seconds after the first note press, and put all notes pressed during this period into a list. Then I process this list. However, when I attempt this with Coroutine, the code inside WaitThenNotify() never executes.

Here is the code.

    private List<NoteOnEvent> inputs = new List<NoteOnEvent>();
    private bool waiting = false;

    // Start is called before the first frame update
    void Start() {
        if ((InputDevice.GetAll() is null)) {
            return;
        }
        inputDevice = InputDevice.GetById(0);
        inputDevice.EventReceived += OnEventReceived;
        inputDevice.StartEventsListening();
    }

    private void OnEventReceived(object sender, MidiEventReceivedEventArgs e) {
        if (e.Event.EventType.Equals(MidiEventType.NoteOn)) {
            inputs.Add((NoteOnEvent)e.Event);
        }
        if (!waiting) {
            // catch all inputs within 0.1 seconds, for chords.
            waiting = true;
            StartCoroutine(WaitThenNotify());
        }
    }
    
    IEnumerator WaitThenNotify() {
        yield return new WaitForSeconds(0.1f);
        print("here");
        
        PianoPressObserver.UpdateSubjects(inputs);
        waiting = false;
        inputs.Clear();
    }

Can anyone inform me as to why this happens? Or better yet, is there a better way of catching chord inputs?

jintsuyi
  • 15
  • 4

1 Answers1

1

I'm the author of DryWetMIDI. I suppose your problem is related to multi-threading. OnEventReceived will be called from internal WinMM thread. But as far as I know in Unity you should start coroutines on main Unity thread. So you need to call StartCoroutine from Unity main thread.

Please read this section of the library docs: https://melanchall.github.io/drywetmidi/articles/playback/Common-problems.html#setactive-can-only-be-called-from-the-main-thread-in-unity.

Related question: https://answers.unity.com/questions/1670686/startcoroutine-can-only-be-called-from-the-main-th.html

Maxim
  • 1,995
  • 1
  • 19
  • 24
  • Hi Maxim, I see what the problem is now. However, I have done alot of research into invoking the main UI thread from the WinMM thread but still cannot figure out the exact way to do it. I know I should ask this question in a separate stackoverflow thread, but can you offer me some ideas on how to accomplish this? – jintsuyi Jul 08 '20 at 04:33
  • Did you read info by the provided links? Also you can read the GitHub issue from this comment: https://github.com/melanchall/drywetmidi/issues/85#issuecomment-641520521 There was the same problem. – Maxim Jul 09 '20 at 12:27