diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs
index a890dbde43..3a8b3f67d0 100644
--- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs
+++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs
@@ -195,19 +195,17 @@ namespace osu.Game.Rulesets.Osu.Utils
/// true if hitObject is on a (down-)beat, false otherwise.
public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false)
{
- var timingPoints = beatmap.ControlPointInfo.TimingPoints;
- var currentTimingPoint = timingPoints.LastOrDefault(p => p.Time <= hitObject.StartTime);
+ var timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
- if (currentTimingPoint == null)
- return false;
+ double timeSinceTimingPoint = hitObject.StartTime - timingPoint.Time;
- double timeSinceTimingPoint = hitObject.StartTime - currentTimingPoint.Time;
+ double beatLength = timingPoint.BeatLength;
- double length = downbeatsOnly
- ? currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator
- : currentTimingPoint.BeatLength;
+ if (downbeatsOnly)
+ beatLength *= timingPoint.TimeSignature.Numerator;
- return (timeSinceTimingPoint + 1) % length < 2;
+ // Ensure within 1ms of expected location.
+ return Math.Abs(timeSinceTimingPoint + 1) % beatLength < 2;
}
///