npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uttori/audio-midi

v0.9.1

Published

Utility to parse and manipulate MIDI files.

Downloads

37

Readme

view on npm npm module downloads Tree-Shaking Support Dependency Count Minified + GZip Minified

Uttori Audio MIDI

A utility to manipulate and parse MIDI data.

Install

npm install --save @uttori/audio-midi

Example

import fs from 'fs';
import AudioMIDI from '@uttori/audio-midi';
const data = fs.readFileSync('./song.mid');
const midi = new AudioPadInfo(data);
console.log('MIDI:', midi);

API Reference

Classes

Typedefs

AudioMIDI ⇐ DataBuffer

AudioMIDI - MIDI Utility MIDI File Format Parser & Generator

Kind: global class
Extends: DataBuffer

new AudioMIDI([input], [options])

Creates a new AudioMIDI.

| Param | Type | Description | | --- | --- | --- | | [input] | Array.<number> | ArrayBuffer | Buffer | DataBuffer | Int8Array | Int16Array | Int32Array | number | string | Uint8Array | Uint16Array | Uint32Array | undefined | The data to process. | | [options] | object | Options for this AudioMIDI instance. | | [options.format] | number | The MIDI format: 0, 1, or 2, default is 0. | | [options.timeDivision] | number | The indication of how MIDI ticks should be translated into time, default is 128. |

Example (AudioMIDI)

const data = fs.readFileSync('./song.mid');
const file = new AudioMIDI(data);
file.parse();
console.log('Chunks:', file.chunks);

audioMIDI.format : number

The MIDI format: 0, 1, or 2

Kind: instance property of AudioMIDI

audioMIDI.trackCount : number

The internal track count.

Kind: instance property of AudioMIDI

audioMIDI.timeDivision : number

The indication of how MIDI ticks should be translated into time.

Kind: instance property of AudioMIDI

audioMIDI.chunks : Array.<Track>

Kind: instance property of AudioMIDI

audioMIDI.readVariableLengthValues ⇒ number

Several different values in events are expressed as variable length quantities (e.g. delta time values). A variable length value uses a minimum number of bytes to hold the value, and in most circumstances this leads to some degree of data compresssion.

A variable length value uses the low order 7 bits of a byte to represent the value or part of the value. The high order bit is an "escape" or "continuation" bit. All but the last byte of a variable length value have the high order bit set. The last byte has the high order bit cleared. The bytes always appear most significant byte first.

Kind: instance property of AudioMIDI
Returns: number - The length of the next chunk.

audioMIDI.parse()

Parse a MIDI file from a Uint8Array.

Kind: instance method of AudioMIDI
See

audioMIDI.addTrack() ⇒ Track

Adds a new track to the MIDI file.

Kind: instance method of AudioMIDI
Returns: Track - The new track.

audioMIDI.addEvent(track, event)

Adds an event to a track.

Kind: instance method of AudioMIDI

| Param | Type | Description | | --- | --- | --- | | track | Track | The track to add the event to. | | event | Event | Array.<Event> | The event to add. |

audioMIDI.saveToDataBuffer() ⇒ DataBuffer

Writes the MIDI data to a binary file.

Kind: instance method of AudioMIDI
Returns: DataBuffer - The binary data buffer.

audioMIDI.writeChunk(dataBuffer, chunk)

Write a track chunk to the data buffer.

Kind: instance method of AudioMIDI

| Param | Type | Description | | --- | --- | --- | | dataBuffer | DataBuffer | The data buffer to write to. | | chunk | Track | The track chunk to write. |

audioMIDI.writeEvent(dataBuffer, event)

Helper function to write an event to the data buffer.

Kind: instance method of AudioMIDI

| Param | Type | Description | | --- | --- | --- | | dataBuffer | DataBuffer | The data buffer to write to. | | event | MidiTrackEvent | The event to write. |

audioMIDI.getUsedNotes() ⇒ Array.<UsedNote>

Returns a sorted list of all unique note numbers used in "Note On" events, along with their note names (e.g. "C3", "D#4").

Kind: instance method of AudioMIDI
Returns: Array.<UsedNote> - Array of note data

audioMIDI.validate() ⇒ Array.<string>

Validate a MIDI instance for common issues. Matching Note Ons / Offs: A velocity > 0 "Note On" increments activeNotes[note]. A "Note Off" or "Note On" with velocity == 0 decrements. If the count is already 0, that is invalid. At the end of the track, if any notes still have a positive count, that is also invalid. Meta Events: We do a small switch on event.metaType to check if the declared metaEventLength is correct for well-known meta events (End of Track, Set Tempo, Time Signature, etc.). Chunk Length: Since the parser already stored each chunk's chunkLength, we do minimal checks: if chunkLength > 0 but there are zero events, or vice versa, that is unusual.

Kind: instance method of AudioMIDI
Returns: Array.<string> - Array of warning / error messages discovered, an empty array if no issues are found.

AudioMIDI.decodeHeader(chunk) ⇒ Header

Decodes and validates MIDI Header. Checks for MThd header, reads the chunk length, format, track count, and PPQN (pulses per quarter note) / PPQ (pulses per quarter) / PQN (per quarter note) / TPQN (ticks per quarter note) / TPB (ticks per beat).

Signature (Decimal): [77, 84, 104, 100, ...] Signature (Hexadecimal): [4D, 54, 68, 64, ...] Signature (ASCII): [M, T, h, d, ...]

Kind: static method of AudioMIDI
Returns: Header - The decoded values.
Throws:

  • Error Invalid WAV header

| Param | Type | Description | | --- | --- | --- | | chunk | Buffer | string | Uint8Array | Data Blob |

AudioMIDI.getControllerLabel(controller) ⇒ string

Return the human readable controller name from the ID.

Kind: static method of AudioMIDI
Returns: string - The human-readable controller name.
See

| Param | Type | Description | | --- | --- | --- | | controller | number | The controller ID. |

AudioMIDI.getManufacturerLabel(manufacturerId) ⇒ string

Return the human readable manufacturer name from the ID.

Kind: static method of AudioMIDI
Returns: string - The human-readable manufacturer name.
See: MidiKit Help MIDI Manufacturers List

| Param | Type | Description | | --- | --- | --- | | manufacturerId | number | The manufacturer ID. |

AudioMIDI.writeVariableLengthValue(dataBuffer, value)

Write a variable-length value.

Kind: static method of AudioMIDI

| Param | Type | Description | | --- | --- | --- | | dataBuffer | DataBuffer | The data buffer to write to. | | value | number | The value to write as a variable-length quantity. |

AudioMIDI.writeEventData(dataBuffer, data)

Write event data.

Kind: static method of AudioMIDI

| Param | Type | Description | | --- | --- | --- | | dataBuffer | DataBuffer | The data buffer to write to. | | data | Uint8Array | Array.<number> | The event data to write. |

AudioMIDI.generateTempoEvent(bpm) ⇒ MidiTrackEvent

Generate a Set Tempo event with a provided BPM.

Kind: static method of AudioMIDI
Returns: MidiTrackEvent - The tempo event with the correct byte values.

| Param | Type | Description | | --- | --- | --- | | bpm | number | The desired tempo in Beats Per Minute. |

AudioMIDI.generateMetaStringEvent(metaType, data) ⇒ MidiTrackEvent

Generate a Meta String event:

  • 0x01: 'Text Event'
  • 0x02: 'Copyright Notice'
  • 0x03: 'Sequence / Track Name'
  • 0x04: 'Instrument Name'
  • 0x05: 'Lyrics'
  • 0x06: 'Marker'
  • 0x07: 'Cue Point'
  • 0x08: 'Program Name'
  • 0x09: 'Device (Port) Name'

Kind: static method of AudioMIDI
Returns: MidiTrackEvent - The meta string event with the encoded string data.

| Param | Type | Description | | --- | --- | --- | | metaType | number | The meta event type. (e.g., 0x03 for Track Name). | | data | string | The string value for the event (e.g., the name of the track). |

AudioMIDI.generateEndOfTrackEvent() ⇒ MidiTrackEvent

Generate an end of track event.

Kind: static method of AudioMIDI
Returns: MidiTrackEvent - The end of track event.

AudioMIDI.convertToMidi(options) ⇒ AudioMIDI

Convert a collection of tracks and notes into a new AudioMIDI instance.

Kind: static method of AudioMIDI
Returns: AudioMIDI - The newly constured MIDI

| Param | Type | Description | | --- | --- | --- | | options | object | The options | | [options.ppq] | number | The pulses per quarter note, default is 480. | | [options.bpm] | number | The BPM of the track, when blank no tempo event will be added. | | [options.tracks] | Array.<WritableTrack> | The MIDI tracks to write. | | [options.skipNotes] | Array.<number> | The MIDI notes to ship, if any. |

Example

const midi = AudioMIDI.convertToMidi({
  bpm,
  ppq,
  tracks: [
    {
      notes: myCustomNotes.map((note) => {
        return {
          note: note.midiNote,
          velocity: note.velocity,
          length: note.length,
        }
      }),
      metaStringEvents: {
        0x03: `Custom MIDI`,
      },
    }
  ],
  skipNotes: [128],
});
return midi;

AudioMIDI.noteToMidi(noteString, [octaveOffset], [noteMap]) ⇒ number

Convert a note string like C1 or D#2 to the MIDI value.

Kind: static method of AudioMIDI
Returns: number - The MIDI value for the provided note.

| Param | Type | Default | Description | | --- | --- | --- | --- | | noteString | string | | The notation string. | | [octaveOffset] | number | 2 | The default octave offset for C1, where a value of 2 means C1 = 36; default is 2. | | [noteMap] | Record.<string, number> | | The note map to use for the conversion. |

Example

AudioMIDI.noteToMidi('C4') === 72
AudioMIDI.noteToMidi('C3') === 60
AudioMIDI.noteToMidi('C2') === 48
AudioMIDI.noteToMidi('C1') === 36
AudioMIDI.noteToMidi('C-1') === 12
AudioMIDI.noteToMidi('C-2') === 0

AudioMIDI.midiToNote(midiValue, [octaveOffset], [noteNames]) ⇒ string

Convert a MIDI value back to a note string like C1 or D#2.

Kind: static method of AudioMIDI
Returns: string - The note label corresponding to the MIDI value.

| Param | Type | Default | Description | | --- | --- | --- | --- | | midiValue | number | | The MIDI value (0-127). | | [octaveOffset] | number | 2 | The default octave offset for C1, where a value of 2 means C1 = 36; default is 2. | | [noteNames] | Array.<string> | | The note names to use for the conversion. |

Example

AudioMIDI.midiToNote(72) === 'C4'
AudioMIDI.midiToNote(60) === 'C3'
AudioMIDI.midiToNote(48) === 'C2'
AudioMIDI.midiToNote(36) === 'C1'
AudioMIDI.midiToNote(12) === 'C-1'
AudioMIDI.midiToNote(0) === 'C-2'

WritableNote : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | ticks | number | The delay in ticks until the next track. | | midiNote | number | The MIDI note value. | | velocity | number | The velocity of the note (0-127). | | length | number | The length of the note in ticks. |

WritableTrack : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | [bpm] | number | The BPM of the track, when blank no tempo event will be added. | | [metaStringEvents] | Record.<number, string> | A key value collection of meta events to add where they key is the event type and the value is the data to add. | | [notes] | Array.<WritableNote> | A collection of notes to write on the track. |

NoteData : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | note | string | A note value. | | velocity | number | The velocity of the note (0-127). | | length | number | The length of the note in ticks. |

SysExData : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | manufacturerId | number | The manufacturer's ID code. | | manufacturerLabel | string | The manufacturer's label based on the ID. | | data | Array.<number> | The SysEx data bytes. |

EventData : string | number | Uint8Array | NoteData | SysExData

Kind: global typedef

MidiTrackEvent : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | deltaTime | number | The delta time of the MIDI event. | | type | number | The type of the event (e.g., meta event, regular event). | | label | string | A human-readable label describing the event. | | data | EventData | The data associated with the event. | | [metaType] | number | The subtype of the meta event. | | [metaEventLength] | number | The length of the meta event data. | | [channel] | number | The MIDI channel the event is for. | | [tag] | number | The tag for the M-Live Tag event. |

Header : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | type | string | The type of the chunk (e.g., MThd, MTrk). | | format | number | The format of the MIDI file (header only). | | trackCount | number | The number of tracks in the MIDI file (header only). | | timeDivision | number | The time division of the MIDI file (header only). | | chunkLength | number | The length of the chunk data. |

Track : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | type | string | The type of the chunk (e.g., MThd, MTrk). | | chunkLength | number | The length of the chunk data. | | events | Array.<MidiTrackEvent> | The collection of events in the track. |

UsedNote : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | noteNumber | number | The numeric value of the note. | | noteString | string | The human-readable note string. |


Tests

To run the test suite, first install the dependencies, then run npm test:

npm install
npm test
DEBUG=Uttori* npm test

Contributors

References

I found these links really helpful for understanding the MIDI format.

  • https://midi.org/midi-1-0-control-change-messages
  • https://midi.org/community/midi-specifications/yamaha-meta-events-in-midi-files
  • https://www.mixagesoftware.com/en/midikit/help/HTML/meta_events.html
  • https://web.archive.org/web/20140325195418/http://www.ta7.de/txt/musik/musi0006.htm#expand
  • https://www.lim.di.unimi.it/IEEE/MIDI/META.HTM
  • https://www.un4seen.com/forum/?topic=20355.msg142507#msg142507
  • https://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html
  • http://www.jososoft.dk/yamaha/docs_specs.htm

License