1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 12:57:36 +08:00

Add a low-pass filter effect to music when certain popup dialogs are shown

This commit is contained in:
Jamie Taylor 2021-09-23 20:14:32 +09:00
parent 8bbd8cd948
commit 94e2dbd7e7
No known key found for this signature in database
GPG Key ID: 2ACFA8B6370B8C8C
2 changed files with 90 additions and 0 deletions

View File

@ -0,0 +1,75 @@
// 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 ManagedBass.Fx;
using osu.Framework.Audio.Mixing;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Audio.Effects
{
public class LowPassFilter : Component
{
private const float filter_cutoff_start = 2000;
private const float filter_cutoff_end = 150;
private const float filter_sweep_duration = 100;
private readonly Bindable<float> filterFreq = new Bindable<float>(filter_cutoff_start);
private readonly AudioMixer mixer;
private readonly BQFParameters filter;
/// <summary>
/// A toggle-able low-pass filter with a subtle filter-sweep effect when toggled that can be attached to an <see cref="AudioMixer"/>.
/// </summary>
public LowPassFilter(AudioMixer mixer)
{
this.mixer = mixer;
filter = new BQFParameters
{
lFilter = BQFType.LowPass,
fCenter = filterFreq.Value
};
}
public void Enable()
{
attachFilter();
this.TransformBindableTo(filterFreq, filter_cutoff_end, filter_sweep_duration);
}
public void Disable()
{
this.TransformBindableTo(filterFreq, filter_cutoff_start, filter_sweep_duration)
.OnComplete(_ => detatchFilter());
}
private void attachFilter()
{
mixer.Effects.Add(filter);
filterFreq.ValueChanged += updateFilter;
}
private void detatchFilter()
{
filterFreq.ValueChanged -= updateFilter;
mixer.Effects.Remove(filter);
}
private void updateFilter(ValueChangedEvent<float> cutoff)
{
var filterIndex = mixer.Effects.IndexOf(filter);
if (filterIndex < 0) return;
var existingFilter = mixer.Effects[filterIndex] as BQFParameters;
if (existingFilter == null) return;
existingFilter.fCenter = cutoff.NewValue;
mixer.Effects[filterIndex] = existingFilter;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
detatchFilter();
}
}
}

View File

@ -7,7 +7,10 @@ using osu.Game.Overlays.Dialog;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Audio.Effects;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
@ -18,6 +21,8 @@ namespace osu.Game.Overlays
protected override string PopInSampleName => "UI/dialog-pop-in"; protected override string PopInSampleName => "UI/dialog-pop-in";
protected override string PopOutSampleName => "UI/dialog-pop-out"; protected override string PopOutSampleName => "UI/dialog-pop-out";
private LowPassFilter filter;
public PopupDialog CurrentDialog { get; private set; } public PopupDialog CurrentDialog { get; private set; }
public DialogOverlay() public DialogOverlay()
@ -34,6 +39,12 @@ namespace osu.Game.Overlays
Origin = Anchor.BottomCentre; Origin = Anchor.BottomCentre;
} }
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
AddInternal(filter = new LowPassFilter(audio.TrackMixer));
}
public void Push(PopupDialog dialog) public void Push(PopupDialog dialog)
{ {
if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return; if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return;
@ -71,12 +82,16 @@ namespace osu.Game.Overlays
{ {
base.PopIn(); base.PopIn();
this.FadeIn(PopupDialog.ENTER_DURATION, Easing.OutQuint); this.FadeIn(PopupDialog.ENTER_DURATION, Easing.OutQuint);
filter.Enable();
} }
protected override void PopOut() protected override void PopOut()
{ {
base.PopOut(); base.PopOut();
if (IsLoaded)
filter.Disable();
if (CurrentDialog?.State.Value == Visibility.Visible) if (CurrentDialog?.State.Value == Visibility.Visible)
{ {
CurrentDialog.Hide(); CurrentDialog.Hide();