Easy io for the Web MIDI API
Development has just started and until v1.0.0 has been released, noon-io should be considered unstable.
A more detailed documentation of noon-io can be found here.
npm i noon-io
Send a A4 NOTE ON
message on all available MIDI outputs
import * as MIDI from 'noon-io';
// Gain access to the Web MIDI API
const midiAccess = await navigator.requestMIDIAccess();
// Send a Note On message over all available outputs on channel 2
for (const output of midiAccess.outputs.values()) {
const noteOnMessage = {
status: MIDI.Status.NOTE_ON,
channel: 2,
data: {
value: 69, // A4
velocity: 127
}
};
output.send(MIDI.write(noteOnMessage));
}
For one dedicated channel, noon-io offers a more concise way of writing messages using factory functions.
// send a CC of 80 for control 71
output.send(MIDI.channel(2).controlChange(71, 80));
// send a A4 note on message with a velocity of 120
output.send(MIDI.channel(2).noteOn(69, 120));
// send the subsequent note off message for our A4 note
output.send(MIDI.channel(2).noteOff(69));
For more information about noon-io factories, you can checkout this documentation
import * as MIDI from 'noon-io';
// Gain access to the Web MIDI API
const midiAccess = await navigator.requestMIDIAccess();
// Bind MIDI reader to all midi inputs
for (const input of midiAccess.inputs.values()) {
input.onmidimessage = MIDI.read;
}
The read function can be instantiated through the reader
factory which takes an optional configuration object. This object allow to define one decorator function per MIDI status,
in order to populate the meta
property of the message with application specific data,
in order to implement custom logic when subscribing to the message.
// example: read current UI state to check if MIDI learning is enabled
input.onmidimessage = MIDI.reader({
decorators: {
[MIDI.Status.CONTROL_CHANGE](message) {
return {
isMidiLearning: isMidiLearning()
};
}
},
});
Once read, messages are exposed through the Rx
Subject.
import * as MIDI from 'noon-io';
MIDI.Rx.subscribe(message => {
console.log(message.meta); // log the meta object populated by the custom decorator function
});
In addition to the message stream, noon-io provides a convenient observe
function,
which will return a observable of MIDI messages matching the given MIDI status and an optional MIDI chanel.
import * as MIDI from 'noon-io';
MIDI.observe(MIDI.Status.CONTROL_CHANGE, 1)
.subscribe(message => {
// handle control change message for channel 1
});
Sending a bank select followed by a program change can be achieved by sending two consecutive control change messages before sending the actual program change.
(The following has been tested on a Dave Smith Instruments Mopho device)
import * as MIDI from 'noon-io';
/*
* Start Bank Select message
* Selects banks 2 (bank 1 is 0) for channel 2
*/
output.send(
MIDI.writeMidiMessage({
status: MIDI.Status.CONTROL_CHANGE,
channel: 2,
data: {
control: 0, // bank select MSB (always 0)
value: 1, // MSB multiplier
}
})
);
output.send(
MIDI.writeMidiMessage({
status: MIDI.Status.CONTROL_CHANGE,
channel: 2,
data: {
control: 0, // bank select LSB (always 32)
value: 1, // LSB multiplier
}
})
); // Ends bank select message
/*
* Now that we have selected bank 2,
* let's select a random program
*/
output.send(
MIDI.writeMidiMessage({
status: MIDI.Status.PROGRAM_CHANGE,
channel: 2,
data: {
value: Math.ceil(Math.random() * 127),
}
})
);
Or using the bankSelectMSB
and bankSelectLSB
factories provided by noon-io
// Select bank 1
output.send(MIDI.channel(2).bankSelectMSB(0));
output.send(MIDI.channel(2).bankSelectLSB(0));
// Select program 109 from bank 1
output.send(MIDI.channel(2).programChange(Math.ceil(Math.random() * 127)));
Type | Reader | Writer | Status |
---|---|---|---|
NOTE ON | ✅ | ✅ | Read and write have been tested on a MIDI port |
NOTE OFF | ✅ | ✅ | Read and write have been tested on a MIDI port |
PITCH BEND | ✅ | ✅ | Read and write have been tested on a MIDI port |
CONTROL CHANGE | ✅ | ✅ | Read and write have been tested on a MIDI port |
PROGRAM CHANGE | ✅ | ✅ | Read and write have been tested on a MIDI port |
POLYPHONIC AFTER TOUCH | ✅ | ✅ | Both read and write have not been tested |
CHANNEL AFTER TOUCH | ✅ | ✅ | Both read and write have not been tested |
Type | Reader | Writer | Status |
---|---|---|---|
TIMING CLOCK | ✅ | ✅ | Only Read has been tester on a MIDI port |
START | ✅ | ✅ | Both read and write have not been tested |
STOP | ✅ | ✅ | Both read and write have not been tested |
CONTINUE | ✅ | ✅ | Both read and write have not been tested |
SYSTEM RESET | ✅ | ✅ | Both read and write have not been tested |
ACTIVE SENSING | ✅ | ✅ | Both read and write have not been tested |
SYSTEM EXCLUSIVE | ✅ | ❌ | Reader has not been tested, writer is not implemented |
MIDI TIME CODE | ❌ | ❌ | Not Implemented |
SONG POSITION | ❌ | ❌ | Not Implemented |
SONG SELECT | ❌ | ❌ | Not Implemented |
TUNE REQUEST | ❌ | ❌ | Not Implemented |