[FFmpeg-devel] [PATCH] lavfi: add earwax audio filter, ported from Sox

Stefano Sabatini stefasab at gmail.com
Sat Nov 5 02:21:13 CET 2011


On date Tuesday 2011-11-01 19:24:49 +0100, Stefano Sabatini encoded:
> On date Tuesday 2011-11-01 03:23:51 +0100, Michael Niedermayer encoded:
> > On Tue, Nov 01, 2011 at 01:51:32AM +0100, Stefano Sabatini wrote:
> > > From: Mina Nagy Zaki <mnzaki at gmail.com>
> > > 
> > > Signed-off-by: Stefano Sabatini <stefasab at gmail.com>
> > > ---
> > >  doc/filters.texi         |   10 +++
> > >  libavfilter/Makefile     |    1 +
> > >  libavfilter/af_earwax.c  |  159 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  libavfilter/allfilters.c |    1 +
> > >  4 files changed, 171 insertions(+), 0 deletions(-)
> > >  create mode 100644 libavfilter/af_earwax.c
> > > 
> > > diff --git a/doc/filters.texi b/doc/filters.texi
> > > index f282b18..7085ae1 100644
> > > --- a/doc/filters.texi
> > > +++ b/doc/filters.texi
> > > @@ -224,6 +224,16 @@ expressed in the form "[@var{c0} @var{c1} @var{c2} @var{c3} @var{c4} @var{c5}
> > >  @var{c6} @var{c7}]"
> > >  @end table
> > >  
> > > + at section earwax
> > > +
> > > +Make audio easier to listen to on headphones. Adds `cues' to 44.1kHz
> > > +stereo (i.e. audio CD format) audio so that when listened to on
> > > +headphones the stereo image is moved from inside your head (standard
> > > +for headphones) to outside and in front of the listener (standard for
> > > +speakers).
> > > +
> > > +Ported from SoX.
> > > +
> > >  @section ladspa
> > >  
> > >  Apply a LADSPA effect.
> > > diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> > > index 040d565..583dd6d 100644
> > > --- a/libavfilter/Makefile
> > > +++ b/libavfilter/Makefile
> > > @@ -28,6 +28,7 @@ OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
> > >  OBJS-$(CONFIG_ANULL_FILTER)                  += af_anull.o
> > >  OBJS-$(CONFIG_ARESAMPLE_FILTER)              += af_aresample.o
> > >  OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o
> > > +OBJS-$(CONFIG_EARWAX_FILTER)                 += af_earwax.o
> > >  OBJS-$(CONFIG_LADSPA_FILTER)                 += af_ladspa.o
> > >  OBJS-$(CONFIG_SOX_FILTER)                    += af_sox.o
> > >  
> > > diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
> > > new file mode 100644
> > > index 0000000..21099e2
> > > --- /dev/null
> > > +++ b/libavfilter/af_earwax.c
> > > @@ -0,0 +1,159 @@
> > > +/*
> > > + * Copyright (c) 2011 Mina Nagy Zaki
> > > + * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
> > > + * This source code is freely redistributable and may be used for any purpose.
> > > + * This copyright notice must be maintained.  Edward Beingessner And Sundry
> > > + * Contributors are not responsible for the consequences of using this
> > > + * software.
> > > + *
> > > + * 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
> > > + */
> > > +
> > > +/**
> > > + * @file
> > > + * Stereo Widening Effect. Adds audio cues to move stereo image in
> > > + * front of the listener. Adapted from the libsox earwax effect.
> > > + */
> > > +
> > > +#include "libavutil/audioconvert.h"
> > > +#include "avfilter.h"
> > > +
> > > +#define NUMTAPS 64
> > > +
> > > +static const int8_t filt[NUMTAPS] = {
> > > +/* 30°  330° */
> > > +    4,   -6,     /* 32 tap stereo FIR filter. */
> > > +    4,  -11,     /* One side filters as if the */
> > > +   -1,   -5,     /* signal was from 30 degrees */
> > > +    3,    3,     /* from the ear, the other as */
> > > +   -2,    5,     /* if 330 degrees. */
> > > +   -5,    0,
> > > +    9,    1,
> > > +    6,    3,     /*                         Input                         */
> > > +   -4,   -1,     /*                   Left         Right                  */
> > > +   -5,   -3,     /*                __________   __________                */
> > > +   -2,   -5,     /*               |          | |          |               */
> > > +   -7,    1,     /*           .---|  Hh,0(f) | |  Hh,0(f) |---.           */
> > > +    6,   -7,     /*          /    |__________| |__________|    \          */
> > > +   30,  -29,     /*         /                \ /                \         */
> > > +   12,   -3,     /*        /                  X                  \        */
> > > +  -11,    4,     /*       /                  / \                  \       */
> > > +   -3,    7,     /*  ____V_____   __________V   V__________   _____V____  */
> > > +  -20,   23,     /* |          | |          |   |          | |          | */
> > > +    2,    0,     /* | Hh,30(f) | | Hh,330(f)|   | Hh,330(f)| | Hh,30(f) | */
> > > +    1,   -6,     /* |__________| |__________|   |__________| |__________| */
> > > +  -14,   -5,     /*      \     ___      /           \      ___     /      */
> > > +   15,  -18,     /*       \   /   \    /    _____    \    /   \   /       */
> > > +    6,    7,     /*        `->| + |<--'    /     \    `-->| + |<-'        */
> > > +   15,  -10,     /*           \___/      _/       \_      \___/           */
> > > +  -14,   22,     /*               \     / \       / \     /               */
> > > +   -7,   -2,     /*                `--->| |       | |<---'                */
> > > +   -4,    9,     /*                     \_/       \_/                     */
> > > +    6,  -12,     /*                                                       */
> > > +    6,   -6,     /*                       Headphones                      */
> > > +    0,  -11,
> > > +    0,   -5,
> > > +    4,    0};
> > > +
> > > +typedef struct {
> > > +    int16_t taps[NUMTAPS * 2];
> > > +} EarwaxContext;
> > > +
> > > +static int query_formats(AVFilterContext *ctx)
> > > +{
> > > +    AVFilterFormats *formats = NULL;
> > > +    avfilter_add_format(&formats, AV_SAMPLE_FMT_S16);
> > > +    avfilter_set_common_sample_formats(ctx, formats);
> > > +    formats = NULL;
> > > +    avfilter_add_format(&formats, AV_CH_LAYOUT_STEREO);
> > > +    avfilter_set_common_channel_layouts(ctx, formats);
> > > +    formats = NULL;
> > > +    avfilter_add_format(&formats, AVFILTER_PACKED);
> > > +    avfilter_set_common_packing_formats(ctx, formats);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int config_input(AVFilterLink *inlink)
> > > +{
> > > +    if (inlink->sample_rate != 44100) {
> > > +        av_log(inlink->dst, AV_LOG_ERROR,
> > > +               "The earwax filter only works for 44.1kHz audio. Insert "
> > > +               "a resample filter before this\n");
> > > +        return AVERROR(EINVAL);
> > > +    }
> > > +    return 0;
> > > +}
> > 
> > does the code check for stereo somewhere?
> 
> Yes, in query_formats().
>   
> > > +
> > > +//FIXME: replace with DSPContext.scalarproduct_int16
> > > +static inline int16_t *scalarproduct(int16_t *in, int16_t *endin, int16_t *out)
> > 
> > const in, const endin
> 
> Fixed.
>  
> > > +{
> > > +    int32_t sample;
> > > +    int16_t j;
> > > +
> > > +    while (in < endin) {
> > > +        sample = 0;
> > 
> > 32 for rounding
> 
> I suppose you mean sample = 32.
> 
> > 
> > 
> > > +        for (j = 0; j < NUMTAPS; j++)
> > > +            sample += in[j] * filt[j];
> > > +        *out = sample >> 6;
> > > +        out++; in++;
> > > +    }
> > 
> > i assume this matches SOX
> 
> Yes, but SOX works in float32 so the code looks somehow different:
> 
>   while (len--) {       /* update taps and calculate output */
>     double output = 0;
> 
>     for (i = NUMTAPS - 1; i; --i) {
>       p->tap[i] = p->tap[i - 1];
>       output += p->tap[i] * filt[i];
>     }
>     p->tap[0] = *ibuf++ / 64; /* scale output */
>     output += p->tap[0] * filt[0];
>     *obuf++ = SOX_ROUND_CLIP_COUNT(output, effp->clips);
>   }
>  
> > And for the record, this can be implemented with 2 FFTs but i am not
> > sure it would beat a naive SIMD scalarproduct
> > 
> > either way, patch LGTM otherwise
> 
> Updated.

Checked in.
-- 
FFmpeg = Fundamental & Fiendish MultiPurpose Excellent Gadget


More information about the ffmpeg-devel mailing list