diff mbox series

[FFmpeg-devel] avfilter: add tiltshelf audio filter

Message ID 20220528072327.116623-1-onemda@gmail.com
State New
Headers show
Series [FFmpeg-devel] avfilter: add tiltshelf audio filter | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_armv7_RPi4 success Make finished
andriy/make_fate_armv7_RPi4 success Make fate finished

Commit Message

Paul B Mahol May 28, 2022, 7:23 a.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 doc/filters.texi         | 91 ++++++++++++++++++++++++++++++++++++++++
 libavfilter/af_biquads.c | 39 ++++++++++++++---
 libavfilter/allfilters.c |  1 +
 3 files changed, 125 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index 0e10946cca..d65e83d4d0 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -6690,6 +6690,97 @@  Set window overlap. If set to 1, the recommended overlap for selected
 window function will be picked. Default is @code{0.5}.
 @end table
 
+@section tiltshelf
+
+Boost or cut the lower frequencies and cut or boost higher frequencies
+of the audio using a two-pole shelving filter with a response similar to
+that of a standard hi-fi's tone-controls.
+This is also known as shelving equalisation (EQ).
+
+The filter accepts the following options:
+
+@table @option
+@item gain, g
+Give the gain at 0 Hz. Its useful range is about -20
+(for a large cut) to +20 (for a large boost).
+Beware of clipping when using a positive gain.
+
+@item frequency, f
+Set the filter's central frequency and so can be used
+to extend or reduce the frequency range to be boosted or cut.
+The default value is @code{3000} Hz.
+
+@item width_type, t
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@item k
+kHz
+@end table
+
+@item width, w
+Determine how steep is the filter's shelf transition.
+
+@item poles, p
+Set number of poles. Default is 2.
+
+@item mix, m
+How much to use filtered signal in output. Default is 1.
+Range is between 0 and 1.
+
+@item channels, c
+Specify which channels to filter, by default all available are filtered.
+
+@item normalize, n
+Normalize biquad coefficients, by default is disabled.
+Enabling it will normalize magnitude response at DC to 0dB.
+
+@item transform, a
+Set transform type of IIR filter.
+@table @option
+@item di
+@item dii
+@item tdi
+@item tdii
+@item latt
+@item svf
+@item zdf
+@end table
+
+@item precision, r
+Set precison of filtering.
+@table @option
+@item auto
+Pick automatic sample format depending on surround filters.
+@item s16
+Always use signed 16-bit.
+@item s32
+Always use signed 32-bit.
+@item f32
+Always use float 32-bit.
+@item f64
+Always use float 64-bit.
+@end table
+
+@item block_size, b
+Set block size used for reverse IIR processing. If this value is set to high enough
+value (higher than impulse response length truncated when reaches near zero values) filtering
+will become linear phase otherwise if not big enough it will just produce nasty artifacts.
+
+Note that filter delay will be exactly this many samples when set to non-zero value.
+@end table
+
+@subsection Commands
+
+This filter supports some options as @ref{commands}.
+
 @section treble, highshelf
 
 Boost or cut treble (upper) frequencies of the audio using a two-pole
diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
index 26cb4d49bb..9110faabac 100644
--- a/libavfilter/af_biquads.c
+++ b/libavfilter/af_biquads.c
@@ -85,6 +85,7 @@  enum FilterType {
     lowpass,
     lowshelf,
     highshelf,
+    tiltshelf,
 };
 
 enum WidthType {
@@ -698,6 +699,17 @@  static void convert_dir2zdf(BiquadsContext *s, int sample_rate)
         m[1] = k * (A - 1.);
         m[2] = A * A - 1.;
         break;
+    case tiltshelf:
+        A = ff_exp10(s->gain / 20.);
+        g = tan(M_PI * s->frequency / sample_rate) / sqrt(A);
+        k = 1. / Q;
+        a[0] = 1. / (1. + g * (g + k));
+        a[1] = g * a[0];
+        a[2] = g * a[1];
+        m[0] = 1./ A;
+        m[1] = k * (A - 1.) / A;
+        m[2] = (A * A - 1.) / A;
+        break;
     case treble:
     case highshelf:
         A = ff_exp10(s->gain / 40.);
@@ -777,7 +789,8 @@  static int config_filter(AVFilterLink *outlink, int reset)
     AVFilterContext *ctx    = outlink->src;
     BiquadsContext *s       = ctx->priv;
     AVFilterLink *inlink    = ctx->inputs[0];
-    double A = ff_exp10(s->gain / 40);
+    double gain = s->gain * ((s->filter_type == tiltshelf) + 1.);
+    double A = ff_exp10(gain / 40);
     double w0 = 2 * M_PI * s->frequency / inlink->sample_rate;
     double K = tan(w0 / 2.);
     double alpha, beta;
@@ -835,9 +848,10 @@  static int config_filter(AVFilterLink *outlink, int reset)
         break;
     case bass:
         beta = sqrt((A * A + 1) - (A - 1) * (A - 1));
+    case tiltshelf:
     case lowshelf:
         if (s->poles == 1) {
-            double A = ff_exp10(s->gain / 20);
+            double A = ff_exp10(gain / 20);
             double ro = -sin(w0 / 2. - M_PI_4) / sin(w0 / 2. + M_PI_4);
             double n = (A + 1) / (A - 1);
             double alpha1 = A == 1. ? 0. : n - FFSIGN(n) * sqrt(n * n - 1);
@@ -863,7 +877,7 @@  static int config_filter(AVFilterLink *outlink, int reset)
         beta = sqrt((A * A + 1) - (A - 1) * (A - 1));
     case highshelf:
         if (s->poles == 1) {
-            double A = ff_exp10(s->gain / 20);
+            double A = ff_exp10(gain / 20);
             double ro = sin(w0 / 2. - M_PI_4) / sin(w0 / 2. + M_PI_4);
             double n = (A + 1) / (A - 1);
             double alpha1 = A == 1. ? 0. : n - FFSIGN(n) * sqrt(n * n - 1);
@@ -985,6 +999,14 @@  static int config_filter(AVFilterLink *outlink, int reset)
         s->b2 *= factor;
     }
 
+    switch (s->filter_type) {
+    case tiltshelf:
+        s->b0 /= A;
+        s->b1 /= A;
+        s->b2 /= A;
+        break;
+    }
+
     s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->ch_layout.nb_channels);
     if (!s->cache)
         return AVERROR(ENOMEM);
@@ -1528,7 +1550,7 @@  DEFINE_BIQUAD_FILTER_2(bass, "Boost or cut lower frequencies.", bass_lowshelf);
 DEFINE_BIQUAD_FILTER_2(lowshelf, "Apply a low shelf filter.", bass_lowshelf);
 #endif  /* CONFIG_LOWSHELF_FILTER */
 #endif  /* CONFIG_BASS_FILTER || CONFIG LOWSHELF_FILTER */
-#if CONFIG_TREBLE_FILTER || CONFIG_HIGHSHELF_FILTER
+#if CONFIG_TREBLE_FILTER || CONFIG_HIGHSHELF_FILTER || CONFIG_TILTSHELF_FILTER
 static const AVOption treble_highshelf_options[] = {
     {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
     {"f",         "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
@@ -1572,7 +1594,7 @@  static const AVOption treble_highshelf_options[] = {
     {NULL}
 };
 
-AVFILTER_DEFINE_CLASS_EXT(treble_highshelf, "treble/highshelf",
+AVFILTER_DEFINE_CLASS_EXT(treble_highshelf, "treble/high/tiltshelf",
                           treble_highshelf_options);
 
 #if CONFIG_TREBLE_FILTER
@@ -1582,7 +1604,12 @@  DEFINE_BIQUAD_FILTER_2(treble, "Boost or cut upper frequencies.", treble_highshe
 #if CONFIG_HIGHSHELF_FILTER
 DEFINE_BIQUAD_FILTER_2(highshelf, "Apply a high shelf filter.", treble_highshelf);
 #endif  /* CONFIG_HIGHSHELF_FILTER */
-#endif  /* CONFIG_TREBLE_FILTER || CONFIG_HIGHSHELF_FILTER */
+
+#if CONFIG_TILTSHELF_FILTER
+DEFINE_BIQUAD_FILTER_2(tiltshelf, "Apply a tilt shelf filter.", treble_highshelf);
+#endif
+#endif  /* CONFIG_TREBLE_FILTER || CONFIG_HIGHSHELF_FILTER || CONFIG_TILTSHELF_FILTER */
+
 #if CONFIG_BANDPASS_FILTER
 static const AVOption bandpass_options[] = {
     {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 2409964e53..2f72477523 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -149,6 +149,7 @@  extern const AVFilter ff_af_stereotools;
 extern const AVFilter ff_af_stereowiden;
 extern const AVFilter ff_af_superequalizer;
 extern const AVFilter ff_af_surround;
+extern const AVFilter ff_af_tiltshelf;
 extern const AVFilter ff_af_treble;
 extern const AVFilter ff_af_tremolo;
 extern const AVFilter ff_af_vibrato;