Git Product home page Git Product logo

midi-parser-js's Introduction

logo

MidiParser.js

NoDependencies Browser Node

MidiParser is a Javascript Binary MIDI file reader for the browser and Node which converts a MIDI binary data structure to a JSON object, making it much easier to iterate over and interact with.

  • Tiny and dependency free
  • Browser & Node Compatible
  • Supported data input :
    • BASE64 encoded Midi data
    • UINT8 arrayBuffer, obtained when reading or fetching a .mid binary.
    • FileInput Element in the Browser
  • Custom Midi Messages

Example

A simple example parsing a MIDI file in Node ...

let midiParser  = require('midi-parser-js');
let fs = require('fs')

// read a .mid binary (as base64)
fs.readFile('./test.mid', 'base64', function (err,data) {
  // Parse the obtainer base64 string ...
  var midiArray = midiParser.parse(data);
  // done!
  console.log(midiArray);
});

Example in Browser...

<script type="module">
  import MidiParser from 'midi-parser-js'
  // select the INPUT element that will handle
  // the file selection.
  let source = document.getElementById('filereader');
  // provide the File source and a callback function
  MidiParser.parse( source, function(obj){
    console.log(obj);
  });
</script>
<input type="file" id="filereader"/>

If you want to see it in action, you can test it Here

Syntax:

  MidiParser.parse( input [, callback] );

- input : Accepts any of the supported Data Sources : FileInputElement | uint8Array | base64String

- callback : Callback to be executed when data is parsed. Only required when input is a FileInputElement.


Handle Custom messages ( sysEx, non-standard...)

By default, the library ignores the sysEx, and non-standard messages, simply converting their values to integers (when possible). However you can provide a custom hook function to be executed when any non-standard message is found, and process it by your own, returning the resulting value.

MidiParser.customInterpreter = function( msgType, arrayBuffer, metaEventLength){  /* your code */ }

- msgType : Hex value of the message type

- arrayBuffer : Dataview of the midi data. You have to extract your value/s from it, moving the pointer as needed.

- metaEventLength : A length greater than 0 indicates a received message

If you want the default action to be executed, return false

Output JSON anatomy :

The returned JSON object contains all the attributes of the MIDI file (format type, time division, track count... ) as properties. The tracks and the MIDI events related to each track are container inside the track property.

logo

The following JSON object represents a MIDI file with 3 tracks and 4 events in Track 0

outputObject{
....formatType: 0|1|2,  // Midi format type
....timeDivision: (int),  // song tempo (bpm)
....tracks: (int),  // total tracks count
....track: Array[
........[0]: Object{  // TRACK 1!
............event: Array[  // Midi events in track 1
................[0] : Object{  // EVENT 1
....................data: (string),
....................deltaTime: (int),
....................metaType: (int),
....................type: (int)
................},
................[1] : Object{...},  // EVENT 2
................[2] : Object{...}, // EVENT 3
................[3] : Object{...}  // EVENT 4
............]
........},
........[1] : Object{...},  // TRACK 2
........[2] : Object{...}  // TRACK 3
....]
}

If you want to read the data from Event 2 of Track 0 , you should use the following keypath :

outputObject.track[0].event[2].data;

Distribution & Installation :

The following distribution channels are available :

- NPM : Install using the following command :

  $ npm install midi-parser-js -s

- GIT : You can clone the repository :

  $ git clone https://github.com/colxi/midi-parser-js.git

-ZIP : Or download the package in a ZIP file from

GITHUB LATEST PACKAGE RELEASE PAGE

-CDN : Include the latest release of this library in your HTML head using the CDN :

Warning : Not recommended for production enviroments!

<script src="https://colxi.info/midi-parser-js/src/main.js"></script>

Importing

This package is shipped with support to Node CommonJS and ES6 Modules. Use the appropiate method accoordintg to your enviroment.

  // ES6 Module Import : 
  import {MidiParser} from './midi-parser.js'; 

  // CommonJS Node Import :
  let MidiParser = require('midi-parser-js');

Bonus : MIDI File Format Specifications :

MIDI Binary Encoding Specifications in https://github.com/colxi/midi-parser-js/wiki/MIDI-File-Format-Specifications

midi-parser-js's People

Contributors

colxi avatar jdevries3133 avatar micuat avatar nicolaitanes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

midi-parser-js's Issues

Only note-off (9) events

On the parsed track, all the note events are type 9, never type 8. However when I open in a midi sequencer, I see it shouldn't be the case, the notes finish at some point.
See here, we the default example provided by default, from the chrome's console:

{deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2601 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2602 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2603 : {deltaTime: 3, type: 9, channel: 0, data: Array(2)} 2604 : {deltaTime: 36, type: 9, channel: 0, data: Array(2)} 2605 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2606 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2607 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2608 : {deltaTime: 3, type: 9, channel: 0, data: Array(2)} 2609 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2610 : {deltaTime: 11, type: 9, channel: 0, data: Array(2)} 2611 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2612 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2613 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2614 : {deltaTime: 4, type: 9, channel: 0, data: Array(2)} 2615 : {deltaTime: 3, type: 9, channel: 0, data: Array(2)} 2616 : {deltaTime: 33, type: 9, channel: 0, data: Array(2)} 2617 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2618 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2619 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2620 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2621 : {deltaTime: 5, type: 9, channel: 0, data: Array(2)} 2622 : {deltaTime: 3, type: 9, channel: 0, data: Array(2)} 2623 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2624 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2625 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2626 : {deltaTime: 5, type: 9, channel: 0, data: Array(2)} 2627 : {deltaTime: 6, type: 9, channel: 0, data: Array(2)} 2628 : {deltaTime: 4, type: 9, channel: 0, data: Array(2)} 2629 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2630 : {deltaTime: 27, type: 9, channel: 0, data: Array(2)} 2631 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2632 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2633 : {deltaTime: 10, type: 9, channel: 0, data: Array(2)} 2634 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2635 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2636 : {deltaTime: 4, type: 9, channel: 0, data: Array(2)} 2637 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2638 : {deltaTime: 9, type: 9, channel: 0, data: Array(2)} 2639 : {deltaTime: 11, type: 9, channel: 0, data: Array(2)} 2640 : {deltaTime: 12, type: 9, channel: 0, data: Array(2)} 2641 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2642 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2643 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2644 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2645 : {deltaTime: 9, type: 9, channel: 0, data: Array(2)} 2646 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2647 : {deltaTime: 1, type: 9, channel: 0, data: Array(2)} 2648 : {deltaTime: 4, type: 9, channel: 0, data: Array(2)} 2649 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2650 : {deltaTime: 15, type: 9, channel: 0, data: Array(2)} 2651 : {deltaTime: 16, type: 9, channel: 0, data: Array(2)} 2652 : {deltaTime: 5, type: 9, channel: 0, data: Array(2)} 2653 : {deltaTime: 0, type: 9, channel: 0, data: Array(2)} 2654 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2655 : {deltaTime: 2, type: 9, channel: 0, data: Array(2)} 2656 : {deltaTime: 8, type: 9, channel: 0, data: Array(2)} 2657 : {deltaTime: 5, type: 9, channel: 0, data: Array(2)}

default sysex parser correct?

If I understand the sysex message format its lead-in is 0xF0 followed by an arbitrary number of bytes ending in a final 0xF7. Bit 8 may never be set in the payload, which means they have to be less than 128.

Your code simply reads a single byte and then goes on.

Anyway, thanx for the code. I'm into TypeScript, but the project is a great starting point for me.

Not parsing correctly

I have run into bugs with this parser...

I made a simple midi region in LogicPro with notes one tick apart. I export this region as type 0 midi file. When I parse this midi file with midi-parse-js and log the parsed JSON immediately, it is showing incorrect structure in the JSON structure. the notes are being parsed as meta events with -1 deltaTime... I don't know how to attach the midi file to this ticket but if you ask me for it I can send it in email.

{
  "formatType": 0,
  "tracks": 1,
  "track": [
    {
      "event": [
        {
          "deltaTime": 0,
          "type": 255,
          "metaType": 32,
          "data": 0
        },
        {
          "deltaTime": 16259,
          "type": 255,
          "metaType": 6,
          "data": "nst 1\u0000ÿ\u0004\u0006Inst 1\u0000ÿX\u0004\u0004\u0002\u0018\b\u0000ÿY\u0002\u0000\u0000\u0000ÿT\u0005!\u0000\u0000\u0000\u0000\u0000ÿQ\u0003\u0007¡ \u0000�<P\u0000=P\u0000>P\u0000?P\u0000@P\u0000APx�<\u0000\u0000�=\u0000\u0000"
        },
        {
          "deltaTime": 62,
          "type": 255,
          "metaType": 0,
          "data": -1
        },
        {
          "deltaTime": 63,
          "type": 255,
          "metaType": 0,
          "data": -1
        },
        {
          "deltaTime": 64,
          "type": 255,
          "metaType": 0,
          "data": -1
        },
        {
          "deltaTime": 65,
          "type": 255,
          "metaType": 0,
          "data": -1
        },
        {
          "deltaTime": -1
        }
      ]
    }
  ],
  "timeDivision": 480
}

wrong parsing of certain files

hi,

i've found several issues while trying to parse certain midi files for which I have no issue in other midi programs :
issue
As you can see, midi-parser-js says there are 10 tracks, but only show two, and they contain no note...

I have no issue at all when I load it into MidiEditor or music21 :

issue2

I don't know what's causing this

Meta Events 0x04, 0x05, and 0x07 not handled

The text events 0x04 (Instrument Name), 0x05 (Lyrics), and 0x07 (Cue point) are missing from the meta handling routine. This causes them to be parsed as integer values which can lead to incorrect parsing of the next event. The fix is extremely simple; just add them in at line 251-252.

Test file attached. Track 1's second event is meta 0x04 with data "Piano".
LetItGo.zip

typo in MIDI spec

small typo in MIDI spec

74-79 (0x4A-0x4F) | Sound Controller 6-10

Should be 5-10

midi-parser-js in Express

Heyo, just want to quickly ask how I would use this tool in Express or if you hadn't made this available for express.

Readme is not clear on how to import

Hi, thanks for the great tool!

I'm using React and wanted to import it via
import { MidiParser } from 'midi-parser-js';
as the readme says, but it did only work with
import MidiParser from 'midi-parser-js';.

I'm not sure if this is only relevant for React users or also WebPack etc., but it might be worth mentioning this in the readme, as it took me some minutes to figure that out.

Can't add module due to .git repo in release on npm (got workaround)

The Problem

I noticed when executing npm i midi-parser-js I get the following error message:

[wurstbrohd@wurstbrohd midi-converter]$ npm i midi-parser-js
npm ERR! path /home/wurstbrohd/semester-6/fp/fp-project/extra-tools/midi-converter/node_modules/midi-parser-js
npm ERR! code EISGIT
npm ERR! git /home/wurstbrohd/semester-6/fp/fp-project/extra-tools/midi-converter/node_modules/midi-parser-js: Appears to be a git repo or submodule.
npm ERR! git     /home/wurstbrohd/semester-6/fp/fp-project/extra-tools/midi-converter/node_modules/midi-parser-js
npm ERR! git Refusing to remove it. Update manually,
npm ERR! git or move it out of the way first.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/wurstbrohd/.npm/_logs/2019-06-14T16_07_03_825Z-debug.log

With a quick Google search I found this answer, according to which the maintainer has to remove the .git directory from the node module.

Workaround

According to this, after executing npm i midi-parser-js, go to the subdir <project-root>/node_modules/midi-parser-js/ and delete the .git directory. Afterwards - for good measure - execute npm i once again to finish the module installation.

Or simply execute this from your project root directory:

rm -rf node_modules/midi-parser-js/.git && npm i && echo "woop woop"

deltaTime 16384

I have several midis with channels that starts at a certain part of the file, like after 20-30 seconds, but the deltaTime value is always 16384 and makes the channel's notes start early. Is 16384 the maximum?

How can I use this data?

I have installed the package and have it reading a midi file, but I do not know how I can use the data. I am a noob to all things audio related, and am trying to play a song from a midi file. I am wondering, what are midi events? What is the data in them? What part of the data structure is the actual music notes? What is delta time? What s the type in midi events?

Thanks, I hope all my questions can be answered!

parsing JSON to MIDI

Hey,

This looks awesome, but I was wondering if the inverse is also possible... parse this specific JSON object architecture into a MIDI file? It is not clear from reading the readme if this is possible.

Thank you.

Bugs? about uncategorized meta-events

Hello! Thanks for making such a nice module.
There seems to be a bug where lines 263-264 in main.js (commit 310b076 on 11 Mar 2021), which read a file twice as long as metaEventLength.
Among the MIDI files I have, there are files in which an error occurs due to the syntax. I corrected the above and it was solved. I'll send you the MIDI file if you want. Please provide your contact information.

HTMLElement is not defined

Node version: v.16.4.2

Code from example
`let midiParser = require('midi-parser-js');
let fs = require('fs');

// read a .mid binary (as base64)
fs.readFile('./test.mid', 'base64', function (err,data) {
// Parse the obtainer base64 string ...
var midiArray = midiParser.parse(data);
// done!
console.log(midiArray);
});
`

Error:
`midi-parser-js/src/main.js:67
else if(input instanceof HTMLElement && input.type === 'file') return MidiParser.addListener(input , _callback);
^

ReferenceError: HTMLElement is not defined
`

Is it an error or will I need additional packages to make this work in nodejs?

Does not parse Uint8Array or base64.

My code:

  console.log(dataArray);
  MidiParser.parse(dataArray, function(obj){
    console.log(obj);
  });

Console output:

Uint8Array(2358) [ 77, 84, 104, 100, 0, 0, 0, 6, 0, 1, … ]

There is no callback from MidiParser.parse.

Likewise, there's no callback if a base64 string is provided.

However, if a file input is provided, then it works fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.