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