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 };