Fix inaccurate beat snapping for osu charts. Fix osu charts with too low BPM not able to be imported.
This commit is contained in:
@@ -12,12 +12,12 @@ namespace Cryville.Common.Math {
|
|||||||
/// <param name="error">The error.</param>
|
/// <param name="error">The error.</param>
|
||||||
/// <param name="n">The numerator.</param>
|
/// <param name="n">The numerator.</param>
|
||||||
/// <param name="d">The denominator.</param>
|
/// <param name="d">The denominator.</param>
|
||||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="value" /> is less than 0 or <paramref name="error" /> is not greater than 0 or not less than 1.</exception>
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="value" /> is less than 0 or <paramref name="error" /> is not greater than 0 or greater than 1.</exception>
|
||||||
public static void ToFraction(double value, double error, out int n, out int d) {
|
public static void ToFraction(double value, double error, out int n, out int d) {
|
||||||
if (value < 0.0)
|
if (value < 0.0)
|
||||||
throw new ArgumentOutOfRangeException("value", "Must be >= 0.");
|
throw new ArgumentOutOfRangeException("value", "Must be >= 0.");
|
||||||
if (error <= 0.0 || error >= 1.0)
|
if (error <= 0.0 || error > 1.0)
|
||||||
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
|
throw new ArgumentOutOfRangeException("error", "Must be > 0 and <= 1.");
|
||||||
|
|
||||||
int num = (int)System.Math.Floor(value);
|
int num = (int)System.Math.Floor(value);
|
||||||
value -= num;
|
value -= num;
|
||||||
|
@@ -42,15 +42,24 @@ namespace Cryville.Crtr.Extensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class TimeTimingModel : TimingModel {
|
public class TimeTimingModel : TimingModel {
|
||||||
public TimeTimingModel(double offset = 0) : base(offset) { }
|
public readonly double InputTimeAccuracy;
|
||||||
|
public TimeTimingModel(double accuracy = 2e-3, double offset = 0) : base(offset) {
|
||||||
|
if (accuracy <= 0) throw new ArgumentOutOfRangeException("accuracy");
|
||||||
|
InputTimeAccuracy = accuracy;
|
||||||
|
}
|
||||||
public void ForwardTo(double t) {
|
public void ForwardTo(double t) {
|
||||||
if (t == Time) return;
|
if (t == Time) return;
|
||||||
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
||||||
BeatTime += (t - Time) * BPM / 60;
|
BeatTime += (t - Time) * BPM / 60;
|
||||||
int n, d;
|
int n, d;
|
||||||
FractionUtils.ToFraction(BeatTime, 1f / 48 / BPM * 60, out n, out d);
|
FractionUtils.ToFraction(BeatTime, Math.Min(1, InputTimeAccuracy * BPM / 60), out n, out d);
|
||||||
FractionalBeatTime = new BeatTime(n, d);
|
FractionalBeatTime = new BeatTime(n, d);
|
||||||
Time = t;
|
Time = t;
|
||||||
}
|
}
|
||||||
|
public void ForceSnap() {
|
||||||
|
var alignedBeat = (int)Math.Round(BeatTime);
|
||||||
|
BeatTime = alignedBeat;
|
||||||
|
FractionalBeatTime = new BeatTime(alignedBeat, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -108,10 +108,11 @@ namespace Cryville.Crtr.Extensions.osu {
|
|||||||
else if (ev is osuEvent.TimingChange) {
|
else if (ev is osuEvent.TimingChange) {
|
||||||
var tev = (osuEvent.TimingChange)ev;
|
var tev = (osuEvent.TimingChange)ev;
|
||||||
if (tm == null) {
|
if (tm == null) {
|
||||||
tm = new TimeTimingModel(tev.StartTime / 1e3);
|
tm = new TimeTimingModel(tev.StartTime / 1e3) { InputTimeAccuracy = 2e-3 };
|
||||||
bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET);
|
bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET);
|
||||||
}
|
}
|
||||||
tm.BeatLength = tev.BeatLength / 1e3;
|
tm.BeatLength = tev.BeatLength / 1e3;
|
||||||
|
tm.ForceSnap();
|
||||||
chart.sigs.Add(new Chart.Signature {
|
chart.sigs.Add(new Chart.Signature {
|
||||||
time = tm.FractionalBeatTime,
|
time = tm.FractionalBeatTime,
|
||||||
tempo = (float)tm.BPM,
|
tempo = (float)tm.BPM,
|
||||||
|
Reference in New Issue
Block a user