From 1851bd3c54de7d2d0240adbabfc8a947d6a5907b Mon Sep 17 00:00:00 2001 From: PopSlime Date: Sun, 5 Mar 2023 20:40:02 +0800 Subject: [PATCH] Fix inaccurate beat snapping for osu charts. Fix osu charts with too low BPM not able to be imported. --- Assets/Cryville/Common/Math/FractionUtils.cs | 6 +++--- Assets/Cryville/Crtr/Extensions/TimingModel.cs | 13 +++++++++++-- .../Crtr/Extensions/osu/osuChartConverter.cs | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Assets/Cryville/Common/Math/FractionUtils.cs b/Assets/Cryville/Common/Math/FractionUtils.cs index b5b8e20..4c1d868 100644 --- a/Assets/Cryville/Common/Math/FractionUtils.cs +++ b/Assets/Cryville/Common/Math/FractionUtils.cs @@ -12,12 +12,12 @@ namespace Cryville.Common.Math { /// The error. /// The numerator. /// The denominator. - /// is less than 0 or is not greater than 0 or not less than 1. + /// is less than 0 or is not greater than 0 or greater than 1. public static void ToFraction(double value, double error, out int n, out int d) { if (value < 0.0) throw new ArgumentOutOfRangeException("value", "Must be >= 0."); - if (error <= 0.0 || error >= 1.0) - throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1."); + if (error <= 0.0 || error > 1.0) + throw new ArgumentOutOfRangeException("error", "Must be > 0 and <= 1."); int num = (int)System.Math.Floor(value); value -= num; diff --git a/Assets/Cryville/Crtr/Extensions/TimingModel.cs b/Assets/Cryville/Crtr/Extensions/TimingModel.cs index 8081109..bb6b8f5 100644 --- a/Assets/Cryville/Crtr/Extensions/TimingModel.cs +++ b/Assets/Cryville/Crtr/Extensions/TimingModel.cs @@ -42,15 +42,24 @@ namespace Cryville.Crtr.Extensions { } } 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) { if (t == Time) return; if (BPM == 0) throw new InvalidOperationException("BPM not determined"); BeatTime += (t - Time) * BPM / 60; 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); Time = t; } + public void ForceSnap() { + var alignedBeat = (int)Math.Round(BeatTime); + BeatTime = alignedBeat; + FractionalBeatTime = new BeatTime(alignedBeat, 1); + } } } diff --git a/Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs b/Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs index c77c860..0f3b929 100644 --- a/Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs +++ b/Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs @@ -108,10 +108,11 @@ namespace Cryville.Crtr.Extensions.osu { else if (ev is osuEvent.TimingChange) { var tev = (osuEvent.TimingChange)ev; 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); } tm.BeatLength = tev.BeatLength / 1e3; + tm.ForceSnap(); chart.sigs.Add(new Chart.Signature { time = tm.FractionalBeatTime, tempo = (float)tm.BPM,