1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 18:12:56 +08:00

Move track to MusicController, compiles

This commit is contained in:
smoogipoo 2020-08-04 21:53:00 +09:00
parent 641279ec3e
commit 6e42b8219c
57 changed files with 438 additions and 346 deletions

View File

@ -343,7 +343,7 @@ namespace osu.Game.Rulesets.Mania.Tests
judgementResults = new List<JudgementResult>(); judgementResults = new List<JudgementResult>();
}); });
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
} }

View File

@ -385,7 +385,7 @@ namespace osu.Game.Rulesets.Osu.Tests
judgementResults = new List<JudgementResult>(); judgementResults = new List<JudgementResult>();
}); });
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
} }

View File

@ -366,7 +366,7 @@ namespace osu.Game.Rulesets.Osu.Tests
judgementResults = new List<JudgementResult>(); judgementResults = new List<JudgementResult>();
}); });
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
} }

View File

@ -22,7 +22,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using osu.Game.Storyboards; using osu.Game.Storyboards;
using osuTK; using osuTK;
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
{ {
@ -32,8 +31,6 @@ namespace osu.Game.Rulesets.Osu.Tests
[Resolved] [Resolved]
private AudioManager audioManager { get; set; } private AudioManager audioManager { get; set; }
private TrackVirtualManual track;
protected override bool Autoplay => autoplay; protected override bool Autoplay => autoplay;
private bool autoplay; private bool autoplay;
@ -44,11 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private const double fade_in_modifier = -1200; private const double fade_in_modifier = -1200;
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
track = (TrackVirtualManual)working.Track;
return working;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetConfigCache configCache) private void load(RulesetConfigCache configCache)
@ -72,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
AddStep("enable autoplay", () => autoplay = true); AddStep("enable autoplay", () => autoplay = true);
base.SetUpSteps(); base.SetUpSteps();
AddUntilStep("wait for track to start running", () => track.IsRunning); AddUntilStep("wait for track to start running", () => MusicController.IsPlaying);
double startTime = hitObjects[sliderIndex].StartTime; double startTime = hitObjects[sliderIndex].StartTime;
retrieveDrawableSlider(sliderIndex); retrieveDrawableSlider(sliderIndex);
@ -97,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
AddStep("have autoplay", () => autoplay = true); AddStep("have autoplay", () => autoplay = true);
base.SetUpSteps(); base.SetUpSteps();
AddUntilStep("wait for track to start running", () => track.IsRunning); AddUntilStep("wait for track to start running", () => MusicController.IsPlaying);
double startTime = hitObjects[sliderIndex].StartTime; double startTime = hitObjects[sliderIndex].StartTime;
retrieveDrawableSlider(sliderIndex); retrieveDrawableSlider(sliderIndex);
@ -201,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void addSeekStep(double time) private void addSeekStep(double time)
{ {
AddStep($"seek to {time}", () => track.Seek(time)); AddStep($"seek to {time}", () => MusicController.SeekTo(time));
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
} }

View File

@ -24,7 +24,6 @@ using osu.Game.Scoring;
using osu.Game.Storyboards; using osu.Game.Storyboards;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK; using osuTK;
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
{ {
@ -33,18 +32,12 @@ namespace osu.Game.Rulesets.Osu.Tests
[Resolved] [Resolved]
private AudioManager audioManager { get; set; } private AudioManager audioManager { get; set; }
private TrackVirtualManual track;
protected override bool Autoplay => true; protected override bool Autoplay => true;
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer(); protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer();
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
track = (TrackVirtualManual)working.Track;
return working;
}
private DrawableSpinner drawableSpinner; private DrawableSpinner drawableSpinner;
private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType<SpriteIcon>().Single(); private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType<SpriteIcon>().Single();
@ -54,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
base.SetUpSteps(); base.SetUpSteps();
AddUntilStep("wait for track to start running", () => track.IsRunning); AddUntilStep("wait for track to start running", () => MusicController.IsPlaying);
AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First()); AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First());
} }
@ -198,7 +191,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void addSeekStep(double time) private void addSeekStep(double time)
{ {
AddStep($"seek to {time}", () => track.Seek(time)); AddStep($"seek to {time}", () => MusicController.SeekTo(time));
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
} }

View File

@ -175,11 +175,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
private void createDrawableRuleset() private void createDrawableRuleset()
{ {
AddUntilStep("wait for beatmap to be loaded", () => Beatmap.Value.Track.IsLoaded); AddUntilStep("wait for beatmap to be loaded", () => MusicController.TrackLoaded);
AddStep("create drawable ruleset", () => AddStep("create drawable ruleset", () =>
{ {
Beatmap.Value.Track.Start(); MusicController.Play(true);
SetContents(() => SetContents(() =>
{ {

View File

@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 });
Beatmap.Value.Track.Start(); MusicController.Play(true);
}); });
AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo()) AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo())

View File

@ -3,7 +3,6 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -32,6 +31,6 @@ namespace osu.Game.Tests.Skins
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null); public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null);
[Test] [Test]
public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => !(beatmap.Track is TrackVirtual)); public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => !MusicController.IsDummyDevice);
} }
} }

View File

@ -3,12 +3,11 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
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.Game.Beatmaps;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.Compose.Components.Timeline;
@ -65,10 +64,10 @@ namespace osu.Game.Tests.Visual.Editing
private readonly Drawable marker; private readonly Drawable marker;
[Resolved] [Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; } private EditorClock editorClock { get; set; }
[Resolved] [Resolved]
private EditorClock editorClock { get; set; } private MusicController musicController { get; set; }
public AudioVisualiser() public AudioVisualiser()
{ {
@ -94,8 +93,8 @@ namespace osu.Game.Tests.Visual.Editing
{ {
base.Update(); base.Update();
if (beatmap.Value.Track.IsLoaded) if (musicController.TrackLoaded)
marker.X = (float)(editorClock.CurrentTime / beatmap.Value.Track.Length); marker.X = (float)(editorClock.CurrentTime / musicController.TrackLength);
} }
} }

View File

@ -4,7 +4,6 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Timing; using osu.Framework.Timing;
@ -18,8 +17,6 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneCompletionCancellation : OsuPlayerTestScene public class TestSceneCompletionCancellation : OsuPlayerTestScene
{ {
private Track track;
[Resolved] [Resolved]
private AudioManager audio { get; set; } private AudioManager audio { get; set; }
@ -34,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
base.SetUpSteps(); base.SetUpSteps();
// Ensure track has actually running before attempting to seek // Ensure track has actually running before attempting to seek
AddUntilStep("wait for track to start running", () => track.IsRunning); AddUntilStep("wait for track to start running", () => MusicController.IsPlaying);
} }
[Test] [Test]
@ -73,13 +70,13 @@ namespace osu.Game.Tests.Visual.Gameplay
private void complete() private void complete()
{ {
AddStep("seek to completion", () => track.Seek(5000)); AddStep("seek to completion", () => MusicController.SeekTo(5000));
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
} }
private void cancel() private void cancel()
{ {
AddStep("rewind to cancel", () => track.Seek(4000)); AddStep("rewind to cancel", () => MusicController.SeekTo(4000));
AddUntilStep("completion cleared by processor", () => !Player.ScoreProcessor.HasCompleted.Value); AddUntilStep("completion cleared by processor", () => !Player.ScoreProcessor.HasCompleted.Value);
} }
@ -91,11 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
} }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio);
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio);
track = working.Track;
return working;
}
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {

View File

@ -5,10 +5,10 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Storyboards; using osu.Game.Storyboards;
@ -21,19 +21,16 @@ namespace osu.Game.Tests.Visual.Gameplay
[Resolved] [Resolved]
private AudioManager audioManager { get; set; } private AudioManager audioManager { get; set; }
private Track track; [Resolved]
private MusicController musicController { get; set; }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
track = working.Track;
return working;
}
[Test] [Test]
public void TestNoJudgementsOnRewind() public void TestNoJudgementsOnRewind()
{ {
AddUntilStep("wait for track to start running", () => track.IsRunning); AddUntilStep("wait for track to start running", () => MusicController.IsPlaying);
addSeekStep(3000); addSeekStep(3000);
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7)); AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
@ -46,7 +43,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void addSeekStep(double time) private void addSeekStep(double time)
{ {
AddStep($"seek to {time}", () => track.Seek(time)); AddStep($"seek to {time}", () => MusicController.SeekTo(time));
// Allow a few frames of lenience // Allow a few frames of lenience
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));

View File

@ -19,8 +19,8 @@ namespace osu.Game.Tests.Visual.Gameplay
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Beatmap.Value.Track.Start(); MusicController.Play(true);
Beatmap.Value.Track.Seek(Beatmap.Value.Beatmap.HitObjects.First().StartTime - 1000); MusicController.SeekTo(Beatmap.Value.Beatmap.HitObjects.First().StartTime - 1000);
Add(new ModNightcore<HitObject>.NightcoreBeatContainer()); Add(new ModNightcore<HitObject>.NightcoreBeatContainer());

View File

@ -288,7 +288,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void confirmNoTrackAdjustments() private void confirmNoTrackAdjustments()
{ {
AddAssert("track has no adjustments", () => Beatmap.Value.Track.AggregateFrequency.Value == 1); AddAssert("track has no adjustments", () => MusicController.AggregateFrequency.Value == 1);
} }
private void restart() => AddStep("restart", () => Player.Restart()); private void restart() => AddStep("restart", () => Player.Restart());

View File

@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>()) foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(Beatmap.Value.Track); mod.ApplyToTrack(MusicController);
InputManager.Child = container = new TestPlayerLoaderContainer( InputManager.Child = container = new TestPlayerLoaderContainer(
loader = new TestPlayerLoader(() => loader = new TestPlayerLoader(() =>
@ -77,12 +77,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddStep("load dummy beatmap", () => ResetPlayer(false, () => SelectedMods.Value = new[] { new OsuModNightcore() })); AddStep("load dummy beatmap", () => ResetPlayer(false, () => SelectedMods.Value = new[] { new OsuModNightcore() }));
AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddUntilStep("wait for current", () => loader.IsCurrentScreen());
AddAssert("mod rate applied", () => Beatmap.Value.Track.Rate != 1); AddAssert("mod rate applied", () => MusicController.Rate != 1);
AddStep("exit loader", () => loader.Exit()); AddStep("exit loader", () => loader.Exit());
AddUntilStep("wait for not current", () => !loader.IsCurrentScreen()); AddUntilStep("wait for not current", () => !loader.IsCurrentScreen());
AddAssert("player did not load", () => !player.IsLoaded); AddAssert("player did not load", () => !player.IsLoaded);
AddUntilStep("player disposed", () => loader.DisposalTask?.IsCompleted == true); AddUntilStep("player disposed", () => loader.DisposalTask?.IsCompleted == true);
AddAssert("mod rate still applied", () => Beatmap.Value.Track.Rate != 1); AddAssert("mod rate still applied", () => MusicController.Rate != 1);
} }
[Test] [Test]

View File

@ -87,11 +87,9 @@ namespace osu.Game.Tests.Visual.Gameplay
private void restart() private void restart()
{ {
var track = Beatmap.Value.Track; MusicController.Reset();
track.Reset();
loadStoryboard(Beatmap.Value); loadStoryboard(Beatmap.Value);
track.Start(); MusicController.Play(true);
} }
private void loadStoryboard(WorkingBeatmap working) private void loadStoryboard(WorkingBeatmap working)
@ -106,7 +104,7 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboard.Passing = false; storyboard.Passing = false;
storyboardContainer.Add(storyboard); storyboardContainer.Add(storyboard);
decoupledClock.ChangeSource(working.Track); decoupledClock.ChangeSource(musicController.GetTrackClock());
} }
private void loadStoryboardNoVideo() private void loadStoryboardNoVideo()
@ -129,7 +127,7 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboard = sb.CreateDrawable(Beatmap.Value); storyboard = sb.CreateDrawable(Beatmap.Value);
storyboardContainer.Add(storyboard); storyboardContainer.Add(storyboard);
decoupledClock.ChangeSource(Beatmap.Value.Track); decoupledClock.ChangeSource(musicController.GetTrackClock());
} }
} }
} }

View File

@ -2,7 +2,6 @@
// 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;
using osu.Framework.Audio.Track;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -15,11 +14,9 @@ namespace osu.Game.Tests.Visual.Menus
public TestSceneIntroWelcome() public TestSceneIntroWelcome()
{ {
AddUntilStep("wait for load", () => getTrack() != null); AddUntilStep("wait for load", () => MusicController.TrackLoaded);
AddAssert("check if menu music loops", () => getTrack().Looping); AddAssert("check if menu music loops", () => MusicController.Looping);
} }
private Track getTrack() => (IntroStack?.CurrentScreen as MainMenu)?.Track;
} }
} }

View File

@ -4,7 +4,6 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -46,7 +45,6 @@ namespace osu.Game.Tests.Visual.Navigation
Player player = null; Player player = null;
WorkingBeatmap beatmap() => Game.Beatmap.Value; WorkingBeatmap beatmap() => Game.Beatmap.Value;
Track track() => beatmap().Track;
PushAndConfirm(() => new TestSongSelect()); PushAndConfirm(() => new TestSongSelect());
@ -62,30 +60,27 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null); AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
AddUntilStep("wait for fail", () => player.HasFailed); AddUntilStep("wait for fail", () => player.HasFailed);
AddUntilStep("wait for track stop", () => !track().IsRunning); AddUntilStep("wait for track stop", () => !MusicController.IsPlaying);
AddAssert("Ensure time before preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime); AddAssert("Ensure time before preview point", () => MusicController.CurrentTrackTime < beatmap().Metadata.PreviewTime);
pushEscape(); pushEscape();
AddUntilStep("wait for track playing", () => track().IsRunning); AddUntilStep("wait for track playing", () => MusicController.IsPlaying);
AddAssert("Ensure time wasn't reset to preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime); AddAssert("Ensure time wasn't reset to preview point", () => MusicController.CurrentTrackTime < beatmap().Metadata.PreviewTime);
} }
[Test] [Test]
public void TestMenuMakesMusic() public void TestMenuMakesMusic()
{ {
WorkingBeatmap beatmap() => Game.Beatmap.Value;
Track track() => beatmap().Track;
TestSongSelect songSelect = null; TestSongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestSongSelect()); PushAndConfirm(() => songSelect = new TestSongSelect());
AddUntilStep("wait for no track", () => track() is TrackVirtual); AddUntilStep("wait for no track", () => MusicController.IsDummyDevice);
AddStep("return to menu", () => songSelect.Exit()); AddStep("return to menu", () => songSelect.Exit());
AddUntilStep("wait for track", () => !(track() is TrackVirtual) && track().IsRunning); AddUntilStep("wait for track", () => !MusicController.IsDummyDevice && MusicController.IsPlaying);
} }
[Test] [Test]
@ -140,12 +135,12 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded); AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
AddStep("Seek close to end", () => AddStep("Seek close to end", () =>
{ {
Game.MusicController.SeekTo(Game.Beatmap.Value.Track.Length - 1000); Game.MusicController.SeekTo(MusicController.TrackLength - 1000);
Game.Beatmap.Value.Track.Completed += () => trackCompleted = true; // MusicController.Completed += () => trackCompleted = true;
}); });
AddUntilStep("Track was completed", () => trackCompleted); AddUntilStep("Track was completed", () => trackCompleted);
AddUntilStep("Track was restarted", () => Game.Beatmap.Value.Track.IsRunning); AddUntilStep("Track was restarted", () => MusicController.IsPlaying);
} }
private void pushEscape() => private void pushEscape() =>

View File

@ -71,6 +71,9 @@ namespace osu.Game.Tests.Visual.UserInterface
private readonly Box flashLayer; private readonly Box flashLayer;
[Resolved]
private MusicController musicController { get; set; }
public BeatContainer() public BeatContainer()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -165,7 +168,7 @@ namespace osu.Game.Tests.Visual.UserInterface
if (timingPoints.Count == 0) return 0; if (timingPoints.Count == 0) return 0;
if (timingPoints[^1] == current) if (timingPoints[^1] == current)
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength); return (int)Math.Ceiling((musicController.TrackLength - current.Time) / current.BeatLength);
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength); return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
} }

View File

@ -80,12 +80,12 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("Store track", () => currentBeatmap = Beatmap.Value); AddStep("Store track", () => currentBeatmap = Beatmap.Value);
AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000)); AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000));
AddUntilStep(@"Wait for current time to update", () => currentBeatmap.Track.CurrentTime > 5000); AddUntilStep(@"Wait for current time to update", () => musicController.CurrentTrackTime > 5000);
AddStep(@"Set previous", () => musicController.PreviousTrack()); AddStep(@"Set previous", () => musicController.PreviousTrack());
AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value); AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value);
AddUntilStep("Wait for current time to update", () => currentBeatmap.Track.CurrentTime < 5000); AddUntilStep("Wait for current time to update", () => musicController.CurrentTrackTime < 5000);
AddStep(@"Set previous", () => musicController.PreviousTrack()); AddStep(@"Set previous", () => musicController.PreviousTrack());
AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value); AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value);

View File

@ -255,7 +255,7 @@ namespace osu.Game.Beatmaps
new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager)); new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager));
} }
previous?.TransferTo(working); // previous?.TransferTo(working);
return working; return working;
} }
} }

View File

@ -79,22 +79,6 @@ namespace osu.Game.Beatmaps
} }
} }
public override void RecycleTrack()
{
base.RecycleTrack();
trackStore?.Dispose();
trackStore = null;
}
public override void TransferTo(WorkingBeatmap other)
{
base.TransferTo(other);
if (other is BeatmapManagerWorkingBeatmap owb && textureStore != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo))
owb.textureStore = textureStore;
}
protected override Waveform GetWaveform() protected override Waveform GetWaveform()
{ {
try try

View File

@ -26,11 +26,6 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
Texture Background { get; } Texture Background { get; }
/// <summary>
/// Retrieves the audio track for this <see cref="WorkingBeatmap"/>.
/// </summary>
Track Track { get; }
/// <summary> /// <summary>
/// Retrieves the <see cref="Waveform"/> for the <see cref="Track"/> of this <see cref="WorkingBeatmap"/>. /// Retrieves the <see cref="Waveform"/> for the <see cref="Track"/> of this <see cref="WorkingBeatmap"/>.
/// </summary> /// </summary>

View File

@ -40,7 +40,6 @@ namespace osu.Game.Beatmaps
BeatmapSetInfo = beatmapInfo.BeatmapSet; BeatmapSetInfo = beatmapInfo.BeatmapSet;
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
track = new RecyclableLazy<Track>(() => GetTrack() ?? GetVirtualTrack(1000));
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);
@ -250,10 +249,9 @@ namespace osu.Game.Beatmaps
protected abstract Texture GetBackground(); protected abstract Texture GetBackground();
private readonly RecyclableLazy<Texture> background; private readonly RecyclableLazy<Texture> background;
public virtual bool TrackLoaded => track.IsResultAvailable; public Track GetRealTrack() => GetTrack() ?? GetVirtualTrack(1000);
public Track Track => track.Value;
protected abstract Track GetTrack(); protected abstract Track GetTrack();
private RecyclableLazy<Track> track;
public bool WaveformLoaded => waveform.IsResultAvailable; public bool WaveformLoaded => waveform.IsResultAvailable;
public Waveform Waveform => waveform.Value; public Waveform Waveform => waveform.Value;
@ -271,22 +269,6 @@ namespace osu.Game.Beatmaps
protected virtual ISkin GetSkin() => new DefaultSkin(); protected virtual ISkin GetSkin() => new DefaultSkin();
private readonly RecyclableLazy<ISkin> skin; private readonly RecyclableLazy<ISkin> skin;
/// <summary>
/// Transfer pieces of a beatmap to a new one, where possible, to save on loading.
/// </summary>
/// <param name="other">The new beatmap which is being switched to.</param>
public virtual void TransferTo(WorkingBeatmap other)
{
if (track.IsResultAvailable && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
other.track = track;
}
/// <summary>
/// Eagerly dispose of the audio track associated with this <see cref="WorkingBeatmap"/> (if any).
/// Accessing track again will load a fresh instance.
/// </summary>
public virtual void RecycleTrack() => track.Recycle();
~WorkingBeatmap() ~WorkingBeatmap()
{ {
total_count.Value--; total_count.Value--;

View File

@ -7,6 +7,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
{ {
@ -14,6 +15,9 @@ namespace osu.Game.Graphics.Containers
{ {
protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
[Resolved]
private MusicController musicController { get; set; }
private int lastBeat; private int lastBeat;
private TimingControlPoint lastTimingPoint; private TimingControlPoint lastTimingPoint;
@ -47,22 +51,18 @@ namespace osu.Game.Graphics.Containers
protected override void Update() protected override void Update()
{ {
Track track = null;
IBeatmap beatmap = null; IBeatmap beatmap = null;
double currentTrackTime = 0; double currentTrackTime = 0;
TimingControlPoint timingPoint = null; TimingControlPoint timingPoint = null;
EffectControlPoint effectPoint = null; EffectControlPoint effectPoint = null;
if (Beatmap.Value.TrackLoaded && Beatmap.Value.BeatmapLoaded) if (musicController.TrackLoaded && Beatmap.Value.BeatmapLoaded)
{
track = Beatmap.Value.Track;
beatmap = Beatmap.Value.Beatmap; beatmap = Beatmap.Value.Beatmap;
}
if (track != null && beatmap != null && track.IsRunning && track.Length > 0) if (beatmap != null && musicController.IsPlaying && musicController.TrackLength > 0)
{ {
currentTrackTime = track.CurrentTime + EarlyActivationMilliseconds; currentTrackTime = musicController.CurrentTrackTime + EarlyActivationMilliseconds;
timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
@ -98,7 +98,7 @@ namespace osu.Game.Graphics.Containers
return; return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true)) using (BeginDelayedSequence(-TimeSinceLastBeat, true))
OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty); OnNewBeat(beatIndex, timingPoint, effectPoint, musicController.CurrentAmplitudes);
lastBeat = beatIndex; lastBeat = beatIndex;
lastTimingPoint = timingPoint; lastTimingPoint = timingPoint;

View File

@ -431,19 +431,19 @@ namespace osu.Game
if (newBeatmap != null) if (newBeatmap != null)
{ {
newBeatmap.Track.Completed += () => Scheduler.AddOnce(() => trackCompleted(newBeatmap)); // MusicController.Completed += () => Scheduler.AddOnce(() => trackCompleted(newBeatmap));
newBeatmap.BeginAsyncLoad(); newBeatmap.BeginAsyncLoad();
} }
void trackCompleted(WorkingBeatmap b) // void trackCompleted(WorkingBeatmap b)
{ // {
// the source of track completion is the audio thread, so the beatmap may have changed before firing. // // the source of track completion is the audio thread, so the beatmap may have changed before firing.
if (Beatmap.Value != b) // if (Beatmap.Value != b)
return; // return;
//
if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled) // if (!MusicController.Looping && !Beatmap.Disabled)
MusicController.NextTrack(); // MusicController.NextTrack();
} // }
} }
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods) private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
@ -555,6 +555,7 @@ namespace osu.Game
BackButton.Receptor receptor; BackButton.Receptor receptor;
dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); dependencies.CacheAs(idleTracker = new GameIdleTracker(6000));
dependencies.CacheAs(MusicController = new MusicController());
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
@ -617,7 +618,7 @@ namespace osu.Game
loadComponentSingleFile(new OnScreenDisplay(), Add, true); loadComponentSingleFile(new OnScreenDisplay(), Add, true);
loadComponentSingleFile(MusicController = new MusicController(), Add, true); loadComponentSingleFile(MusicController, Add);
loadComponentSingleFile(notifications.With(d => loadComponentSingleFile(notifications.With(d =>
{ {

View File

@ -238,16 +238,6 @@ namespace osu.Game
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap); Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
// ScheduleAfterChildren is safety against something in the current frame accessing the previous beatmap's track
// and potentially causing a reload of it after just unloading.
// Note that the reason for this being added *has* been resolved, so it may be feasible to removed this if required.
Beatmap.BindValueChanged(b => ScheduleAfterChildren(() =>
{
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
if (b.OldValue?.TrackLoaded == true && b.OldValue?.Track != b.NewValue?.Track)
b.OldValue.RecycleTrack();
}));
dependencies.CacheAs<IBindable<WorkingBeatmap>>(Beatmap); dependencies.CacheAs<IBindable<WorkingBeatmap>>(Beatmap);
dependencies.CacheAs(Beatmap); dependencies.CacheAs(Beatmap);

View File

@ -30,6 +30,9 @@ namespace osu.Game.Overlays.Music
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
[Resolved]
private MusicController musicController { get; set; }
private FilterControl filter; private FilterControl filter;
private Playlist list; private Playlist list;
@ -80,10 +83,7 @@ namespace osu.Game.Overlays.Music
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault(); BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
if (toSelect != null) if (toSelect != null)
{
beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect); beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect);
beatmap.Value.Track.Restart();
}
}; };
} }
@ -116,12 +116,12 @@ namespace osu.Game.Overlays.Music
{ {
if (set.ID == (beatmap.Value?.BeatmapSetInfo?.ID ?? -1)) if (set.ID == (beatmap.Value?.BeatmapSetInfo?.ID ?? -1))
{ {
beatmap.Value?.Track?.Seek(0); musicController.SeekTo(0);
return; return;
} }
beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First());
beatmap.Value.Track.Restart(); musicController.Play(true);
} }
} }

View File

@ -4,13 +4,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations;
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.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Overlays.OSD; using osu.Game.Overlays.OSD;
@ -21,7 +26,7 @@ namespace osu.Game.Overlays
/// <summary> /// <summary>
/// Handles playback of the global music track. /// Handles playback of the global music track.
/// </summary> /// </summary>
public class MusicController : Component, IKeyBindingHandler<GlobalAction> public class MusicController : CompositeDrawable, IKeyBindingHandler<GlobalAction>, ITrack
{ {
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
@ -61,9 +66,23 @@ namespace osu.Game.Overlays
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private OnScreenDisplay onScreenDisplay { get; set; } private OnScreenDisplay onScreenDisplay { get; set; }
[NotNull]
private readonly TrackContainer trackContainer;
[CanBeNull]
private DrawableTrack drawableTrack;
[CanBeNull]
private Track track;
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated; private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved; private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
public MusicController()
{
InternalChild = trackContainer = new TrackContainer { RelativeSizeAxes = Axes.Both };
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -95,9 +114,35 @@ namespace osu.Game.Overlays
} }
/// <summary> /// <summary>
/// Returns whether the current beatmap track is playing. /// Returns whether the beatmap track is playing.
/// </summary> /// </summary>
public bool IsPlaying => current?.Track.IsRunning ?? false; public bool IsPlaying => drawableTrack?.IsRunning ?? false;
/// <summary>
/// Returns whether the beatmap track is loaded.
/// </summary>
public bool TrackLoaded => drawableTrack?.IsLoaded == true;
/// <summary>
/// Returns the current time of the beatmap track.
/// </summary>
public double CurrentTrackTime => drawableTrack?.CurrentTime ?? 0;
/// <summary>
/// Returns the length of the beatmap track.
/// </summary>
public double TrackLength => drawableTrack?.Length ?? 0;
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
=> trackContainer.AddAdjustment(type, adjustBindable);
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
=> trackContainer.RemoveAdjustment(type, adjustBindable);
public void Reset() => drawableTrack?.Reset();
[CanBeNull]
public IAdjustableClock GetTrackClock() => track;
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet) private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
{ {
@ -130,7 +175,7 @@ namespace osu.Game.Overlays
seekDelegate = Schedule(() => seekDelegate = Schedule(() =>
{ {
if (!beatmap.Disabled) if (!beatmap.Disabled)
current?.Track.Seek(position); drawableTrack?.Seek(position);
}); });
} }
@ -142,9 +187,7 @@ namespace osu.Game.Overlays
{ {
if (IsUserPaused) return; if (IsUserPaused) return;
var track = current?.Track; if (drawableTrack == null || drawableTrack.IsDummyDevice)
if (track == null || track is TrackVirtual)
{ {
if (beatmap.Disabled) if (beatmap.Disabled)
return; return;
@ -163,17 +206,15 @@ namespace osu.Game.Overlays
/// <returns>Whether the operation was successful.</returns> /// <returns>Whether the operation was successful.</returns>
public bool Play(bool restart = false) public bool Play(bool restart = false)
{ {
var track = current?.Track;
IsUserPaused = false; IsUserPaused = false;
if (track == null) if (drawableTrack == null)
return false; return false;
if (restart) if (restart)
track.Restart(); drawableTrack.Restart();
else if (!IsPlaying) else if (!IsPlaying)
track.Start(); drawableTrack.Start();
return true; return true;
} }
@ -183,11 +224,9 @@ namespace osu.Game.Overlays
/// </summary> /// </summary>
public void Stop() public void Stop()
{ {
var track = current?.Track;
IsUserPaused = true; IsUserPaused = true;
if (track?.IsRunning == true) if (drawableTrack?.IsRunning == true)
track.Stop(); drawableTrack.Stop();
} }
/// <summary> /// <summary>
@ -196,9 +235,7 @@ namespace osu.Game.Overlays
/// <returns>Whether the operation was successful.</returns> /// <returns>Whether the operation was successful.</returns>
public bool TogglePause() public bool TogglePause()
{ {
var track = current?.Track; if (drawableTrack?.IsRunning == true)
if (track?.IsRunning == true)
Stop(); Stop();
else else
Play(); Play();
@ -220,7 +257,7 @@ namespace osu.Game.Overlays
if (beatmap.Disabled) if (beatmap.Disabled)
return PreviousTrackResult.None; return PreviousTrackResult.None;
var currentTrackPosition = current?.Track.CurrentTime; var currentTrackPosition = drawableTrack?.CurrentTime;
if (currentTrackPosition >= restart_cutoff_point) if (currentTrackPosition >= restart_cutoff_point)
{ {
@ -274,7 +311,7 @@ namespace osu.Game.Overlays
{ {
// if not scheduled, the previously track will be stopped one frame later (see ScheduleAfterChildren logic in GameBase). // if not scheduled, the previously track will be stopped one frame later (see ScheduleAfterChildren logic in GameBase).
// we probably want to move this to a central method for switching to a new working beatmap in the future. // we probably want to move this to a central method for switching to a new working beatmap in the future.
Schedule(() => beatmap.Value.Track.Restart()); Schedule(() => drawableTrack?.Restart());
} }
private WorkingBeatmap current; private WorkingBeatmap current;
@ -307,6 +344,14 @@ namespace osu.Game.Overlays
} }
current = beatmap.NewValue; current = beatmap.NewValue;
drawableTrack?.Expire();
drawableTrack = null;
track = null;
if (current != null)
trackContainer.Add(drawableTrack = new DrawableTrack(track = current.GetRealTrack()));
TrackChanged?.Invoke(current, direction); TrackChanged?.Invoke(current, direction);
ResetTrackAdjustments(); ResetTrackAdjustments();
@ -334,16 +379,15 @@ namespace osu.Game.Overlays
public void ResetTrackAdjustments() public void ResetTrackAdjustments()
{ {
var track = current?.Track; if (drawableTrack == null)
if (track == null)
return; return;
track.ResetSpeedAdjustments(); drawableTrack.ResetSpeedAdjustments();
if (allowRateAdjustments) if (allowRateAdjustments)
{ {
foreach (var mod in mods.Value.OfType<IApplicableToTrack>()) foreach (var mod in mods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(track); mod.ApplyToTrack(drawableTrack);
} }
} }
@ -394,6 +438,133 @@ namespace osu.Game.Overlays
{ {
} }
} }
private class TrackContainer : AudioContainer<DrawableTrack>
{
}
#region ITrack
/// <summary>
/// The volume of this component.
/// </summary>
public BindableNumber<double> Volume => drawableTrack?.Volume; // Todo: Bad
/// <summary>
/// The playback balance of this sample (-1 .. 1 where 0 is centered)
/// </summary>
public BindableNumber<double> Balance => drawableTrack?.Balance; // Todo: Bad
/// <summary>
/// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency.
/// </summary>
public BindableNumber<double> Frequency => drawableTrack?.Frequency; // Todo: Bad
/// <summary>
/// Rate at which the component is played back (does not affect pitch). 1 is 100% playback speed.
/// </summary>
public BindableNumber<double> Tempo => drawableTrack?.Tempo; // Todo: Bad
public IBindable<double> AggregateVolume => drawableTrack?.AggregateVolume; // Todo: Bad
public IBindable<double> AggregateBalance => drawableTrack?.AggregateBalance; // Todo: Bad
public IBindable<double> AggregateFrequency => drawableTrack?.AggregateFrequency; // Todo: Bad
public IBindable<double> AggregateTempo => drawableTrack?.AggregateTempo; // Todo: Bad
/// <summary>
/// Overall playback rate (1 is 100%, -1 is reversed at 100%).
/// </summary>
public double Rate => AggregateFrequency.Value * AggregateTempo.Value;
event Action ITrack.Completed
{
add
{
if (drawableTrack != null)
drawableTrack.Completed += value;
}
remove
{
if (drawableTrack != null)
drawableTrack.Completed -= value;
}
}
event Action ITrack.Failed
{
add
{
if (drawableTrack != null)
drawableTrack.Failed += value;
}
remove
{
if (drawableTrack != null)
drawableTrack.Failed -= value;
}
}
public bool Looping
{
get => drawableTrack?.Looping ?? false;
set
{
if (drawableTrack != null)
drawableTrack.Looping = value;
}
}
public bool IsDummyDevice => drawableTrack?.IsDummyDevice ?? true;
public double RestartPoint
{
get => drawableTrack?.RestartPoint ?? 0;
set
{
if (drawableTrack != null)
drawableTrack.RestartPoint = value;
}
}
double ITrack.CurrentTime => CurrentTrackTime;
double ITrack.Length
{
get => TrackLength;
set
{
if (drawableTrack != null)
drawableTrack.Length = value;
}
}
public int? Bitrate => drawableTrack?.Bitrate;
bool ITrack.IsRunning => IsPlaying;
public bool IsReversed => drawableTrack?.IsReversed ?? false;
public bool HasCompleted => drawableTrack?.HasCompleted ?? false;
void ITrack.Reset() => drawableTrack?.Reset();
void ITrack.Restart() => Play(true);
void ITrack.ResetSpeedAdjustments() => ResetTrackAdjustments();
bool ITrack.Seek(double seek)
{
SeekTo(seek);
return true;
}
void ITrack.Start() => Play();
public ChannelAmplitudes CurrentAmplitudes => drawableTrack?.CurrentAmplitudes ?? ChannelAmplitudes.Empty;
#endregion
} }
public enum TrackChangeDirection public enum TrackChangeDirection

View File

@ -234,14 +234,12 @@ namespace osu.Game.Overlays
pendingBeatmapSwitch = null; pendingBeatmapSwitch = null;
} }
var track = beatmap.Value?.TrackLoaded ?? false ? beatmap.Value.Track : null; if (musicController.IsDummyDevice == false)
if (track?.IsDummyDevice == false)
{ {
progressBar.EndTime = track.Length; progressBar.EndTime = musicController.TrackLength;
progressBar.CurrentTime = track.CurrentTime; progressBar.CurrentTime = musicController.CurrentTrackTime;
playButton.Icon = track.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle; playButton.Icon = musicController.IsPlaying ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle;
} }
else else
{ {

View File

@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Mods
/// </summary> /// </summary>
public interface IApplicableToTrack : IApplicableMod public interface IApplicableToTrack : IApplicableMod
{ {
void ApplyToTrack(Track track); void ApplyToTrack(ITrack track);
} }
} }

View File

@ -27,11 +27,11 @@ namespace osu.Game.Rulesets.Mods
}, true); }, true);
} }
public override void ApplyToTrack(Track track) public override void ApplyToTrack(ITrack track)
{ {
// base.ApplyToTrack() intentionally not called (different tempo adjustment is applied) // base.ApplyToTrack() intentionally not called (different tempo adjustment is applied)
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust); (track as Track)?.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust); (track as Track)?.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
} }
} }
} }

View File

@ -38,11 +38,11 @@ namespace osu.Game.Rulesets.Mods
}, true); }, true);
} }
public override void ApplyToTrack(Track track) public override void ApplyToTrack(ITrack track)
{ {
// base.ApplyToTrack() intentionally not called (different tempo adjustment is applied) // base.ApplyToTrack() intentionally not called (different tempo adjustment is applied)
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust); (track as Track)?.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust); (track as Track)?.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
} }
public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset) public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset)

View File

@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Mods
{ {
public abstract BindableNumber<double> SpeedChange { get; } public abstract BindableNumber<double> SpeedChange { get; }
public virtual void ApplyToTrack(Track track) public virtual void ApplyToTrack(ITrack track)
{ {
track.AddAdjustment(AdjustableProperty.Tempo, SpeedChange); (track as Track)?.AddAdjustment(AdjustableProperty.Tempo, SpeedChange);
} }
public virtual void ApplyToSample(SampleChannel sample) public virtual void ApplyToSample(SampleChannel sample)

View File

@ -51,9 +51,9 @@ namespace osu.Game.Rulesets.Mods
AdjustPitch.BindValueChanged(applyPitchAdjustment); AdjustPitch.BindValueChanged(applyPitchAdjustment);
} }
public void ApplyToTrack(Track track) public void ApplyToTrack(ITrack track)
{ {
this.track = track; this.track = track as Track;
FinalRate.TriggerChange(); FinalRate.TriggerChange();
AdjustPitch.TriggerChange(); AdjustPitch.TriggerChange();

View File

@ -2,7 +2,6 @@
// 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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
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;
@ -18,7 +17,6 @@ namespace osu.Game.Screens.Edit.Components
private const float contents_padding = 15; private const float contents_padding = 15;
protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected Track Track => Beatmap.Value.Track;
private readonly Drawable background; private readonly Drawable background;
private readonly Container content; private readonly Container content;

View File

@ -16,6 +16,7 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osuTK.Input; using osuTK.Input;
namespace osu.Game.Screens.Edit.Components namespace osu.Game.Screens.Edit.Components
@ -27,6 +28,9 @@ namespace osu.Game.Screens.Edit.Components
[Resolved] [Resolved]
private EditorClock editorClock { get; set; } private EditorClock editorClock { get; set; }
[Resolved]
private MusicController musicController { get; set; }
private readonly BindableNumber<double> tempo = new BindableDouble(1); private readonly BindableNumber<double> tempo = new BindableDouble(1);
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -62,12 +66,12 @@ namespace osu.Game.Screens.Edit.Components
} }
}; };
Track?.AddAdjustment(AdjustableProperty.Tempo, tempo); musicController.AddAdjustment(AdjustableProperty.Tempo, tempo);
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
Track?.RemoveAdjustment(AdjustableProperty.Tempo, tempo); musicController?.RemoveAdjustment(AdjustableProperty.Tempo, tempo);
base.Dispose(isDisposing); base.Dispose(isDisposing);
} }

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.Diagnostics;
using osuTK; using osuTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -58,7 +59,9 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
return; return;
float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
editorClock.SeekTo(markerPos / DrawWidth * editorClock.TrackLength);
Debug.Assert(editorClock.TrackLength != null);
editorClock.SeekTo(markerPos / DrawWidth * editorClock.TrackLength.Value);
}); });
} }

View File

@ -8,6 +8,7 @@ using osuTK;
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.Beatmaps;
using osu.Game.Overlays;
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
{ {
@ -26,6 +27,9 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
protected override Container<T> Content => content; protected override Container<T> Content => content;
[Resolved]
private MusicController musicController { get; set; }
public TimelinePart(Container<T> content = null) public TimelinePart(Container<T> content = null)
{ {
AddInternal(this.content = content ?? new Container<T> { RelativeSizeAxes = Axes.Both }); AddInternal(this.content = content ?? new Container<T> { RelativeSizeAxes = Axes.Both });
@ -46,14 +50,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
private void updateRelativeChildSize() private void updateRelativeChildSize()
{ {
// the track may not be loaded completely (only has a length once it is). // the track may not be loaded completely (only has a length once it is).
if (!Beatmap.Value.Track.IsLoaded) if (!musicController.TrackLoaded)
{ {
content.RelativeChildSize = Vector2.One; content.RelativeChildSize = Vector2.One;
Schedule(updateRelativeChildSize); Schedule(updateRelativeChildSize);
return; return;
} }
content.RelativeChildSize = new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1); content.RelativeChildSize = new Vector2((float)Math.Max(1, musicController.TrackLength), 1);
} }
protected virtual void LoadBeatmap(WorkingBeatmap beatmap) protected virtual void LoadBeatmap(WorkingBeatmap beatmap)

View File

@ -3,7 +3,6 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -11,6 +10,7 @@ using osu.Framework.Graphics.Audio;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osuTK; using osuTK;
@ -26,6 +26,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
[Resolved] [Resolved]
private EditorClock editorClock { get; set; } private EditorClock editorClock { get; set; }
[Resolved]
private MusicController musicController { get; set; }
public Timeline() public Timeline()
{ {
ZoomDuration = 200; ZoomDuration = 200;
@ -57,18 +60,21 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
Beatmap.BindValueChanged(b => Beatmap.BindValueChanged(b =>
{ {
waveform.Waveform = b.NewValue.Waveform; waveform.Waveform = b.NewValue.Waveform;
track = b.NewValue.Track;
if (track.Length > 0) // Todo: Wrong.
Schedule(() =>
{ {
MaxZoom = getZoomLevelForVisibleMilliseconds(500); if (musicController.TrackLength > 0)
MinZoom = getZoomLevelForVisibleMilliseconds(10000); {
Zoom = getZoomLevelForVisibleMilliseconds(2000); MaxZoom = getZoomLevelForVisibleMilliseconds(500);
} MinZoom = getZoomLevelForVisibleMilliseconds(10000);
Zoom = getZoomLevelForVisibleMilliseconds(2000);
}
});
}, true); }, true);
} }
private float getZoomLevelForVisibleMilliseconds(double milliseconds) => (float)(track.Length / milliseconds); private float getZoomLevelForVisibleMilliseconds(double milliseconds) => (float)(musicController.TrackLength / milliseconds);
/// <summary> /// <summary>
/// The timeline's scroll position in the last frame. /// The timeline's scroll position in the last frame.
@ -90,8 +96,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
/// </summary> /// </summary>
private bool trackWasPlaying; private bool trackWasPlaying;
private Track track;
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -129,18 +133,18 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
private void seekTrackToCurrent() private void seekTrackToCurrent()
{ {
if (!track.IsLoaded) if (!musicController.TrackLoaded)
return; return;
editorClock.Seek(Current / Content.DrawWidth * track.Length); editorClock.Seek(Current / Content.DrawWidth * musicController.TrackLength);
} }
private void scrollToTrackTime() private void scrollToTrackTime()
{ {
if (!track.IsLoaded || track.Length == 0) if (!musicController.TrackLoaded || musicController.TrackLength == 0)
return; return;
ScrollTo((float)(editorClock.CurrentTime / track.Length) * Content.DrawWidth, false); ScrollTo((float)(editorClock.CurrentTime / musicController.TrackLength) * Content.DrawWidth, false);
} }
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
@ -184,7 +188,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition)))); new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition))));
private double getTimeFromPosition(Vector2 localPosition) => private double getTimeFromPosition(Vector2 localPosition) =>
(localPosition.X / Content.DrawWidth) * track.Length; (localPosition.X / Content.DrawWidth) * musicController.TrackLength;
public float GetBeatSnapDistanceAt(double referenceTime) => throw new NotImplementedException(); public float GetBeatSnapDistanceAt(double referenceTime) => throw new NotImplementedException();

View File

@ -3,10 +3,9 @@
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations; using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations;
@ -18,7 +17,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
private EditorBeatmap beatmap { get; set; } private EditorBeatmap beatmap { get; set; }
[Resolved] [Resolved]
private Bindable<WorkingBeatmap> working { get; set; } private MusicController musicController { get; set; }
[Resolved] [Resolved]
private BindableBeatDivisor beatDivisor { get; set; } private BindableBeatDivisor beatDivisor { get; set; }
@ -44,7 +43,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
for (var i = 0; i < beatmap.ControlPointInfo.TimingPoints.Count; i++) for (var i = 0; i < beatmap.ControlPointInfo.TimingPoints.Count; i++)
{ {
var point = beatmap.ControlPointInfo.TimingPoints[i]; var point = beatmap.ControlPointInfo.TimingPoints[i];
var until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : working.Value.Track.Length; var until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : musicController.TrackLength;
int beat = 0; int beat = 0;

View File

@ -28,6 +28,7 @@ using osu.Framework.Logging;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose;
using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Edit.Setup;
@ -53,6 +54,9 @@ namespace osu.Game.Screens.Edit
[Resolved] [Resolved]
private BeatmapManager beatmapManager { get; set; } private BeatmapManager beatmapManager { get; set; }
[Resolved]
private MusicController musicController { get; set; }
private Box bottomBackground; private Box bottomBackground;
private Container screenContainer; private Container screenContainer;
@ -79,7 +83,7 @@ namespace osu.Game.Screens.Edit
beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue); beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue);
// Todo: should probably be done at a DrawableRuleset level to share logic with Player. // Todo: should probably be done at a DrawableRuleset level to share logic with Player.
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock(); var sourceClock = musicController.GetTrackClock() ?? new StopwatchClock();
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false }; clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
clock.ChangeSource(sourceClock); clock.ChangeSource(sourceClock);
@ -346,7 +350,7 @@ namespace osu.Game.Screens.Edit
private void resetTrack(bool seekToStart = false) private void resetTrack(bool seekToStart = false)
{ {
Beatmap.Value.Track?.Stop(); musicController.Stop();
if (seekToStart) if (seekToStart)
{ {

View File

@ -2,13 +2,16 @@
// 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.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms; using osu.Framework.Graphics.Transforms;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Framework.Timing; 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.Overlays;
namespace osu.Game.Screens.Edit namespace osu.Game.Screens.Edit
{ {
@ -17,7 +20,7 @@ namespace osu.Game.Screens.Edit
/// </summary> /// </summary>
public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock
{ {
public readonly double TrackLength; public double? TrackLength { get; private set; }
public ControlPointInfo ControlPointInfo; public ControlPointInfo ControlPointInfo;
@ -25,12 +28,15 @@ namespace osu.Game.Screens.Edit
private readonly DecoupleableInterpolatingFramedClock underlyingClock; private readonly DecoupleableInterpolatingFramedClock underlyingClock;
[Resolved]
private MusicController musicController { get; set; }
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor) public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
: this(beatmap.Beatmap.ControlPointInfo, beatmap.Track.Length, beatDivisor) : this(beatmap.Beatmap.ControlPointInfo, null, beatDivisor)
{ {
} }
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor) public EditorClock(ControlPointInfo controlPointInfo, double? trackLength, BindableBeatDivisor beatDivisor)
{ {
this.beatDivisor = beatDivisor; this.beatDivisor = beatDivisor;
@ -45,6 +51,13 @@ namespace osu.Game.Screens.Edit
{ {
} }
[BackgroundDependencyLoader]
private void load()
{
// Todo: What.
TrackLength ??= musicController.TrackLength;
}
/// <summary> /// <summary>
/// Seek to the closest snappable beat from a time. /// Seek to the closest snappable beat from a time.
/// </summary> /// </summary>
@ -135,7 +148,8 @@ namespace osu.Game.Screens.Edit
seekTime = timingPoint.Time; seekTime = timingPoint.Time;
// Ensure the sought point is within the boundaries // Ensure the sought point is within the boundaries
seekTime = Math.Clamp(seekTime, 0, TrackLength); Debug.Assert(TrackLength != null);
seekTime = Math.Clamp(seekTime, 0, TrackLength.Value);
SeekTo(seekTime); SeekTo(seekTime);
} }

View File

@ -12,6 +12,7 @@ using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.IO.Archives; using osu.Game.IO.Archives;
using osu.Game.Overlays;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
@ -43,7 +44,8 @@ namespace osu.Game.Screens.Menu
private WorkingBeatmap initialBeatmap; private WorkingBeatmap initialBeatmap;
protected Track Track => initialBeatmap?.Track; [Resolved]
protected MusicController MusicController { get; private set; }
private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); private readonly BindableDouble exitingVolumeFade = new BindableDouble(1);
@ -111,7 +113,7 @@ namespace osu.Game.Screens.Menu
if (setInfo != null) if (setInfo != null)
{ {
initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
UsingThemedIntro = !(Track is TrackVirtual); UsingThemedIntro = !MusicController.IsDummyDevice;
} }
return UsingThemedIntro; return UsingThemedIntro;
@ -150,7 +152,7 @@ namespace osu.Game.Screens.Menu
{ {
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu.
if (UsingThemedIntro) if (UsingThemedIntro)
Track.Restart(); MusicController.Play(true);
} }
protected override void LogoArriving(OsuLogo logo, bool resuming) protected override void LogoArriving(OsuLogo logo, bool resuming)

View File

@ -59,7 +59,7 @@ namespace osu.Game.Screens.Menu
LoadComponentAsync(new TrianglesIntroSequence(logo, background) LoadComponentAsync(new TrianglesIntroSequence(logo, background)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Clock = new FramedClock(UsingThemedIntro ? Track : null), Clock = new FramedClock(UsingThemedIntro ? MusicController.GetTrackClock() : null),
LoadMenu = LoadMenu LoadMenu = LoadMenu
}, t => }, t =>
{ {

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Overlays;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osuTK.Graphics; using osuTK.Graphics;
@ -30,6 +31,9 @@ namespace osu.Game.Screens.Menu
Alpha = 0, Alpha = 0,
}; };
[Resolved]
private MusicController musicController { get; set; }
private BackgroundScreenDefault background; private BackgroundScreenDefault background;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -40,7 +44,7 @@ namespace osu.Game.Screens.Menu
pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano"); pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano");
Track.Looping = true; musicController.Looping = true;
} }
protected override void LogoArriving(OsuLogo logo, bool resuming) protected override void LogoArriving(OsuLogo logo, bool resuming)

View File

@ -20,6 +20,7 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Overlays;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
@ -74,6 +75,9 @@ namespace osu.Game.Screens.Menu
/// </summary> /// </summary>
public float Magnitude { get; set; } = 1; public float Magnitude { get; set; } = 1;
[Resolved]
private MusicController musicController { get; set; }
private readonly float[] frequencyAmplitudes = new float[256]; private readonly float[] frequencyAmplitudes = new float[256];
private IShader shader; private IShader shader;
@ -103,15 +107,15 @@ namespace osu.Game.Screens.Menu
private void updateAmplitudes() private void updateAmplitudes()
{ {
var effect = beatmap.Value.BeatmapLoaded && beatmap.Value.TrackLoaded var effect = beatmap.Value.BeatmapLoaded && musicController.TrackLoaded
? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(beatmap.Value.Track.CurrentTime) ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(musicController.CurrentTrackTime)
: null; : null;
for (int i = 0; i < temporalAmplitudes.Length; i++) for (int i = 0; i < temporalAmplitudes.Length; i++)
temporalAmplitudes[i] = 0; temporalAmplitudes[i] = 0;
if (beatmap.Value.TrackLoaded) if (musicController.TrackLoaded)
addAmplitudesFromSource(beatmap.Value.Track); addAmplitudesFromSource(musicController);
foreach (var source in amplitudeSources) foreach (var source in amplitudeSources)
addAmplitudesFromSource(source); addAmplitudesFromSource(source);

View File

@ -5,7 +5,6 @@ using System.Linq;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Platform; using osu.Framework.Platform;
@ -62,8 +61,6 @@ namespace osu.Game.Screens.Menu
protected override BackgroundScreen CreateBackground() => background; protected override BackgroundScreen CreateBackground() => background;
internal Track Track { get; private set; }
private Bindable<float> holdDelay; private Bindable<float> holdDelay;
private Bindable<bool> loginDisplayed; private Bindable<bool> loginDisplayed;
@ -172,20 +169,23 @@ namespace osu.Game.Screens.Menu
[Resolved] [Resolved]
private Storage storage { get; set; } private Storage storage { get; set; }
[Resolved]
private MusicController musicController { get; set; }
public override void OnEntering(IScreen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
buttons.FadeInFromZero(500); buttons.FadeInFromZero(500);
Track = Beatmap.Value.Track;
var metadata = Beatmap.Value.Metadata; var metadata = Beatmap.Value.Metadata;
if (last is IntroScreen && Track != null) if (last is IntroScreen && musicController.TrackLoaded)
{ {
if (!Track.IsRunning) // Todo: Wrong.
if (!musicController.IsPlaying)
{ {
Track.Seek(metadata.PreviewTime != -1 ? metadata.PreviewTime : 0.4f * Track.Length); musicController.SeekTo(metadata.PreviewTime != -1 ? metadata.PreviewTime : 0.4f * musicController.TrackLength);
Track.Start(); musicController.Play();
} }
} }

View File

@ -17,6 +17,7 @@ using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input; using osuTK.Input;
@ -46,7 +47,6 @@ namespace osu.Game.Screens.Menu
private SampleChannel sampleBeat; private SampleChannel sampleBeat;
private readonly Container colourAndTriangles; private readonly Container colourAndTriangles;
private readonly Triangles triangles; private readonly Triangles triangles;
/// <summary> /// <summary>
@ -319,6 +319,9 @@ namespace osu.Game.Screens.Menu
intro.Delay(length + fade).FadeOut(); intro.Delay(length + fade).FadeOut();
} }
[Resolved]
private MusicController musicController { get; set; }
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -327,9 +330,9 @@ namespace osu.Game.Screens.Menu
const float velocity_adjust_cutoff = 0.98f; const float velocity_adjust_cutoff = 0.98f;
const float paused_velocity = 0.5f; const float paused_velocity = 0.5f;
if (Beatmap.Value.Track.IsRunning) if (musicController.IsPlaying)
{ {
var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value.Track.CurrentAmplitudes.Maximum : 0; var maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentAmplitudes.Maximum : 0;
logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed)); logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed));
if (maxAmplitude > velocity_adjust_cutoff) if (maxAmplitude > velocity_adjust_cutoff)

View File

@ -10,6 +10,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Overlays;
namespace osu.Game.Screens.Multi.Match.Components namespace osu.Game.Screens.Multi.Match.Components
{ {
@ -26,6 +27,9 @@ namespace osu.Game.Screens.Multi.Match.Components
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
[Resolved]
private MusicController musicController { get; set; }
private bool hasBeatmap; private bool hasBeatmap;
public ReadyButton() public ReadyButton()
@ -100,7 +104,7 @@ namespace osu.Game.Screens.Multi.Match.Components
return; return;
} }
bool hasEnoughTime = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(gameBeatmap.Value.Track.Length) < endDate.Value; bool hasEnoughTime = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(musicController.TrackLength) < endDate.Value;
Enabled.Value = hasBeatmap && hasEnoughTime; Enabled.Value = hasBeatmap && hasEnoughTime;
} }

View File

@ -52,7 +52,7 @@ namespace osu.Game.Screens.Multi
private readonly Bindable<FilterCriteria> currentFilter = new Bindable<FilterCriteria>(new FilterCriteria()); private readonly Bindable<FilterCriteria> currentFilter = new Bindable<FilterCriteria>(new FilterCriteria());
[Resolved] [Resolved]
private MusicController music { get; set; } private MusicController musicController { get; set; }
[Cached(Type = typeof(IRoomManager))] [Cached(Type = typeof(IRoomManager))]
private RoomManager roomManager; private RoomManager roomManager;
@ -343,15 +343,9 @@ namespace osu.Game.Screens.Multi
{ {
if (screenStack.CurrentScreen is MatchSubScreen) if (screenStack.CurrentScreen is MatchSubScreen)
{ {
var track = Beatmap.Value?.Track; musicController.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
musicController.Looping = true;
if (track != null) musicController.EnsurePlayingSomething();
{
track.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
track.Looping = true;
music.EnsurePlayingSomething();
}
} }
else else
{ {
@ -361,13 +355,8 @@ namespace osu.Game.Screens.Multi
private void cancelLooping() private void cancelLooping()
{ {
var track = Beatmap?.Value?.Track; musicController.Looping = false;
musicController.RestartPoint = 0;
if (track != null)
{
track.Looping = false;
track.RestartPoint = 0;
}
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -8,10 +8,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -30,12 +30,13 @@ namespace osu.Game.Screens.Play
private readonly BindableDouble trackFreq = new BindableDouble(1); private readonly BindableDouble trackFreq = new BindableDouble(1);
private Track track;
private const float duration = 2500; private const float duration = 2500;
private SampleChannel failSample; private SampleChannel failSample;
[Resolved]
private MusicController musicController { get; set; }
public FailAnimation(DrawableRuleset drawableRuleset) public FailAnimation(DrawableRuleset drawableRuleset)
{ {
this.drawableRuleset = drawableRuleset; this.drawableRuleset = drawableRuleset;
@ -44,7 +45,6 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap) private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap)
{ {
track = beatmap.Value.Track;
failSample = audio.Samples.Get(@"Gameplay/failsound"); failSample = audio.Samples.Get(@"Gameplay/failsound");
} }
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Play
Expire(); Expire();
}); });
track.AddAdjustment(AdjustableProperty.Frequency, trackFreq); musicController.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
applyToPlayfield(drawableRuleset.Playfield); applyToPlayfield(drawableRuleset.Playfield);
drawableRuleset.Playfield.HitObjectContainer.FlashColour(Color4.Red, 500); drawableRuleset.Playfield.HitObjectContainer.FlashColour(Color4.Red, 500);
@ -107,7 +107,7 @@ namespace osu.Game.Screens.Play
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq); musicController?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
} }
} }
} }

View File

@ -8,13 +8,13 @@ using System.Threading.Tasks;
using osu.Framework; using osu.Framework;
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; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Overlays;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
@ -27,10 +27,8 @@ namespace osu.Game.Screens.Play
private readonly WorkingBeatmap beatmap; private readonly WorkingBeatmap beatmap;
private readonly IReadOnlyList<Mod> mods; private readonly IReadOnlyList<Mod> mods;
/// <summary> [Resolved]
/// The <see cref="WorkingBeatmap"/>'s track. private MusicController musicController { get; set; }
/// </summary>
private Track track;
public readonly BindableBool IsPaused = new BindableBool(); public readonly BindableBool IsPaused = new BindableBool();
@ -72,8 +70,6 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
track = beatmap.Track;
adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
// Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited.
@ -125,15 +121,15 @@ namespace osu.Game.Screens.Play
{ {
// The Reset() call below causes speed adjustments to be reset in an async context, leading to deadlocks. // The Reset() call below causes speed adjustments to be reset in an async context, leading to deadlocks.
// The deadlock can be prevented by resetting the track synchronously before entering the async context. // The deadlock can be prevented by resetting the track synchronously before entering the async context.
track.ResetSpeedAdjustments(); musicController.Reset();
Task.Run(() => Task.Run(() =>
{ {
track.Reset(); musicController.Reset();
Schedule(() => Schedule(() =>
{ {
adjustableClock.ChangeSource(track); adjustableClock.ChangeSource(musicController.GetTrackClock());
updateRate(); updateRate();
if (!IsPaused.Value) if (!IsPaused.Value)
@ -194,20 +190,6 @@ namespace osu.Game.Screens.Play
IsPaused.Value = true; IsPaused.Value = true;
} }
/// <summary>
/// Changes the backing clock to avoid using the originally provided beatmap's track.
/// </summary>
public void StopUsingBeatmapClock()
{
if (track != beatmap.Track)
return;
removeSourceClockAdjustments();
track = new TrackVirtual(beatmap.Track.Length);
adjustableClock.ChangeSource(track);
}
protected override void Update() protected override void Update()
{ {
if (!IsPaused.Value) if (!IsPaused.Value)
@ -220,31 +202,23 @@ namespace osu.Game.Screens.Play
private void updateRate() private void updateRate()
{ {
if (track == null) return;
speedAdjustmentsApplied = true; speedAdjustmentsApplied = true;
track.ResetSpeedAdjustments(); musicController.ResetTrackAdjustments();
musicController.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); musicController.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
foreach (var mod in mods.OfType<IApplicableToTrack>())
mod.ApplyToTrack(track);
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
removeSourceClockAdjustments(); removeSourceClockAdjustments();
track = null;
} }
private void removeSourceClockAdjustments() private void removeSourceClockAdjustments()
{ {
if (speedAdjustmentsApplied) if (speedAdjustmentsApplied)
{ {
track.ResetSpeedAdjustments(); musicController.ResetTrackAdjustments();
speedAdjustmentsApplied = false; speedAdjustmentsApplied = false;
} }
} }

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
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;
@ -561,8 +560,11 @@ namespace osu.Game.Screens.Select
BeatmapDetails.Refresh(); BeatmapDetails.Refresh();
Beatmap.Value.Track.Looping = true; if (music != null)
music?.ResetTrackAdjustments(); {
music.Looping = true;
music.ResetTrackAdjustments();
}
if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
{ {
@ -586,8 +588,8 @@ namespace osu.Game.Screens.Select
BeatmapOptions.Hide(); BeatmapOptions.Hide();
if (Beatmap.Value.Track != null) if (music != null)
Beatmap.Value.Track.Looping = false; music.Looping = false;
this.ScaleTo(1.1f, 250, Easing.InSine); this.ScaleTo(1.1f, 250, Easing.InSine);
@ -608,8 +610,8 @@ namespace osu.Game.Screens.Select
FilterControl.Deactivate(); FilterControl.Deactivate();
if (Beatmap.Value.Track != null) if (music != null)
Beatmap.Value.Track.Looping = false; music.Looping = false;
return false; return false;
} }
@ -650,28 +652,18 @@ namespace osu.Game.Screens.Select
BeatmapDetails.Beatmap = beatmap; BeatmapDetails.Beatmap = beatmap;
if (beatmap.Track != null) if (music != null)
beatmap.Track.Looping = true; music.Looping = false;
} }
private readonly WeakReference<Track> lastTrack = new WeakReference<Track>(null);
/// <summary> /// <summary>
/// Ensures some music is playing for the current track. /// Ensures some music is playing for the current track.
/// Will resume playback from a manual user pause if the track has changed. /// Will resume playback from a manual user pause if the track has changed.
/// </summary> /// </summary>
private void ensurePlayingSelected() private void ensurePlayingSelected()
{ {
Track track = Beatmap.Value.Track; music.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
music.EnsurePlayingSomething();
bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track;
track.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack))
music?.Play(true);
lastTrack.SetTarget(track);
} }
private void carouselBeatmapsLoaded() private void carouselBeatmapsLoaded()

View File

@ -27,8 +27,6 @@ namespace osu.Game.Tests.Beatmaps
this.storyboard = storyboard; this.storyboard = storyboard;
} }
public override bool TrackLoaded => true;
public override bool BeatmapLoaded => true; public override bool BeatmapLoaded => true;
protected override IBeatmap GetBeatmap() => beatmap; protected override IBeatmap GetBeatmap() => beatmap;

View File

@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e) private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e)
{ {
Clock.ControlPointInfo = e.NewValue.Beatmap.ControlPointInfo; Clock.ControlPointInfo = e.NewValue.Beatmap.ControlPointInfo;
Clock.ChangeSource((IAdjustableClock)e.NewValue.Track ?? new StopwatchClock()); Clock.ChangeSource(MusicController.GetTrackClock() ?? new StopwatchClock());
Clock.ProcessFrame(); Clock.ProcessFrame();
} }

View File

@ -20,6 +20,7 @@ using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -135,6 +136,9 @@ namespace osu.Game.Tests.Visual
[Resolved] [Resolved]
protected AudioManager Audio { get; private set; } protected AudioManager Audio { get; private set; }
[Resolved]
protected MusicController MusicController { get; private set; }
/// <summary> /// <summary>
/// Creates the ruleset to be used for this test scene. /// Creates the ruleset to be used for this test scene.
/// </summary> /// </summary>
@ -164,8 +168,8 @@ namespace osu.Game.Tests.Visual
rulesetDependencies?.Dispose(); rulesetDependencies?.Dispose();
if (Beatmap?.Value.TrackLoaded == true) if (MusicController?.TrackLoaded == true)
Beatmap.Value.Track.Stop(); MusicController.Stop();
if (contextFactory.IsValueCreated) if (contextFactory.IsValueCreated)
contextFactory.Value.ResetDatabase(); contextFactory.Value.ResetDatabase();

View File

@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual
base.Update(); base.Update();
// note that this will override any mod rate application // note that this will override any mod rate application
Beatmap.Value.Track.Tempo.Value = Clock.Rate; MusicController.Tempo.Value = Clock.Rate;
} }
} }
} }