Skip to content
2 changes: 1 addition & 1 deletion osu.Android.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.1005.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.1008.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.
Expand Down
3 changes: 1 addition & 2 deletions osu.Game.Tests/Skins/TestSceneSkinResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Rendering.Dummy;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
Expand Down Expand Up @@ -104,7 +103,7 @@ public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceSto

public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();

public override ISample GetSample(ISampleInfo sampleInfo) => Samples.AsNonNull().Get(SAMPLE_NAME);
public override ISample GetSample(ISampleInfo sampleInfo) => GetSampleFromSkinFiles(SAMPLE_NAME, sampleInfo.IsHitsound)!;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ public void TestSongSelectScrollHandling()
SoloSongSelect songSelect = null;
double scrollPosition = 0;

AddStep("move to screen centre", () => InputManager.MoveMouseTo(Game));
AddStep("set game volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeUniversal, 1d));
AddStep("set effect volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeEffect, 1d));
AddUntilStep("wait for volume overlay to hide", () => Game.ChildrenOfType<VolumeOverlay>().SingleOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Hidden));
PushAndConfirm(() => songSelect = new SoloSongSelect());
AddUntilStep("wait for song select", () => songSelect.IsLoaded);
Expand Down Expand Up @@ -294,7 +296,7 @@ public void TestSongSelectScrollHandling()
InputManager.ScrollVerticalBy(-1);
InputManager.ReleaseKey(Key.AltLeft);
}, 5);
AddAssert("game volume decreased", () => Game.Dependencies.Get<FrameworkConfigManager>().Get<double>(FrameworkSetting.VolumeUniversal), () => Is.LessThan(1));
AddAssert("effect volume decreased", () => Game.Dependencies.Get<FrameworkConfigManager>().Get<double>(FrameworkSetting.VolumeEffect), () => Is.LessThan(1));

AddStep("move to carousel", () => InputManager.MoveMouseTo(songSelect.ChildrenOfType<BeatmapCarousel>().Single()));
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Audio/HitSampleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo>
// new bank used exclusively by taiko for now.
public const string BANK_STRONG = @"strong";

public bool IsHitsound => true;

/// <summary>
/// All valid sample addition constants.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Audio/ISampleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ public interface ISampleInfo
IEnumerable<string> LookupNames { get; }

int Volume { get; }

bool IsHitsound { get; }
}
}
2 changes: 2 additions & 0 deletions osu.Game/Audio/SampleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class SampleInfo : ISampleInfo, IEquatable<SampleInfo>
{
private readonly string[] sampleNames;

public bool IsHitsound => false;

public SampleInfo(params string[] sampleNames)
{
this.sampleNames = sampleNames;
Expand Down
3 changes: 3 additions & 0 deletions osu.Game/Configuration/OsuConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ protected override void InitialiseDefaults()
// Audio
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);

SetDefault(OsuSetting.HitsoundVolume, 0.6, 0, 1, 0.01);

SetDefault(OsuSetting.MenuVoice, true);
SetDefault(OsuSetting.MenuMusic, true);
SetDefault(OsuSetting.MenuTips, true);
Expand Down Expand Up @@ -485,5 +487,6 @@ public enum OsuSetting
/// Blocks private messages, multiplayer room invites, and duel requests from people not on the user's friends list.
/// </summary>
PMFriendsOnly,
HitsoundVolume,
}
}
5 changes: 5 additions & 0 deletions osu.Game/Localisation/AudioSettingsStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public static class AudioSettingsStrings
/// </summary>
public static LocalisableString MusicVolume => new TranslatableString(getKey(@"music_volume"), @"Music");

/// <summary>
/// "Hitsound"
/// </summary>
public static LocalisableString HitsoundVolume => new TranslatableString(getKey(@"hitsound_volume"), @"Hitsound");

/// <summary>
/// "Offset Adjustment"
/// </summary>
Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Localisation/SkinSettingsStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public static class SkinSettingsStrings
/// </summary>
public static LocalisableString BeatmapHitsounds => new TranslatableString(getKey(@"beatmap_hitsounds"), @"Beatmap hitsounds");

private static string getKey(string key) => $"{prefix}:{key}";
/// <summary>
/// "Hitsound volume"
/// </summary>
public static LocalisableString HitsoundVolume => new TranslatableString(getKey(@"hitsound_volume"), @"Hitsound volume");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
12 changes: 10 additions & 2 deletions osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ private void load(AudioManager audio, OsuConfigManager config)
DisplayAsPercentage = true
}),
new SettingsItemV2(new FormSliderBar<double>
{
Caption = AudioSettingsStrings.MusicVolume,
Current = audio.VolumeTrack,
KeyboardStep = 0.01f,
DisplayAsPercentage = true,
PlaySamplesOnAdjust = false,
}),
new SettingsItemV2(new FormSliderBar<double>
{
Caption = AudioSettingsStrings.EffectVolume,
Current = audio.VolumeSample,
Expand All @@ -45,8 +53,8 @@ private void load(AudioManager audio, OsuConfigManager config)
}),
new SettingsItemV2(new FormSliderBar<double>
{
Caption = AudioSettingsStrings.MusicVolume,
Current = audio.VolumeTrack,
Caption = AudioSettingsStrings.HitsoundVolume,
Current = config.GetBindable<double>(OsuSetting.HitsoundVolume),
KeyboardStep = 0.01f,
DisplayAsPercentage = true,
PlaySamplesOnAdjust = false,
Expand Down
15 changes: 11 additions & 4 deletions osu.Game/Overlays/VolumeOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
Expand All @@ -33,11 +34,15 @@ public partial class VolumeOverlay : VisibilityContainer
private VolumeMeter volumeMeterMaster = null!;
private VolumeMeter volumeMeterEffect = null!;
private VolumeMeter volumeMeterMusic = null!;
private VolumeMeter volumeMeterHitsound = null!;

// ReSharper disable once NotAccessedField.Local
private Bindable<double> volumeGameplay = null!;
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

private SelectionCycleFillFlowContainer<VolumeMeter> volumeMeters = null!;

[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
private void load(AudioManager audio, OsuColour colours, OsuConfigManager config)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Expand Down Expand Up @@ -69,9 +74,10 @@ private void load(AudioManager audio, OsuColour colours)
Spacing = new Vector2(0, offset),
Children = new[]
{
volumeMeterEffect = new VolumeMeter(AudioSettingsStrings.EffectVolume.ToUpper(), 125, colours.BlueDarker),
volumeMeterMaster = new MasterVolumeMeter(AudioSettingsStrings.MasterVolume.ToUpper(), 150, colours.PinkDarker) { IsMuted = { BindTarget = IsMuted }, },
volumeMeterMusic = new VolumeMeter(AudioSettingsStrings.MusicVolume.ToUpper(), 125, colours.BlueDarker),
volumeMeterMaster = new MasterVolumeMeter(AudioSettingsStrings.MasterVolume.ToUpper(), 140, colours.PinkDarker) { IsMuted = { BindTarget = IsMuted }, },
volumeMeterMusic = new VolumeMeter(AudioSettingsStrings.MusicVolume.ToUpper(), 100, colours.BlueDarker),
volumeMeterEffect = new VolumeMeter(AudioSettingsStrings.EffectVolume.ToUpper(), 100, colours.BlueDarker),
volumeMeterHitsound = new VolumeMeter(AudioSettingsStrings.HitsoundVolume.ToUpper(), 100, colours.BlueDarker),
}
},
},
Expand All @@ -81,6 +87,7 @@ private void load(AudioManager audio, OsuColour colours)
volumeMeterMaster.Bindable.BindTo(audio.Volume);
volumeMeterEffect.Bindable.BindTo(audio.VolumeSample);
volumeMeterMusic.Bindable.BindTo(audio.VolumeTrack);
volumeMeterHitsound.Bindable.BindTo(volumeGameplay = config.GetBindable<double>(OsuSetting.HitsoundVolume));
}

protected override void LoadComplete()
Expand Down
12 changes: 9 additions & 3 deletions osu.Game/Rulesets/UI/DrawableRuleset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
Expand Down Expand Up @@ -74,9 +75,9 @@ public abstract partial class DrawableRuleset<TObject> : DrawableRuleset, IProvi

public override Container Overlays { get; } = new Container { RelativeSizeAxes = Axes.Both };

public override IAdjustableAudioComponent Audio => audioContainer;
public override IAdjustableAudioComponent Audio => gameplayMixer;

private readonly AudioContainer audioContainer = new AudioContainer { RelativeSizeAxes = Axes.Both };
private readonly DrawableAudioMixer gameplayMixer = new DrawableAudioMixer { RelativeSizeAxes = Axes.Both, Name = "GameplayMixer" };

public override Container FrameStableComponents { get; } = new Container { RelativeSizeAxes = Axes.Both };

Expand Down Expand Up @@ -104,6 +105,8 @@ public abstract partial class DrawableRuleset<TObject> : DrawableRuleset, IProvi

private bool frameStablePlayback = true;

private Bindable<double> hitsoundVolume;

internal override bool FrameStablePlayback
{
get => frameStablePlayback;
Expand Down Expand Up @@ -179,7 +182,7 @@ private void load(CancellationToken? cancellationToken)
Children = new Drawable[]
{
FrameStableComponents,
audioContainer.WithChild(KeyBindingInputManager
gameplayMixer.WithChild(KeyBindingInputManager
.WithChildren(new Drawable[]
{
playfieldAdjustmentContainer.WithChild(Playfield),
Expand All @@ -195,6 +198,9 @@ private void load(CancellationToken? cancellationToken)
.WithChild(ResumeOverlay)));
}

hitsoundVolume = config.GetBindable<double>(OsuSetting.HitsoundVolume);
gameplayMixer.Volume.BindTo(hitsoundVolume);

applyRulesetMods(Mods, config);

loadObjects(cancellationToken ?? CancellationToken.None);
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Screens/Edit/Components/FormSampleSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private void recycleSamples() => Schedule(() =>

AddInternal(hoverSounds = (ActualFilename.Value == null ? new HoverClickSounds(HoverSampleSet.Button) : new HoverSounds(HoverSampleSet.Button)));

sample = ActualFilename.Value != null ? editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value) : null;
sample = ActualFilename.Value != null ? editorBeatmap?.BeatmapSkin?.Skin.GetSampleFromSkinFiles(ActualFilename.Value, true) : null;
});

protected override bool OnHover(HoverEvent e)
Expand Down
35 changes: 16 additions & 19 deletions osu.Game/Screens/Edit/EditorBeatmapSkin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,32 +119,29 @@ public IEnumerable<SampleSet> GetAvailableSampleSets()
[1] = new SampleSet(1),
};

if (Skin.Samples != null)
foreach (string sample in Skin.AllAvailableSamples)
{
foreach (string sample in Skin.Samples.GetAvailableResources())
foreach (string possiblePrefix in possiblePrefixes)
{
foreach (string possiblePrefix in possiblePrefixes)
{
if (!sample.StartsWith(possiblePrefix, StringComparison.Ordinal))
continue;
if (!sample.StartsWith(possiblePrefix, StringComparison.Ordinal))
continue;

string indexString = Path.GetFileNameWithoutExtension(sample)[possiblePrefix.Length..];
int? index = null;
string indexString = Path.GetFileNameWithoutExtension(sample)[possiblePrefix.Length..];
int? index = null;

if (string.IsNullOrEmpty(indexString))
index = 1;
if (int.TryParse(indexString, out int parsed) && parsed >= 2)
index = parsed;
if (string.IsNullOrEmpty(indexString))
index = 1;
if (int.TryParse(indexString, out int parsed) && parsed >= 2)
index = parsed;

if (!index.HasValue)
continue;
if (!index.HasValue)
continue;

SampleSet? sampleSet;
if (!sampleSets.TryGetValue(index.Value, out sampleSet))
sampleSet = sampleSets[index.Value] = new SampleSet(index.Value);
SampleSet? sampleSet;
if (!sampleSets.TryGetValue(index.Value, out sampleSet))
sampleSet = sampleSets[index.Value] = new SampleSet(index.Value);

sampleSet.Filenames.Add(sample);
}
sampleSet.Filenames.Add(sample);
}
}

Expand Down
29 changes: 19 additions & 10 deletions osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,35 @@ public partial class AudioSettings : PlayerSettingsGroup
{
private Bindable<ScoreInfo> referenceScore { get; } = new Bindable<ScoreInfo>();

private readonly PlayerCheckbox beatmapHitsoundsToggle;

public AudioSettings()
: base(PlayerSettingsOverlayStrings.AudioSettingsTitle)
{
}

[BackgroundDependencyLoader]
private void load(OsuConfigManager config, SessionStatics statics)
{
statics.BindWith(Static.LastLocalUserScore, referenceScore);

Children = new Drawable[]
{
beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapHitsounds },
new PlayerCheckbox
{
LabelText = SkinSettingsStrings.BeatmapHitsounds,
Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds),
},
new PlayerSliderBar<double>
{
LabelText = SkinSettingsStrings.HitsoundVolume,
Current = config.GetBindable<double>(OsuSetting.HitsoundVolume),
KeyboardStep = 0.01f,
DisplayAsPercentage = true,
},
new BeatmapOffsetControl
{
ReferenceScore = { BindTarget = referenceScore },
},
};
}

[BackgroundDependencyLoader]
private void load(OsuConfigManager config, SessionStatics statics)
{
beatmapHitsoundsToggle.Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds);
statics.BindWith(Static.LastLocalUserScore, referenceScore);
}
}
}
8 changes: 4 additions & 4 deletions osu.Game/Skinning/ArgonProSkin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ public class ArgonProSkin : ArgonSkin
{
foreach (string lookup in sampleInfo.LookupNames)
{
var sample = Samples?.Get(lookup)
?? Resources.AudioManager?.Samples.Get(lookup.Replace(@"Gameplay/", @"Gameplay/ArgonPro/"))
?? Resources.AudioManager?.Samples.Get(lookup.Replace(@"Gameplay/", @"Gameplay/Argon/"))
?? Resources.AudioManager?.Samples.Get(lookup);
var sample = GetSampleFromSkinFiles(lookup, sampleInfo.IsHitsound)
?? GetSampleFromResourceFiles(lookup.Replace(@"Gameplay/", @"Gameplay/ArgonPro/"), sampleInfo.IsHitsound)
?? GetSampleFromResourceFiles(lookup.Replace(@"Gameplay/", @"Gameplay/Argon/"), sampleInfo.IsHitsound)
?? GetSampleFromResourceFiles(lookup, sampleInfo.IsHitsound);

if (sample != null)
return sample;
Expand Down
6 changes: 3 additions & 3 deletions osu.Game/Skinning/ArgonSkin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources)
{
foreach (string lookup in sampleInfo.LookupNames)
{
var sample = Samples?.Get(lookup)
?? Resources.AudioManager?.Samples.Get(lookup.Replace(@"Gameplay/", @"Gameplay/Argon/"))
?? Resources.AudioManager?.Samples.Get(lookup);
var sample = GetSampleFromSkinFiles(lookup, sampleInfo.IsHitsound)
?? GetSampleFromResourceFiles(lookup.Replace(@"Gameplay/", @"Gameplay/Argon/"), sampleInfo.IsHitsound)
?? GetSampleFromResourceFiles(lookup, sampleInfo.IsHitsound);

if (sample != null)
return sample;
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Skinning/LegacySkin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ protected override void ParseConfigurationStream(Stream stream)

foreach (string lookup in lookupNames)
{
var sample = Samples?.Get(lookup);
var sample = GetSampleFromSkinFiles(lookup, sampleInfo.IsHitsound);

if (sample != null)
{
Expand Down
Loading
Loading