tiny javascript library for midi input in the any browser/os with webmidi
baton.js is a javascript library to make it easy to handle midi input and output using the newish WebMIDI standard.
WebMIDI is supported in Chrome on OSX, but you have to enable it by visiting chrome://flags/#enable-web-midi, clicking enable
, and relaunching Chrome.
On other browsers/OSes, you can use the WebMIDI API Polyfill, which in turn requires the Jazz-Soft Jazz Plugin.
In my experience, I need to relaunch Chrome every time I plug in a new MIDI source or (or open a DAW, or whatever) before it’s recognized.
You can check out the following example files to see how Baton works. Remember to enable the web-midi flag in Chrome.
They all require a MIDI source. You can either plug in a controller, or use MidiKeys
Use baton with a single input source callback shows basic midi input, with all controllers handled by the same function.
use Baton with multiple input source callbacks uses different functions to handle input from two different midi sources.
Automatic MIDI Mapping with Baton shows how to easily map a variable to any midi control by clicking a button then twiddling that control.
use Baton with processing.js draws velocity-sized circle at note-position, at a color set from midi control signals
use Baton to make sound with webPd plays sine waves
use Baton to control an external midi instrument sends midi notes
use Baton with threejs uses midi input to affect a 3d scene
use the WebMIDIAPI shim uses the WebMIDIAPI shim to add midi functionality to browsers that don’t support WebMID3
route midi over WebRTC uses webrtc to send midi data peer-to-peer over the internet. Use your controller to control your friend’s synth over the internet.
Here’s a list of midi event types supported by baton.
noteoff
note
polypress
control
program
aftertouch
pitchbend
checkSupport()
checkSupport()
returns true if the browser supports WebMIDI or false if the browser does not.
connect(function callback)
connect(callback)
connects Baton to MIDI, and calls an optional callback function once it’s connected.
Baton.connect( Baton.print() );
check()
check()
returns true
if Baton has an active midi connection, and false
if it doesn’t.
inputs()
If baton is connected, inputs()
returns an array of the available midi inputs.
Baton.inputs(); # ["Bus 1", "MidiKeys"]
send(int output, object data)
If baton is connected, send(output, data)
sends a data packet out of the given output.
var data = {
type: "note",
channel: 1,
note: 100,
value: 127
};
for (var o = 0; o < Baton.outputs().length; o++) {
console.log("data to send", data);
Baton.send(o, data);
}
listen(int input)
If baton is connected, listen(input)
makes it start listening to the given input.
// listen to input 0
Baton.listen(0);
// listen to all inputs
for (var i = 0; i < Baton.inputs().length; i++) {
Baton.listen(i);
}
callback
callback
stores an optional callback fucntion which is executed when midi input is received.
Baton.callback = function(midi) { console.log(midi); };
autoMap(string name, function fn)
autoMap(name, fn)
waits until the next MIDI input message, then maps that midi control to the function fn
. The mapping is named name
.
var loudness;
$('#map-button').on('click', function() {
Baton.autoMap('loudness', function(m) {
loudness = m.value;
});
});
autoMapObj(string name, object obj)
autoMapObj(name, obj)
waits until the next MIDI input message, then maps that midi control to the value
of the object obj
. The mapping is named name
.
var loudness = {value: 0};
$('#map-button').on('click', function() {
Baton.autoMapObj('loudness', loudness);
});
mappings
mappings
is the array of mappings used by Baton. If you’re careful, you can edit it manually, or you can simply use the autoMap()
or autoMapObj()
functions described above.
Baton.mappings = [
{
'name': 'loudness',
'midi': { channel: 1, note: 1, type: "control" },
'fn': function(m) { loudness = m.value; }
}
]
// instantiate object
var baton = new Baton();
// instantiate mapped variable
var paramVal = {value: null};
// map function
// perhaps use a button:
// $('button#map-param').on('click', mapParam);
function mapParam() {
// call autoMap
baton.autoMapObj('param', paramVal);
});
// create a function to be called once the midi connection is made
listen = function() {
// listen to all inputs
for (var i = 0; i < baton.inputs().length; i++) {
baton.listen(i);
}
};
// connect to midi, set the function to be called when connected
baton.connect(listen);
// instantiate object
baton = new Baton();
// create a function to be called once the midi connection is made
listenMulti = function() {
// listen to all inputs
for (var i = 0; i < baton.inputs().length; i++) {
baton.listen(i);
}
};
// connect to midi, set the function to be called when connected
baton.connect(listenMulti);
// this callback is executed when a midi event is received.
baton.callback = function(m) { console.log("multi", m); };
// instantiate objects
midiZero = new Baton();
midiOne = new Baton();
// create functions to be called once the midi connections are made
listenZero = function() { midiZero.listen(0); };
listenOne = function() { midiOne.listen(1); };
// connect to midi, set the functions to be called when connected
midiZero.connect(listenZero);
midiOne.connect(listenOne);
// these callbacks are executed when a midi event is received.
midiZero.callback = function(m) { console.log("midiZero", m); };
midiOne.callback = function(m) { console.log("midiOne", m); };
// instantiate object
baton = new Baton();
// create a function to be called once the midi connection is made
sender = function() {
// every 5 seconds
setInterval(function() {
// turn the note on
console.log("note on");
for (var o = 0; o < baton.outputs().length; o++) {
var data = {
type: "note",
channel: 1,
note: 100,
value: 127
};
baton.send(o, data);
}
// then one second later
setTimeout(function() {
// turn the note off
console.log("note off");
for (var o = 0; o < baton.outputs().length; o++) {
var data = {
type: "noteoff",
channel: 1,
note: 100,
value: 0
};
baton.send(o, data);
}
}, 1000);
}, 2000);
};
// connect to midi, set the function to be called when connected
baton.connect(sender);