1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 14:32:55 +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
{
BeatmapInfo = new BeatmapInfo
{
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
{
BeatmapInfo = new BeatmapInfo
{
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
{
BeatmapInfo = new BeatmapInfo
{
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);
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo =
{
Ruleset = ruleset.RulesetInfo,
Ruleset = ruleset,
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
{
BeatmapInfo = new BeatmapInfo
{
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.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK;
@ -299,7 +298,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
AddStep("load player", () =>
{
Beatmap.Value = new TestWorkingBeatmap(new Beatmap<OsuHitObject>
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
{
HitObjects =
{
@ -323,7 +322,7 @@ namespace osu.Game.Rulesets.Osu.Tests
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
Ruleset = new OsuRuleset().RulesetInfo
},
}, Clock);
});
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.Drawables;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK;
using osu.Game.Rulesets.Scoring;
@ -64,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
var controlPointInfo = new ControlPointInfo();
controlPointInfo.TimingPoints.Add(new TimingControlPoint());
WorkingBeatmap beatmap = new TestWorkingBeatmap(new Beatmap
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
{
HitObjects = new List<HitObject> { new CentreHit() },
BeatmapInfo = new BeatmapInfo
@ -79,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Ruleset = new TaikoRuleset().RulesetInfo
},
ControlPointInfo = controlPointInfo
}, Clock);
});
Add(playfieldContainer = new Container
{

View File

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

View File

@ -111,16 +111,19 @@ namespace osu.Game.Tests.Visual.Components
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
{
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager)
private readonly ITrackStore trackManager;
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore 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.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Compose;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Editor
{
@ -19,7 +18,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, Clock);
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Child = new ComposeScreen();
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -30,9 +31,9 @@ namespace osu.Game.Tests.Visual.Editor
};
[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audio)
{
Beatmap.Value = new WaveformTestBeatmap();
Beatmap.Value = new WaveformTestBeatmap(audio);
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.
using NUnit.Framework;
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps;
using osuTK;
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 };
}

View File

@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@ -21,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null);
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
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.Screens.Edit.Compose;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@ -45,7 +44,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new TestWorkingBeatmap(new Beatmap
Beatmap.Value = CreateWorkingBeatmap(new Beatmap
{
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.
using NUnit.Framework;
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Components;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Editor
Size = new Vector2(200, 100)
};
Beatmap.Value = new TestWorkingBeatmap(new Beatmap(), Clock);
Beatmap.Value = CreateWorkingBeatmap(new Beatmap());
Child = playback;
}

View File

@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
@ -10,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor
@ -20,9 +22,9 @@ namespace osu.Game.Tests.Visual.Editor
private WorkingBeatmap waveformBeatmap;
[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audio)
{
waveformBeatmap = new WaveformTestBeatmap();
waveformBeatmap = new WaveformTestBeatmap(audio);
}
[TestCase(1f)]
@ -91,7 +93,7 @@ namespace osu.Game.Tests.Visual.Editor
Child = graph = new TestWaveformGraph
{
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.
using System;
@ -16,7 +16,6 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Gameplay
{
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public void Setup() => Schedule(() =>
{
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]

View File

@ -3,7 +3,6 @@
using System;
using osu.Framework.Lists;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
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);
return working;
}

View File

@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
@ -57,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name");
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);
AddStep("clear name", () => Room.Name.Value = "");

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Online
@ -25,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online
[BackgroundDependencyLoader]
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.HasStoryboard = true;

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
@ -18,7 +19,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BeatmapDetails) };
public TestSceneBeatmapDetailArea()
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
BeatmapDetailArea detailsArea;
Add(detailsArea = new BeatmapDetailArea
@ -28,7 +30,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Size = new Vector2(550f, 450f),
});
AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap
AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
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 =
{
@ -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 =
{
@ -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 =
{
@ -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 =
{

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.
using System.Collections.Generic;
@ -18,7 +18,6 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
@ -136,7 +135,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () =>
{
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);

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.MathUtils;
@ -79,7 +80,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
[BackgroundDependencyLoader]
private void load(GameHost host)
private void load(GameHost host, AudioManager audio)
{
factory = new DatabaseContextFactory(LocalStorage);
factory.ResetDatabase();
@ -93,7 +94,7 @@ namespace osu.Game.Tests.Visual.SongSelect
usage.Migrate();
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();
}

View File

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

View File

@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
@ -19,12 +20,14 @@ namespace osu.Game.Tests
{
private readonly ZipArchiveReader reader;
private readonly Stream stream;
private readonly ITrackStore trackStore;
public WaveformTestBeatmap()
: base(new BeatmapInfo())
public WaveformTestBeatmap(AudioManager audioManager)
: base(new BeatmapInfo(), audioManager)
{
stream = TestResources.GetTestBeatmapStream();
reader = new ZipArchiveReader(stream);
trackStore = audioManager.GetTrackStore(reader);
}
public override void Dispose()
@ -32,17 +35,19 @@ namespace osu.Game.Tests
base.Dispose();
stream?.Dispose();
reader?.Dispose();
trackStore?.Dispose();
}
protected override IBeatmap GetBeatmap() => createTestBeatmap();
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 Beatmap createTestBeatmap()

View File

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

View File

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

View File

@ -20,14 +20,12 @@ namespace osu.Game.Beatmaps
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
{
private readonly IResourceStore<byte[]> store;
private readonly AudioManager audioManager;
public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, TextureStore textureStore, BeatmapInfo beatmapInfo, AudioManager audioManager)
: base(beatmapInfo)
: base(beatmapInfo, audioManager)
{
this.store = store;
this.textureStore = textureStore;
this.audioManager = audioManager;
}
protected override IBeatmap GetBeatmap()
@ -47,6 +45,8 @@ namespace osu.Game.Beatmaps
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 Texture GetBackground()
@ -68,8 +68,7 @@ namespace osu.Game.Beatmaps
{
try
{
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new TrackBass(trackData);
return (trackStore ?? (trackStore = AudioManager.GetTrackStore(store))).Get(getPathForFile(Metadata.AudioFile));
}
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)
{
base.TransferTo(other);
@ -135,7 +142,7 @@ namespace osu.Game.Beatmaps
try
{
skin = new LegacyBeatmapSkin(BeatmapInfo, store, audioManager);
skin = new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager);
}
catch (Exception e)
{

View File

@ -1,11 +1,7 @@
// 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;
using System.Diagnostics;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
namespace osu.Game.Beatmaps
@ -16,32 +12,15 @@ namespace osu.Game.Beatmaps
/// </summary>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>
{
private AudioManager audioManager;
private WorkingBeatmap lastBeatmap;
protected BindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
BindValueChanged(b => updateAudioTrack(b.NewValue), true);
}
/// <summary>
/// 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)
private void updateAudioTrack(WorkingBeatmap beatmap)
{
var trackLoaded = lastBeatmap?.TrackLoaded ?? false;
@ -55,18 +34,9 @@ namespace osu.Game.Beatmaps
lastBeatmap.RecycleTrack();
}
audioManager.Track.AddItem(beatmap.Track);
}
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.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -31,24 +32,8 @@ namespace osu.Game.Beatmaps.Drawables
/// </summary>
protected virtual double UnloadDelay => 10000;
private BeatmapInfo lastModel;
private bool firstLoad = true;
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 DelayedLoadWrapper CreateDelayedLoadWrapper(Func<Drawable> createContentFunc, double timeBeforeLoad)
=> new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay);
protected override Drawable CreateDrawable(BeatmapInfo model)
{

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Textures;
@ -16,9 +17,9 @@ namespace osu.Game.Beatmaps
{
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
{
Metadata = new BeatmapMetadata
@ -34,16 +35,16 @@ namespace osu.Game.Beatmaps
OverallDifficulty = 0,
},
Ruleset = new DummyRulesetInfo()
})
}, audio)
{
this.game = game;
this.textures = textures;
}
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
{

View File

@ -11,15 +11,17 @@ using osu.Framework.IO.File;
using System.IO;
using System.Linq;
using System.Threading;
using osu.Framework.Audio;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
namespace osu.Game.Beatmaps
{
public abstract partial class WorkingBeatmap : IDisposable
public abstract class WorkingBeatmap : IDisposable
{
public readonly BeatmapInfo BeatmapInfo;
@ -27,8 +29,11 @@ namespace osu.Game.Beatmaps
public readonly BeatmapMetadata Metadata;
protected WorkingBeatmap(BeatmapInfo beatmapInfo)
protected AudioManager AudioManager { get; }
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
{
AudioManager = audioManager;
BeatmapInfo = beatmapInfo;
BeatmapSetInfo = beatmapInfo.BeatmapSet;
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
@ -46,13 +51,39 @@ namespace osu.Game.Beatmaps
return b;
});
track = new RecyclableLazy<Track>(() => GetTrack() ?? new VirtualBeatmapTrack(Beatmap));
track = new RecyclableLazy<Track>(() => GetTrack() ?? GetVirtualTrack());
background = new RecyclableLazy<Texture>(GetBackground, BackgroundStillValid);
waveform = new RecyclableLazy<Waveform>(GetWaveform);
storyboard = new RecyclableLazy<Storyboard>(GetStoryboard);
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>
/// Saves the <see cref="Beatmaps.Beatmap"/>.
/// </summary>
@ -150,6 +181,7 @@ namespace osu.Game.Beatmaps
public bool SkinLoaded => skin.IsResultAvailable;
public Skin Skin => skin.Value;
protected virtual Skin GetSkin() => new DefaultSkin();
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).
/// Accessing track again will load a fresh instance.
/// </summary>
public void RecycleTrack() => track.Recycle();
public virtual void RecycleTrack() => track.Recycle();
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)
OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
samplePopIn = audio.Samples.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Samples.Get(@"UI/overlay-pop-out");
StateChanged += onStateChanged;
}

View File

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

View File

@ -31,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader]
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]
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]
private void load(AudioManager audio)
{
sampleChecked = audio.Sample.Get(@"UI/check-on");
sampleUnchecked = audio.Sample.Get(@"UI/check-off");
sampleChecked = audio.Samples.Get(@"UI/check-on");
sampleUnchecked = audio.Samples.Get(@"UI/check-off");
}
}
}

View File

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

View File

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

View File

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

View File

@ -161,7 +161,7 @@ namespace osu.Game
dependencies.CacheAs<IAPIProvider>(API);
var defaultBeatmap = new DummyWorkingBeatmap(this);
var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
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.
// 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(beatmap);
@ -281,23 +281,10 @@ namespace osu.Game
private class OsuBindableBeatmap : BindableBeatmap
{
public OsuBindableBeatmap(WorkingBeatmap defaultValue, AudioManager audioManager)
: this(defaultValue)
{
RegisterAudioManager(audioManager);
}
public OsuBindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
}
public override BindableBeatmap GetBoundCopy()
{
var copy = new OsuBindableBeatmap(Default);
copy.BindTo(this);
return copy;
}
}
private class OsuUserInputManager : UserInputManager

View File

@ -90,8 +90,8 @@ namespace osu.Game.Overlays.Changelog
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleClick = audio.Sample.Get(@"UI/generic-select-soft");
sampleHover = audio.Sample.Get(@"UI/generic-hover-soft");
sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
}
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);

View File

@ -145,7 +145,7 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
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");
disc.EdgeEffect = leftStrip.EdgeEffect = rightStrip.EdgeEffect = new EdgeEffectParameters

View File

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

View File

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

View File

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

View File

@ -150,7 +150,7 @@ namespace osu.Game.Screens.Menu
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()

View File

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

View File

@ -255,8 +255,8 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader]
private void load(TextureStore textures, AudioManager audio)
{
sampleClick = audio.Sample.Get(@"Menu/osu-logo-select");
sampleBeat = audio.Sample.Get(@"Menu/osu-logo-heartbeat");
sampleClick = audio.Samples.Get(@"Menu/osu-logo-select");
sampleBeat = audio.Samples.Get(@"Menu/osu-logo-heartbeat");
logo.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
{
protected override double FadeDuration => 200;
protected override double TransformDuration => 200;
}
}
}

View File

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

View File

@ -99,7 +99,7 @@ namespace osu.Game.Screens
[BackgroundDependencyLoader(true)]
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)

View File

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

View File

@ -234,7 +234,7 @@ namespace osu.Game.Screens.Play
colourNormal = colours.Yellow;
colourHover = colours.YellowDark;
sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection");
sampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection");
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);
}

View File

@ -242,9 +242,9 @@ namespace osu.Game.Screens.Select
dialogOverlay = dialog;
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty");
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
SampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection");
sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty");
sampleChangeBeatmap = audio.Samples.Get(@"SongSelect/select-expand");
SampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection");
Carousel.LoadBeatmapSetsFromManager(this.beatmaps);
@ -580,9 +580,6 @@ namespace osu.Game.Screens.Select
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.Restart();
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -21,7 +22,7 @@ namespace osu.Game.Skinning
{
protected TextureStore Textures;
protected SampleManager Samples;
protected IResourceStore<SampleChannel> Samples;
public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager)
: this(skin, new LegacySkinResourceStore<SkinFileInfo>(skin, storage), audioManager, "skin.ini")
@ -38,10 +39,17 @@ namespace osu.Game.Skinning
else
Configuration = new SkinConfiguration();
Samples = audioManager.GetSampleManager(storage);
Samples = audioManager.GetSampleStore(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)
{
switch (componentName)
@ -133,6 +141,8 @@ namespace osu.Game.Skinning
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;
public Task<byte[]> GetAsync(string name)

View File

@ -39,7 +39,7 @@ namespace osu.Game.Skinning
{
var ch = loadChannel(s, skin.GetSample);
if (ch == null && allowFallback)
ch = loadChannel(s, audio.Sample.Get);
ch = loadChannel(s, audio.Samples.Get);
return ch;
}).Where(c => c != null).ToArray();
}
@ -58,5 +58,13 @@ namespace osu.Game.Skinning
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.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osuTK;
namespace osu.Game.Tests.Beatmaps
{
public class TestWorkingBeatmap : WorkingBeatmap
{
private readonly TrackVirtualManual track;
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>
/// 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>
public TestWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock referenceClock = null)
: base(beatmap.BeatmapInfo)
public TestWorkingBeatmap(IBeatmap beatmap)
: base(beatmap.BeatmapInfo, null)
{
this.beatmap = beatmap;
if (referenceClock != null)
track = new TrackVirtualManual(referenceClock);
}
protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack() => 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();
}
}
}
protected override Track GetTrack() => null;
}
}

View File

@ -4,13 +4,10 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual
{
@ -50,26 +47,20 @@ namespace osu.Game.Tests.Visual
protected abstract void AddCheckSteps();
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo);
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock clock) =>
new TestWorkingBeatmap(beatmap, Clock);
private Player loadPlayerFor(RulesetInfo ri)
private Player loadPlayerFor(RulesetInfo rulesetInfo)
{
Ruleset.Value = ri;
var r = ri.CreateInstance();
Ruleset.Value = rulesetInfo;
var ruleset = rulesetInfo.CreateInstance();
var beatmap = CreateBeatmap(r);
var working = CreateWorkingBeatmap(beatmap, Clock);
var working = CreateWorkingBeatmap(rulesetInfo);
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 = null;
Player = CreatePlayer(r);
Player = CreatePlayer(ruleset);
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.
using System;
@ -6,7 +6,6 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Screens.Edit;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual
{
@ -24,7 +23,7 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo, null);
Beatmap.Value = CreateWorkingBeatmap(ruleset.RulesetInfo);
LoadScreen(new Editor());
}

View File

@ -3,15 +3,22 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual
{
@ -19,7 +26,7 @@ namespace osu.Game.Tests.Visual
{
[Cached(typeof(Bindable<WorkingBeatmap>))]
[Cached(typeof(IBindable<WorkingBeatmap>))]
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap());
private OsuTestBeatmap beatmap;
protected BindableBeatmap Beatmap => beatmap;
@ -39,7 +46,12 @@ namespace osu.Game.Tests.Visual
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
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));
}
@ -49,11 +61,20 @@ namespace osu.Game.Tests.Visual
localStorage = new Lazy<Storage>(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}"));
}
[BackgroundDependencyLoader]
private void load(AudioManager audioManager, RulesetStore rulesets)
{
beatmap.SetAudioManager(audioManager);
[Resolved]
private AudioManager audio { get; set; }
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();
}
@ -79,6 +100,164 @@ namespace osu.Game.Tests.Visual
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
{
private TestSceneTestRunner.TestRunner runner;
@ -100,15 +279,6 @@ namespace osu.Game.Tests.Visual
: 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))]
public abstract class PlacementBlueprintTestScene : OsuTestScene, IPlacementHandler
{
protected readonly Container HitObjectContainer;
protected Container HitObjectContainer;
private PlacementBlueprint currentBlueprint;
protected PlacementBlueprintTestScene()
{
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2;
Add(HitObjectContainer = CreateHitObjectContainer());
}
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2;
Add(currentBlueprint = CreateBlueprint());
}

View File

@ -4,12 +4,10 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual
{
@ -39,15 +37,13 @@ namespace osu.Game.Tests.Visual
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
}
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo);
protected virtual bool AllowFail => false;
private void loadPlayer()
{
var beatmap = CreateBeatmap(ruleset);
var beatmap = CreateBeatmap(ruleset.RulesetInfo);
Beatmap.Value = new TestWorkingBeatmap(beatmap, Clock);
Beatmap.Value = CreateWorkingBeatmap(beatmap);
if (!AllowFail)
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="Newtonsoft.Json" Version="12.0.2" />
<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="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />