MIDI.js/inc/jasmid/replayer.js
2012-10-09 22:59:04 -07:00

81 lines
2.3 KiB
JavaScript

var clone = function (o) {
if (typeof o != 'object') return (o);
if (o == null) return (o);
var ret = (typeof o.length == 'number') ? [] : {};
for (var key in o) ret[key] = clone(o[key]);
return ret;
};
function Replayer(midiFile, timeWarp, eventProcessor) {
var trackStates = [];
var beatsPerMinute = 120;
var ticksPerBeat = midiFile.header.ticksPerBeat;
for (var i = 0; i < midiFile.tracks.length; i++) {
trackStates[i] = {
"nextEventIndex": 0,
"ticksToNextEvent": (
midiFile.tracks[i].length ? midiFile.tracks[i][0].deltaTime : null
)
};
}
function getNextEvent() {
var ticksToNextEvent = null;
var nextEventTrack = null;
var nextEventIndex = null;
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null && (ticksToNextEvent == null || trackStates[i].ticksToNextEvent < ticksToNextEvent)) {
ticksToNextEvent = trackStates[i].ticksToNextEvent;
nextEventTrack = i;
nextEventIndex = trackStates[i].nextEventIndex;
}
}
if (nextEventTrack != null) {
/// consume event from that track
var nextEvent = midiFile.tracks[nextEventTrack][nextEventIndex];
if (midiFile.tracks[nextEventTrack][nextEventIndex + 1]) {
trackStates[nextEventTrack].ticksToNextEvent += midiFile.tracks[nextEventTrack][nextEventIndex + 1].deltaTime;
} else {
trackStates[nextEventTrack].ticksToNextEvent = null;
}
trackStates[nextEventTrack].nextEventIndex += 1;
/// advance timings on all tracks by ticksToNextEvent
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null) {
trackStates[i].ticksToNextEvent -= ticksToNextEvent
}
}
return {
"ticksToEvent": ticksToNextEvent,
"event": nextEvent,
"track": nextEventTrack
}
} else {
return null;
}
};
//
var midiEvent;
var temporal = [];
//
function processEvents() {
function processNext() {
if (midiEvent.ticksToEvent > 0) {
var beatsToGenerate = midiEvent.ticksToEvent / ticksPerBeat;
var secondsToGenerate = beatsToGenerate / (beatsPerMinute / 60);
}
var time = (secondsToGenerate * 1000 * timeWarp) || 0;
temporal.push([ midiEvent, time]);
midiEvent = getNextEvent();
};
//
if (midiEvent = getNextEvent()) {
while(midiEvent) processNext(true);
}
};
processEvents();
return {
"getData": function() {
return clone(temporal);
}
};
};