Midibridge

[ Deprecated: Chrome 43 supports MIDI natively, see this post ]

1) Introduction
2) Quick start guide
3) Documentation
4) About midi out
5) Earlier versions
6) What about Flash?
7) Known issues
8) Forthcoming features

Introduction

The midibridge is a Javascript API for interacting with the midi devices on your computer.

It provides methods for detecting the midi devices and for connecting these devices with each other.

The midibridge itself is considered a midi device as well, so it can be connected to the detected devices.

The midibridge can generate and send midi events to midi output devices, and receive midi events from midi input devices.

The midibridge can also filter and alter midi events.

A sequencer for playing back midi files is implemented as well, recording will be added in a later version.

A midi output device is a physical output port on your computer, a virtual output port or a software synthesizer. It can also be a sequencer, a file or a function.

A midi input device is a physical or virtual input port, a sequencer, a file or a function.

A midi device can be both in- and output. The midibridge itself for instance is both in- and output because it can send and receive midi events.

The actual interaction with the midi devices on your computer is done by a Java applet. The midibridge automatically adds the applet to your webpage.

The midibridge has no visual parts, it is ‘headless’ code. You could say the midibridge enables you to write a ‘front-end’ on top of the applet.

Midi Devices -> Java Applet -> Javascript Midibridge API -> a GUI in Javascript, Flash, SVG, C# (Silverlight)

Because the midibridge is written in native Javascript, you can use it conflict-free with any Javascript framework.

Quick start guide

1) Download the zip file from Github.

2) In this zip file you’ll find an index.html and 3 folders: /java contains a Java archive (jar) file, /lib contains a Javascript file (minified and non-minified) and /examples contains the code examples of this documentation.

On your webserver, put the jar file in a folder called “java” and the minified javascript file in the folder where you usually store your javascript libraries. Personally, i put the Javascript libraries that i use in a project in a “lib” folder, and the project specific javascript files in a folder “js”.

3) Include the file midibridge-0.5.3.min.js in your webpage. If you use a Javascript framework (jQuery, YUI, Dojo, etc.), include it right after you’ve included the framework. See the index.html in the zip.

4) Start the midibridge. The page has to be fully loaded before you start the midibridge, so call the init function of the midibridge inside your onload handler:

window.addEventListener('load', function() {
    midiBridge.init(function(midiEvent) {
        console.log(midiEvent);
    });
}, false);

5) Done! If you have a midikeyboard connected to you computer, play some notes and you’ll hear a piano sound. Also you will see that the midi events are printed to your console.

Documentation

By adding the midibridge to your html page, a global variable midiBridge is created. Below follows a list of the methods that you can call on the midiBridge object. There is also a bunch of handy static members that you use in your code:

– init()   
– sendMidiEvent(status, channel, data1, data2)   
– getDevices()   
– refreshDevices()   
– connectAllInputs()   
– connectFirstInput()   
– connectFirstOutput()   
– connectAllInputsToFirstOutput()   
– addConnection(input,output,filter)   
– removeConnection(input,output)   
– disconnectAll()   
– getNoteName(midiNoteNumber,mode)   
– getNoteNumber(noteName,octave)   
– getStatus(statusCode)
– loadBase64String(base64String)   
– playBase64String(base64String)   
– startSequencer()   
– pauseSequencer()   
– stopSequencer()   
– closeSequencer()   
– getSequencerPosition()   
– setSequencerPosition(microseconds)   
– getNiceTime(microseconds)
– getObject(id)   
– MidiMessage(jsonString)   
– List of static members

init()

The init method of the midibridge adds an extra div to the body of your html page, and in this div the Java applet gets loaded. After the applet has loaded, it detects all currently connected midi in- and outputs. Then it automatically connects all midi inputs to the midibridge. Also, the first found midi output gets connected to all midi inputs and to the midibridge.

This way you can start playing your midi keyboard directly after the midibridge is initialized. When you play, the callback method that you have passed as an argument to the init function will be called. In the example above, the incoming midi events are only printed to the console, but i’m sure you can come up with something more funky.

You can also call the init method with a configuration object as argument, this object may contain one or all of the following keys:

  • ready : [function] callback function that gets called as soon as the midibridge is ready/initialized
  • error : [function] callback function that gets called in case of an error, for instance the user does not have a Java plugin or an outdated version or the user is using a not-supported browser
  • data : [function] callback that gets called when midi data has arrived
  • javaDir : [string] the folder where you store the midiapplet.jar on your webserver, defaults to “java”
  • connectFirstInput : [true,false] the first found midi input device gets connected automatically, defaults to false
  • connectAllInputs : [true,false] all found midi input devices get connected automatically, defaults to false
  • connectFirstOutput : [true,false] the first found midi output device gets connected automatically, defaults to false
  • connectAllInputsToFirstOutput : [true,false] all found midi input devices will be automatically connected to the first found midi output device, defaults to true
  • debug : [true,false] when set to true, some debug information is printed to the console, eg: the filtered MIDI messages, see next bullet
  • midiCommands : [array] an array with the types of MIDI messages that the midibridge is passing to the data handler, defaults to: [midiBridge.NOTE_OFF,
    midiBridge.NOTE_ON,
    midiBridge.CONTROL_CHANGE,
    midiBridge.PITCH_BEND,
    midiBridge.PROGRAM_CHANGE]
    this setting overrules the filter setting on MIDI connections, see addConnection().

In the example below all midi inputs get connected to the midibridge, but they will not be connected to the first midi output, i.e. you won’t hear a sound when you play your keyboard(s).

Also, all messages from the midibridge are printed to a div in the html page.

window.addEventListener('load', function() {

    var contentDiv = document.getElementById('content');
    contentDiv.innerHTML += 'midibridge says:<br/>';

    midiBridge.init({
        connectAllInputs: true,

        ready: function(msg){
            contentDiv.innerHTML += msg + '<br/>';
        },
        error: function(msg) {
            contentDiv.innerHTML += msg + '<br/>';
        },
        data: function(midiEvent) {
            contentDiv.innerHTML += midiEvent + '<br/>';
        }
    });


}, false);

You can check this example here.

sendMidiEvent(status, channel, data1, data2)

With this method you can send midi events to the applet. You can use this method for instance to make a vitual keyboard. Here is a code snippet to help you started:

window.addEventListener('load', function() {

    midiBridge.init(function(midiEvent) {
        console.log(midiEvent);
    });

    var contentDiv = document.getElementById("content");
    contentDiv.innerHTML += "<div id='playAnote'>play a note</div>";
    var playNote = document.getElementById("playAnote");
    playNote.style.textDecoration = "underline";

    playNote.addEventListener("click",function(){
        midiBridge.sendMidiEvent(midiBridge.NOTE_ON,1,80,100);
    }, false);
};

Now if you click on “play a note”, you should hear a note.

You can check this example here.

getDevices()

This method returns a JSON object that contains all midi devices that were detected on your computer when the midibridge was initialized.

window.addEventListener('load', function() {

    var contentDiv = document.getElementById('content');

    midiBridge.init({
        connectAllInputsToFirstOutput: false,

        ready: function(msg){
            var devices = midiBridge.getDevices();
            for(var i = 0, max = devices.length; i < max; i++) {

                var device  = devices[i];
                var id      = device.id;
                var type    = device.type;
                var name    = device.name;
                var descr   = device.descr;
                var available = device.available;
                contentDiv.innerHTML += id + ' : ' + type+ ' : ' + name+ ' : ' + descr+ ' : ' + available + '<br/>';
            }
        },
    });

}, false);

The parameter available shows whether the device is currently in use or not. For instance if your midi keyboard was connected to a softsynth at the time you started the midibridge, that midi keyboard will be listed but the parameter available will be set to false.

You can check this example here.

refreshDevices()

You can use this method if your midi configuration has changed after you have started the midibridge. For instance if you connect a new midi device to your computer.

If you call this method, all current connections between your midi devices between your midi inputs and the midibridge will be disconnected.

connectAllInputs()

By calling this method, all detected midi inputs will be connected to the midibridge. You can also achieve this if you call the init() method with a configuration object, and then set the key connectAllInputs to true.

connectFirstInput()

By calling this method, the first detected midi input will be connected to the midibridge. You can also achieve this if you call the init() method with a configuration object, and then set the key connectFirstInput to true.

This method does not connect a midi output, so you can use this configuration for instance if your application only has a visual representation of the midi events.

NOTE: Sometimes the first midi input is not the device that you actually want to connect. In this case use getDevices() to check what id has been assigned to the midi input that you want to connect to the midibridge, and establish the connection with addConnection(midiInputId,midiOutputId). This also applies to connectFirstOutput.

connectFirstOutput()

By calling this method, the first detected midi output will be connected to the midibridge. You can also achieve this if you call the init() method with a configuration object, and then set the key connectFirstOutput to true.

This method does not connect a midi input, so you can use this configuration for instance if your application has a virtual keyboard, or if you attach the regular keyboard to the midibridge.

window.addEventListener('load', function() {

    midiBridge.init({
        connectFirstOutput : true
        ready : function(msg) {
            connectKeyboard();
        },
        error : function(msg) {
            console.log(msg);
        }
    });

    var noteNumbers = {
        //white keys
        65 : 48,     //key a -> note c
        83 : 50,     //key s -> note d
        68 : 52,     //key d -> note e
        70 : 53,     //key f -> note f
        71 : 55,     //key g -> note g
        72 : 57,     //key h -> note a
        74 : 59,     //key j -> note b
        75 : 60,     //key k -> note c
        76 : 62,     //key l -> note d
        186 : 64,    //key ; -> note e
        222 : 65,    //key : -> note f
        //black keys
        87 : 49,     //key w -> note c#/d♭
        69 : 51,     //key e -> note d#/e♭
        84 : 54,     //key t -> note f#/g♭
        89 : 56,     //key y -> note g#/a♭
        85 : 58,     //key u -> note a#/b♭
        79 : 61,     //key o -> note c#/d♭
        80 : 63      //key p -> note d#/e♭
    }

    var keysPressed = {};

    var connectKeyboard = function(){

        document.addEventListener('keydown', function(e) {
            if(e.which === 32) {
                midiBridge.sendMidiEvent(midiBridge.CONTROL_CHANGE, 1, 64, 127);
            } else if(noteNumbers[e.which] &amp;&amp; !keysPressed[e.which]) {
                midiBridge.sendMidiEvent(midiBridge.NOTE_ON, 1, noteNumbers[e.which], 100);
                keysPressed[e.which] = true;
            }
        }, false);


        document.addEventListener('keyup', function(e) {
            if(e.which === 32) {
                midiBridge.sendMidiEvent(midiBridge.CONTROL_CHANGE, 1, 64, 0);
            } else if(noteNumbers[e.which]) {
                midiBridge.sendMidiEvent(midiBridge.NOTE_OFF, 1, noteNumbers[e.which], 0);
                keysPressed[e.which] = false;
            }
        }, false);
    };


}, false);

The spacebar is used for the sustainpedal. Pressing a sustainpedal is a control change event. The controller number of the sustainpedal is 64 and 127 means pedal down, 0 means pedal up.

You can check this example here.

connectAllInputsToFirstOutput()

By calling this method, all detected midi inputs will be connected to the midibridge, and all inputs will also be connected to the first detected midi output.

This is the default configuration of the midibridge, so you can also achieve this if you call the init() method with no arguments, or with a callback function as argument.

It is interesting to know that the applet duplicates all midi events that arrive from your midi inputs (e.g. your midi keyboard). One event travels on to the midibridge and thus is available in Javascript. The other event travels to a midi out device if a midi output is connected to that midi input.

addConnection(input,output,filter) You can set up a connection between any midi input and midi output device by passing the ids of the devices as arguments to this method. You can lookup the id of an device in the JSON object that is returned when you call getDevices() or refreshDevices().

The id of the midi input and the midi output can also be set to -1. If you for instance only want to capture midi events in your application without connecting to an output device, you can set the id of the midi output to -1. If you set both the midi input and the midi outport to -1, nothing will happen.

The filter argument is an optional argument that you can use to pass an array with midi message types (status codes) that you are not interested in. If a midi message of one of the specified types is generated by an external midi input, the message will not be passed on to the midibridge. You can specify the midi message types with a decimal number (224), a hexadecimal number (0xF0) or with a human readable midibridge constant (midiBridge.PITCH_BEND). In the example below pitch bend midi messages will be filtered.

The code below shows you how you could implement functionality that allows the users to set up midi connections:

window.addEventListener('load', function() {

    var contentDiv = document.getElementById('content');
    var currentMidiInputId = -1;
    var currentMidiOutputId = -1;

    //create a dropdown box for the midi inputs
    var midiInputs = document.createElement('select');
    midiInputs.setAttribute('id', 'midi-in');
    contentDiv.appendChild(midiInputs);
    midiInputs.addEventListener('change', function(e) {
        var device = midiInputs.options[midiInputs.selectedIndex];
        currentMidiInputId = device.id;
        var result = midiBridge.addConnection(currentMidiInputId, currentMidiOutputId, [midiBridge.PITCH_BEND]);
        parseResult(result);
    }, false);

    //create a dropdown box for the midi outputs
    var midiOutputs = document.createElement('select');
    midiOutputs.setAttribute('id', 'midi-out');
    contentDiv.appendChild(midiOutputs);
    midiOutputs.addEventListener('change', function(e) {
        var device = midiOutputs.options[midiOutputs.selectedIndex];
        currentMidiOutputId = device.id;
        var result = midiBridge.addConnection(currentMidiInputId, currentMidiOutputId, [midiBridge.PITCH_BEND]);
        parseResult(result);
    }, false);

    var devices;

    midiBridge.init({
        connectAllInputsToFirstOutput : false,

        ready : function(msg) {
            devices = midiBridge.getDevices();
            populateDropDownMenus()
        },

        error : function(msg) {
            contentDiv.innerHTML += msg + '<br/>';
        },

        data : function(midiEvent) {
            contentDiv.innerHTML += midiEvent + '<br/>';
        }

    });

    var populateDropDownMenus = function() {

        midiInputs.appendChild(createOption('-1', 'choose a midi input'));
        midiOutputs.appendChild(createOption('-1', 'choose a midi output'));

        for(var deviceId in devices) {
            var device = devices[deviceId];
            if(device.type === 'input' &amp;&amp; device.available === 'true') {
                midiInputs.appendChild(createOption(device.id, device.name))
            } else if(device.type === 'output' &amp;&amp; device.available === 'true') {
                midiOutputs.appendChild(createOption(device.id, device.name))
            }
        }
    }

    var createOption = function(id, label) {
        var option = document.createElement('option');
        option.setAttribute('id', id);
        option.innerHTML = label;
        return option;
    }

    var parseResult = function(data){
        contentDiv.innerHTML += data.msg + ' : ' + currentMidiInputId + ' : ' + currentMidiOutputId + '</br>';
    }


}, false);

You can check this example here.

removeConnection(input,output)

You can remove a connection between a midi input and a midi output by passing their respective ids as arguments to this method.

disconnectAll()

This method does exactly what you would expect: it disconnects all current connections between midi in- and output and between your midi inputs and the midibridge

getNoteName(midiNoteNumber,mode)

Returns the name of the note based on the midi notenumber. Midi notenumbers are part of the midi standard and range between 0 and 127. The central C (261.626 Hz in 440 pitch) has notenumber 60.

The parameter mode can be one of the following values:

  • midiBridge.NOTE_NAMES_SHARP : the black keys will be named sharps, so notenumber 61 will be called C#
  • midiBridge.NOTE_NAMES_FLAT : the black keys will be named flats, so notenumber 61 will be called D♭
  • midiBridge.NOTE_NAMES_ENHARMONIC_SHARP : all keys will be named sharps, so notenumber 60 will be called B#, notenumber 62 will be called C## (double sharp)
  • midiBridge.NOTE_NAMES_ENHARMONIC_FLAT : all keys will be named flats, notenumber 64 will be called F♭, notenumber 62 will be called E♭♭ (double flat)

getNoteNumber(midiName,octave)

Returns the midi notenumber based on the name of the note and the octave. Octave -1 is the lowest possible octave number, octave 9 the highest possible. A regular 88 key keyboard ranges between A-1 and C7.

getStatus(statusCode)

Returns a string representation of the status byte of the midi message. For instance midiBridge.getStatus(midiBridge.NOTE_ON) returns “NOTE ON”.

loadBase64String(base64String)

Loads a base64 encoded MIDI file in the sequencer and return an object containing data about the loaded MIDI file.

  • microseconds: duration of the MIDI file in microseconds
  • ticklength: duration of the MIDI file in ticks
  • ticks: number of ticks in the MIDI file

There are several ways of getting a MIDI file as base64 string into your application.

1) By using html5 drag and drop functionality with the File API, see this example.

2) By using the File API, see this example.

3) Store the MIDI file as a base64 string in a Javascript variable, see also this example. The Javascript file chopin_opus18.mid.js contains a global variable chopin_opus18 that contains the MIDI file as base64 string.

4) Since global variables are bad code practise, loading base64 MIDI files from a webserver is preferred over option 3. Encoding MIDI files on the server can be done with a single line of php code:

<?php

$tmpFile = "tmp.mid";

//store the uploaded MIDI file in a temporarily file file_put_contents(tmpFile, file_get_contents("php://input",r));

//read the temp file, base64 encode it and echo it back echo base64_encode(file_get_contents($tmpFile));

?>

playBase64String(base64String)

Same as loadBase64String(base64String) but the file starts playing immediately.

startSequencer()

If a MIDI file is loaded the sequencer starts playing the file at the current position.

pauseSequencer()

Pauses the sequencer. Note: pause does not toggle, so you have to call startSequencer() to unpause the sequencer.

stopSequencer()

Stops the sequencer and rewinds sets the position of the file back to the start.

closeSequencer()

Stops the sequencers and then closes it. You have to call loadBase64String(base64String) or playBase64String(base64String) to open a sequencer again.

getSequencerPosition()

Gets the position of the MIDI file in the sequencer in microseconds.

setSequencerPosition(microseconds)

Sets the position of the MIDI file in the sequencer in microseconds.

getNiceTime(microseconds)

Converts microseconds to the time format m:ss:SSS.

Typically used to display the sequencer position of the MIDI file.

getObject(id)

Returns a reference to the object in the html page whose id is specified. It is used for getting a reference to the applet, but you can also use it for getting a reference to any other type of object. For instance for getting the swf object if your application is built with Flash, see What about Flash?

MidiMessage(jsonString)

An internal class of the midibrigde that is used for storage and easy handling of the midi events that arrive from the applet. The applet sends midi events as JSON strings to the midibridge. The midibridge uses the native JSON.parse() method to parse this string into a JSON object.

The MidiMessage class has 2 useful methods that you might need in your code toString() and toJSONString(). The first method is handy for printing the midi incoming events to a log, and the latter can be used if you want to send the midi event to Flash or another technology. See the offical JSON website for more information. Flash programmers might be interested in the JSON library of Mike Chambers.

Static members Besides methods, there are also a bunch of very handy static members that you can use:

  • midiBridge.version : version of the midibridge as string
  • midiBridge.ready : set to true if the midiBridge has been initialized successfully, otherwise set to false
  • midiBridge.NOTE_NAMES_SHARP : “sharp” see getNoteNumber()
  • midiBridge.NOTE_NAMES_FLAT : “flat” see getNoteNumber()
  • midiBridge.NOTE_NAMES_ENHARMONIC_SHARP : “enh-sharp” see getNoteNumber()
  • midiBridge.NOTE_NAMES_ENHARMONIC_FLAT : “enh-flat” see getNoteNumber()
  • midiBridge.NOTE_OFF : 0x80 (128)
  • midiBridge.NOTE_ON : 0x90 (144)
  • midiBridge.POLY_PRESSURE : 0xA0 (160)
  • midiBridge.CONTROL_CHANGE : 0xB0 (176)
  • midiBridge.PROGRAM_CHANGE : 0xC0 (192)
  • midiBridge.CHANNEL_PRESSURE : 0xD0 (208)
  • midiBridge.PITCH_BEND : 0xE0 (224)
  • midiBridge.SYSTEM_EXCLUSIVE : 0xF0 (240)

About midi out

If you’re on Windows or Linux, the latency of the Java Sound Synthesizer makes it almost impossible to play. On Windows you can also choose the Microsoft GS Wavetable Synth and with some soundcards you may get a decent latency (i was told the Realtek AC97 perfoms pretty well).

On a Mac you can just select a default midi synthesizer (Java Sound Synthesizer) and start playing with no noticeable latency.

Latency is caused by both the drivers of your soundcard and the way your synthesizer works. Most modern softsynths hardly cause any latency, but even with the latest M-Audio pro cards you’ll experience latency when using the Java Sound Synthesizer or the Microsoft GS Wavetable Synth.

So we need to be able to connect to some real softsynths like Pianoteq or Lounge Lizard and for this we need a virtual midi driver.

If you’re on a Mac, you’re lucky because such a thing is already installed on your machine. It is called IAC Driver and you’ll find it if you open the Audio MIDI Setup in your Applications folder.

If you are on Windows you can download LoopBe1 from nerds.de and Linux users can check VirMidi

Below i’ll give a brief explanation for every driver.

– LoopBe   
– IAC   
– VirMidi

LoopBe1

Download it from nerds.de and run the installer. After the installation has finished LoopBe is up and running and will automatically start with Windows (if you don’t want this, run msconfig and remove the LoopBe startup service).

Now LoopBe Internal MIDI will be listed as both a midi input as well as a midi output when you call getDevices(). You can setup a connection betweein your favorite keyboard as input device and LoopBe Internal MIDI as output with addConnection().

Now open your favorite softsynth and go to the midi settings and set your synth’s midi input to LoopBe Internal MIDI. Here is a screendump of what this looks like in Pianteq:

Pianoteq LoopBe Abumarkub midibridge

You should now be able to play your softsynth while midi data is passing thru the midibridge, and dependent on your soundcard’s driver, with very low latency.

Please notice that LoopBe1 is only free for non-commercial use. For commercial use you need to acquire a license after a 30-day evolution period. But for only € 11,90 inc VAT it’s really a bargain. If you are willing to spend an extra 5 euro on top, i would recommend to buy LoopBe1 bigger brother LoopBe30, which gives you up to 30 virtual midi ports! Check here.

IAC

Open your Finder, go to menu Go -> Applications and scroll down till you’ve found a folder named Utilities. Open the folder Utilities and double click on Audio MIDI Setup. If you only see a window with Audio Devices, go to Window -> Show MIDI Window.

In the window that subsequently opens, you should see an icon named IAC Driver. IAC stands for Inter-Application Communication, and that is exactly what it does.

If the icon is greyed out double click it and check the box “Device is online” in the popup that appears. Now you should have a window like:

IAC-Driver-Abumarkub-midibridge

Don’t worry if looks a little different on your machine. You should see at least 1 port in the “Ports” part of the screen. If not, simply click the plus sign to add a port. I recommend to add a least 2 ports to the IAC Driver.

Close this popup and the Audio MIDI Setup. Now “IAC Driver IAC Bus 1” (or something alike) will be listed as midi input when you call getDevices().

Set up a connection between your favorite keyboard as input device and “IAC Driver IAC Bus 1” as output with addConnection(). Open your favorite softsynth and go to the midi settings and set your synth’s midi input to “IAC Driver IAC Bus 1”. Here is a screendump of what this looks like in Lounge Lizard:

Lounge Lizard IAC input Abumarkub midibridge

Now you can play your softsynth while midi data is passing thru the midibridge.

VirMidi

If you are using Ubuntu or Kubuntu, there is a thread about VirMidi on the Ubuntu forum

Because snd-virmidi is a kernel module, you can simply load this module by typing sudo modprobe snd-virmidi on the command line.

Now if you call getDevices(), you should see at least 4 additional devices listed.

Set up a connection between your keyboard as input device and one of the virtual midi ports as output with addConnection(). Connect this output to the input of your favorite softsynth, for instance in Pianoteq this would look like:

VirMidi Kubuntu Pianoteq midibridge abumarkub

Now you can play your softsynth while midi data is passing thru the midibridge.

Pianoteq is available for both 32 and 64 bits Linux, so if you want to try it yourself you can download a demo version over here.

Earlier versions

I started this project in the summer of 2008. Since then i have released 5 versions:

  • proof of concept : With dynamical sound generation, a chord finder, a color organ, midi learn functionality, a virtual keyboard and an adjustable pitch bend controller that acts upon the generated sound
  • version 2 : With all features of the proof of concept, but with an extra swf that sits between the applet and the application swf. This extra swf connects on one site via ExternalInternface to the applet, and on the other side via LocalConnection to the application swf.
  • version 3 : The in-between swf removed again, dynamical sound generation replaced by midi out. A very simple GUI: virtual keyboard, chord finder and pich bend controller removed, simple animation added in.
  • version 4 : FluidSynth softsynth added that allows you to use Soundfont files at choice. Also the midibridge is able to generate midi events itself. Virtual keyboard added again
  • version 5 : Same as version 4 but you can also export the code to a standalone AIR version.

In my blogposts you can still find information about the earlier versions. This might be confusing and therefor i have started this page where you can find only up to date information about the latest, and thus featured release. Some of this information can also be found in various posts, but if it appears here as well it is still valid for the current release.

With this version, the development of all earlier versions of the midibridge will be frozen. The reason for this is that with this new version i have redefined what the midibridge exactly is.

In former version of the midibridge i have added too much GUI functionality. As explained in the introduction, the new midibridge provides only a compact set of methods that allows you to interact transparently with the midi devices on your computer, but leaves the GUI totally up to you.

So therefor the new version has no control panel, virtual keyboard, midi learn functionality and so on. I have provided code examples for the basic features of the midibridge and i will add some more examples for more advanced features like sound generation soon. Also i might develop some configurable UI plugins for the midibridge (alike jQuery UI) somewhere in the future.

Another reason for stripping down the midibridge to its core is that former versions were too much tied to Flash and Actionscript. In modern browsers Flash is no longer the only reasonable choice for creating compelling animations. This applies to dynamically generating sound as well.

What’s more, the latency of Mozilla’s Audio Data API allows you to set the minimal audio buffer as low as 512 samples, which results in a latency of only 512/44100 ≈ 11.6 ms(!). In Flash the minimal buffer size is 2048 (recommended) which results in an almost un-playable latency of 2048/44100 ≈ 46ms.

To summarize the benefits of the new approach:

  • the midibridge now only takes 5K of code
  • it makes it much easier to add the midibridge to your code
  • it gives you more control over what your website/application looks like
  • it does not impose a specific client side language on you

The only downside is that the new version is not compatible with the earlier versions. However, you can still use it; the code is fully functional and remains available at GitHub and Google Code. You are encouraged to switch to the new version though.

Code at GitHub (version 5):

http://github.com/abudaan/javamidi

http://github.com/abudaan/flashmidi

Code at Google Code (version 5):

http://code.google.com/p/miditoflash/downloads/

As i mentioned above, the earlier version had both a web and an AIR version. The Air version uses NativeProcess to start a Java program on the commandline, and communicates with this program via its standard input and standard output.

I am not yet sure what to do with the AIR version. You can use both Actionscript and Javascript in an AIR app, but i am actually looking for another way of creating a browser-less application. Any suggestions are welcome.

What about Flash?

The midibridge is fully accessible from Actionscript 3.0 if you use the ExternalInterface.

You probably want to load Flash before you initialize the midibridge so you can show some loading animation. In Actionscript you have to test when the page has fully loaded and then call the init() function of the midibridge.

First a Timer is set up to check if the midibridge object is null. As soon as the midibridge object exists, Flash creates callback handlers for Javascript: these are methods that can be called directly from Javascript.

Flash also calls the global Javascript method callFromFlash(). You can name it anything you like btw. The first parameter determines what action of the midibridge is requested:

package {

    import flash.display.Sprite;
    import flash.events.TimerEvent;
    import flash.external.ExternalInterface;
    import flash.utils.Timer;


    public class Main extends Sprite {
        private var _readyTimer:Timer = new Timer(1, 1);

        public function Main() {
            if(ExternalInterface.available) {
                _readyTimer.addEventListener(TimerEvent.TIMER, check);
                _readyTimer.start();
            } else {
                trace('ExternalInterface not avaible in this browser');
            }
        }

        public function midibridgeReady(msg:String):void {
            var jsonString:String = ExternalInterface.call('callFromFlash', 'getDevices');
            trace(jsonString);
        }

        public function midibridgeError(msg:String):void {
            trace(msg);
        }

        public function midibridgeData(msg:String):void {
            trace(msg);
        }

        private function check(e:TimerEvent = null):void {
            try {
                if(ExternalInterface.call('midiBridge') !== null) {
                    ExternalInterface.addCallback('midibridgeReady', midibridgeReady);
                    ExternalInterface.addCallback('midibridgeError', midibridgeError);
                    ExternalInterface.addCallback('midibridgeData', midibridgeData);
                    ExternalInterface.call('callFromFlash', 'start');
                    _readyTimer.stop();
                } else {
                    _readyTimer = new Timer(100, 1);
                    _readyTimer.addEventListener(TimerEvent.TIMER, check);
                    _readyTimer.start();
                }
            } catch(err1:SecurityError) {
                trace(err1.message);
            } catch(err2:Error) {
                trace(err2.message);
            }
        }
    }


}

Now back in Javascript, the call to callFromFlash() gets processed. The first parameter was “start” so the midibridge gets initialized. As you can see, the callback handlers of the midibridge get directly connected to the Javascript callback handlers of Flash. This way data and messages are routed from the midibridge to Flash:

/**
 * You can only call global functions from Flash, therefor we declare a single global function that is used for all
 * communication with the Flashplayer.
 *
 */

 function callFromFlash() {

    /**
     * getObject is utility function of midiBridge, it is used to get the Applet object,
     * but it can also be used to get the swf object
     *
     * flashapp is the id of the swf object in the html page.
     */
    var flashObject = midiBridge.getObject('flashapp');

    /**
     * convert the arguments to a array, the first argument is the msgId.
     * the msgId is used to determine what the Flashplayer wants from the midibridge
     */
    var args = Array.prototype.slice.call(arguments);
    var msgId = args[0];


    switch(msgId) {

        case 'start':
            midiBridge.init({
                connectAllInputsToFirstOutput : true,

                ready : function(msg) {
                    flashObject.midibridgeReady(msg);
                    return msg;
                },

                error : function(msg) {
                    flashObject.midibridgeError(msg);
                },

                data : function(midiEvent) {
                    flashObject.midibridgeData(midiEvent.toString());
                }

            });
            break;

        case 'getDevices':
            return midiBridge.getDevices();
            break;
    }


};

You can check this example here.

Known issues

Currently the midibridge does not work with the Icedtea Java plugin on Linux.

Forthcoming features

In a future release i will add more functionality to the sequencer. The following methods will be implemented.

getSequencerTickPosition(); setSequencerTickPosition(ticks); recordMidi(file); setTempo(tempo);

For more feature requests or other suggestions, please drop me a line!

81 replies on “Midibridge”

This is great work. Thanks!

One question…Midibridge works well on each of my computers here with all browsers but I’m having an issue with it on one configuration: IE8 running on XP. My Java plugin version is 1.6.0_23 and the Midibridge test applet shows my connected midi in devices properly but when I run bi-directional midibridge with fluidsynth I don’t get any choices in the midi in pulldown menu. The event log says:

default midi in: null
default midi out: null
Fluidsynth (internal) loaded
midi in set to -1
midi out set to -1

I know this is something simple I am missing. Thanks in advance!

Ok, probably there is nothing wrong. I’ll give you an explanation of the lines in the event log:

  • default midi in: null -> There is currently no default midi device saved to a flash cookie (Shared Object). If you click “save settings” after you have selected a midi in device, this device will be automatically selected when you open the page next time. Of course, only if that device still is connected to your computer.
  • default midi out:null -> See above. The difference with default midi in is that the default midi out is a software port, such as “Microsoft GS Wavetable Synth”
  • Fluidsynth (internal) loaded -> The internal (built in Flash) software synth is loaded and active. If you press with your mouse on a key of the virtual keyboard, you should hear a piano sound.
  • midi in set to -1 -> Means that currently no midi in device is connected. Connect a midi device (for instance a keyboard) to your computer and click “rescan devices”. Now your midi device should be listed in the “midi in” dropdown menu. Select it and press “save settings”. The next time you open the page this device will be automatically selected and there is a value greater than -1 is the line “midi in set to …”
  • midi out set to -1 -> See previous point.

But, ‘midi in set to -1’ [in bi-directional midibridge with fluidsynth event log] is an incorrect readout because I do have several USB MIDI devices connected (Axiom 25 and Trigger Finger). The pulldown menu for MIDI In devices is grayed out and it gives me no options for some reason. Clicking ‘rescan devices’ does not help. That is just in IE8. In FireFox and Chrome however “bi-directional midibridge with fluidsynth” works perfectly as soon as I start it. I see my MIDI In devices listed and I can choose them and they work well.

Another indicator is that when I run your Test Applet it definitely shows my MIDI In devices as connected and as viable MIDI In devices. I just don’t know why “bi-directional midibridge with fluidsynth” in IE8 is not seeing those devices. What could be causing this just with IE8? Thanks.

Sorry, i misunderstood your problem. I will look into it again.

-> Do you have Service Pack 3 installed?
-> What are your settings for Browser Mode and Document Mode?
-> Do your midi in devices show up in the old version?

– Yes I have Service Pack 3 installed.
– I have tried with Compatibility View on and off. I don’t know how to check settings for Document Mode though.
– My MIDI devices do not show up in the old version either.

Thanks again for checking this out for me.

Hi,
What a great solution – very exciting! I made a custom hardware Midi-controller with arduino and I was hoping to use Midibridge to “teach” my controller’s CCs via a fancy flash GUI. I have the CS5 SimpleSampleAppWeb working/compiling fine but I don’t know what to do next. I would basically like to have a dozen buttons send midi notes from nearby editable textboxes when you click them. I’m eager to learn but I’m new to actionscript3. Maybe I could hire you for an hour to get me started? If you could drop a text box and a button to send it’s contents into a .fla file, that would be a great starting point.
Thanks!!!

Best
Alex

Thanks for your kind words!

In the repository you can find a folder net/abumarkub/midi/learn/. This folder contains all necessary classes for midi learn functionality.

There is also a sample app called AppWeb that has implemented these midi learn classes (in the folder net/abumarkub/app_midibridge/ ).

You can use this code as a starting point for your code. Let me know if you run into any issues.

Outstanding, so excited to integrate this into something cool. The classes are very clean, and documented well, kudos! Perhaps you could start a list on this page to showcase how it’s being used elsewhere.

Thanks again! I am glad that you like the code because i have put a lot of time and effort in it to make it kind of self-explanatory, but i wasn’t too sure about it.

There are 2 implementations that i know of: ColorKeys and TheWebaphone

If anybody knows of the existence of other implementations, please let me know!

This is really fantastic! Just what I’ve been looking for for the past couple of weeks!
I want to implement a web version of my Assistant Performer software, and this solves the first problem. Thanks! May run into a couple of other problems. We’ll see…
If you’re interested in music notation, you could take a look at
http://james-ingram-act-two.de/compositions/study2/study2b/Study2b3.html
and
http://james-ingram-act-two.de/compositions/study2/study2b/Study2b2.html
These scores are of the same piece. They are written in SVG using different chord symbols, but the chords contain identical MIDI info…

Thank you for your massively interesting links!!

I saw that you’ve had music lessons from David Rowland, i was a student of his as well, very coincidental wouldn’t you say?

Please let me know if you need any help implementing the midibridge.

Nice work — I’m really impressed. We have a desktop app that helps people learn to play the piano, and we’re looking to move the MIDI input to a new system. We can’t use a browser or Adobe Air, but we do use a SWF wrapper (Zinc) that lets us launch external executables and also make calls to the system using shell scripts.

Is there a way to modify what you created for Air and use shell scripts to connect to the midibridge instead? We’ve done tests and can launch the bridge using Java, but we’re not sure how to connect to the bridge and get input from the MIDI device — to basically addListenerEvents like you’re doing with the Air version.

Thanks for any tips. And thanks again for great tool.

Thanks for your kind words!

I haven’t worked with Zinc, but in the documentation i found the following methods:

mdm.System.exec(argument:String):Void
mdm.System.execStdOut(exePath:String):String
mdm.Process.create():Number

But i am afraid that these methods don’t provide the possibility to pass arguments to the process after it has started.

The documentation tells explicitely about the method mdm.Process.setParams() that it should be called before mdm.Process.create().

However you have to start the midibridge process first, and then when it runs you need to be able to interact with it by sending parameters to the stdIn of the process.

Also i don’t see a possibility to listen for messages coming from the stdOut after the process has started: only when you start the process it returns the stdOut, as the name of the method execStdOut() already suggests.

I think in your case a midi socket server like flosc would be a better solution.

You can easily set up a socket connection with Zinc, see the mdm.Network.UDP.Socket api:

mdm.Network.UDP.Socket.broadcast():Void
mdm.Network.UDP.Socket.send():Void
mdm.Network.UDP.Socket.startServer():Void
mdm.Network.UDP.Socket.startServer():Void
mdm.Network.UDP.Socket.onData:Function

Hope this helps you a little further. Please feel free to ask me any further questions.

Hi,

I’m really amazed by all the work you have done to accomplish this project; it’s unique, I love it!

I have one question. When you’re gonna add the “playMidiFile(url)” function?

I’m making a little experiment in flash and I want to play midi files (I have months trying it, but I’ve not the programming knowledge to make this work). Something like this page would be perfect:
http://www.playintune.net/

I just need a simple midi player for flash.
Thanks in advance, and once again, GREAT WORK!

hello:

im trying to design an application where what i play on my midi controller is passed to a midi server and then clients can view/listen to the midi in the browser

what i want to know is can midibridge accept a midi stream from a midi server?

also what midi servers would you recommend

sorry if my terminology is wonky

Hi,

Great Library. I am getting an error in the firebug console when I try to run our flash example.

h.connectAllInputsToFirstOutput is not a function

Not sure what to do at the point I have copied text from above.

Thanks

Hi I was able to get it working. But now I have another question. How could I get flash to trace the midi note number of the key that was pressed?

I am assuming I need to use getNoteNumber(midiName,octave) but am not sure what to pass as the arguments.

Thanks!

Yes indeed, getNoteNumber(noteName,octave) returns the midi notenumber. So if you for instance pass C (notename) and 4 (octave) for arguments, the method returns 60. See this overview

Thanks for the reply.

I understand how that works now, but am still a little confused about how to implement it in flash, if for instance the user pressed C4 on their keyboard how could I trace 60 in flash?

Other only way I can see to do it is to substring this midiEvent.toString() when it traced in flash.

Thanks!

Hi Admin,

Could you tell me how to trace the midi note number in Flash, when a user presses a key on their keyboard? I can hire you for a quick consultation if I need to.

Thanks!

Hi James. I am also having this same issue. Were you ever able to get it resolved?

Thanks!

Hey thanks for the reply. I was able to achieve the results I was looking for by doing all of my logic in an external AS file hooked into the library. I was making the mistake of trying to perform the actions in the timeline code.

I’ve been using your library as part of my senior thesis project in university (I’m a digital design student), and I couldn’t be happier with how this API has worked out. Thank you so much for this. Very cool work!

Hi,

Love this and could be exactly what I need.

Bit of a noob question here, so apologies if this has been covered in the documentation.

I would like to be able to use a MIDI keyboard to trigger some samples on a webpage. For example if the user presses A4 on the keyboard a pre-recorded sample will play or possibly a sine tone at 440Hz. I have it working in so far as the MIDI message pops up on the bottom of my web page.

I have been trying things such as:

if (midiEvent.indexOf(“C3”) != -1)
{
pianoC3.play();
}

and

var n = midiBridge.MidiMessage.noteName;
if (n.indexOf(“C3”) != -1)
{
pianoC3.play();
}

I have tried various other versions of something like this but have been unable to get anything working. I’m new to programming and JavaScript so would appreciate any help with this.

Cheers,
Ned

Thanks for your reply.

I haven’t been able to get that working.

The code I have been playing with is:
var n = midiEvent.noteName;
//alert(n);
switch (n) {
case “A4”: n = 440; break;
case “B4”: n = 493.883; break;

if (!n) {return;}
osc = audioLib.Oscillator(dev.sampleRate, n);
osc.waveShape = document.getElementById(“waveform”).value;
}

I can’t seem to get access to midiEvent or midiEvent.noteName in order to manipulate or use the value.

I have tried using this method and also the .indexOf method to search the String of the midiEvent.
Am I doing this right? Is there another way to acces the data for the note name? There may be something fundamental I am missing.

Cheers.

Hi there,

This looks really interesting! but I have run into a problem trying to get this to load.

Will the applet run locally? or does it have to run from a web server? I am running a local setup in osx 10.7.2 I get an error saying
failed to load status undefined

mylocalpathtofiles/net.abumarkub.midi.applet.MidiApplet

Any ideas why this might be?

thanks in advance

L

Hey,

It strange all of the examples actually seem to work but the init method callback doesnt seem to be triggered. So for example if I execute

midiBridge.sendMidiEvent(midiBridge.NOTE_ON,1,72,40);

within

midiBridge.init(function(midiEvent) {});

then it doesnt fire but if i call it as the function for a click event then it seems to work.

Hi 😉

I’ve loaded, dezipped and put all files (keyboard.html + 2 JS + the .jar file) on my server but it doesn’t seem to work despite your online example works properly on my OSX. Nothing happens when using keyboard… Chrome displays an alert (GET http://mywebserver/MIDI/net.abumarkub.midi.applet.MidiApplet 404 (Not Found))
I’ve even tried with JS in absolute links (http://abumarkub.net/midibridge/examples/js/regularkeyboard.js…..) >#fail Any idea ?

I have updated the files at Github; if you download the zip again it should work as expected!

Let me know if you run into troubles.

Hi,

I first downloaded 5.0.1 a couple of days ago using the link in the Quick Start at the top of this page:
http://code.google.com/p/midibridge-js/downloads/detail?name=midibridge-0.5.zip&can=2&q=
But even the non-deprecated version there is out of date.

I’ve now reloaded and installed the latest version from
https://github.com/abudaan/midibridge-js

And everything is working fine, including my MIDI keyboard. :-)))
Just install the contents of the zip parallel to your own html file.

A small problem: The regularkeyboard.js example is still not working, either here or on my site.
Debugging it will be a good exercise! 🙂

All the best,
James

OS: Windows Vista 64bit Ultimate

Hi James,

All examples have been updated, both on this site and in the coderepositories (Github and Google Code).

Also, the midibridge has been updated to version 0.5.2.

Thanks for reporting the issue with connectAllInputsToFirstOutput on Github; this bug has been fixed as well.

Thx for answer but nothing happens 🙁

OK, last ressources loaded (0.5.1) In the ‘MIDI’ dir on my webserver I have the ‘keyboard.html’ file – which calls ‘midibridge-0.5.1.min.js’ and ‘regularkeybord.js’ – and the ‘midiapplet.jar’, all these files at the same level in the same directory.
I’ve tried to modify object’s params to see what happens, changing sizes to 200 pixels. In Chrome a msg of error appears instead of the Java applet. When I click on this msg to get more details it open the Java console which displays a lot of lines beginning and ending with something around ‘java.lang.ClassNotFoundException: net.abumarkub.midi.applet.MidiApplet’…

Noob question: do I need a MIDI-server (or any special serv config) or any HTTP webserver is supposed to work?

Thanks.
regularkeyboard.js is now working, but one has to activate the screen first (by giving it a click).

There seem to be undocumented functions in MidiBridge.js. For example, midiBridge.loadMidiFile() and midiBridge.playMidiFile(). Presumably these are “reserved” and not implemented yet.

Are there any other things that are not yet implemented?
For example I am currently trying unsuccessfully to get
midiBridge.sendMidiEvent(midiBridge.PROGRAM_CHANGE, midiEvent.channel, 13, 0);
to work.

Is there a better place to ask things like this? For example on Github?

best, James

Yes, that is normal behavior: the browser window needs to have focus before it can respond to keyboard events.

There are undocumented functions indeed since MIDI playback has been implemented:

loadBase64String(base64MIDIFile);
startSequencer();
stopSequencer();
pauseSequencer();
setSequencerPosition(microseconds);

This blog is a good place to ask for features, but currently i am also answering your email 😉

Thanks you two, now everything’s working perfectly 😉
If interested I’ll post here my project once fully developped in a couple of monthes, an urban experimentation with geolocated people tracked to produce a sound creation event.
Thanks again for all 😉

Your project sounds very interesting!

Please let me know if i can be of any further help.

OK. Project just started last week. I’m currently working with 2 musicians and I’m in charge of the ICT parts, reason why I’m just discovering the midi format, unusual in my activities. If I met some big probs in the next few days I may need your opinion. Of course, even if not, you’ll be credited in the project for your API 😉

Thank you for your great effort. I’m building a site for midi file exchange and would like to add ability to preview files online. Playback is fine but in the data callback I get events only for one channel. I’m getting the same result when running playmidifile example,- only events for the first channel are displayed on the screen. Am I missing something or multi-channel files are not supported in this version?

Hi, this plug-in looks great, however I have one simple question, and I think I know the answer, but it’s worth a shot : is there anyway to have access to the midi devices without going through Java ? Just plain & simple javascript, no java applet ?

I highly doubt it, but since you’ve been working on this, I hope you’ll be able to give me a definitive answer.

I saw the Jazz plug-in, but I was really hoping for a javascript only solution.

I guess I’ll wait for the w3c guys to put Web MIDI API on prod. In the meantime I think I’m gonna use your API with the java applet.

Hi!

This is a fantastic solution! I was looking for a way to get track names out of Native Instruments Traktor Pro (DJ Software). Midibridge would perfectly do the job. Unfortunately I can’t see any MIDI output on the console. Nevertheless I can hear the sound when I connect in- and output and play any note on a virtual piano. Any idea why this happens? I’m using Firefox 14.01. I added an alert() statement in the “printMIDIMessage” function, but it does not appear. So the callback seems not to be called from the plugin.

I would greatly apreciate your help!

Hello,

First, thank you for this library !

Now, is the sequence parameter of createMidiMessage working ?

I tried this:
midiMessage = midiAccess.createMIDIMessage(midiBridge.NOTE_ON, 0, note, velocity, seq);
output.sendMIDIMessage(midiMessage);

but even if seq is non-zero, the msg is sent immediately… Maybe I misunderstood the role of the seq parameter ? Doesn’t it delay the message actual triggering ?

Thanks,

stephane

This is a great resource – very straightforward information about a very useful library. Thank you!

Can you provide any more information about the System_Exclusive static member? I’ve managed to connect to a LoopBe port and send NoteOn information with SendMIDIEvent, but I need to be able to send SysEx strings to control external equipment. Is this supported by way of the System_Exclusive member, or is that read-only?

Thanks again,
Marc

Hi There,

Did you ever get round to adding a “RecordMidi” feature? I would love to be able to record the midi events to a .mid file which I can save to my system.

Also is is possible to change the tempo of a midi file loaded via the sequencer to playback slower/faster? as that would be ideal for what I have in mind!

Perhaps you can help me? I have a synthesizer plugged into my PC and I am trying your examples with sendMidiEvent… no matter what channel I choose I am getting a piano sound… possible not even through my synths midi input.

How do I choose which device to output to? I’d like to be able to select a voice on my synth and have it play in that program when I hit the button depending on what I have selected on the hardware.

Hey admin! First of all thank for sharing this! You are awesome!

I was wondering if there is any JS function to send the same midi event to all the keys/ buttons / knobs on the midi device. Im using sendMidiEvent to each button on the midi device and its massively lagging. (This function happens several times per second) Thanks !

I am afraid I don’t understand what you mean. Do you mean you want to send control change events to your hardware?

Thanks! You are right, the .jar needs to be signed. You can sign the applet with a self-signed certificate, which is free. I can send you the Java code if you want. But maybe it is better to use the Jazz plugin? Also Chrome and Chromium have already implemented the WebMIDI API.

Thanks so much for the speedy reply! I have the Java code from github, but I can sign the jar file directly (I think) and don’t need to recompile.

I have a website that compiles Lilypond code into PDFs and midi files, and it’s important that first-time newbie users can hear midi right away with the least hassle on their part. Installing jazz-plugin is an extra step that I would like to avoid (at least for the new users).

I’ve been playing with “midijs”, it’s ok, it will play midi files without any extra installation, but it keeps ‘hiccuping’ or ‘stuttering’ when it loads new chunks every 10 or 15 seconds. midibridge seemed to work perfectly for what i want, except for the warnings and hassle to newbies about it not being signed. I’ll try self-signing – thank you! 🙂

Well, it won’t run with a self-signed cert “java blocked an entrusted application” or something like that.

Geez, MIDI came out in 1983 – but it’s the hardest thing to get up and running in browsers!

Leave a Reply to clayton cottingham Cancel reply

Your email address will not be published. Required fields are marked *