mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 03:22:55 +08:00
Set fQ to recommended value from BASS developer to prevent filter calculations from overflowing when approaching nyquist
This commit is contained in:
parent
2a4a376b87
commit
df182ba92b
@ -10,7 +10,7 @@ namespace osu.Game.Audio.Effects
|
|||||||
{
|
{
|
||||||
public class Filter : Component, ITransformableFilter
|
public class Filter : Component, ITransformableFilter
|
||||||
{
|
{
|
||||||
public readonly int MaxCutoff;
|
public readonly int MaxCutoff = 22049; // nyquist - 1hz
|
||||||
private readonly AudioMixer mixer;
|
private readonly AudioMixer mixer;
|
||||||
private readonly BQFParameters filter;
|
private readonly BQFParameters filter;
|
||||||
private readonly BQFType type;
|
private readonly BQFType type;
|
||||||
@ -18,36 +18,29 @@ namespace osu.Game.Audio.Effects
|
|||||||
public BindableNumber<int> Cutoff { get; }
|
public BindableNumber<int> Cutoff { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A BiQuad filter that performs a filter-sweep when toggled on or off.
|
/// A Component that implements a BASS FX BiQuad Filter Effect.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mixer">The mixer this effect should be attached to.</param>
|
/// <param name="mixer">The mixer this effect should be applied to.</param>
|
||||||
/// <param name="type">The type of filter (e.g. LowPass, HighPass, etc)</param>
|
/// <param name="type">The type of filter (e.g. LowPass, HighPass, etc)</param>
|
||||||
public Filter(AudioMixer mixer, BQFType type = BQFType.LowPass)
|
public Filter(AudioMixer mixer, BQFType type = BQFType.LowPass)
|
||||||
{
|
{
|
||||||
this.mixer = mixer;
|
this.mixer = mixer;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
||||||
var initialCutoff = 1;
|
int initialCutoff;
|
||||||
|
|
||||||
// These max cutoff values are a work-around for BASS' BiQuad filters behaving weirdly when approaching nyquist.
|
|
||||||
// Note that these values assume a sample rate of 44100 (as per BassAudioMixer in osu.Framework)
|
|
||||||
// See also https://www.un4seen.com/forum/?topic=19542.0 for more information.
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case BQFType.HighPass:
|
case BQFType.HighPass:
|
||||||
MaxCutoff = 21968; // beyond this value, the high-pass cuts out
|
initialCutoff = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BQFType.LowPass:
|
case BQFType.LowPass:
|
||||||
MaxCutoff = initialCutoff = 14000; // beyond (roughly) this value, the low-pass filter audibly wraps/reflects
|
initialCutoff = MaxCutoff;
|
||||||
break;
|
|
||||||
|
|
||||||
case BQFType.BandPass:
|
|
||||||
MaxCutoff = 16000; // beyond (roughly) this value, the band-pass filter audibly wraps/reflects
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MaxCutoff = 22050; // default to nyquist for other filter types, TODO: handle quirks of other filter types
|
initialCutoff = 500; // A default that should ensure audio remains audible for other filters.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +52,12 @@ namespace osu.Game.Audio.Effects
|
|||||||
filter = new BQFParameters
|
filter = new BQFParameters
|
||||||
{
|
{
|
||||||
lFilter = type,
|
lFilter = type,
|
||||||
fCenter = initialCutoff
|
fCenter = initialCutoff,
|
||||||
|
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)
|
||||||
};
|
};
|
||||||
|
|
||||||
attachFilter();
|
attachFilter();
|
||||||
|
|
||||||
Cutoff.ValueChanged += updateFilter;
|
Cutoff.ValueChanged += updateFilter;
|
||||||
Cutoff.Value = initialCutoff;
|
Cutoff.Value = initialCutoff;
|
||||||
}
|
}
|
||||||
@ -74,9 +68,7 @@ namespace osu.Game.Audio.Effects
|
|||||||
|
|
||||||
private void updateFilter(ValueChangedEvent<int> cutoff)
|
private void updateFilter(ValueChangedEvent<int> cutoff)
|
||||||
{
|
{
|
||||||
// This is another workaround for quirks in BASS' BiQuad filters.
|
// Workaround for weird behaviour when rapidly setting fCenter of a low-pass filter to nyquist - 1hz.
|
||||||
// Because the cutoff can't be set above ~14khz (i.e. outside of human hearing range) without the aforementioned wrapping/reflecting quirk occuring, we instead
|
|
||||||
// remove the effect from the mixer when the cutoff is at maximum so that a LowPass filter isn't always attenuating high frequencies just by existing.
|
|
||||||
if (type == BQFType.LowPass)
|
if (type == BQFType.LowPass)
|
||||||
{
|
{
|
||||||
if (cutoff.NewValue >= MaxCutoff)
|
if (cutoff.NewValue >= MaxCutoff)
|
||||||
@ -89,6 +81,19 @@ namespace osu.Game.Audio.Effects
|
|||||||
attachFilter();
|
attachFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround for weird behaviour when rapidly setting fCenter of a high-pass filter to 1hz.
|
||||||
|
if (type == BQFType.HighPass)
|
||||||
|
{
|
||||||
|
if (cutoff.NewValue <= 1)
|
||||||
|
{
|
||||||
|
detachFilter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cutoff.OldValue <= 1 && cutoff.NewValue > 1)
|
||||||
|
attachFilter();
|
||||||
|
}
|
||||||
|
|
||||||
var filterIndex = mixer.Effects.IndexOf(filter);
|
var filterIndex = mixer.Effects.IndexOf(filter);
|
||||||
if (filterIndex < 0) return;
|
if (filterIndex < 0) return;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user