| @@ -65,6 +65,7 @@ typedef struct { · 64 unmodified lines |
| 65 | typedef struct { | 65 | typedef struct { |
| 66 | const AVClass *class; | 66 | const AVClass *class; |
| 67 | | 67 | |
| | 68 | RDFTContext *analysis_rdft; |
| 68 | RDFTContext *analysis_irdft; | 69 | RDFTContext *analysis_irdft; |
| 69 | RDFTContext *rdft; | 70 | RDFTContext *rdft; |
| 70 | RDFTContext *irdft; | 71 | RDFTContext *irdft; |
| @@ -72,6 +73,7 @@ typedef struct { · 1 unmodified line |
| 72 | int rdft_len; | 73 | int rdft_len; |
| 73 | | 74 | |
| 74 | float *analysis_buf; | 75 | float *analysis_buf; |
| | 76 | float *dump_buf; |
| 75 | float *kernel_tmp_buf; | 77 | float *kernel_tmp_buf; |
| 76 | float *kernel_buf; | 78 | float *kernel_buf; |
| 77 | float *conv_buf; | 79 | float *conv_buf; |
| @@ -93,6 +95,8 @@ typedef struct { · 15 unmodified lines |
| 93 | int multi; | 95 | int multi; |
| 94 | int zero_phase; | 96 | int zero_phase; |
| 95 | int scale; | 97 | int scale; |
| | 98 | char *dumpfile; |
| | 99 | int dumpscale; |
| 96 | | 100 | |
| 97 | int nb_gain_entry; | 101 | int nb_gain_entry; |
| 98 | int gain_entry_err; | 102 | int gain_entry_err; |
| @@ -126,6 +130,8 @@ static const AVOption firequalizer_options[] = { · 27 unmodified lines |
| 126 | { "linlog", "linear-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLOG }, 0, 0, FLAGS, "scale" }, | 130 | { "linlog", "linear-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LINLOG }, 0, 0, FLAGS, "scale" }, |
| 127 | { "loglin", "logarithmic-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLIN }, 0, 0, FLAGS, "scale" }, | 131 | { "loglin", "logarithmic-freq linear-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLIN }, 0, 0, FLAGS, "scale" }, |
| 128 | { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" }, | 132 | { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" }, |
| | 133 | { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, |
| | 134 | { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" }, |
| 129 | { NULL } | 135 | { NULL } |
| 130 | }; | 136 | }; |
| 131 | | 137 | |
| @@ -133,12 +139,14 @@ AVFILTER_DEFINE_CLASS(firequalizer); · 1 unmodified line |
| 133 | | 139 | |
| 134 | static void common_uninit(FIREqualizerContext *s) | 140 | static void common_uninit(FIREqualizerContext *s) |
| 135 | { | 141 | { |
| | 142 | av_rdft_end(s->analysis_rdft); |
| 136 | av_rdft_end(s->analysis_irdft); | 143 | av_rdft_end(s->analysis_irdft); |
| 137 | av_rdft_end(s->rdft); | 144 | av_rdft_end(s->rdft); |
| 138 | av_rdft_end(s->irdft); | 145 | av_rdft_end(s->irdft); |
| 139 | s->analysis_irdft = s->rdft = s->irdft = NULL; | 146 | s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL; |
| 140 | | 147 | |
| 141 | av_freep(&s->analysis_buf); | 148 | av_freep(&s->analysis_buf); |
| | 149 | av_freep(&s->dump_buf); |
| 142 | av_freep(&s->kernel_tmp_buf); | 150 | av_freep(&s->kernel_tmp_buf); |
| 143 | av_freep(&s->kernel_buf); | 151 | av_freep(&s->kernel_buf); |
| 144 | av_freep(&s->conv_buf); | 152 | av_freep(&s->conv_buf); |
| @@ -223,6 +231,53 @@ static void fast_convolute(FIREqualizerContext *s, const float *kernel_buf, floa · 78 unmodified lines |
| 223 | } | 231 | } |
| 224 | } | 232 | } |
| 225 | | 233 | |
| | 234 | static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch) |
| | 235 | { |
| | 236 | FIREqualizerContext *s = ctx->priv; |
| | 237 | int rate = ctx->inputs[0]->sample_rate; |
| | 238 | int xlog = s->dumpscale == SCALE_LOGLIN || s->dumpscale == SCALE_LOGLOG; |
| | 239 | int ylog = s->dumpscale == SCALE_LINLOG || s->dumpscale == SCALE_LOGLOG; |
| | 240 | int x; |
| | 241 | int center = s->fir_len / 2; |
| | 242 | double delay = s->zero_phase ? 0.0 : (double) center / rate; |
| | 243 | double vx, ya, yb; |
| | 244 | |
| | 245 | s->analysis_buf[0] *= s->rdft_len/2; |
| | 246 | for (x = 1; x <= center; x++) { |
| | 247 | s->analysis_buf[x] *= s->rdft_len/2; |
| | 248 | s->analysis_buf[s->analysis_rdft_len - x] *= s->rdft_len/2; |
| | 249 | } |
| | 250 | |
| | 251 | if (ch) |
| | 252 | fprintf(fp, "\n\n"); |
| | 253 | |
| | 254 | fprintf(fp, "# time[%d] (time amplitude)\n", ch); |
| | 255 | |
| | 256 | for (x = center; x > 0; x--) |
| | 257 | fprintf(fp, "%15.10f %15.10f\n", delay - (double) x / rate, (double) s->analysis_buf[s->analysis_rdft_len - x]); |
| | 258 | |
| | 259 | for (x = 0; x <= center; x++) |
| | 260 | fprintf(fp, "%15.10f %15.10f\n", delay + (double)x / rate , (double) s->analysis_buf[x]); |
| | 261 | |
| | 262 | av_rdft_calc(s->analysis_rdft, s->analysis_buf); |
| | 263 | |
| | 264 | fprintf(fp, "\n\n# freq[%d] (frequency desired_gain actual_gain)\n", ch); |
| | 265 | |
| | 266 | for (x = 0; x <= s->analysis_rdft_len/2; x++) { |
| | 267 | int i = (x == s->analysis_rdft_len/2) ? 1 : 2 * x; |
| | 268 | vx = (double)x * rate / s->analysis_rdft_len; |
| | 269 | if (xlog) |
| | 270 | vx = log2(0.05*vx); |
| | 271 | ya = s->dump_buf[i]; |
| | 272 | yb = s->analysis_buf[i]; |
| | 273 | if (ylog) { |
| | 274 | ya = 20.0 * log10(fabs(ya)); |
| | 275 | yb = 20.0 * log10(fabs(yb)); |
| | 276 | } |
| | 277 | fprintf(fp, "%17.10f %17.10f %17.10f\n", vx, ya, yb); |
| | 278 | } |
| | 279 | } |
| | 280 | |
| 226 | static double entry_func(void *p, double freq, double gain) | 281 | static double entry_func(void *p, double freq, double gain) |
| 227 | { | 282 | { |
| 228 | AVFilterContext *ctx = p; | 283 | AVFilterContext *ctx = p; |
| @@ -332,6 +387,7 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g · 103 unmodified lines |
| 332 | int ret, k, center, ch; | 387 | int ret, k, center, ch; |
| 333 | int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG; | 388 | int xlog = s->scale == SCALE_LOGLIN || s->scale == SCALE_LOGLOG; |
| 334 | int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG; | 389 | int ylog = s->scale == SCALE_LINLOG || s->scale == SCALE_LOGLOG; |
| | 390 | FILE *dump_fp = NULL; |
| 335 | | 391 | |
| 336 | s->nb_gain_entry = 0; | 392 | s->nb_gain_entry = 0; |
| 337 | s->gain_entry_err = 0; | 393 | s->gain_entry_err = 0; |
| @@ -352,10 +408,14 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g · 14 unmodified lines |
| 352 | if (ret < 0) | 408 | if (ret < 0) |
| 353 | return ret; | 409 | return ret; |
| 354 | | 410 | |
| | 411 | if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = fopen(s->dumpfile, "w")))) |
| | 412 | av_log(ctx, AV_LOG_WARNING, "dumping failed.\n"); |
| | 413 | |
| 355 | vars[VAR_CHS] = inlink->channels; | 414 | vars[VAR_CHS] = inlink->channels; |
| 356 | vars[VAR_CHLAYOUT] = inlink->channel_layout; | 415 | vars[VAR_CHLAYOUT] = inlink->channel_layout; |
| 357 | vars[VAR_SR] = inlink->sample_rate; | 416 | vars[VAR_SR] = inlink->sample_rate; |
| 358 | for (ch = 0; ch < inlink->channels; ch++) { | 417 | for (ch = 0; ch < inlink->channels; ch++) { |
| | 418 | float *rdft_buf = s->kernel_tmp_buf + ch * s->rdft_len; |
| 359 | double result; | 419 | double result; |
| 360 | vars[VAR_CH] = ch; | 420 | vars[VAR_CH] = ch; |
| 361 | vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch); | 421 | vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch); |
| @@ -380,6 +440,9 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g · 18 unmodified lines |
| 380 | s->analysis_buf[2*k+1] = 0.0; | 440 | s->analysis_buf[2*k+1] = 0.0; |
| 381 | } | 441 | } |
| 382 | | 442 | |
| | 443 | if (s->dump_buf) |
| | 444 | memcpy(s->dump_buf, s->analysis_buf, s->analysis_rdft_len * sizeof(*s->analysis_buf)); |
| | 445 | |
| 383 | av_rdft_calc(s->analysis_irdft, s->analysis_buf); | 446 | av_rdft_calc(s->analysis_irdft, s->analysis_buf); |
| 384 | center = s->fir_len / 2; | 447 | center = s->fir_len / 2; |
| 385 | | 448 | |
| @@ -421,35 +484,36 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g · 35 unmodified lines |
| 421 | av_assert0(0); | 484 | av_assert0(0); |
| 422 | } | 485 | } |
| 423 | s->analysis_buf[k] *= (2.0/s->analysis_rdft_len) * (2.0/s->rdft_len) * win; | 486 | s->analysis_buf[k] *= (2.0/s->analysis_rdft_len) * (2.0/s->rdft_len) * win; |
| | 487 | if (k) |
| | 488 | s->analysis_buf[s->analysis_rdft_len - k] = s->analysis_buf[k]; |
| 424 | } | 489 | } |
| 425 | | 490 | |
| 426 | for (k = 0; k < center - k; k++) { | 491 | memset(s->analysis_buf + center + 1, 0, (s->analysis_rdft_len - s->fir_len) * sizeof(*s->analysis_buf)); |
| 427 | float tmp = s->analysis_buf[k]; | 492 | memcpy(rdft_buf, s->analysis_buf + s->analysis_rdft_len - center, center * sizeof(*s->analysis_buf)); |
| 428 | s->analysis_buf[k] = s->analysis_buf[center - k]; | 493 | memcpy(rdft_buf + center, s->analysis_buf, (s->rdft_len - center) * sizeof(*s->analysis_buf)); |
| 429 | s->analysis_buf[center - k] = tmp; | 494 | av_rdft_calc(s->rdft, rdft_buf); |
| 430 | } | | |
| 431 | | | |
| 432 | for (k = 1; k <= center; k++) | | |
| 433 | s->analysis_buf[center + k] = s->analysis_buf[center - k]; | | |
| 434 | | | |
| 435 | memset(s->analysis_buf + s->fir_len, 0, (s->rdft_len - s->fir_len) * sizeof(*s->analysis_buf)); | | |
| 436 | av_rdft_calc(s->rdft, s->analysis_buf); | | |
| 437 | | 495 | |
| 438 | for (k = 0; k < s->rdft_len; k++) { | 496 | for (k = 0; k < s->rdft_len; k++) { |
| 439 | if (isnan(s->analysis_buf[k]) || isinf(s->analysis_buf[k])) { | 497 | if (isnan(rdft_buf[k]) || isinf(rdft_buf[k])) { |
| 440 | av_log(ctx, AV_LOG_ERROR, "filter kernel contains nan or infinity.\n"); | 498 | av_log(ctx, AV_LOG_ERROR, "filter kernel contains nan or infinity.\n"); |
| 441 | av_expr_free(gain_expr); | 499 | av_expr_free(gain_expr); |
| | 500 | if (dump_fp) |
| | 501 | fclose(dump_fp); |
| 442 | return AVERROR(EINVAL); | 502 | return AVERROR(EINVAL); |
| 443 | } | 503 | } |
| 444 | } | 504 | } |
| 445 | | 505 | |
| 446 | memcpy(s->kernel_tmp_buf + ch * s->rdft_len, s->analysis_buf, s->rdft_len * sizeof(*s->analysis_buf)); | 506 | if (dump_fp) |
| | 507 | dump_fir(ctx, dump_fp, ch); |
| | 508 | |
| 447 | if (!s->multi) | 509 | if (!s->multi) |
| 448 | break; | 510 | break; |
| 449 | } | 511 | } |
| 450 | | 512 | |
| 451 | memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf)); | 513 | memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf)); |
| 452 | av_expr_free(gain_expr); | 514 | av_expr_free(gain_expr); |
| | 515 | if (dump_fp) |
| | 516 | fclose(dump_fp); |
| 453 | return 0; | 517 | return 0; |
| 454 | } | 518 | } |
| 455 | | 519 | |
| @@ -499,6 +563,11 @@ static int config_input(AVFilterLink *inlink) · 43 unmodified lines |
| 499 | if (!(s->analysis_irdft = av_rdft_init(rdft_bits, IDFT_C2R))) | 563 | if (!(s->analysis_irdft = av_rdft_init(rdft_bits, IDFT_C2R))) |
| 500 | return AVERROR(ENOMEM); | 564 | return AVERROR(ENOMEM); |
| 501 | | 565 | |
| | 566 | if (s->dumpfile) { |
| | 567 | s->analysis_rdft = av_rdft_init(rdft_bits, DFT_R2C); |
| | 568 | s->dump_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->dump_buf)); |
| | 569 | } |
| | 570 | |
| 502 | s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf)); | 571 | s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf)); |
| 503 | s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf)); | 572 | s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf)); |
| 504 | s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf)); | 573 | s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf)); |