package org.open2jam.game; import java.util.Arrays; import java.util.LinkedList; import java.util.List; /** * This class stores the timing data, replaces the velocity tree. * It is also able to calculate elapsed beat from the elapsed time. * @author Thai Pangsakulyanont */ public class TimingData { public static class VelocityChange { private double time; private double bpm; private double beat; public VelocityChange(double time, double bpm) { this.time = time; this.bpm = bpm; } public double getBeat() { return beat; } public void setBeat(double beat) { this.beat = beat; } public double getBpm() { return bpm; } public double getTime() { return time; } public double calculateBeat(double target) { return beat + (target - time) * bpm / 60000; } } List<VelocityChange> buffer = new LinkedList<VelocityChange>(); VelocityChange[] changes; public void add(double time, double bpm) { buffer.add(new VelocityChange(time, bpm)); } public void finish() { changes = buffer.toArray(new VelocityChange[buffer.size()]); changes[0].beat = 0; for (int i = 1; i < changes.length; i ++) { changes[i].setBeat(changes[i - 1].calculateBeat(changes[i].getTime())); } } public double getBeat(double time) { int min = 0, max = changes.length - 1; int left = min, right = max; while (left <= right) { int mid = (left + right) / 2; boolean afterMid = mid < 0 || changes[mid].getTime() <= time; boolean beforeNext = mid + 1 >= changes.length || time < changes[mid + 1].getTime(); if (afterMid && beforeNext) { return changes[mid].calculateBeat(time); } else if (afterMid) { left = mid + 1; } else { right = mid - 1; } } return changes[0].calculateBeat(time); } }