djipco / webmidi

Tame the Web MIDI API. Send and receive MIDI messages with ease. Control instruments with user-friendly functions (playNote, sendPitchBend, etc.). React to MIDI input with simple event listeners (noteon, pitchbend, controlchange, etc.).
Apache License 2.0
1.54k stars 115 forks source link

Not receiving input events #40

Closed aik099 closed 6 years ago

aik099 commented 6 years ago

Hi, I was able to call .playNote method on the output, but attempting to read note being pressed via noteon event doesn't produce any results for me.

I'm using this code:

$(document).ready(function () {
   WebMidi.enable(function (err) {
       var $input = WebMidi.getInputByName('MIDI Device Name');

       $input.addListener('noteon', 'all', function($e) {
           console.log('The "noteon" event: ', $e);
       });
   });
});

I do have same MIDI device shown in WebMidi.inputs and WebMidi.outputs. Any ideas?

I'm connecting MIDI device via Bluetooth, but I have no idea how to test, that connection actually worked. I think, that if device is shown in inputs, then it's connected properly.

I've used https://owow.io/faq/connecting-midi-bluetooth-osx-devices/ instruction for connecting.

djipco commented 6 years ago

Your code looks fine. The transport layer (Bluetooth in this case) should be transparent to WebMidi.js. It is the OS that's taking care of that. The fact that you are able to see the device likely means it is properly recognized. By the way, it is normal to see a device as both an input and an output (most devices are actually both).

However, in all honesty, I have not tried WebMidi.js with a Bluetooth device as I do not own one. Maybe somebody else can chime in with their own experience of using a BT-connected device with WebMidi.js?

aik099 commented 6 years ago

It must be Bluetooth related, because when I use iOS app (e.g. Synthesia) to connect to MIDI keyboard it (keyboard) shows "MIDI" icon on built-in display and is recognized as MIDI input device by the app.

When however I connect MIDI keyboard via Bluetooth to computer (macOS) and run Synthesia, then MIDI keyboard is shown as available device, but no matter what note I press it doesn't end up in Synthesia nor the built-in MIDI keyboard display shows "MIDI" icon.

The https://taktech.org/takm/WebMIDIBrowser/startpage105.html page is super basic MIDIAccess demo that shows all events that are happening.

When I open it via "Web MIDI Browser" iOS app (see https://itunes.apple.com/us/app/web-midi-browser/id953846217?mt=8), then it shows all notes being played as well connection events. When I open it on Google Chrome it shows only connection events.

aik099 commented 6 years ago

I'm doing step-by-step debugging of this library (where Bluetooth issue happens) in comparison with above mentioned website to determine the difference, that causes the issue to happen. I'm also in the process of getting correct wires for testing MIDI-USB connection of the MIDI keyboard to verify that my changes won't break anything in that part of the library by accident.

I'll keep you posted with my findings and if I'll find a way how to fix them, then I'll be sending a PR.

aik099 commented 6 years ago

The issue is with Promised-based attempt to all .open method on all inputs and outputs.

https://github.com/djipco/webmidi/blob/master/src/webmidi.js#L485-L493

The "Web MIDI Browser" iOS app (see https://itunes.apple.com/us/app/web-midi-browser/id953846217?mt=8) I'm using has 2 inputs/outputs:

If the .open method is called on Session 1 input/output, then it never finishes because at a given moment no network-based connection was established to MIDI accessory. Since we're waiting for all .open method promises to be finished it ends up with no inputs/outputs initialized at the end and WebMidi.enable provided callback never finishes.

The strangest thing is that if I only do 2nd .open method call (for Bluetooth MIDI device both input/output), then both MIDI devices appear as opened and connected in inputs/outputs arrays, because they're auto-opened upon setting onmidimessage callback.

All the promise stuff is for connected events to be fired properly.

If I temporarily switch from Promise-based to timeout-based approach (used when Promise class is missing), then all works fine.

@djipco , what should be proper way of fixing it?

djipco commented 6 years ago

@djipco , what should be proper way of fixing it?

Hmm... I'm not sure. Maybe I should fall back to the timer method if the promise does not resolve within a reasonable amount of time? I will have to look at it in more details (which will probably have to wait until next week). I'm open to suggestions.

aik099 commented 6 years ago

The whole .open method calling (as I can see from comments in the code) was done to allow listening for connected event. As far as I can tell this doesn't work (tried wired keyboard connection).

input.addListener('connected', 'all', function ($e) {
    alert('connected');
});

The above code gives me an exception:

webmidi.js:1423 Uncaught (in promise) TypeError: The specified event type is not supported.
    at Input.addListener (webmidi.js:1423)
    at WebMidi.<anonymous> ((index):143)
    at WebMidi.onPortsOpen (webmidi.js:541)

The code collects these events, but I can't really add a listener for them.

djipco commented 6 years ago

The connected events are being fired by the WebMidi object, not by the Input object. This means you would need to use:

WebMidi.addListener('connected', function(e) {
  console.log('connected');
});
aik099 commented 6 years ago

I see.

I agree to a fix, where fallback code (https://github.com/djipco/webmidi/blob/master/src/webmidi.js#L503) would executed after 200ms (current delay) if promises weren't executed by that time. Time-wise it all stays the same, but now instead of calling setTimeout when browser doesn't support promises we attempt to open ports when promised either are not supported or failed to run within certain (200ms) amount of time.

djipco commented 6 years ago

@aik099 I pushed an update to /src/webmidi.js. Can you try it and let me know if it works properly in your Bluetooth setup? If it does, I'll include the fix in release 2.1.

djipco commented 6 years ago

@aik099 I'm all set for release 2.1. If you had a second to check for the Bluetooth, that would be great. Thanks!

aik099 commented 6 years ago

Tested latest src/webmidi.js version from GitHub using Web MIDI Browser over Bluetooth. It works as expected. Thank you.

djipco commented 6 years ago

Fixed in release 2.1.