FFmpeg  4.4
af_aexciter.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Markus Schmidt and Christian Holschuh
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "libavutil/opt.h"
22 #include "avfilter.h"
23 #include "internal.h"
24 #include "audio.h"
25 
26 typedef struct ChannelParams {
28  double rdrive, rbdr, kpa, kpb, kna, knb, ap,
29  an, imr, kc, srct, sq, pwrq;
30  double prev_med, prev_out;
31 
32  double hp[5], lp[5];
33  double hw[4][2], lw[2][2];
35 
36 typedef struct AExciterContext {
37  const AVClass *class;
38 
39  double level_in;
40  double level_out;
41  double amount;
42  double drive;
43  double blend;
44  double freq;
45  double ceil;
46  int listen;
47 
50 
51 #define OFFSET(x) offsetof(AExciterContext, x)
52 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
53 
54 static const AVOption aexciter_options[] = {
55  { "level_in", "set level in", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 64, A },
56  { "level_out", "set level out", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 64, A },
57  { "amount", "set amount", OFFSET(amount), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 64, A },
58  { "drive", "set harmonics", OFFSET(drive), AV_OPT_TYPE_DOUBLE, {.dbl=8.5}, 0.1, 10, A },
59  { "blend", "set blend harmonics", OFFSET(blend), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -10, 10, A },
60  { "freq", "set scope", OFFSET(freq), AV_OPT_TYPE_DOUBLE, {.dbl=7500}, 2000, 12000, A },
61  { "ceil", "set ceiling", OFFSET(ceil), AV_OPT_TYPE_DOUBLE, {.dbl=9999}, 9999, 20000, A },
62  { "listen", "enable listen mode", OFFSET(listen), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A },
63  { NULL }
64 };
65 
67 
68 static inline double M(double x)
69 {
70  return (fabs(x) > 0.00000001) ? x : 0.0;
71 }
72 
73 static inline double D(double x)
74 {
75  x = fabs(x);
76 
77  return (x > 0.00000001) ? sqrt(x) : 0.0;
78 }
79 
80 static void set_params(ChannelParams *p,
81  double blend, double drive,
82  double srate, double freq,
83  double ceil)
84 {
85  double a0, a1, a2, b0, b1, b2, w0, alpha;
86 
87  p->rdrive = 12.0 / drive;
88  p->rbdr = p->rdrive / (10.5 - blend) * 780.0 / 33.0;
89  p->kpa = D(2.0 * (p->rdrive*p->rdrive) - 1.0) + 1.0;
90  p->kpb = (2.0 - p->kpa) / 2.0;
91  p->ap = ((p->rdrive*p->rdrive) - p->kpa + 1.0) / 2.0;
92  p->kc = p->kpa / D(2.0 * D(2.0 * (p->rdrive*p->rdrive) - 1.0) - 2.0 * p->rdrive*p->rdrive);
93 
94  p->srct = (0.1 * srate) / (0.1 * srate + 1.0);
95  p->sq = p->kc*p->kc + 1.0;
96  p->knb = -1.0 * p->rbdr / D(p->sq);
97  p->kna = 2.0 * p->kc * p->rbdr / D(p->sq);
98  p->an = p->rbdr*p->rbdr / p->sq;
99  p->imr = 2.0 * p->knb + D(2.0 * p->kna + 4.0 * p->an - 1.0);
100  p->pwrq = 2.0 / (p->imr + 1.0);
101 
102  w0 = 2 * M_PI * freq / srate;
103  alpha = sin(w0) / (2. * 0.707);
104  a0 = 1 + alpha;
105  a1 = -2 * cos(w0);
106  a2 = 1 - alpha;
107  b0 = (1 + cos(w0)) / 2;
108  b1 = -(1 + cos(w0));
109  b2 = (1 + cos(w0)) / 2;
110 
111  p->hp[0] =-a1 / a0;
112  p->hp[1] =-a2 / a0;
113  p->hp[2] = b0 / a0;
114  p->hp[3] = b1 / a0;
115  p->hp[4] = b2 / a0;
116 
117  w0 = 2 * M_PI * ceil / srate;
118  alpha = sin(w0) / (2. * 0.707);
119  a0 = 1 + alpha;
120  a1 = -2 * cos(w0);
121  a2 = 1 - alpha;
122  b0 = (1 - cos(w0)) / 2;
123  b1 = 1 - cos(w0);
124  b2 = (1 - cos(w0)) / 2;
125 
126  p->lp[0] =-a1 / a0;
127  p->lp[1] =-a2 / a0;
128  p->lp[2] = b0 / a0;
129  p->lp[3] = b1 / a0;
130  p->lp[4] = b2 / a0;
131 }
132 
133 static double bprocess(double in, const double *const c,
134  double *w1, double *w2)
135 {
136  double out = c[2] * in + *w1;
137 
138  *w1 = c[3] * in + *w2 + c[0] * out;
139  *w2 = c[4] * in + c[1] * out;
140 
141  return out;
142 }
143 
145 {
146  double proc = in, med;
147 
148  proc = bprocess(proc, p->hp, &p->hw[0][0], &p->hw[0][1]);
149  proc = bprocess(proc, p->hp, &p->hw[1][0], &p->hw[1][1]);
150 
151  if (proc >= 0.0) {
152  med = (D(p->ap + proc * (p->kpa - proc)) + p->kpb) * p->pwrq;
153  } else {
154  med = (D(p->an - proc * (p->kna + proc)) + p->knb) * p->pwrq * -1.0;
155  }
156 
157  proc = p->srct * (med - p->prev_med + p->prev_out);
158  p->prev_med = M(med);
159  p->prev_out = M(proc);
160 
161  proc = bprocess(proc, p->hp, &p->hw[2][0], &p->hw[2][1]);
162  proc = bprocess(proc, p->hp, &p->hw[3][0], &p->hw[3][1]);
163 
164  if (s->ceil >= 10000.) {
165  proc = bprocess(proc, p->lp, &p->lw[0][0], &p->lw[0][1]);
166  proc = bprocess(proc, p->lp, &p->lw[1][0], &p->lw[1][1]);
167  }
168 
169  return proc;
170 }
171 
172 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
173 {
174  AVFilterContext *ctx = inlink->dst;
175  AExciterContext *s = ctx->priv;
176  AVFilterLink *outlink = ctx->outputs[0];
177  AVFrame *out;
178  const double *src = (const double *)in->data[0];
179  const double level_in = s->level_in;
180  const double level_out = s->level_out;
181  const double amount = s->amount;
182  const double listen = 1.0 - s->listen;
183  double *dst;
184 
186  out = in;
187  } else {
188  out = ff_get_audio_buffer(inlink, in->nb_samples);
189  if (!out) {
190  av_frame_free(&in);
191  return AVERROR(ENOMEM);
192  }
194  }
195 
196  dst = (double *)out->data[0];
197  for (int n = 0; n < in->nb_samples; n++) {
198  for (int c = 0; c < inlink->channels; c++) {
199  double sample = src[c] * level_in;
200 
201  sample = distortion_process(s, &s->cp[c], sample);
202  sample = sample * amount + listen * src[c];
203 
204  sample *= level_out;
205  if (ctx->is_disabled)
206  dst[c] = src[c];
207  else
208  dst[c] = sample;
209  }
210 
211  src += inlink->channels;
212  dst += inlink->channels;
213  }
214 
215  if (in != out)
216  av_frame_free(&in);
217 
218  return ff_filter_frame(outlink, out);
219 }
220 
222 {
225  static const enum AVSampleFormat sample_fmts[] = {
228  };
229  int ret;
230 
232  if (!layouts)
233  return AVERROR(ENOMEM);
235  if (ret < 0)
236  return ret;
237 
239  if (!formats)
240  return AVERROR(ENOMEM);
242  if (ret < 0)
243  return ret;
244 
246  if (!formats)
247  return AVERROR(ENOMEM);
249 }
250 
252 {
253  AExciterContext *s = ctx->priv;
254 
255  av_freep(&s->cp);
256 }
257 
258 static int config_input(AVFilterLink *inlink)
259 {
260  AVFilterContext *ctx = inlink->dst;
261  AExciterContext *s = ctx->priv;
262 
263  if (!s->cp)
264  s->cp = av_calloc(inlink->channels, sizeof(*s->cp));
265  if (!s->cp)
266  return AVERROR(ENOMEM);
267 
268  for (int i = 0; i < inlink->channels; i++)
269  set_params(&s->cp[i], s->blend, s->drive, inlink->sample_rate,
270  s->freq, s->ceil);
271 
272  return 0;
273 }
274 
275 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
276  char *res, int res_len, int flags)
277 {
278  AVFilterLink *inlink = ctx->inputs[0];
279  int ret;
280 
281  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
282  if (ret < 0)
283  return ret;
284 
285  return config_input(inlink);
286 }
287 
289  {
290  .name = "default",
291  .type = AVMEDIA_TYPE_AUDIO,
292  .config_props = config_input,
293  .filter_frame = filter_frame,
294  },
295  { NULL }
296 };
297 
299  {
300  .name = "default",
301  .type = AVMEDIA_TYPE_AUDIO,
302  },
303  { NULL }
304 };
305 
307  .name = "aexciter",
308  .description = NULL_IF_CONFIG_SMALL("Enhance high frequency part of audio."),
309  .priv_size = sizeof(AExciterContext),
310  .priv_class = &aexciter_class,
311  .uninit = uninit,
317 };
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:925
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
static double distortion_process(AExciterContext *s, ChannelParams *p, double in)
Definition: af_aexciter.c:144
AVFilter ff_af_aexciter
Definition: af_aexciter.c:306
static int query_formats(AVFilterContext *ctx)
Definition: af_aexciter.c:221
static int config_input(AVFilterLink *inlink)
Definition: af_aexciter.c:258
static const AVFilterPad avfilter_af_aexciter_inputs[]
Definition: af_aexciter.c:288
AVFILTER_DEFINE_CLASS(aexciter)
static double D(double x)
Definition: af_aexciter.c:73
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_aexciter.c:172
#define A
Definition: af_aexciter.c:52
static void set_params(ChannelParams *p, double blend, double drive, double srate, double freq, double ceil)
Definition: af_aexciter.c:80
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_aexciter.c:275
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_aexciter.c:251
static const AVOption aexciter_options[]
Definition: af_aexciter.c:54
#define OFFSET(x)
Definition: af_aexciter.c:51
static double M(double x)
Definition: af_aexciter.c:68
static double bprocess(double in, const double *const c, double *w1, double *w2)
Definition: af_aexciter.c:133
static const AVFilterPad avfilter_af_aexciter_outputs[]
Definition: af_aexciter.c:298
#define av_cold
Definition: attributes.h:88
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:86
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1094
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:882
Main libavfilter public API header.
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#define s(width, name)
Definition: cbs_vp9.c:257
#define NULL
Definition: coverity.c:32
static __device__ float ceil(float a)
Definition: cuda_runtime.h:176
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
#define sample
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition: formats.c:436
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:587
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
int ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:575
int ff_set_common_channel_layouts(AVFilterContext *ctx, AVFilterChannelLayouts *channel_layouts)
A helper for query_formats() which sets all links to the same list of channel layouts/sample rates.
Definition: formats.c:568
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:421
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:227
@ AV_OPT_TYPE_BOOL
Definition: opt.h:242
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:134
#define AVERROR(e)
Definition: error.h:43
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:594
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:658
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
@ AV_SAMPLE_FMT_DBL
double
Definition: samplefmt.h:64
for(j=16;j >0;--j)
static const int16_t alpha[]
Definition: ilbcdata.h:55
int i
Definition: input.c:407
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
#define M_PI
Definition: mathematics.h:52
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
AVOptions.
#define a2
Definition: regdef.h:48
#define a0
Definition: regdef.h:46
#define a1
Definition: regdef.h:47
formats
Definition: signature.h:48
ChannelParams * cp
Definition: af_aexciter.c:48
double level_out
Definition: af_aexciter.c:40
Describe the class of an AVClass context structure.
Definition: log.h:67
A list of supported channel layouts.
Definition: formats.h:86
An instance of a filter.
Definition: avfilter.h:341
A list of supported formats for one end of a filter link.
Definition: formats.h:65
A filter pad used for either input or output.
Definition: internal.h:54
const char * name
Pad name.
Definition: internal.h:60
Filter definition.
Definition: avfilter.h:145
const char * name
Filter name.
Definition: avfilter.h:149
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
AVOption.
Definition: opt.h:248
sample data coding information
Definition: mlp.h:85
double rdrive
Definition: af_aexciter.c:28
double lw[2][2]
Definition: af_aexciter.c:33
double lp[5]
Definition: af_aexciter.c:32
double drive_old
Definition: af_aexciter.c:27
double hw[4][2]
Definition: af_aexciter.c:33
double blend_old
Definition: af_aexciter.c:27
double hp[5]
Definition: af_aexciter.c:32
double prev_med
Definition: af_aexciter.c:30
double prev_out
Definition: af_aexciter.c:30
#define av_freep(p)
#define src
Definition: vp8dsp.c:255
FILE * out
Definition: movenc.c:54
AVFormatContext * ctx
Definition: movenc.c:48
if(ret< 0)
Definition: vf_mcdeint.c:282
static double b1(void *priv, double x, double y)
Definition: vf_xfade.c:1665
static double b2(void *priv, double x, double y)
Definition: vf_xfade.c:1666
static double b0(void *priv, double x, double y)
Definition: vf_xfade.c:1664
static double c[64]