00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00032 #include "libavutil/audioconvert.h"
00033 #include "avfilter.h"
00034 #include "audio.h"
00035 #include "formats.h"
00036 
00037 #define NUMTAPS 64
00038 
00039 static const int8_t filt[NUMTAPS] = {
00040 
00041     4,   -6,     
00042     4,  -11,     
00043    -1,   -5,     
00044     3,    3,     
00045    -2,    5,     
00046    -5,    0,
00047     9,    1,
00048     6,    3,     
00049    -4,   -1,     
00050    -5,   -3,     
00051    -2,   -5,     
00052    -7,    1,     
00053     6,   -7,     
00054    30,  -29,     
00055    12,   -3,     
00056   -11,    4,     
00057    -3,    7,     
00058   -20,   23,     
00059     2,    0,     
00060     1,   -6,     
00061   -14,   -5,     
00062    15,  -18,     
00063     6,    7,     
00064    15,  -10,     
00065   -14,   22,     
00066    -7,   -2,     
00067    -4,    9,     
00068     6,  -12,     
00069     6,   -6,     
00070     0,  -11,
00071     0,   -5,
00072     4,    0};
00073 
00074 typedef struct {
00075     int16_t taps[NUMTAPS * 2];
00076 } EarwaxContext;
00077 
00078 static int query_formats(AVFilterContext *ctx)
00079 {
00080     int sample_rates[] = { 44100, -1 };
00081 
00082     AVFilterFormats *formats = NULL;
00083     AVFilterChannelLayouts *layout = NULL;
00084 
00085     ff_add_format(&formats, AV_SAMPLE_FMT_S16);
00086     ff_set_common_formats(ctx, formats);
00087     ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
00088     ff_set_common_channel_layouts(ctx, layout);
00089     ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
00090 
00091     return 0;
00092 }
00093 
00094 static int config_input(AVFilterLink *inlink)
00095 {
00096     if (inlink->sample_rate != 44100) {
00097         av_log(inlink->dst, AV_LOG_ERROR,
00098                "The earwax filter only works for 44.1kHz audio. Insert "
00099                "a resample filter before this\n");
00100         return AVERROR(EINVAL);
00101     }
00102     return 0;
00103 }
00104 
00105 
00106 static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, int16_t *out)
00107 {
00108     int32_t sample;
00109     int16_t j;
00110 
00111     while (in < endin) {
00112         sample = 32;
00113         for (j = 0; j < NUMTAPS; j++)
00114             sample += in[j] * filt[j];
00115         *out = sample >> 6;
00116         out++;
00117         in++;
00118     }
00119 
00120     return out;
00121 }
00122 
00123 static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00124 {
00125     AVFilterLink *outlink = inlink->dst->outputs[0];
00126     int16_t *taps, *endin, *in, *out;
00127     AVFilterBufferRef *outsamples =
00128         ff_get_audio_buffer(inlink, AV_PERM_WRITE,
00129                                   insamples->audio->nb_samples);
00130     int ret;
00131 
00132     avfilter_copy_buffer_ref_props(outsamples, insamples);
00133 
00134     taps  = ((EarwaxContext *)inlink->dst->priv)->taps;
00135     out   = (int16_t *)outsamples->data[0];
00136     in    = (int16_t *)insamples ->data[0];
00137 
00138     
00139     memcpy(taps+NUMTAPS, in, NUMTAPS * sizeof(*taps));
00140     out   = scalarproduct(taps, taps + NUMTAPS, out);
00141 
00142     
00143     endin = in + insamples->audio->nb_samples * 2 - NUMTAPS;
00144     out   = scalarproduct(in, endin, out);
00145 
00146     
00147     memcpy(taps, endin, NUMTAPS * sizeof(*taps));
00148 
00149     ret = ff_filter_samples(outlink, outsamples);
00150     avfilter_unref_buffer(insamples);
00151     return ret;
00152 }
00153 
00154 AVFilter avfilter_af_earwax = {
00155     .name           = "earwax",
00156     .description    = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
00157     .query_formats  = query_formats,
00158     .priv_size      = sizeof(EarwaxContext),
00159     .inputs  = (const AVFilterPad[])  {{  .name     = "default",
00160                                     .type           = AVMEDIA_TYPE_AUDIO,
00161                                     .filter_samples = filter_samples,
00162                                     .config_props   = config_input,
00163                                     .min_perms      = AV_PERM_READ, },
00164                                  {  .name = NULL}},
00165 
00166     .outputs = (const AVFilterPad[])  {{  .name     = "default",
00167                                     .type           = AVMEDIA_TYPE_AUDIO, },
00168                                  {  .name = NULL}},
00169 };