1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-16 05:52:55 +08:00

Merge branch 'editor-clock-cache' into editor-clock-transform

This commit is contained in:
Dean Herbert 2020-05-22 19:51:02 +09:00
commit 1486a44b55
7 changed files with 100 additions and 16 deletions

View File

@ -0,0 +1,73 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Tests.NonVisual
{
public class BarLineGeneratorTest
{
[Test]
public void TestRoundingErrorCompensation()
{
// The aim of this test is to make sure bar line generation compensates for floating-point errors.
// The premise of the test is that we have a single timing point that should result in bar lines
// that start at a time point that is a whole number every seventh beat.
// The fact it's every seventh beat is important - it's a number indivisible by 2, which makes
// it susceptible to rounding inaccuracies. In fact this was originally spotted in cases of maps
// that met exactly this criteria.
const int beat_length_numerator = 2000;
const int beat_length_denominator = 7;
const TimeSignatures signature = TimeSignatures.SimpleQuadruple;
var beatmap = new Beatmap
{
HitObjects = new List<HitObject>
{
new HitObject { StartTime = 0 },
new HitObject { StartTime = 120_000 }
},
ControlPointInfo = new ControlPointInfo()
};
beatmap.ControlPointInfo.Add(0, new TimingControlPoint
{
BeatLength = (double)beat_length_numerator / beat_length_denominator,
TimeSignature = signature
});
var barLines = new BarLineGenerator<BarLine>(beatmap).BarLines;
for (int i = 0; i * beat_length_denominator < barLines.Count; i++)
{
var barLine = barLines[i * beat_length_denominator];
var expectedTime = beat_length_numerator * (int)signature * i;
// every seventh bar's start time should be at least greater than the whole number we expect.
// It cannot be less, as that can affect overlapping scroll algorithms
// (the previous timing point might be chosen incorrectly if this is not the case)
Assert.GreaterOrEqual(barLine.StartTime, expectedTime);
// on the other side, make sure we don't stray too far from the expected time either.
Assert.IsTrue(Precision.AlmostEquals(barLine.StartTime, expectedTime));
// check major/minor lines for good measure too
Assert.AreEqual(i % (int)signature == 0, barLine.Major);
}
}
private class BarLine : IBarLine
{
public double StartTime { get; set; }
public bool Major { get; set; }
}
}
}

View File

@ -4,8 +4,8 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components;
using osuTK; using osuTK;
@ -17,9 +17,8 @@ namespace osu.Game.Tests.Visual.Editing
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var clock = new EditorClock { IsCoupled = false };
Dependencies.CacheAs<IAdjustableClock>(clock); Dependencies.CacheAs(clock);
Dependencies.CacheAs<IFrameBasedClock>(clock);
var playback = new PlaybackControl var playback = new PlaybackControl
{ {

View File

@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.Editing
private IBindable<WorkingBeatmap> beatmap { get; set; } private IBindable<WorkingBeatmap> beatmap { get; set; }
[Resolved] [Resolved]
private EditorClock adjustableClock { get; set; } private EditorClock editorClock { get; set; }
public AudioVisualiser() public AudioVisualiser()
{ {
@ -95,13 +95,15 @@ namespace osu.Game.Tests.Visual.Editing
base.Update(); base.Update();
if (beatmap.Value.Track.IsLoaded) if (beatmap.Value.Track.IsLoaded)
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); marker.X = (float)(editorClock.CurrentTime / beatmap.Value.Track.Length);
} }
} }
private class StartStopButton : OsuButton private class StartStopButton : OsuButton
{ {
private EditorClock editorClock; [Resolved]
private EditorClock editorClock { get; set; }
private bool started; private bool started;
public StartStopButton() public StartStopButton()
@ -113,12 +115,6 @@ namespace osu.Game.Tests.Visual.Editing
Action = onClick; Action = onClick;
} }
[BackgroundDependencyLoader]
private void load(EditorClock editorClock)
{
this.editorClock = editorClock;
}
private void onClick() private void onClick()
{ {
if (started) if (started)

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Utils; using osu.Framework.Utils;
@ -46,6 +47,16 @@ namespace osu.Game.Rulesets.Objects
for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++) for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++)
{ {
var roundedTime = Math.Round(t, MidpointRounding.AwayFromZero);
// in the case of some bar lengths, rounding errors can cause t to be slightly less than
// the expected whole number value due to floating point inaccuracies.
// if this is the case, apply rounding.
if (Precision.AlmostEquals(t, roundedTime))
{
t = roundedTime;
}
BarLines.Add(new TBarLine BarLines.Add(new TBarLine
{ {
StartTime = t, StartTime = t,

View File

@ -40,6 +40,11 @@ namespace osu.Game.Screens.Edit
underlyingClock = new DecoupleableInterpolatingFramedClock(); underlyingClock = new DecoupleableInterpolatingFramedClock();
} }
public EditorClock()
: this(new ControlPointInfo(), 1000, new BindableBeatDivisor())
{
}
/// <summary> /// <summary>
/// Seek to the closest snappable beat from a time. /// Seek to the closest snappable beat from a time.
/// </summary> /// </summary>

View File

@ -7,7 +7,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -62,7 +61,7 @@ namespace osu.Game.Screens.Edit.Timing
private IBindableList<ControlPointGroup> controlGroups; private IBindableList<ControlPointGroup> controlGroups;
[Resolved] [Resolved]
private IFrameBasedClock clock { get; set; } private EditorClock clock { get; set; }
[Resolved] [Resolved]
protected IBindable<WorkingBeatmap> Beatmap { get; private set; } protected IBindable<WorkingBeatmap> Beatmap { get; private set; }

View File

@ -8,6 +8,7 @@ using osu.Framework.Timing;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
@ -32,7 +33,7 @@ namespace osu.Game.Tests.Visual
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IAdjustableClock>(new StopwatchClock()); dependencies.CacheAs(new EditorClock());
return dependencies; return dependencies;
} }