summaryrefslogtreecommitdiffstats
path: root/Processing-js/libs/inc/jasmid/replayer.js
diff options
context:
space:
mode:
Diffstat (limited to 'Processing-js/libs/inc/jasmid/replayer.js')
-rw-r--r--Processing-js/libs/inc/jasmid/replayer.js96
1 files changed, 96 insertions, 0 deletions
diff --git a/Processing-js/libs/inc/jasmid/replayer.js b/Processing-js/libs/inc/jasmid/replayer.js
new file mode 100644
index 0000000..347fa1d
--- /dev/null
+++ b/Processing-js/libs/inc/jasmid/replayer.js
@@ -0,0 +1,96 @@
+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
+ )
+ };
+ }
+
+ var nextEventInfo;
+ var samplesToNextEvent = 0;
+
+ 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.event.type == "meta" && midiEvent.event.subtype == "setTempo" ) {
+ // tempo change events can occur anywhere in the middle and affect events that follow
+ beatsPerMinute = 60000000 / midiEvent.event.microsecondsPerBeat;
+ }
+ 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);
+ }
+ };
+};