@julusian/midi
Version:
MIDI hardware IO
195 lines (166 loc) • 4.2 kB
JavaScript
const midi = require("pkg-prebuilds/bindings")(
__dirname,
require("./binding-options")
);
const Stream = require('stream');
// MIDI input inherits from EventEmitter
const { EventEmitter } = require('events');
// Bring in the set of constants to reflect MIDI messages and their
// parameters, to eliminate the need for magic numbers.
/** An instrument list, only valid in the General MIDI standard */
const Instruments = require('./lib/instruments');
/** A drum map, only valid in the General MIDI standard */
const Drums = require('./lib/drums');
/** Note descriptions, with Middle C = C5 = MIDI note 60 */
const Notes = require('./lib/notes');
/** Message names, including CCs */
const Messages = require('./lib/messages');
class Input extends EventEmitter {
constructor() {
super()
this.input = new midi.Input((deltaTime, message) => {
this.emit('message', deltaTime, Array.from(message.values()))
})
}
closePort() {
return this.input.closePort()
}
destroy() {
return this.input.destroy()
}
getPortCount() {
return this.input.getPortCount()
}
getPortName(port) {
return this.input.getPortName(port)
}
isPortOpen() {
return this.input.isPortOpen()
}
ignoreTypes(sysex, timing, activeSensing) {
return this.input.ignoreTypes(sysex, timing, activeSensing)
}
openPort(port) {
return this.input.openPort(port)
}
openPortByName(name) {
for(let port=0; port<this.input.getPortCount(); ++port) {
if (name === this.input.getPortName(port)) {
return this.input.openPort(port);
}
}
return undefined;
}
openVirtualPort(port) {
return this.input.openVirtualPort(port)
}
setBufferSize(size, count = 4) {
return this.input.setBufferSize(size, count)
}
}
class Output {
constructor() {
this.output = new midi.Output()
}
closePort() {
return this.output.closePort()
}
destroy() {
return this.output.destroy()
}
getPortCount() {
return this.output.getPortCount()
}
getPortName(port) {
return this.output.getPortName(port)
}
isPortOpen() {
return this.output.isPortOpen()
}
openPort(port) {
return this.output.openPort(port)
}
openPortByName(name) {
for(let port=0; port<this.output.getPortCount(); ++port) {
if (name === this.output.getPortName(port)) {
return this.output.openPort(port);
}
}
return undefined;
}
openVirtualPort(port) {
return this.output.openVirtualPort(port)
}
send(message) {
return this.sendMessage(message)
}
sendMessage(message) {
if (Array.isArray(message)) {
message = Buffer.from(message)
}
if (!Buffer.isBuffer(message)) {
throw new Error('First argument must be an array or Buffer')
}
return this.output.sendMessage(message)
}
}
function createReadStream(input) {
input = input || new Input();
var stream = new Stream();
stream.readable = true;
stream.paused = false;
stream.queue = [];
input.on('message', function(deltaTime, message) {
var packet = new Buffer.from(message);
if (!stream.paused) {
stream.emit('data', packet);
} else {
stream.queue.push(packet);
}
});
stream.pause = function() {
stream.paused = true;
};
stream.resume = function() {
stream.paused = false;
while (stream.queue.length && stream.emit('data', stream.queue.shift())) {}
};
return stream;
};
function createWriteStream(output) {
output = output || new Output();
var stream = new Stream();
stream.writable = true;
stream.paused = false;
stream.queue = [];
stream.write = function(d) {
if (Buffer.isBuffer(d)) {
d = Array.prototype.slice.call(d, 0);
}
output.sendMessage(d);
return !this.paused;
}
stream.end = function(buf) {
buf && stream.write(buf);
stream.writable = false;
};
stream.destroy = function() {
stream.writable = false;
}
return stream;
};
module.exports = {
Input,
Output,
createReadStream,
createWriteStream,
Constants: {
Instruments,
Drums,
Notes,
Messages,
},
// Backwards compatibility.
input: Input,
output: Output,
};