1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 21:27:24 +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);
track = beatmap.LoadTrack();
OsuSliderBar<int> lowPassCutoff;
OsuSliderBar<int> highPassCutoff;
Add(new FillFlowContainer
{
Children = new Drawable[]
@ -43,33 +46,41 @@ namespace osu.Game.Tests.Visual.Audio
lowpassText = new OsuSpriteText
{
Padding = new MarginPadding(20),
Text = $"Low Pass: {lowpassFilter.Cutoff.Value}hz",
Text = $"Low Pass: {lowpassFilter.Cutoff}hz",
Font = new FontUsage(size: 40)
},
new OsuSliderBar<int>
lowPassCutoff = new OsuSliderBar<int>
{
Width = 500,
Height = 50,
Padding = new MarginPadding(20),
Current = { BindTarget = lowpassFilter.Cutoff }
},
highpassText = new OsuSpriteText
{
Padding = new MarginPadding(20),
Text = $"High Pass: {highpassFilter.Cutoff.Value}hz",
Text = $"High Pass: {highpassFilter.Cutoff}hz",
Font = new FontUsage(size: 40)
},
new OsuSliderBar<int>
highPassCutoff = new OsuSliderBar<int>
{
Width = 500,
Height = 50,
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]

View File

@ -4,7 +4,6 @@
using System.Diagnostics;
using ManagedBass.Fx;
using osu.Framework.Audio.Mixing;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Audio.Effects
@ -21,10 +20,25 @@ namespace osu.Game.Audio.Effects
private readonly BQFParameters filter;
private readonly BQFType type;
private int cutoff;
/// <summary>
/// The current cutoff of this filter.
/// The cutoff frequency of this filter.
/// </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>
/// A Component that implements a BASS FX BiQuad Filter Effect.
@ -36,33 +50,25 @@ namespace osu.Game.Audio.Effects
this.mixer = mixer;
this.type = type;
int initialCutoff;
switch (type)
{
case BQFType.HighPass:
initialCutoff = 1;
cutoff = 1;
break;
case BQFType.LowPass:
initialCutoff = MAX_LOWPASS_CUTOFF;
cutoff = MAX_LOWPASS_CUTOFF;
break;
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;
}
Cutoff = new BindableNumber<int>(initialCutoff)
{
MinValue = 1,
MaxValue = MAX_LOWPASS_CUTOFF
};
filter = new BQFParameters
{
lFilter = type,
fCenter = initialCutoff,
fCenter = cutoff,
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)
};
@ -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)
if (type != BQFType.LowPass && type != BQFType.HighPass)
attachFilter();
Cutoff.ValueChanged += updateFilter;
}
private void attachFilter()
@ -86,40 +90,41 @@ namespace osu.Game.Audio.Effects
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.
if (type == BQFType.LowPass)
{
if (cutoff.NewValue >= MAX_LOWPASS_CUTOFF)
if (newValue >= MAX_LOWPASS_CUTOFF)
{
detachFilter();
return;
}
if (cutoff.OldValue >= MAX_LOWPASS_CUTOFF && cutoff.NewValue < MAX_LOWPASS_CUTOFF)
if (oldValue >= MAX_LOWPASS_CUTOFF)
attachFilter();
}
// Workaround for weird behaviour when rapidly setting fCenter of a high-pass filter to 1hz.
if (type == BQFType.HighPass)
{
if (cutoff.NewValue <= 1)
if (newValue <= 1)
{
detachFilter();
return;
}
if (cutoff.OldValue <= 1 && cutoff.NewValue > 1)
if (oldValue <= 1)
attachFilter();
}
var filterIndex = mixer.Effects.IndexOf(filter);
if (filterIndex < 0) return;
if (mixer.Effects[filterIndex] is BQFParameters existingFilter)
{
existingFilter.fCenter = cutoff.NewValue;
existingFilter.fCenter = newValue;
// required to update effect with new parameters.
mixer.Effects[filterIndex] = existingFilter;

View File

@ -1,7 +1,6 @@
// 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 osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
@ -12,7 +11,7 @@ namespace osu.Game.Audio.Effects
/// <summary>
/// The filter cutoff.
/// </summary>
BindableNumber<int> Cutoff { get; }
int Cutoff { get; set; }
}
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)
where T : class, ITransformableFilter, IDrawable
where TEasing : IEasingFunction
=> component.TransformBindableTo(component.Cutoff, newCutoff, duration, easing);
=> component.TransformTo(nameof(component.Cutoff), newCutoff, duration, easing);
/// <summary>
/// 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)
where T : class, ITransformableFilter, IDrawable
where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Cutoff, newCutoff, duration, easing));
=> sequence.Append(o => o.TransformTo(nameof(o.Cutoff), newCutoff, duration, easing));
}
}