2 * Copyright (c) 2011 Mina Nagy Zaki
3 * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
4 * This source code is freely redistributable and may be used for any purpose.
5 * This copyright notice must be maintained. Edward Beingessner And Sundry
6 * Contributors are not responsible for the consequences of using this
9 * This file is part of FFmpeg.
11 * FFmpeg is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * FFmpeg is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with FFmpeg; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 * Stereo Widening Effect. Adds audio cues to move stereo image in
29 * front of the listener. Adapted from the libsox earwax effect.
32 #include "libavutil/channel_layout.h"
39 static const int8_t filt
[NUMTAPS
] = {
41 4, -6, /* 32 tap stereo FIR filter. */
42 4, -11, /* One side filters as if the */
43 -1, -5, /* signal was from 30 degrees */
44 3, 3, /* from the ear, the other as */
45 -2, 5, /* if 330 degrees. */
49 -4, -1, /* Left Right */
50 -5, -3, /* __________ __________ */
52 -7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */
53 6, -7, /* / |__________| |__________| \ */
54 30, -29, /* / \ / \ */
57 -3, 7, /* ____V_____ __________V V__________ _____V____ */
58 -20, 23, /* | | | | | | | | */
59 2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */
60 1, -6, /* |__________| |__________| |__________| |__________| */
61 -14, -5, /* \ ___ / \ ___ / */
62 15, -18, /* \ / \ / _____ \ / \ / */
63 6, 7, /* `->| + |<--' / \ `-->| + |<-' */
64 15, -10, /* \___/ _/ \_ \___/ */
65 -14, 22, /* \ / \ / \ / */
66 -7, -2, /* `--->| | | |<---' */
69 6, -6, /* Headphones */
75 int16_t taps
[NUMTAPS
* 2];
78 static int query_formats(AVFilterContext
*ctx
)
80 static const int sample_rates
[] = { 44100, -1 };
82 AVFilterFormats
*formats
= NULL
;
83 AVFilterChannelLayouts
*layout
= NULL
;
85 ff_add_format(&formats
, AV_SAMPLE_FMT_S16
);
86 ff_set_common_formats(ctx
, formats
);
87 ff_add_channel_layout(&layout
, AV_CH_LAYOUT_STEREO
);
88 ff_set_common_channel_layouts(ctx
, layout
);
89 ff_set_common_samplerates(ctx
, ff_make_format_list(sample_rates
));
94 //FIXME: replace with DSPContext.scalarproduct_int16
95 static inline int16_t *scalarproduct(const int16_t *in
, const int16_t *endin
, int16_t *out
)
102 for (j
= 0; j
< NUMTAPS
; j
++)
103 sample
+= in
[j
] * filt
[j
];
104 *out
= av_clip_int16(sample
>> 6);
112 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*insamples
)
114 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
115 int16_t *taps
, *endin
, *in
, *out
;
116 AVFrame
*outsamples
= ff_get_audio_buffer(inlink
, insamples
->nb_samples
);
120 av_frame_free(&insamples
);
121 return AVERROR(ENOMEM
);
123 av_frame_copy_props(outsamples
, insamples
);
125 taps
= ((EarwaxContext
*)inlink
->dst
->priv
)->taps
;
126 out
= (int16_t *)outsamples
->data
[0];
127 in
= (int16_t *)insamples
->data
[0];
129 len
= FFMIN(NUMTAPS
, 2*insamples
->nb_samples
);
130 // copy part of new input and process with saved input
131 memcpy(taps
+NUMTAPS
, in
, len
* sizeof(*taps
));
132 out
= scalarproduct(taps
, taps
+ len
, out
);
134 // process current input
135 if (2*insamples
->nb_samples
>= NUMTAPS
){
136 endin
= in
+ insamples
->nb_samples
* 2 - NUMTAPS
;
137 scalarproduct(in
, endin
, out
);
139 // save part of input for next round
140 memcpy(taps
, endin
, NUMTAPS
* sizeof(*taps
));
142 memmove(taps
, taps
+ 2*insamples
->nb_samples
, NUMTAPS
* sizeof(*taps
));
144 av_frame_free(&insamples
);
145 return ff_filter_frame(outlink
, outsamples
);
148 static const AVFilterPad earwax_inputs
[] = {
151 .type
= AVMEDIA_TYPE_AUDIO
,
152 .filter_frame
= filter_frame
,
157 static const AVFilterPad earwax_outputs
[] = {
160 .type
= AVMEDIA_TYPE_AUDIO
,
165 AVFilter ff_af_earwax
= {
167 .description
= NULL_IF_CONFIG_SMALL("Widen the stereo image."),
168 .query_formats
= query_formats
,
169 .priv_size
= sizeof(EarwaxContext
),
170 .inputs
= earwax_inputs
,
171 .outputs
= earwax_outputs
,