66 lines
2.3 KiB
C#
66 lines
2.3 KiB
C#
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; }
|
|
double m_bpm;
|
|
public double BPM { get { return m_bpm; } set { m_bpm = value; } }
|
|
public double BeatLength { get { return 60 / m_bpm; } set { m_bpm = 60 / value; } }
|
|
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);
|
|
}
|
|
}
|
|
public class TimeTimingModel : TimingModel {
|
|
public readonly double InputTimeAccuracy;
|
|
public TimeTimingModel(double offset = 0, double accuracy = 2e-3) : base(offset) {
|
|
if (accuracy <= 0) throw new ArgumentOutOfRangeException("accuracy");
|
|
InputTimeAccuracy = accuracy;
|
|
}
|
|
public void ForwardTo(double t) {
|
|
if (t == Time) return;
|
|
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
|
BeatTime += (t - Time) * BPM / 60;
|
|
int n, d;
|
|
FractionUtils.ToFraction(BeatTime, Math.Min(1, InputTimeAccuracy * BPM / 60), out n, out d);
|
|
FractionalBeatTime = new BeatTime(n, d);
|
|
Time = t;
|
|
}
|
|
public void ForceSnap() {
|
|
var alignedBeat = (int)Math.Round(BeatTime);
|
|
BeatTime = alignedBeat;
|
|
FractionalBeatTime = new BeatTime(alignedBeat, 1);
|
|
}
|
|
}
|
|
}
|