diff mbox series

[FFmpeg-devel] avfilter: add afwtdn filter

Message ID 20200531202935.8767-1-onemda@gmail.com
State Superseded
Headers show
Series [FFmpeg-devel] avfilter: add afwtdn filter | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Paul B Mahol May 31, 2020, 8:29 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavfilter/Makefile     |   1 +
 libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
 libavfilter/allfilters.c |   1 +
 3 files changed, 621 insertions(+)
 create mode 100644 libavfilter/af_afwtdn.c

Comments

Nicolas George May 31, 2020, 8:35 p.m. UTC | #1
Paul B Mahol (12020-05-31):
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  libavfilter/Makefile     |   1 +
>  libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
>  libavfilter/allfilters.c |   1 +
>  3 files changed, 621 insertions(+)
>  create mode 100644 libavfilter/af_afwtdn.c

No doc, name completely impossible to understand. Unacceptable.
Paul B Mahol May 31, 2020, 8:37 p.m. UTC | #2
On 5/31/20, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (12020-05-31):
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  libavfilter/Makefile     |   1 +
>>  libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
>>  libavfilter/allfilters.c |   1 +
>>  3 files changed, 621 insertions(+)
>>  create mode 100644 libavfilter/af_afwtdn.c
>
> No doc, name completely impossible to understand. Unacceptable.
>

Go away!
Lou Logan May 31, 2020, 9:07 p.m. UTC | #3
On Sun, May 31, 2020, at 12:35 PM, Nicolas George wrote:
>
> No doc

Yes, docs are needed, and an example would be nice. One complaint I
hear often is that many filters have no examples.

> name completely impossible to understand. Unacceptable.

Got any suggestions? We have 3 existing "audio-3 letter algorithm name-
denoise" filters so there is sort of a naming convention already.
Reino Wijnsma May 31, 2020, 9:26 p.m. UTC | #4
On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
> On 5/31/20, Nicolas George <george@nsup.org> wrote:
>> Paul B Mahol (12020-05-31):
>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>> ---
>>>  libavfilter/Makefile     |   1 +
>>>  libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
>>>  libavfilter/allfilters.c |   1 +
>>>  3 files changed, 621 insertions(+)
>>>  create mode 100644 libavfilter/af_afwtdn.c
>> No doc, name completely impossible to understand. Unacceptable.
> Go away!

Can you please act as a grown-up for once?!
Nicolas is right. How would anyone be able to understand what your patch does. No name, no discription, no documentation. Nothing!
I would immediately reject this patch if this would be my project.

Whatever issue you have with Nicolas, I suggest you two have a serious conversation about this, preferably face-to-face if possible, and talk this out! I've been around here long enough to see that it's polluting this mailinglist.

-- Reino
Paul B Mahol June 1, 2020, 7:32 a.m. UTC | #5
On 5/31/20, Reino Wijnsma <rwijnsma@xs4all.nl> wrote:
> On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
>> On 5/31/20, Nicolas George <george@nsup.org> wrote:
>>> Paul B Mahol (12020-05-31):
>>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>>> ---
>>>>  libavfilter/Makefile     |   1 +
>>>>  libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
>>>>  libavfilter/allfilters.c |   1 +
>>>>  3 files changed, 621 insertions(+)
>>>>  create mode 100644 libavfilter/af_afwtdn.c
>>> No doc, name completely impossible to understand. Unacceptable.
>> Go away!
>
> Can you please act as a grown-up for once?!
> Nicolas is right. How would anyone be able to understand what your patch
> does. No name, no discription, no documentation. Nothing!
> I would immediately reject this patch if this would be my project.
>
> Whatever issue you have with Nicolas, I suggest you two have a serious
> conversation about this, preferably face-to-face if possible, and talk this
> out! I've been around here long enough to see that it's polluting this
> mailinglist.
>

Look, you are not here to talk like that.
Anton Khirnov June 1, 2020, 8:09 a.m. UTC | #6
Quoting Paul B Mahol (2020-06-01 09:32:06)
> On 5/31/20, Reino Wijnsma <rwijnsma@xs4all.nl> wrote:
> > On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
> >> On 5/31/20, Nicolas George <george@nsup.org> wrote:
> >>> Paul B Mahol (12020-05-31):
> >>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >>>> ---
> >>>>  libavfilter/Makefile     |   1 +
> >>>>  libavfilter/af_afwtdn.c  | 619 +++++++++++++++++++++++++++++++++++++++
> >>>>  libavfilter/allfilters.c |   1 +
> >>>>  3 files changed, 621 insertions(+)
> >>>>  create mode 100644 libavfilter/af_afwtdn.c
> >>> No doc, name completely impossible to understand. Unacceptable.
> >> Go away!
> >
> > Can you please act as a grown-up for once?!
> > Nicolas is right. How would anyone be able to understand what your patch
> > does. No name, no discription, no documentation. Nothing!
> > I would immediately reject this patch if this would be my project.
> >
> > Whatever issue you have with Nicolas, I suggest you two have a serious
> > conversation about this, preferably face-to-face if possible, and talk this
> > out! I've been around here long enough to see that it's polluting this
> > mailinglist.
> >
> 
> Look, you are not here to talk like that.

Neither are you.

At least this should remind people why we need an enforceable code of
conduct.
Paul B Mahol June 1, 2020, 8:33 a.m. UTC | #7
On 6/1/20, Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Paul B Mahol (2020-06-01 09:32:06)
>> On 5/31/20, Reino Wijnsma <rwijnsma@xs4all.nl> wrote:
>> > On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
>> >> On 5/31/20, Nicolas George <george@nsup.org> wrote:
>> >>> Paul B Mahol (12020-05-31):
>> >>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> >>>> ---
>> >>>>  libavfilter/Makefile     |   1 +
>> >>>>  libavfilter/af_afwtdn.c  | 619
>> >>>> +++++++++++++++++++++++++++++++++++++++
>> >>>>  libavfilter/allfilters.c |   1 +
>> >>>>  3 files changed, 621 insertions(+)
>> >>>>  create mode 100644 libavfilter/af_afwtdn.c
>> >>> No doc, name completely impossible to understand. Unacceptable.
>> >> Go away!
>> >
>> > Can you please act as a grown-up for once?!
>> > Nicolas is right. How would anyone be able to understand what your patch
>> > does. No name, no discription, no documentation. Nothing!
>> > I would immediately reject this patch if this would be my project.
>> >
>> > Whatever issue you have with Nicolas, I suggest you two have a serious
>> > conversation about this, preferably face-to-face if possible, and talk
>> > this
>> > out! I've been around here long enough to see that it's polluting this
>> > mailinglist.
>> >
>>
>> Look, you are not here to talk like that.
>
> Neither are you.
>
> At least this should remind people why we need an enforceable code of
> conduct.
>

What I did wrong? What you want to enforce upon me?
Anton Khirnov June 1, 2020, 8:45 a.m. UTC | #8
Quoting Paul B Mahol (2020-06-01 10:33:24)
> On 6/1/20, Anton Khirnov <anton@khirnov.net> wrote:
> > Quoting Paul B Mahol (2020-06-01 09:32:06)
> >> On 5/31/20, Reino Wijnsma <rwijnsma@xs4all.nl> wrote:
> >> > On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
> >> >> On 5/31/20, Nicolas George <george@nsup.org> wrote:
> >> >>> Paul B Mahol (12020-05-31):
> >> >>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >> >>>> ---
> >> >>>>  libavfilter/Makefile     |   1 +
> >> >>>>  libavfilter/af_afwtdn.c  | 619
> >> >>>> +++++++++++++++++++++++++++++++++++++++
> >> >>>>  libavfilter/allfilters.c |   1 +
> >> >>>>  3 files changed, 621 insertions(+)
> >> >>>>  create mode 100644 libavfilter/af_afwtdn.c
> >> >>> No doc, name completely impossible to understand. Unacceptable.
> >> >> Go away!
> >> >
> >> > Can you please act as a grown-up for once?!
> >> > Nicolas is right. How would anyone be able to understand what your patch
> >> > does. No name, no discription, no documentation. Nothing!
> >> > I would immediately reject this patch if this would be my project.
> >> >
> >> > Whatever issue you have with Nicolas, I suggest you two have a serious
> >> > conversation about this, preferably face-to-face if possible, and talk
> >> > this
> >> > out! I've been around here long enough to see that it's polluting this
> >> > mailinglist.
> >> >
> >>
> >> Look, you are not here to talk like that.
> >
> > Neither are you.
> >
> > At least this should remind people why we need an enforceable code of
> > conduct.
> >
> 
> What I did wrong? What you want to enforce upon me?

You are insulting, attacking and belittling other contributors. I have
no idea how you can think such behaviour is anywhere near acceptable.
Paul B Mahol June 1, 2020, 9:06 a.m. UTC | #9
On 6/1/20, Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Paul B Mahol (2020-06-01 10:33:24)
>> On 6/1/20, Anton Khirnov <anton@khirnov.net> wrote:
>> > Quoting Paul B Mahol (2020-06-01 09:32:06)
>> >> On 5/31/20, Reino Wijnsma <rwijnsma@xs4all.nl> wrote:
>> >> > On 2020-05-31T22:37:20+0200, Paul B Mahol <onemda@gmail.com> wrote:
>> >> >> On 5/31/20, Nicolas George <george@nsup.org> wrote:
>> >> >>> Paul B Mahol (12020-05-31):
>> >> >>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> >> >>>> ---
>> >> >>>>  libavfilter/Makefile     |   1 +
>> >> >>>>  libavfilter/af_afwtdn.c  | 619
>> >> >>>> +++++++++++++++++++++++++++++++++++++++
>> >> >>>>  libavfilter/allfilters.c |   1 +
>> >> >>>>  3 files changed, 621 insertions(+)
>> >> >>>>  create mode 100644 libavfilter/af_afwtdn.c
>> >> >>> No doc, name completely impossible to understand. Unacceptable.
>> >> >> Go away!
>> >> >
>> >> > Can you please act as a grown-up for once?!
>> >> > Nicolas is right. How would anyone be able to understand what your
>> >> > patch
>> >> > does. No name, no discription, no documentation. Nothing!
>> >> > I would immediately reject this patch if this would be my project.
>> >> >
>> >> > Whatever issue you have with Nicolas, I suggest you two have a
>> >> > serious
>> >> > conversation about this, preferably face-to-face if possible, and
>> >> > talk
>> >> > this
>> >> > out! I've been around here long enough to see that it's polluting
>> >> > this
>> >> > mailinglist.
>> >> >
>> >>
>> >> Look, you are not here to talk like that.
>> >
>> > Neither are you.
>> >
>> > At least this should remind people why we need an enforceable code of
>> > conduct.
>> >
>>
>> What I did wrong? What you want to enforce upon me?
>
> You are insulting, attacking and belittling other contributors. I have
> no idea how you can think such behaviour is anywhere near acceptable.
>

Where I insulted, attacked, belittled other contributorS, not counting Nicolas.
Nicolas George June 2, 2020, 1:43 p.m. UTC | #10
Lou Logan (12020-05-31):
> Got any suggestions? We have 3 existing "audio-3 letter algorithm name-
> denoise" filters so there is sort of a naming convention already.

I do not consider something that was pushed by a single developer,
mostly without review, to be a binding convention.

And we probably should not have several filters in the first place, we
should have different modes of operation for the same filter.

In any case, the name should reflect what is done, not how it is done:
the not the algorithm. The doc should explain it too. It should explain
in what cases this filter is better than the others and in what cases it
is not.

We have been lax in the past, but that does not mean we should be lax
now or in the future. This filter should not be pushed unless these
concerns about user interface are addressed.

Regards,
diff mbox series

Patch

diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 5123540653..191826a622 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -50,6 +50,7 @@  OBJS-$(CONFIG_AFFTDN_FILTER)                 += af_afftdn.o
 OBJS-$(CONFIG_AFFTFILT_FILTER)               += af_afftfilt.o
 OBJS-$(CONFIG_AFIR_FILTER)                   += af_afir.o
 OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
+OBJS-$(CONFIG_AFWTDN_FILTER)                 += af_afwtdn.o
 OBJS-$(CONFIG_AGATE_FILTER)                  += af_agate.o
 OBJS-$(CONFIG_AIIR_FILTER)                   += af_aiir.o
 OBJS-$(CONFIG_AINTEGRAL_FILTER)              += af_aderivative.o
diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c
new file mode 100644
index 0000000000..00b93c29af
--- /dev/null
+++ b/libavfilter/af_afwtdn.c
@@ -0,0 +1,619 @@ 
+/*
+ * Copyright (c) 2020 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <float.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/audio_fifo.h"
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "filters.h"
+#include "formats.h"
+
+static const double coif5_lp[30] = {
+    -9.517657273819165e-08, -1.6744288576823017e-07,
+    2.0637618513646814e-06, 3.7346551751414047e-06,
+    -2.1315026809955787e-05, -4.134043227251251e-05,
+    0.00014054114970203437, 0.00030225958181306315,
+    -0.0006381313430451114, -0.0016628637020130838,
+    0.0024333732126576722, 0.006764185448053083,
+    -0.009164231162481846, -0.01976177894257264,
+    0.03268357426711183, 0.0412892087501817,
+    -0.10557420870333893, -0.06203596396290357,
+    0.4379916261718371, 0.7742896036529562,
+    0.4215662066908515, -0.05204316317624377,
+    -0.09192001055969624, 0.02816802897093635,
+    0.023408156785839195, -0.010131117519849788,
+    -0.004159358781386048, 0.0021782363581090178,
+    0.00035858968789573785, -0.00021208083980379827,
+};
+
+static const double coif5_hp[30] = {
+    0.00021208083980379827, 0.00035858968789573785,
+    -0.0021782363581090178, -0.004159358781386048,
+    0.010131117519849788, 0.023408156785839195,
+    -0.02816802897093635, -0.09192001055969624,
+    0.05204316317624377, 0.4215662066908515,
+    -0.7742896036529562, 0.4379916261718371,
+    0.06203596396290357, -0.10557420870333893,
+    -0.0412892087501817, 0.03268357426711183,
+    0.01976177894257264, -0.009164231162481846,
+    -0.006764185448053083, 0.0024333732126576722,
+    0.0016628637020130838, -0.0006381313430451114,
+    -0.00030225958181306315, 0.00014054114970203437,
+    4.134043227251251e-05, -2.1315026809955787e-05,
+    -3.7346551751414047e-06, 2.0637618513646814e-06,
+    1.6744288576823017e-07, -9.517657273819165e-08,
+};
+
+static const double coif5_ilp[30] = {
+    -0.00021208083980379827, 0.00035858968789573785,
+    0.0021782363581090178, -0.004159358781386048,
+    -0.010131117519849788, 0.023408156785839195,
+    0.02816802897093635, -0.09192001055969624,
+    -0.05204316317624377, 0.4215662066908515,
+    0.7742896036529562, 0.4379916261718371,
+    -0.06203596396290357, -0.10557420870333893,
+    0.0412892087501817, 0.03268357426711183,
+    -0.01976177894257264, -0.009164231162481846,
+    0.006764185448053083, 0.0024333732126576722,
+    -0.0016628637020130838, -0.0006381313430451114,
+    0.00030225958181306315, 0.00014054114970203437,
+    -4.134043227251251e-05, -2.1315026809955787e-05,
+    3.7346551751414047e-06, 2.0637618513646814e-06,
+    -1.6744288576823017e-07, -9.517657273819165e-08,
+};
+
+static const double coif5_ihp[30] = {
+    -9.517657273819165e-08, 1.6744288576823017e-07,
+    2.0637618513646814e-06, -3.7346551751414047e-06,
+    -2.1315026809955787e-05, 4.134043227251251e-05,
+    0.00014054114970203437, -0.00030225958181306315,
+    -0.0006381313430451114, 0.0016628637020130838,
+    0.0024333732126576722, -0.006764185448053083,
+    -0.009164231162481846, 0.01976177894257264,
+    0.03268357426711183, -0.0412892087501817,
+    -0.10557420870333893, 0.06203596396290357,
+    0.4379916261718371, -0.7742896036529562,
+    0.4215662066908515, 0.05204316317624377,
+    -0.09192001055969624, -0.02816802897093635,
+    0.023408156785839195, 0.010131117519849788,
+    -0.004159358781386048, -0.0021782363581090178,
+    0.00035858968789573785, 0.00021208083980379827,
+};
+
+static const double deb10_lp[20] = {
+    -1.326420300235487e-05, 9.358867000108985e-05,
+    -0.0001164668549943862, -0.0006858566950046825,
+    0.00199240529499085, 0.0013953517469940798,
+    -0.010733175482979604, 0.0036065535669883944,
+    0.03321267405893324, -0.02945753682194567,
+    -0.07139414716586077, 0.09305736460380659,
+    0.12736934033574265, -0.19594627437659665,
+    -0.24984642432648865, 0.2811723436604265,
+    0.6884590394525921, 0.5272011889309198,
+    0.18817680007762133, 0.026670057900950818,
+};
+
+static const double deb10_hp[20] = {
+    -0.026670057900950818, 0.18817680007762133,
+    -0.5272011889309198, 0.6884590394525921,
+    -0.2811723436604265, -0.24984642432648865,
+    0.19594627437659665, 0.12736934033574265,
+    -0.09305736460380659, -0.07139414716586077,
+    0.02945753682194567, 0.03321267405893324,
+    -0.0036065535669883944, -0.010733175482979604,
+    -0.0013953517469940798, 0.00199240529499085,
+    0.0006858566950046825, -0.0001164668549943862,
+    -9.358867000108985e-05, -1.326420300235487e-05,
+};
+
+static const double deb10_ilp[20] = {
+    0.026670057900950818, 0.18817680007762133,
+    0.5272011889309198, 0.6884590394525921,
+    0.2811723436604265, -0.24984642432648865,
+    -0.19594627437659665, 0.12736934033574265,
+    0.09305736460380659, -0.07139414716586077,
+    -0.02945753682194567, 0.03321267405893324,
+    0.0036065535669883944, -0.010733175482979604,
+    0.0013953517469940798, 0.00199240529499085,
+    -0.0006858566950046825, -0.0001164668549943862,
+    9.358867000108985e-05, -1.326420300235487e-05,
+};
+
+static const double deb10_ihp[20] = {
+    -1.326420300235487e-05, -9.358867000108985e-05,
+    -0.0001164668549943862, 0.0006858566950046825,
+    0.00199240529499085, -0.0013953517469940798,
+    -0.010733175482979604, -0.0036065535669883944,
+    0.03321267405893324, 0.02945753682194567,
+    -0.07139414716586077, -0.09305736460380659,
+    0.12736934033574265, 0.19594627437659665,
+    -0.24984642432648865, -0.2811723436604265,
+    0.6884590394525921, -0.5272011889309198,
+    0.18817680007762133, -0.026670057900950818,
+};
+
+static const double deb4_lp[8] = {
+    -0.0105974018, 0.0328830117,
+     0.0308413818, -0.1870348117,
+    -0.0279837694, 0.6308807679,
+     0.7148465706, 0.2303778133,
+};
+
+static const double deb4_hp[8] = {
+    -0.2303778133, 0.7148465706,
+    -0.6308807679, -0.0279837694,
+     0.1870348117, 0.0308413818,
+    -0.0328830117, -0.0105974018,
+};
+
+static const double deb4_ilp[8] = {
+     0.23037781330885523, 0.7148465705525415,
+     0.6308807679295904, -0.02798376941698385,
+    -0.18703481171888114, 0.030841381835986965,
+     0.032883011666982945, -0.010597401784997278,
+};
+
+static const double deb4_ihp[8] = {
+    -0.010597401784997278, -0.032883011666982945,
+     0.030841381835986965, 0.18703481171888114,
+    -0.02798376941698385, -0.6308807679295904,
+     0.7148465705525415, -0.23037781330885523,
+};
+
+typedef struct AudioFWTDNContext {
+    const AVClass *class;
+
+    double sigma;
+    double percent;
+
+    int wavelet_type;
+    int thresholding_function;
+    int nb_samples;
+    int levels;
+    int wavelet_length;
+    int length[11];
+    int outlength;
+
+    const double *lp, *hp;
+    const double *ilp, *ihp;
+
+    AVFrame *temp0, *temp1;
+    AVFrame *wtc;
+
+    void (*thresholding)(AVFilterContext *ctx, double *wtc, int length, double sigma);
+} AudioFWTDNContext;
+
+#define OFFSET(x) offsetof(AudioFWTDNContext, x)
+#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption afwtdn_options[] = {
+    { "sigma", "set noise sigma", OFFSET(sigma), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1000, AF },
+    { "level", "set wavelet level", OFFSET(levels), AV_OPT_TYPE_INT, {.i64=5}, 1,   10, AF },
+    { "thref", "set threshold function", OFFSET(thresholding_function), AV_OPT_TYPE_INT, {.i64=1}, 0, 4, AF, "thret" },
+    { "hard",  "hard", 0, AV_OPT_TYPE_CONST,  {.i64=0}, 0, 0, AF, "thret"},
+    { "soft",  "soft", 0, AV_OPT_TYPE_CONST,  {.i64=1}, 0, 0, AF, "thret"},
+    { "garrote", "garrote", 0, AV_OPT_TYPE_CONST,  {.i64=2}, 0, 0, AF, "thret"},
+    { "new",   "new", 0, AV_OPT_TYPE_CONST,  {.i64=3}, 0, 0, AF, "thret"},
+    { "semisoft", "semisoft", 0, AV_OPT_TYPE_CONST,  {.i64=4}, 0, 0, AF, "thret"},
+    { "wavet", "set wavelet type", OFFSET(wavelet_type), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, AF, "wavet"},
+    { "deb4",  "deb4", 0, AV_OPT_TYPE_CONST,  {.i64=0}, 0, 2, AF, "wavet"},
+    { "deb10", "deb10", 0, AV_OPT_TYPE_CONST,  {.i64=1}, 0, 2, AF, "wavet"},
+    { "coif5", "coif5", 0, AV_OPT_TYPE_CONST,  {.i64=2}, 0, 2, AF, "wavet"},
+    { "percent", "set percent of full denoising", OFFSET(percent),AV_OPT_TYPE_DOUBLE, {.dbl=85}, 0, 100, AF },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(afwtdn);
+
+static int query_formats(AVFilterContext *ctx)
+{
+    AVFilterFormats *formats = NULL;
+    AVFilterChannelLayouts *layouts = NULL;
+    static const enum AVSampleFormat sample_fmts[] = {
+        AV_SAMPLE_FMT_DBLP,
+        AV_SAMPLE_FMT_NONE
+    };
+    int ret;
+
+    formats = ff_make_format_list(sample_fmts);
+    if (!formats)
+        return AVERROR(ENOMEM);
+    ret = ff_set_common_formats(ctx, formats);
+    if (ret < 0)
+        return ret;
+
+    layouts = ff_all_channel_counts();
+    if (!layouts)
+        return AVERROR(ENOMEM);
+
+    ret = ff_set_common_channel_layouts(ctx, layouts);
+    if (ret < 0)
+        return ret;
+
+    formats = ff_all_samplerates();
+    return ff_set_common_samplerates(ctx, formats);
+}
+
+static void hard_thresholding(AVFilterContext *ctx, double *wtc, int length, double threshold)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    const double frac = 1.0 - s->percent * 0.01;
+
+    for (int i = 0; i < length; i++) {
+        if (fabs(wtc[i]) <= threshold)
+            wtc[i] *= frac;
+    }
+}
+
+static void soft_thresholding(AVFilterContext *ctx, double *wtc, int length, double threshold)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    const double frac = 1.0 - s->percent * 0.01;
+    const double shift = threshold * 0.01 * s->percent;
+
+    for (int i = 0; i < length; i++) {
+        const double temp = fabs(wtc[i]);
+        if (temp <= threshold)
+            wtc[i] *= frac;
+        else
+            wtc[i] = (wtc[i] < 0.0 ? -1.0 : (wtc[i] > 0.0 ? 1.0 : 0.0)) * (temp - shift);
+    }
+}
+
+static void semisoft_thresholding(AVFilterContext *ctx, double *wtc, int length, double threshold)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    const double percent01 = s->percent * 0.01;
+    const double frac = 1.0 - percent01;
+    const double sigma2 = threshold * 0.1 * s->percent;
+
+    for (int i = 0; i < length; i++) {
+        const double temp = fabs(wtc[i]);
+        if (temp <= threshold)
+            wtc[i] *= frac;
+        else if (temp <= sigma2)
+            wtc[i] = wtc[i] * sigma2 * (1.0 - threshold / temp) / (sigma2 - threshold);
+    }
+}
+
+static void garrote_thresholding(AVFilterContext *ctx, double *wtc, int length, double threshold)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    const double percent01 = s->percent * 0.01;
+    const double tr2 = threshold * threshold * percent01;
+    const double frac = 1.0 - percent01;
+
+    for (int i = 0; i < length; i++) {
+        const double temp = fabs(wtc[i]);
+        if (temp <= threshold) {
+            wtc[i] *= frac;
+        } else {
+            const double tp2 = temp * temp;
+            wtc[i] *= (tp2 - tr2) / tp2;
+        }
+    }
+}
+
+static void new_thresholding(AVFilterContext *ctx, double *wtc, int length, double threshold)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    const double percent01 = s->percent * 0.01;
+    const double frac = 1.0 - percent01;
+
+    for (int i = 0; i < length; i++) {
+        const double temp = fabs(wtc[i]);
+        if (temp <= threshold)
+            wtc[i] *= frac;
+        else
+            wtc[i] = FFSIGN(wtc[i]) * (temp - threshold / exp((temp - threshold) / threshold));
+    }
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    AudioFWTDNContext *s = ctx->priv;
+    int N, i;
+
+    switch (s->wavelet_type) {
+    case 0:
+        s->wavelet_length = 8;
+        s->lp  = deb4_lp;
+        s->hp  = deb4_hp;
+        s->ilp = deb4_ilp;
+        s->ihp = deb4_ihp;
+        break;
+    case 1:
+        s->wavelet_length = 20;
+        s->lp  = deb10_lp;
+        s->hp  = deb10_hp;
+        s->ilp = deb10_ilp;
+        s->ihp = deb10_ihp;
+        break;
+    case 2:
+        s->wavelet_length = 30;
+        s->lp  = coif5_lp;
+        s->hp  = coif5_hp;
+        s->ilp = coif5_ilp;
+        s->ihp = coif5_ihp;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    s->nb_samples = 8192;
+    s->levels = FFMIN(s->levels, lrint(log(s->nb_samples / (s->wavelet_length - 1.0)) / M_LN2));
+    N = s->nb_samples;
+    i = s->levels;
+
+    while (i > 0) {
+        N = N + s->wavelet_length - 2;
+        N = ceil(N / 2.0);
+        s->length[i] = N;
+        s->outlength += N;
+        i--;
+    }
+
+    s->length[0]  = s->length[1];
+    s->outlength += s->length[0];
+
+    s->temp0 = ff_get_audio_buffer(outlink, 2 * s->nb_samples + 2 * s->wavelet_length);
+    s->temp1 = ff_get_audio_buffer(outlink, 2 * s->nb_samples + 2 * s->wavelet_length);
+    s->wtc   = ff_get_audio_buffer(outlink, 2 * s->nb_samples + 2 * s->wavelet_length);
+    if (!s->temp0 || !s->temp1 || !s->wtc)
+        return AVERROR(ENOMEM);
+
+    switch (s->thresholding_function) {
+    case 0:
+        s->thresholding = hard_thresholding;
+        break;
+    case 1:
+        s->thresholding = soft_thresholding;
+        break;
+    case 2:
+        s->thresholding = garrote_thresholding;
+        break;
+    case 3:
+        s->thresholding = new_thresholding;
+        break;
+    case 4:
+        s->thresholding = semisoft_thresholding;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return 0;
+}
+
+static void dwt(double *src, int N,
+                const double *lf, const double *hf, int flen,
+                double *low, double *high, int lhlen)
+{
+    for (int i = 0; i < lhlen; i++) {
+        const int t = 2 * i + 1;
+
+        low[i] = 0.0;
+        high[i] = 0.0;
+
+        for (int l = 0; l < flen; l++) {
+            if (t - l >= 0 && t - l < N) {
+                const int is = t - l;
+                low[i] += lf[l] * src[is];
+                high[i] += hf[l] * src[is];
+            } else if (t - l < 0) {
+                const int is = -t + l - 1;
+                low[i] += lf[l] * src[is];
+                high[i] += hf[l] * src[is];
+            } else if (t - l >= N) {
+                const int is = 2 * N - t + l - 1;
+                low[i] += lf[l] * src[is];
+                high[i] += hf[l] * src[is];
+            }
+        }
+    }
+}
+
+static void idwt(double *low, int lhlen, double *high,
+                 const double *lf, const double *hf,
+                 int flen, double *dst)
+{
+    int m = -2, n = -1;
+
+    for (int v = 0; v < lhlen; v++) {
+        m += 2;
+        n += 2;
+        dst[m] = 0.0;
+        dst[n] = 0.0;
+        for (int l = 0; l < flen / 2; l++) {
+            const int t = 2 * l;
+
+            if (v - l >= 0 && v - l < lhlen) {
+                const int is = v - l;
+
+                dst[m] += lf[t] * low[is] + hf[t] * high[is];
+                dst[n] += lf[t + 1] * low[is] + hf[t + 1] * high[is];
+            }
+        }
+    }
+}
+
+static void dwt_levels(AudioFWTDNContext *s, int levels, int inlength, int outlength,
+                       const double *in, double *temp0, double *temp1, double *wtc)
+{
+    int N = outlength;
+    int temp_len = s->nb_samples;
+
+    for (int i = 0; i < inlength; i++)
+        temp0[i] = in[i];
+    for (int i = inlength; i < s->nb_samples; i++)
+        temp0[i] = 0.;
+
+    for (int level = 0; level < levels; level++) {
+        int level_length = s->length[levels - level];
+
+        N -= level_length;
+        dwt(temp0, temp_len, s->lp, s->hp, s->wavelet_length, temp1, wtc + N, level_length);
+        temp_len = s->length[levels - level];
+
+        if (level == levels - 1) {
+            for (int i = 0; i < level_length; i++)
+                wtc[i] = temp1[i];
+        } else {
+            for (int i = 0; i < level_length; i++)
+                temp0[i] = temp1[i];
+        }
+    }
+}
+
+static void idwt_levels(AudioFWTDNContext *s, int levels, double *out,
+                        double *temp0, double *temp1, double *wtc)
+{
+    int app_len = s->length[0];
+    int det_len = s->length[1];
+    int lf = (s->wavelet_length + s->wavelet_length) / 2;
+    int iter = app_len;
+
+    for (int i = 0; i < app_len; i++)
+        out[i] = wtc[i];
+
+    for (int i = 0; i < levels; i++) {
+        idwt(out, det_len, wtc + iter, s->ilp, s->ihp, s->wavelet_length, temp1);
+        for (int k = lf - 2; k < 2 * det_len; k++) {
+            out[k - lf + 2] = temp1[k];
+        }
+
+        iter += det_len;
+        det_len = s->length[i + 2];
+    }
+}
+
+typedef struct ThreadData {
+    AVFrame *in, *out;
+} ThreadData;
+
+static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
+{
+    AudioFWTDNContext *s = ctx->priv;
+    ThreadData *td = arg;
+    AVFrame *in = td->in;
+    AVFrame *out = td->out;
+    const double *src = (const double *)(in->extended_data[ch]);
+    double *temp0 = (double *)s->temp0->extended_data[ch];
+    double *temp1 = (double *)s->temp1->extended_data[ch];
+    double *wtc = (double *)s->wtc->extended_data[ch];
+    double *dst = (double *)out->extended_data[ch];
+    double sigma = 4.0 * s->sigma / 10000.;
+
+    dwt_levels(s, s->levels, in->nb_samples, s->outlength, src, temp0, temp1, wtc);
+
+    s->thresholding(ctx, wtc, 2 * (s->wavelet_length + s->nb_samples), sigma);
+
+    idwt_levels(s, s->levels, dst, temp0, temp1, wtc);
+
+    return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    ThreadData td;
+    AVFrame *out = NULL;
+
+    out = ff_get_audio_buffer(outlink, in->nb_samples);
+    if (!out) {
+        av_frame_free(&in);
+        return AVERROR(ENOMEM);
+    }
+    out->pts = in->pts;
+
+    td.in  = in;
+    td.out = out;
+    ctx->internal->execute(ctx, filter_channel, &td, NULL, inlink->channels);
+
+    av_frame_free(&in);
+    return ff_filter_frame(outlink, out);
+}
+
+static int activate(AVFilterContext *ctx)
+{
+    AVFilterLink *inlink = ctx->inputs[0];
+    AVFilterLink *outlink = ctx->outputs[0];
+    AudioFWTDNContext *s = ctx->priv;
+    AVFrame *in = NULL;
+    int ret;
+
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
+
+    ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in);
+    if (ret < 0)
+        return ret;
+    if (ret > 0)
+        return filter_frame(inlink, in);
+
+    FF_FILTER_FORWARD_STATUS(inlink, outlink);
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
+    return FFERROR_NOT_READY;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    AudioFWTDNContext *s = ctx->priv;
+
+    av_frame_free(&s->wtc);
+    av_frame_free(&s->temp0);
+    av_frame_free(&s->temp1);
+}
+
+static const AVFilterPad inputs[] = {
+    {
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_AUDIO,
+    },
+    { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_AUDIO,
+        .config_props  = config_output,
+    },
+    { NULL }
+};
+
+AVFilter ff_af_afwtdn = {
+    .name          = "afwtdn",
+    .description   = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Fast Wavelet Transform."),
+    .query_formats = query_formats,
+    .priv_size     = sizeof(AudioFWTDNContext),
+    .priv_class    = &afwtdn_class,
+    .activate      = activate,
+    .uninit        = uninit,
+    .inputs        = inputs,
+    .outputs       = outputs,
+    .flags         = AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 1183e40267..de5884529c 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -43,6 +43,7 @@  extern AVFilter ff_af_afftdn;
 extern AVFilter ff_af_afftfilt;
 extern AVFilter ff_af_afir;
 extern AVFilter ff_af_aformat;
+extern AVFilter ff_af_afwtdn;
 extern AVFilter ff_af_agate;
 extern AVFilter ff_af_aiir;
 extern AVFilter ff_af_aintegral;