1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 17:32:54 +08:00

Merge pull request #4873 from peppy/audio-refactor-update

Update osu! in line with audio subsystem refactor
This commit is contained in:
Dan Balasescu 2019-06-04 12:18:58 +09:00 committed by GitHub
commit 76474987ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 400 additions and 389 deletions

View File

@ -20,14 +20,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
} }
protected override IBeatmap CreateBeatmap(Ruleset ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo
{ {
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 }, BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
Ruleset = ruleset.RulesetInfo Ruleset = ruleset
} }
}; };

View File

@ -29,14 +29,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
} }
protected override IBeatmap CreateBeatmap(Ruleset ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo
{ {
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 }, BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
Ruleset = ruleset.RulesetInfo Ruleset = ruleset
} }
}; };

View File

@ -16,14 +16,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
} }
protected override IBeatmap CreateBeatmap(Ruleset ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo
{ {
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 }, BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
Ruleset = ruleset.RulesetInfo Ruleset = ruleset
} }
}; };

View File

@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Catch.Tests
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash); AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
} }
protected override IBeatmap CreateBeatmap(Ruleset ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = BeatmapInfo =
{ {
Ruleset = ruleset.RulesetInfo, Ruleset = ruleset,
BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f } BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f }
} }
}; };

View File

@ -17,14 +17,14 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
} }
protected override IBeatmap CreateBeatmap(Ruleset ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo
{ {
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 }, BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
Ruleset = ruleset.RulesetInfo Ruleset = ruleset
} }
}; };

View File

@ -20,7 +20,6 @@ using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK; using osuTK;
@ -299,7 +298,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
AddStep("load player", () => AddStep("load player", () =>
{ {
Beatmap.Value = new TestWorkingBeatmap(new Beatmap<OsuHitObject> Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
{ {
HitObjects = HitObjects =
{ {
@ -323,7 +322,7 @@ namespace osu.Game.Rulesets.Osu.Tests
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 }, BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
Ruleset = new OsuRuleset().RulesetInfo Ruleset = new OsuRuleset().RulesetInfo
}, },
}, Clock); });
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } }); var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });

View File

@ -18,7 +18,6 @@ using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK; using osuTK;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -64,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
var controlPointInfo = new ControlPointInfo(); var controlPointInfo = new ControlPointInfo();
controlPointInfo.TimingPoints.Add(new TimingControlPoint()); controlPointInfo.TimingPoints.Add(new TimingControlPoint());
WorkingBeatmap beatmap = new TestWorkingBeatmap(new Beatmap WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> { new CentreHit() }, HitObjects = new List<HitObject> { new CentreHit() },
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo
@ -79,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Ruleset = new TaikoRuleset().RulesetInfo Ruleset = new TaikoRuleset().RulesetInfo
}, },
ControlPointInfo = controlPointInfo ControlPointInfo = controlPointInfo
}, Clock); });
Add(playfieldContainer = new Container Add(playfieldContainer = new Container
{ {

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -54,7 +55,7 @@ namespace osu.Game.Tests.Visual.Background
private RulesetStore rulesets; private RulesetStore rulesets;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(GameHost host) private void load(GameHost host, AudioManager audio)
{ {
factory = new DatabaseContextFactory(LocalStorage); factory = new DatabaseContextFactory(LocalStorage);
factory.ResetDatabase(); factory.ResetDatabase();
@ -68,7 +69,7 @@ namespace osu.Game.Tests.Visual.Background
usage.Migrate(); usage.Migrate();
Dependencies.Cache(rulesets = new RulesetStore(factory)); Dependencies.Cache(rulesets = new RulesetStore(factory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, audio, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage)); Dependencies.Cache(new OsuConfigManager(LocalStorage));
manager.Import(TestResources.GetTestBeatmapForImport()); manager.Import(TestResources.GetTestBeatmapForImport());

View File

@ -111,16 +111,19 @@ namespace osu.Game.Tests.Visual.Components
private class TestPreviewTrackManager : PreviewTrackManager private class TestPreviewTrackManager : PreviewTrackManager
{ {
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TestPreviewTrack(beatmapSetInfo, trackManager); protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
protected class TestPreviewTrack : TrackManagerPreviewTrack protected class TestPreviewTrack : TrackManagerPreviewTrack
{ {
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) private readonly ITrackStore trackManager;
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
: base(beatmapSetInfo, trackManager) : base(beatmapSetInfo, trackManager)
{ {
this.trackManager = trackManager;
} }
protected override Track GetTrack() => new TrackVirtual { Length = 100000 }; protected override Track GetTrack() => trackManager.GetVirtual(100000);
} }
} }
} }

View File

@ -7,7 +7,6 @@ using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
{ {
@ -19,7 +18,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, Clock); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Child = new ComposeScreen(); Child = new ComposeScreen();
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -30,9 +31,9 @@ namespace osu.Game.Tests.Visual.Editor
}; };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(AudioManager audio)
{ {
Beatmap.Value = new WaveformTestBeatmap(); Beatmap.Value = new WaveformTestBeatmap(audio);
Children = new Drawable[] Children = new Drawable[]
{ {

View File

@ -1,4 +1,4 @@
// 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 NUnit.Framework; using NUnit.Framework;
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -48,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editor
} }
}; };
Beatmap.Value = new TestWorkingBeatmap(testBeatmap, Clock); Beatmap.Value = CreateWorkingBeatmap(testBeatmap);
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock }; Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };
} }

View File

@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Components.Timelines.Summary; using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
@ -21,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Add(new SummaryTimeline Add(new SummaryTimeline
{ {

View File

@ -18,7 +18,6 @@ using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose;
using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
@ -45,7 +44,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value = new TestWorkingBeatmap(new Beatmap Beatmap.Value = CreateWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> HitObjects = new List<HitObject>
{ {

View File

@ -1,4 +1,4 @@
// 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 NUnit.Framework; using NUnit.Framework;
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Editor
Size = new Vector2(200, 100) Size = new Vector2(200, 100)
}; };
Beatmap.Value = new TestWorkingBeatmap(new Beatmap(), Clock); Beatmap.Value = CreateWorkingBeatmap(new Beatmap());
Child = playback; Child = playback;
} }

View File

@ -3,6 +3,7 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Audio;
@ -10,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
@ -20,9 +22,9 @@ namespace osu.Game.Tests.Visual.Editor
private WorkingBeatmap waveformBeatmap; private WorkingBeatmap waveformBeatmap;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(AudioManager audio)
{ {
waveformBeatmap = new WaveformTestBeatmap(); waveformBeatmap = new WaveformTestBeatmap(audio);
} }
[TestCase(1f)] [TestCase(1f)]
@ -91,7 +93,7 @@ namespace osu.Game.Tests.Visual.Editor
Child = graph = new TestWaveformGraph Child = graph = new TestWaveformGraph
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Waveform = new DummyWorkingBeatmap().Waveform, Waveform = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).Waveform,
}, },
}; };
}); });

View File

@ -1,4 +1,4 @@
// 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;
@ -16,7 +16,6 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public void Setup() => Schedule(() => public void Setup() => Schedule(() =>
{ {
InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
Beatmap.Value = new TestWorkingBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), Clock); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
}); });
[Test] [Test]

View File

@ -3,7 +3,6 @@
using System; using System;
using osu.Framework.Lists; using osu.Framework.Lists;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -43,9 +42,9 @@ namespace osu.Game.Tests.Visual.Gameplay
}); });
} }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock clock) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
{ {
var working = base.CreateWorkingBeatmap(beatmap, clock); var working = base.CreateWorkingBeatmap(beatmap);
workingWeakReferences.Add(working); workingWeakReferences.Add(working);
return working; return working;
} }

View File

@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
@ -57,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name"); AddStep("set name", () => Room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value); AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = new DummyWorkingBeatmap().BeatmapInfo })); AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value); AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => Room.Name.Value = ""); AddStep("clear name", () => Room.Name.Value = "");

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Direct; using osu.Game.Overlays.Direct;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.Online namespace osu.Game.Tests.Visual.Online
@ -25,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
var beatmap = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null); var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
beatmap.BeatmapSetInfo.OnlineInfo.HasVideo = true; beatmap.BeatmapSetInfo.OnlineInfo.HasVideo = true;
beatmap.BeatmapSetInfo.OnlineInfo.HasStoryboard = true; beatmap.BeatmapSetInfo.OnlineInfo.HasStoryboard = true;

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
@ -18,7 +19,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BeatmapDetails) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BeatmapDetails) };
public TestSceneBeatmapDetailArea() [BackgroundDependencyLoader]
private void load(OsuGameBase game)
{ {
BeatmapDetailArea detailsArea; BeatmapDetailArea detailsArea;
Add(detailsArea = new BeatmapDetailArea Add(detailsArea = new BeatmapDetailArea
@ -28,7 +30,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Size = new Vector2(550f, 450f), Size = new Vector2(550f, 450f),
}); });
AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapInfo = BeatmapInfo =
{ {
@ -56,7 +58,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
); );
AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapInfo = BeatmapInfo =
{ {
@ -82,7 +84,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
}); });
AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapInfo = BeatmapInfo =
{ {
@ -107,7 +109,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
}); });
AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapInfo = BeatmapInfo =
{ {
@ -133,7 +135,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
}); });
AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapInfo = BeatmapInfo =
{ {

View File

@ -1,4 +1,4 @@
// 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.Collections.Generic; using System.Collections.Generic;
@ -18,7 +18,6 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko; using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.SongSelect namespace osu.Game.Tests.Visual.SongSelect
@ -136,7 +135,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () => AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () =>
{ {
infoBefore = infoWedge.Info; infoBefore = infoWedge.Info;
infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : new TestWorkingBeatmap(b); infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b);
}); });
AddUntilStep("wait for async load", () => infoWedge.Info != infoBefore); AddUntilStep("wait for async load", () => infoWedge.Info != infoBefore);

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
@ -79,7 +80,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(GameHost host) private void load(GameHost host, AudioManager audio)
{ {
factory = new DatabaseContextFactory(LocalStorage); factory = new DatabaseContextFactory(LocalStorage);
factory.ResetDatabase(); factory.ResetDatabase();
@ -93,7 +94,7 @@ namespace osu.Game.Tests.Visual.SongSelect
usage.Migrate(); usage.Migrate();
Dependencies.Cache(rulesets = new RulesetStore(factory)); Dependencies.Cache(rulesets = new RulesetStore(factory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, defaultBeatmap = Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default));
Beatmap.SetDefault(); Beatmap.SetDefault();
} }

View File

@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
TestUpdateableBeatmapBackgroundSprite background = null; TestUpdateableBeatmapBackgroundSprite background = null;
AddStep("load null beatmap", () => Child = background = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }); AddStep("load null beatmap", () => Child = background = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both });
AddUntilStep("wait for load", () => background.ContentLoaded); AddAssert("no content", () => !background.ContentLoaded);
} }
[Test] [Test]

View File

@ -3,6 +3,7 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -19,12 +20,14 @@ namespace osu.Game.Tests
{ {
private readonly ZipArchiveReader reader; private readonly ZipArchiveReader reader;
private readonly Stream stream; private readonly Stream stream;
private readonly ITrackStore trackStore;
public WaveformTestBeatmap() public WaveformTestBeatmap(AudioManager audioManager)
: base(new BeatmapInfo()) : base(new BeatmapInfo(), audioManager)
{ {
stream = TestResources.GetTestBeatmapStream(); stream = TestResources.GetTestBeatmapStream();
reader = new ZipArchiveReader(stream); reader = new ZipArchiveReader(stream);
trackStore = audioManager.GetTrackStore(reader);
} }
public override void Dispose() public override void Dispose()
@ -32,17 +35,19 @@ namespace osu.Game.Tests
base.Dispose(); base.Dispose();
stream?.Dispose(); stream?.Dispose();
reader?.Dispose(); reader?.Dispose();
trackStore?.Dispose();
} }
protected override IBeatmap GetBeatmap() => createTestBeatmap(); protected override IBeatmap GetBeatmap() => createTestBeatmap();
protected override Texture GetBackground() => null; protected override Texture GetBackground() => null;
protected override Waveform GetWaveform() => new Waveform(getAudioStream()); protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
protected override Track GetTrack() => new TrackBass(getAudioStream()); protected override Track GetTrack() => trackStore.Get(firstAudioFile);
private string firstAudioFile => reader.Filenames.First(f => f.EndsWith(".mp3"));
private Stream getAudioStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".mp3")));
private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu"))); private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")));
private Beatmap createTestBeatmap() private Beatmap createTestBeatmap()

View File

@ -20,19 +20,18 @@ namespace osu.Game.Audio
private readonly BindableDouble muteBindable = new BindableDouble(); private readonly BindableDouble muteBindable = new BindableDouble();
private AudioManager audio; private AudioManager audio;
private TrackManager trackManager; private ITrackStore trackStore;
private TrackManagerPreviewTrack current; private TrackManagerPreviewTrack current;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, FrameworkConfigManager config) private void load(AudioManager audio, FrameworkConfigManager config)
{ {
trackManager = new TrackManager(new OnlineStore()); trackStore = audio.GetTrackStore(new OnlineStore());
this.audio = audio; this.audio = audio;
audio.AddItem(trackManager);
config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); config.BindWith(FrameworkSetting.VolumeMusic, trackStore.Volume);
} }
/// <summary> /// <summary>
@ -42,19 +41,19 @@ namespace osu.Game.Audio
/// <returns>The playable <see cref="PreviewTrack"/>.</returns> /// <returns>The playable <see cref="PreviewTrack"/>.</returns>
public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo)
{ {
var track = CreatePreviewTrack(beatmapSetInfo, trackManager); var track = CreatePreviewTrack(beatmapSetInfo, trackStore);
track.Started += () => track.Started += () =>
{ {
current?.Stop(); current?.Stop();
current = track; current = track;
audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable);
}; };
track.Stopped += () => track.Stopped += () =>
{ {
current = null; current = null;
audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
}; };
return track; return track;
@ -81,16 +80,16 @@ namespace osu.Game.Audio
/// <summary> /// <summary>
/// Creates the <see cref="TrackManagerPreviewTrack"/>. /// Creates the <see cref="TrackManagerPreviewTrack"/>.
/// </summary> /// </summary>
protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TrackManagerPreviewTrack(beatmapSetInfo, trackManager); protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TrackManagerPreviewTrack(beatmapSetInfo, trackStore);
protected class TrackManagerPreviewTrack : PreviewTrack protected class TrackManagerPreviewTrack : PreviewTrack
{ {
public IPreviewTrackOwner Owner { get; private set; } public IPreviewTrackOwner Owner { get; private set; }
private readonly BeatmapSetInfo beatmapSetInfo; private readonly BeatmapSetInfo beatmapSetInfo;
private readonly TrackManager trackManager; private readonly ITrackStore trackManager;
public TrackManagerPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) public TrackManagerPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
{ {
this.beatmapSetInfo = beatmapSetInfo; this.beatmapSetInfo = beatmapSetInfo;
this.trackManager = trackManager; this.trackManager = trackManager;

View File

@ -429,7 +429,7 @@ namespace osu.Game.Beatmaps
private readonly IBeatmap beatmap; private readonly IBeatmap beatmap;
public DummyConversionBeatmap(IBeatmap beatmap) public DummyConversionBeatmap(IBeatmap beatmap)
: base(beatmap.BeatmapInfo) : base(beatmap.BeatmapInfo, null)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
} }

View File

@ -20,14 +20,12 @@ namespace osu.Game.Beatmaps
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
{ {
private readonly IResourceStore<byte[]> store; private readonly IResourceStore<byte[]> store;
private readonly AudioManager audioManager;
public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, TextureStore textureStore, BeatmapInfo beatmapInfo, AudioManager audioManager) public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, TextureStore textureStore, BeatmapInfo beatmapInfo, AudioManager audioManager)
: base(beatmapInfo) : base(beatmapInfo, audioManager)
{ {
this.store = store; this.store = store;
this.textureStore = textureStore; this.textureStore = textureStore;
this.audioManager = audioManager;
} }
protected override IBeatmap GetBeatmap() protected override IBeatmap GetBeatmap()
@ -47,6 +45,8 @@ namespace osu.Game.Beatmaps
private TextureStore textureStore; private TextureStore textureStore;
private ITrackStore trackStore;
protected override bool BackgroundStillValid(Texture b) => false; // bypass lazy logic. we want to return a new background each time for refcounting purposes. protected override bool BackgroundStillValid(Texture b) => false; // bypass lazy logic. we want to return a new background each time for refcounting purposes.
protected override Texture GetBackground() protected override Texture GetBackground()
@ -68,8 +68,7 @@ namespace osu.Game.Beatmaps
{ {
try try
{ {
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile)); return (trackStore ?? (trackStore = AudioManager.GetTrackStore(store))).Get(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new TrackBass(trackData);
} }
catch catch
{ {
@ -77,6 +76,14 @@ namespace osu.Game.Beatmaps
} }
} }
public override void RecycleTrack()
{
base.RecycleTrack();
trackStore?.Dispose();
trackStore = null;
}
public override void TransferTo(WorkingBeatmap other) public override void TransferTo(WorkingBeatmap other)
{ {
base.TransferTo(other); base.TransferTo(other);
@ -135,7 +142,7 @@ namespace osu.Game.Beatmaps
try try
{ {
skin = new LegacyBeatmapSkin(BeatmapInfo, store, audioManager); skin = new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -1,11 +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.Diagnostics; using System.Diagnostics;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
@ -16,32 +12,15 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap> public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>
{ {
private AudioManager audioManager;
private WorkingBeatmap lastBeatmap; private WorkingBeatmap lastBeatmap;
protected BindableBeatmap(WorkingBeatmap defaultValue) protected BindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue) : base(defaultValue)
{ {
BindValueChanged(b => updateAudioTrack(b.NewValue), true);
} }
/// <summary> private void updateAudioTrack(WorkingBeatmap beatmap)
/// Registers an <see cref="AudioManager"/> for <see cref="Track"/>s to be added to.
/// </summary>
/// <param name="audioManager">The <see cref="AudioManager"/> to register.</param>
protected void RegisterAudioManager([NotNull] AudioManager audioManager)
{
if (this.audioManager != null) throw new InvalidOperationException($"Cannot register multiple {nameof(AudioManager)}s.");
this.audioManager = audioManager;
ValueChanged += b => registerAudioTrack(b.NewValue);
// If the track has changed prior to this being called, let's register it
if (Value != Default)
registerAudioTrack(Value);
}
private void registerAudioTrack(WorkingBeatmap beatmap)
{ {
var trackLoaded = lastBeatmap?.TrackLoaded ?? false; var trackLoaded = lastBeatmap?.TrackLoaded ?? false;
@ -55,18 +34,9 @@ namespace osu.Game.Beatmaps
lastBeatmap.RecycleTrack(); lastBeatmap.RecycleTrack();
} }
audioManager.Track.AddItem(beatmap.Track);
} }
lastBeatmap = beatmap; lastBeatmap = beatmap;
} }
/// <summary>
/// Retrieve a new <see cref="BindableBeatmap"/> instance weakly bound to this <see cref="BindableBeatmap"/>.
/// If you are further binding to events of the retrieved <see cref="BindableBeatmap"/>, ensure a local reference is held.
/// </summary>
[NotNull]
public new abstract BindableBeatmap GetBoundCopy();
} }
} }

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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -31,24 +32,8 @@ namespace osu.Game.Beatmaps.Drawables
/// </summary> /// </summary>
protected virtual double UnloadDelay => 10000; protected virtual double UnloadDelay => 10000;
private BeatmapInfo lastModel; protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Func<Drawable> createContentFunc, double timeBeforeLoad)
private bool firstLoad = true; => new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay);
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Drawable content, double timeBeforeLoad)
{
return new DelayedLoadUnloadWrapper(() =>
{
// If DelayedLoadUnloadWrapper is attempting to RELOAD the same content (Beatmap), that means that it was
// previously UNLOADED and thus its children have been disposed of, so we need to recreate them here.
if (!firstLoad && lastModel == Beatmap.Value)
return CreateDrawable(Beatmap.Value);
// If the model has changed since the previous unload (or if there was no load), then we can safely use the given content
lastModel = Beatmap.Value;
firstLoad = false;
return content;
}, timeBeforeLoad, UnloadDelay);
}
protected override Drawable CreateDrawable(BeatmapInfo model) protected override Drawable CreateDrawable(BeatmapInfo model)
{ {

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
@ -16,9 +17,9 @@ namespace osu.Game.Beatmaps
{ {
public class DummyWorkingBeatmap : WorkingBeatmap public class DummyWorkingBeatmap : WorkingBeatmap
{ {
private readonly OsuGameBase game; private readonly TextureStore textures;
public DummyWorkingBeatmap(OsuGameBase game = null) public DummyWorkingBeatmap(AudioManager audio, TextureStore textures)
: base(new BeatmapInfo : base(new BeatmapInfo
{ {
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
@ -34,16 +35,16 @@ namespace osu.Game.Beatmaps
OverallDifficulty = 0, OverallDifficulty = 0,
}, },
Ruleset = new DummyRulesetInfo() Ruleset = new DummyRulesetInfo()
}) }, audio)
{ {
this.game = game; this.textures = textures;
} }
protected override IBeatmap GetBeatmap() => new Beatmap(); protected override IBeatmap GetBeatmap() => new Beatmap();
protected override Texture GetBackground() => game?.Textures.Get(@"Backgrounds/bg4"); protected override Texture GetBackground() => textures?.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual { Length = 1000 }; protected override Track GetTrack() => GetVirtualTrack();
private class DummyRulesetInfo : RulesetInfo private class DummyRulesetInfo : RulesetInfo
{ {

View File

@ -11,15 +11,17 @@ using osu.Framework.IO.File;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using osu.Framework.Audio;
using osu.Game.IO.Serialization; using osu.Game.IO.Serialization;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public abstract partial class WorkingBeatmap : IDisposable public abstract class WorkingBeatmap : IDisposable
{ {
public readonly BeatmapInfo BeatmapInfo; public readonly BeatmapInfo BeatmapInfo;
@ -27,8 +29,11 @@ namespace osu.Game.Beatmaps
public readonly BeatmapMetadata Metadata; public readonly BeatmapMetadata Metadata;
protected WorkingBeatmap(BeatmapInfo beatmapInfo) protected AudioManager AudioManager { get; }
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
{ {
AudioManager = audioManager;
BeatmapInfo = beatmapInfo; BeatmapInfo = beatmapInfo;
BeatmapSetInfo = beatmapInfo.BeatmapSet; BeatmapSetInfo = beatmapInfo.BeatmapSet;
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
@ -46,13 +51,39 @@ namespace osu.Game.Beatmaps
return b; return b;
}); });
track = new RecyclableLazy<Track>(() => GetTrack() ?? new VirtualBeatmapTrack(Beatmap)); track = new RecyclableLazy<Track>(() => GetTrack() ?? GetVirtualTrack());
background = new RecyclableLazy<Texture>(GetBackground, BackgroundStillValid); background = new RecyclableLazy<Texture>(GetBackground, BackgroundStillValid);
waveform = new RecyclableLazy<Waveform>(GetWaveform); waveform = new RecyclableLazy<Waveform>(GetWaveform);
storyboard = new RecyclableLazy<Storyboard>(GetStoryboard); storyboard = new RecyclableLazy<Storyboard>(GetStoryboard);
skin = new RecyclableLazy<Skin>(GetSkin); skin = new RecyclableLazy<Skin>(GetSkin);
} }
protected virtual Track GetVirtualTrack()
{
const double excess_length = 1000;
var lastObject = Beatmap.HitObjects.LastOrDefault();
double length;
switch (lastObject)
{
case null:
length = excess_length;
break;
case IHasEndTime endTime:
length = endTime.EndTime + excess_length;
break;
default:
length = lastObject.StartTime + excess_length;
break;
}
return AudioManager.Tracks.GetVirtual(length);
}
/// <summary> /// <summary>
/// Saves the <see cref="Beatmaps.Beatmap"/>. /// Saves the <see cref="Beatmaps.Beatmap"/>.
/// </summary> /// </summary>
@ -150,6 +181,7 @@ namespace osu.Game.Beatmaps
public bool SkinLoaded => skin.IsResultAvailable; public bool SkinLoaded => skin.IsResultAvailable;
public Skin Skin => skin.Value; public Skin Skin => skin.Value;
protected virtual Skin GetSkin() => new DefaultSkin(); protected virtual Skin GetSkin() => new DefaultSkin();
private readonly RecyclableLazy<Skin> skin; private readonly RecyclableLazy<Skin> skin;
@ -175,7 +207,7 @@ namespace osu.Game.Beatmaps
/// Eagerly dispose of the audio track associated with this <see cref="WorkingBeatmap"/> (if any). /// Eagerly dispose of the audio track associated with this <see cref="WorkingBeatmap"/> (if any).
/// Accessing track again will load a fresh instance. /// Accessing track again will load a fresh instance.
/// </summary> /// </summary>
public void RecycleTrack() => track.Recycle(); public virtual void RecycleTrack() => track.Recycle();
public class RecyclableLazy<T> public class RecyclableLazy<T>
{ {

View File

@ -1,41 +0,0 @@
// 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.Linq;
using osu.Framework.Audio.Track;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps
{
public partial class WorkingBeatmap
{
/// <summary>
/// A type of <see cref="TrackVirtual"/> which provides a valid length based on the <see cref="HitObject"/>s of an <see cref="IBeatmap"/>.
/// </summary>
protected class VirtualBeatmapTrack : TrackVirtual
{
private const double excess_length = 1000;
public VirtualBeatmapTrack(IBeatmap beatmap)
{
var lastObject = beatmap.HitObjects.LastOrDefault();
switch (lastObject)
{
case null:
Length = excess_length;
break;
case IHasEndTime endTime:
Length = endTime.EndTime + excess_length;
break;
default:
Length = lastObject.StartTime + excess_length;
break;
}
}
}
}
}

View File

@ -51,8 +51,8 @@ namespace osu.Game.Graphics.Containers
if (osuGame != null) if (osuGame != null)
OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in"); samplePopIn = audio.Samples.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out"); samplePopOut = audio.Samples.Get(@"UI/overlay-pop-out");
StateChanged += onStateChanged; StateChanged += onStateChanged;
} }

View File

@ -51,7 +51,7 @@ namespace osu.Game.Graphics
screenshotFormat = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat); screenshotFormat = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat);
captureMenuCursor = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor); captureMenuCursor = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor);
shutter = audio.Sample.Get("UI/shutter"); shutter = audio.Samples.Get("UI/shutter");
} }
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)

View File

@ -31,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}"); sampleClick = audio.Samples.Get($@"UI/generic-select{SampleSet.GetDescription()}");
} }
} }
} }

View File

@ -37,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
} }
} }

View File

@ -112,8 +112,8 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleChecked = audio.Sample.Get(@"UI/check-on"); sampleChecked = audio.Samples.Get(@"UI/check-on");
sampleUnchecked = audio.Sample.Get(@"UI/check-off"); sampleUnchecked = audio.Samples.Get(@"UI/check-off");
} }
} }
} }

View File

@ -71,8 +71,8 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleHover = audio.Sample.Get(@"UI/generic-hover"); sampleHover = audio.Samples.Get(@"UI/generic-hover");
sampleClick = audio.Sample.Get(@"UI/generic-select"); sampleClick = audio.Samples.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent; BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023"); BackgroundColourHover = OsuColour.FromHex(@"172023");

View File

@ -86,7 +86,7 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours) private void load(AudioManager audio, OsuColour colours)
{ {
sample = audio.Sample.Get(@"UI/sliderbar-notch"); sample = audio.Samples.Get(@"UI/sliderbar-notch");
AccentColour = colours.Pink; AccentColour = colours.Pink;
} }

View File

@ -15,6 +15,8 @@ namespace osu.Game.IO.Archives
/// </summary> /// </summary>
public abstract Stream GetStream(string name); public abstract Stream GetStream(string name);
public IEnumerable<string> GetAvailableResources() => Filenames;
public abstract void Dispose(); public abstract void Dispose();
/// <summary> /// <summary>

View File

@ -161,7 +161,7 @@ namespace osu.Game
dependencies.CacheAs<IAPIProvider>(API); dependencies.CacheAs<IAPIProvider>(API);
var defaultBeatmap = new DummyWorkingBeatmap(this); var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
@ -193,9 +193,9 @@ namespace osu.Game
// tracks play so loud our samples can't keep up. // tracks play so loud our samples can't keep up.
// this adds a global reduction of track volume for the time being. // this adds a global reduction of track volume for the time being.
Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8));
beatmap = new OsuBindableBeatmap(defaultBeatmap, Audio); beatmap = new OsuBindableBeatmap(defaultBeatmap);
dependencies.CacheAs<IBindable<WorkingBeatmap>>(beatmap); dependencies.CacheAs<IBindable<WorkingBeatmap>>(beatmap);
dependencies.CacheAs(beatmap); dependencies.CacheAs(beatmap);
@ -281,23 +281,10 @@ namespace osu.Game
private class OsuBindableBeatmap : BindableBeatmap private class OsuBindableBeatmap : BindableBeatmap
{ {
public OsuBindableBeatmap(WorkingBeatmap defaultValue, AudioManager audioManager)
: this(defaultValue)
{
RegisterAudioManager(audioManager);
}
public OsuBindableBeatmap(WorkingBeatmap defaultValue) public OsuBindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue) : base(defaultValue)
{ {
} }
public override BindableBeatmap GetBoundCopy()
{
var copy = new OsuBindableBeatmap(Default);
copy.BindTo(this);
return copy;
}
} }
private class OsuUserInputManager : UserInputManager private class OsuUserInputManager : UserInputManager

View File

@ -90,8 +90,8 @@ namespace osu.Game.Overlays.Changelog
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleClick = audio.Sample.Get(@"UI/generic-select-soft"); sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
sampleHover = audio.Sample.Get(@"UI/generic-hover-soft"); sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
} }
protected override void OnActivated() => updateState(); protected override void OnActivated() => updateState();

View File

@ -76,7 +76,7 @@ namespace osu.Game.Overlays
}, },
}; };
sampleBack = audio.Sample.Get(@"UI/generic-select-soft"); sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
header.Current.BindTo(Current); header.Current.BindTo(Current);

View File

@ -145,7 +145,7 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, TextureStore textures, AudioManager audio) private void load(OsuColour colours, TextureStore textures, AudioManager audio)
{ {
getSample = audio.Sample.Get(@"MedalSplash/medal-get"); getSample = audio.Samples.Get(@"MedalSplash/medal-get");
innerSpin.Texture = outerSpin.Texture = textures.Get(@"MedalSplash/disc-spin"); innerSpin.Texture = outerSpin.Texture = textures.Get(@"MedalSplash/disc-spin");
disc.EdgeEffect = leftStrip.EdgeEffect = rightStrip.EdgeEffect = new EdgeEffectParameters disc.EdgeEffect = leftStrip.EdgeEffect = rightStrip.EdgeEffect = new EdgeEffectParameters

View File

@ -56,8 +56,8 @@ namespace osu.Game.Overlays.Mods
Ruleset.BindTo(ruleset); Ruleset.BindTo(ruleset);
if (mods != null) SelectedMods.BindTo(mods); if (mods != null) SelectedMods.BindTo(mods);
sampleOn = audio.Sample.Get(@"UI/check-on"); sampleOn = audio.Samples.Get(@"UI/check-on");
sampleOff = audio.Sample.Get(@"UI/check-off"); sampleOff = audio.Samples.Get(@"UI/check-off");
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -350,7 +350,7 @@ namespace osu.Game.Overlays
direction = last > next ? TransformDirection.Prev : TransformDirection.Next; direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
} }
current.Track.Completed -= currentTrackCompleted; //current.Track.Completed -= currentTrackCompleted;
} }
current = beatmap.NewValue; current = beatmap.NewValue;

View File

@ -182,9 +182,9 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
sampleHover = audio.Sample.Get(@"Menu/button-hover"); sampleHover = audio.Samples.Get(@"Menu/button-hover");
if (!string.IsNullOrEmpty(sampleName)) if (!string.IsNullOrEmpty(sampleName))
sampleClick = audio.Sample.Get($@"Menu/{sampleName}"); sampleClick = audio.Samples.Get($@"Menu/{sampleName}");
} }
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)

View File

@ -150,7 +150,7 @@ namespace osu.Game.Screens.Menu
if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle);
sampleBack = audio.Sample.Get(@"Menu/button-back-select"); sampleBack = audio.Samples.Get(@"Menu/button-back-select");
} }
private void onMulti() private void onMulti()

View File

@ -76,8 +76,8 @@ namespace osu.Game.Screens.Menu
introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = introBeatmap.Track; track = introBeatmap.Track;
welcome = audio.Sample.Get(@"welcome"); welcome = audio.Samples.Get(@"welcome");
seeya = audio.Sample.Get(@"seeya"); seeya = audio.Samples.Get(@"seeya");
} }
private const double delay_step_one = 2300; private const double delay_step_one = 2300;

View File

@ -255,8 +255,8 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(TextureStore textures, AudioManager audio) private void load(TextureStore textures, AudioManager audio)
{ {
sampleClick = audio.Sample.Get(@"Menu/osu-logo-select"); sampleClick = audio.Samples.Get(@"Menu/osu-logo-select");
sampleBeat = audio.Sample.Get(@"Menu/osu-logo-heartbeat"); sampleBeat = audio.Samples.Get(@"Menu/osu-logo-heartbeat");
logo.Texture = textures.Get(@"Menu/logo"); logo.Texture = textures.Get(@"Menu/logo");
ripple.Texture = textures.Get(@"Menu/logo"); ripple.Texture = textures.Get(@"Menu/logo");

View File

@ -137,7 +137,7 @@ namespace osu.Game.Screens.Multi.Match.Components
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite private class BackgroundSprite : UpdateableBeatmapBackgroundSprite
{ {
protected override double FadeDuration => 200; protected override double TransformDuration => 200;
} }
} }
} }

View File

@ -255,7 +255,7 @@ namespace osu.Game.Screens.Multi
if (!track.IsRunning) if (!track.IsRunning)
{ {
game.Audio.AddItemToList(track); game.Audio.AddItem(track);
track.Seek(Beatmap.Value.Metadata.PreviewTime); track.Seek(Beatmap.Value.Metadata.PreviewTime);
track.Start(); track.Start();
} }

View File

@ -99,7 +99,7 @@ namespace osu.Game.Screens
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuGame osu, AudioManager audio) private void load(OsuGame osu, AudioManager audio)
{ {
sampleExit = audio.Sample.Get(@"UI/screen-back"); sampleExit = audio.Samples.Get(@"UI/screen-back");
} }
public virtual bool OnPressed(GlobalAction action) public virtual bool OnPressed(GlobalAction action)

View File

@ -103,7 +103,7 @@ namespace osu.Game.Screens.Play
if (working == null) if (working == null)
return; return;
sampleRestart = audio.Sample.Get(@"Gameplay/restart"); sampleRestart = audio.Samples.Get(@"Gameplay/restart");
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel); mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard); showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);

View File

@ -234,7 +234,7 @@ namespace osu.Game.Screens.Play
colourNormal = colours.Yellow; colourNormal = colours.Yellow;
colourHover = colours.YellowDark; colourHover = colours.YellowDark;
sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); sampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection");
Children = new Drawable[] Children = new Drawable[]
{ {

View File

@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel
} }
}; };
sampleHover = audio.Sample.Get($@"SongSelect/song-ping-variation-{RNG.Next(1, 5)}"); sampleHover = audio.Samples.Get($@"SongSelect/song-ping-variation-{RNG.Next(1, 5)}");
hoverLayer.Colour = colours.Blue.Opacity(0.1f); hoverLayer.Colour = colours.Blue.Opacity(0.1f);
} }

View File

@ -242,9 +242,9 @@ namespace osu.Game.Screens.Select
dialogOverlay = dialog; dialogOverlay = dialog;
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty"); sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty");
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand"); sampleChangeBeatmap = audio.Samples.Get(@"SongSelect/select-expand");
SampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); SampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection");
Carousel.LoadBeatmapSetsFromManager(this.beatmaps); Carousel.LoadBeatmapSetsFromManager(this.beatmaps);
@ -580,9 +580,6 @@ namespace osu.Game.Screens.Select
if (!track.IsRunning || restart) if (!track.IsRunning || restart)
{ {
// Ensure the track is added to the TrackManager, since it is removed after the player finishes the map.
// Using AddItemToList rather than AddItem so that it doesn't attempt to register adjustment dependencies more than once.
Game.Audio.Track.AddItemToList(track);
track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; track.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
track.Restart(); track.Restart();
} }

View File

@ -2,6 +2,7 @@
// 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;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,7 +22,7 @@ namespace osu.Game.Skinning
{ {
protected TextureStore Textures; protected TextureStore Textures;
protected SampleManager Samples; protected IResourceStore<SampleChannel> Samples;
public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager) public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager)
: this(skin, new LegacySkinResourceStore<SkinFileInfo>(skin, storage), audioManager, "skin.ini") : this(skin, new LegacySkinResourceStore<SkinFileInfo>(skin, storage), audioManager, "skin.ini")
@ -38,10 +39,17 @@ namespace osu.Game.Skinning
else else
Configuration = new SkinConfiguration(); Configuration = new SkinConfiguration();
Samples = audioManager.GetSampleManager(storage); Samples = audioManager.GetSampleStore(storage);
Textures = new TextureStore(new TextureLoaderStore(storage)); Textures = new TextureStore(new TextureLoaderStore(storage));
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Textures?.Dispose();
Samples?.Dispose();
}
public override Drawable GetDrawableComponent(string componentName) public override Drawable GetDrawableComponent(string componentName)
{ {
switch (componentName) switch (componentName)
@ -133,6 +141,8 @@ namespace osu.Game.Skinning
return path == null ? null : underlyingStore.GetStream(path); return path == null ? null : underlyingStore.GetStream(path);
} }
public IEnumerable<string> GetAvailableResources() => source.Files.Select(f => f.Filename);
byte[] IResourceStore<byte[]>.Get(string name) => GetAsync(name).Result; byte[] IResourceStore<byte[]>.Get(string name) => GetAsync(name).Result;
public Task<byte[]> GetAsync(string name) public Task<byte[]> GetAsync(string name)

View File

@ -39,7 +39,7 @@ namespace osu.Game.Skinning
{ {
var ch = loadChannel(s, skin.GetSample); var ch = loadChannel(s, skin.GetSample);
if (ch == null && allowFallback) if (ch == null && allowFallback)
ch = loadChannel(s, audio.Sample.Get); ch = loadChannel(s, audio.Samples.Get);
return ch; return ch;
}).Where(c => c != null).ToArray(); }).Where(c => c != null).ToArray();
} }
@ -58,5 +58,13 @@ namespace osu.Game.Skinning
return null; return null;
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
foreach (var c in channels)
c.Dispose();
}
} }
} }

View File

@ -1,134 +1,30 @@
// 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 osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osuTK;
namespace osu.Game.Tests.Beatmaps namespace osu.Game.Tests.Beatmaps
{ {
public class TestWorkingBeatmap : WorkingBeatmap public class TestWorkingBeatmap : WorkingBeatmap
{ {
private readonly TrackVirtualManual track;
private readonly IBeatmap beatmap; private readonly IBeatmap beatmap;
/// <summary>
/// Create an instance which creates a <see cref="TestBeatmap"/> for the provided ruleset when requested.
/// </summary>
/// <param name="ruleset">The target ruleset.</param>
/// <param name="referenceClock">A clock which should be used instead of a stopwatch for virtual time progression.</param>
public TestWorkingBeatmap(RulesetInfo ruleset, IFrameBasedClock referenceClock)
: this(new TestBeatmap(ruleset), referenceClock)
{
}
/// <summary> /// <summary>
/// Create an instance which provides the <see cref="IBeatmap"/> when requested. /// Create an instance which provides the <see cref="IBeatmap"/> when requested.
/// </summary> /// </summary>
/// <param name="beatmap">The beatmap</param> /// <param name="beatmap">The beatmap</param>
/// <param name="referenceClock">An optional clock which should be used instead of a stopwatch for virtual time progression.</param> public TestWorkingBeatmap(IBeatmap beatmap)
public TestWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock referenceClock = null) : base(beatmap.BeatmapInfo, null)
: base(beatmap.BeatmapInfo)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
if (referenceClock != null)
track = new TrackVirtualManual(referenceClock);
} }
protected override IBeatmap GetBeatmap() => beatmap; protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null; protected override Texture GetBackground() => null;
protected override Track GetTrack() => track;
/// <summary> protected override Track GetTrack() => null;
/// A virtual track which tracks a reference clock.
/// </summary>
public class TrackVirtualManual : Track
{
private readonly IFrameBasedClock referenceClock;
private readonly ManualClock clock = new ManualClock();
private bool running;
/// <summary>
/// Local offset added to the reference clock to resolve correct time.
/// </summary>
private double offset;
public TrackVirtualManual(IFrameBasedClock referenceClock)
{
this.referenceClock = referenceClock;
Length = double.PositiveInfinity;
}
public override bool Seek(double seek)
{
offset = MathHelper.Clamp(seek, 0, Length);
lastReferenceTime = null;
return offset == seek;
}
public override void Start()
{
running = true;
}
public override void Reset()
{
Seek(0);
base.Reset();
}
public override void Stop()
{
if (running)
{
running = false;
// on stopping, the current value should be transferred out of the clock, as we can no longer rely on
// the referenceClock (which will still be counting time).
offset = clock.CurrentTime;
lastReferenceTime = null;
}
}
public override bool IsRunning => running;
private double? lastReferenceTime;
public override double CurrentTime => clock.CurrentTime;
protected override void UpdateState()
{
base.UpdateState();
if (running)
{
double refTime = referenceClock.CurrentTime;
if (!lastReferenceTime.HasValue)
{
// if the clock just started running, the current value should be transferred to the offset
// (to zero the progression of time).
offset -= refTime;
}
lastReferenceTime = refTime;
}
clock.CurrentTime = Math.Min((lastReferenceTime ?? 0) + offset, Length);
if (CurrentTime >= Length)
{
Stop();
RaiseCompleted();
}
}
}
} }
} }

View File

@ -4,13 +4,10 @@
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
@ -50,26 +47,20 @@ namespace osu.Game.Tests.Visual
protected abstract void AddCheckSteps(); protected abstract void AddCheckSteps();
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); private Player loadPlayerFor(RulesetInfo rulesetInfo)
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock clock) =>
new TestWorkingBeatmap(beatmap, Clock);
private Player loadPlayerFor(RulesetInfo ri)
{ {
Ruleset.Value = ri; Ruleset.Value = rulesetInfo;
var r = ri.CreateInstance(); var ruleset = rulesetInfo.CreateInstance();
var beatmap = CreateBeatmap(r); var working = CreateWorkingBeatmap(rulesetInfo);
var working = CreateWorkingBeatmap(beatmap, Clock);
Beatmap.Value = working; Beatmap.Value = working;
Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };
Player?.Exit(); Player?.Exit();
Player = null; Player = null;
Player = CreatePlayer(r); Player = CreatePlayer(ruleset);
LoadScreen(Player); LoadScreen(Player);

View File

@ -1,4 +1,4 @@
// 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;
@ -6,7 +6,6 @@ using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
@ -24,7 +23,7 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo, null); Beatmap.Value = CreateWorkingBeatmap(ruleset.RulesetInfo);
LoadScreen(new Editor()); LoadScreen(new Editor());
} }

View File

@ -3,15 +3,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
@ -19,7 +26,7 @@ namespace osu.Game.Tests.Visual
{ {
[Cached(typeof(Bindable<WorkingBeatmap>))] [Cached(typeof(Bindable<WorkingBeatmap>))]
[Cached(typeof(IBindable<WorkingBeatmap>))] [Cached(typeof(IBindable<WorkingBeatmap>))]
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap()); private OsuTestBeatmap beatmap;
protected BindableBeatmap Beatmap => beatmap; protected BindableBeatmap Beatmap => beatmap;
@ -39,7 +46,12 @@ namespace osu.Game.Tests.Visual
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
// This is the earliest we can get OsuGameBase, which is used by the dummy working beatmap to find textures // This is the earliest we can get OsuGameBase, which is used by the dummy working beatmap to find textures
beatmap.Default = new DummyWorkingBeatmap(parent.Get<OsuGameBase>()); var working = new DummyWorkingBeatmap(parent.Get<AudioManager>(), parent.Get<TextureStore>());
beatmap = new OsuTestBeatmap(working)
{
Default = working
};
return Dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); return Dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
} }
@ -49,11 +61,20 @@ namespace osu.Game.Tests.Visual
localStorage = new Lazy<Storage>(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}")); localStorage = new Lazy<Storage>(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}"));
} }
[BackgroundDependencyLoader] [Resolved]
private void load(AudioManager audioManager, RulesetStore rulesets) private AudioManager audio { get; set; }
{
beatmap.SetAudioManager(audioManager);
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
protected WorkingBeatmap CreateWorkingBeatmap(RulesetInfo ruleset) =>
CreateWorkingBeatmap(CreateBeatmap(ruleset));
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) =>
new ClockBackedTestWorkingBeatmap(beatmap, Clock, audio);
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
Ruleset.Value = rulesets.AvailableRulesets.First(); Ruleset.Value = rulesets.AvailableRulesets.First();
} }
@ -79,6 +100,164 @@ namespace osu.Game.Tests.Visual
protected override ITestSceneTestRunner CreateRunner() => new OsuTestSceneTestRunner(); protected override ITestSceneTestRunner CreateRunner() => new OsuTestSceneTestRunner();
public class ClockBackedTestWorkingBeatmap : TestWorkingBeatmap
{
private readonly Track track;
private readonly TrackVirtualStore store;
/// <summary>
/// Create an instance which creates a <see cref="TestBeatmap"/> for the provided ruleset when requested.
/// </summary>
/// <param name="ruleset">The target ruleset.</param>
/// <param name="referenceClock">A clock which should be used instead of a stopwatch for virtual time progression.</param>
/// <param name="audio">Audio manager. Required if a reference clock isn't provided.</param>
public ClockBackedTestWorkingBeatmap(RulesetInfo ruleset, IFrameBasedClock referenceClock, AudioManager audio)
: this(new TestBeatmap(ruleset), referenceClock, audio)
{
}
/// <summary>
/// Create an instance which provides the <see cref="IBeatmap"/> when requested.
/// </summary>
/// <param name="beatmap">The beatmap</param>
/// <param name="referenceClock">An optional clock which should be used instead of a stopwatch for virtual time progression.</param>
/// <param name="audio">Audio manager. Required if a reference clock isn't provided.</param>
/// <param name="length">The length of the returned virtual track.</param>
public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock referenceClock, AudioManager audio, double length = 60000)
: base(beatmap)
{
if (referenceClock != null)
{
store = new TrackVirtualStore(referenceClock);
audio.AddItem(store);
track = store.GetVirtual(length);
}
else
track = audio?.Tracks.GetVirtual(length);
}
public override void Dispose()
{
base.Dispose();
store?.Dispose();
}
protected override Track GetTrack() => track;
public class TrackVirtualStore : AudioCollectionManager<Track>, ITrackStore
{
private readonly IFrameBasedClock referenceClock;
public TrackVirtualStore(IFrameBasedClock referenceClock)
{
this.referenceClock = referenceClock;
}
public Track Get(string name) => throw new NotImplementedException();
public Task<Track> GetAsync(string name) => throw new NotImplementedException();
public Stream GetStream(string name) => throw new NotImplementedException();
public IEnumerable<string> GetAvailableResources() => throw new NotImplementedException();
public Track GetVirtual(double length = Double.PositiveInfinity)
{
var track = new TrackVirtualManual(referenceClock) { Length = length };
AddItem(track);
return track;
}
}
/// <summary>
/// A virtual track which tracks a reference clock.
/// </summary>
public class TrackVirtualManual : Track
{
private readonly IFrameBasedClock referenceClock;
private readonly ManualClock clock = new ManualClock();
private bool running;
/// <summary>
/// Local offset added to the reference clock to resolve correct time.
/// </summary>
private double offset;
public TrackVirtualManual(IFrameBasedClock referenceClock)
{
this.referenceClock = referenceClock;
Length = double.PositiveInfinity;
}
public override bool Seek(double seek)
{
offset = MathHelper.Clamp(seek, 0, Length);
lastReferenceTime = null;
return offset == seek;
}
public override void Start()
{
running = true;
}
public override void Reset()
{
Seek(0);
base.Reset();
}
public override void Stop()
{
if (running)
{
running = false;
// on stopping, the current value should be transferred out of the clock, as we can no longer rely on
// the referenceClock (which will still be counting time).
offset = clock.CurrentTime;
lastReferenceTime = null;
}
}
public override bool IsRunning => running;
private double? lastReferenceTime;
public override double CurrentTime => clock.CurrentTime;
protected override void UpdateState()
{
base.UpdateState();
if (running)
{
double refTime = referenceClock.CurrentTime;
if (!lastReferenceTime.HasValue)
{
// if the clock just started running, the current value should be transferred to the offset
// (to zero the progression of time).
offset -= refTime;
}
lastReferenceTime = refTime;
}
clock.CurrentTime = Math.Min((lastReferenceTime ?? 0) + offset, Length);
if (CurrentTime >= Length)
{
Stop();
RaiseCompleted();
}
}
}
}
public class OsuTestSceneTestRunner : OsuGameBase, ITestSceneTestRunner public class OsuTestSceneTestRunner : OsuGameBase, ITestSceneTestRunner
{ {
private TestSceneTestRunner.TestRunner runner; private TestSceneTestRunner.TestRunner runner;
@ -100,15 +279,6 @@ namespace osu.Game.Tests.Visual
: base(defaultValue) : base(defaultValue)
{ {
} }
public void SetAudioManager(AudioManager audioManager) => RegisterAudioManager(audioManager);
public override BindableBeatmap GetBoundCopy()
{
var copy = new OsuTestBeatmap(Default);
copy.BindTo(this);
return copy;
}
} }
} }
} }

View File

@ -15,19 +15,18 @@ namespace osu.Game.Tests.Visual
[Cached(Type = typeof(IPlacementHandler))] [Cached(Type = typeof(IPlacementHandler))]
public abstract class PlacementBlueprintTestScene : OsuTestScene, IPlacementHandler public abstract class PlacementBlueprintTestScene : OsuTestScene, IPlacementHandler
{ {
protected readonly Container HitObjectContainer; protected Container HitObjectContainer;
private PlacementBlueprint currentBlueprint; private PlacementBlueprint currentBlueprint;
protected PlacementBlueprintTestScene() protected PlacementBlueprintTestScene()
{ {
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2;
Add(HitObjectContainer = CreateHitObjectContainer()); Add(HitObjectContainer = CreateHitObjectContainer());
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2;
Add(currentBlueprint = CreateBlueprint()); Add(currentBlueprint = CreateBlueprint());
} }

View File

@ -4,12 +4,10 @@
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
@ -39,15 +37,13 @@ namespace osu.Game.Tests.Visual
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1); AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
} }
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo);
protected virtual bool AllowFail => false; protected virtual bool AllowFail => false;
private void loadPlayer() private void loadPlayer()
{ {
var beatmap = CreateBeatmap(ruleset); var beatmap = CreateBeatmap(ruleset.RulesetInfo);
Beatmap.Value = new TestWorkingBeatmap(beatmap, Clock); Beatmap.Value = CreateWorkingBeatmap(beatmap);
if (!AllowFail) if (!AllowFail)
Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) }; Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };

View File

@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.518.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.518.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.523.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.604.1" />
<PackageReference Include="SharpCompress" Version="0.23.0" /> <PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />