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

@i-win/midi-processing-js

v1.0.0

Published

Converts MIDI files to a JSON-friendly object and back for you to modify and do what you need with it.

Downloads

106

Readme

midi-processing-js

NOTE: I made this library because it integrates well with what I do. This may not be rigorously tested, nor may I be able to constantly maintain it. If you need a library that is more robust please use @tonejs/midi.

Converts MIDI files to a JSON-friendly object and back for you to modify and do whatever you want with it.

Method Overview

Global Functions

fromMidiBytes(data: ArrayLike<number>): MidiRep

Convert any byte sequence into a MidiRep instance. May throw an exception with malformed data.

Sample usage:

const data = await readFile("./file.mid");
const midiRep = fromMidiBytes(data);

toMidiBytes(midiRep: MidiRep): Uint8Array

Return the byte sequence from the MidiRep. May throw an exception with malformed data.

MNote

Represents an individual note.

| Property | Type | Description | | --- | --- | --- | | channel | number | Channel of the note. Each note has one. In FL Studio, if you enable map colors to channel notes, the color is the channel, but keep in mind colors here count from 0. int, 0-15 incl; cannot save if this is violated | | pitch | number | C5 (middle C) == 60, C#5 == 61. int, 0-127 incl; cannot save if this is violated | | vel | number | Velocity of this note when it starts playing. Usually 100 is the loudest volume. int, 0-127 incl; cannot save if this is violated | | beat | number | Beat of the note where it starts playing. float >= 0; note dropped if this is violated, when saved. To avoid floating point issues, you may want to represent these values as a quotient of 96 if you want to do any comparisons (round(beat*96)/96). Or you can use approximate comparisons. | | duration | number | Duration of the note. The note ends at beat + duration. float >= 0; set to 0 if violated when saved |

TempoChange

Represents a change in the MIDI's tempo. With no tempo changes, there will be one instance with beat = 0.

| Property | Type | Description | | --- | --- | --- | | beat | number | Beat where the tempo change occurs. float >= 0; instance dropped if this is violated, when saved | | new_bpm | number | float >= 0; cannot save if this is violated |

Track

A track. Tracks store notes. While track ordering is guaranteed when you re-export the MIDI file, do not rely on the indices of each track since programs may offset them for some reason.

| Property | Type | Description | | --- | --- | --- | | notes | MNote[] | All notes of this track. Notes do not need to be sorted, and do not assume they are sorted without sorting them yourself. However, they are usually sorted after loading them with the MIDI loader bundled. | | track_name | string \| null | Name of the track, or null if no name. | | instrument | string \| null | Instrument name. This does not actually impact the instrument, and most of the time you may ignore this field. |

TimeSignature

| Property | Type | Description | | --- | --- | --- | | numerator | number | int, 0-15 inclusive; cannot save if violated or may be % 16 | | denominator_log2 | number | int, 0-15 inclusive; cannot save if violated or may be % 16. A value of 2 means the time signature denominator is 4, because 2^2 == 4. A value of B means the time signature denominator is 2^B. | | clocks_per_click | number | Do not change; int, 0-15 incl; cannot save if violated or may be % 16 | | t32_notes_per_quarter | number | Do not change; int, 0-15 incl; cannot save if violated or may be % 16 | | beat | number | float >= 0; instance dropped if this is violated, when saved |

KeySignature

Key signature changes. Unless explicit, this won't appear.

| Property | Type | Description | | --- | --- | --- | | key | number | int, -8 to 7; cannot save if violated | | minor | boolean | Indicates if the key is minor. | | beat | number | float >= 0; instance dropped if this is violated, when saved |

MidiRep

The primary container for MIDI data.

| Property | Type | Description | | --- | --- | --- | | tracks | Track[] | All tracks in this MIDI. In FL Studio, each MIDI out channel is its own track, and the name you give that thing will be its name. Order is preserved but tracks may be offset because some MIDI processors like adding stuff. | | bpm_changes | TempoChange[] | All tempo changes. If there are no tempo changes, then there will be a TempoChange instance there at beat 0, which signals the song's BPM. This list may not and does not need to be sorted by beat, but on MIDI load, it is | | time_signature_changes | TimeSignature[] | All time signature changes. MIDI files can still be exported even if time signature conventions are violated (e.g. 4/4, then it changes to 3/4 after 2 beats). This list may not and does not need to be sorted by beat, but on MIDI load, it is | | key_signature_changes | KeySignature[] | Most of the time, this is empty. But if a MIDI has key signature changes specified for any reason, they will be here. This list may not and does not need to be sorted by beat, but on MIDI load, it is | | channel_to_instrument_map | ChannelInstMapType | Array has length 16 (indices 0 to 15); Values must be between 0-127 inclusive. Indices correspond to MIDI channel; Values correspond to MIDI instrument number | | ticks_per_beat | number | Do not modify. Typically, 96. Value must be between 0 and 2^16-1 |

Extra Functions

noChords(m: MidiRep): void

Removes all but one note from chords, keeping only the highest pitch. Only applies to notes on the same channel, track, and starting beat.

swingMidi(midiRepresentation: MidiRep, mult: number = 1): void

Adds a swing rhythm to the MIDI in place. Keep mult at 1

unswingMidi(midiRepresentation: MidiRep, mult: number = 1): void

Reverses any swing rhythm on the MIDI in place. Keep mult at 1

tempoIntegrator(m: MidiRep): void

Removes all tempo changes. Forces the tempo to 60 BPM (where 1 beat = 1 second). Adjusts note start times and durations to accommodate the removal of tempo changes.

Notes on Information Kept and Lost

All notes are saved.

Along with note data, we save and can rewrite:

  • Track names
  • Tempo, and tempo changes
  • Key signatures and their changes, if declared
  • Time signatures and their changes

Any other information is dropped.

If there exists two notes a and b such that b starts after a starts, but before a ends, then a's end time will be reduced to b's start time.

Tracks that are unnamed and contain no notes will be dropped. Tempo, time, and key signatures are stored inside tracks, but are stored separately here, so you can expect tracks exclusively containing them to be dropped.

On export, tracks may be offset due to additional tracks being put at the start for tempo, time signature, and key signature declarations.

Midi Specs

  • Keys (pitches) must be between 0 and 127 inclusive
  • Channels must be between 0 and 15 inclusive. There are always 16 channels.
  • Velocity must be between 0 and 127 (but keep it 0 to 100)
  • Instrument IDs must be between 0 and 127 inclusive