Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] new audio filter and misc improvements
@ 2023-08-09 21:36 Paul B Mahol
  2023-08-10  9:47 ` Michael Niedermayer
  0 siblings, 1 reply; 6+ messages in thread
From: Paul B Mahol @ 2023-08-09 21:36 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

[-- Attachment #1: Type: text/plain, Size: 18 bytes --]

Patches attached.

[-- Attachment #2: 0003-avfilter-af_adeclick-do-not-output-pointless-message.patch --]
[-- Type: text/x-patch, Size: 1198 bytes --]

From 2d8c330f543397642fa1afe0a01a67155008d4e1 Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 21:53:04 +0200
Subject: [PATCH 3/3] avfilter/af_adeclick: do not output pointless message

Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavfilter/af_adeclick.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index fd0438d252..3401028c6b 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -721,9 +721,10 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     AudioDeclickContext *s = ctx->priv;
 
-    av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
-           filter_modes[s->mode], s->detected_errors,
-           s->nb_samples, 100. * s->detected_errors / s->nb_samples);
+    if (s->nb_samples > 0)
+        av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
+               filter_modes[s->mode], s->detected_errors,
+               s->nb_samples, 100. * s->detected_errors / s->nb_samples);
 
     av_audio_fifo_free(s->fifo);
     av_audio_fifo_free(s->efifo);
-- 
2.39.1


[-- Attachment #3: 0002-avfilter-af_adeclick-refactor-and-cleanup.patch --]
[-- Type: text/x-patch, Size: 15328 bytes --]

From 0a6de9b1482ece4402b1c7274501b43e43f5f56a Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 21:49:19 +0200
Subject: [PATCH 2/3] avfilter/af_adeclick: refactor and cleanup

Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavfilter/af_adeclick.c | 136 +++++++++++++++++++-------------------
 1 file changed, 67 insertions(+), 69 deletions(-)

diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index 1137dbe25b..fd0438d252 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -119,7 +119,6 @@ static int config_input(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
     AudioDeclickContext *s = ctx->priv;
-    int i;
 
     s->pts = AV_NOPTS_VALUE;
     s->window_size = inlink->sample_rate * s->w / 1000.;
@@ -134,7 +133,7 @@ static int config_input(AVFilterLink *inlink)
     s->window_func_lut = av_calloc(s->window_size, sizeof(*s->window_func_lut));
     if (!s->window_func_lut)
         return AVERROR(ENOMEM);
-    for (i = 0; i < s->window_size; i++)
+    for (int i = 0; i < s->window_size; i++)
         s->window_func_lut[i] = sin(M_PI * i / s->window_size) *
                                 (1. - (s->overlap / 100.)) * M_PI_2;
 
@@ -167,7 +166,7 @@ static int config_input(AVFilterLink *inlink)
     if (!s->chan)
         return AVERROR(ENOMEM);
 
-    for (i = 0; i < inlink->ch_layout.nb_channels; i++) {
+    for (int i = 0; i < inlink->ch_layout.nb_channels; i++) {
         DeclickChannel *c = &s->chan[i];
 
         c->detection = av_calloc(s->window_size, sizeof(*c->detection));
@@ -189,13 +188,13 @@ static int config_input(AVFilterLink *inlink)
 static void autocorrelation(const double *input, int order, int size,
                             double *output, double scale)
 {
-    int i, j;
-
-    for (i = 0; i <= order; i++) {
+    for (int i = 0; i <= order; i++) {
+        const double *ninput = input + i;
+        const int isize = size - i;
         double value = 0.;
 
-        for (j = i; j < size; j++)
-            value += input[j] * input[j - i];
+        for (int j = 0; j < isize; j++)
+            value += ninput[j] * input[j];
 
         output[i] = value * scale;
     }
@@ -205,7 +204,6 @@ static double autoregression(const double *samples, int ar_order,
                              int nb_samples, double *k, double *r, double *a)
 {
     double alpha;
-    int i, j;
 
     memset(a, 0, ar_order * sizeof(*a));
 
@@ -214,23 +212,23 @@ static double autoregression(const double *samples, int ar_order,
     /* Levinson-Durbin algorithm */
     k[0] = a[0] = -r[1] / r[0];
     alpha = r[0] * (1. - k[0] * k[0]);
-    for (i = 1; i < ar_order; i++) {
+    for (int i = 1; i < ar_order; i++) {
         double epsilon = 0.;
 
-        for (j = 0; j < i; j++)
+        for (int j = 0; j < i; j++)
             epsilon += a[j] * r[i - j];
         epsilon += r[i + 1];
 
         k[i] = -epsilon / alpha;
         alpha *= (1. - k[i] * k[i]);
-        for (j = i - 1; j >= 0; j--)
+        for (int j = i - 1; j >= 0; j--)
             k[j] = a[j] + k[i] * a[i - j - 1];
-        for (j = 0; j <= i; j++)
+        for (int j = 0; j <= i; j++)
             a[j] = k[j];
     }
 
     k[0] = 1.;
-    for (i = 1; i <= ar_order; i++)
+    for (int i = 1; i <= ar_order; i++)
         k[i] = a[i - 1];
 
     return sqrt(alpha);
@@ -238,9 +236,7 @@ static double autoregression(const double *samples, int ar_order,
 
 static int isfinite_array(double *samples, int nb_samples)
 {
-    int i;
-
-    for (i = 0; i < nb_samples; i++)
+    for (int i = 0; i < nb_samples; i++)
         if (!isfinite(samples[i]))
             return 0;
 
@@ -272,14 +268,12 @@ static int find_index(int *index, int value, int size)
 
 static int factorization(double *matrix, int n)
 {
-    int i, j, k;
-
-    for (i = 0; i < n; i++) {
+    for (int i = 0; i < n; i++) {
         const int in = i * n;
         double value;
 
         value = matrix[in + i];
-        for (j = 0; j < i; j++)
+        for (int j = 0; j < i; j++)
             value -= matrix[j * n + j] * matrix[in + j] * matrix[in + j];
 
         if (value == 0.) {
@@ -287,12 +281,12 @@ static int factorization(double *matrix, int n)
         }
 
         matrix[in + i] = value;
-        for (j = i + 1; j < n; j++) {
+        for (int j = i + 1; j < n; j++) {
             const int jn = j * n;
             double x;
 
             x = matrix[jn + i];
-            for (k = 0; k < i; k++)
+            for (int k = 0; k < i; k++)
                 x -= matrix[k * n + k] * matrix[in + k] * matrix[jn + k];
             matrix[jn + i] = x / matrix[in + i];
         }
@@ -304,8 +298,8 @@ static int factorization(double *matrix, int n)
 static int do_interpolation(DeclickChannel *c, double *matrix,
                             double *vector, int n, double *out)
 {
-    int i, j, ret;
     double *y;
+    int ret;
 
     ret = factorization(matrix, n);
     if (ret < 0)
@@ -316,19 +310,19 @@ static int do_interpolation(DeclickChannel *c, double *matrix,
     if (!y)
         return AVERROR(ENOMEM);
 
-    for (i = 0; i < n; i++) {
+    for (int i = 0; i < n; i++) {
         const int in = i * n;
         double value;
 
         value = vector[i];
-        for (j = 0; j < i; j++)
+        for (int j = 0; j < i; j++)
             value -= matrix[in + j] * y[j];
         y[i] = value;
     }
 
-    for (i = n - 1; i >= 0; i--) {
+    for (int i = n - 1; i >= 0; i--) {
         out[i] = y[i] / matrix[i * n + i];
-        for (j = i + 1; j < n; j++)
+        for (int j = i + 1; j < n; j++)
             out[i] -= matrix[j * n + i] * out[j];
     }
 
@@ -340,7 +334,6 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
                          double *auxiliary, double *interpolated)
 {
     double *vector, *matrix;
-    int i, j;
 
     av_fast_malloc(&c->matrix, &c->matrix_size, nb_errors * nb_errors * sizeof(*c->matrix));
     matrix = c->matrix;
@@ -354,10 +347,10 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
 
     autocorrelation(acoefficients, ar_order, ar_order + 1, auxiliary, 1.);
 
-    for (i = 0; i < nb_errors; i++) {
+    for (int i = 0; i < nb_errors; i++) {
         const int im = i * nb_errors;
 
-        for (j = i; j < nb_errors; j++) {
+        for (int j = i; j < nb_errors; j++) {
             if (abs(index[j] - index[i]) <= ar_order) {
                 matrix[j * nb_errors + i] = matrix[im + j] = auxiliary[abs(index[j] - index[i])];
             } else {
@@ -366,10 +359,10 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
         }
     }
 
-    for (i = 0; i < nb_errors; i++) {
+    for (int i = 0; i < nb_errors; i++) {
         double value = 0.;
 
-        for (j = -ar_order; j <= ar_order; j++)
+        for (int j = -ar_order; j <= ar_order; j++)
             if (find_index(index, index[i] - j, nb_errors))
                 value -= src[index[i] - j] * auxiliary[abs(j)];
 
@@ -386,9 +379,11 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
                         const double *src, double *dst)
 {
     const double threshold = s->threshold;
+    const int window_size = s->window_size;
+    const int ar_order = s->ar_order;
     double max_amplitude = 0;
     unsigned *histogram;
-    int i, nb_clips = 0;
+    int nb_clips = 0;
 
     av_fast_malloc(&c->histogram, &c->histogram_size, s->nb_hbins * sizeof(*c->histogram));
     if (!c->histogram)
@@ -396,7 +391,7 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
     histogram = c->histogram;
     memset(histogram, 0, sizeof(*histogram) * s->nb_hbins);
 
-    for (i = 0; i < s->window_size; i++) {
+    for (int i = 0; i < window_size; i++) {
         const unsigned index = fmin(fabs(src[i]), 1) * (s->nb_hbins - 1);
 
         histogram[index]++;
@@ -404,7 +399,7 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
         clip[i] = 0;
     }
 
-    for (i = s->nb_hbins - 1; i > 1; i--) {
+    for (int i = s->nb_hbins - 1; i > 1; i--) {
         if (histogram[i]) {
             if (histogram[i] / (double)FFMAX(histogram[i - 1], 1) > threshold) {
                 max_amplitude = i / (double)s->nb_hbins;
@@ -414,15 +409,15 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
     }
 
     if (max_amplitude > 0.) {
-        for (i = 0; i < s->window_size; i++) {
+        for (int i = 0; i < window_size; i++) {
             clip[i] = fabs(src[i]) >= max_amplitude;
         }
     }
 
-    memset(clip, 0, s->ar_order * sizeof(*clip));
-    memset(clip + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*clip));
+    memset(clip, 0, ar_order * sizeof(*clip));
+    memset(clip + (window_size - ar_order), 0, ar_order * sizeof(*clip));
 
-    for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+    for (int i = ar_order; i < window_size - ar_order; i++)
         if (clip[i])
             index[nb_clips++] = i;
 
@@ -436,35 +431,37 @@ static int detect_clicks(AudioDeclickContext *s, DeclickChannel *c,
                          const double *src, double *dst)
 {
     const double threshold = s->threshold;
-    int i, j, nb_clicks = 0, prev = -1;
+    const int window_size = s->window_size;
+    int nb_clicks = 0, prev = -1;
+    const int ar_order = s->ar_order;
 
-    memset(detection, 0, s->window_size * sizeof(*detection));
+    memset(detection, 0, window_size * sizeof(*detection));
 
-    for (i = s->ar_order; i < s->window_size; i++) {
-        for (j = 0; j <= s->ar_order; j++) {
+    for (int i = ar_order; i < window_size; i++) {
+        for (int j = 0; j <= ar_order; j++) {
             detection[i] += acoefficients[j] * src[i - j];
         }
     }
 
-    for (i = 0; i < s->window_size; i++) {
+    for (int i = 0; i < window_size; i++) {
         click[i] = fabs(detection[i]) > sigmae * threshold;
         dst[i] = src[i];
     }
 
-    for (i = 0; i < s->window_size; i++) {
+    for (int i = 0; i < window_size; i++) {
         if (!click[i])
             continue;
 
         if (prev >= 0 && (i > prev + 1) && (i <= s->nb_burst_samples + prev))
-            for (j = prev + 1; j < i; j++)
+            for (int j = prev + 1; j < i; j++)
                 click[j] = 1;
         prev = i;
     }
 
-    memset(click, 0, s->ar_order * sizeof(*click));
-    memset(click + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*click));
+    memset(click, 0, ar_order * sizeof(*click));
+    memset(click + (window_size - ar_order), 0, ar_order * sizeof(*click));
 
-    for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+    for (int i = ar_order; i < window_size - ar_order; i++)
         if (click[i])
             index[nb_clicks++] = i;
 
@@ -478,33 +475,35 @@ static int detect_surges(AudioDeclickContext *s, DeclickChannel *c,
                          const double *src, double *dst)
 {
     const double threshold = s->threshold;
+    const int window_size = s->window_size;
     const int size = s->nb_surge_samples * 2;
-    int i, j, nb_surges = 0;
+    const int ar_order = s->ar_order;
+    int nb_surges = 0;
 
-    memset(detection, 0, s->window_size * sizeof(*detection));
+    memset(detection, 0, window_size * sizeof(*detection));
 
-    for (i = s->ar_order; i < s->window_size; i++) {
-        for (j = 0; j <= s->ar_order; j++) {
+    for (int i = ar_order; i < window_size; i++) {
+        for (int j = 0; j <= ar_order; j++) {
             detection[i] += acoefficients[j] * src[i - j];
         }
     }
 
-    for (i = 0; i < s->window_size; i++) {
+    for (int i = 0; i < window_size; i++) {
         surge[i] = fabs(detection[i]) > sigmae * threshold;
         dst[i] = src[i];
     }
 
-    for (i = 0; i < s->window_size;) {
+    for (int i = 0; i < window_size;) {
         if (!surge[i++])
             continue;
-        memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, s->window_size - i));
+        memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, window_size - i));
         i += size/2;
     }
 
-    memset(surge, 0, s->ar_order * sizeof(*surge));
-    memset(surge + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*surge));
+    memset(surge, 0, ar_order * sizeof(*surge));
+    memset(surge + (window_size - ar_order), 0, ar_order * sizeof(*surge));
 
-    for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+    for (int i = ar_order; i < window_size - ar_order; i++)
         if (surge[i])
             index[nb_surges++] = i;
 
@@ -528,7 +527,7 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
     const double *w = s->window_func_lut;
     DeclickChannel *c = &s->chan[ch];
     double sigmae;
-    int j, ret;
+    int ret;
 
     sigmae = autoregression(src, s->ar_order, s->window_size, c->acoefficients, c->acorrelation, c->tmp);
 
@@ -549,7 +548,7 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
 
             av_audio_fifo_peek(s->efifo, (void**)s->enabled->extended_data, s->window_size);
 
-            for (j = 0; j < nb_errors; j++) {
+            for (int j = 0; j < nb_errors; j++) {
                 if (enabled[index[j]]) {
                     dst[index[j]] = interpolated[j];
                     is[index[j]] = 1;
@@ -561,15 +560,15 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
     }
 
     if (s->method == 0) {
-        for (j = 0; j < s->window_size; j++)
+        for (int j = 0; j < s->window_size; j++)
             buf[j] += dst[j] * w[j];
     } else {
         const int skip = s->overlap_skip;
 
-        for (j = 0; j < s->hop_size; j++)
+        for (int j = 0; j < s->hop_size; j++)
             buf[j] = dst[skip + j];
     }
-    for (j = 0; j < s->hop_size; j++)
+    for (int j = 0; j < s->hop_size; j++)
         ptr[j] = buf[j];
 
     memmove(buf, buf + s->hop_size, (s->window_size * 2 - s->hop_size) * sizeof(*buf));
@@ -586,7 +585,7 @@ static int filter_frame(AVFilterLink *inlink)
     AVFilterLink *outlink = ctx->outputs[0];
     AudioDeclickContext *s = ctx->priv;
     AVFrame *out = NULL;
-    int ret = 0, j, ch, detected_errors = 0;
+    int ret = 0, ch, detected_errors = 0;
     ThreadData td;
 
     out = ff_get_audio_buffer(outlink, s->hop_size);
@@ -606,7 +605,7 @@ static int filter_frame(AVFilterLink *inlink)
     for (ch = 0; ch < s->in->ch_layout.nb_channels; ch++) {
         double *is = (double *)s->is->extended_data[ch];
 
-        for (j = 0; j < s->hop_size; j++) {
+        for (int j = 0; j < s->hop_size; j++) {
             if (is[j])
                 detected_errors++;
         }
@@ -721,7 +720,6 @@ static av_cold int init(AVFilterContext *ctx)
 static av_cold void uninit(AVFilterContext *ctx)
 {
     AudioDeclickContext *s = ctx->priv;
-    int i;
 
     av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
            filter_modes[s->mode], s->detected_errors,
@@ -737,7 +735,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_frame_free(&s->is);
 
     if (s->chan) {
-        for (i = 0; i < s->nb_channels; i++) {
+        for (int i = 0; i < s->nb_channels; i++) {
             DeclickChannel *c = &s->chan[i];
 
             av_freep(&c->detection);
-- 
2.39.1


[-- Attachment #4: 0001-avfilter-add-adesurge-filter.patch --]
[-- Type: text/x-patch, Size: 9480 bytes --]

From af565f57f733af327edc1e1724e31a3c5f1fe44f Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 18:21:25 +0200
Subject: [PATCH 1/3] avfilter: add adesurge filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 doc/filters.texi          | 51 ++++++++++++++++++++++
 libavfilter/Makefile      |  1 +
 libavfilter/af_adeclick.c | 91 +++++++++++++++++++++++++++++++++++++--
 libavfilter/allfilters.c  |  1 +
 4 files changed, 140 insertions(+), 4 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index b30ff8240b..e041adc40f 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -913,6 +913,57 @@ Compute derivative/integral of audio stream.
 
 Applying both filters one after another produces original audio.
 
+@section adesurge
+Remove big surge in audio samples from input audio.
+
+Samples detected as instant increase or decrease of volume are replaced by
+interpolated samples using autoregressive modelling.
+
+@table @option
+@item window, w
+Set window size, in milliseconds. Allowed range is from @code{10} to
+@code{100}. Default value is @code{85} milliseconds.
+This sets size of window which will be processed at once.
+
+@item overlap, o
+Set window overlap, in percentage of window size. Allowed range is from
+@code{50} to @code{95}. Default value is @code{75} percent.
+Setting this to a very high value may increases surges removal but makes
+whole process much slower.
+
+@item arorder, a
+Set autoregression order, in percentage of window size. Allowed range is from
+@code{0} to @code{25}. Default value is @code{0.5} percent. This option also
+controls quality of interpolated samples using neighbour good samples.
+
+@item threshold, t
+Set threshold value. Allowed range is from @code{1} to @code{100}.
+Default value is @code{20}.
+This controls the strength of surges which is going to be removed.
+The lower value, the more samples will be detected as surges.
+
+@item surges, s
+Set surges size, in number of samples. Allowed range is @code{1} to
+@code{50}. Default value is @code{5}.
+For any sample detected as surge then also its surrounding samples of this size
+will be interpolated also.
+
+@item method, m
+Set overlap method.
+
+It accepts the following values:
+@table @option
+@item add, a
+Select overlap-add method. Even not interpolated samples are slightly
+changed with this method.
+
+@item save, s
+Select overlap-save method. Not interpolated samples remain unchanged.
+@end table
+
+Default value is @code{s}.
+@end table
+
 @section adrc
 
 Apply spectral dynamic range controller filter to input audio stream.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 30a0e22ef8..b26a85a7d2 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -49,6 +49,7 @@ OBJS-$(CONFIG_ADECORRELATE_FILTER)           += af_adecorrelate.o
 OBJS-$(CONFIG_ADELAY_FILTER)                 += af_adelay.o
 OBJS-$(CONFIG_ADENORM_FILTER)                += af_adenorm.o
 OBJS-$(CONFIG_ADERIVATIVE_FILTER)            += af_aderivative.o
+OBJS-$(CONFIG_ADESURGE_FILTER)               += af_adesurge.o
 OBJS-$(CONFIG_ADRC_FILTER)                   += af_adrc.o
 OBJS-$(CONFIG_ADYNAMICEQUALIZER_FILTER)      += af_adynamicequalizer.o
 OBJS-$(CONFIG_ADYNAMICSMOOTH_FILTER)         += af_adynamicsmooth.o
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index 822f3065b8..1137dbe25b 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -25,6 +25,8 @@
 #include "filters.h"
 #include "internal.h"
 
+static const char *filter_modes[] = {"clicks", "clips", "surges" };
+
 typedef struct DeclickChannel {
     double *auxiliary;
     double *detection;
@@ -55,8 +57,9 @@ typedef struct AudioDeclickContext {
     int method;
     int nb_hbins;
 
-    int is_declip;
+    int mode;
     int ar_order;
+    int nb_surge_samples;
     int nb_burst_samples;
     int window_size;
     int hop_size;
@@ -468,6 +471,46 @@ static int detect_clicks(AudioDeclickContext *s, DeclickChannel *c,
     return nb_clicks;
 }
 
+static int detect_surges(AudioDeclickContext *s, DeclickChannel *c,
+                         double sigmae,
+                         double *detection, double *acoefficients,
+                         uint8_t *surge, int *index,
+                         const double *src, double *dst)
+{
+    const double threshold = s->threshold;
+    const int size = s->nb_surge_samples * 2;
+    int i, j, nb_surges = 0;
+
+    memset(detection, 0, s->window_size * sizeof(*detection));
+
+    for (i = s->ar_order; i < s->window_size; i++) {
+        for (j = 0; j <= s->ar_order; j++) {
+            detection[i] += acoefficients[j] * src[i - j];
+        }
+    }
+
+    for (i = 0; i < s->window_size; i++) {
+        surge[i] = fabs(detection[i]) > sigmae * threshold;
+        dst[i] = src[i];
+    }
+
+    for (i = 0; i < s->window_size;) {
+        if (!surge[i++])
+            continue;
+        memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, s->window_size - i));
+        i += size/2;
+    }
+
+    memset(surge, 0, s->ar_order * sizeof(*surge));
+    memset(surge + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*surge));
+
+    for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+        if (surge[i])
+            index[nb_surges++] = i;
+
+    return nb_surges;
+}
+
 typedef struct ThreadData {
     AVFrame *out;
 } ThreadData;
@@ -661,10 +704,14 @@ static av_cold int init(AVFilterContext *ctx)
 {
     AudioDeclickContext *s = ctx->priv;
 
-    s->is_declip = !strcmp(ctx->filter->name, "adeclip");
-    if (s->is_declip) {
+    if (!strcmp(ctx->filter->name, "adesurge")) {
+        s->mode = 2;
+        s->detector = detect_surges;
+    } else if (!strcmp(ctx->filter->name, "adeclip")) {
+        s->mode = 1;
         s->detector = detect_clips;
     } else {
+        s->mode = 0;
         s->detector = detect_clicks;
     }
 
@@ -677,7 +724,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     int i;
 
     av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
-           s->is_declip ? "clips" : "clicks", s->detected_errors,
+           filter_modes[s->mode], s->detected_errors,
            s->nb_samples, 100. * s->detected_errors / s->nb_samples);
 
     av_audio_fifo_free(s->fifo);
@@ -772,3 +819,39 @@ const AVFilter ff_af_adeclip = {
     FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
+
+static const AVOption adesurge_options[] = {
+    { "window", "set window size",     OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=85},     10,  100, AF },
+    { "w", "set window size",          OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=85},     10,  100, AF },
+    { "overlap", "set window overlap", OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75},     50,   95, AF },
+    { "o", "set window overlap",       OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75},     50,   95, AF },
+    { "arorder", "set autoregression order", OFFSET(ar),  AV_OPT_TYPE_DOUBLE, {.dbl=0.5},     0,   25, AF },
+    { "a", "set autoregression order", OFFSET(ar),        AV_OPT_TYPE_DOUBLE, {.dbl=0.5},     0,   25, AF },
+    { "threshold", "set threshold",    OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=20},      1,  100, AF },
+    { "t", "set threshold",            OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=20},      1,  100, AF },
+    { "surges", "set surge size",      OFFSET(nb_surge_samples), AV_OPT_TYPE_INT, {.i64=5},   1,   50, AF },
+    { "s", "set surge size",           OFFSET(nb_surge_samples), AV_OPT_TYPE_INT, {.i64=5},   1,   50, AF },
+    { "method", "set overlap method",  OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=1},       0,    1, AF, "m" },
+    { "m", "set overlap method",       OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=1},       0,    1, AF, "m" },
+    { "add", "overlap-add",            0,                 AV_OPT_TYPE_CONST,  {.i64=0},       0,    0, AF, "m" },
+    { "a", "overlap-add",              0,                 AV_OPT_TYPE_CONST,  {.i64=0},       0,    0, AF, "m" },
+    { "save", "overlap-save",          0,                 AV_OPT_TYPE_CONST,  {.i64=1},       0,    0, AF, "m" },
+    { "s", "overlap-save",             0,                 AV_OPT_TYPE_CONST,  {.i64=1},       0,    0, AF, "m" },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(adesurge);
+
+const AVFilter ff_af_adesurge = {
+    .name          = "adesurge",
+    .description   = NULL_IF_CONFIG_SMALL("Remove surges from input audio."),
+    .priv_size     = sizeof(AudioDeclickContext),
+    .priv_class    = &adesurge_class,
+    .init          = init,
+    .activate      = activate,
+    .uninit        = uninit,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(ff_audio_default_filterpad),
+    FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
+    .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 089ad3a0ed..286e601799 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -35,6 +35,7 @@ extern const AVFilter ff_af_adecorrelate;
 extern const AVFilter ff_af_adelay;
 extern const AVFilter ff_af_adenorm;
 extern const AVFilter ff_af_aderivative;
+extern const AVFilter ff_af_adesurge;
 extern const AVFilter ff_af_adrc;
 extern const AVFilter ff_af_adynamicequalizer;
 extern const AVFilter ff_af_adynamicsmooth;
-- 
2.39.1


[-- Attachment #5: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-08-12 10:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-09 21:36 [FFmpeg-devel] [PATCH] new audio filter and misc improvements Paul B Mahol
2023-08-10  9:47 ` Michael Niedermayer
2023-08-10 10:10   ` Paul B Mahol
2023-08-10 15:13     ` Michael Niedermayer
2023-08-10 16:49       ` Paul B Mahol
2023-08-12 10:09         ` Michael Niedermayer

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git