Click the buttons below to go to the demos. In order for them to work, your browser needs to implement the MIDI API. Currently it works in Chrome/Chromium and nightly releases of Firefox. The code can be found in this repository. The rest of this page details the simple example, and points out some further features used by a more complex example.
This example has the following directory structure:
simple-example
├── midi.js
├── midi.json
├── index.html.template
├── site_gen.py
└── index.html
midi.js
is a file containing a javascript class called
midiHandler
and other helper functions.
midi.json
specifies the midi-aware inputs of the page, with
the following example content:
[
{
"name": "Input 1",
"shortName": "input1",
"symbol": "1"
},
{
"name": "Input 2",
"shortName": "input2",
"symbol": "2"
},
{
"name": "Input 3",
"shortName": "input3",
"symbol": "3"
}
]
This defines three inputs. For each, “name” is a human readable name, “shortName” is a machine-readable name, and “symbol” is the symbol associated with the input which will be displayed on SLIDER’s 8x8 display.
index.html.template
is a template for the main html
index file of the page, and has the following in its body:
{MIDI_BOILERPLATE}
<input type="range" min="0" max="127" name="input1" id="input1" value="0">
<input type="range" min="0" max="127" name="input2" id="input2" value="0">
<input type="radio" name="input3" id="input3" value="0">
{MIDI_BOILERPLATE}
is a location where a midi settings
dialog will be added, this is why the file is called
index.html.template
– running site_gen.py
will
insert this boilerplate and output the complete index file to
index.html
. The MIDI settings dialog can be seen on this page, where the demo runs.
index.html.template
also contains the following
javascript, which sets up MIDI handling:
// create the midiHandler object
let mHandler = new midiHandler(document.getElementById("midi"), "mHandler")
// populate it with event handlers for each input defined in midi.json
.midi_event_handlers["input1"] = function(value) {
mHandlerdocument.getElementById("input1").value = value;
}
.midi_event_handlers["input2"] = function(value) {
mHandlerdocument.getElementById("input2").value = value;
}
.midi_event_handlers["input3"] = function(value) {
mHandlerif (value === 127) { // button down
var inp = document.getElementById("input3");
.checked = !inp.checked;
inp
}
}
// start the event loop, which will run forever
.eventLoop(); mHandler
The first line simply creates the midiHandler
object,
passing in the element of the MIDI settings dialog (part of
{MIDI_BOILERPLATE}
), and its own name, which it requires
because it inserts HTML input buttons into the page which call functions
of midiHandler
. Next,
midiHandler.midi_event_handlers
is populated with an event
handler function for each input which was defined in
midi.json
.
These event handler functions will be run as quickly as the webpage can handle, each time updating the page as desired by the website designer. In this simple example, the first two inputs, connected by the user to SLIDER’s slider and rotary encoder, will simply move a HTML input slider. The third, connected to SLIDER’s button, will toggle a checkbox.
The last line of the example javascript will start the event loop.
midiHandler
has a number of further features which are
used in the demos in . Here is the event handler for SLIDER’s switch
used in histograms demo in , simplified for explanatory purposes:
.midi_event_handlers["switch"] = async function(value) {
mHandlerif (value != 127) return;
if (Object.values(mHandler.control_change_dict).includes("r_center")) {
// if the reaction norm is currently being controlled,
// start controlling the efficiency norm
.assignMIDI("e_center", 0, 0);
mHandler.assignMIDI("e_extent", 0, 1);
mHandlerelse {
} .assignMIDI("r_center", 0, 0);
mHandler.assignMIDI("r_extent", 0, 1);
mHandler
} }
This code checks which histogram is currently being controlled, and swaps over to controlling the other one. This is combined with another feature called assignment callbacks. Assignment callbacks are set each time an input is assigned to. Here is one example:
.assignment_callbacks["r_center"] = function(value) {
mHandler// put SLIDER into Go To mode, and move it to the new position
// `midi_hist_shapes` contains the current shapes of the histograms
.goTo(0, midi_hist_shapes["reaction_norm"].center);
mHandler// `plot_indices` maps the names to indices in the html
for (const [val, idx] of Object.entries(plot_indices)) {
if (idx === plot_indices["r_center"]) {
// set the border of the new plot to red
document.getElementsByClassName("plot")[idx].style.border
= "5px solid red";
else {
} // set the border of all other plots to white
document.getElementsByClassName("plot")[idx].style.border
= "5px solid white";
}
} }
This assignment callback is set up such that when the SLIDER switches
to controlling the reaction norm histogram, it will physically move its
motorised slider to the new position, and the page will update so that
the newly controlled plot is highlighted in red.
goTo(channel, position)
is a convenience function to
abstract away the interface specified here,
there is also setPassive(channel)
,
rumble(channel, value)
,
setNotch(channel, position)
,
setBump(channel, position)
,
setEncoder(channel, value)
, and
setSymbol(channel, value)
, which correspond to the other
available MIDI messages detailed at the earlier link.