Browse code

avfilter/firequalizer: add cubic_interpolate function on gain

smoother version of gain_interpolate

Signed-off-by: Muhammad Faiz <mfcc64@gmail.com>

Muhammad Faiz authored on 2016/10/19 00:55:39
Showing 2 changed files
... ...
@@ -2508,6 +2508,8 @@ and functions:
2508 2508
 @table @option
2509 2509
 @item gain_interpolate(f)
2510 2510
 interpolate gain on frequency f based on gain_entry
2511
+@item cubic_interpolate(f)
2512
+same as gain_interpolate, but smoother
2511 2513
 @end table
2512 2514
 This option is also available as command. Default is @code{gain_interpolate(f)}.
2513 2515
 
... ...
@@ -354,6 +354,51 @@ static double gain_interpolate_func(void *p, double freq)
354 354
     return res[0].gain;
355 355
 }
356 356
 
357
+static double cubic_interpolate_func(void *p, double freq)
358
+{
359
+    AVFilterContext *ctx = p;
360
+    FIREqualizerContext *s = ctx->priv;
361
+    GainEntry *res;
362
+    double x, x2, x3;
363
+    double a, b, c, d;
364
+    double m0, m1, m2, msum, unit;
365
+
366
+    if (!s->nb_gain_entry)
367
+        return 0;
368
+
369
+    if (freq <= s->gain_entry_tbl[0].freq)
370
+        return s->gain_entry_tbl[0].gain;
371
+
372
+    if (freq >= s->gain_entry_tbl[s->nb_gain_entry-1].freq)
373
+        return s->gain_entry_tbl[s->nb_gain_entry-1].gain;
374
+
375
+    res = bsearch(&freq, &s->gain_entry_tbl, s->nb_gain_entry - 1, sizeof(*res), gain_entry_compare);
376
+    av_assert0(res);
377
+
378
+    unit = res[1].freq - res[0].freq;
379
+    m0 = res != s->gain_entry_tbl ?
380
+         unit * (res[0].gain - res[-1].gain) / (res[0].freq - res[-1].freq) : 0;
381
+    m1 = res[1].gain - res[0].gain;
382
+    m2 = res != s->gain_entry_tbl + s->nb_gain_entry - 2 ?
383
+         unit * (res[2].gain - res[1].gain) / (res[2].freq - res[1].freq) : 0;
384
+
385
+    msum = fabs(m0) + fabs(m1);
386
+    m0 = msum > 0 ? (fabs(m0) * m1 + fabs(m1) * m0) / msum : 0;
387
+    msum = fabs(m1) + fabs(m2);
388
+    m1 = msum > 0 ? (fabs(m1) * m2 + fabs(m2) * m1) / msum : 0;
389
+
390
+    d = res[0].gain;
391
+    c = m0;
392
+    b = 3 * res[1].gain - m1 - 2 * c - 3 * d;
393
+    a = res[1].gain - b - c - d;
394
+
395
+    x = (freq - res[0].freq) / unit;
396
+    x2 = x * x;
397
+    x3 = x2 * x;
398
+
399
+    return a * x3 + b * x2 + c * x + d;
400
+}
401
+
357 402
 static const char *const var_names[] = {
358 403
     "f",
359 404
     "sr",
... ...
@@ -379,9 +424,9 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
379 379
     FIREqualizerContext *s = ctx->priv;
380 380
     AVFilterLink *inlink = ctx->inputs[0];
381 381
     const char *gain_entry_func_names[] = { "entry", NULL };
382
-    const char *gain_func_names[] = { "gain_interpolate", NULL };
382
+    const char *gain_func_names[] = { "gain_interpolate", "cubic_interpolate", NULL };
383 383
     double (*gain_entry_funcs[])(void *, double, double) = { entry_func, NULL };
384
-    double (*gain_funcs[])(void *, double) = { gain_interpolate_func, NULL };
384
+    double (*gain_funcs[])(void *, double) = { gain_interpolate_func, cubic_interpolate_func, NULL };
385 385
     double vars[VAR_NB];
386 386
     AVExpr *gain_expr;
387 387
     int ret, k, center, ch;