diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumSampleTriggerSource.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumSampleTriggerSource.cs new file mode 100644 index 0000000000..0c8f18badd --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumSampleTriggerSource.cs @@ -0,0 +1,273 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Timing; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public partial class TestSceneDrumSampleTriggerSource : OsuTestScene + { + private readonly ManualClock manualClock = new ManualClock(); + + [Cached(typeof(IScrollingInfo))] + private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo + { + Direction = { Value = ScrollingDirection.Left }, + TimeRange = { Value = 200 }, + }; + + private ScrollingHitObjectContainer hitObjectContainer = null!; + private TestDrumSampleTriggerSource triggerSource = null!; + + [SetUp] + public void SetUp() => Schedule(() => + { + hitObjectContainer = new ScrollingHitObjectContainer(); + manualClock.CurrentTime = 0; + + Child = new Container + { + Clock = new FramedClock(manualClock), + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + hitObjectContainer, + triggerSource = new TestDrumSampleTriggerSource(hitObjectContainer) + } + }; + }); + + [Test] + public void TestNormalHit() + { + AddStep("add hit with normal samples", () => + { + var hit = new Hit + { + StartTime = 100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL) + } + }; + hit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableHit = new DrawableHit(hit); + hitObjectContainer.Add(drawableHit); + }); + + AddAssert("most valid object is hit", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + + AddStep("seek past hit", () => manualClock.CurrentTime = 200); + AddAssert("most valid object is hit", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + } + + [Test] + public void TestSoftHit() + { + AddStep("add hit with soft samples", () => + { + var hit = new Hit + { + StartTime = 100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "soft") + } + }; + hit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableHit = new DrawableHit(hit); + hitObjectContainer.Add(drawableHit); + }); + + AddAssert("most valid object is hit", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "soft"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "soft"); + + AddStep("seek past hit", () => manualClock.CurrentTime = 200); + AddAssert("most valid object is hit", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "soft"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "soft"); + } + + [Test] + public void TestNormalDrumRoll() + { + AddStep("add drum roll with normal samples", () => + { + var drumRoll = new DrumRoll + { + StartTime = 100, + EndTime = 1100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL) + } + }; + drumRoll.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableDrumRoll = new DrawableDrumRoll(drumRoll); + hitObjectContainer.Add(drawableDrumRoll); + }); + + AddAssert("most valid object is drum roll tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + + AddStep("seek to middle of drum roll", () => manualClock.CurrentTime = 600); + AddAssert("most valid object is drum roll tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + + AddStep("seek past drum roll", () => manualClock.CurrentTime = 1200); + AddAssert("most valid object is drum roll", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + } + + [Test] + public void TestSoftDrumRoll() + { + AddStep("add drum roll with soft samples", () => + { + var drumRoll = new DrumRoll + { + StartTime = 100, + EndTime = 1100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "soft") + } + }; + drumRoll.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableDrumRoll = new DrawableDrumRoll(drumRoll); + hitObjectContainer.Add(drawableDrumRoll); + }); + + AddAssert("most valid object is drum roll tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "soft"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "soft"); + + AddStep("seek to middle of drum roll", () => manualClock.CurrentTime = 600); + AddAssert("most valid object is drum roll tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "soft"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "soft"); + + AddStep("seek past drum roll", () => manualClock.CurrentTime = 1200); + AddAssert("most valid object is drum roll", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "soft"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "soft"); + } + + [Test] + public void TestNormalSwell() + { + AddStep("add swell with normal samples", () => + { + var swell = new Swell + { + StartTime = 100, + EndTime = 1100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL) + } + }; + swell.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableSwell = new DrawableSwell(swell); + hitObjectContainer.Add(drawableSwell); + }); + + AddAssert("most valid object is swell tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + + AddStep("seek to middle of swell", () => manualClock.CurrentTime = 600); + AddAssert("most valid object is swell tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + + AddStep("seek past swell", () => manualClock.CurrentTime = 1200); + AddAssert("most valid object is swell", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, SampleControlPoint.DEFAULT_BANK); + } + + [Test] + public void TestDrumSwell() + { + AddStep("add swell with drum samples", () => + { + var swell = new Swell() + { + StartTime = 100, + EndTime = 1100, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "drum") + } + }; + swell.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var drawableSwell = new DrawableSwell(swell); + hitObjectContainer.Add(drawableSwell); + }); + + AddAssert("most valid object is swell tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "drum"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "drum"); + + AddStep("seek to middle of swell", () => manualClock.CurrentTime = 600); + AddAssert("most valid object is swell tick", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "drum"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "drum"); + + AddStep("seek past swell", () => manualClock.CurrentTime = 1200); + AddAssert("most valid object is swell", () => triggerSource.GetMostValidObject(), Is.InstanceOf); + checkSound(HitType.Centre, HitSampleInfo.HIT_NORMAL, "drum"); + checkSound(HitType.Rim, HitSampleInfo.HIT_CLAP, "drum"); + } + + private void checkSound(HitType hitType, string expectedName, string expectedBank) + { + AddStep($"hit {hitType}", () => triggerSource.Play(hitType)); + AddAssert($"last played sample is {expectedName}", () => triggerSource.LastPlayedSamples!.OfType().Single().Name, () => Is.EqualTo(expectedName)); + AddAssert($"last played sample has {expectedBank} bank", () => triggerSource.LastPlayedSamples!.OfType().Single().Bank, () => Is.EqualTo(expectedBank)); + } + + private partial class TestDrumSampleTriggerSource : DrumSampleTriggerSource + { + public ISampleInfo[]? LastPlayedSamples { get; private set; } + + public TestDrumSampleTriggerSource(HitObjectContainer hitObjectContainer) + : base(hitObjectContainer) + { + } + + protected override void PlaySamples(ISampleInfo[] samples) + { + base.PlaySamples(samples); + LastPlayedSamples = samples; + } + + public new HitObject GetMostValidObject() => base.GetMostValidObject(); + } + } +} diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index d4510a4519..fbb7a20a5d 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.UI PlaySamples(samples); } - protected void PlaySamples(ISampleInfo[] samples) => Schedule(() => + protected virtual void PlaySamples(ISampleInfo[] samples) => Schedule(() => { var hitSound = getNextSample(); hitSound.Samples = samples;