jsm Manual & Documentation


Table Of Contents


jsm - MIDI library for node

jsm makes a system's MIDI ports accessible to node applications. It uses the portmidi cross-platform media library, so it should work on MacOS, Windows and Linux.

jsm is designed to make it easy for node applications to send and receive MIDI messages. It was initially developed to implement flexible interfaces between control surfaces and synthesizers. Efficiency is a concern, too, but at this stage, there is no provision to make strict timing promises. This means that while it is possible to generate note messages, jitter and latency cannot be controlled tightly yet.

Sending MIDI messages

This is an example of a program that sends a few MIDI control messages:

var MIDI = require('MIDI');

var midiOutput = new MIDI.MIDIOutput();
console.log("opened MIDI output port", midiOutput.portName);

midiOutput.channel(3);              // Set output channel 3
midiOutput.controlChange(0, 10);    // Select bank 10 (CC0)
midiOutput.channel(4);              // Set output channel 4
midiOutput.controlChange(7, 80);    // Set volume to 80 (CC7)

Receiving MIDI messages

This is an example of a program that receives MIDI noteOn messages and prints them to the console:

var MIDI = require('MIDI');

var midiInput = new MIDI.MIDIInput();
console.log("opened MIDI input port", midiOutput.portName);

midiInput.on('noteOn',
             function (pitch, velocity, channel) {
                 console.log('note', MIDI.pitchToNote(pitch),
                             'velocity', velocity,
                             'channel', channel);
             });

MIDI utility functions

MIDI.inputPorts()

MIDI.outputPorts()

Return the available MIDI input port and output port names, as arrays of strings.

MIDI.pitchToNote(pitch)

Convert the given integer MIDI pitch to a note name string.

MIDI.noteToPitch(noteName)

Convert the given noteName string to a MIDI integer pitch.

MIDI.messageToString(message)

Convert the given binary message, an array containing integer values, to a string of hex bytes separated by spaces.

MIDI.currentTime()

Returns the current time in terms of milliseconds since program start. This is the time base used for sending delayed messages and timestamps of incoming messages.

MIDI.at(time, callback)

Establishes a callback function to be called synchronously to the MIDI clock. time is specified in absolute time as returned by the currentTime() function, passed to the application from callbacks and specified in message sending functions.

MIDIInput

The MIDIInput objects represents a handle to a MIDI input port. Its constructor function accepts a port name as argument.

Applications are notified by incoming messages by the way of events that are delivered to callbacks, using the standard node event handling idiom.

All event handlers are called with the message timestamp as last argument. The message timestamp indicates the point in time when the message was received, measured in milliseconds since the start of the program.

MIDIInput(portName)

Return a MIDIInput object opened to the port with the given portName. portName can be specified as undefined. If so, the port named by the MIDI_INPUT environment variable, or, if that variable is not set, the first MIDI input port available in the system will be opened.

Higher-level events

Event: 'nrpn7'

Event: 'nrpn14'

function (parameterNumber, value, channel, time) { }

Emitted when an NRPN control change has been received. NRPNs are a sort of extended parameters that allow for a larger number of parameters with a wider value range to be submitted. The parameter number is represented by 14 bits sent in two controlChange message for controller 0x63 (MSB) and 0x62 (LSB), the value is either 7 bits sent as controlChange for controller 0x06, or 14 bits sent in two controlChange messages for controller 0x06 (MSB) and 0x26 (LSB). To change the value of an NRPN controller, the sender first sends the parameter number as two controlChange messages for controller 0x63 (MSB) and 0x62 (LSB) followed by the value, either as one message for controller 0x06 or as two messages for controller 0x06 (MSB) and controller 0x26.

When the NRPN controller number has been selected, the sender can also send incremental changes using the controller number 0x60 (increment) or 0x61 (decrement).

The sender does not need to re-select the NRPN controller for each value change. Rather, the NRPN controller is kept selected until overwritten. For NRPN controllers in 14 bit mode, it is possible to send only the LSB after the controller number and the MSB have been sent.

The 'nrpn7' and 'nrpn14' events are emitted to the application whenever a new value has been completely received, either through an incremental or an absolute change message.

Standard MIDI message events

Applications can listen for any of the standard MIDI messages as listed below. Event handlers are called with the message argument(s) parsed as integer values.

Event: 'noteOn'

function (pitch, velocity, channel, time) { }

Event: 'noteOff'

function (pitch, velocity, channel, time) { }

Event: 'polyphonicKeyPressure'

function (pitch, velocity, channel, time) { }

Event: 'controlChange'

function (controllerNumber, controllerValue, channel, time) { }

Event: 'programChange'

function (programNumber, channel, time) { }

Event: 'channelPressure'

function (pressureValue, channel, time) { }

Event: 'pitchWheelChange'

function (valueLsb, valueMsb, channel, time) { }

System Common Messages

Event: 'sysex'

function (message, time) { }

Emitted when a system exclusive message has been received. The message is passed as an array of numbers, including the 0xf0 and 0xf7 message delimiters.

Event: 'midiTimeCode'

function (argument, time) { }

Event: 'songPositionPointer'

function (positionLsb, positionMsb, time) { }

Event: 'songSelect'

function (songNumber, time) { }

Event: 'tuneRequest'

function (time) { }

System Real-Time Messages

Event: 'timingClock'

function (time) { }

Event: 'tick'

function (time) { }

Event: 'start'

function (time) { }

Event: 'stop'

function (time) { }

Event: 'continue'

function (time) { }

Event: 'activeSensing'

function (time) { }

Event: 'reset'

function (time) { }

MIDIInput.portName

Returns the port name that this MIDIInput object has been opened on.

MIDIOutput.channels(argument)

Establish the channel mask for received messages. By default, messages for all channels are received.

The argument may be either a single channel number or an array of channel numbers to listen to. Channel numbers are one-based. Channel number zero indicates that messages for all channels should be listened for. ## MIDIOutput

The MIDIOutput object represents a handle to a MIDI output port. Its constructor function accepts a port name as argument. It has a send() function for sending arbitary MIDI messages as well as convenience functions for each defined MIDI message.

MIDIOutput(portName, [latency])

Return a MIDIOutput object opened to the port with the given portName. portName can be specified as undefined. If so, the port named by the MIDI_OUTPUT environment variable, or, if that variable is not set, the first MIDI output port available in the system will be opened.

If a latency is supplied, it determines the portmidi latency of the port and enables deferred sending of messages.

The time argument that can be supplied to all the message sending functions below specifies the absolute time at which the message will be sent. The current absolute time may be determined by the 'MIDI.currentTime()' function. Note that it is an error to specify a sending time that has already passed. Also, message sending timestamps must be monotonically increasing, i.e. once a message has been enqueued for a certain point in time, it is not possible to enqueue another message to be sent earlier than that. Such a condition will be detected and signalled as an error to the application.

MIDIOutput.portName()

Returns the port name that this MIDIOutput object has been opened on.

MIDIOutput.channel(channelNumber)

The channel number to use for sending messages (1 to 16). When using the send() function directly, the channel number is not used. By default, the MIDIOutput object sends on MIDI channel 1.

MIDIOutput.send(message, [time])

Send a raw MIDI message. message is either a string with space separated hexadecimal values or an array of numbers.

MIDIOutput.noteOn(pitch, velocity, [time])

MIDIOutput.noteOff(pitch, velocity, [time])

Send a MIDI Note On or Note Off event on the current channel. pitch is the pitch of the note, which may be specified either as integer MIDI note number or as note name string (e.g. 'C0', 'F#4' or 'B-2').

MIDIOutput.pitchWheelChange(value, [time])

Send a MIDI pitchWheelChange message with the given value as argument. value must be passed as a number between -8192 and 8191.

MIDIOutput.sysex(message, [time])

Send the given MIDI sysex message. The message must be either a string with space separated hexadecimal values or an array of numbers. The start sysex (0xf0) and end sysex (0xf7) bytes must be included in the message. Nested messages are not allowed.

MIDIOutput.nrpn7(parameter, value, [time])

MIDIOutput.nrpn14(parameter, value, [time])

Send a NRPN message consisting of a 14 bit NRPN parameter and a 7 (nrpn7) or 14 (nrpn14) bit value. No previous selection of the NRPN controller number in the target device is assumed, i.e. nrpn7 results in three controlChange messages and nrpn14 results in four controlChange message to be sent to the target device.

MIDIOutput.polyphonicKeyPressure(pitch, velocity, [time])

MIDIOutput.controlChange(controllerNumber, controllerValue, [time])

MIDIOutput.programChange(programNumber, [time])

MIDIOutput.channelPressure(pressureValue, [time])

MIDIOutput.midiTimeCode(argument, [time])

MIDIOutput.songPositionPointer(positionLsb, positionMsb, [time])

MIDIOutput.songSelect(songNumber, [time])

MIDIOutput.tuneRequest([time])

MIDIOutput.timingClock([time])

MIDIOutput.tick([time])

MIDIOutput.start([time])

MIDIOutput.stop([time])

MIDIOutput.continue([time])

MIDIOutput.activeSensing([time])

MIDIOutput.reset([time])

Send the respective standard MIDI message with the arguments supplied on the current channel. No further translation of the arguments is performed for these messages.