1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-03 04:41:24 +08:00

Add audio feedback to BSS process

This commit is contained in:
Jamie Taylor
2025-04-18 19:45:30 +09:00
Unverified
parent bb30d86401
commit 5208d8a0b2
3 changed files with 161 additions and 2 deletions
@@ -1,10 +1,14 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Overlays;
using osu.Game.Screens.Edit.Submission;
using osuTK;
@@ -16,6 +20,11 @@ namespace osu.Game.Tests.Visual.Editing
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
[Resolved]
private AudioManager audio { get; set; } = null!;
private Sample? completeSample;
[Test]
public void TestAppearance()
{
@@ -43,5 +52,92 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("failed with long message", () => progress.SetFailed("this is a very very very very VERY VEEEEEEEEEEEEEEEEEEEEEEEEERY long error message like you would never believe"));
AddStep("canceled", () => progress.SetCanceled());
}
[Test]
public void TestAudioSequence()
{
SubmissionStageProgress[] stages = new SubmissionStageProgress[4];
Container? cardContainer = null;
AddStep("prepare", () =>
{
Child = new Container
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new Drawable[]
{
stages[0] = new SubmissionStageProgress
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
StageDescription = "Export...",
StageIndex = 0
},
stages[1] = new SubmissionStageProgress
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
StageDescription = "CreateSet...",
StageIndex = 1
},
stages[2] = new SubmissionStageProgress
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
StageDescription = "Upload...",
StageIndex = 2
},
stages[3] = new SubmissionStageProgress
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
StageDescription = "Update...",
StageIndex = 3
},
cardContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
}
}
};
completeSample = audio.Samples.Get(@"UI/bss-complete");
});
for (int i = 0; i < stages.Length; i++)
{
int step = i;
AddStep($"{step}: not started", () => stages[step].SetNotStarted());
AddStep($"{step}: indeterminate progress", () => stages[step].SetInProgress());
AddStep($"{step}: 70% progress", () => stages[step].SetInProgress(0.25f));
AddStep($"{step}: completed", () => stages[step].SetCompleted());
}
AddStep("pause for timing", () => { });
AddStep("Sequence Complete", () =>
{
var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSet.Beatmaps = Enumerable.Repeat(beatmapSet.Beatmaps.First(), 100).ToArray();
LoadComponentAsync(new BeatmapCardExtra(beatmapSet, false), loaded =>
{
cardContainer?.Add(loaded);
completeSample?.Play();
});
});
}
}
}
@@ -8,6 +8,8 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Development;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
@@ -81,8 +83,10 @@ namespace osu.Game.Screens.Edit.Submission
private Live<BeatmapSetInfo>? importedSet;
private Sample completedSample = null!;
[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audio)
{
AddRangeInternal(new Drawable[]
{
@@ -118,24 +122,28 @@ namespace osu.Game.Screens.Edit.Submission
createSetStep = new SubmissionStageProgress
{
StageDescription = BeatmapSubmissionStrings.Preparing,
StageIndex = 0,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
exportStep = new SubmissionStageProgress
{
StageDescription = BeatmapSubmissionStrings.Exporting,
StageIndex = 1,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
uploadStep = new SubmissionStageProgress
{
StageDescription = BeatmapSubmissionStrings.Uploading,
StageIndex = 2,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
updateStep = new SubmissionStageProgress
{
StageDescription = BeatmapSubmissionStrings.Finishing,
StageIndex = 3,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
@@ -181,6 +189,8 @@ namespace osu.Game.Screens.Edit.Submission
}
}
});
completedSample = audio.Samples.Get(@"UI/bss-complete");
}
private void createBeatmapSet()
@@ -382,6 +392,8 @@ namespace osu.Game.Screens.Edit.Submission
successContainer.Add(loaded);
flashLayer.FadeOutFromOne(2000, Easing.OutQuint);
});
completedSample.Play();
};
api.Queue(getBeatmapSetRequest);
@@ -1,13 +1,17 @@
// 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.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -21,6 +25,8 @@ namespace osu.Game.Screens.Edit.Submission
{
public LocalisableString StageDescription { get; init; }
public int StageIndex { get; init; }
private Bindable<StageStatusType> status { get; } = new Bindable<StageStatusType>();
private Bindable<float?> progress { get; } = new Bindable<float?>();
@@ -33,8 +39,19 @@ namespace osu.Game.Screens.Edit.Submission
[Resolved]
private OsuColour colours { get; set; } = null!;
private Sample progressSample = null!;
private const int stage_done_sample_count = 4;
private Sample stageDoneSample = null!;
private Sample errorSample = null!;
private Sample cancelSample = null!;
private double? lastSamplePlayback;
private float? previousPercent;
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
private void load(OverlayColourProvider colourProvider, AudioManager audio)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
@@ -111,6 +128,13 @@ namespace osu.Game.Screens.Edit.Submission
}
}
};
errorSample = audio.Samples.Get(@"UI/generic-error");
cancelSample = audio.Samples.Get(@"UI/notification-cancel");
progressSample = audio.Samples.Get(@"UI/bss-progress");
int stageSample = Math.Min(stage_done_sample_count - 1, StageIndex);
stageDoneSample = audio.Samples.Get(@$"UI/bss-stage-{stageSample}");
}
protected override void LoadComplete()
@@ -119,6 +143,25 @@ namespace osu.Game.Screens.Edit.Submission
status.BindValueChanged(_ => Scheduler.AddOnce(updateStatus), true);
progress.BindValueChanged(_ => Scheduler.AddOnce(updateProgress), true);
// Binding to `progressBar` updates instead of `progress` for more frequent/granular updates
progressBar.OnUpdate += playProgressSound;
}
private void playProgressSound(Drawable box)
{
float width = box.Width;
SampleChannel sampleChannel = progressSample.GetChannel();
if (Precision.AlmostEquals(previousPercent ?? 0f, width) || (lastSamplePlayback != null && Time.Current - lastSamplePlayback < 10))
return;
sampleChannel.Frequency.Value = 0.5f + (width * 1.5f);
sampleChannel.Volume.Value = 0.25f + (width / 2f) * .75f;
sampleChannel.Play();
lastSamplePlayback = Time.Current;
previousPercent = width;
}
public void SetNotStarted() => status.Value = StageStatusType.NotStarted;
@@ -176,6 +219,12 @@ namespace osu.Game.Screens.Edit.Submission
};
iconContainer.Colour = colours.Green1;
iconContainer.FlashColour(Colour4.White, 1000, Easing.OutQuint);
// manually set progress value, as to trigger sample playback for the final section
progress.Value = 1;
stageDoneSample.Play();
break;
case StageStatusType.Failed:
@@ -186,6 +235,7 @@ namespace osu.Game.Screens.Edit.Submission
};
iconContainer.Colour = colours.Red1;
iconContainer.FlashColour(Colour4.White, 1000, Easing.OutQuint);
errorSample.Play();
break;
case StageStatusType.Canceled:
@@ -196,6 +246,7 @@ namespace osu.Game.Screens.Edit.Submission
};
iconContainer.Colour = colours.Gray8;
iconContainer.FlashColour(Colour4.White, 1000, Easing.OutQuint);
cancelSample.Play();
break;
}
}