diff --git a/osu.Game/Audio/Effects/LowPassFilter.cs b/osu.Game/Audio/Effects/LowPassFilter.cs new file mode 100644 index 0000000000..b1e78e4324 --- /dev/null +++ b/osu.Game/Audio/Effects/LowPassFilter.cs @@ -0,0 +1,75 @@ +// Copyright (c) ppy Pty Ltd . 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 filterFreq = new Bindable(filter_cutoff_start); + private readonly AudioMixer mixer; + private readonly BQFParameters filter; + + /// + /// A toggle-able low-pass filter with a subtle filter-sweep effect when toggled that can be attached to an . + /// + 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 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(); + } + } +} diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index f051e09c08..d653ef3888 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -7,7 +7,10 @@ using osu.Game.Overlays.Dialog; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Input.Events; +using osu.Game.Audio.Effects; namespace osu.Game.Overlays { @@ -18,6 +21,8 @@ namespace osu.Game.Overlays protected override string PopInSampleName => "UI/dialog-pop-in"; protected override string PopOutSampleName => "UI/dialog-pop-out"; + private LowPassFilter filter; + public PopupDialog CurrentDialog { get; private set; } public DialogOverlay() @@ -34,6 +39,12 @@ namespace osu.Game.Overlays Origin = Anchor.BottomCentre; } + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + AddInternal(filter = new LowPassFilter(audio.TrackMixer)); + } + public void Push(PopupDialog dialog) { if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return; @@ -71,12 +82,16 @@ namespace osu.Game.Overlays { base.PopIn(); this.FadeIn(PopupDialog.ENTER_DURATION, Easing.OutQuint); + filter.Enable(); } protected override void PopOut() { base.PopOut(); + if (IsLoaded) + filter.Disable(); + if (CurrentDialog?.State.Value == Visibility.Visible) { CurrentDialog.Hide();