smoother version of gain_interpolate
Signed-off-by: Muhammad Faiz <mfcc64@gmail.com>
... | ... |
@@ -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; |