From 16f1a7694d9397a9acac2acfd0c39f38ef438547 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jun 2023 18:43:37 +0900 Subject: [PATCH] Add time-based flourish support --- .../Skinning/Argon/ArgonDrumSamplePlayer.cs | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonDrumSamplePlayer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonDrumSamplePlayer.cs index 67d417c599..72e5ac5b3d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonDrumSamplePlayer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonDrumSamplePlayer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Game.Audio; using osu.Game.Rulesets.Taiko.Objects; @@ -18,12 +19,20 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon public partial class ArgonDrumSampleTriggerSource : DrumSampleTriggerSource { + private readonly HitObjectContainer hitObjectContainer; + [Resolved] private ISkinSource skinSource { get; set; } = null!; + /// + /// The minimum time to leave between flourishes that are added to strong rim hits. + /// + private const double time_between_flourishes = 2000; + public ArgonDrumSampleTriggerSource(HitObjectContainer hitObjectContainer, SampleBalance balance) : base(hitObjectContainer, balance) { + this.hitObjectContainer = hitObjectContainer; // TODO: pool flourish sample } @@ -44,21 +53,41 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon } // let the magic begin... + var samplesToPlay = new List { new VolumeAwareHitSampleInfo(originalSample, strong) }; - if (strong) + if (strong && hitType == HitType.Rim && canPlayFlourish(hitObject)) + samplesToPlay.Add(new VolumeAwareHitSampleInfo(hitObject.CreateHitSampleInfo(HitSampleInfo.HIT_FLOURISH), true)); + + PlaySamples(samplesToPlay.ToArray()); + } + + private bool canPlayFlourish(TaikoHitObject hitObject) + { + double? lastFlourish = null; + + // TODO: check on nested strong hits. we're not accounting for them here yet. + + var hitObjects = hitObjectContainer.AliveObjects + .Reverse() + .Select(d => d.HitObject) + .OfType() + .Where(h => h.IsStrong && h.Type == HitType.Rim); + + // Add an additional 'flourish' sample to strong rim hits (that are at least `time_between_flourishes` apart). + // This is applied to hitobjects in reverse order, as to sound more musically coherent by biasing towards to + // end of groups/combos of strong rim hits instead of the start. + foreach (var h in hitObjects) { - PlaySamples(new ISampleInfo[] - { - new VolumeAwareHitSampleInfo(originalSample, true), - // TODO: flourish should only play every time_between_flourishes. - new VolumeAwareHitSampleInfo(hitObject.CreateHitSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_FLOURISH : string.Empty), true), - new VolumeAwareHitSampleInfo(originalSample) - }); - } - else - { - PlaySamples(new ISampleInfo[] { new VolumeAwareHitSampleInfo(new VolumeAwareHitSampleInfo(originalSample)) }); + bool canFlourish = lastFlourish == null || lastFlourish - h.StartTime >= time_between_flourishes; + + if (canFlourish) + lastFlourish = h.StartTime; + + if (h == hitObject) + return canFlourish; } + + return false; } private class VolumeAwareHitSampleInfo : HitSampleInfo