Skip to content
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

Implement MIDI input support #2804

Merged
merged 26 commits into from
May 3, 2020
Merged

Implement MIDI input support #2804

merged 26 commits into from
May 3, 2020

Conversation

holly-hacker
Copy link
Contributor

@holly-hacker holly-hacker commented Aug 28, 2019

Closes #2723.

Still WIP, uses managed-midi for cross-platform MIDI input.

Remaining issues:

Tested on:

  • Windows
  • MacOS
  • Linux
  • Android
  • iOS

osu.Framework/Input/Handlers/MidiInputHandler.cs Outdated Show resolved Hide resolved
@holly-hacker
Copy link
Contributor Author

Point raised in private discussion: Should MidiKey be part of InputKey? Right now it's a separate enum which makes conversion to and from integers easy, but it probably isn't usable as an input in projects like lazer.

@peppy
Copy link
Member

peppy commented Aug 29, 2019

It should be available as normal input, yes.

@holly-hacker
Copy link
Contributor Author

That CodeFactor failure complains about KeyBindingContainer.Handle(UIEvent) being too complex, but it contains only a switch statement so I don't know if it's logical to split that up into different methods.

@holly-hacker
Copy link
Contributor Author

PR should be ready for review and testing on Android, iOS and MacOS. I've tried testing on Android but my device doesn't seem to support MIDI input.

@smoogipoo
Copy link
Contributor

Unfortunately this library seems to crash on macOS (atsushieno/managed-midi#50), and the developer seems to be "unable to continue development" (atsushieno/managed-midi#42).

May be best to wait for ManagedBass to be fixed...

Code-wide it looks great.

@atsushieno
Copy link

the developer seems to be "unable to continue development"

True, but this applies to primary development (on Linux) and not for MacOS-specific issues. I will try fixing this on weekend.

@smoogipoo
Copy link
Contributor

Have made a few fixes for other hard crashes in managed-midi, but at this point I'm not completely sold on the stability of the framework. Gonna delay merging this one for a few weeks while the managedbass guy responds (they're generally pretty responsive).

@holly-hacker
Copy link
Contributor Author

@smoogipoo ManagedBass got updated to v3 and I got a response in ManagedBass/ManagedBass#54, and it seems Bass does not support MIDI input on Android. Managed-midi has received a few bugfixes since your last message so could you give it another look when you have a spare moment?

@smoogipoo
Copy link
Contributor

smoogipoo commented Apr 27, 2020

I'm able to trigger the sequence:

0x000000F0
0x0000000D

By refreshing devices on macOS. Based on how MIDI input is implemented on macOS it's probably doing something really silly, but this should probably be guarded against otherwise it crashes the app. Causes:

Unhandled exception. [runtime] 2020-04-27 04:45:45 [error]: An unhandled error has occurred.
[runtime] 2020-04-27 04:45:45 [error]: System.Collections.Generic.KeyNotFoundException: The given key '__Source0' was not present in the dictionary.
[runtime] 2020-04-27 04:45:45 [error]: at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
[runtime] 2020-04-27 04:45:45 [error]: at osu.Framework.Input.Handlers.Midi.MidiInputHandler.readEvent(Byte[] data, String senderId, Int32& i, Byte& eventType, Byte& key, Byte& velocity) in /Users/smoogipoo/Repos/osu-framework/osu.Framework/Input/Handlers/Midi/MidiInputHandler.cs:line 120
[runtime] 2020-04-27 04:45:45 [error]: at osu.Framework.Input.Handlers.Midi.MidiInputHandler.onMidiMessageReceived(Object sender, MidiReceivedEventArgs e) in /Users/smoogipoo/Repos/osu-framework/osu.Framework/Input/Handlers/Midi/MidiInputHandler.cs:line 108
[runtime] 2020-04-27 04:45:45 [error]: at Commons.Music.Midi.CoreMidiApi.CoreMidiInput.OnMessageReceived(Object sender, MidiPacketsEventArgs e)
[runtime] 2020-04-27 04:45:45 [error]: at CoreMidi.MidiPort.CallMessageReceived(IntPtr pktlist, IntPtr readProcRefCon, IntPtr srcConnRefCon)

@@ -539,6 +560,10 @@ protected virtual void HandleMouseButtonStateChange(ButtonStateChangeEvent<Mouse

private bool handleScroll(InputState state, Vector2 lastScroll, bool isPrecise) => PropagateBlockableEvent(PositionalInputQueue, new ScrollEvent(state, state.Mouse.Scroll - lastScroll, isPrecise));

private bool handleMidiKeyDown(InputState state, MidiKey key, byte velocity) => PropagateBlockableEvent(NonPositionalInputQueue, new MidiDownEvent(state, key, velocity));

private bool handleMidiKeyUp(InputState state, MidiKey key) => PropagateBlockableEvent(NonPositionalInputQueue, new MidiUpEvent(state, key));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be updated to use the new ButtonEventManager stuff. See how it's implemented for joysticks / mouse buttons / keys for reference.

@@ -2192,6 +2198,10 @@ public bool TriggerEvent(UIEvent e)
/// <param name="e">The <see cref="JoystickReleaseEvent"/> containing information about the input event.</param>
protected virtual void OnJoystickRelease(JoystickReleaseEvent e) => Handle(e);

protected virtual bool OnMidiDown(MidiDownEvent e) => Handle(e);

protected virtual bool OnMidiUp(MidiUpEvent e) => Handle(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return void (and false in TriggerEvent()).

osu.Framework/osu.Framework.csproj Outdated Show resolved Hide resolved
@smoogipoo
Copy link
Contributor

Also I assume this isn't supposed to support channels at this point? It's coded in such a way that it seems like it should support them, but it isn't for some reason.

@atsushieno
Copy link

In case you are trying to use managed-midi's own Core MIDI support, note that its quality is super low and not quite ready for general consumption yet. I cannot provide solid implementation for Xamarin.Mac alternatives up to CoreFoundation level. On Mac managed-midi via Xamarin.Mac is the only viable approach (managed-midi has particular build for the profile). Or you might want to try RtMidiSharp which might work better.

@smoogipoo
Copy link
Contributor

Ah... We're avoiding using Xamarin on desktop platforms in favour of netcore, so that isn't really an option for us at this point. Maybe NET5 will change that.

I'm not super concerned about macOS support for the time being though, just as long as it doesn't crash the app. If the reason for channels not working is a result of being on macOS then I'm fine with that.

@atsushieno
Copy link

Sorry but I'm not really tracking this project issue and have no idea what kind of issue the "channels" stuff is. If there is something reproducible at my side let me know and I might be able to help.

@holly-hacker
Copy link
Contributor Author

Updated according to feedback, there's a few things I want to mention:

  • MidiKeyInput does not extend ButtonInput<TKey>, but implements IInput directly. ButtonInput<TKey>'s purpose seems to be to handle multiple input changes at once, but MidiKeyInput is only directly used in MidiInputHandler so it doesn't seem useful.
  • I changed how velocity gets stored. MidiState now stores an internal Dictionary<MidiKey, byte>, which gets updated in MidiStateChangeEvent's ctor and read in MidiKeyEventManager.HandleButtonDown. It's not the prettiest solution, but the only other way I could think of involved refactoring ButtonEventManager which seems a bit silly if it's only for MIDI input. I can try to look for something better if this isn't good enough.
  • MIDI input is currently accepted even when the game is not focused, though most other programs share this behavior.

@smoogipoo
Copy link
Contributor

The way you've implemented it is fine :) Made one minor change to make the velocities public - may come in useful if someone's handling input manually via InputManager.CurrentState.

Thanks!

@smoogipoo smoogipoo merged commit 0f73c6d into ppy:master May 3, 2020
@holly-hacker holly-hacker deleted the midi-input branch May 3, 2020 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

MIDI input support
6 participants