using Cryville.Common.Math; using System; namespace Cryville.Crtr.Extensions { public abstract class TimingModel { public double Time { get; protected set; } public double BeatTime { get; protected set; } public BeatTime FractionalBeatTime { get; protected set; } public double BPM { get; set; } public TimingModel(double offset) { Time = offset; FractionalBeatTime = new BeatTime(0, 0, 1); } } public class FractionalBeatTimeTimingModel : TimingModel { public FractionalBeatTimeTimingModel(double offset = 0) : base(offset) { } public void ForwardTo(BeatTime t) { if (t == FractionalBeatTime) return; if (BPM == 0) throw new InvalidOperationException("BPM not determined"); FractionalBeatTime = t; var nt = t.Decimal; Time += (nt - BeatTime) / BPM * 60; BeatTime = nt; } } public class BeatTimeTimingModel : TimingModel { public BeatTimeTimingModel(double offset = 0) : base(offset) { } public void ForwardTo(double t) { if (t == BeatTime) return; if (BPM == 0) throw new InvalidOperationException("BPM not determined"); Time += (t - BeatTime) / BPM * 60; BeatTime = t; FractionalBeatTime = ToBeatTime(t); } static BeatTime ToBeatTime(double beat, double error = 1e-4) { int i, n, d; FractionUtils.ToFraction(beat, error, out n, out d); i = n / d; n %= d; return new BeatTime(i, n, d); } } }