diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
index 5740c961b1..acf90931ac 100644
--- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
+++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The time to find the timing control point at.
/// The timing control point.
- public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time);
+ public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault());
///
/// Finds the maximum BPM represented by any timing control point.
@@ -75,14 +75,21 @@ namespace osu.Game.Beatmaps.ControlPoints
public double BPMMode =>
60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
- private T binarySearch(SortedList list, double time)
+ ///
+ /// Binary searches one of the control point lists to find the active control point at .
+ ///
+ /// The list to search.
+ /// The time to find the control point at.
+ /// The control point to use when is before any control points. If null, a new control point will be constructed.
+ /// The active control point at .
+ private T binarySearch(SortedList list, double time, T prePoint = null)
where T : ControlPoint, new()
{
if (list.Count == 0)
return new T();
if (time < list[0].Time)
- return new T();
+ return prePoint ?? new T();
int index = list.BinarySearch(new T() { Time = time });
@@ -92,8 +99,8 @@ namespace osu.Game.Beatmaps.ControlPoints
index = ~index;
- if (index == list.Count)
- return list[list.Count - 1];
+ // BinarySearch will return the index of the first element _greater_ than the search
+ // This is the inactive point - the active point is the one before it (index - 1)
return list[index - 1];
}
}