2012-02-16 05:46:03 +01:00
|
|
|
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);
|
|
|
|
}
|
2012-04-14 06:59:48 +02:00
|
|
|
var time = (secondsToGenerate * 1000 * timeWarp) || 0;
|
2012-02-16 05:46:03 +01:00
|
|
|
temporal.push([ midiEvent, time]);
|
|
|
|
midiEvent = getNextEvent();
|
|
|
|
};
|
|
|
|
//
|
|
|
|
if (midiEvent = getNextEvent()) {
|
|
|
|
while(midiEvent) processNext(true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
processEvents();
|
|
|
|
return {
|
|
|
|
"getData": function() {
|
|
|
|
return clone(temporal);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|