2014-09-09 04:44:19 +00:00
|
|
|
/**
|
|
|
|
* Pass in a MIDI File as the command line argument to this Node.js
|
|
|
|
* script and it will output a js file in the same directory.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* node MidiToScore.js mySong.mid
|
|
|
|
*/
|
|
|
|
|
2014-09-09 04:24:34 +00:00
|
|
|
var midiFileParser = require("midi-file-parser");
|
|
|
|
var fs = require("fs");
|
|
|
|
|
|
|
|
var file = fs.readFileSync(process.argv[2], "binary");
|
|
|
|
|
|
|
|
var midi = midiFileParser(file);
|
|
|
|
|
|
|
|
var output = {};
|
|
|
|
|
|
|
|
var tempo = 120;
|
|
|
|
var ticksPerBeat = midi.header.ticksPerBeat;
|
|
|
|
var timeSignature = [4, 4];
|
|
|
|
var microsecondsPerBeat = 60000000 / tempo;
|
|
|
|
|
|
|
|
//parse the tracks
|
|
|
|
for (var i = 0; i < midi.tracks.length; i++) {
|
|
|
|
var data = midi.tracks[i];
|
|
|
|
var trackName = "track"+i;
|
|
|
|
var trackNotes = [];
|
|
|
|
var currentTime = 0;
|
|
|
|
for (var j = 0; j < data.length; j++) {
|
|
|
|
//meta tag stuff
|
|
|
|
var evnt = data[j];
|
|
|
|
if (evnt.type === "meta"){
|
|
|
|
if (evnt.subtype === "timeSignature"){
|
|
|
|
timeSignature[0] = evnt.numerator;
|
|
|
|
timeSignature[1] = evnt.denominator;
|
|
|
|
} else if (evnt.subtype === "setTempo"){
|
|
|
|
tempo = 60000000 / evnt.microsecondsPerBeat;
|
|
|
|
microsecondsPerBeat = evnt.microsecondsPerBeat;
|
|
|
|
} else if (evnt.subtype === "trackName"){
|
|
|
|
trackName = evnt.text;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (evnt.subtype === "noteOn" || evnt.subtype === "noteOff"){
|
|
|
|
currentTime += evnt.deltaTime;
|
|
|
|
var time = deltaTimeToMeter(currentTime);
|
|
|
|
var note = midiToNote(evnt.noteNumber);
|
|
|
|
var velocity = evnt.velocity / 127;
|
|
|
|
if (evnt.subtype === "noteOff"){
|
|
|
|
velocity = 0;
|
|
|
|
}
|
|
|
|
trackNotes.push([time, note, velocity.toFixed(2)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
output[trackName] = trackNotes;
|
|
|
|
}
|
|
|
|
|
|
|
|
output.tempo = tempo;
|
|
|
|
output.timeSignature = timeSignature;
|
|
|
|
|
|
|
|
//write it to the output file
|
|
|
|
fs.writeFileSync(process.argv[2]+".js", JSON.stringify(output));
|
|
|
|
|
|
|
|
function deltaTimeToMeter(deltaTime){
|
|
|
|
var timeSigValue = timeSignature[0] / (timeSignature[1] / 4);
|
|
|
|
// return deltaTime;
|
|
|
|
var quarters = deltaTime / ticksPerBeat;
|
|
|
|
var measures = Math.floor(quarters / timeSigValue);
|
|
|
|
var sixteenths = (quarters % 1) * 4;
|
|
|
|
quarters = Math.floor(quarters) % timeSigValue;
|
|
|
|
var progress = [measures, quarters, sixteenths];
|
|
|
|
return progress.join(":");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function midiToNote(noteNum){
|
|
|
|
var noteIndexToNote = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
|
|
var octave = Math.floor(noteNum / 12) - 2;
|
|
|
|
var note = noteNum % 12;
|
|
|
|
return noteIndexToNote[note] + octave;
|
|
|
|
}
|