MidiConvert
This is a fork of Tonejs/MidiConvert. The fork has diverged since by including directly the parser of NHQ/midi-file-parser and adding the following features:
- Generate MIDI file by including functions from dingram/jsmidgen
- Output sustain pedal events
- Output instruments used in tracks
- Splitting tracks by MIDI Channel of MIDI Type 0 file
The toolchain is also different:
- Bundling with Rollup
- Minification with Clojure compiler
- Code linting with ESLint
- Continuous integration with Travis CI
Read more about the changes in the CHANGELOG.md.
Usage
This library can be installed via NPM:
npm i --save @pioug/MidiConvert
In HTML:
<script src="build/MidiConvert.js"></script>
Or in JavaScript:
var MidiConvert = require('@pioug/MidiConvert');
API
MidiConvert.parse(BinaryString midiBlob, [Object options]) => Object
This function returns an object with two properties:
-
transport
: the bpm and time signature values of the midi file as a Javascript Object (formerlyparseTransport
) -
parts
: an array of the tracks. Each track is an array of notes (formerlyparseParts
)
var midiObject = MidiConvert.parse(midiBlob, options);
{
transport: {
bpm: 120,
instruments: [1, 25, 0],
timeSignature: [4, 4],
trackNames: ["Solo piano", "Guitar riff", "Kick-ass drums"]
},
parts: [
[
{
time: "0i",
midiNote: 67,
noteName: "G4",
velocity: 0.7086614173228346,
duration: "12i"
},
... rest of events
],
... rest of tracks
]
}
Which can then be used in Tone.Part:
var pianoPart = new Tone.Part(callback, midiObject.parts[0]).start();
Options
The options object defines how the MIDI file is parsed:
MidiConvert.parse(midiBlob, {
/*
* the pulses per quarter note at which
* the midi file is parsed.
*/
PPQ : 192,
/*
* if the notes scientific pitch notation
* should be included in the output.
*/
noteName : true,
/*
* if the normalized velocity should be included
* in the output
*/
velocity : true,
/*
* if the time between the noteOn and noteOff event
* should be included in the output. Otherwise
* each event represents a noteOn.
*/
duration : true,
/*
* execute an additional sorting function
* useful for testing
*/
deterministic: true
});
MidiConvert.generate(midiJson) => Buffer
Generate a file buffer from an object respecting the structure of the parse
output.
var sourceFile = fs.readFileSync('./midi/bwv-846.mid', 'binary'),
sourceData = MidiConvert.parse(sourceFile, midiConvertOpts),
destinationData = MidiConvert.parse(MidiConvert.generate(sourceData), midiConvertOpts);
t.deepEqual(sourceData, destinationData) // TRUE;
MidiConvert.File
Class -
addTrack()
- Add a new Track object to the file and return the new track -
addTrack(track)
- Add the given Track object to the file and return the file -
toBytes()
- Convert to buffer
MidiConvert.Track
Class Time and duration are specified in "ticks", and there is a hardcoded value of 128 ticks per beat. This means that a quarter note has a duration of 128.
Pitch can be specified by note name with octave (a#4
) or by note number (60
).
Middle C is represented as c4
or 60
.
-
addNote(channel, pitch, duration[, time[, velocity]])
- Add a new note with the given channel, pitch, and duration
- If
time
is given, delay that many ticks before starting the note - If
velocity
is given, strike the note with that velocity
-
addNoteOn(channel, pitch[, time[, velocity]])
-Start a new note with the given channel and pitch- If
time
is given, delay that many ticks before starting the note - If
velocity
is given, strike the note with that velocity
- If
-
addNoteOff(channel, pitch[, time[, velocity]])
- End a note with the given channel and pitch
- If
time
is given, delay that many ticks before ending the note - If
velocity
is given, strike the note with that velocity
-
addChord(channel, chord[, velocity])
- Add a chord with the given channel and pitches
- Accepts an array of pitches to play as a chord
- If
velocity
is given, strike the chord with that velocity
-
setInstrument(channel, instrument[, time])
- Change the given channel to the given instrument
- If
time
is given, delay that many ticks before making the change
-
setTempo(bpm[, time])
- Set the tempo to
bpm
beats per minute - If
time
is given, delay that many ticks before making the change
- Set the tempo to
-
setTimeSignature(numerator, denominator[, time])
- Set the time signature with the given numerator and denominator
- If
time
is given, delay that many ticks before making the change
-
setTrackName(name[, time])
- Set the track name with the given string
- If
time
is given, delay that many ticks before making the change
var fs = require('fs');
var MidiConvert = require('@pioug/MidiConvert');
var file = new MidiConvert.MidiGen.File();
var track = new MidiConvert.MidiGen.Track();
file.addTrack(track);
track.addNote(0, 'C4', 64);
track.addNote(0, 'D4', 64);
track.addNote(0, 'E4', 64);
track.addNote(0, 'F4', 64);
track.addNote(0, 'G4', 64);
track.addNote(0, 'A4', 64);
track.addNote(0, 'B4', 64);
track.addNote(0, 'B5', 64);
fs.writeFileSync('test.mid', file.toBytes(), 'binary');
MIDI Blob
In Node.js, pass to MidiConvert the output from fs.readFile
:
fs.readFile('./test.mid', 'binary', function(err, buffer) {
if (err) return;
var midiObject = MidiConvert.parse(buffer);
});
In the browser, the MIDI blob as a string can be obtained using the FileReader API.
var reader = new FileReader();
reader.onload = function(e) {
var midiObject = MidiConvert.parse(e.target.result);
}
reader.readAsBinaryString(file);
Development
If you want to contribute to this project:
git clone git@github.com:pioug/MidiConvert.git
npm i
npm run build
npm test