CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-webmidi

JavaScript library for MIDI communication that simplifies sending and receiving MIDI messages between browsers/Node.js and MIDI instruments

Pending
Overview
Eval results
Files

constants.mddocs/

Constants and Enumerations

The Enumerations class provides MIDI specification constants and enumerations for all message types, control change mappings, and system messages. These constants ensure consistent and correct MIDI communication.

Capabilities

Channel Message Constants

Constants for MIDI channel messages (0x80-0xEF).

class Enumerations {
  /**
   * Channel message type constants
   */
  static readonly CHANNEL_MESSAGES: {
    noteoff: number;
    noteon: number;
    keyaftertouch: number;
    controlchange: number;
    programchange: number;
    channelaftertouch: number;
    pitchbend: number;
  };
  
  /**
   * MIDI channel message constants (with MIDI channel values 0-15)
   */
  static readonly MIDI_CHANNEL_MESSAGES: {
    noteoff: number;
    noteon: number;
    keyaftertouch: number;
    controlchange: number;
    programchange: number;
    channelaftertouch: number;
    pitchbend: number;
  };
}

Usage Examples:

import { Enumerations } from "webmidi";

// Channel message constants
console.log(Enumerations.CHANNEL_MESSAGES.noteon);        // 9
console.log(Enumerations.CHANNEL_MESSAGES.noteoff);       // 8
console.log(Enumerations.CHANNEL_MESSAGES.controlchange); // 11
console.log(Enumerations.CHANNEL_MESSAGES.programchange); // 12
console.log(Enumerations.CHANNEL_MESSAGES.pitchbend);     // 14

// MIDI channel message constants (base values)
console.log(Enumerations.MIDI_CHANNEL_MESSAGES.noteon);   // 144 (0x90)
console.log(Enumerations.MIDI_CHANNEL_MESSAGES.noteoff);  // 128 (0x80)

Channel Numbers

Valid channel number constants.

/**
 * Valid channel numbers (1-16)
 */
static readonly CHANNEL_NUMBERS: number[];

/**
 * MIDI channel numbers (0-15)
 */
static readonly MIDI_CHANNEL_NUMBERS: number[];

Usage Examples:

// User-facing channel numbers (1-16)
console.log(Enumerations.CHANNEL_NUMBERS); // [1, 2, 3, ..., 16]

// MIDI protocol channel numbers (0-15)
console.log(Enumerations.MIDI_CHANNEL_NUMBERS); // [0, 1, 2, ..., 15]

// Validate channel numbers
function isValidChannel(channel) {
  return Enumerations.CHANNEL_NUMBERS.includes(channel);
}

function isValidMidiChannel(channel) {
  return Enumerations.MIDI_CHANNEL_NUMBERS.includes(channel);
}

Control Change Messages

Comprehensive control change message mappings.

/**
 * Control change message constants with descriptive names
 */
static readonly CONTROL_CHANGE_MESSAGES: {
  bankselectcoarse: number;
  modulationwheelcoarse: number;
  breathcontrollercoarse: number;
  footcontrollercoarse: number;
  portamentotimecoarse: number;
  dataentrycoarse: number;
  volumecoarse: number;
  balancecoarse: number;
  pancoarse: number;
  expressioncoarse: number;
  effectcontrol1coarse: number;
  effectcontrol2coarse: number;
  generalpurposecontroller1: number;
  generalpurposecontroller2: number;
  generalpurposecontroller3: number;
  generalpurposecontroller4: number;
  bankselectfine: number;
  modulationwheelfine: number;
  breathcontrollerfine: number;
  footcontrollerfine: number;
  portamentotimefine: number;
  dataentryfine: number;
  volumefine: number;
  balancefine: number;
  panfine: number;
  expressionfine: number;
  effectcontrol1fine: number;
  effectcontrol2fine: number;
  sustain: number;
  portamento: number;
  sostenuto: number;
  softpedal: number;
  legatofootswitch: number;
  hold2: number;
  soundvariation: number;
  resonance: number;
  releasetime: number;
  attacktime: number;
  brightness: number;
  decaytime: number;
  vibratorate: number;
  vibratodepth: number;
  vibratodelay: number;
  generalpurposecontroller5: number;
  generalpurposecontroller6: number;
  generalpurposecontroller7: number;
  generalpurposecontroller8: number;
  portamentocontrol: number;
  effects1depth: number;
  effects2depth: number;
  effects3depth: number;
  effects4depth: number;
  effects5depth: number;
  dataincrement: number;
  datadecrement: number;
  nonregisteredparametercoarse: number;
  nonregisteredparameterfine: number;
  registeredparametercoarse: number;
  registeredparameterfine: number;
  allsoundoff: number;
  resetallcontrollers: number;
  localcontrol: number;
  allnotesoff: number;
  omnimodeoff: number;
  omnimodeon: number;
  monomodeon: number;
  polymodeon: number;
};

/**
 * MIDI control change message constants (CC numbers 0-127)
 */
static readonly MIDI_CONTROL_CHANGE_MESSAGES: object;

Usage Examples:

// Common control changes
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.volumecoarse);    // 7
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.pancoarse);       // 10
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.sustain);         // 64
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.effects1depth);   // 91 (reverb)
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.effects3depth);   // 93 (chorus)

// Channel mode messages
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.allsoundoff);     // 120
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.allnotesoff);     // 123
console.log(Enumerations.CONTROL_CHANGE_MESSAGES.resetallcontrollers); // 121

// Use in code
function sendVolume(output, channel, volume) {
  const ccNumber = Enumerations.CONTROL_CHANGE_MESSAGES.volumecoarse;
  output.sendControlChange(ccNumber, volume, { channels: channel });
}

function enableSustain(output, channel) {
  const ccNumber = Enumerations.CONTROL_CHANGE_MESSAGES.sustain;
  output.sendControlChange(ccNumber, 127, { channels: channel });
}

Channel Mode Messages

Channel mode message constants for voice and mode control.

/**
 * Channel mode message constants
 */
static readonly CHANNEL_MODE_MESSAGES: {
  allsoundoff: number;
  resetallcontrollers: number;
  localcontrol: number;
  allnotesoff: number;
  omnimodeoff: number;
  omnimodeon: number;
  monomodeon: number;
  polymodeon: number;
};

/**
 * MIDI channel mode message constants
 */
static readonly MIDI_CHANNEL_MODE_MESSAGES: object;

Usage Examples:

// Channel mode constants
console.log(Enumerations.CHANNEL_MODE_MESSAGES.allsoundoff);      // 120
console.log(Enumerations.CHANNEL_MODE_MESSAGES.allnotesoff);      // 123
console.log(Enumerations.CHANNEL_MODE_MESSAGES.resetallcontrollers); // 121
console.log(Enumerations.CHANNEL_MODE_MESSAGES.localcontrol);     // 122

// Omni mode constants
console.log(Enumerations.CHANNEL_MODE_MESSAGES.omnimodeoff);      // 124
console.log(Enumerations.CHANNEL_MODE_MESSAGES.omnimodeon);       // 125

// Mono/poly mode constants
console.log(Enumerations.CHANNEL_MODE_MESSAGES.monomodeon);       // 126
console.log(Enumerations.CHANNEL_MODE_MESSAGES.polymodeon);       // 127

// Use in emergency stop function
function panicStop(output) {
  const allSoundOff = Enumerations.CHANNEL_MODE_MESSAGES.allsoundoff;
  const allNotesOff = Enumerations.CHANNEL_MODE_MESSAGES.allnotesoff;
  
  // Send to all channels
  for (let channel = 1; channel <= 16; channel++) {
    output.sendControlChange(allSoundOff, 0, { channels: channel });
    output.sendControlChange(allNotesOff, 0, { channels: channel });
  }
}

Registered Parameter Numbers

Registered Parameter Number (RPN) constants for standard parameters.

/**
 * Registered parameter constants
 */
static readonly REGISTERED_PARAMETERS: {
  pitchbendrange: number[];
  channelfinetuning: number[];
  channelcoarsetuning: number[];
  tuningprogram: number[];
  tuningbank: number[];
  modulationrange: number[];
  azimuthangle: number[];
  elevationangle: number[];
  gain: number[];
  distanceratio: number[];
  maximumdistance: number[];
  gainincrease: number[];
  referenceazimuthangle: number[];
  referenceelvationangle: number[];
  referencegain: number[];
  referencedistanceratio: number[];
};

/**
 * MIDI registered parameter constants
 */
static readonly MIDI_REGISTERED_PARAMETERS: object;

Usage Examples:

// RPN constants
console.log(Enumerations.REGISTERED_PARAMETERS.pitchbendrange);    // [0, 0]
console.log(Enumerations.REGISTERED_PARAMETERS.channelfinetuning); // [0, 1]
console.log(Enumerations.REGISTERED_PARAMETERS.channelcoarsetuning); // [0, 2]
console.log(Enumerations.REGISTERED_PARAMETERS.tuningprogram);     // [0, 3]

// Use with RPN messages
function setPitchBendRange(output, channel, semitones, cents = 0) {
  const rpn = Enumerations.REGISTERED_PARAMETERS.pitchbendrange;
  output.sendRpnValue(rpn, [semitones, cents], { channels: channel });
}

function setFineTuning(output, channel, cents) {
  const rpn = Enumerations.REGISTERED_PARAMETERS.channelfinetuning;
  const msbLsb = Utilities.fromFloatToMsbLsb((cents + 100) / 200); // -100 to +100 cents
  output.sendRpnValue(rpn, [msbLsb.msb, msbLsb.lsb], { channels: channel });
}

System Messages

System message constants for real-time and common messages.

/**
 * System message constants
 */
static readonly SYSTEM_MESSAGES: {
  sysex: number;
  timecode: number;
  songposition: number;
  songselect: number;
  tunerequest: number;
  sysexend: number;
  clock: number;
  start: number;
  continue: number;
  stop: number;
  activesensing: number;
  reset: number;
};

/**
 * MIDI system message constants
 */
static readonly MIDI_SYSTEM_MESSAGES: object;

Usage Examples:

// System message constants
console.log(Enumerations.SYSTEM_MESSAGES.sysex);        // 240 (0xF0)
console.log(Enumerations.SYSTEM_MESSAGES.clock);        // 248 (0xF8)
console.log(Enumerations.SYSTEM_MESSAGES.start);        // 250 (0xFA)
console.log(Enumerations.SYSTEM_MESSAGES.stop);         // 252 (0xFC)
console.log(Enumerations.SYSTEM_MESSAGES.reset);        // 255 (0xFF)

// System common messages
console.log(Enumerations.SYSTEM_MESSAGES.timecode);     // 241 (0xF1)
console.log(Enumerations.SYSTEM_MESSAGES.songposition); // 242 (0xF2)
console.log(Enumerations.SYSTEM_MESSAGES.songselect);   // 243 (0xF3)
console.log(Enumerations.SYSTEM_MESSAGES.tunerequest);  // 246 (0xF6)

// Use for message filtering
function isClockMessage(message) {
  return message.statusByte === Enumerations.SYSTEM_MESSAGES.clock;
}

function isTransportMessage(message) {
  const transportMessages = [
    Enumerations.SYSTEM_MESSAGES.start,
    Enumerations.SYSTEM_MESSAGES.continue,
    Enumerations.SYSTEM_MESSAGES.stop
  ];
  return transportMessages.includes(message.statusByte);
}

Channel Events

Array of channel event type names.

/**
 * Channel event type names
 */
static readonly CHANNEL_EVENTS: string[];

Usage Examples:

// Channel event names
console.log(Enumerations.CHANNEL_EVENTS);
// ["noteoff", "noteon", "keyaftertouch", "controlchange", 
//  "programchange", "channelaftertouch", "pitchbend"]

// Use for event handling
function setupChannelListeners(input) {
  Enumerations.CHANNEL_EVENTS.forEach(eventType => {
    input.addListener(eventType, (e) => {
      console.log(`Received ${eventType} on channel ${e.channel}`);
    });
  });
}

// Check if event is a channel event
function isChannelEvent(eventType) {
  return Enumerations.CHANNEL_EVENTS.includes(eventType);
}

Practical Usage Examples

Message Type Detection

import { Enumerations, Message } from "webmidi";

function analyzeMessage(message) {
  const statusByte = message.statusByte;
  
  // Check channel messages
  if (message.isChannelMessage) {
    const command = message.command;
    
    if (command === Enumerations.CHANNEL_MESSAGES.noteon) {
      return "Note On";
    } else if (command === Enumerations.CHANNEL_MESSAGES.controlchange) {
      const ccNumber = message.dataBytes[0];
      
      // Check for channel mode messages
      if (ccNumber >= 120) {
        for (const [name, value] of Object.entries(Enumerations.CHANNEL_MODE_MESSAGES)) {
          if (value === ccNumber) {
            return `Channel Mode: ${name}`;
          }
        }
      }
      
      // Regular control change
      return `Control Change: CC${ccNumber}`;
    }
  }
  
  // Check system messages
  for (const [name, value] of Object.entries(Enumerations.SYSTEM_MESSAGES)) {
    if (value === statusByte) {
      return `System: ${name}`;
    }
  }
  
  return "Unknown";
}

Control Change Name Resolution

function getControllerName(ccNumber) {
  // Find name in control change messages
  for (const [name, value] of Object.entries(Enumerations.CONTROL_CHANGE_MESSAGES)) {
    if (value === ccNumber) {
      return name;
    }
  }
  
  return `CC${ccNumber}`;
}

function getControllerNumber(ccName) {
  const normalizedName = ccName.toLowerCase().replace(/[^a-z0-9]/g, '');
  
  for (const [name, value] of Object.entries(Enumerations.CONTROL_CHANGE_MESSAGES)) {
    if (name === normalizedName) {
      return value;
    }
  }
  
  return undefined;
}

// Usage
console.log(getControllerName(64));        // "sustain"
console.log(getControllerName(91));        // "effects1depth" (reverb)  
console.log(getControllerNumber("volume")); // undefined (need "volumecoarse")
console.log(getControllerNumber("volumecoarse")); // 7

Standard MIDI Implementation

// Create a standard MIDI implementation using constants
class StandardMidiDevice {
  constructor(output) {
    this.output = output;
  }
  
  // Standard program change
  selectProgram(channel, program) {
    this.output.sendProgramChange(program, { channels: channel });
  }
  
  // Volume control
  setVolume(channel, volume) {
    const cc = Enumerations.CONTROL_CHANGE_MESSAGES.volumecoarse;
    this.output.sendControlChange(cc, volume, { channels: channel });
  }
  
  // Pan control
  setPan(channel, pan) {
    const cc = Enumerations.CONTROL_CHANGE_MESSAGES.pancoarse;
    this.output.sendControlChange(cc, pan, { channels: channel });
  }
  
  // Sustain pedal
  setSustain(channel, enabled) {
    const cc = Enumerations.CONTROL_CHANGE_MESSAGES.sustain;
    const value = enabled ? 127 : 0;
    this.output.sendControlChange(cc, value, { channels: channel });
  }
  
  // Emergency stop
  panic() {
    const allSoundOff = Enumerations.CHANNEL_MODE_MESSAGES.allsoundoff;
    const allNotesOff = Enumerations.CHANNEL_MODE_MESSAGES.allnotesoff;
    
    Enumerations.CHANNEL_NUMBERS.forEach(channel => {
      this.output.sendControlChange(allSoundOff, 0, { channels: channel });
      this.output.sendControlChange(allNotesOff, 0, { channels: channel });
    });
  }
  
  // Reset all controllers
  resetControllers(channel = "all") {
    const reset = Enumerations.CHANNEL_MODE_MESSAGES.resetallcontrollers;
    this.output.sendControlChange(reset, 0, { channels: channel });
  }
}

Types

type ChannelMessageType = "noteoff" | "noteon" | "keyaftertouch" | "controlchange" | "programchange" | "channelaftertouch" | "pitchbend";

type SystemMessageType = "sysex" | "timecode" | "songposition" | "songselect" | "tunerequest" | "clock" | "start" | "continue" | "stop" | "activesensing" | "reset";

type ChannelModeMessageType = "allsoundoff" | "resetallcontrollers" | "localcontrol" | "allnotesoff" | "omnimodeoff" | "omnimodeon" | "monomodeon" | "polymodeon";

interface ControlChangeMessages {
  [key: string]: number;
}

interface RegisteredParameters {
  [key: string]: number[];
}

Install with Tessl CLI

npx tessl i tessl/npm-webmidi

docs

constants.md

index.md

message-forwarding.md

message-processing.md

midi-input.md

midi-output.md

note-processing.md

utilities.md

webmidi-interface.md

tile.json