js/Mobilizing/serial/Midi.js
import Component from '../core/Component';
import * as debug from '../core/util/Debug';
export default class MIDI extends Component {
/**
Gives access to the MIDI devices. This class requires the Web MIDI API to operate properly.
@param {Object} params Parameters object, given by the constructor.
@param {String} params.inputName The MIDI IN interface name we want to open.
@param {String} params.outputName The MIDI OUT interface name we want to open.
@param {Function} params.onMIDIIn The MIDI IN callback we want to be called on a MIDI in event.
@requires Web MIDI API
*/
constructor({
inputName = undefined,
outputName = undefined,
onMIDIIn = undefined,
} = {}) {
super(...arguments);
this.inputName = inputName;
this.outputName = outputName;
this.onMIDIIn = onMIDIIn;
debug.log(`this.onMIDIIn=${this.onMIDIIn}`);
if (navigator.requestMIDIAccess) {
navigator.requestMIDIAccess().then(this.onMIDIInit.bind(this), this.onMIDIReject.bind(this));
}
else {
console.warn("No MIDI support present in your browser. Try in another browser.");
}
}
/**
Web MIDI API success callback.
@private
@param {Object} MIDI
*/
onMIDIInit(access) {
this.access = access;
this.hookUpMIDI();
this.access.onstatechange = this.hookUpMIDI;
}
/**
Web MIDI API failure callback.
@private
@param {Object} err
*/
onMIDIReject(err) {
alert(`
The MIDI system failed to start.
You're gonna have a bad time.
Error: ${err.message}
`);
}
/**
* hookUpMIDI
* @private
*/
hookUpMIDI() {
if (this.inputName !== undefined) {
const inputs = this.access.inputs.values();
debug.log("MIDI inputs on your system : ");
for (let input = inputs.next(); input && !input.done; input = inputs.next()) {
debug.log("input=", input);
if (input.value.name === this.inputName) {
debug.log(`found MIDI interface IN : ${input.value.name}`);
input.value.onMIDImessage = this.onMIDIMessage.bind(this);
}
}
}
if (this.outputName !== undefined) {
const outputs = this.access.outputs.values();
debug.log("MIDI outputs on your system : ");
for (let output = outputs.next(); output && !output.done; output = outputs.next()) {
debug.log("output=", output);
if (output.value.name === this.outputName) {
debug.log(`found MIDI interface OUT : ${output.value.name}`);
this.output = output.value;
}
}
}
}
/**
* onMIDIMessage
* @method onMIDIMessage
* @param {Object} event MIDI event
* @private
*/
onMIDIMessage(event) {
debug.log(`this.onMIDIIn=${this.onMIDIIn}`);
if (this.onMIDIIn !== undefined) {
//channel message data1 data2
const message = event.data[0] & 0xf0;
const channel = event.data[0] - message;
const data1 = event.data[1];
const data2 = event.data[2];
this.onMIDIIn(channel, message, data1, data2);
}
}
/**
Sends a Control Change MIDI message.
@method ControlChange
@param {Number} channel MIDI channel [0-15]
@param {Number} cc ControlChange number [0-127]
@param {Number} val ControlChange value [0-127]
@example
MIDI.ControlChange(2,11,50);
*/
ControlChange(channel, cc, val) {
if (this.output === undefined) {
return;
}
let ccMessage;
const m = 0xB0 + channel;
ccMessage = [m, cc, val];
this.output.send(ccMessage);
}
/**
Sends a NoteOn MIDI message.
@method NoteOn
@param {Number} channel MIDI channel [0-15]
@param {Number} note MIDI Note number [0-127]
@param {Number} vel note MIDI velocity [0-127]
@example
MIDI.NoteOn(0,60,127);
*/
NoteOn(channel, note, vel) {
if (this.output === undefined) {
return;
}
let ccMessage;
const m = 0x90 + channel;
ccMessage = [m, note, vel];
this.output.send(ccMessage);
}
/**
Sends a NoteOff MIDI message.
@method NoteOff
@param {Number} channel MIDI channel [0-15]
@param {Number} note MIDI Note number [0-127]
@param {Number} vel note MIDI velocity [0-127]
@example
MIDI.NoteOff(0,60,0);
*/
NoteOff(channel, note, vel) {
if (this.output === undefined) {
return;
}
let ccMessage;
const m = 0x80 + channel;
ccMessage = [m, note, vel];
this.output.send(ccMessage);
}
}
/**
* Note On
*
* @property NoteOn
* @type Number
* @static
* @final
*/
MIDI.NoteOn = 144;
/**
* Note Off
*
* @property NoteOff
* @type Number
* @static
* @final
*/
MIDI.NoteOff = 128;
/**
* After touch
*
* @property Aftertouch
* @type Number
* @static
* @final
*/
MIDI.Aftertouch = 160;
/**
* Control change
*
* @property ControlChange
* @type Number
* @static
* @final
*/
MIDI.ControlChange = 176;
/**
* Program change
*
* @property ProgramChange
* @type Number
* @static
* @final
*/
MIDI.ProgramChange = 192;