1

I'm building an experimental Web MIDI app which graphically displays the notes you're playing on an external MIDI keyboard to the browser. I'm having a strange error where the following callback only works if I log it to the console:

// ============================================================================
// Web MIDI API
// ============================================================================
var MIDI = null;

$(document ).ready(function(){

  function onMIDISuccess( midiAccess )
  {
    MIDI = midiAccess;

    // Start listening to the MIDI ports!
    var selected_input = MIDI.inputs()[0];
    console.log( selected_input );
    selected_input.onmidimessage = function( event )
    {
      if( event.data[0] == 144 )
      {
        // Zero velocity means note OFF
        if( event.data[2] == 0 )
          $("pianokey[note="+event.data[1]+"]" ).removeClass("active");

        // Non-zero velocity means note ON
        else
          $("pianokey[note="+event.data[1]+"]" ).addClass("active");
      }
    };
  }

  function onMIDIFailure( error )
  {
    console.error( "MIDI Failed! Error: ", error );
  }

  navigator.requestMIDIAccess().then( onMIDISuccess, onMIDIFailure );

});

What I'm finding is that my code works but only when the line console.log( selected_input ); is included.

Easiest to see what I mean by running my fiddle: http://jsfiddle.net/8sSMe/1/

If you have an external midi keyboard plugged in, you should see the keys light up on screen mimicking what you're playing on your keyboard. Remember, you might have to restart chrome to pickup your keyboard, and you might need to choose a different input from the array for selected_input. You also might need to turn Web MIDI on in your chrome by going to chrome://flags/#enable-web-midi (also I'm only interested in getting this to work on Chrome). Once you see that it is working, try it with console.log( selected_input ); commented out and it will strangely stop working.

Any ideas?

Anson Kao
  • 5,256
  • 4
  • 28
  • 37

2 Answers2

1

I think I found the problem...

Scope / Garbage collection

My reference var selected_input = MIDI.outputs()[0]; was occurring in a scope that goes away. So when it goes away, along with it goes the callback response mechanism. Keeping the reference to it in global scope solves the problem. Somehow, console.log() was perhaps changing the scope.

So have a solution but my theory is just a working solution, I would gladly welcome anyone with more expertise who could corroborate my theory. I don't know how to test if a variable is being garbage collected...?

Alas, the challenges of the Javascript language...

Anson Kao
  • 5,256
  • 4
  • 28
  • 37
  • 1
    Yep. You got it! I have experienced a similar situation working with the audio render callback -- where I had to manually hold onto the containing object. Making the variable global must surely be the simplest solution -- I can't see any reason to look further. – P i May 12 '15 at 15:27
0

Something wierd happened to me too with this code : when I do console.log(MIDI) right after navigator... it says that MIDI is null. But when I call MIDI in console input right after the page is loaded I can retrieve a non null MIDI object.

Asynchronous call ?

Goufalite
  • 2,253
  • 3
  • 17
  • 29