JavaScript library for MIDI communication that simplifies sending and receiving MIDI messages between browsers/Node.js and MIDI instruments
—
MIDI Input handling provides comprehensive functionality for receiving and processing MIDI messages from devices. Input objects represent physical or virtual MIDI input ports, while InputChannel objects provide channel-specific message handling.
Access and manage MIDI input ports.
class Input extends EventEmitter {
/**
* Array of 16 InputChannel objects (channels 1-16)
*/
readonly channels: InputChannel[];
/**
* Input port name as reported by the system
*/
readonly name: string;
/**
* Unique identifier for this input port
*/
readonly id: string;
/**
* Connection state: "closed", "open", or "pending"
*/
readonly connection: string;
/**
* Port state: "connected" or "disconnected"
*/
readonly state: string;
/**
* Device manufacturer name (if available)
*/
readonly manufacturer: string;
/**
* Port type (always "input")
*/
readonly type: string;
/**
* Octave offset for this input (-10 to 10)
*/
readonly octaveOffset: number;
}Add and remove event listeners for MIDI messages.
/**
* Add event listener for MIDI messages
* @param event - Event type (e.g., "noteon", "noteoff", "controlchange")
* @param listener - Event handler function
* @param options - Listener options
* @param options.channels - Channel filter (number, array, or "all")
* @param options.data1 - Filter by first data byte
* @param options.data2 - Filter by second data byte
* @returns Input instance for chaining
*/
addListener(event: string, listener: Function, options?: {
channels?: number | number[] | "all";
data1?: number | number[];
data2?: number | number[];
}): Input;
/**
* Add one-time event listener
* @param event - Event type
* @param listener - Event handler function
* @param options - Listener options
* @returns Input instance for chaining
*/
addOneTimeListener(event: string, listener: Function, options?: object): Input;
/**
* Shorthand for addListener with channel specification
* @param event - Event type
* @param channel - Channel number (1-16) or "all"
* @param listener - Event handler function
* @param options - Additional options
* @returns Input instance for chaining
*/
on(event: string, channel: number | "all", listener: Function, options?: object): Input;
/**
* Check if listener exists
* @param event - Event type
* @param listener - Event handler function
* @param options - Listener options to match
* @returns True if listener exists
*/
hasListener(event: string, listener: Function, options?: object): boolean;
/**
* Remove event listener
* @param event - Event type
* @param listener - Event handler function
* @param options - Listener options to match
* @returns Input instance for chaining
*/
removeListener(event: string, listener: Function, options?: object): Input;Usage Examples:
import { WebMidi } from "webmidi";
await WebMidi.enable();
const input = WebMidi.inputs[0];
// Listen for note on/off messages
input.addListener("noteon", (e) => {
console.log("Note on:", e.note.name + e.note.octave, "velocity:", e.velocity);
});
input.addListener("noteoff", (e) => {
console.log("Note off:", e.note.name + e.note.octave);
});
// Listen only on specific channel
input.addListener("controlchange", (e) => {
console.log("CC:", e.controller.number, "value:", e.value);
}, { channels: 1 });
// Listen for pitch bend on multiple channels
input.addListener("pitchbend", (e) => {
console.log("Pitch bend on channel", e.channel, "value:", e.value);
}, { channels: [1, 2, 3] });
// One-time listener
input.addOneTimeListener("programchange", (e) => {
console.log("Program changed to:", e.value);
});Forward MIDI messages to output ports.
/**
* Add message forwarder to output port
* @param output - Output port to forward messages to
* @param options - Forwarding options
* @param options.channels - Channel filter for forwarding
* @param options.types - Message types to forward
* @returns Forwarder instance
*/
addForwarder(output: Output, options?: {
channels?: number | number[] | "all";
types?: string | string[];
}): Forwarder;
/**
* Remove message forwarder
* @param forwarder - Forwarder instance to remove
*/
removeForwarder(forwarder: Forwarder): void;
/**
* Check if forwarder exists
* @param forwarder - Forwarder instance to check
* @returns True if forwarder exists
*/
hasForwarder(forwarder: Forwarder): boolean;Usage Examples:
const input = WebMidi.getInputByName("My Keyboard");
const output = WebMidi.getOutputByName("My Synth");
// Forward all messages
const forwarder = input.addForwarder(output);
// Forward only note messages from channels 1-4
const noteForwarder = input.addForwarder(output, {
channels: [1, 2, 3, 4],
types: ["noteon", "noteoff"]
});
// Remove forwarder
input.removeForwarder(forwarder);Channel-specific input handling for targeted MIDI communication.
class InputChannel extends EventEmitter {
/**
* Channel number (1-16)
*/
readonly number: number;
/**
* Parent Input object
*/
readonly input: Input;
/**
* Octave offset for this channel
*/
readonly octaveOffset: number;
/**
* Whether NRPN events are enabled for this channel
*/
readonly nrpnEventsEnabled: boolean;
}/**
* Get current state of a specific note
* @param note - Note to check (name, number, or Note object)
* @returns Note state object with velocity and timestamp
*/
getNoteState(note: string | number | Note): {
velocity: number;
timestamp: number;
rawVelocity: number;
} | false;
/**
* Get control change name by number
* @param number - CC number (0-127)
* @returns Control change name
*/
getCcNameByNumber(number: number): string;
/**
* Get channel mode name by number
* @param number - Channel mode number
* @returns Channel mode name
*/
getChannelModeByNumber(number: number): string;
/**
* Destroy the input channel (cleanup)
*/
destroy(): void;Usage Examples:
const input = WebMidi.inputs[0];
const channel1 = input.channels[0]; // Channel 1 (index 0)
// Check if a note is currently pressed
const noteState = channel1.getNoteState("C4");
if (noteState) {
console.log("C4 is pressed with velocity:", noteState.velocity);
}
// Listen to channel-specific events
channel1.addListener("noteon", (e) => {
console.log("Note on channel 1:", e.note.identifier);
});
// Get control change name
const ccName = channel1.getCcNameByNumber(64); // "sustain"// Note on event
input.addListener("noteon", (e) => {
console.log("Note:", e.note.name);
console.log("Octave:", e.note.octave);
console.log("Velocity:", e.velocity); // 0-1
console.log("Raw velocity:", e.rawVelocity); // 0-127
console.log("Channel:", e.channel); // 1-16
});
// Note off event
input.addListener("noteoff", (e) => {
console.log("Note off:", e.note.identifier);
console.log("Release velocity:", e.velocity);
});// Control change
input.addListener("controlchange", (e) => {
console.log("Controller:", e.controller.name);
console.log("Number:", e.controller.number);
console.log("Value:", e.value); // 0-1
console.log("Raw value:", e.rawValue); // 0-127
});
// Specific control changes
input.addListener("controlchange-sustain", (e) => {
console.log("Sustain pedal:", e.value > 0.5 ? "pressed" : "released");
});// Pitch bend
input.addListener("pitchbend", (e) => {
console.log("Pitch bend:", e.value); // -1 to 1
});
// Program change
input.addListener("programchange", (e) => {
console.log("Program:", e.value); // 1-128
});
// Channel aftertouch
input.addListener("channelaftertouch", (e) => {
console.log("Channel pressure:", e.value);
});
// Key aftertouch (polyphonic)
input.addListener("keyaftertouch", (e) => {
console.log("Key pressure:", e.note.identifier, e.value);
});interface NoteEvent {
note: Note;
velocity: number;
rawVelocity: number;
channel: number;
timestamp: number;
target: Input | InputChannel;
}
interface ControlChangeEvent {
controller: {
name: string;
number: number;
};
value: number;
rawValue: number;
channel: number;
timestamp: number;
target: Input | InputChannel;
}
interface PitchBendEvent {
value: number;
rawValue: number;
channel: number;
timestamp: number;
target: Input | InputChannel;
}
interface ListenerOptions {
channels?: number | number[] | "all";
data1?: number | number[];
data2?: number | number[];
}Install with Tessl CLI
npx tessl i tessl/npm-webmidi