1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 13:37:25 +08:00

Avoid using bindable for AudioFilter cutoff

It doesn't play nicely with screen exiting, as it is automatically
unbound during the exit process. Easiest to just avoid using this for
now.
This commit is contained in:
Dean Herbert 2021-10-13 13:25:30 +09:00
parent 6f79d29ba4
commit b37096f440
3 changed files with 50 additions and 35 deletions

View File

@ -34,6 +34,9 @@ namespace osu.Game.Tests.Visual.Audio
beatmap = new WaveformTestBeatmap(audio); beatmap = new WaveformTestBeatmap(audio);
track = beatmap.LoadTrack(); track = beatmap.LoadTrack();
OsuSliderBar<int> lowPassCutoff;
OsuSliderBar<int> highPassCutoff;
Add(new FillFlowContainer Add(new FillFlowContainer
{ {
Children = new Drawable[] Children = new Drawable[]
@ -43,33 +46,41 @@ namespace osu.Game.Tests.Visual.Audio
lowpassText = new OsuSpriteText lowpassText = new OsuSpriteText
{ {
Padding = new MarginPadding(20), Padding = new MarginPadding(20),
Text = $"Low Pass: {lowpassFilter.Cutoff.Value}hz", Text = $"Low Pass: {lowpassFilter.Cutoff}hz",
Font = new FontUsage(size: 40) Font = new FontUsage(size: 40)
}, },
new OsuSliderBar<int> lowPassCutoff = new OsuSliderBar<int>
{ {
Width = 500, Width = 500,
Height = 50, Height = 50,
Padding = new MarginPadding(20), Padding = new MarginPadding(20),
Current = { BindTarget = lowpassFilter.Cutoff }
}, },
highpassText = new OsuSpriteText highpassText = new OsuSpriteText
{ {
Padding = new MarginPadding(20), Padding = new MarginPadding(20),
Text = $"High Pass: {highpassFilter.Cutoff.Value}hz", Text = $"High Pass: {highpassFilter.Cutoff}hz",
Font = new FontUsage(size: 40) Font = new FontUsage(size: 40)
}, },
new OsuSliderBar<int> highPassCutoff = new OsuSliderBar<int>
{ {
Width = 500, Width = 500,
Height = 50, Height = 50,
Padding = new MarginPadding(20), Padding = new MarginPadding(20),
Current = { BindTarget = highpassFilter.Cutoff }
} }
} }
}); });
lowpassFilter.Cutoff.ValueChanged += e => lowpassText.Text = $"Low Pass: {e.NewValue}hz";
highpassFilter.Cutoff.ValueChanged += e => highpassText.Text = $"High Pass: {e.NewValue}hz"; lowPassCutoff.Current.ValueChanged += e =>
{
lowpassText.Text = $"Low Pass: {e.NewValue}hz";
lowpassFilter.Cutoff = e.NewValue;
};
highPassCutoff.Current.ValueChanged += e =>
{
highpassText.Text = $"High Pass: {e.NewValue}hz";
highpassFilter.Cutoff = e.NewValue;
};
} }
[SetUpSteps] [SetUpSteps]

View File

@ -4,7 +4,6 @@
using System.Diagnostics; using System.Diagnostics;
using ManagedBass.Fx; using ManagedBass.Fx;
using osu.Framework.Audio.Mixing; using osu.Framework.Audio.Mixing;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
namespace osu.Game.Audio.Effects namespace osu.Game.Audio.Effects
@ -21,10 +20,25 @@ namespace osu.Game.Audio.Effects
private readonly BQFParameters filter; private readonly BQFParameters filter;
private readonly BQFType type; private readonly BQFType type;
private int cutoff;
/// <summary> /// <summary>
/// The current cutoff of this filter. /// The cutoff frequency of this filter.
/// </summary> /// </summary>
public BindableNumber<int> Cutoff { get; } public int Cutoff
{
get => cutoff;
set
{
if (value == cutoff)
return;
int oldValue = cutoff;
cutoff = value;
updateFilter(oldValue, cutoff);
}
}
/// <summary> /// <summary>
/// A Component that implements a BASS FX BiQuad Filter Effect. /// A Component that implements a BASS FX BiQuad Filter Effect.
@ -36,33 +50,25 @@ namespace osu.Game.Audio.Effects
this.mixer = mixer; this.mixer = mixer;
this.type = type; this.type = type;
int initialCutoff;
switch (type) switch (type)
{ {
case BQFType.HighPass: case BQFType.HighPass:
initialCutoff = 1; cutoff = 1;
break; break;
case BQFType.LowPass: case BQFType.LowPass:
initialCutoff = MAX_LOWPASS_CUTOFF; cutoff = MAX_LOWPASS_CUTOFF;
break; break;
default: default:
initialCutoff = 500; // A default that should ensure audio remains audible for other filters. cutoff = 500; // A default that should ensure audio remains audible for other filters.
break; break;
} }
Cutoff = new BindableNumber<int>(initialCutoff)
{
MinValue = 1,
MaxValue = MAX_LOWPASS_CUTOFF
};
filter = new BQFParameters filter = new BQFParameters
{ {
lFilter = type, lFilter = type,
fCenter = initialCutoff, fCenter = cutoff,
fBandwidth = 0, fBandwidth = 0,
fQ = 0.7f // This allows fCenter to go up to 22049hz (nyquist - 1hz) without overflowing and causing weird filter behaviour (see: https://www.un4seen.com/forum/?topic=19542.0) fQ = 0.7f // This allows fCenter to go up to 22049hz (nyquist - 1hz) without overflowing and causing weird filter behaviour (see: https://www.un4seen.com/forum/?topic=19542.0)
}; };
@ -70,8 +76,6 @@ namespace osu.Game.Audio.Effects
// Don't start attached if this is low-pass or high-pass filter (as they have special auto-attach/detach logic) // Don't start attached if this is low-pass or high-pass filter (as they have special auto-attach/detach logic)
if (type != BQFType.LowPass && type != BQFType.HighPass) if (type != BQFType.LowPass && type != BQFType.HighPass)
attachFilter(); attachFilter();
Cutoff.ValueChanged += updateFilter;
} }
private void attachFilter() private void attachFilter()
@ -86,40 +90,41 @@ namespace osu.Game.Audio.Effects
mixer.Effects.Remove(filter); mixer.Effects.Remove(filter);
} }
private void updateFilter(ValueChangedEvent<int> cutoff) private void updateFilter(int oldValue, int newValue)
{ {
// Workaround for weird behaviour when rapidly setting fCenter of a low-pass filter to nyquist - 1hz. // Workaround for weird behaviour when rapidly setting fCenter of a low-pass filter to nyquist - 1hz.
if (type == BQFType.LowPass) if (type == BQFType.LowPass)
{ {
if (cutoff.NewValue >= MAX_LOWPASS_CUTOFF) if (newValue >= MAX_LOWPASS_CUTOFF)
{ {
detachFilter(); detachFilter();
return; return;
} }
if (cutoff.OldValue >= MAX_LOWPASS_CUTOFF && cutoff.NewValue < MAX_LOWPASS_CUTOFF) if (oldValue >= MAX_LOWPASS_CUTOFF)
attachFilter(); attachFilter();
} }
// Workaround for weird behaviour when rapidly setting fCenter of a high-pass filter to 1hz. // Workaround for weird behaviour when rapidly setting fCenter of a high-pass filter to 1hz.
if (type == BQFType.HighPass) if (type == BQFType.HighPass)
{ {
if (cutoff.NewValue <= 1) if (newValue <= 1)
{ {
detachFilter(); detachFilter();
return; return;
} }
if (cutoff.OldValue <= 1 && cutoff.NewValue > 1) if (oldValue <= 1)
attachFilter(); attachFilter();
} }
var filterIndex = mixer.Effects.IndexOf(filter); var filterIndex = mixer.Effects.IndexOf(filter);
if (filterIndex < 0) return; if (filterIndex < 0) return;
if (mixer.Effects[filterIndex] is BQFParameters existingFilter) if (mixer.Effects[filterIndex] is BQFParameters existingFilter)
{ {
existingFilter.fCenter = cutoff.NewValue; existingFilter.fCenter = newValue;
// required to update effect with new parameters. // required to update effect with new parameters.
mixer.Effects[filterIndex] = existingFilter; mixer.Effects[filterIndex] = existingFilter;

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms; using osu.Framework.Graphics.Transforms;
@ -12,7 +11,7 @@ namespace osu.Game.Audio.Effects
/// <summary> /// <summary>
/// The filter cutoff. /// The filter cutoff.
/// </summary> /// </summary>
BindableNumber<int> Cutoff { get; } int Cutoff { get; set; }
} }
public static class FilterableAudioComponentExtensions public static class FilterableAudioComponentExtensions
@ -40,7 +39,7 @@ namespace osu.Game.Audio.Effects
public static TransformSequence<T> CutoffTo<T, TEasing>(this T component, int newCutoff, double duration, TEasing easing) public static TransformSequence<T> CutoffTo<T, TEasing>(this T component, int newCutoff, double duration, TEasing easing)
where T : class, ITransformableFilter, IDrawable where T : class, ITransformableFilter, IDrawable
where TEasing : IEasingFunction where TEasing : IEasingFunction
=> component.TransformBindableTo(component.Cutoff, newCutoff, duration, easing); => component.TransformTo(nameof(component.Cutoff), newCutoff, duration, easing);
/// <summary> /// <summary>
/// Smoothly adjusts filter cutoff over time. /// Smoothly adjusts filter cutoff over time.
@ -49,6 +48,6 @@ namespace osu.Game.Audio.Effects
public static TransformSequence<T> CutoffTo<T, TEasing>(this TransformSequence<T> sequence, int newCutoff, double duration, TEasing easing) public static TransformSequence<T> CutoffTo<T, TEasing>(this TransformSequence<T> sequence, int newCutoff, double duration, TEasing easing)
where T : class, ITransformableFilter, IDrawable where T : class, ITransformableFilter, IDrawable
where TEasing : IEasingFunction where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Cutoff, newCutoff, duration, easing)); => sequence.Append(o => o.TransformTo(nameof(o.Cutoff), newCutoff, duration, easing));
} }
} }