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

@jbfullstack/score-parser

v1.0.1

Published

Parse MIDI and Guitar Pro files into a clean, format-neutral JSON structure. Handles transposing instruments (saxophone, clarinet, trumpet) correctly.

Readme

score-parser

Parse MIDI and Guitar Pro files into a clean, format-neutral JSON structure.

Handles transposing instruments correctly (saxophone, clarinet, trumpet) — written pitch is automatically converted to concert pitch based on the MIDI program number.

Install

npm install score-parser @tonejs/midi @coderline/alphatab

@tonejs/midi and @coderline/alphatab are peer dependencies — install them once even if you use multiple packages that depend on them.

Quick start

import { parseFile } from "score-parser";
import { readFile } from "node:fs/promises";

const buf = await readFile("song.gp5");
const score = await parseFile(buf, { ext: "gp5" });

const saxTrack = score.tracks.find(t => t.isSaxophone);
console.log(`${saxTrack?.notes.length} notes at concert pitch`);

// First note
const note = saxTrack?.notes[0];
console.log(`MIDI ${note?.pitchMidi}, tick ${note?.startTick}, dur ${note?.durationTicks}`);

Why this exists

Most JavaScript music parsing libraries either:

  • Ignore transposing instruments (a written Bb on an alto sax is an actual concert Db)
  • Expose format-specific APIs that make it hard to switch between MIDI and Guitar Pro
  • Don't handle Guitar Pro repeat signs, tuplets, or tied notes correctly

score-parser gives you a single ParsedScore object regardless of input format, with all pitches in concert pitch (MIDI note numbers, middle C = 60).

Supported formats

| Format | Extension | Underlying lib | Known limitations | |--------|-----------|----------------|-------------------| | MIDI | .mid .midi | @tonejs/midi | Key signatures not extracted; multi-channel tracks use first channel | | Guitar Pro | .gp .gp3 .gp4 .gp5 .gpx | @coderline/alphatab | Volta brackets (1st/2nd ending) not expanded |

API Reference

parseFile(buffer, options?)

Unified dispatcher — recommended entry point.

const score = await parseFile(buffer, {
  ext: "gp5",             // file extension (required unless magic bytes are detectable)
  expandRepeats: true,    // unfold ||: :|| repeat signs (GP only, default: true)
});

parseMidi(buffer, options?)

Parse a MIDI file directly.

const score = parseMidi(buffer, {
  ppqOverride: 480,   // force PPQ value (optional)
});

parseGuitarPro(buffer, options?)

Parse a Guitar Pro file directly.

const score = await parseGuitarPro(buffer, {
  expandRepeats: true,
});

listTracksFromBuffer(buffer, ext)

Preview track names and note counts without a full parse — useful for a track-selection UI.

const result = await listTracksFromBuffer(buffer, "gp5");
// { title, artist, format, tracks: TrackInfo[] }
for (const t of result.tracks) {
  console.log(`[${t.index}] ${t.name} — ${t.instrumentLabel} — ${t.noteCount} notes`);
}

scoreToMusicXML(score, trackIndex?)

Export a track to MusicXML v4.0 (Sibelius, Finale, MuseScore, Dorico compatible).

const xml = scoreToMusicXML(score, 0);
await writeFile("output.xml", xml);

scoreToABC(score, trackIndex?)

Export a track to ABC Notation v2.1.

const abc = scoreToABC(score, 0);

ParsedScore format

{
  "title": "My Song",
  "artist": "Artist",
  "composer": "Composer",
  "ppq": 480,                        // ticks per quarter note
  "sourceFormat": "gpx",             // "midi" | "gpx" | "gp"
  "tempos": [{ "tick": 0, "bpm": 120 }],
  "timeSigs": [{ "tick": 0, "numerator": 4, "denominator": 4 }],
  "keySigs": [{ "tick": 0, "fifths": 0, "mode": "major" }],  // fifths: -7..+7
  "tracks": [{
    "id": 0,
    "name": "Alto Sax",
    "midiProgram": 65,               // GM program (65 = Alto Sax)
    "midiChannel": 0,
    "isSaxophone": true,             // auto-detected
    "notes": [{
      "pitchMidi": 65,               // concert pitch, MIDI note number
      "startTick": 0,
      "durationTicks": 480,          // 480 = quarter note at PPQ 480
      "velocity": 80,                // 0–127
      "isRest": false,
      "annotations": ["bend"]        // optional: guitar effects (informational only)
    }]
  }]
}

Transposing instruments

All pitches are stored at concert pitch (the actual sounding pitch). The conversion from written pitch (as printed in the score) to concert pitch is applied automatically based on the MIDI program number.

| Instrument | GM Program | Transposition (written → concert) | |------------|------------|----------------------------------| | Soprano Sax | 64 | −2 semitones (Bb instrument) | | Alto Sax | 65 | −9 semitones (Eb instrument) | | Tenor Sax | 66 | −14 semitones (Bb, lower octave) | | Baritone Sax | 67 | −21 semitones (Eb, lower octave) | | Bb Clarinet | 71 | −2 semitones | | Bb Trumpet | 56 | −2 semitones |

MIDI files are assumed to already be at concert pitch (no transposition applied).

CLI

# List tracks
npx score-parser song.gp5 --list-tracks

# Export specific track to MusicXML
npx score-parser song.gp5 --track 2 --format musicxml --out song.xml

# Pipe JSON to jq
npx score-parser song.mid --format json | jq '.tracks[0].notes | length'

# Disable repeat expansion
npx score-parser song.gp5 --no-expand-repeats --format json

Limitations

  • Volta brackets (1st/2nd endings): not expanded — only the first pass is parsed.
  • Multi-channel MIDI tracks: only the first channel is used.
  • Guitar ornaments (bend, vibrato, hammer-on, etc.): stored as annotations[] on the note but not sonically modeled.
  • Grace notes: duration is approximated as a 32nd note.

License

MIT

CI npm license